added clienti in template, export

This commit is contained in:
2026-03-19 10:08:29 +01:00
parent eb21910ef3
commit 5a58decd40
15 changed files with 3497 additions and 235 deletions
+100 -227
View File
@@ -167,6 +167,8 @@ $fixedFieldsRaw = $fixedStmt->fetchAll(PDO::FETCH_ASSOC);
// Ordine desiderato: Cliente Responsabile prima, poi gli altri, ConsegnaRichiesta prima delle 3 speciali
$desiredOrder = [
'ClienteResponsabile',
'ClienteFornitore',
'ClienteAnalisi',
'AnagraficaCertestObject',
'AnagraficaCertestService',
'MoltiplicatorePrezzo',
@@ -174,8 +176,8 @@ $desiredOrder = [
// se ci sono altri campi fixed li mettiamo dopo
];
// ClienteFornitore is rendered as a standalone column (like idclient), skip it in fixed fields
$excludeFromFixed = ['ClienteFornitore'];
// No exclusions: fixed fields will be rendered together at the end
$excludeFromFixed = [];
$fixedFields = [];
$tempMap = [];
@@ -199,10 +201,11 @@ foreach ($tempMap as $f) {
// Maps logical fixed_field_key → real datadb column name (mirrors JS fixedAliasMap)
$fixedAliasMap = [
'ClienteResponsabile' => 'cliente_responsabile_id',
'ClienteFornitore' => 'cliente_fornitore_id',
'ClienteAnalisi' => 'clienteAnalisi',
'MoltiplicatorePrezzo' => 'moltiplicatore_prezzo_id',
'AnagraficaCertestObject' => 'anagrafica_certest_object_id',
'AnagraficaCertestService' => 'anagrafica_certest_service_id',
'ClienteFornitore' => 'cliente_fornitore_id',
'ConsegnaRichiesta' => 'consegna_richiesta',
];
@@ -966,15 +969,9 @@ function fixedDefaultValue(array $f): string
<button type="button" class="propagate-btn" data-column="idclient"><i class="fas fa-arrow-down"></i></button>
<span id="clientLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Recupero clienti in corso...</span>
</div>
<div class="grid-cell grid-top-cell" style="flex: 0 0 300px;" data-index="<?= $mainFieldMapping ? 4 : 3 ?>">
<select class="custom-field dropdown-select client-select searchable-client" data-column="cliente_fornitore_id" id="clienteFornitoreSelect" name="cliente_fornitore_id">
<option value="">Select a supplier...</option>
</select>
<button type="button" class="propagate-btn" data-column="cliente_fornitore_id"><i class="fas fa-arrow-down"></i></button>
</div>
<?php
$topColIndex = $mainFieldMapping ? 5 : 4;
$topColIndex = $mainFieldMapping ? 4 : 3;
$autoIndex = 0;
foreach ($allMappings as $mapping) {
@@ -1083,6 +1080,8 @@ function fixedDefaultValue(array $f): string
$isApiField = in_array($key, [
'MoltiplicatorePrezzo',
'ClienteResponsabile',
'ClienteFornitore',
'ClienteAnalisi',
'AnagraficaCertestObject',
'AnagraficaCertestService'
], true);
@@ -1140,10 +1139,8 @@ function fixedDefaultValue(array $f): string
</div>
<div class="grid-header" data-index="<?= $mainFieldMapping ? 3 : 2 ?>" style="flex: 0 0 300px; position: relative;">Client<div class="resizer"></div>
</div>
<div class="grid-header" data-index="<?= $mainFieldMapping ? 4 : 3 ?>" style="flex: 0 0 300px; position: relative;">Cliente Fornitore<div class="resizer"></div>
</div>
<?php
$headerIndex = $mainFieldMapping ? 5 : 4;
$headerIndex = $mainFieldMapping ? 4 : 3;
foreach ($allMappings as $mapping) {
if (!$mapping['is_manual'] && $mapping['main_field'] != 1 && $mapping['is_visible_import'] == 1) {
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
@@ -1245,13 +1242,9 @@ function fixedDefaultValue(array $f): string
<option value="">Select a client...</option>
</select>
</div>
<div class="grid-cell editable-cell" data-col="cliente_fornitore_id" data-row="<?= $index ?>" data-index="<?= $mainFieldMapping ? 4 : 3 ?>" style="flex: 0 0 300px;">
<select name="rows[<?= $index ?>][cliente_fornitore_id]" class="cell-input dropdown-select client-select searchable-client fornitore-select" data-current-value="<?= htmlspecialchars($row['cliente_fornitore_id'] ?? '') ?>">
<option value="">Select a supplier...</option>
</select>
</div>
<?php
$cellIndex = $mainFieldMapping ? 5 : 4;
$cellIndex = $mainFieldMapping ? 4 : 3;
$rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']);
$autoIndex = 0;
foreach ($allMappings as $mapping) {
@@ -1376,7 +1369,7 @@ function fixedDefaultValue(array $f): string
. (((int)$f['is_required'] === 1) ? "required" : "")
. ">";
} else {
$isApiField = in_array($key, ['MoltiplicatorePrezzo', 'ClienteResponsabile', 'AnagraficaCertestObject', 'AnagraficaCertestService'], true);
$isApiField = in_array($key, ['MoltiplicatorePrezzo', 'ClienteResponsabile', 'ClienteFornitore', 'ClienteAnalisi', 'AnagraficaCertestObject', 'AnagraficaCertestService'], true);
$selectClass = $isApiField ? 'api-fixed-select' : '';
echo "<select
name='rows[$index][$key]'
@@ -1443,6 +1436,60 @@ function fixedDefaultValue(array $f): string
<script src="partsTable.js"></script>
<script src="tracking.js"></script>
<script src="export_to_lims.js"></script>
<script>
let globalClientData = [];
let globalClientPromise = null;
function formatClientLabel(client) {
const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "";
const codiceCliente = (client.CodiceCliente ?? client.codiceCliente ?? '').toString().trim();
const suffix = (codiceCliente.split('_')[1] || '').trim();
const shortCode = suffix || (codiceCliente ? codiceCliente.charAt(0) : '--');
return `${nome.trim()} - ${shortCode} (ID: ${id})`;
}
async function ensureClientsLoaded(retryCount = 0, maxRetries = 3) {
if (globalClientData.length > 0) {
return globalClientData;
}
if (globalClientPromise) {
return globalClientPromise;
}
globalClientPromise = (async () => {
const response = await fetch("get_clienti.php", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
const data = await response.json();
if (!response.ok) {
if (
response.status === 500 &&
data.error &&
data.error.includes('Cannot persist the object') &&
retryCount < maxRetries
) {
await new Promise(resolve => setTimeout(resolve, 1000));
globalClientPromise = null;
return ensureClientsLoaded(retryCount + 1, maxRetries);
}
throw new Error(data.error || `Errore HTTP: ${response.status}`);
}
globalClientData = data.value || [];
return globalClientData;
})();
return globalClientPromise;
}
</script>
<script>
function expandColumn(cell, expand) {
const columnIndex = cell.getAttribute('data-index');
@@ -1577,11 +1624,6 @@ function fixedDefaultValue(array $f): string
formData.append('idclient', idclientSelect.value);
}
const fornitoreSelect = row.querySelector(`select[name="rows[${rowIndex}][cliente_fornitore_id]"]`);
if (fornitoreSelect) {
formData.append('cliente_fornitore_id', fornitoreSelect.value);
}
// ---- FIXED FIELDS (NEW) ----
const fixedInputs = row.querySelectorAll(`input[name^="rows[${rowIndex}]["], select[name^="rows[${rowIndex}]["]`);
fixedInputs.forEach(inp => {
@@ -1593,6 +1635,8 @@ function fixedDefaultValue(array $f): string
// Map: fixed key (logical) -> datadb real column
const fixedAliasMap = {
ClienteResponsabile: 'cliente_responsabile_id',
ClienteFornitore: 'cliente_fornitore_id',
ClienteAnalisi: 'clienteAnalisi',
MoltiplicatorePrezzo: 'moltiplicatore_prezzo_id',
AnagraficaCertestObject: 'anagrafica_certest_object_id',
AnagraficaCertestService: 'anagrafica_certest_service_id',
@@ -1746,10 +1790,6 @@ function fixedDefaultValue(array $f): string
if (idclientSelect) {
formData.append('idclient', idclientSelect.value);
}
const fornitoreSelect = row.querySelector(`select[name="rows[${rowIndex}][cliente_fornitore_id]"]`);
if (fornitoreSelect) {
formData.append('cliente_fornitore_id', fornitoreSelect.value);
}
// ---- FIXED FIELDS ----
const fixedInputs = row.querySelectorAll(`input[name^="rows[${rowIndex}]["], select[name^="rows[${rowIndex}]["]`);
fixedInputs.forEach(inp => {
@@ -1757,6 +1797,8 @@ function fixedDefaultValue(array $f): string
const m = inp.name.match(/rows\[\d+\]\[([^\]]+)\]/);
const fixedAliasMap = {
ClienteResponsabile: 'cliente_responsabile_id',
ClienteFornitore: 'cliente_fornitore_id',
ClienteAnalisi: 'clienteAnalisi',
MoltiplicatorePrezzo: 'moltiplicatore_prezzo_id',
AnagraficaCertestObject: 'anagrafica_certest_object_id',
AnagraficaCertestService: 'anagrafica_certest_service_id',
@@ -1884,51 +1926,31 @@ function fixedDefaultValue(array $f): string
<script>
document.addEventListener("DOMContentLoaded", function() {
const inputs = document.querySelectorAll('.cell-input');
let clientData = []; // Dichiarazione di clientData qui
let clientData = globalClientData;
// Funzione per caricare i client
async function loadClients(retryCount = 0, maxRetries = 3) {
async function loadClients() {
const clientLoadingStatus = document.getElementById("clientLoadingStatus");
try {
clientLoadingStatus.style.display = 'inline';
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
const response = await fetch("get_clienti.php", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
const data = await response.json();
if (!response.ok) {
if (response.status === 500 && data.error.includes('Cannot persist the object') && retryCount < maxRetries) {
console.log(`Tentativo ${retryCount + 1}/${maxRetries}: Riprovo a caricare i clienti...`);
await new Promise(resolve => setTimeout(resolve, 1000));
return loadClients(retryCount + 1, maxRetries);
}
throw new Error(data.error || `Errore HTTP: ${response.status}`);
}
clientData = data.value || [];
clientData = await ensureClientsLoaded();
const select = document.getElementById("clientSelect");
select.innerHTML = '<option value="">Select a client...</option>';
clientData.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile";
const codiceCliente = (client.CodiceCliente || '').toString().trim();
const suffix = (codiceCliente.split('_')[1] || '').trim();
const shortCode = suffix || (codiceCliente ? codiceCliente.charAt(0) : '--');
const option = new Option(`${nome.trim()} - ${shortCode} (ID: ${id})`, id);
if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) {
clientData.forEach(client => {
const option = new Option(formatClientLabel(client), client.IdCliente);
if (parseInt(client.IdCliente) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) {
option.selected = true;
}
select.add(option);
});
populateClientDropdowns();
populateFornitoreDropdowns();
clientLoadingStatus.textContent = "Clienti caricati.";
// ✅ force refresh of header dependent fixed fields
$('#clientSelect').trigger('change');
$('.grid-top .api-fixed-select[data-fixed-key="ClienteResponsabile"]').trigger('fixed:reload');
@@ -1979,45 +2001,6 @@ function fixedDefaultValue(array $f): string
});
}
// Funzione per popolare i dropdown ClienteFornitore (header + rows)
function populateFornitoreDropdowns() {
// Header
const headerSelect = document.getElementById("clienteFornitoreSelect");
if (headerSelect) {
headerSelect.innerHTML = '<option value="">Select a supplier...</option>';
clientData.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile";
const codiceCliente = (client.CodiceCliente || '').toString().trim();
const suffix = (codiceCliente.split('_')[1] || '').trim();
const shortCode = suffix || (codiceCliente ? codiceCliente.charAt(0) : '--');
headerSelect.add(new Option(`${nome.trim()} - ${shortCode} (ID: ${id})`, id));
});
}
// Row dropdowns
const fornitoreDropdowns = document.querySelectorAll('select[name^="rows"][name$="[cliente_fornitore_id]"]');
fornitoreDropdowns.forEach(dropdown => {
const currentValue = dropdown.getAttribute('data-current-value') || '';
dropdown.innerHTML = '<option value="">Select a supplier...</option>';
clientData.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile";
const codiceCliente = (client.CodiceCliente || '').toString().trim();
const suffix = (codiceCliente.split('_')[1] || '').trim();
const shortCode = suffix || (codiceCliente ? codiceCliente.charAt(0) : '--');
const option = new Option(`${nome.trim()} - ${shortCode} (ID: ${id})`, id);
if (String(id) === String(currentValue)) {
option.selected = true;
}
dropdown.add(option);
});
if (currentValue) {
dropdown.value = currentValue;
}
});
}
// Carica i client all'avvio
loadClients();
@@ -2355,121 +2338,6 @@ function fixedDefaultValue(array $f): string
populateDropdowns();
});
document.addEventListener("DOMContentLoaded", function() {
let clientData = [];
async function loadClients(retryCount = 0, maxRetries = 3) {
const clientLoadingStatus = document.getElementById("clientLoadingStatus");
try {
clientLoadingStatus.style.display = 'inline';
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
const response = await fetch("get_clienti.php", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
const data = await response.json();
if (!response.ok) {
if (response.status === 500 && data.error.includes('Cannot persist the object') && retryCount < maxRetries) {
console.log(`Tentativo ${retryCount + 1}/${maxRetries}: Riprovo a caricare i clienti...`);
await new Promise(resolve => setTimeout(resolve, 1000));
return loadClients(retryCount + 1, maxRetries);
}
throw new Error(data.error || `Errore HTTP: ${response.status}`);
}
clientData = data.value || [];
const select = document.getElementById("clientSelect");
select.innerHTML = '<option value="">Select a client...</option>';
clientData.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile";
// CodiceCliente es: "Bl01858_E" -> vogliamo "E"
const codiceCliente = (client.CodiceCliente ?? client.codiceCliente ?? '').toString().trim();
const suffix = (codiceCliente.split('_')[1] || '').trim(); // parte dopo "_"
const shortCode = suffix || '--';
const option = new Option(`${nome.trim()} - ${shortCode} (ID: ${id})`, id);
if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) {
option.selected = true;
}
select.add(option);
});
populateClientDropdowns();
clientLoadingStatus.textContent = "Clienti caricati.";
} catch (error) {
clientLoadingStatus.textContent = "Errore nel caricamento.";
Swal.fire({
title: "Errore!",
text: "Impossibile caricare i clienti: " + error.message,
icon: "error",
confirmButtonText: "OK"
});
} finally {
setTimeout(() => clientLoadingStatus.style.display = 'none', 2000);
}
}
function populateClientDropdowns() {
const clientDropdowns = document.querySelectorAll('select[name^="rows"][name$="[idclient]"]');
clientDropdowns.forEach(dropdown => {
const currentValue = dropdown.getAttribute('data-current-value') || '';
dropdown.innerHTML = '<option value="">Select a client...</option>';
clientData.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile";
// CodiceCliente es: "Bl01858_E" -> vogliamo "E"
const codiceCliente = (client.CodiceCliente || '').toString().trim();
const suffix = (codiceCliente.split('_')[1] || '').trim(); // parte dopo "_"
const shortCode = suffix || '--';
const option = new Option(`${nome.trim()} - ${shortCode} (ID: ${id})`, id);
if (String(id) === String(currentValue)) {
option.selected = true;
}
dropdown.add(option);
});
// Ripristina il valore corrente
if (currentValue) {
dropdown.value = currentValue;
dropdown.setAttribute('data-restoring', '');
const event = new Event('change', {
bubbles: true
});
dropdown.dispatchEvent(event);
dropdown.removeAttribute('data-restoring');
}
});
}
loadClients();
document.getElementById('clientSelect').addEventListener('change', function() {
const gridCell = this.closest('.grid-cell');
const event = new Event('change', {
bubbles: true
});
gridCell.dispatchEvent(event);
});
document.addEventListener('change', function(e) {
if (e.target.matches('select[name^="rows"][name$="[idclient]"]')) {
const gridCell = e.target.closest('.grid-cell');
const event = new Event('change', {
bubbles: true
});
gridCell.dispatchEvent(event);
}
});
});
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
@@ -2538,22 +2406,6 @@ function fixedDefaultValue(array $f): string
});
});
// Propagate ClienteFornitore
$('.propagate-btn[data-column="cliente_fornitore_id"]').on('click', function() {
const value = $('#clienteFornitoreSelect').val();
const rows = document.querySelectorAll('.grid-row');
rows.forEach(row => {
const fornitoreSelect = row.querySelector('select[name$="[cliente_fornitore_id]"]');
if (fornitoreSelect) {
$(fornitoreSelect).val(value).trigger('change.select2');
const event = new Event('change', {
bubbles: true
});
fornitoreSelect.dispatchEvent(event);
}
});
});
// Quick add part from "Tested Component" (+ button)
$(document).on('click', '.add-part-btn', async function() {
const rowIndex = $(this).data('row');
@@ -2757,6 +2609,12 @@ function fixedDefaultValue(array $f): string
getParams: (clientId) => ({
id_cliente: clientId
})
},
'ClienteFornitore': {
source: 'clients'
},
'ClienteAnalisi': {
source: 'clients'
}
};
@@ -2780,6 +2638,21 @@ function fixedDefaultValue(array $f): string
const config = apiFields[fieldKey];
if (!config) return [];
if (config.source === 'clients') {
const clients = await ensureClientsLoaded();
const results = clients.map(client => ({
id: client.IdCliente,
text: formatClientLabel(client)
}));
results.sort((a, b) => String(a.text || '').localeCompare(String(b.text || ''), 'it', {
sensitivity: 'base'
}));
fixedFieldDataCache[fieldKey] = results;
return results;
}
const cacheKey = fieldKey + (clientId ? '_' + clientId : '');
if (fixedFieldDataCache[cacheKey]) {
return fixedFieldDataCache[cacheKey];