From 2f0f1135ac3de22945f6a449b099fe05dddd8de6 Mon Sep 17 00:00:00 2001 From: solocla Date: Mon, 26 Oct 2026 14:05:31 +0100 Subject: [PATCH] fixed manage worksheet --- public/userarea/manage-worksheet.php | 222 ++++++++++++++++++++++----- 1 file changed, 181 insertions(+), 41 deletions(-) diff --git a/public/userarea/manage-worksheet.php b/public/userarea/manage-worksheet.php index 48228802..9d9ae40b 100644 --- a/public/userarea/manage-worksheet.php +++ b/public/userarea/manage-worksheet.php @@ -1462,6 +1462,7 @@ $isEdit = ($worksheet_id > 0); +
@@ -1684,7 +1685,7 @@ $isEdit = ($worksheet_id > 0); // Prepare modal for add $('#mixModal').on('show.bs.modal', function() { const wsId = parseInt(wsIdInput.val() || '0', 10); - if (wsId <= 0) { + if (wsId <= 0 && !window.importStaged) { Swal.fire({ icon: 'warning', title: 'Salva prima la testata', @@ -1693,12 +1694,12 @@ $isEdit = ($worksheet_id > 0); return false; } - // Se stiamo modificando una riga esistente, non resettare il form - if (parseInt($('#mixRowId').val() || '0', 10) > 0) { + // Se stiamo modificando una riga esistente o provvisoria, non resettare il form + if (parseInt($('#mixRowId').val() || '0', 10) > 0 || $('#mixStagedIdx').val() !== '') { return; } - $('#mixModalTitle').text('Aggiungi Mescola'); + $('#mixModalTitle').text(wsId > 0 ? 'Aggiungi Mescola' : 'Aggiungi Mescola (verrà salvata con la testata)'); $('#mixForm')[0].reset(); $('#mixRowId').val('0'); $('#mixWorksheetId').val(wsId); @@ -1706,6 +1707,11 @@ $isEdit = ($worksheet_id > 0); $('#lubrication_type').val(''); }); + $('#mixModal').on('hidden.bs.modal', function() { + $('#mixStagedIdx').val(''); + $('#mixRowId').val('0'); + }); + // Edit mix row $(document).on('click', '.edit-mix', function() { let row = $(this).attr('data-row'); @@ -1735,6 +1741,11 @@ $isEdit = ($worksheet_id > 0); $('#mixForm').on('submit', function(e) { e.preventDefault(); + if (parseInt(wsIdInput.val() || '0', 10) <= 0 && window.importStaged) { + window.stageMixFromForm(); + return; + } + const formData = new FormData(this); formData.append('ajax', '1'); formData.append('action', 'save_mix_row'); @@ -1823,6 +1834,19 @@ $isEdit = ($worksheet_id > 0); // Click: aggiungi imballo btnAddPackage.on('click', function() { const wsId = parseInt(wsIdInput.val() || '0', 10); + if (wsId <= 0 && window.importStaged) { + const code = $('#requested_package_code').val(); + if (!code) { + Swal.fire({ + icon: 'warning', + title: 'Seleziona un imballo', + timer: 1500 + }); + return; + } + window.stagePackage(code, $('#requested_package_code option:selected').text(), $('#packaging_category').val()); + return; + } if (wsId <= 0) { Swal.fire({ icon: 'warning', @@ -1922,40 +1946,53 @@ $isEdit = ($worksheet_id > 0); $(function() { window.importStaged = null; + function escH(v) { + return $('
').text(v == null ? '' : String(v)).html(); + } + + function stagedButtons() { + // con import in corso si può lavorare anche prima del salvataggio + if (window.importStaged) $('#btnAddMix, #btnAddPackage').prop('disabled', false); + } + function renderPendingPackages(packages) { $('#packageRowsBody tr.import-pending').remove(); $('#packageImportNote').remove(); const $tb = $('#packageRowsBody'); const nonAbbinati = []; + const rows = []; - (packages || []).forEach(function(p) { - // righe solo per gli imballi ABBINATI (sicuri o proposti) + (packages || []).forEach(function(p, i) { + // righe solo per gli imballi ABBINATI (sicuri, proposti o aggiunti a mano) if (!p.package_code) { - nonAbbinati.push('“' + (p.raw || '') + '” (' + (p.source || '') + ')'); + nonAbbinati.push('“' + escH(p.raw) + '” (' + escH(p.source) + ')'); return; } - const stato = p.needs_review ? - '❓ proposto — verifica' : - '⏳ verrà aggiunto al salvataggio'; - const nome = p.matched_name || '—'; - const $tr = $( + const stato = p.manual ? + '➕ aggiunto, verrà salvato' : + (p.needs_review ? + '❓ proposto — verifica' : + '⏳ verrà salvato'); + const origine = p.manual ? 'aggiunto a mano' : ('dal file: ' + escH(p.raw) + ' (' + escH(p.source) + ')'); + rows.push( '' + '—' + - '' + (p.category || '—') + '' + - '
' + nome + '
' + - '
dal file: ' + (p.raw || '') + ' (' + (p.source || '') + ')
' + - '' + stato + '' + + '' + escH(p.category || '—') + '' + + '
' + escH(p.matched_name || '—') + '
' + + '
' + origine + '
' + + '' + stato + + ' ' + '' ); - $tb.prepend($tr); }); + $tb.prepend(rows.join('')); // nota per gli imballi NON abbinati (niente righe vuote) if (nonAbbinati.length) { const $note = $( '
' + '⚠ Dal file non abbinati automaticamente: ' + nonAbbinati.join(', ') + - '. Aggiungili a mano qui sotto se servono.' + + '. Se servono, sceglili qui sopra e premi “Aggiungi imballo”.' + '
' ); $('#packageRowsBody').closest('.table-wrap').before($note); @@ -1963,29 +2000,137 @@ $isEdit = ($worksheet_id > 0); } function renderPendingMescole(mescole) { - // rimuove eventuali righe provvisorie precedenti + // rimuove eventuali righe provvisorie precedenti e la riga "nessun dato" di DataTables $('#tabellaMixRows tbody tr.import-pending').remove(); + $('#tabellaMixRows tbody td.dataTables_empty').closest('tr').remove(); const $tb = $('#tabellaMixRows tbody'); - (mescole || []).forEach(function(m) { - if (!m.idmescola) return; // le non riconosciute passano dal modal, non qui - const nome = m.matched_name || m.raw || '-'; - const $tr = $( + const rows = []; + (mescole || []).forEach(function(m, i) { + const nome = m.idmescola ? + escH(m.matched_name || m.raw || '-') : + '⚠ da abbinare'; + const origine = m.manual ? 'aggiunta a mano' : ('dal file: ' + escH(m.raw)); + const stato = m.idmescola ? + '⏳ verrà salvata' : + '❓ scegli la mescola'; + rows.push( '' + '—' + '
' + nome + '
' + - '
dal file: ' + (m.raw || '') + '
' + - '' + (m.mix_weight_g_m ?? '-') + '' + - '' + (m.support_weight_g_m ?? '-') + '' + - '' + (m.required_density ?? '-') + '' + - '' + (m.required_hardness_shore_a ?? '-') + '' + - '' + (m.lubrication_type ?? '-') + '' + - '⏳ verrà aggiunta al salvataggio' + + '
' + origine + '
' + + '' + escH(m.mix_weight_g_m ?? '-') + '' + + '' + escH(m.support_weight_g_m ?? '-') + '' + + '' + escH(m.required_density || '-') + '' + + '' + escH(m.required_hardness_shore_a || '-') + '' + + '' + escH(m.lubrication_type || '-') + '' + + '' + stato + '
' + + ' ' + + '' + + '' + '' ); - $tb.prepend($tr); }); + $tb.prepend(rows.join('')); } + // ---- modifica della lista provvisoria (prima del salvataggio) ---- + window.stagePackage = function(code, label, category) { + const st = window.importStaged; + if (!st) return; + if (st.packages.some(p => String(p.package_code) === String(code))) { + Swal.fire({ + icon: 'warning', + title: 'Imballo già presente', + timer: 1500 + }); + return; + } + st.packages.push({ + package_code: code, + matched_name: label, + category: category || '', + raw: '', + source: 'manuale', + needs_review: false, + manual: true + }); + renderPendingPackages(st.packages); + $('#requested_package_code').val(''); + }; + + $(document).on('click', '.staged-pkg-del', function() { + const st = window.importStaged; + if (!st) return; + st.packages.splice(parseInt($(this).data('i'), 10), 1); + renderPendingPackages(st.packages); + }); + + $(document).on('click', '.staged-mix-del', function() { + const st = window.importStaged; + if (!st) return; + st.mescole.splice(parseInt($(this).data('i'), 10), 1); + renderPendingMescole(st.mescole); + }); + + $(document).on('click', '.staged-mix-edit', function() { + const st = window.importStaged; + if (!st) return; + const i = parseInt($(this).data('i'), 10); + const m = st.mescole[i]; + if (!m) return; + + $('#mixForm')[0].reset(); + $('#mixRowId').val('0'); + $('#mixStagedIdx').val(i); + $('#mixModalTitle').text(m.idmescola ? 'Modifica mescola (non ancora salvata)' : 'Mescola dal file: ' + (m.raw || '') + ' — seleziona la corrispondenza'); + $('#idmescola').prop('disabled', false).val(m.idmescola ? String(m.idmescola) : '').trigger('change'); + $('#mix_weight_g_m').val(m.mix_weight_g_m ?? ''); + $('#support_weight_g_m').val(m.support_weight_g_m ?? ''); + $('#required_density').val(m.required_density ?? ''); + $('#required_hardness_shore_a').val(m.required_hardness_shore_a ?? ''); + $('#lubrication_type').val(m.lubrication_type ?? ''); + $('#lubrication_notes').val(m.lubrication_notes ?? ''); + + bootstrap.Modal.getOrCreateInstance(document.getElementById('mixModal')).show(); + }); + + // salvataggio del modal mescola quando il foglio non esiste ancora + window.stageMixFromForm = function() { + const st = window.importStaged; + if (!st) return; + const idm = $('#idmescola').val(); + if (!idm) { + Swal.fire({ + icon: 'warning', + title: 'Seleziona una mescola', + timer: 1500 + }); + return; + } + const idxTxt = $('#mixStagedIdx').val(); + const old = idxTxt !== '' ? (st.mescole[parseInt(idxTxt, 10)] || {}) : {}; + const m = Object.assign({}, old, { + idmescola: idm, + matched_name: $.trim($('#idmescola option:selected').text()), + needs_review: false, + mix_weight_g_m: $('#mix_weight_g_m').val(), + support_weight_g_m: $('#support_weight_g_m').val(), + required_density: $('#required_density').val(), + required_hardness_shore_a: $('#required_hardness_shore_a').val(), + lubrication_type: $('#lubrication_type').val(), + lubrication_notes: $('#lubrication_notes').val() + }); + if (idxTxt !== '') { + st.mescole[parseInt(idxTxt, 10)] = m; + } else { + m.raw = ''; + m.manual = true; + st.mescole.push(m); + } + renderPendingMescole(st.mescole); + bootstrap.Modal.getOrCreateInstance(document.getElementById('mixModal')).hide(); + }; + function postForm(obj) { return fetch('', { method: 'POST', @@ -2027,7 +2172,7 @@ $isEdit = ($worksheet_id > 0); bits.push('Mescola “' + m.raw + '” ' + (m.idmescola ? '✓' : '⚠ da abbinare a mano'))); (data.packages || []).forEach(p => bits.push('Imballo “' + p.raw + '” (' + p.source + ') ' + (p.package_code ? '✓' : '⚠ da aggiungere a mano'))); - let html = '
Import completato. Controlla i campi evidenziati in giallo, poi premi “Salva testata”.'; + let html = '
Import completato. Controlla i campi evidenziati in giallo. Imballi e mescole in giallo si possono togliere (🗑️), correggere o aggiungere: al “Salva testata” viene salvato quello che vedi in tabella.'; if (bits.length) html += '
    ' + bits.map(b => '
  • ' + b + '
  • ').join('') + '
'; if ((data.warnings || []).length) html += '
' + data.warnings.join('
') + '
'; html += '
'; @@ -2048,17 +2193,15 @@ $isEdit = ($worksheet_id > 0); const matchedMescole = []; const unmatchedMescole = []; - // imballi: salva solo quelli SICURI; i proposti li segnaliamo da confermare + // imballi: salva quelli rimasti in tabella (sicuri, proposti non tolti, aggiunti a mano) for (const p of (staged.packages || [])) { - if (p.package_code && !p.needs_review) { + if (p.package_code) { await postForm({ ajax: 1, action: 'save_package_row', worksheet_id: newId, package_code: p.package_code }); - } else if (p.package_code && p.needs_review) { - unresolvedPkgs.push('Imballo “' + p.raw + '” (' + p.source + ') → proposto: ' + (p.matched_name || '') + ' — verifica e aggiungi a mano'); } else { unresolvedPkgs.push('Imballo “' + p.raw + '” (' + p.source + ') → nessun abbinamento, aggiungi a mano'); } @@ -2082,7 +2225,7 @@ $isEdit = ($worksheet_id > 0); required_density: m.required_density ?? '', required_hardness_shore_a: m.required_hardness_shore_a ?? '', lubrication_type: m.lubrication_type ?? '', - lubrication_notes: '' + lubrication_notes: m.lubrication_notes ?? '' }); } @@ -2211,10 +2354,6 @@ $isEdit = ($worksheet_id > 0); setVal('meters_per_package_tolerance', h.meters_per_package_tolerance); setVal('meters_per_package_notes', h.meters_per_package_notes); setVal('meters_per_box', h.meters_per_box); - setVal('meters_per_package', h.meters_per_package); - setVal('meters_per_package_tolerance', h.meters_per_package_tolerance); - setVal('meters_per_package_notes', h.meters_per_package_notes); - setVal('meters_per_box', h.meters_per_box); setVal('packages_or_pieces_per_box', h.packages_or_pieces_per_box); setVal('boxes_or_packages_per_pallet', h.boxes_or_packages_per_pallet); setVal('speed_expected_kg_h', h.speed_expected_kg_h); @@ -2234,6 +2373,7 @@ $isEdit = ($worksheet_id > 0); renderBanner(data); renderPendingMescole(data.mescole || []); renderPendingPackages(data.packages || []); + stagedButtons(); Swal.fire({ icon: 'success',