diff --git a/Web/templates/library_table.html b/Web/templates/library_table.html index bbefe13..8f77143 100644 --- a/Web/templates/library_table.html +++ b/Web/templates/library_table.html @@ -1027,47 +1027,21 @@ } async function processQuickToggleScan(scannedCode) { - if (!activeStudentCardId) { - // If return-only mode is active, always attempt to return by code - const returnOnly = (document.getElementById('returnOnlyToggle') || {}).checked; - if (returnOnly) { - await returnByCode(scannedCode); - return; - } - - if (!activeStudentCardId) { - setActiveStudentCard(scannedCode); - setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}`, 'ok'); - return; - } - - - async function returnByCode(code) { - if (!code) return; - setScanStatus('Verarbeite Rückgabe...', 'warn'); - try { - const resp = await fetch('/api/library_return_by_code', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ item_code: code }) - }); - const result = await resp.json(); - if (!resp.ok || !result.ok) { - setScanStatus(result.message || 'Rückgabe fehlgeschlagen.', 'error'); - showSmallConfirm(result.message || 'Rückgabe fehlgeschlagen.', 'error'); - return false; - } - setScanStatus(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); - showSmallConfirm(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); - await loadLibraryItems(); - return true; - } catch (err) { - console.error('Return by code failed:', err); - setScanStatus('Fehler bei Rückgabe.', 'error'); - showSmallConfirm('Fehler bei Rückgabe.', 'error'); - return false; + // 1. Prüfen, ob "Nur Rückgabe"-Modus aktiv ist + const returnOnly = (document.getElementById('returnOnlyToggle') || {}).checked; + if (returnOnly) { + await returnByCode(scannedCode); + return; } - } + + // 2. Wenn kein Ausweis gesetzt ist, wird der Code als Ausweis interpretiert + if (!activeStudentCardId) { + setActiveStudentCard(scannedCode); + setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}`, 'ok'); + return; + } + + // 3. Ausleihe/Rückgabe verarbeiten (wenn Ausweis vorhanden) try { setScanStatus('Verarbeite Mediencode...', 'warn'); const response = await fetch('/api/library_scan_action', { @@ -1103,6 +1077,33 @@ } } + async function returnByCode(code) { + if (!code) return; + setScanStatus('Verarbeite Rückgabe...', 'warn'); + try { + const resp = await fetch('/api/library_return_by_code', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({ item_code: code }) + }); + const result = await resp.json(); + if (!resp.ok || !result.ok) { + setScanStatus(result.message || 'Rückgabe fehlgeschlagen.', 'error'); + showSmallConfirm(result.message || 'Rückgabe fehlgeschlagen.', 'error'); + return false; + } + setScanStatus(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); + showSmallConfirm(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); + await loadLibraryItems(); + return true; + } catch (err) { + console.error('Return by code failed:', err); + setScanStatus('Fehler bei Rückgabe.', 'error'); + showSmallConfirm('Fehler bei Rückgabe.', 'error'); + return false; + } + } + function scanIntoEditCode() { const scanReaderWrap = document.getElementById('scanReaderWrap'); const editCodeInput = document.getElementById('edit-code4'); @@ -1399,74 +1400,8 @@ }); } - // Edit Modal Form processing const editForm = document.getElementById('editLibraryForm'); if (editForm) { - try { - if (isGroupedEdit) { - const payload = { - series_group_id: currentItem.SeriesGroupId, - ...sharedPayload, - items: groupMembers.map(member => ({ - id: member._id, - code_4: codeByItemId.get(member._id) || '' - })) - }; - - const response = await fetch('/update_group', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': '{{ csrf_token }}', - 'X-CSRF-Token': '{{ csrf_token }}' - }, - body: JSON.stringify(payload) - }); - - const result = await response.json(); - if (response.ok && result.success) { - alert(result.message || 'Gruppe erfolgreich aktualisiert!'); - closeEditLibraryModal(); - pagingState.loading = false; - await loadLibraryItems(); - } else { - alert(result.message || 'Fehler beim Speichern der Gruppenänderungen.'); - } - } else { - const primaryCodeInput = codeInputs[0]; - const payload = { - name: sharedPayload.name, - item_type: sharedPayload.item_type, - isbn: sharedPayload.isbn, - code_4: primaryCodeInput ? primaryCodeInput.value.trim() : (currentItem.Code_4 || currentItem.Code4 || '').trim(), - ort: sharedPayload.ort, - beschreibung: sharedPayload.beschreibung - }; - - const response = await fetch(`/api/library_item/${itemId}/update`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': '{{ csrf_token }}', - 'X-CSRF-Token': '{{ csrf_token }}' - }, - body: JSON.stringify(payload) - }); - - const result = await response.json(); - if (response.ok && result.ok) { - alert(result.message || 'Medium erfolgreich aktualisiert!'); - closeEditLibraryModal(); - pagingState.loading = false; - await loadLibraryItems(); - } else { - alert(result.message || 'Fehler beim Speichern der Änderungen.'); - } - } - } catch (error) { - console.error('Update failed:', error); - alert('Netzwerkfehler beim Aktualisieren des Mediums.'); - } editForm.addEventListener('submit', async function (e) { e.preventDefault(); @@ -1476,6 +1411,7 @@ const codeInputs = Array.from(document.querySelectorAll('#editLibraryCodesContainer input[data-item-id]')); + // Daten aus dem Formular sammeln const sharedPayload = { name: document.getElementById('editLibraryName').value, item_type: document.getElementById('editLibraryType').value, @@ -1486,114 +1422,179 @@ ansch_kost: currentItem.Anschaffungskosten || '', reservierbar: currentItem.Reservierbar !== false, }; + const codeByItemId = new Map(codeInputs.map(input => [input.dataset.itemId, (input.value || '').trim()])); const groupMembers = editLibraryState.groupMembers.length > 0 ? editLibraryState.groupMembers : [currentItem]; const isGroupedEdit = Boolean(currentItem.SeriesGroupId) && groupMembers.length > 1; + // API-Aufruf + try { + if (isGroupedEdit) { + const payload = { + series_group_id: currentItem.SeriesGroupId, + ...sharedPayload, + items: groupMembers.map(member => ({ + id: member._id, + code_4: codeByItemId.get(member._id) || '' + })) + }; + + const response = await fetch('/update_group', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': '{{ csrf_token }}', + 'X-CSRF-Token': '{{ csrf_token }}' + }, + body: JSON.stringify(payload) + }); + + const result = await response.json(); + if (response.ok && result.success) { + alert(result.message || 'Gruppe erfolgreich aktualisiert!'); + closeEditLibraryModal(); + pagingState.loading = false; + await loadLibraryItems(); + } else { + alert(result.message || 'Fehler beim Speichern der Gruppenänderungen.'); + } + } else { + const primaryCodeInput = codeInputs[0]; + const payload = { + name: sharedPayload.name, + item_type: sharedPayload.item_type, + isbn: sharedPayload.isbn, + code_4: primaryCodeInput ? primaryCodeInput.value.trim() : (currentItem.Code_4 || currentItem.Code4 || '').trim(), + ort: sharedPayload.ort, + beschreibung: sharedPayload.beschreibung + }; + + const response = await fetch(`/api/library_item/${itemId}/update`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': '{{ csrf_token }}', + 'X-CSRF-Token': '{{ csrf_token }}' + }, + body: JSON.stringify(payload) + }); + + const result = await response.json(); + if (response.ok && result.ok) { + alert(result.message || 'Medium erfolgreich aktualisiert!'); + closeEditLibraryModal(); + pagingState.loading = false; + await loadLibraryItems(); + } else { + alert(result.message || 'Fehler beim Speichern der Änderungen.'); + } + } + } catch (error) { + console.error('Update failed:', error); + alert('Netzwerkfehler beim Aktualisieren des Mediums.'); + } }); } }); async function fetchLibraryGroupMembers(seriesGroupId) { if (!seriesGroupId) return []; - - try { - const response = await fetch(`/api/library_group/${encodeURIComponent(seriesGroupId)}`); - if (!response.ok) { - throw new Error(`HTTP ${response.status}`); - } - - const payload = await response.json(); - return Array.isArray(payload.items) ? payload.items : []; - } catch (error) { - console.warn('Falling back to loaded library items for group editing:', error); - return (libraryItems || []).filter(item => item.SeriesGroupId === seriesGroupId); + try { + const response = await fetch(`/api/library_group/${encodeURIComponent(seriesGroupId)}`); + if (!response.ok) { + throw new Error(`HTTP ${response.status}`); } + + const payload = await response.json(); + return Array.isArray(payload.items) ? payload.items : []; + } catch (error) { + console.warn('Falling back to loaded library items for group editing:', error); + return (libraryItems || []).filter(item => item.SeriesGroupId === seriesGroupId); + } + } + + function renderLibraryGroupCodeFields(groupMembers, currentItemId) { + const codesContainer = document.getElementById('editLibraryCodesContainer'); + const groupWarning = document.getElementById('editLibraryGroupWarning'); + const groupCount = document.getElementById('editLibraryGroupCount'); + const groupHint = document.getElementById('editLibraryGroupHint'); + + if (!codesContainer) return; + + const items = Array.isArray(groupMembers) ? groupMembers.slice() : []; + items.sort((a, b) => (a.SeriesPosition || 0) - (b.SeriesPosition || 0) || String(a.Name || '').localeCompare(String(b.Name || ''))); + + editLibraryState.groupMembers = items; + + if (groupWarning) { + groupWarning.style.display = items.length > 1 ? 'block' : 'none'; + } + if (groupCount) { + const totalCount = items.length || 1; + const declaredCount = items[0]?.SeriesCount || totalCount; + groupCount.textContent = `${totalCount} / ${declaredCount}`; + } + if (groupHint) { + groupHint.textContent = items.length > 1 + ? 'Jeder Code gehört zu einem eigenen Exemplar. Änderungen werden für alle Codes gespeichert.' + : 'Einzelnes Exemplar. Der Code wird direkt gespeichert.'; } - function renderLibraryGroupCodeFields(groupMembers, currentItemId) { - const codesContainer = document.getElementById('editLibraryCodesContainer'); - const groupWarning = document.getElementById('editLibraryGroupWarning'); - const groupCount = document.getElementById('editLibraryGroupCount'); - const groupHint = document.getElementById('editLibraryGroupHint'); + if (!items.length) { + codesContainer.innerHTML = '
Keine Codes geladen.
'; + return; + } - if (!codesContainer) return; - - const items = Array.isArray(groupMembers) ? groupMembers.slice() : []; - items.sort((a, b) => (a.SeriesPosition || 0) - (b.SeriesPosition || 0) || String(a.Name || '').localeCompare(String(b.Name || ''))); - - editLibraryState.groupMembers = items; - - if (groupWarning) { - groupWarning.style.display = items.length > 1 ? 'block' : 'none'; + codesContainer.innerHTML = items.map((member, index) => { + const codeValue = member.Code_4 || member.Code4 || ''; + const labelParts = []; + if (member.SeriesPosition !== undefined && member.SeriesPosition !== null) { + labelParts.push(`Exemplar ${member.SeriesPosition}`); + } else { + labelParts.push(`Exemplar ${index + 1}`); } - if (groupCount) { - const totalCount = items.length || 1; - const declaredCount = items[0]?.SeriesCount || totalCount; - groupCount.textContent = `${totalCount} / ${declaredCount}`; + if (member._id === currentItemId) { + labelParts.push('aktuelles Medium'); } - if (groupHint) { - groupHint.textContent = items.length > 1 - ? 'Jeder Code gehört zu einem eigenen Exemplar. Änderungen werden für alle Codes gespeichert.' - : 'Einzelnes Exemplar. Der Code wird direkt gespeichert.'; - } - - if (!items.length) { - codesContainer.innerHTML = '
Keine Codes geladen.
'; - return; - } - - codesContainer.innerHTML = items.map((member, index) => { - const codeValue = member.Code_4 || member.Code4 || ''; - const labelParts = []; - if (member.SeriesPosition !== undefined && member.SeriesPosition !== null) { - labelParts.push(`Exemplar ${member.SeriesPosition}`); - } else { - labelParts.push(`Exemplar ${index + 1}`); - } - if (member._id === currentItemId) { - labelParts.push('aktuelles Medium'); - } - return ` -
- - -
+ return ` +
+ + +
`; - }).join(''); + }).join(''); + } + + window.openEditLibraryItem = async function (itemId) { + const item = libraryItems.find(i => i._id === itemId); + if (!item) return; + + editLibraryState.itemId = item._id; + editLibraryState.seriesGroupId = item.SeriesGroupId || ''; + editLibraryState.groupMembers = []; + + // Felder befüllen + document.getElementById('editLibraryItemId').value = item._id; + document.getElementById('editLibraryName').value = item.Name; + document.getElementById('editLibraryType').value = item.ItemType; + document.getElementById('editLibraryIsbn').value = item.ISBN || ''; + document.getElementById('editLibraryLocation').value = item.Ort; + document.getElementById('editLibraryDescription').value = item.Beschreibung; + + const codesContainer = document.getElementById('editLibraryCodesContainer'); + if (codesContainer) { + codesContainer.innerHTML = '
Lade Codes...
'; } - window.openEditLibraryItem = async function (itemId) { - const item = libraryItems.find(i => i._id === itemId); - if (!item) return; + const groupMembers = item.SeriesGroupId ? await fetchLibraryGroupMembers(item.SeriesGroupId) : [item]; + renderLibraryGroupCodeFields(groupMembers.length > 0 ? groupMembers : [item], item._id); - editLibraryState.itemId = item._id; - editLibraryState.seriesGroupId = item.SeriesGroupId || ''; - editLibraryState.groupMembers = []; - - // 1. Felder befüllen - document.getElementById('editLibraryItemId').value = item._id; - document.getElementById('editLibraryName').value = item.Name; - document.getElementById('editLibraryType').value = item.ItemType; - document.getElementById('editLibraryIsbn').value = item.ISBN || ''; - document.getElementById('editLibraryLocation').value = item.Ort; - document.getElementById('editLibraryDescription').value = item.Beschreibung; - - const codesContainer = document.getElementById('editLibraryCodesContainer'); - if (codesContainer) { - codesContainer.innerHTML = '
Lade Codes...
'; - } - - const groupMembers = item.SeriesGroupId ? await fetchLibraryGroupMembers(item.SeriesGroupId) : [item]; - renderLibraryGroupCodeFields(groupMembers.length > 0 ? groupMembers : [item], item._id); - - document.getElementById('editLibraryModal').style.display = 'flex'; - }; + document.getElementById('editLibraryModal').style.display = 'flex'; + }; function closeEditLibraryModal() { document.getElementById('editLibraryModal').style.display = 'none'; } - }