Compare commits

...

4 Commits

Author SHA1 Message Date
Aiirondev_dev 4535800a34 change of the datetime implementation
Release Inventarsystem / release-docker (push) Successful in 2m14s
2026-08-23 19:38:08 +02:00
Aiirondev_dev e3aea734bb Change of the notification-reminder
Release Inventarsystem / release-docker (push) Successful in 2m15s
2026-08-23 19:36:06 +02:00
Aiirondev_dev ad77514574 Implementation for the test data
Release Inventarsystem / release-docker (push) Successful in 2m15s
2026-08-23 19:29:54 +02:00
Aiirondev_dev 9870726c76 changes to the testdataset used to test the system
Release Inventarsystem / release-docker (push) Successful in 2m17s
2026-08-23 19:14:48 +02:00
+104 -51
View File
@@ -1160,8 +1160,8 @@ def _build_reminder_message(item_name, start_dt=None, end_dt=None):
)
def create_return_reminders():
"""Create one-time reminders for day-1 and planned-end events."""
def create_return_reminders_admin():
"""Create one-time reminders for day-1 and planned-end events for admins."""
now = datetime.datetime.now(ZoneInfo("Europe/Berlin"))
one_day_ago = now - datetime.timedelta(days=1)
@@ -1202,9 +1202,14 @@ def create_return_reminders():
for borrow_doc in candidates:
borrow_id = str(borrow_doc.get('_id'))
username = str(borrow_doc.get('User', '')).strip()
if not borrow_id or not username:
continue
# Falls der Benutzername verschlüsselt ist, hier entschlüsseln,
# damit der Admin den echten Namen/Ausweis lesen kann.
display_user = decrypt_text(username) if 'decrypt_text' in globals() else username
item_id = str(borrow_doc.get('Item', '')).strip()
item_doc = item_docs.get(item_id, {})
item_name = item_doc.get('Name') or f'Item {item_id}'
@@ -1212,33 +1217,42 @@ def create_return_reminders():
start_dt = borrow_doc.get('Start')
end_dt = borrow_doc.get('End')
if isinstance(start_dt, datetime.datetime) and start_dt.tzinfo is None:
start_dt = start_dt.replace(tzinfo=datetime.timezone.utc)
if isinstance(end_dt, datetime.datetime) and end_dt.tzinfo is None:
end_dt = end_dt.replace(tzinfo=datetime.timezone.utc)
if isinstance(start_dt, datetime.datetime) and start_dt <= one_day_ago:
_create_notification(
db,
audience='user',
notif_type='return_day_1',
title='Erinnerung: Rueckgabe nach 1 Tag',
message=_build_reminder_message(item_name, start_dt=start_dt, end_dt=end_dt),
target_user=username,
reference={'borrow_id': borrow_id, 'item_id': item_id, 'event': 'day_1'},
unique_key=f'reminder:day1:{borrow_id}',
severity='warning',
audience='admin',
notif_type='admin_return_day_1',
title='Admin-Info: Ausleihe über 1 Tag aktiv',
message=f'Nutzer {display_user} hat das Medium "{item_name}" seit über einem Tag ausgeliehen.',
target_user=None,
reference={'borrow_id': borrow_id, 'item_id': item_id, 'user': username, 'event': 'day_1'},
unique_key=f'admin_reminder:day1:{borrow_id}',
severity='info',
)
if isinstance(end_dt, datetime.datetime) and end_dt <= now:
_create_notification(
db,
audience='user',
notif_type='return_after_end',
title='Erinnerung: Geplante Ausleihe ist beendet',
message=_build_reminder_message(item_name, start_dt=start_dt, end_dt=end_dt),
target_user=username,
reference={'borrow_id': borrow_id, 'item_id': item_id, 'event': 'after_end'},
unique_key=f'reminder:end:{borrow_id}',
audience='admin',
notif_type='admin_return_after_end',
title='Admin-Info: Geplante Ausleihe überfällig',
message=f'Die Ausleihe von "{item_name}" durch {display_user} hat das geplante Enddatum überschritten.',
target_user=None,
reference={'borrow_id': borrow_id, 'item_id': item_id, 'user': username, 'event': 'after_end'},
unique_key=f'admin_reminder:end:{borrow_id}',
severity='warning',
)
except Exception as exc:
app.logger.warning(f"Reminder creation failed: {exc}")
if 'app' in globals():
app.logger.warning(f"Admin reminder creation failed: {exc}")
else:
print(f"Admin reminder creation failed: {exc}")
finally:
if client:
client.close()
@@ -3534,7 +3548,7 @@ def library_loans_admin():
def generate_test_ausleihen():
"""
Generiert Testdaten für die Überprüfung der Mahnungs- und Sperrlogik.
Erstellt Dummy-Nutzer, Dummy-Items und Ausleihungen mit manipulierten Daten (DueDate).
Erstellt Dummy-Schülerausweise, Bibliotheks-Items und Ausleihungen mit manipulierten Daten (DueDate).
"""
current_time = datetime.datetime.now(ZoneInfo("Europe/Berlin"))
@@ -3542,43 +3556,83 @@ def generate_test_ausleihen():
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
db = client[MONGODB_DB]
ausleihungen = db['ausleihungen']
users_col = db['users']
student_cards_col = db['student_cards']
items_col = db['items']
print("Generiere Testdaten...")
print("Generiere Testdaten für das Mahnungssystem...")
# 1. Test-Nutzer erstellen oder aktualisieren (upsert)
test_users = [
{"username": "test_user_stufe1", "email": "stufe1@test.local", "is_blocked": False},
{"username": "test_user_stufe2", "email": "stufe2@test.local", "is_blocked": False},
{"username": "test_user_frisch", "email": "frisch@test.local", "is_blocked": False}
# 1. Test-Schülerausweise erstellen oder aktualisieren (upsert)
# Wir nutzen AusweisIds, die im System als Identifikation dienen
test_students = [
{
"AusweisId": "TEST-AUSWEIS-01",
"SchülerName": "Max Mustermann (Stufe 1 Test)",
"Klasse": "9a",
"is_blocked": False
},
{
"AusweisId": "TEST-AUSWEIS-02",
"SchülerName": "Erika Musterfrau (Stufe 2 Test)",
"Klasse": "10b",
"is_blocked": False
},
{
"AusweisId": "TEST-AUSWEIS-03",
"SchülerName": "Tom Frisch (Keine Mahnung Test)",
"Klasse": "8c",
"is_blocked": False
}
]
for u in test_users:
users_col.update_one(
{'username': u['username']},
{'$set': u},
for s in test_students:
student_cards_col.update_one(
{'AusweisId': s['AusweisId']},
{'$set': s},
upsert=True
)
# 2. Test-Items (Gegenstände) erstellen
item1_res = items_col.insert_one({"Name": "Biologie Buch (Test Stufe 1)"})
item2_res = items_col.insert_one({"Name": "iPad Pro (Test Stufe 2)"})
item3_res = items_col.insert_one({"Name": "Taschenrechner (Test Frisch)"})
# 2. Test-Items als Bibliotheksartikel erstellen (ItemType wird gesetzt, damit it.is_library_itemgreift)
# Passe LIBRARY_ITEM_TYPES an deine verwendeten Typen an (hier beispielhaft 'Buch' / 'Medien')
item_type = LIBRARY_ITEM_TYPES[0] if 'LIBRARY_ITEM_TYPES' in globals() and LIBRARY_ITEM_TYPES else 'Buch'
item1_res = items_col.insert_one({
"Name": "Biologie Buch (Test Stufe 1)",
"ItemType": item_type,
"Verfuegbar": False,
"Exemplare": 1
})
item2_res = items_col.insert_one({
"Name": "iPad Pro (Test Stufe 2)",
"ItemType": item_type,
"Verfuegbar": False,
"Exemplare": 1
})
item3_res = items_col.insert_one({
"Name": "Taschenrechner (Test Frisch)",
"ItemType": item_type,
"Verfuegbar": False,
"Exemplare": 1
})
# 3. Test-Ausleihungen generieren
# Fall 1: 20 Tage drüber, Mahnstufe 0 -> Sollte Stufe 1 triggern
due_date_stufe1 = current_time - datetime.timedelta(days=20)
# Fall 1: 15 Tage drüber, Mahnstufe 0 -> Sollte Stufe 1 triggern (>= 14 Tage)
due_date_stufe1 = current_time - datetime.timedelta(days=15)
# Fall 2: 30 Tage drüber, Mahnstufe 1 -> Sollte Stufe 2 triggern & Nutzer sperren
due_date_stufe2 = current_time - datetime.timedelta(days=30)
# Fall 2: 29 Tage drüber, Mahnstufe 1 -> Sollte Stufe 2 triggern & Ausweis sperren (>= 28 Tage)
due_date_stufe2 = current_time - datetime.timedelta(days=29)
# Fall 3: 5 Tage drüber, Mahnstufe 0 -> Sollte NICHTS tun (da < 14 Tage)
due_date_frisch = current_time - datetime.timedelta(days=5)
# Je nachdem, ob dein System die User-Felder in Ausleihungen verschlüsselt speichert:
# Hier wird encrypt_text verwendet, falls die Funktion im Scope liegt.
user_val_1 = encrypt_text("TEST-AUSWEIS-01") if 'encrypt_text' in globals() else "TEST-AUSWEIS-01"
user_val_2 = encrypt_text("TEST-AUSWEIS-02") if 'encrypt_text' in globals() else "TEST-AUSWEIS-02"
user_val_3 = encrypt_text("TEST-AUSWEIS-03") if 'encrypt_text' in globals() else "TEST-AUSWEIS-03"
test_ausleihungen = [
{
"User": encrypt_text("test_user_stufe1"),
"User": encrypt_text(user_val_1),
"Item": str(item1_res.inserted_id),
"Status": "active",
"DueDate": due_date_stufe1,
@@ -3586,15 +3640,15 @@ def generate_test_ausleihen():
"LastUpdated": current_time
},
{
"User": "test_user_stufe2",
"User": encrypt_text(user_val_2),
"Item": str(item2_res.inserted_id),
"Status": "active",
"DueDate": due_date_stufe2,
"Mahnstufe": 1, # Hat bereits Stufe 1
"LastUpdated": due_date_stufe2 # Wurde in der Vergangenheit gemahnt
"Mahnstufe": 1, # Hat bereits Stufe 1, wartet auf Eskalation zu Stufe 2
"LastUpdated": due_date_stufe2
},
{
"User": "test_user_frisch",
"User": encrypt_text(user_val_3),
"Item": str(item3_res.inserted_id),
"Status": "active",
"DueDate": due_date_frisch,
@@ -3606,24 +3660,23 @@ def generate_test_ausleihen():
# In die Datenbank einfügen
ausleihungen.insert_many(test_ausleihungen)
print("Erfolgreich! Folgende Testdaten wurden in die DB geschrieben:")
print(
f"- Fall 1 (Mahnstufe 1 Trigger): Nutzer 'test_user_stufe1', fällig war am {due_date_stufe1.strftime('%Y-%m-%d')}")
print(
f"- Fall 2 (Mahnstufe 2 & Sperre Trigger): Nutzer 'test_user_stufe2', fällig war am {due_date_stufe2.strftime('%Y-%m-%d')}")
print(
f"- Fall 3 (Ignorieren - zu früh): Nutzer 'test_user_frisch', fällig war am {due_date_frisch.strftime('%Y-%m-%d')}")
print("Erfolgreich! Folgende Testdaten wurden für das Mahnungssystem in die DB geschrieben:")
print(f"- Fall 1 (Mahnstufe 1 Trigger): Ausweis 'TEST-AUSWEIS-01', fällig war am {due_date_stufe1.strftime('%Y-%m-%d')} (15 Tage überfällig)")
print(f"- Fall 2 (Mahnstufe 2 & Sperre): Ausweis 'TEST-AUSWEIS-02', fällig war am {due_date_stufe2.strftime('%Y-%m-%d')} (29 Tage überfällig)")
print(f"- Fall 3 (Zu früh / Ignorieren): Ausweis 'TEST-AUSWEIS-03', fällig war am {due_date_frisch.strftime('%Y-%m-%d')} (5 Tage überfällig)")
except Exception as e:
print(f"Fehler beim Erstellen der Testdaten: {e}")
finally:
client.close()
if client:
client.close()
@app.route('/test_mahnungen')
def test_mahnungen():
# Testdaten (Mock-Daten), um alle if/else Bedingungen im HTML zu testen
generate_test_ausleihen()
create_return_reminders()
return redirect(url_for('mahnungen_admin'))
@app.route('/mahnungen_admin')