Implementation for the Damage history for the library items
Release Inventarsystem / release-docker (push) Successful in 2m22s
Release Inventarsystem / release-docker (push) Successful in 2m22s
This commit is contained in:
+112
-64
@@ -3312,13 +3312,17 @@ def library_view():
|
||||
def library_loans_admin():
|
||||
"""Admin overview for library borrowings and damaged library items."""
|
||||
if 'username' not in session:
|
||||
flash('Ihnen ist es nicht gestattet auf dieser Internetanwendung, die eben besuchte Adrrese zu nutzen, versuchen sie es erneut nach dem sie sich mit einem berechtigten Nutzer angemeldet haben!','error')
|
||||
flash(
|
||||
'Ihnen ist es nicht gestattet auf dieser Internetanwendung, die eben besuchte Adrrese zu nutzen, versuchen sie es erneut nach dem sie sich mit einem berechtigten Nutzer angemeldet haben!',
|
||||
'error')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
current_permissions = us.get_effective_permissions(session['username'])
|
||||
|
||||
if not current_permissions['pages'].get('library_loans_admin', False):
|
||||
flash('Ihnen ist es nicht gestattet auf dieser Internetanwendung, die eben besuchte Adrrese zu nutzen, versuchen sie es erneut nach dem sie sich mit einem berechtigten Nutzer angemeldet haben!','error')
|
||||
flash(
|
||||
'Ihnen ist es nicht gestattet auf dieser Internetanwendung, die eben besuchte Adrrese zu nutzen, versuchen sie es erneut nach dem sie sich mit einem berechtigten Nutzer angemeldet haben!',
|
||||
'error')
|
||||
return redirect(url_for('library_view'))
|
||||
|
||||
if not cfg.MODULES.is_enabled('library'):
|
||||
@@ -3337,7 +3341,6 @@ def library_loans_admin():
|
||||
return _format_money_value(value)
|
||||
|
||||
def safe_decrypt(val):
|
||||
"""Helper to decrypt strings that start with enc:: or standard encrypted strings."""
|
||||
if not val or not isinstance(val, str):
|
||||
return val or ''
|
||||
try:
|
||||
@@ -3345,19 +3348,48 @@ def library_loans_admin():
|
||||
except Exception:
|
||||
return val
|
||||
|
||||
# Hilfsfunktion zur Formatierung der Schadenshistorie
|
||||
def format_damage_history(reports, repairs):
|
||||
fmt_reports = []
|
||||
for r in (reports or []):
|
||||
fmt_reports.append({
|
||||
'description': r.get('description', ''),
|
||||
'reported_by': r.get('reported_by', ''),
|
||||
'reported_at': fmt_dt(r.get('reported_at'))
|
||||
})
|
||||
|
||||
fmt_repairs = []
|
||||
for rep in (repairs or []):
|
||||
res_reports = []
|
||||
for res in rep.get('resolved_reports', []):
|
||||
res_reports.append({
|
||||
'description': res.get('description', ''),
|
||||
'reported_by': res.get('reported_by', ''),
|
||||
'reported_at': fmt_dt(res.get('reported_at'))
|
||||
})
|
||||
fmt_repairs.append({
|
||||
'repaired_by': rep.get('repaired_by', ''),
|
||||
'repaired_at': fmt_dt(rep.get('repaired_at')),
|
||||
'resolved_reports': res_reports
|
||||
})
|
||||
return fmt_reports, fmt_repairs
|
||||
|
||||
client = None
|
||||
try:
|
||||
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
|
||||
db = client[MONGODB_DB]
|
||||
items_col = db['items']
|
||||
ausleihungen_col = db['ausleihungen']
|
||||
users_col = db['users']
|
||||
student_cards_col = db['student_cards']
|
||||
|
||||
# WICHTIG: 'DamageRepairs': 1 zur Projektion hinzugefügt!
|
||||
library_items = list(items_col.find(
|
||||
{'ItemType': {'$in': LIBRARY_ITEM_TYPES}, 'Deleted': {'$ne': True}},
|
||||
{'Name': 1, 'Code_4': 1, 'Anschaffungskosten': 1, 'Condition': 1, 'HasDamage': 1, 'DamageReports': 1,
|
||||
'Verfuegbar': 1, 'User': 1, 'ItemType': 1, 'Author': 1, 'ISBN': 1}
|
||||
{
|
||||
'Name': 1, 'Code_4': 1, 'Anschaffungskosten': 1, 'Condition': 1,
|
||||
'HasDamage': 1, 'DamageReports': 1, 'DamageRepairs': 1,
|
||||
'Verfuegbar': 1, 'User': 1, 'ItemType': 1, 'Author': 1, 'ISBN': 1
|
||||
}
|
||||
))
|
||||
item_map = {str(item['_id']): item for item in library_items if item.get('_id')}
|
||||
item_ids = list(item_map.keys())
|
||||
@@ -3370,42 +3402,29 @@ def library_loans_admin():
|
||||
'Klasse': 1, 'klasse': 1, 'Class': 1, 'school_class': 1}
|
||||
).sort('Start', -1))
|
||||
|
||||
# class_map aufbauen (wie zuvor besprochen)
|
||||
class_map = {}
|
||||
student_cards = list(student_cards_col.find({}, {'SchülerName': 1, 'Klasse': 1, 'AusweisId': 1}))
|
||||
for sc in student_cards:
|
||||
dec_cls = safe_decrypt(sc.get('Klasse'))
|
||||
all_cards = list(student_cards_col.find({}, {'SchülerName': 1, 'Klasse': 1, 'AusweisId': 1}))
|
||||
for card in all_cards:
|
||||
raw_cls = card.get('Klasse')
|
||||
dec_cls = safe_decrypt(raw_cls)
|
||||
if not dec_cls:
|
||||
continue
|
||||
|
||||
dec_name = safe_decrypt(sc.get('SchülerName'))
|
||||
raw_name = sc.get('SchülerName')
|
||||
ausweis_id = sc.get('AusweisId')
|
||||
raw_name = card.get('SchülerName')
|
||||
dec_name = safe_decrypt(raw_name)
|
||||
ausweis_id = card.get('AusweisId')
|
||||
|
||||
if dec_name:
|
||||
class_map[dec_name.strip().lower()] = dec_cls
|
||||
class_map[dec_name] = dec_cls
|
||||
if raw_name:
|
||||
class_map[raw_name] = dec_cls
|
||||
if ausweis_id:
|
||||
class_map[str(ausweis_id).strip().lower()] = dec_cls
|
||||
|
||||
users = list(users_col.find({}, {'Username': 1, 'Name': 1, 'User': 1, 'Klasse': 1, 'klasse': 1, 'Class': 1,
|
||||
'school_class': 1}))
|
||||
for u in users:
|
||||
raw_cls = u.get('Klasse') or u.get('klasse') or u.get('Class') or u.get('school_class') or ''
|
||||
dec_cls = safe_decrypt(raw_cls)
|
||||
if not dec_cls:
|
||||
continue
|
||||
|
||||
for key in [u.get('Username'), u.get('Name'), u.get('User')]:
|
||||
if key:
|
||||
dec_key = safe_decrypt(key)
|
||||
class_map[key] = dec_cls
|
||||
class_map[dec_key] = dec_cls
|
||||
class_map[dec_key.strip().lower()] = dec_cls
|
||||
|
||||
active_item_ids = set()
|
||||
loan_entries = []
|
||||
|
||||
for record in active_records:
|
||||
item_id = str(record.get('Item') or '')
|
||||
if item_id and record.get('Status') == 'active':
|
||||
@@ -3417,26 +3436,24 @@ def library_loans_admin():
|
||||
|
||||
invoice_data = record.get('InvoiceData') or {}
|
||||
condition_value = str(item_doc.get('Condition', '')).strip().lower()
|
||||
item_has_damage = bool(item_doc.get('HasDamage')) or condition_value == 'destroyed' or bool(
|
||||
item_doc.get('DamageReports'))
|
||||
damage_reports = item_doc.get('DamageReports', []) or []
|
||||
|
||||
raw_reports = item_doc.get('DamageReports', [])
|
||||
raw_repairs = item_doc.get('DamageRepairs', [])
|
||||
item_has_damage = bool(item_doc.get('HasDamage')) or condition_value == 'destroyed' or bool(raw_reports)
|
||||
|
||||
fmt_reports, fmt_repairs = format_damage_history(raw_reports, raw_repairs)
|
||||
|
||||
raw_user = record.get('User', '')
|
||||
decrypted_user = safe_decrypt(raw_user)
|
||||
|
||||
direct_class = (
|
||||
user_class = (
|
||||
safe_decrypt(record.get('Klasse'))
|
||||
or safe_decrypt(record.get('klasse'))
|
||||
or safe_decrypt(record.get('Class'))
|
||||
or safe_decrypt(record.get('school_class'))
|
||||
)
|
||||
|
||||
user_class = (
|
||||
direct_class
|
||||
or class_map.get(decrypted_user)
|
||||
or class_map.get(decrypted_user.strip().lower())
|
||||
or class_map.get(raw_user)
|
||||
or ''
|
||||
or class_map.get(raw_user, '')
|
||||
or class_map.get(decrypted_user, '')
|
||||
or class_map.get(decrypted_user.strip().lower(), '')
|
||||
or '—'
|
||||
)
|
||||
|
||||
loan_entries.append({
|
||||
@@ -3447,7 +3464,7 @@ def library_loans_admin():
|
||||
'item_author': item_doc.get('Author', ''),
|
||||
'item_isbn': item_doc.get('ISBN', ''),
|
||||
'item_cost_raw': item_doc.get('Anschaffungskosten', ''),
|
||||
'user': decrypted_user,
|
||||
'user': decrypted_user if decrypted_user else raw_user,
|
||||
'klasse': user_class,
|
||||
'status': record.get('Status', ''),
|
||||
'start': fmt_dt(record.get('Start')),
|
||||
@@ -3455,24 +3472,32 @@ def library_loans_admin():
|
||||
'period': record.get('Period', ''),
|
||||
'notes': record.get('Notes', ''),
|
||||
'invoice_number': invoice_data.get('invoice_number', ''),
|
||||
'invoice_amount': fmt_money(invoice_data.get('amount')) if invoice_data.get('amount') is not None else fmt_money(item_doc.get('Anschaffungskosten')),
|
||||
'invoice_amount': fmt_money(invoice_data.get('amount')) if invoice_data.get(
|
||||
'amount') is not None else fmt_money(item_doc.get('Anschaffungskosten')),
|
||||
'invoice_paid': bool(invoice_data.get('paid', False)),
|
||||
'invoice_paid_at': fmt_dt(invoice_data.get('paid_at')) if isinstance(invoice_data.get('paid_at'), datetime.datetime) else '',
|
||||
'invoice_corrections_count': len(record.get('InvoiceCorrections', []) or []),
|
||||
'invoice_paid_at': fmt_dt(invoice_data.get('paid_at')) if isinstance(invoice_data.get('paid_at'),
|
||||
datetime.datetime) else '',
|
||||
'has_damage': item_has_damage,
|
||||
'damage_count': len(damage_reports),
|
||||
'damage_text': (damage_reports[0].get('description', '') if damage_reports else ''),
|
||||
'damage_count': len(raw_reports),
|
||||
'damage_text': fmt_reports[0]['description'] if fmt_reports else '',
|
||||
'damage_reports': fmt_reports,
|
||||
'damage_repairs': fmt_repairs
|
||||
})
|
||||
|
||||
damaged_items = []
|
||||
for item_doc in library_items:
|
||||
item_id = str(item_doc.get('_id') or '')
|
||||
condition_value = str(item_doc.get('Condition', '')).strip().lower()
|
||||
damage_reports = item_doc.get('DamageReports', []) or []
|
||||
item_has_damage = bool(item_doc.get('HasDamage')) or condition_value == 'destroyed' or bool(damage_reports)
|
||||
|
||||
raw_reports = item_doc.get('DamageReports', [])
|
||||
raw_repairs = item_doc.get('DamageRepairs', [])
|
||||
item_has_damage = bool(item_doc.get('HasDamage')) or condition_value == 'destroyed' or bool(raw_reports)
|
||||
|
||||
if not item_has_damage or item_id in active_item_ids:
|
||||
continue
|
||||
|
||||
fmt_reports, fmt_repairs = format_damage_history(raw_reports, raw_repairs)
|
||||
|
||||
damaged_items.append({
|
||||
'id': item_id,
|
||||
'name': item_doc.get('Name', ''),
|
||||
@@ -3480,11 +3505,13 @@ def library_loans_admin():
|
||||
'author': item_doc.get('Author', ''),
|
||||
'isbn': item_doc.get('ISBN', ''),
|
||||
'condition': item_doc.get('Condition', ''),
|
||||
'damage_count': len(damage_reports),
|
||||
'damage_text': (damage_reports[0].get('description', '') if damage_reports else ''),
|
||||
'available': bool(item_doc.get('Verfuegbar', False)),
|
||||
'last_updated': fmt_dt(item_doc.get('LastUpdated')),
|
||||
'acquisition_costs': item_doc.get('Anschaffungskosten', "")
|
||||
'acquisition_costs': item_doc.get('Anschaffungskosten', ""),
|
||||
'damage_count': len(raw_reports),
|
||||
'damage_text': fmt_reports[0]['description'] if fmt_reports else '',
|
||||
'damage_reports': fmt_reports,
|
||||
'damage_repairs': fmt_repairs
|
||||
})
|
||||
|
||||
return render_template(
|
||||
@@ -9214,7 +9241,7 @@ def resolve_repaired_item_funct(item_id, action, new_code_4="", current_user="ad
|
||||
"""
|
||||
Verarbeitet Items aus der Reparatur und aktualisiert die Serien-Counts
|
||||
sowie Parent/Child-Abhängigkeiten beim Löschen korrekt.
|
||||
Entfernt Schadens-Flags komplett aus Items und zugehörigen Ausleihen.
|
||||
Verschiebt gemeldete Schäden in die Historie (DamageRepairs) bei Reparatur/Austausch.
|
||||
"""
|
||||
if not ObjectId.is_valid(item_id):
|
||||
return False, "Ungültige Item-ID."
|
||||
@@ -9231,19 +9258,24 @@ def resolve_repaired_item_funct(item_id, action, new_code_4="", current_user="ad
|
||||
return False, "Item nicht in der Datenbank gefunden."
|
||||
|
||||
series_group_id = item.get('SeriesGroupId')
|
||||
now = datetime.datetime.now()
|
||||
|
||||
damage_unset = {
|
||||
'HasDamage': "",
|
||||
legacy_damage_unset = {
|
||||
'has_damage': "",
|
||||
'DamageCount': "",
|
||||
'damage_count': "",
|
||||
'DamageText': "",
|
||||
'damage_text': "",
|
||||
'is_damaged': "",
|
||||
'IsDamaged': "",
|
||||
'IsDamaged': ""
|
||||
}
|
||||
|
||||
borrowings_unset = legacy_damage_unset.copy()
|
||||
borrowings_unset.update({
|
||||
'HasDamage': "",
|
||||
'Condition': "",
|
||||
'DamageReports': ""
|
||||
}
|
||||
})
|
||||
|
||||
# --- OPTION 1: DELETE ---
|
||||
if action == 'delete':
|
||||
@@ -9285,24 +9317,36 @@ def resolve_repaired_item_funct(item_id, action, new_code_4="", current_user="ad
|
||||
|
||||
return True, "Item wurde gelöscht und der Bestand aller Serien-Items angepasst."
|
||||
|
||||
current_reports = item.get('DamageReports', [])
|
||||
repair_entry = {
|
||||
'repaired_by': current_user,
|
||||
'repaired_at': now,
|
||||
'action_taken': action,
|
||||
'resolved_reports': current_reports
|
||||
}
|
||||
|
||||
# --- OPTION 2: REPLACE ---
|
||||
elif action == 'replace':
|
||||
if action == 'replace':
|
||||
items.update_one(
|
||||
{'_id': ObjectId(item_id)},
|
||||
{
|
||||
'$push': {'DamageRepairs': repair_entry},
|
||||
'$set': {
|
||||
'Code_4': str(new_code_4).strip(),
|
||||
'Verfuegbar': True,
|
||||
'LastUpdated': datetime.datetime.now()
|
||||
'HasDamage': False,
|
||||
'Condition': 'gut',
|
||||
'DamageReports': [],
|
||||
'LastUpdated': now
|
||||
},
|
||||
'$unset': damage_unset
|
||||
'$unset': legacy_damage_unset
|
||||
}
|
||||
)
|
||||
|
||||
if borrowings is not None:
|
||||
borrowings.update_many(
|
||||
{'$or': [{'item_id': str(item_id)}, {'item_id': ObjectId(item_id)}]},
|
||||
{'$unset': damage_unset}
|
||||
{'$unset': borrowings_unset}
|
||||
)
|
||||
|
||||
return True, f"Item wurde ersetzt. Neuer Code 4 zugewiesen: {new_code_4}."
|
||||
@@ -9312,18 +9356,22 @@ def resolve_repaired_item_funct(item_id, action, new_code_4="", current_user="ad
|
||||
items.update_one(
|
||||
{'_id': ObjectId(item_id)},
|
||||
{
|
||||
'$push': {'DamageRepairs': repair_entry},
|
||||
'$set': {
|
||||
'Verfuegbar': True,
|
||||
'LastUpdated': datetime.datetime.now()
|
||||
'HasDamage': False,
|
||||
'Condition': 'gut',
|
||||
'DamageReports': [],
|
||||
'LastUpdated': now
|
||||
},
|
||||
'$unset': damage_unset
|
||||
'$unset': legacy_damage_unset
|
||||
}
|
||||
)
|
||||
|
||||
if borrowings is not None:
|
||||
borrowings.update_many(
|
||||
{'$or': [{'item_id': str(item_id)}, {'item_id': ObjectId(item_id)}]},
|
||||
{'$unset': damage_unset}
|
||||
{'$unset': borrowings_unset}
|
||||
)
|
||||
|
||||
return True, "Item wurde repariert und ist wieder regulär verfügbar."
|
||||
|
||||
Reference in New Issue
Block a user