fixed sales matrici2

This commit is contained in:
2026-10-27 12:14:07 +01:00
parent e042a156c8
commit ccfe34637d
+55 -39
View File
@@ -1273,7 +1273,7 @@ if ($action === 'list' || $action === 'detail') {
renderMix();
}).catch(e => {
console.error(e);
$('#loading').html('<div class="text-danger">Errore nel caricamento</div>');
$('#loading').html('<div class="text-danger">Errore nel caricamento: ' + esc(e && e.message ? e.message : e) + '</div>');
});
}
@@ -1784,46 +1784,62 @@ if ($action === 'list' || $action === 'detail') {
function mixPane(d) {
const h = d.head;
if (h.kind === 'pz') return '<div class="alert alert-warning mb-0"><span class="tb tb-pz">A pezzi</span> Le righe vendute a pezzi aspettano la conversione pezzi → metri: le mescole non sono ancora stimate.</div>';
if (!d.mix.length) return `<div class="alert alert-light mb-0">${h.id ? 'Nessuna mescola collegata: completa la scheda di lavoro della matrice.' : 'Non collegata a una matrice dell\'anagrafica.'}</div>`;
const src = h.mix_source === 'scheda' ? 'dall\'ultima scheda di lavoro' : 'dall\'anagrafica matrice (senza g/m)';
return `<div class="chart-hint mb-2">Mescole ${src}. ${h.kind === 'm' ? 'Kg = metri × g/m ÷ 1000.' : 'I kg venduti si dividono in base alla quota.'}</div>
<div class="table-responsive"><table class="table table-striped align-middle mx-table mb-0"><thead><tr><th>Mescola</th><th class="text-end">g/m</th><th class="text-end">Quota</th><th class="text-end">€/kg</th><th class="text-end">Costo /${UOM_LABEL[h.kind] || esc(h.uom)}</th><th class="text-end">Kg periodo</th><th class="text-end">Kg da produrre</th></tr></thead><tbody>
${d.mix.map(m => {
const pt = ((d.cost || {}).parts || []).find(x => x.id === m.id) || {};
const eur = pt.eur_kg !== null && pt.eur_kg !== undefined ?
`
$ {
fmtNum(pt.eur_kg, 3)
const cost = d.cost || {};
const ul = UOM_LABEL[h.kind] || esc(h.uom);
if (h.kind === 'pz') {
return '<div class="alert alert-warning mb-0"><span class="tb tb-pz">A pezzi</span> Le righe vendute a pezzi aspettano la conversione pezzi → metri: le mescole non sono ancora stimate.</div>';
}
$ {
pt.old ? ' <span class="tb tb-gm" title="Ultimo acquisto ' + fmtDate(pt.last_date) + '">vecchio</span>' : ''
if (!d.mix.length) {
const msg = h.id ? 'Nessuna mescola collegata: completa la scheda di lavoro della matrice.' : 'Non collegata a una matrice dell&#39;anagrafica.';
return '<div class="alert alert-light mb-0">' + msg + '</div>';
}
$ {
pt.check ? ' <span class="tb tb-check">da verificare</span>' : ''
} < div class = "small text-muted" > $ {
esc(pt.supplier || '')
} < /div>` :
'<span class="tb tb-gm" title="Nessun acquisto abbinato: aggiungi il nome d\'acquisto nella pagina mescole">senza prezzo</span>';
return `<tr style="cursor:default;"><td><b>${esc(m.name)}</b>${m.out ? `<div class="small text-muted">${esc(m.out)}</div>` : ''}</td>
<td class="text-end">${m.gm ? fmtNum(m.gm, 1) : '<span class="tb tb-gm">mancante</span>'}</td>
<td class="text-end">${fmtNum(m.share, 1)}%</td>
<td class="text-end">${eur}</td>
<td class="text-end amount">${pt.part !== null && pt.part !== undefined ? '<b>' + fmtPrice(pt.part) + '</b>' : '—'}</td>
<td class="text-end amount">${fmtNum(m.kg)} kg</td>
<td class="text-end amount">${m.kg_open ? '<b style="color:#047857">' + fmtNum(m.kg_open) + ' kg</b>' : '—'}</td></tr>`;
}).join('')
const src = h.mix_source === 'scheda' ? 'dall&#39;ultima scheda di lavoro' : 'dall&#39;anagrafica matrice (senza g/m)';
const rule = h.kind === 'm' ? 'Kg = metri × g/m ÷ 1000.' : 'I kg venduti si dividono in base alla quota.';
let html = '<div class="chart-hint mb-2">Mescole ' + src + '. ' + rule + '</div>';
html += '<div class="table-responsive"><table class="table table-striped align-middle mx-table mb-0"><thead><tr>';
html += '<th>Mescola</th><th class="text-end">g/m</th><th class="text-end">Quota</th><th class="text-end">€/kg</th>';
html += '<th class="text-end">Costo /' + ul + '</th><th class="text-end">Kg periodo</th><th class="text-end">Kg da produrre</th>';
html += '</tr></thead><tbody>';
d.mix.forEach(function(m) {
html += mixRow(m, cost);
});
if (cost.cost !== null && cost.cost !== undefined) {
html += '<tr class="table-light" style="cursor:default;"><td colspan="4" class="text-end fw-bold">Costo mescola totale</td>';
html += '<td class="text-end amount"><b>' + fmtPrice(cost.cost) + '</b></td><td colspan="2"></td></tr>';
}
$ {
(d.cost || {}).cost !== null && (d.cost || {}).cost !== undefined ? `<tr style="cursor:default;" class="table-light"><td colspan="4" class="text-end fw-bold">Costo mescola totale</td><td class="text-end amount"><b>${fmtPrice(d.cost.cost)}</b></td><td colspan="2"></td></tr>` : ''
} <
/tbody></table > < /div> <
div class = "chart-hint mt-2" > Costo = $ {
h.kind === 'm' ? 'g/m × €/kg ÷ 1000' : 'media dei €/kg pesata sulla quota'
}, prezzi medi degli ultimi $ {
(d.cost || {}).price_months || 3
html += '</tbody></table></div>';
html += '<div class="chart-hint mt-2">Costo = ' + (h.kind === 'm' ? 'g/m × €/kg ÷ 1000' : 'media dei €/kg pesata sulla quota') +
', prezzi medi degli ultimi ' + (cost.price_months || 3) + ' mesi pagati in Mago. Solo mescola: senza scarto, lavorazione, energia.</div>';
return html;
}
mesi pagati in Mago.Solo mescola: senza scarto, lavorazione, energia. < /div>`;
function mixRow(m, cost) {
const pt = (cost.parts || []).find(function(x) {
return x.id === m.id;
}) || {};
let eur;
if (pt.eur_kg !== null && pt.eur_kg !== undefined) {
eur = fmtNum(pt.eur_kg, 3);
if (pt.old) eur += ' <span class="tb tb-gm" title="Ultimo acquisto ' + fmtDate(pt.last_date) + '">vecchio</span>';
if (pt.check) eur += ' <span class="tb tb-check">da verificare</span>';
eur += '<div class="small text-muted">' + esc(pt.supplier || '') + '</div>';
} else {
eur = '<span class="tb tb-gm" title="Nessun acquisto abbinato: aggiungi il nome d&#39;acquisto nella pagina mescole">senza prezzo</span>';
}
const gm = m.gm ? fmtNum(m.gm, 1) : '<span class="tb tb-gm">mancante</span>';
const part = (pt.part !== null && pt.part !== undefined) ? '<b>' + fmtPrice(pt.part) + '</b>' : '—';
const open = m.kg_open ? '<b style="color:#047857">' + fmtNum(m.kg_open) + ' kg</b>' : '—';
const out = m.out ? '<div class="small text-muted">' + esc(m.out) + '</div>' : '';
return '<tr style="cursor:default;">' +
'<td><b>' + esc(m.name) + '</b>' + out + '</td>' +
'<td class="text-end">' + gm + '</td>' +
'<td class="text-end">' + fmtNum(m.share, 1) + '%</td>' +
'<td class="text-end">' + eur + '</td>' +
'<td class="text-end amount">' + part + '</td>' +
'<td class="text-end amount">' + fmtNum(m.kg) + ' kg</td>' +
'<td class="text-end amount">' + open + '</td>' +
'</tr>';
}
function renderDetailChart(d) {
@@ -2001,7 +2017,7 @@ if ($action === 'list' || $action === 'detail') {
title: 'Margine',
data: 'margin_pct',
className: 'text-end',
render: (v, t, r) => t === 'display' ? (v === null ? '<span class="text-muted">—</span>' : `${marginSpan(v)}<div class="small text-muted" title="Margine sull'ultimo prezzo">ultimo ${r.last_margin_pct === null ? '—' : fmtNum(r.last_margin_pct, 0) + '%'}</div>`) : (v === null ? (t === 'export' ? '' : -1e9) : (t === 'export' ? v / 100 : +v))
render: (v, t, r) => t === 'display' ? (v === null ? '<span class="text-muted">—</span>' : `${marginSpan(v)}<div class="small text-muted" title="Margine sull&#39;ultimo prezzo">ultimo ${r.last_margin_pct === null ? '—' : fmtNum(r.last_margin_pct, 0) + '%'}</div>`) : (v === null ? (t === 'export' ? '' : -1e9) : (t === 'export' ? v / 100 : +v))
}],
order: [
[3, 'desc']
@@ -2170,7 +2186,7 @@ if ($action === 'list' || $action === 'detail') {
}
});
loadFilters().then(load).then(() => {
loadFilters().catch(e => console.error('Filtri non caricati', e)).then(load).then(() => {
const k = new URLSearchParams(location.search).get('k');
if (k) openDetail(k);
});