Compare commits

...

3 Commits

Author SHA1 Message Date
Aiirondev_dev 9de09a2f41 custom Mahnungs reset implementation 2026-09-27 14:20:44 +02:00
Aiirondev_dev 3d5a81824f changes to the Student Card clearing 2026-09-25 22:02:26 +02:00
Aiirondev_dev b0344627a7 removal of unused Code 2026-09-25 17:01:56 +02:00
3 changed files with 77 additions and 146 deletions
+4 -142
View File
@@ -3506,144 +3506,6 @@ def library_loans_admin():
if client:
client.close()
def generate_test_ausleihen():
"""
Generiert Testdaten für die Überprüfung der Mahnungs- und Sperrlogik.
Erstellt Dummy-Schülerausweise, Bibliotheks-Items und Ausleihungen mit manipulierten Daten (DueDate).
"""
current_time = datetime.datetime.now(ZoneInfo("Europe/Berlin"))
try:
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
db = client[MONGODB_DB]
ausleihungen = db['ausleihungen']
student_cards_col = db['student_cards']
items_col = db['items']
print("Generiere Testdaten für das Mahnungssystem...")
# 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": encrypt_text("Max Mustermann (Stufe 1 Test)"),
"Klasse": "9a",
"is_blocked": False
},
{
"AusweisId": "TEST-AUSWEIS-02",
"SchülerName": encrypt_text("Erika Musterfrau (Stufe 2 Test)"),
"Klasse": "10b",
"is_blocked": False
},
{
"AusweisId": "TEST-AUSWEIS-03",
"SchülerName": encrypt_text("Tom Frisch (Keine Mahnung Test)"),
"Klasse": "8c",
"is_blocked": False
}
]
for s in test_students:
student_cards_col.update_one(
{'AusweisId': s['AusweisId']},
{'$set': s},
upsert=True
)
# 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,
"Code_4": "TR-9988"
})
item2_res = items_col.insert_one({
"Name": "iPad Pro (Test Stufe 2)",
"ItemType": item_type,
"Verfuegbar": False,
"Exemplare": 1,
"Code_4": "TR-9988"
})
item3_res = items_col.insert_one({
"Name": "Taschenrechner (Test Frisch)",
"ItemType": item_type,
"Verfuegbar": False,
"Exemplare": 1,
"Code_4": "TR-9988"
})
# 3. Test-Ausleihungen generieren
# 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: 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")
user_val_2 = encrypt_text("TEST-AUSWEIS-02")
user_val_3 = encrypt_text("TEST-AUSWEIS-03")
test_ausleihungen = [
{
"User": user_val_1,
"Item": str(item1_res.inserted_id),
"Status": "active",
"DueDate": due_date_stufe1,
"Mahnstufe": 0,
"LastUpdated": current_time
},
{
"User": user_val_2,
"Item": str(item2_res.inserted_id),
"Status": "active",
"DueDate": due_date_stufe2,
"Mahnstufe": 1, # Hat bereits Stufe 1, wartet auf Eskalation zu Stufe 2
"LastUpdated": due_date_stufe2
},
{
"User": user_val_3,
"Item": str(item3_res.inserted_id),
"Status": "active",
"DueDate": due_date_frisch,
"Mahnstufe": 2,
"LastUpdated": current_time
}
]
# In die Datenbank einfügen
ausleihungen.insert_many(test_ausleihungen)
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:
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')
def mahnungen_admin():
"""Admin-Übersicht für überfällige Bibliotheks-Ausleihen."""
@@ -3763,8 +3625,8 @@ def mahnungen_admin():
email_service_enabled=cfg.EMAIL_ENABLED
)
@app.route('/mahnungen_reset', methods=['POST'])
def mahnungen_reset():
@app.route('/mahnungen_reset/<int:days>', methods=['POST'])
def mahnungen_reset(days):
"""Setzt die Mahnstufe einer Ausleihe zurück, verlängert die Frist und entsperrt den Schülerausweis."""
if 'username' not in session:
return jsonify({'success': False, 'message': 'Nicht angemeldet.'}), 401
@@ -3792,7 +3654,7 @@ def mahnungen_reset():
return jsonify({'success': False, 'message': 'Ausleihe nicht gefunden.'}), 404
current_time = datetime.datetime.now(ZoneInfo("Europe/Berlin"))
new_due_date = current_time + datetime.timedelta(days=14) # Frist um 14 Tage verlängern
new_due_date = current_time + datetime.timedelta(days=days) # Frist um die angegebene Anzahl an Tagen verlängern
# 2. Mahnstufe zurücksetzen und Frist verlängern
ausleihungen_col.update_one(
@@ -3826,7 +3688,7 @@ def mahnungen_reset():
return jsonify({
'success': True,
'message': 'Mahnstufe zurückgesetzt, Frist um 14 Tage verlängert und Ausweis entsperrt.'
'message': f'Mahnstufe zurückgesetzt, Frist um {days} Tage verlängert und Ausweis entsperrt.'
})
except Exception as e:
+1
View File
@@ -1419,6 +1419,7 @@
keyboardScannerEnabled = false;
keyboardScanBuffer = '';
keyboardLastKeyAt = 0;
setActiveStudentCard('');
document.removeEventListener('keydown', keyboardScanKeydownHandler);
const modal = document.getElementById('physicalScannerModal');
if (modal) modal.style.display = 'none';
+72 -4
View File
@@ -187,7 +187,11 @@
{% endif %}
<button type="button" class="btn btn-sm btn-outline-warning text-dark"
onclick="resetMahnung('{{ item.id }}', '{{ item.schueler_name }}')">
<i class="bi bi-arrow-counterclockwise"></i> Zurücksetzen
<i class="bi bi-arrow-counterclockwise"></i> Zurücksetzen (14 Tage)
</button>
<button type="button" class="btn btn-sm btn-outline-warning text-dark"
onclick="resetMahnungCustom('{{ item.id }}', '{{ item.schueler_name }}')">
<i class="bi bi-arrow-counterclockwise"></i> Zurücksetzen mit eigener Frist
</button>
</div>
</td>
@@ -228,7 +232,7 @@
<input type="email" class="form-control" id="modalEmail" placeholder="E-Mail-Adresse eingeben...">
</div>
<div class="mb-3">
<label for="modalMessage" class="form-label">Nachricht</label>
<label for="modalMessage" class="form-label">Nachrichten-Text</label>
<textarea class="form-control" id="modalMessage" rows="4" placeholder="Optionaler Text..."></textarea>
</div>
</form>
@@ -241,6 +245,31 @@
</div>
</div>
<!-- Custom Reset Days Modal -->
<div class="modal fade" id="customResetModal" tabindex="-1" aria-labelledby="customResetModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="customResetModalLabel">Mahnung zurücksetzen</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Schließen"></button>
</div>
<div class="modal-body">
<input type="hidden" id="resetModalLoanId">
<p>Möchten Sie die Mahnung für <strong id="resetModalStudentName"></strong> wirklich zurücksetzen?</p>
<p class="text-muted small">Dadurch wird die Mahnstufe auf 0 gesetzt und der Schülerausweis entsperrt.</p>
<div class="mb-3">
<label for="resetModalDays" class="form-label">Frist verlängern um (Tage):</label>
<input type="number" class="form-control" id="resetModalDays" value="14" min="1">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<button type="button" class="btn btn-warning" onclick="submitCustomReset()">Mahnung zurücksetzen</button>
</div>
</div>
</div>
</div>
<script>
function openEmailModal(loanId, studentName, studentEmail) {
document.getElementById('modalLoanId').value = loanId;
@@ -292,7 +321,7 @@ function resetMahnung(loanId, studentName) {
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '';
fetch('/mahnungen_reset', {
fetch('/mahnungen_reset/14', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken },
body: JSON.stringify({ loan_id: loanId })
@@ -301,7 +330,46 @@ function resetMahnung(loanId, studentName) {
.then(data => {
if (data.success) {
alert(data.message);
location.reload(); // Seite neu laden, um die aktualisierte Ansicht zu sehen
location.reload();
} else {
alert('Fehler: ' + data.message);
}
})
.catch(error => {
alert('Fehler beim Senden der Anfrage.');
console.error(error);
});
}
function resetMahnungCustom(loanId, studentName) {
document.getElementById('resetModalLoanId').value = loanId;
document.getElementById('resetModalStudentName').textContent = studentName;
document.getElementById('resetModalDays').value = 14;
var customModal = new bootstrap.Modal(document.getElementById('customResetModal'));
customModal.show();
}
function submitCustomReset() {
const loanId = document.getElementById('resetModalLoanId').value;
const daysToExtend = parseInt(document.getElementById('resetModalDays').value, 10);
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '';
if (isNaN(daysToExtend) || daysToExtend < 1) {
alert('Bitte geben Sie eine gültige Anzahl an Tagen ein.');
return;
}
fetch(`/mahnungen_reset/${daysToExtend}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken },
body: JSON.stringify({ loan_id: loanId })
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert(data.message);
location.reload();
} else {
alert('Fehler: ' + data.message);
}