Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d5a81824f | |||
| b0344627a7 | |||
| 8d07577220 | |||
| f3c7b6cd55 |
+7
-138
@@ -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."""
|
||||
@@ -13775,6 +13637,13 @@ def upload_csv_batch():
|
||||
"images_failed": error_count
|
||||
}), 200
|
||||
|
||||
@app.route('/get/asv_export', methods=['GET'])
|
||||
def get_asv_export():
|
||||
if 'username' not in session:
|
||||
flash('Bitte melden Sie sich an.', 'error')
|
||||
return redirect(url_for('login'))
|
||||
return send_from_directory(app.static_folder, 'img/asv_export_invario_2026.exfj')
|
||||
|
||||
"""
|
||||
@app.route('/test_email')
|
||||
def test_email():
|
||||
|
||||
Binary file not shown.
@@ -26,18 +26,27 @@
|
||||
<form method="POST" action="{{ url_for('change_password') }}">
|
||||
<div class="form-group">
|
||||
<label for="current_password">Aktuelles Passwort:</label>
|
||||
<input type="password" id="current_password" name="current_password" required>
|
||||
<div class="input-group">
|
||||
<input type="password" class="form-control" id="current_password" name="current_password" required>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="togglePasswordVisibility('current_password', this)">Anzeigen</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="new_password">Neues Passwort:</label>
|
||||
<input type="password" id="new_password" name="new_password" required>
|
||||
<div class="input-group">
|
||||
<input type="password" class="form-control" id="new_password" name="new_password" required>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="togglePasswordVisibility('new_password', this)">Anzeigen</button>
|
||||
</div>
|
||||
<small class="form-text text-muted">Das Passwort sollte mindestens 6 Zeichen lang sein.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">Neues Passwort bestätigen:</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" required>
|
||||
<div class="input-group">
|
||||
<input type="password" class="form-control" id="confirm_password" name="confirm_password" required>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="togglePasswordVisibility('confirm_password', this)">Anzeigen</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
@@ -48,6 +57,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function togglePasswordVisibility(fieldId, button) {
|
||||
var passwordInput = document.getElementById(fieldId);
|
||||
|
||||
if (passwordInput.type === 'password') {
|
||||
passwordInput.type = 'text';
|
||||
button.textContent = 'Verbergen';
|
||||
} else {
|
||||
passwordInput.type = 'password';
|
||||
button.textContent = 'Anzeigen';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.password-change-form {
|
||||
max-width: 500px;
|
||||
@@ -74,7 +97,7 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input[type="password"] {
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ced4da;
|
||||
@@ -122,6 +145,16 @@
|
||||
.btn-secondary:hover {
|
||||
background-color: #5a6268;
|
||||
}
|
||||
|
||||
.btn-outline-secondary {
|
||||
border: 1px solid #ced4da;
|
||||
background-color: #f8f9fa;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.btn-outline-secondary:hover {
|
||||
background-color: #e2e6ea;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 12px;
|
||||
@@ -141,4 +174,4 @@
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -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';
|
||||
|
||||
@@ -514,6 +514,7 @@
|
||||
<p style="margin:0 0 12px 0; color:#555; font-size:13px; line-height:1.4;">
|
||||
Laden Sie eine <strong>.xlsx</strong>- oder <strong>.csv</strong>-Datei hoch (z. B. aus <strong>ASV</strong>). Erkannt werden Rufame, Nachname, Klasse*, Ausweis-ID*, lokales Differenzierungsmerkmal*, Notizen* & Ausleihdauer*.
|
||||
Hinweis: Die Daten werden Validiert und müssen dann noch einmal aus sicherheits gründen hochgeladen werden!
|
||||
Im folgenden ist eine export vorlage für ihre ASV-Software hinterlegt: <a href="{{ url_for('get_asv_export') }}" target="_blank" style="color:#007bff; text-decoration:underline;">ASV Export Vorlage</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user