Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6496716572 | |||
| f750739b51 | |||
| 4c3545f4ba | |||
| c0bf0c0b8e | |||
| 2cd95ef808 | |||
| 17b58ff7ca | |||
| c67f64a45a | |||
| 7727bfd94a | |||
| 55f34e0462 |
+292
-2
@@ -1588,8 +1588,7 @@ def update_appointment_statuses():
|
||||
f"Failed to create activation notification for {appointment.get('_id')}: {notif_err}"
|
||||
)
|
||||
elif it.is_library_item(appointment.get('Item')):
|
||||
# Introduction of an messaging system and a Mahnstufen implementation for the library Book bookings after the designatet time.
|
||||
pass
|
||||
create_return_reminders()
|
||||
|
||||
client.close()
|
||||
|
||||
@@ -1713,6 +1712,111 @@ def _shutdown_scheduler():
|
||||
|
||||
atexit.register(_shutdown_scheduler)
|
||||
|
||||
|
||||
def create_return_reminders():
|
||||
"""
|
||||
Prüft aktive Ausleihungen auf Überschreitung der Rückgabefrist,
|
||||
erhöht Mahnstufen, versendet E-Mails/Benachrichtigungen und sperrt Nutzer.
|
||||
"""
|
||||
current_time = datetime.datetime.now(datetime.timezone.utc)
|
||||
|
||||
try:
|
||||
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
|
||||
db = client[MONGODB_DB]
|
||||
ausleihungen = db['ausleihungen']
|
||||
users_col = db['users']
|
||||
items_col = db['items']
|
||||
|
||||
# Finde alle aktiven Ausleihungen, die in der Vergangenheit fällig waren
|
||||
overdue_appointments = list(ausleihungen.find({
|
||||
'Status': 'active',
|
||||
'DueDate': {'$lt': current_time}
|
||||
}))
|
||||
|
||||
for appt in overdue_appointments:
|
||||
days_overdue = (current_time - appt.get('DueDate', current_time)).days
|
||||
mahnstufe = appt.get('Mahnstufe', 0)
|
||||
target_user = str(appt.get('User', '')).strip()
|
||||
item_id = appt.get('Item')
|
||||
|
||||
# 1. Objektdetails holen (für den E-Mail-Text)
|
||||
item_name = "Unbekannter Artikel"
|
||||
if item_id:
|
||||
try:
|
||||
item_doc = items_col.find_one({'_id': ObjectId(item_id)})
|
||||
if item_doc:
|
||||
item_name = item_doc.get('Name', str(item_id))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 2. Nutzerdetails holen (für die E-Mail-Adresse)
|
||||
user_doc = users_col.find_one({'username': target_user}) # Feldnamen ggf. anpassen (z.B. '_id')
|
||||
if not user_doc:
|
||||
app.logger.warning(f"Nutzer '{target_user}' für Mahnung nicht gefunden.")
|
||||
continue
|
||||
|
||||
user_email = user_doc.get('email')
|
||||
|
||||
# 3. Eskalationsstufen prüfen
|
||||
if days_overdue >= 14 and days_overdue < 28 and mahnstufe == 0:
|
||||
# STUFE 1: Erste Mahnung
|
||||
ausleihungen.update_one(
|
||||
{'_id': appt['_id']},
|
||||
{'$set': {'Mahnstufe': 1, 'LastUpdated': current_time}}
|
||||
)
|
||||
|
||||
_create_notification(
|
||||
db, audience='user', notif_type='warning',
|
||||
title='Erinnerung: Ausleihe überfällig',
|
||||
message=f'Deine Ausleihe für "{item_name}" ist seit {days_overdue} Tagen überfällig.',
|
||||
target_user=target_user, severity='warning'
|
||||
)
|
||||
|
||||
if user_email:
|
||||
subject = "1. Mahnung: Rückgabe überfällig"
|
||||
note = (f"Hallo {target_user},<br><br>"
|
||||
f"bitte beachte, dass die Ausleihe für den Artikel <b>{item_name}</b> "
|
||||
f"seit {days_overdue} Tagen überfällig ist. Bitte bringe den Artikel zeitnah zurück.")
|
||||
send(email=user_email, subject=subject, note=note, sender="Bibliotheksverwaltung")
|
||||
app.logger.info(f"1. Mahnung an {user_email} gesendet.")
|
||||
|
||||
elif days_overdue >= 28 and mahnstufe == 1:
|
||||
# STUFE 2: Letzte Mahnung, Sperrung und Report
|
||||
ausleihungen.update_one(
|
||||
{'_id': appt['_id']},
|
||||
{'$set': {'Mahnstufe': 2, 'LastUpdated': current_time}}
|
||||
)
|
||||
|
||||
# Nutzerkonto für weitere Ausleihen sperren
|
||||
users_col.update_one(
|
||||
{'_id': user_doc['_id']},
|
||||
{'$set': {
|
||||
'is_blocked': True,
|
||||
'block_reason': f'System-Sperre: Ausleihe von "{item_name}" {days_overdue} Tage überfällig.'
|
||||
}}
|
||||
)
|
||||
|
||||
_create_notification(
|
||||
db, audience='user', notif_type='error',
|
||||
title='Konto gesperrt - 2. Mahnung',
|
||||
message=f'Aufgrund der starken Überfälligkeit von "{item_name}" wurde dein Konto vorübergehend gesperrt.',
|
||||
target_user=target_user, severity='critical'
|
||||
)
|
||||
|
||||
if user_email:
|
||||
subject = "WICHTIG: Kontosperrung & 2. Mahnung"
|
||||
note = (f"Hallo {target_user},<br><br>"
|
||||
f"deine Ausleihe für den Artikel <b>{item_name}</b> ist nun seit {days_overdue} Tagen überfällig. "
|
||||
f"Dies ist ein automatischer Bericht über deinen Status: <b>Dein Konto wurde soeben für neue Reservierungen gesperrt.</b><br><br>"
|
||||
f"Die Sperre wird erst aufgehoben, sobald der Artikel im System als zurückgegeben gemeldet wurde.")
|
||||
send(email=user_email, subject=subject, note=note, sender="Bibliotheksverwaltung")
|
||||
app.logger.warning(f"Nutzer {target_user} gesperrt. 2. Mahnung an {user_email} gesendet.")
|
||||
|
||||
client.close()
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"Fehler bei der automatischen Mahnlauf-Prüfung: {e}")
|
||||
|
||||
"""-------------------------------------------------------------File Upload Validation----------------------------------------------------------------------------- """
|
||||
|
||||
def allowed_file(filename, file_content=None, max_size_mb=cfg.MAX_UPLOAD_MB):
|
||||
@@ -3529,6 +3633,192 @@ def library_loans_admin():
|
||||
if client:
|
||||
client.close()
|
||||
|
||||
|
||||
@app.route('/test_mahnungen')
|
||||
def test_mahnungen():
|
||||
# Testdaten (Mock-Daten), um alle if/else Bedingungen im HTML zu testen
|
||||
test_overdue_list = [
|
||||
{
|
||||
"user": "Max Mustermann",
|
||||
"klasse": "10A",
|
||||
"item_name": "Biologie heute 2",
|
||||
"due_date": "10.08.2026",
|
||||
"days_overdue": 12,
|
||||
"mahnstufe": 2,
|
||||
"is_blocked": True
|
||||
},
|
||||
{
|
||||
"user": "Anna Schmidt",
|
||||
"klasse": "9B",
|
||||
"item_name": "Taschenrechner TI-30",
|
||||
"due_date": "15.08.2026",
|
||||
"days_overdue": 7,
|
||||
"mahnstufe": 1,
|
||||
"is_blocked": False
|
||||
},
|
||||
{
|
||||
"user": "Lukas Weber",
|
||||
"klasse": "12",
|
||||
"item_name": "Faust - Der Tragödie erster Teil",
|
||||
"due_date": "21.08.2026",
|
||||
"days_overdue": 1,
|
||||
"mahnstufe": 0,
|
||||
"is_blocked": False
|
||||
}
|
||||
]
|
||||
|
||||
# Render das Template und übergebe die Testdaten
|
||||
return render_template('mahnungen_admin.html', overdue_list=test_overdue_list, APP_VERSION="1.0.0")
|
||||
|
||||
|
||||
@app.route('/mahnungen_admin')
|
||||
def mahnungen_admin():
|
||||
"""Admin overview for overdue library items (Mahnungen)."""
|
||||
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')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
current_permissions = us.get_effective_permissions(session['username'])
|
||||
|
||||
# Hier nutzen wir beispielhaft die library_loans_admin Berechtigung
|
||||
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')
|
||||
return redirect(url_for('library_view'))
|
||||
|
||||
if not cfg.MODULES.is_enabled('library'):
|
||||
flash('Bibliotheks-Modul ist deaktiviert.', 'error')
|
||||
return redirect(url_for('home_admin'))
|
||||
|
||||
def fmt_dt(dt):
|
||||
try:
|
||||
return dt.strftime('%d.%m.%Y') if dt else 'Unbekannt'
|
||||
except Exception:
|
||||
return str(dt) if dt else 'Unbekannt'
|
||||
|
||||
def safe_decrypt(val):
|
||||
if not val or not isinstance(val, str):
|
||||
return val or ''
|
||||
try:
|
||||
return decrypt_text(val)
|
||||
except Exception:
|
||||
return val
|
||||
|
||||
current_time = datetime.datetime.now(datetime.timezone.utc)
|
||||
client = None
|
||||
|
||||
try:
|
||||
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
|
||||
db = client[MONGODB_DB]
|
||||
ausleihungen_col = db['ausleihungen']
|
||||
items_col = db['items']
|
||||
users_col = db['users']
|
||||
student_cards_col = db['student_cards']
|
||||
|
||||
# Überfällige Ausleihen abrufen (Status 'active' und DueDate in der Vergangenheit)
|
||||
overdue_records = list(ausleihungen_col.find({
|
||||
'Status': 'active',
|
||||
'DueDate': {'$lt': current_time}
|
||||
}).sort('DueDate', 1))
|
||||
|
||||
overdue_list = []
|
||||
|
||||
if overdue_records:
|
||||
# Bulk-Lookups zur Vermeidung von N+1 Queries
|
||||
item_ids = []
|
||||
for r in overdue_records:
|
||||
i_id = r.get('Item')
|
||||
if i_id:
|
||||
try:
|
||||
item_ids.append(ObjectId(str(i_id)))
|
||||
except Exception:
|
||||
item_ids.append(str(i_id))
|
||||
|
||||
items_cursor = items_col.find({
|
||||
'_id': {'$in': item_ids}
|
||||
}, {'Name': 1, 'Code_4': 1})
|
||||
item_map = {str(item['_id']): item for item in items_cursor}
|
||||
|
||||
raw_users = [r.get('User') for r in overdue_records if r.get('User')]
|
||||
users_cursor = users_col.find({'username': {'$in': raw_users}}, {'username': 1, 'is_blocked': 1})
|
||||
user_block_map = {u.get('username'): u.get('is_blocked', False) for u in users_cursor}
|
||||
|
||||
class_map = {}
|
||||
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
|
||||
|
||||
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
|
||||
if raw_name:
|
||||
class_map[raw_name] = dec_cls
|
||||
if ausweis_id:
|
||||
class_map[str(ausweis_id).strip().lower()] = dec_cls
|
||||
|
||||
# Datenaufbereitung für das Template
|
||||
for record in overdue_records:
|
||||
item_id = str(record.get('Item') or '')
|
||||
item_doc = item_map.get(item_id, {})
|
||||
item_name = item_doc.get('Name', item_id)
|
||||
item_code = item_doc.get('Code_4', '')
|
||||
|
||||
if item_code:
|
||||
item_name = f"{item_name} ({item_code})"
|
||||
|
||||
raw_user = record.get('User', '')
|
||||
decrypted_user = safe_decrypt(raw_user)
|
||||
display_user = decrypted_user if decrypted_user else (raw_user or 'Unbekannt')
|
||||
|
||||
user_class = (
|
||||
safe_decrypt(record.get('Klasse'))
|
||||
or safe_decrypt(record.get('Class'))
|
||||
or safe_decrypt(record.get('school_class'))
|
||||
or class_map.get(raw_user, '')
|
||||
or class_map.get(decrypted_user, '')
|
||||
or class_map.get(display_user.strip().lower(), '')
|
||||
or '—'
|
||||
)
|
||||
|
||||
due_date_obj = record.get('DueDate')
|
||||
days_overdue = (current_time - due_date_obj).days if due_date_obj else 0
|
||||
is_blocked = user_block_map.get(raw_user, False)
|
||||
|
||||
overdue_list.append({
|
||||
'id': str(record.get('_id')),
|
||||
'item_name': item_name,
|
||||
'user': display_user,
|
||||
'klasse': user_class,
|
||||
'due_date': fmt_dt(due_date_obj),
|
||||
'days_overdue': days_overdue,
|
||||
'mahnstufe': record.get('Mahnstufe', 0),
|
||||
'is_blocked': is_blocked
|
||||
})
|
||||
|
||||
return render_template(
|
||||
'mahnungen_admin.html',
|
||||
overdue_list=overdue_list,
|
||||
library_module_enabled=cfg.MODULES.is_enabled('library'),
|
||||
student_cards_module_enabled=cfg.MODULES.is_enabled('student_cards'),
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"Error loading mahnungen admin view: {e}")
|
||||
flash('Fehler beim Laden der Mahnungsverwaltung.', 'error')
|
||||
return redirect(url_for('home_admin'))
|
||||
finally:
|
||||
if client:
|
||||
client.close()
|
||||
|
||||
@app.route('/api/library_items')
|
||||
def api_library_items():
|
||||
"""
|
||||
|
||||
@@ -1373,6 +1373,7 @@
|
||||
<li><h6 class="dropdown-header">Bibliotheks-Verwaltung</h6></li>
|
||||
{% if current_permissions.pages.get('library_loans_admin', False) %}
|
||||
<li><a class="dropdown-item" href="{{ url_for('library_loans_admin') }}">Alle Ausleihen/Alle Defekten Items</a></li>
|
||||
<li><a class="dropdown-item" href="{{ url_for('mahnungen_admin') }}">Mahnungen</a></li>
|
||||
{% endif %}
|
||||
{% if student_cards_module_enabled %}
|
||||
{% if current_permissions.actions.get('can_manage_users', False) %}
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Mahnungsübersicht{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<style>
|
||||
.mahnungen-shell {
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.mahnungen-head {
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f7f9fc 100%);
|
||||
border: 1px solid #dbe4ee;
|
||||
border-radius: 16px;
|
||||
padding: 18px 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 10px 26px rgba(15, 23, 42, 0.07);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.mahnungen-head h1 {
|
||||
margin: 0;
|
||||
font-size: 1.55rem;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.head-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-box-wrapper {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
width: 100%;
|
||||
max-width: 360px;
|
||||
padding: 10px 14px;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 8px;
|
||||
font-size: 0.95rem;
|
||||
outline: none;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.search-box:focus {
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
|
||||
}
|
||||
|
||||
.mahnungen-card {
|
||||
background: var(--ui-surface, #ffffff);
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 16px;
|
||||
padding: 18px;
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
.mahnungen-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.mahnungen-table th,
|
||||
.mahnungen-table td {
|
||||
padding: 12px 10px;
|
||||
border-bottom: 1px solid #edf2f7;
|
||||
vertical-align: middle;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.mahnungen-table th {
|
||||
font-size: 0.83rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: #64748b;
|
||||
background: var(--ui-surface-soft, #f8fafc);
|
||||
}
|
||||
|
||||
.mahnungen-table tr:hover td {
|
||||
background: #fbfdff;
|
||||
}
|
||||
|
||||
.badge-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.badge-open { background: #fee2e2; color: #991b1b; }
|
||||
.badge-warning { background: #fef3c7; color: #b45309; }
|
||||
.badge-info { background: #e0f2fe; color: #0369a1; }
|
||||
.badge-paid { background: #dcfce7; color: #166534; }
|
||||
|
||||
.mono {
|
||||
font-family: monospace;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: #dc2626;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
color: #6b7280;
|
||||
padding: 36px 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.mahnungen-table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="mahnungen-shell">
|
||||
<div class="mahnungen-head">
|
||||
<h1>Mahnungsübersicht</h1>
|
||||
<div class="head-actions">
|
||||
<a class="btn btn-outline-secondary" href="{{ url_for('library_loans_admin') }}">Zur Ausleihenverwaltung</a>
|
||||
<a class="btn btn-secondary" href="{{ url_for('library_view') }}">Bibliothek öffnen</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mahnungen-card">
|
||||
{% if overdue_list %}
|
||||
<div class="search-box-wrapper">
|
||||
<input type="text" id="searchInput" class="search-box" placeholder="🔍 Suche nach Nutzer, Klasse oder Gegenstand..." onkeyup="filterTable()">
|
||||
</div>
|
||||
|
||||
<table class="mahnungen-table" id="mahnungTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nutzer</th>
|
||||
<th>Klasse</th>
|
||||
<th>Gegenstand</th>
|
||||
<th>Fällig am</th>
|
||||
<th>Tage drüber</th>
|
||||
<th>Mahnstufe</th>
|
||||
<th>Konto-Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in overdue_list %}
|
||||
<tr>
|
||||
<td><strong>{{ item.user or '—' }}</strong></td>
|
||||
<td>{{ item.klasse or '—' }}</td>
|
||||
<td>{{ item.item_name or '—' }}</td>
|
||||
<td><span class="mono">{{ item.due_date or '—' }}</span></td>
|
||||
<td class="text-danger">{{ item.days_overdue }} Tage</td>
|
||||
<td>
|
||||
{% if item.mahnstufe == 2 %}
|
||||
<span class="badge-pill badge-open">Stufe 2 (Gesperrt)</span>
|
||||
{% elif item.mahnstufe == 1 %}
|
||||
<span class="badge-pill badge-warning">Stufe 1 (Gewarnt)</span>
|
||||
{% else %}
|
||||
<span class="badge-pill badge-info">Stufe 0 (Neu)</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if item.is_blocked %}
|
||||
<span class="badge-pill badge-open">Gesperrt</span>
|
||||
{% else %}
|
||||
<span class="badge-pill badge-paid">Aktiv</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<strong>Hervorragend!</strong> Aktuell gibt es keine überfälligen Ausleihen im System.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function filterTable() {
|
||||
const input = document.getElementById("searchInput");
|
||||
const filter = input.value.toLowerCase();
|
||||
const table = document.getElementById("mahnungTable");
|
||||
const tr = table.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
|
||||
|
||||
for (let i = 0; i < tr.length; i++) {
|
||||
const tdUser = tr[i].getElementsByTagName("td")[0];
|
||||
const tdClass = tr[i].getElementsByTagName("td")[1];
|
||||
const tdItem = tr[i].getElementsByTagName("td")[2];
|
||||
|
||||
if (tdUser || tdClass || tdItem) {
|
||||
const textUser = tdUser.textContent || tdUser.innerText;
|
||||
const textClass = tdClass.textContent || tdClass.innerText;
|
||||
const textItem = tdItem.textContent || tdItem.innerText;
|
||||
|
||||
if (
|
||||
textUser.toLowerCase().indexOf(filter) > -1 ||
|
||||
textClass.toLowerCase().indexOf(filter) > -1 ||
|
||||
textItem.toLowerCase().indexOf(filter) > -1
|
||||
) {
|
||||
tr[i].style.display = "";
|
||||
} else {
|
||||
tr[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1531,22 +1531,22 @@
|
||||
}
|
||||
const isbnField = document.getElementById('isbn');
|
||||
const infoContainer = document.getElementById('book-info-container');
|
||||
|
||||
|
||||
if (!isbnField || !infoContainer) {
|
||||
alert('Fehler: Erforderliche Formularelemente nicht gefunden.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const isbn = normalizeIsbnClient(isbnField.value);
|
||||
|
||||
|
||||
if (!isbn) {
|
||||
infoContainer.innerHTML = '<div class="error-message">Bitte geben Sie eine ISBN oder einen Barcode ein.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Show loading indicator
|
||||
infoContainer.innerHTML = '<div class="loading-spinner">Informationen werden abgerufen...</div>';
|
||||
|
||||
|
||||
// Make API request to fetch book data
|
||||
fetch(`/fetch_book_info/${isbn}`)
|
||||
.then(response => {
|
||||
@@ -1564,10 +1564,10 @@
|
||||
infoContainer.innerHTML = `<div class="error-message">${data.error}</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Store book data globally for import functionality
|
||||
currentBookData = data;
|
||||
|
||||
|
||||
// Display book information with import button
|
||||
infoContainer.innerHTML = `
|
||||
<div class="book-info">
|
||||
@@ -1602,23 +1602,23 @@
|
||||
alert('Keine Buchdaten verfügbar zum Import.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get form fields
|
||||
const nameField = document.getElementById('name');
|
||||
const descriptionField = document.getElementById('beschreibung');
|
||||
const priceField = document.getElementById('anschaffungskosten'); // <-- NEU
|
||||
|
||||
|
||||
if (!nameField || !descriptionField) {
|
||||
alert('Fehler: Formularfelder nicht gefunden.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Generate book title
|
||||
let bookTitle = currentBookData.title || '';
|
||||
if (currentBookData.authors && currentBookData.authors !== 'Unknown Author') {
|
||||
bookTitle += ` - ${currentBookData.authors}`;
|
||||
}
|
||||
|
||||
|
||||
// Generate description
|
||||
let description = '';
|
||||
if (currentBookData.description && currentBookData.description !== 'No description available') {
|
||||
@@ -1639,11 +1639,11 @@
|
||||
description += `\nSeiten: ${currentBookData.pageCount}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Import the data into form fields
|
||||
nameField.value = bookTitle;
|
||||
descriptionField.value = description;
|
||||
|
||||
|
||||
// Preis in das Formularfeld eintragen
|
||||
if (priceField && currentBookData.price !== null && currentBookData.price !== undefined) {
|
||||
// Wandelt den Float (z.B. 12.25) in einen String mit Komma (12,25) um
|
||||
@@ -1655,14 +1655,14 @@
|
||||
if (currentBookData.thumbnail) {
|
||||
downloadBookCover(currentBookData.thumbnail);
|
||||
}
|
||||
|
||||
|
||||
// Show success message
|
||||
const infoContainer = document.getElementById('book-info-container');
|
||||
const successMessage = document.createElement('div');
|
||||
successMessage.className = 'import-success-message';
|
||||
successMessage.textContent = 'Buchdaten erfolgreich in das Formular übernommen!';
|
||||
infoContainer.appendChild(successMessage);
|
||||
|
||||
|
||||
// Remove success message after 3 seconds
|
||||
setTimeout(() => {
|
||||
if (successMessage.parentNode) {
|
||||
|
||||
Reference in New Issue
Block a user