Compare commits

..

4 Commits

Author SHA1 Message Date
solocla 9969cc9edc partstable fixed matrici dropdown 2025-10-28 09:31:13 +01:00
solocla 8d6fe92481 fixed multiple parts mix and single line 2025-10-28 08:58:39 +01:00
solocla dbc66723a6 fixed color save 2025-10-27 15:53:12 +01:00
solocla 218fc14462 fixed country client and parts column matrice 2025-10-27 14:38:20 +01:00
6 changed files with 478 additions and 201 deletions
File diff suppressed because one or more lines are too long
+8 -4
View File
@@ -1084,7 +1084,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
clientData.forEach(client => { clientData.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile"; const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile"; const id = client.IdCliente || "ID non disponibile";
const option = new Option(`${nome.trim()} (ID: ${id})`, id); const option = new Option(`${nome.trim()} - ${client.CodiceNazioneFatturazione} (ID: ${id})`, id);
if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) { if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) {
option.selected = true; option.selected = true;
} }
@@ -1116,7 +1116,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
clientData.forEach(client => { clientData.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile"; const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile"; const id = client.IdCliente || "ID non disponibile";
const option = new Option(`${nome.trim()} (ID: ${id})`, id); const option = new Option(`${nome.trim()} - ${client.CodiceNazioneFatturazione} (ID: ${id})`, id);
if (String(id) === String(currentValue)) { if (String(id) === String(currentValue)) {
option.selected = true; option.selected = true;
} }
@@ -1347,7 +1347,9 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
clientData.forEach(client => { clientData.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile"; const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile"; const id = client.IdCliente || "ID non disponibile";
const option = new Option(`${nome.trim()} (ID: ${id})`, id); const codice = (client.CodiceNazioneFatturazione || '').trim();
const option = new Option(`${nome.trim()} - ${codice} (ID: ${id})`, id);
if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) { if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) {
option.selected = true; option.selected = true;
} }
@@ -1377,7 +1379,9 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
clientData.forEach(client => { clientData.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile"; const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile"; const id = client.IdCliente || "ID non disponibile";
const option = new Option(`${nome.trim()} (ID: ${id})`, id); const codice = (client.CodiceNazioneFatturazione || '').trim();
const option = new Option(`${nome.trim()} - ${codice} (ID: ${id})`, id);
if (String(id) === String(currentValue)) { if (String(id) === String(currentValue)) {
option.selected = true; option.selected = true;
} }
@@ -13,13 +13,13 @@ if (session_status() == PHP_SESSION_NONE) {
} }
// Imposta variabili di sessione di default per evitare errori // Imposta variabili di sessione di default per evitare errori
$_SESSION['iduserlogin'] = null; // Nessun utente loggato $_SESSION['iduserlogin'] = '1'; // Nessun utente loggato
$_SESSION['nameuser'] = 'Ospite'; $_SESSION['nameuser'] = 'Ospite';
$_SESSION['surnameuser'] = ''; $_SESSION['surnameuser'] = '';
$_SESSION['emailuser'] = ''; $_SESSION['emailuser'] = '';
$_SESSION['photouser'] = ''; $_SESSION['photouser'] = '';
$photouser = $_SESSION['photouser']; $photouser = $_SESSION['photouser'];
$photousername = ''; $photousername = '';
$iduserlogin = $_SESSION['iduserlogin'];
// Include file di lingua, se necessario // Include file di lingua, se necessario
require_once(__DIR__ . '/../../languages/en/general.php'); require_once(__DIR__ . '/../../languages/en/general.php');
+222 -71
View File
@@ -143,172 +143,323 @@
</div> </div>
<style> <style>
/* --- Base --- */
#partsModal { #partsModal {
z-index: 1060 !important; z-index: 1060 !important
} }
#partsModal .modal-backdrop { #partsModal .modal-backdrop {
z-index: 1055 !important; z-index: 1055 !important
} }
#partsModal .modal-content { #partsModal .modal-content {
width: 100% !important; width: 100% !important;
max-width: 100% !important; max-width: 100% !important
} }
/* Tabelle */
#partsTable tr { #partsTable tr {
display: table-row !important; display: table-row !important
} }
#partsTable tr:hover { #partsTable tr:hover {
background-color: #f5f5f5; background: #f5f5f5
display: table-row !important;
} }
#partsTable td, #partsTable td,
#partsTable th { #partsTable th {
padding: 0.2rem; padding: .2rem;
vertical-align: middle; vertical-align: middle
} }
#partsTable input, #partsTable input,
#partsTable select { #partsTable select {
height: 24px; height: 24px;
padding: 0.1rem 0.3rem; padding: .1rem .3rem
} }
#partsTable button { #partsTable button {
padding: 0.1rem 0.3rem; padding: .1rem .3rem;
margin: 0 2px; margin: 0 2px
} }
#partsTable i { #partsTable i {
font-size: 0.6rem !important; font-size: .6rem !important
} }
#global-matrice, /* --- Larghezze fisse header --- */
.part-matrice, /* MacroMatrici = 250px */
#macro-matrice-filter { #macro-matrice-filter {
width: 100% !important; width: 250px !important;
min-width: 100% !important; min-width: 250px !important;
max-width: 250px !important;
flex: 0 0 250px !important;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.select2-container--default #global-matrice { #macro-matrice-filter.select2-hidden-accessible+.select2 {
width: 350px !important; width: 250px !important;
min-width: 250px !important;
max-width: 250px !important;
flex: 0 0 250px !important;
}
#macro-matrice-filter.select2-hidden-accessible+.select2 .select2-selection__rendered {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Matrice globale = 450px */
#global-matrice {
width: 450px !important;
min-width: 450px !important;
max-width: 450px !important;
flex: 0 0 450px !important;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#global-matrice.select2-hidden-accessible+.select2 {
width: 450px !important;
min-width: 450px !important;
max-width: 450px !important;
flex: 0 0 450px !important;
}
#global-matrice.select2-hidden-accessible+.select2 .select2-selection__rendered {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Select delle righe (colonna Matrice) = 150px */
.part-matrice {
width: 300px !important;
min-width: 300px !important;
max-width: 300px !important;
flex: 0 0 300px !important;
}
.part-matrice.select2-hidden-accessible+.select2 {
width: 300px !important;
min-width: 300px !important;
max-width: 300px !important;
flex: 0 0 300px !important;
}
/* Colonna Descrizione (2ª colonna) = 420px */
#partsTable th:nth-child(2),
#partsTable td:nth-child(2) {
width: 350 !important;
min-width: 350px !important; min-width: 350px !important;
max-width: 350px !important;
} }
.select2-container--default #macro-matrice-filter { #partsTable td:nth-child(2) .part-description {
width: 200px !important; width: 100% !important;
min-width: 200px !important; max-width: 100% !important;
} overflow: hidden;
text-overflow: ellipsis;
.select2-container--default .part-matrice { white-space: nowrap;
width: 150px !important;
min-width: 150px !important;
} }
/* Aspetto Select2 */
.select2-container--default .select2-selection--single { .select2-container--default .select2-selection--single {
height: 24px !important; height: 24px !important;
padding: 0.1rem 0.3rem !important; padding: .1rem .3rem !important;
font-size: 0.8rem !important; font-size: .8rem !important;
border: 1px solid #ced4da !important; border: 1px solid #ced4da !important;
} }
.select2-container--default .select2-selection__rendered {
line-height: 22px !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
.select2-container--default .select2-selection__arrow { .select2-container--default .select2-selection__arrow {
height: 24px !important; height: 24px !important
} }
.select2-container--open .select2-dropdown { .select2-container--open .select2-dropdown {
z-index: 1061 !important; z-index: 1061 !important;
border: 1px solid #aaa !important; border: 1px solid #aaa !important;
border-radius: 4px !important; border-radius: 4px !important;
background: white !important; background: #fff !important;
overflow-y: auto !important;
max-height: 200px !important; max-height: 200px !important;
overflow-y: auto !important;
} }
/* Evita stretching del flex nella riga dei filtri */
#partsModal .modal-body>.row .col-md-9>div[style*="display: flex"]>* {
flex: 0 0 auto;
}
/* Altri modali e pulsanti */
.propagate-matrice-btn, .propagate-matrice-btn,
.propagate-all-btn { .propagate-all-btn {
padding: 0.1rem 0.3rem !important; padding: .1rem .3rem !important;
font-size: 0.8rem !important; font-size: .8rem !important
} }
.save-status, .save-status,
.save-loading { .save-loading {
margin-left: 5px; margin-left: 5px
} }
#confirmDeleteModal { #confirmDeleteModal {
z-index: 1070 !important; z-index: 1070 !important
} }
#confirmDeleteModal .modal-backdrop { #confirmDeleteModal .modal-backdrop {
z-index: 1065 !important; z-index: 1065 !important
} }
.note-btn { .note-btn {
padding: 0.2rem 0.4rem !important; padding: .2rem .4rem !important;
/* Aumentato leggermente il padding per un pulsante più grande */ font-size: .9rem !important
font-size: 0.9rem !important;
/* Aumentato il font-size per un'icona più grande */
} }
.note-btn.has-note { .note-btn.has-note {
color: #dc3545 !important; color: #dc3545 !important
/* Rosso quando la nota è presente */
} }
#noteModal { #noteModal {
z-index: 1090 !important; z-index: 1090 !important
} }
#noteModal .modal-backdrop { #noteModal .modal-backdrop {
z-index: 1085 !important; z-index: 1085 !important
} }
#noteModal .modal-dialog { #noteModal .modal-dialog {
position: relative; position: relative;
z-index: 1090 !important; z-index: 1090 !important
} }
#noteModal textarea { #noteModal textarea,
resize: vertical; #commonNoteModal textarea {
} resize: vertical
.propagate-date-btn {
padding: 0.2rem 0.4rem !important;
font-size: 0.9rem !important;
}
.propagate-note-btn {
padding: 0.2rem 0.4rem !important;
font-size: 0.9rem !important;
} }
#commonNoteModal { #commonNoteModal {
z-index: 1095 !important; z-index: 1095 !important
/* Sopra #noteModal (1090) */
} }
#commonNoteModal .modal-backdrop { #commonNoteModal .modal-backdrop {
z-index: 1090 !important; z-index: 1090 !important
/* Sopra il backdrop di #noteModal (1085) */
} }
#commonNoteModal .modal-dialog { #commonNoteModal .modal-dialog {
position: relative; position: relative;
z-index: 1095 !important; z-index: 1095 !important
} }
#commonNoteModal textarea { /* Evidenza salvataggio riga nel parts table */
resize: vertical; /* Aumenta la specificità per le classi di flash */
table#partsTable tr.row-saving {
background-color: #f0ad4e !important;
/* Arancione per salvataggio in corso */
transition: background-color 0.3s ease;
} }
table#partsTable tr.row-success {
background-color: #5cb85c !important;
/* Verde per successo */
transition: background-color 0.3s ease;
}
table#partsTable tr.row-error {
background-color: #d9534f !important;
/* Rosso per errore */
transition: background-color 0.3s ease;
}
/* Stato base: nascosti (verrà sovrascritto dallo style inline di jQuery) */
#partsModal .save-loading,
#partsModal .save-status {
display: none;
align-items: center;
gap: 6px;
padding: 2px 8px;
border-radius: 999px;
font-weight: 700;
font-size: 12px;
line-height: 1.2;
margin-left: 5px;
}
/* Quando NON sono nascosti via style inline (jQuery .show()), forzali a inline-flex */
#partsModal .save-loading:not([style*="display: none"]),
#partsModal .save-status:not([style*="display: none"]) {
display: inline-flex;
}
/* Loading (giallo) */
/* Loading (giallo) */
#partsModal .save-loading {
background: #ffd753ff;
border: 1px solid #ffd042ff;
color: #111;
/* testo nero */
}
#partsModal .save-loading i {
color: #111;
}
/* icona nera */
#partsModal .save-loading::after {
content: " Salvataggio…";
color: #111;
}
/* Salvato (verde) */
#partsModal .save-status {
background: #5dff83ff;
border: 1px solid #4effafff;
color: #111;
/* testo nero */
}
#partsModal .save-status i {
color: #111;
}
/* icona nera */
#partsModal .save-status::after {
content: " Salvato";
color: #111;
}
/* Animazioni */
@keyframes pulse {
0%,
100% {
transform: scale(1);
opacity: .9
}
50% {
transform: scale(1.05);
opacity: 1
}
}
@keyframes pop {
0% {
transform: scale(.85);
opacity: 0
}
100% {
transform: scale(1);
opacity: 1
}
}
/* rosso */
</style> </style>
+242 -120
View File
@@ -7,6 +7,35 @@ $(document).ready(function () {
let matrici = []; let matrici = [];
let macroMatrici = []; let macroMatrici = [];
// --- ROW ID helpers: niente più cache impazzita di jQuery .data() ---
function getPartId($row) {
// Legge in ordine: cache jQuery, nostra cache, attributo
const d = $row.data("part-id");
const ours = $row.data("__pid");
const attr = $row.attr("data-part-id");
// Scegli il primo definito
const id =
d !== undefined
? d
: ours !== undefined
? ours
: attr !== undefined
? attr
: null;
// Normalizza: "new" o "" NON sono ID validi
return id === "new" || id === "" || id === null ? null : id;
}
function setPartId($row, id) {
if (!id) return;
// Sincronizza TUTTO: attributo + cache jQuery + nostra cache
$row.attr("data-part-id", id);
$row.data("part-id", id); // <<< fondamentale per invalidare la cache di jQuery
$row.data("__pid", id);
}
// =================== // ===================
// VOICE RECOGNITION SETUP // VOICE RECOGNITION SETUP
// =================== // ===================
@@ -439,6 +468,7 @@ $(document).ready(function () {
$(document).on("click", ".add-mix-global", function (e) { $(document).on("click", ".add-mix-global", function (e) {
e.preventDefault(); e.preventDefault();
const maxPartNumber = Math.max( const maxPartNumber = Math.max(
...$("#partsTableBody tr") ...$("#partsTableBody tr")
.map(function () { .map(function () {
@@ -446,36 +476,177 @@ $(document).ready(function () {
}) })
.get(), .get(),
); );
addNewRow(maxPartNumber + 1, true); // Riga Mix
// Crea la riga Mix
addNewRow(maxPartNumber + 1, true);
const $mixRow = $("#partsTableBody tr:last");
// Consenti SOLO ora la creazione (INSERT) della riga Mix
$mixRow.data("allowCreateMix", true);
// esegue SUBITO l'INSERT così ottieni part-id
saveRow($mixRow);
}); });
function extractPartId(response) {
// prova i campi più comuni
if (response == null) return null;
if (response.part_id) return response.part_id;
if (response.id) return response.id;
if (response.insert_id) return response.insert_id;
if (response.lastId) return response.lastId;
// array di id
if (Array.isArray(response.part_ids) && response.part_ids[0]) {
return response.part_ids[0];
}
// oggetti annidati
if (response.parts && response.parts[0]) {
if (response.parts[0].id) return response.parts[0].id;
if (response.parts[0].part_id) return response.parts[0].part_id;
if (response.parts[0].insert_id) return response.parts[0].insert_id;
}
// altri possibili nomi dal backend
if (response.new_id) return response.new_id;
if (response.partId) return response.partId;
return null;
}
function saveRow($row) {
const partNumber = $row.find(".part-number").val();
const partDescription = $row.find(".part-description").val().trim();
const dateexpiry = $row.find(".part-dateexpiry").val();
const note = $row.data("note") || null;
const $saveStatus = $row.find(".save-status");
const $saveLoading = $row.find(".save-loading");
const iddatadb = $("#partsModal").data("iddatadb");
const idquotations = $("#partsModal").data("idquotations");
const isMix = partDescription.startsWith("Mix") ? "Y" : "N";
let partId = getPartId($row);
if (partId === "new") partId = null; // difesa extra (non dovrebbe più servire, ma sicura)
const endpoint = idquotations
? "save_parts_quotation.php"
: "save_parts.php";
const data = idquotations ? { idquotations } : { iddatadb };
// Evita salvataggi concorrenti
if ($row.data("saving") === true) return;
// Blocca INSERT del Mix se non esplicitamente richiesta
if (isMix === "Y" && !partId && $row.data("allowCreateMix") !== true) {
return;
}
$row.data("saving", true);
if (partDescription && (iddatadb || idquotations)) {
$saveLoading.show();
$saveStatus.hide();
$.ajax({
url: endpoint,
method: "POST",
data: JSON.stringify({
...data,
parts: [
{
id: partId,
part_number: partNumber,
part_description: partDescription,
mix: isMix,
dateexpiry: dateexpiry || null,
note: note,
},
],
}),
contentType: "application/json",
success: function (response) {
// assegna ID appena arriva (robusto)
if (response.success) {
const newId = extractPartId(response);
if (newId) {
setPartId($row, newId);
} else {
console.warn(
"Parte salvata ma ID non presente nella risposta. Ricarico parti per sincronizzare gli ID.",
);
loadExistingParts(iddatadb, idquotations); // <<< ORA ANCHE PER RIGHE NORMALI
}
}
$row.data("saving", false);
$row.removeData("allowCreateMix");
// ora che l'ID c'è di sicuro, sblocco gli update pendenti (es. M+)
$row.trigger("row:saved");
$saveLoading.hide();
if (response.success) {
$saveStatus.show();
setTimeout(() => $saveStatus.hide(), 2000);
} else {
const errorMsg = $(
'<div class="alert alert-danger temp-alert" role="alert">Errore nel salvataggio: ' +
response.message +
"</div>",
);
$("#partsModal .modal-body").prepend(errorMsg);
setTimeout(() => {
errorMsg.fadeOut(500, function () {
$(this).remove();
});
}, 5000);
}
},
error: function (xhr, status, error) {
$row.data("saving", false);
$row.removeData("allowCreateMix");
$saveLoading.hide();
const errorMsg = $(
'<div class="alert alert-danger temp-alert" role="alert">Errore nel salvataggio delle parti: ' +
error +
" (" +
xhr.status +
")</div>",
);
$("#partsModal .modal-body").prepend(errorMsg);
setTimeout(() => {
errorMsg.fadeOut(500, function () {
$(this).remove();
});
}, 5000);
},
});
}
}
$(document).on("click", ".add-mix-row", function (e) { $(document).on("click", ".add-mix-row", function (e) {
e.preventDefault(); e.preventDefault();
const $row = $(this).closest("tr");
const partDescription = $row.find(".part-description").val().trim(); const $srcRow = $(this).closest("tr");
const partDescription = $srcRow.find(".part-description").val().trim();
if (!partDescription) { if (!partDescription) {
const errorMsg = $( const errorMsg = $(
'<div class="alert alert-danger temp-alert" role="alert">Inserisci una descrizione valida prima di aggiungerla al Mix.</div>', '<div class="alert alert-danger temp-alert" role="alert">Inserisci una descrizione valida prima di aggiungerla al Mix.</div>',
); );
$("#partsModal .modal-body").prepend(errorMsg); $("#partsModal .modal-body").prepend(errorMsg);
setTimeout(function () { setTimeout(
() =>
errorMsg.fadeOut(500, function () { errorMsg.fadeOut(500, function () {
$(this).remove(); $(this).remove();
}); }),
}, 5000); 5000,
);
return; return;
} }
const maxPartNumber = Math.max( let $mixRow = $("#partsTableBody tr")
...$("#partsTableBody tr")
.map(function () {
return parseInt($(this).find(".part-number").val()) || 0;
})
.get(),
);
let mixDescription = `Mix ${partDescription}`;
const $mixRow = $("#partsTableBody tr")
.filter(function () { .filter(function () {
return $(this) return $(this)
.find(".part-description") .find(".part-description")
@@ -485,31 +656,59 @@ $(document).ready(function () {
}) })
.last(); .last();
if ($mixRow.length > 0) { // Se non esiste una riga Mix, ne creo una e la INSERISCO SUBITO (come fa il bottone in header)
let currentMix = $mixRow.find(".part-description").val().trim(); if ($mixRow.length === 0) {
if (currentMix === "Mix") { const maxPartNumber = Math.max(
mixDescription = currentMix + " " + partDescription; ...$("#partsTableBody tr")
} else if (!currentMix.includes(partDescription)) { .map(function () {
mixDescription = currentMix + " + " + partDescription; return (
parseInt($(this).find(".part-number").val()) || 0
);
})
.get(),
);
addNewRow(maxPartNumber + 1, true);
$mixRow = $("#partsTableBody tr:last");
$mixRow.find(".part-description").val(`Mix ${partDescription}`);
// Consenti la creazione (INSERT) della riga Mix e salvala subito
$mixRow.data("allowCreateMix", true);
saveRow($mixRow); // -> INSERT
return; // la descrizione include già l'elemento appena aggiunto
}
// Aggiorna la descrizione del Mix esistente
const currentMix = $mixRow.find(".part-description").val().trim();
let newDesc = currentMix;
if (currentMix === "Mix") newDesc = currentMix + " " + partDescription;
else if (!currentMix.includes(partDescription))
newDesc = currentMix + " + " + partDescription;
$mixRow.find(".part-description").val(newDesc);
// Se il Mix è già in salvataggio (INSERT o UPDATE in corso), accodiamo un solo UPDATE
if ($mixRow.data("saving") === true) {
// evita più code accumulate
if (!$mixRow.data("pendingUpdate")) {
$mixRow.data("pendingUpdate", true);
$mixRow.one("row:saved", function () {
$mixRow.removeData("pendingUpdate");
// ora che saving è false, salviamo l'ultima descrizione impostata
saveRow($mixRow);
});
} }
$mixRow
.find(".part-description")
.val(mixDescription)
.trigger("blur");
} else { } else {
addNewRow(maxPartNumber + 1, true); // Crea nuova riga Mix // libero: salva subito
const $newMixRow = $("#partsTableBody tr:last"); saveRow($mixRow);
$newMixRow
.find(".part-description")
.val(mixDescription)
.trigger("blur");
} }
}); });
function addNewRow(nextPartNumber, isMix = false) { function addNewRow(nextPartNumber, isMix = false) {
const description = isMix ? "Mix" : ""; const description = isMix ? "Mix" : "";
const newRow = ` const newRow = `
<tr data-part-id=""> <tr data-part-id="new">
<td><input type="number" class="form-control form-control-sm part-number" value="${nextPartNumber || 1}" style="width: 80px;"></td> <td><input type="number" class="form-control form-control-sm part-number" value="${nextPartNumber || 1}" style="width: 80px;"></td>
<td><input type="text" class="form-control form-control-sm part-description" value="${description}" placeholder="Inserisci descrizione"></td> <td><input type="text" class="form-control form-control-sm part-description" value="${description}" placeholder="Inserisci descrizione"></td>
<td> <td>
@@ -540,7 +739,7 @@ $(document).ready(function () {
// =================== // ===================
$(document).on("click", ".note-btn", function () { $(document).on("click", ".note-btn", function () {
const $row = $(this).closest("tr"); const $row = $(this).closest("tr");
const partId = $row.data("part-id"); const partId = getPartId($row);
const note = $row.data("note") || ""; const note = $row.data("note") || "";
const $noteModal = $("#noteModal"); const $noteModal = $("#noteModal");
$noteModal.find(".part-note").val(note); $noteModal.find(".part-note").val(note);
@@ -655,7 +854,7 @@ $(document).ready(function () {
$(document).on("change", ".part-dateexpiry", function () { $(document).on("change", ".part-dateexpiry", function () {
const $input = $(this); const $input = $(this);
const $row = $input.closest("tr"); const $row = $input.closest("tr");
const partId = $row.data("part-id"); const partId = getPartId($row);
const dateexpiry = $input.val(); const dateexpiry = $input.val();
const iddatadb = $("#partsModal").data("iddatadb"); const iddatadb = $("#partsModal").data("iddatadb");
const idquotations = $("#partsModal").data("idquotations"); const idquotations = $("#partsModal").data("idquotations");
@@ -953,88 +1152,7 @@ $(document).ready(function () {
}); });
$(document).on("blur", ".part-description, .part-number", function () { $(document).on("blur", ".part-description, .part-number", function () {
const $input = $(this); saveRow($(this).closest("tr"));
const $row = $input.closest("tr");
const partNumber = $row.find(".part-number").val();
const partDescription = $row.find(".part-description").val().trim();
const dateexpiry = $row.find(".part-dateexpiry").val();
const note = $row.data("note") || null;
const $saveStatus = $row.find(".save-status");
const $saveLoading = $row.find(".save-loading");
const iddatadb = $("#partsModal").data("iddatadb");
const idquotations = $("#partsModal").data("idquotations");
const isMix = partDescription.startsWith("Mix") ? "Y" : "N";
const partId = $row.data("part-id") || null;
const endpoint = idquotations
? "save_parts_quotation.php"
: "save_parts.php";
const data = idquotations
? { idquotations: idquotations }
: { iddatadb: iddatadb };
if (partDescription && (iddatadb || idquotations)) {
$saveLoading.show();
$saveStatus.hide();
$.ajax({
url: endpoint,
method: "POST",
data: JSON.stringify({
...data,
parts: [
{
id: partId,
part_number: partNumber,
part_description: partDescription,
mix: isMix,
dateexpiry: dateexpiry || null,
note: note,
},
],
}),
contentType: "application/json",
success: function (response) {
$saveLoading.hide();
if (response.success) {
$saveStatus.show();
if (response.part_id) {
$row.attr("data-part-id", response.part_id).data(
"part-id",
response.part_id,
);
}
setTimeout(() => $saveStatus.hide(), 2000);
} else {
const errorMsg = $(
'<div class="alert alert-danger temp-alert" role="alert">Errore nel salvataggio: ' +
response.message +
"</div>",
);
$("#partsModal .modal-body").prepend(errorMsg);
setTimeout(function () {
errorMsg.fadeOut(500, function () {
$(this).remove();
});
}, 5000);
}
},
error: function (xhr, status, error) {
$saveLoading.hide();
const errorMsg = $(
'<div class="alert alert-danger temp-alert" role="alert">Errore nel salvataggio delle parti: ' +
error +
" (" +
xhr.status +
")</div>",
);
$("#partsModal .modal-body").prepend(errorMsg);
setTimeout(function () {
errorMsg.fadeOut(500, function () {
$(this).remove();
});
}, 5000);
},
});
}
}); });
function loadExistingParts(iddatadb, idquotations) { function loadExistingParts(iddatadb, idquotations) {
@@ -1356,8 +1474,8 @@ $(document).ready(function () {
}, },
}); });
// Ripristina il valore se valido // === MODIFICA CHIRURGICA: solo qui ===
if (partId && partId !== "new" && currentValue) { if (currentValue && currentValue !== "new") {
const matrice = matrici.find((m) => m.IdMatrice == currentValue); const matrice = matrici.find((m) => m.IdMatrice == currentValue);
if (matrice) { if (matrice) {
const option = new Option( const option = new Option(
@@ -1369,11 +1487,15 @@ $(document).ready(function () {
$select.append(option).trigger("change"); $select.append(option).trigger("change");
partMatrice[partNumber] = matrice.IdMatrice; partMatrice[partNumber] = matrice.IdMatrice;
} else { } else {
// Aggiusta valore non valido
$select.val(null).trigger("change"); $select.val(null).trigger("change");
partMatrice[partNumber] = null; partMatrice[partNumber] = null;
} }
} else {
// Nessun valore: assicurati che sia vuoto
$select.val(null).trigger("change");
partMatrice[partNumber] = null;
} }
// === FINE MODIFICA ===
$select.on("change", function () { $select.on("change", function () {
const idmatrice = $(this).val(); const idmatrice = $(this).val();
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
// upload_photos_mobile.php // upload_photos_mobile.php
include('include/headscript.php'); include('include/headscriptnologin.php');
$db = DBHandlerSelect::getInstance(); $db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection(); $pdo = $db->getConnection();