diff --git a/src/api_packing_list_handler.php b/src/api_packing_list_handler.php index 53d70f9..282c2e7 100644 --- a/src/api_packing_list_handler.php +++ b/src/api_packing_list_handler.php @@ -101,7 +101,7 @@ try { // Die rekursive "traverse"-Funktion im JS garantiert dies (Pre-Order Traversal). $parent_pli_id = isset($item_data['parent_pli_id']) && isset($id_map[$item_data['parent_pli_id']]) ? $id_map[$item_data['parent_pli_id']] : null; - $quantity = isset($old_quantities[$pli_id_frontend]) ? intval($old_quantities[$pli_id_frontend]) : 1; + $quantity = isset($item_data['quantity']) ? intval($item_data['quantity']) : (isset($old_quantities[$pli_id_frontend]) ? intval($old_quantities[$pli_id_frontend]) : 1); if ($quantity < 1) $quantity = 1; $stmt_insert->bind_param("iiiiiiiis", $packing_list_id, $article_id_val, $quantity, $carrier_id, $index, $parent_pli_id, $backpack_id, $backpack_compartment_id, $name_val); @@ -185,27 +185,34 @@ try { $include_children = !empty($data['include_children']); function adjust_single($conn, $packing_list_id, $art_id, $delta) { - if ($delta > 0) { - $idx_res = $conn->query("SELECT MAX(order_index) as max_idx FROM packing_list_items WHERE packing_list_id = $packing_list_id"); - $next_idx = ($idx_res->fetch_assoc()['max_idx'] ?? 0) + 1; - $stmt_insert = $conn->prepare("INSERT INTO packing_list_items (packing_list_id, article_id, quantity, order_index) VALUES (?, ?, ?, ?)"); - $stmt_insert->bind_param("iiii", $packing_list_id, $art_id, $delta, $next_idx); - $stmt_insert->execute(); - $stmt_insert->close(); - } else if ($delta < 0) { - $stmt_find = $conn->prepare("SELECT id, quantity FROM packing_list_items WHERE packing_list_id = ? AND article_id = ? AND carrier_user_id IS NULL AND backpack_id IS NULL AND backpack_compartment_id IS NULL AND parent_packing_list_item_id IS NULL ORDER BY quantity ASC LIMIT 1"); - $stmt_find->bind_param("ii", $packing_list_id, $art_id); - $stmt_find->execute(); - $res = $stmt_find->get_result(); - if ($row = $res->fetch_assoc()) { - if ($row['quantity'] > 1) { - $conn->query("UPDATE packing_list_items SET quantity = quantity - 1 WHERE id = " . $row['id']); - } else { - $conn->query("DELETE FROM packing_list_items WHERE id = " . $row['id']); - } + $stmt_find = $conn->prepare("SELECT id, quantity FROM packing_list_items WHERE packing_list_id = ? AND article_id = ? AND carrier_user_id IS NULL AND backpack_id IS NULL AND backpack_compartment_id IS NULL AND parent_packing_list_item_id IS NULL LIMIT 1"); + $stmt_find->bind_param("ii", $packing_list_id, $art_id); + $stmt_find->execute(); + $res = $stmt_find->get_result(); + if ($row = $res->fetch_assoc()) { + $new_quantity = $row['quantity'] + $delta; + if ($new_quantity > 0) { + $stmt_update = $conn->prepare("UPDATE packing_list_items SET quantity = ? WHERE id = ?"); + $stmt_update->bind_param("ii", $new_quantity, $row['id']); + $stmt_update->execute(); + $stmt_update->close(); + } else { + $stmt_del = $conn->prepare("DELETE FROM packing_list_items WHERE id = ?"); + $stmt_del->bind_param("i", $row['id']); + $stmt_del->execute(); + $stmt_del->close(); + } + } else { + if ($delta > 0) { + $idx_res = $conn->query("SELECT MAX(order_index) as max_idx FROM packing_list_items WHERE packing_list_id = $packing_list_id"); + $next_idx = ($idx_res->fetch_assoc()['max_idx'] ?? 0) + 1; + $stmt_insert = $conn->prepare("INSERT INTO packing_list_items (packing_list_id, article_id, quantity, order_index) VALUES (?, ?, ?, ?)"); + $stmt_insert->bind_param("iiii", $packing_list_id, $art_id, $delta, $next_idx); + $stmt_insert->execute(); + $stmt_insert->close(); } - $stmt_find->close(); } + $stmt_find->close(); } adjust_single($conn, $packing_list_id, $article_id, $delta); diff --git a/src/manage_packing_list_items.php b/src/manage_packing_list_items.php index fba1232..f4dcd38 100644 --- a/src/manage_packing_list_items.php +++ b/src/manage_packing_list_items.php @@ -325,6 +325,26 @@ $conn->close(); + +
Änderungen gespeichert!
@@ -336,6 +356,7 @@ $conn->close(); let sortableInstances = {}; let childrenModal = null; let pendingArticleIdForTable = null; + let pendingSplit = null; document.addEventListener('DOMContentLoaded', () => { const tsOptions = { create: false, sortField: { field: "text", direction: "asc" }, allowEmptyOption: true, onChange: function() { this.input.dispatchEvent(new Event('change')); } }; @@ -344,6 +365,24 @@ $conn->close(); new TomSelect('#group-by', tsOptions); new TomSelect('#sort-by', { create: false, allowEmptyOption: false, onChange: function() { this.input.dispatchEvent(new Event('change')); } }); + document.getElementById('btn-split-save').addEventListener('click', () => { + const moveQty = parseInt(document.getElementById('split-qty-input').value, 10); + if (moveQty < 1 || moveQty > pendingSplit.totalQty) return; + + const remainQty = pendingSplit.totalQty - moveQty; + pendingSplit.itemEl.querySelector('.quantity-input').value = moveQty; + + if (remainQty > 0) { + const clone = pendingSplit.itemEl.cloneNode(true); + clone.dataset.itemId = 'new_' + Date.now(); + clone.querySelector('.quantity-input').value = remainQty; + pendingSplit.fromEl.appendChild(clone); + } + + window.splitItemModalInstance.hide(); + syncListState(); + }); + const tooltip = document.getElementById('image-preview-tooltip'); if (tooltip) { document.body.addEventListener('mouseover', e => { @@ -545,6 +584,28 @@ $conn->close(); }); } + function handleSortableEnd(evt) { + const itemEl = evt.item; + const isFromTable = evt.from.id === 'table-container'; + const isToBackpack = evt.to.id !== 'table-container' && evt.to.classList.contains('nested-sortable'); + + if (isFromTable && isToBackpack) { + const qtyInput = itemEl.querySelector('.quantity-input'); + const totalQty = parseInt(qtyInput ? qtyInput.value : 1, 10); + if (totalQty > 1) { + pendingSplit = { itemEl: itemEl, fromEl: evt.from, toEl: evt.to, totalQty: totalQty }; + document.getElementById('split-max-qty').textContent = totalQty; + const splitInput = document.getElementById('split-qty-input'); + splitInput.value = totalQty; + splitInput.max = totalQty; + if (!window.splitItemModalInstance) window.splitItemModalInstance = new bootstrap.Modal(document.getElementById('splitItemModal')); + window.splitItemModalInstance.show(); + return; + } + } + syncListState(); + } + function renderTable() { const container = document.getElementById('table-container'); @@ -570,7 +631,7 @@ $conn->close(); fallbackOnBody: true, swapThreshold: 0.65, ghostClass: 'sortable-ghost', - onEnd: function() { syncListState(); } + onEnd: handleSortableEnd }); } @@ -621,7 +682,7 @@ $conn->close(); fallbackOnBody: true, swapThreshold: 0.65, ghostClass: 'sortable-ghost', - onEnd: function() { syncListState(); } + onEnd: handleSortableEnd }); }); } @@ -643,7 +704,7 @@ $conn->close(); sortableInstances[prefix + 'nested_'+item.id] = new Sortable(nestedContainer, { group: 'nested', animation: 150, handle: '.packed-item-content', fallbackOnBody: true, swapThreshold: 0.65, ghostClass: 'sortable-ghost', - onEnd: function() { syncListState(); } + onEnd: handleSortableEnd }); }); } @@ -717,6 +778,7 @@ $conn->close(); payload.list.push({ pli_id: pliId, article_id: articleId, + quantity: child.querySelector('.quantity-input') ? parseInt(child.querySelector('.quantity-input').value, 10) : 1, carrier_id: carrierId, parent_pli_id: parentId, backpack_id: child.dataset.backpackId || null, @@ -784,9 +846,16 @@ $conn->close(); }; document.getElementById('btn-remove-totable').onclick = () => { window.removeItemModalInstance.hide(); - const tableContainer = document.getElementById('table-container'); - tableContainer.appendChild(itemToRemoveEl); - syncListState(); + const qtyInput = itemToRemoveEl.querySelector('.quantity-input'); + const qty = parseInt(qtyInput ? qtyInput.value : 1, 10); + const articleId = itemToRemoveEl.dataset.articleId; + itemToRemoveEl.remove(); + sendApiRequest({ action: 'adjust_table_quantity', article_id: articleId, delta: qty }) + .then(() => sendApiRequest({ action: 'delete_item', item_id: itemToRemoveId })) + .then(newItems => { + if(Array.isArray(newItems)) packedItems = newItems; + fullRender(); + }); }; } window.removeItemModalInstance.show();