From da5c4b8777626def805f126cd0b62d2e7201e7d9 Mon Sep 17 00:00:00 2001 From: solocla Date: Wed, 9 Sep 2026 14:59:26 +0200 Subject: [PATCH] added multiple imballaggi --- ...60909121829_create_work_sheet_packages.php | 25 ++ public/userarea/include/headscript.php | 8 + public/userarea/manage-worksheet.php | 242 +++++++++++++++++- public/userarea/production_line_view2.php | 114 +++++---- public/userarea/user_settings.php | 30 ++- 5 files changed, 373 insertions(+), 46 deletions(-) create mode 100644 db/migrations/20260909121829_create_work_sheet_packages.php diff --git a/db/migrations/20260909121829_create_work_sheet_packages.php b/db/migrations/20260909121829_create_work_sheet_packages.php new file mode 100644 index 00000000..6fa6b652 --- /dev/null +++ b/db/migrations/20260909121829_create_work_sheet_packages.php @@ -0,0 +1,25 @@ +table('work_sheet_packages', ['id' => 'id']) + ->addColumn('worksheet_id', 'integer', ['limit' => 11]) + ->addColumn('package_code', 'integer', ['limit' => 11, 'comment' => 'FK -> packaging_items.id']) + ->addColumn('package_position', 'integer', ['default' => 1]) + ->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP']) + ->addColumn('updated_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'update' => 'CURRENT_TIMESTAMP']) + ->addIndex(['worksheet_id'], ['name' => 'idx_wsp_ws']) + ->addIndex(['package_code'], ['name' => 'idx_wsp_pkg']) + ->addIndex(['worksheet_id', 'package_code'], ['unique' => true, 'name' => 'uk_wsp_ws_pkg']) + ->addIndex(['worksheet_id', 'package_position'], ['unique' => true, 'name' => 'uk_wsp_ws_position']) + ->addForeignKey('worksheet_id', 'work_sheets', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE']) + ->addForeignKey('package_code', 'packaging_items', 'id', ['update' => 'CASCADE']) + ->create(); + } +} diff --git a/public/userarea/include/headscript.php b/public/userarea/include/headscript.php index 91d5a1ac..d44b3b75 100644 --- a/public/userarea/include/headscript.php +++ b/public/userarea/include/headscript.php @@ -61,3 +61,11 @@ require_once(__DIR__ . '/../../languages/en/general.php'); //include("generalsettings.php"); require_once __DIR__ . '/permissions_helper.php'; require_once(__DIR__ . '/popup-moved.php'); + +// Timbra la sessione dell'utente a ogni pagina (rolling manuale) +try { + $pdoSess = DBHandlerSelect::getInstance()->getConnection(); + $pdoSess->prepare("UPDATE auth_sessions SET last_activity = ? WHERE user_id = ? ORDER BY last_activity DESC LIMIT 1") + ->execute([time(), $iduserlogin]); +} catch (\Throwable $e) { /* non bloccare la pagina */ +} diff --git a/public/userarea/manage-worksheet.php b/public/userarea/manage-worksheet.php index ea5e554c..e115f032 100644 --- a/public/userarea/manage-worksheet.php +++ b/public/userarea/manage-worksheet.php @@ -327,6 +327,68 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj exit; } + // Add package row + if ($action === 'save_package_row') { + $worksheet_id = (int)($_POST['worksheet_id'] ?? 0); + if ($worksheet_id <= 0) { + echo json_encode(['success' => false, 'message' => 'Salva prima il foglio (testata)']); + exit; + } + + $package_code = (int)($_POST['package_code'] ?? 0); + if ($package_code <= 0) { + echo json_encode(['success' => false, 'message' => 'Seleziona un imballo']); + exit; + } + + $pdo->beginTransaction(); + + $stmtPos = $pdo->prepare(" + SELECT IFNULL(MAX(package_position), 0) + 1 + FROM work_sheet_packages + WHERE worksheet_id = ? + FOR UPDATE + "); + $stmtPos->execute([$worksheet_id]); + $pos = (int)$stmtPos->fetchColumn(); + if ($pos <= 0) $pos = 1; + + try { + $stmt = $pdo->prepare(" + INSERT INTO work_sheet_packages + (worksheet_id, package_code, package_position) + VALUES (?, ?, ?) + "); + $stmt->execute([$worksheet_id, $package_code, $pos]); + } catch (PDOException $ex) { + $pdo->rollBack(); + if ((int)$ex->errorInfo[1] === 1062) { + echo json_encode(['success' => false, 'message' => 'Imballo già presente in questo foglio']); + exit; + } + throw $ex; + } + + $pdo->commit(); + echo json_encode(['success' => true]); + exit; + } + + // Delete package row + if ($action === 'delete_package_row') { + $row_id = (int)($_POST['row_id'] ?? 0); + if ($row_id <= 0) { + echo json_encode(['success' => false, 'message' => 'ID riga non valido']); + exit; + } + + $stmt = $pdo->prepare("DELETE FROM work_sheet_packages WHERE id = ?"); + $stmt->execute([$row_id]); + + echo json_encode(['success' => true]); + exit; + } + echo json_encode(['success' => false, 'message' => 'Azione sconosciuta']); exit; } catch (Exception $e) { @@ -406,6 +468,7 @@ $mescole = $pdo->query(" // Load worksheet (edit) $worksheet = null; $mixRows = []; +$packageRows = []; if ($worksheet_id > 0) { $stmt = $pdo->prepare(" @@ -430,6 +493,20 @@ if ($worksheet_id > 0) { "); $stmt->execute([$worksheet_id]); $mixRows = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $stmt = $pdo->prepare(" + SELECT + wsp.*, + pi.item_name AS package_name, + pi.item_code AS package_item_code, + pi.category AS package_category + FROM work_sheet_packages wsp + LEFT JOIN packaging_items pi ON pi.id = wsp.package_code + WHERE wsp.worksheet_id = ? + ORDER BY wsp.package_position ASC, wsp.id ASC + "); + $stmt->execute([$worksheet_id]); + $packageRows = $stmt->fetchAll(PDO::FETCH_ASSOC); } else { $worksheet_id = 0; } @@ -1079,10 +1156,56 @@ $isEdit = ($worksheet_id > 0);
- -
Il valore salvato è il codice dell'elemento
+
Scegli l'elemento e premi "Aggiungi imballo"
+
+ +
+ + +
+ +
+
+ + + + + + + + + + + + + + + + + + + +
PosCategoriaImballoAzioni
+
+ +
+ +
+ +
+
+
Puoi aggiungere più imballi. I dati "metri per confezione", tolleranza, note, ecc. restano unici per il foglio.
+
+ +
+
@@ -1613,6 +1736,121 @@ $isEdit = ($worksheet_id > 0); }); }); }); + + // ---- IMBALLI ---- + const btnAddPackage = $('#btnAddPackage'); + + // Sblocca il bottone imballo se la testata è salvata + function enablePackageButtonIfSaved() { + const id = parseInt(wsIdInput.val() || '0', 10); + btnAddPackage.prop('disabled', id <= 0); + } + enablePackageButtonIfSaved(); + + // Ogni volta che salvi la testata, riabilita anche questo bottone + const _origEnableMix = enableMixButtonIfSaved; + enableMixButtonIfSaved = function() { + _origEnableMix(); + enablePackageButtonIfSaved(); + }; + enableMixButtonIfSaved(); + + // Click: aggiungi imballo + btnAddPackage.on('click', function() { + const wsId = parseInt(wsIdInput.val() || '0', 10); + if (wsId <= 0) { + Swal.fire({ + icon: 'warning', + title: 'Salva prima la testata', + timer: 1500 + }); + return; + } + + const packageCode = $('#requested_package_code').val(); + if (!packageCode) { + Swal.fire({ + icon: 'warning', + title: 'Seleziona un imballo', + timer: 1500 + }); + return; + } + + fetch('', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: `ajax=1&action=save_package_row&worksheet_id=${wsId}&package_code=${encodeURIComponent(packageCode)}` + }) + .then(r => r.json()) + .then(data => { + if (data.success) { + Swal.fire({ + icon: 'success', + title: 'Imballo aggiunto!', + timer: 800 + }) + .then(() => location.reload()); + } else { + Swal.fire({ + icon: 'error', + title: 'Errore', + text: data.message + }); + } + }) + .catch(err => { + Swal.fire({ + icon: 'error', + title: 'Errore', + text: err.message + }); + }); + }); + + // Click: elimina imballo + $(document).on('click', '.delete-package', function() { + const rowId = $(this).data('id'); + + Swal.fire({ + title: 'Eliminare questo imballo dal foglio?', + icon: 'warning', + showCancelButton: true, + confirmButtonColor: '#d33', + cancelButtonColor: '#6c757d', + confirmButtonText: 'Sì, elimina', + cancelButtonText: 'Annulla' + }).then(result => { + if (!result.isConfirmed) return; + + fetch('', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: `ajax=1&action=delete_package_row&row_id=${rowId}` + }) + .then(r => r.json()) + .then(data => { + if (data.success) { + Swal.fire({ + icon: 'success', + title: 'Eliminato!', + timer: 800 + }) + .then(() => location.reload()); + } else { + Swal.fire({ + icon: 'error', + title: 'Errore', + text: data.message + }); + } + }); + }); + }); }); diff --git a/public/userarea/production_line_view2.php b/public/userarea/production_line_view2.php index 51c91434..dc4da228 100644 --- a/public/userarea/production_line_view2.php +++ b/public/userarea/production_line_view2.php @@ -9,6 +9,17 @@ $pdo = $db->getConnection(); // --- LISTE LINEE --- $linee = $pdo->query("SELECT id, name, color FROM production_lines ORDER BY line_number")->fetchAll(); +// --- LINEA PREFERITA DELL'UTENTE (NULL = Tutte) --- +$preferredLineId = null; +if (!empty($iduserlogin)) { + $stmtPref = $pdo->prepare("SELECT preferred_line_id FROM auth_users WHERE id = :uid LIMIT 1"); + $stmtPref->execute(['uid' => (int)$iduserlogin]); + $val = $stmtPref->fetchColumn(); + if ($val !== false && $val !== null) { + $preferredLineId = (int)$val; + } +} + // --- STATUS DINAMICI --- $statusProgrammato = $pdo->query("SELECT id, nome, badge_color, line_color FROM production_status WHERE id = 6 LIMIT 1")->fetch(); $statusProduzione = $pdo->query("SELECT id, nome, badge_color, line_color FROM production_status WHERE id = 2 LIMIT 1")->fetch(); @@ -988,6 +999,38 @@ if (!empty($_GET['ajax'])) { color: #475569 !important; } + /* --- TAB LINEE (selezione singola) --- */ + .line-tab { + flex: 1 1 auto; + min-width: 130px; + padding: 0.9rem 0.5rem; + font-size: 1.3rem; + font-weight: 800; + border: 2px solid #e2e8f0; + border-radius: 0.9rem 0.9rem 0 0; + background: #f1f5f9; + color: #64748b; + cursor: pointer; + transition: 0.15s; + letter-spacing: 0.5px; + } + + .line-tab:hover { + background: #e2e8f0; + } + + .line-tab.active { + background: var(--line-color, #1d4ed8); + color: #fff; + border-color: transparent; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); + } + + /* il tab "TUTTI" attivo usa un blu neutro */ + .line-tab[data-line="all"].active { + background: #1d4ed8; + } + /* Modale più grande e ottimizzata */ .custom-modal .modal-content.final-wide { @@ -1329,25 +1372,21 @@ if (!empty($_GET['ajax'])) {
-
- - -
+
+
+ - -
- +
-
@@ -1671,43 +1710,32 @@ if (!empty($_GET['ajax'])) { beep.play().catch(() => {}); } - // --- BOTTONI LINEE --- - let selectedLines = []; + // --- TAB LINEE (selezione singola) --- + // Imposta il filtro nascosto in base al tab: "all" = vuoto (tutte), altrimenti l'id. + function setActiveTab($tab) { + $('#lineTabs .line-tab').removeClass('active'); + $tab.addClass('active'); + const line = $tab.data('line'); + $('#filterLine').val(line === 'all' ? '' : String(line)); + } - // inizialmente selezioniamo tutte - $('#lineButtons .line-btn').each(function() { - selectedLines.push($(this).data('line')); - }); - $('#filterLine').val(selectedLines.join(',')); - - - // logica pulsanti - $(document).on('click', '.line-btn', function() { - const id = $(this).data('line'); - - if ($(this).hasClass('active')) { - // se la deseleziono - $(this).removeClass('active').addClass('inactive'); - selectedLines = selectedLines.filter(l => l !== id); - } else { - // se la seleziono - $(this).removeClass('inactive').addClass('active'); - selectedLines.push(id); - } - - // assicurati che non sia vuoto - if (selectedLines.length === 0) { - // se deselezionano tutto → riseleziona tutto - $('#lineButtons .line-btn').removeClass('inactive').addClass('active'); - selectedLines = $('#lineButtons .line-btn').map(function() { - return $(this).data('line'); - }).get(); - } - - $('#filterLine').val(selectedLines.join(',')); + // Click sui tab + $(document).on('click', '.line-tab', function() { + setActiveTab($(this)); loadRecords(); }); + // Tab iniziale: preferita dell'utente se impostata, altrimenti "TUTTI" + (function initLineTab() { + const pref = $('#preferredLine').val(); + let $start = $('#lineTabs .line-tab[data-line="all"]'); + if (pref !== '') { + const $prefTab = $('#lineTabs .line-tab[data-line="' + pref + '"]'); + if ($prefTab.length) $start = $prefTab; + } + setActiveTab($start); + })(); + function escapeHtml(str) { return String(str || '') .replace(/&/g, '&') diff --git a/public/userarea/user_settings.php b/public/userarea/user_settings.php index d4909b92..1b56e011 100644 --- a/public/userarea/user_settings.php +++ b/public/userarea/user_settings.php @@ -35,6 +35,15 @@ try { $countries = []; } +// Load production lines (per la preferenza "Linea preferita"). +$productionLines = []; +try { + $productionLines = $pdo->query("SELECT id, name FROM production_lines ORDER BY line_number ASC") + ->fetchAll(PDO::FETCH_ASSOC); +} catch (Exception $e) { + $productionLines = []; +} + // Load current user. $stmtProfileUser = $pdo->prepare(" SELECT @@ -48,6 +57,7 @@ $stmtProfileUser = $pdo->prepare(" address, country_id, birthday, + preferred_line_id, role_id, status, last_login @@ -126,6 +136,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $address = trim($_POST['address'] ?? ''); $countryId = $_POST['country_id'] !== '' ? (int)$_POST['country_id'] : null; $birthday = trim($_POST['birthday'] ?? ''); + $preferredLineId = (isset($_POST['preferred_line_id']) && $_POST['preferred_line_id'] !== '') + ? (int)$_POST['preferred_line_id'] + : null; $currentPassword = $_POST['current_password'] ?? ''; $newPassword = $_POST['new_password'] ?? ''; @@ -240,7 +253,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!$errorMessage) { try { $pdo->beginTransaction(); - $stmtUpdate = $pdo->prepare(" UPDATE auth_users SET @@ -252,6 +264,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { address = :address, country_id = :country_id, birthday = :birthday, + preferred_line_id = :preferred_line_id, updated_at = NOW() WHERE id = :id LIMIT 1 @@ -266,6 +279,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { ':address' => $address !== '' ? $address : null, ':country_id' => $countryId, ':birthday' => $birthdayValue, + ':preferred_line_id' => $preferredLineId, ':id' => $userId, ]); @@ -745,6 +759,20 @@ $avatarPath = normalizeAvatarPath($profileUser['avatar'] ?? '');
+
+ + +
La pagina Line View si aprirà su questa linea.
+
+