fixed manage worksheet
This commit is contained in:
@@ -1462,6 +1462,7 @@ $isEdit = ($worksheet_id > 0);
|
||||
<input type="hidden" name="worksheet_id" id="mixWorksheetId" value="<?= (int)$worksheet_id ?>">
|
||||
<input type="hidden" name="row_id" id="mixRowId" value="0">
|
||||
<input type="hidden" name="mix_position" id="mix_position" value="">
|
||||
<input type="hidden" id="mixStagedIdx" value="">
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-6">
|
||||
@@ -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 $('<div>').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 ?
|
||||
'<span class="pending-badge">❓ proposto — verifica</span>' :
|
||||
'<span class="pending-badge">⏳ verrà aggiunto al salvataggio</span>';
|
||||
const nome = p.matched_name || '—';
|
||||
const $tr = $(
|
||||
const stato = p.manual ?
|
||||
'<span class="pending-badge">➕ aggiunto, verrà salvato</span>' :
|
||||
(p.needs_review ?
|
||||
'<span class="pending-badge">❓ proposto — verifica</span>' :
|
||||
'<span class="pending-badge">⏳ verrà salvato</span>');
|
||||
const origine = p.manual ? 'aggiunto a mano' : ('dal file: ' + escH(p.raw) + ' (' + escH(p.source) + ')');
|
||||
rows.push(
|
||||
'<tr class="import-pending">' +
|
||||
'<td>—</td>' +
|
||||
'<td>' + (p.category || '—') + '</td>' +
|
||||
'<td><div class="fw-bold">' + nome + '</div>' +
|
||||
'<div class="text-muted small">dal file: ' + (p.raw || '') + ' (' + (p.source || '') + ')</div></td>' +
|
||||
'<td>' + stato + '</td>' +
|
||||
'<td>' + escH(p.category || '—') + '</td>' +
|
||||
'<td><div class="fw-bold">' + escH(p.matched_name || '—') + '</div>' +
|
||||
'<div class="text-muted small">' + origine + '</div></td>' +
|
||||
'<td class="text-nowrap">' + stato +
|
||||
' <button type="button" class="btn btn-sm btn-outline-danger staged-pkg-del ms-1" data-i="' + i + '" title="Togli">🗑️</button></td>' +
|
||||
'</tr>'
|
||||
);
|
||||
$tb.prepend($tr);
|
||||
});
|
||||
$tb.prepend(rows.join(''));
|
||||
|
||||
// nota per gli imballi NON abbinati (niente righe vuote)
|
||||
if (nonAbbinati.length) {
|
||||
const $note = $(
|
||||
'<div id="packageImportNote" class="import-hint" style="margin-bottom:10px;">' +
|
||||
'⚠ Dal file non abbinati automaticamente: ' + nonAbbinati.join(', ') +
|
||||
'. Aggiungili a mano qui sotto se servono.' +
|
||||
'. Se servono, sceglili qui sopra e premi “Aggiungi imballo”.' +
|
||||
'</div>'
|
||||
);
|
||||
$('#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 || '-') :
|
||||
'<span style="color:#b45309;">⚠ da abbinare</span>';
|
||||
const origine = m.manual ? 'aggiunta a mano' : ('dal file: ' + escH(m.raw));
|
||||
const stato = m.idmescola ?
|
||||
'<span class="pending-badge">⏳ verrà salvata</span>' :
|
||||
'<span class="pending-badge">❓ scegli la mescola</span>';
|
||||
rows.push(
|
||||
'<tr class="import-pending">' +
|
||||
'<td>—</td>' +
|
||||
'<td><div class="fw-bold">' + nome + '</div>' +
|
||||
'<div class="text-muted small">dal file: ' + (m.raw || '') + '</div></td>' +
|
||||
'<td>' + (m.mix_weight_g_m ?? '-') + '</td>' +
|
||||
'<td>' + (m.support_weight_g_m ?? '-') + '</td>' +
|
||||
'<td>' + (m.required_density ?? '-') + '</td>' +
|
||||
'<td>' + (m.required_hardness_shore_a ?? '-') + '</td>' +
|
||||
'<td>' + (m.lubrication_type ?? '-') + '</td>' +
|
||||
'<td><span class="pending-badge">⏳ verrà aggiunta al salvataggio</span></td>' +
|
||||
'<div class="text-muted small">' + origine + '</div></td>' +
|
||||
'<td>' + escH(m.mix_weight_g_m ?? '-') + '</td>' +
|
||||
'<td>' + escH(m.support_weight_g_m ?? '-') + '</td>' +
|
||||
'<td>' + escH(m.required_density || '-') + '</td>' +
|
||||
'<td>' + escH(m.required_hardness_shore_a || '-') + '</td>' +
|
||||
'<td>' + escH(m.lubrication_type || '-') + '</td>' +
|
||||
'<td class="text-nowrap">' + stato + '<br>' +
|
||||
'<button type="button" class="btn btn-sm btn-outline-primary staged-mix-edit mt-1" data-i="' + i + '">✏️ Modifica</button> ' +
|
||||
'<button type="button" class="btn btn-sm btn-outline-danger staged-mix-del mt-1" data-i="' + i + '" title="Togli">🗑️</button>' +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
$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 = '<div class="import-banner"><strong>Import completato.</strong> Controlla i campi evidenziati in giallo, poi premi “Salva testata”.';
|
||||
let html = '<div class="import-banner"><strong>Import completato.</strong> 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 += '<ul style="margin:8px 0 0 18px;">' + bits.map(b => '<li>' + b + '</li>').join('') + '</ul>';
|
||||
if ((data.warnings || []).length) html += '<div style="color:#b45309;margin-top:6px;">' + data.warnings.join('<br>') + '</div>';
|
||||
html += '</div>';
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user