fixed orders
This commit is contained in:
@@ -478,6 +478,9 @@ class MagoSalesStats
|
|||||||
'ritardo' => "x.is_late = 1",
|
'ritardo' => "x.is_late = 1",
|
||||||
'ritardo_cliente' => "x.is_late_client = 1",
|
'ritardo_cliente' => "x.is_late_client = 1",
|
||||||
'settimana' => "(x.status IN ('aperto','bloccato') AND x.week_lines > 0)", // righe da consegnare questa settimana
|
'settimana' => "(x.status IN ('aperto','bloccato') AND x.week_lines > 0)", // righe da consegnare questa settimana
|
||||||
|
// ordini con righe aperte la cui data ZIBO è nell'anno in corso (ritardi compresi) / nell'anno prossimo
|
||||||
|
'zibo_anno' => "(x.status IN ('aperto','bloccato') AND EXISTS (SELECT 1 FROM mago_sale_ord_detail zd WHERE zd.sale_ord_id = x.sale_ord_id AND zd.delivered = 0 AND zd.cancelled = 0 AND YEAR(" . self::ziboDate('zd') . ") <= YEAR(CURDATE())))",
|
||||||
|
'zibo_prossimo' => "(x.status IN ('aperto','bloccato') AND EXISTS (SELECT 1 FROM mago_sale_ord_detail zd WHERE zd.sale_ord_id = x.sale_ord_id AND zd.delivered = 0 AND zd.cancelled = 0 AND YEAR(" . self::ziboDate('zd') . ") = YEAR(CURDATE()) + 1))",
|
||||||
'da_fatturare' => "(x.delivered = 1 AND x.invoiced = 0 AND x.cancelled = 0)",
|
'da_fatturare' => "(x.delivered = 1 AND x.invoiced = 0 AND x.cancelled = 0)",
|
||||||
'fatturato' => "x.invoiced = 1",
|
'fatturato' => "x.invoiced = 1",
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -162,7 +162,13 @@
|
|||||||
"st.toship": {
|
"st.toship": {
|
||||||
t: "Da evadere",
|
t: "Da evadere",
|
||||||
b: `<p>Valore degli ordini <b>ancora aperti</b> (non consegnati del tutto). In rosso la parte <b>già in ritardo</b>.</p>
|
b: `<p>Valore degli ordini <b>ancora aperti</b> (non consegnati del tutto). In rosso la parte <b>già in ritardo</b>.</p>
|
||||||
<p class="sh-note">Cosa fare: se la quota in ritardo cresce, guarda la pagina Consegne.</p>`,
|
<p>Sotto, quello che resta <b>da consegnare</b> (solo la parte non ancora consegnata delle righe) diviso per <b>anno della data ZIBO</b>:</p>
|
||||||
|
<ul>
|
||||||
|
<li><b>Anno in corso</b>: righe con settimana ZIBO entro il 31/12, comprese quelle già in ritardo.</li>
|
||||||
|
<li><b>Anno prossimo</b>: righe con settimana ZIBO nel nuovo anno.</li>
|
||||||
|
<li>In grigio, se ci sono: righe più lontane o senza data ZIBO.</li>
|
||||||
|
</ul>
|
||||||
|
<p class="sh-note">Clic su un anno per vedere solo gli ordini con consegne in quell'anno. Cosa fare: se la quota in ritardo cresce, guarda la pagina Consegne.</p>`,
|
||||||
},
|
},
|
||||||
"st.open": {
|
"st.open": {
|
||||||
t: "Aperti",
|
t: "Aperti",
|
||||||
|
|||||||
@@ -93,6 +93,22 @@ if ($action === 'data') {
|
|||||||
WHERE $where
|
WHERE $where
|
||||||
", $params)[0];
|
", $params)[0];
|
||||||
|
|
||||||
|
// --- Da evadere per anno della data ZIBO: residuo delle righe ancora aperte (ritardi = anno in corso) ---
|
||||||
|
$cy = (int)date('Y');
|
||||||
|
$zy = "YEAR(" . MagoSalesStats::ziboDate('d') . ")";
|
||||||
|
$rv = "CASE WHEN d.qty > 0 THEN d.taxable_amount * GREATEST(d.qty - d.delivered_qty, 0) / d.qty ELSE d.taxable_amount END";
|
||||||
|
$kpi['toship'] = MagoSalesStats::fetchAllQ($pdo, "
|
||||||
|
SELECT COALESCE(SUM(CASE WHEN $zy <= $cy THEN $rv END), 0) AS y_cur,
|
||||||
|
COALESCE(SUM(CASE WHEN $zy = $cy + 1 THEN $rv END), 0) AS y_next,
|
||||||
|
COALESCE(SUM(CASE WHEN $zy > $cy + 1 THEN $rv END), 0) AS y_later,
|
||||||
|
COALESCE(SUM(CASE WHEN $zy IS NULL THEN $rv END), 0) AS y_nodate
|
||||||
|
FROM mago_sale_ord_detail d
|
||||||
|
JOIN $from ON x.sale_ord_id = d.sale_ord_id
|
||||||
|
WHERE $where AND x.status IN ('aperto','bloccato')
|
||||||
|
AND d.delivered = 0 AND d.cancelled = 0 AND (d.item <> '' OR d.qty <> 0)
|
||||||
|
", $params)[0];
|
||||||
|
$kpi['toship']['year'] = $cy;
|
||||||
|
|
||||||
// --- Confronto con lo STESSO PERIODO dell'anno precedente ---
|
// --- Confronto con lo STESSO PERIODO dell'anno precedente ---
|
||||||
$kpi['prev_orders'] = null;
|
$kpi['prev_orders'] = null;
|
||||||
$kpi['prev_value'] = null;
|
$kpi['prev_value'] = null;
|
||||||
@@ -835,6 +851,63 @@ if ($action === 'order') {
|
|||||||
box-shadow: inset 0 0 0 2px #b45309;
|
box-shadow: inset 0 0 0 2px #b45309;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Da evadere per anno della data ZIBO */
|
||||||
|
.kpi-years {
|
||||||
|
margin: 10px -18px -16px;
|
||||||
|
padding: 8px 18px 10px;
|
||||||
|
background: #eff6ff;
|
||||||
|
border-top: 1px solid #bfdbfe;
|
||||||
|
font-size: .8rem;
|
||||||
|
color: #1e3a8a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-years .ky-bar {
|
||||||
|
display: flex;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 99px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #dbeafe;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-years .ky-bar i {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-years .ky {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 3px 6px;
|
||||||
|
margin: 0 -6px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-years .ky:hover {
|
||||||
|
background: #dbeafe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-years .ky.selected {
|
||||||
|
background: #bfdbfe;
|
||||||
|
box-shadow: inset 0 0 0 2px #1d4ed8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-years .ky-dot {
|
||||||
|
display: inline-block;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-years .ky-other {
|
||||||
|
color: #64748b;
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.week-badge {
|
.week-badge {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: #fef3c7;
|
background: #fef3c7;
|
||||||
@@ -1336,6 +1409,8 @@ if ($action === 'order') {
|
|||||||
<button type="button" class="chip" data-status="aperto" style="--chip-c:var(--c-open);">Aperti</button>
|
<button type="button" class="chip" data-status="aperto" style="--chip-c:var(--c-open);">Aperti</button>
|
||||||
<button type="button" class="chip" data-status="ritardo" style="--chip-c:var(--c-late);">In ritardo (ZIBO)</button>
|
<button type="button" class="chip" data-status="ritardo" style="--chip-c:var(--c-late);">In ritardo (ZIBO)</button>
|
||||||
<button type="button" class="chip" data-status="settimana" style="--chip-c:#b45309;">In consegna questa sett.</button>
|
<button type="button" class="chip" data-status="settimana" style="--chip-c:#b45309;">In consegna questa sett.</button>
|
||||||
|
<button type="button" class="chip" data-status="zibo_anno" style="--chip-c:#1d4ed8;">ZIBO anno in corso</button>
|
||||||
|
<button type="button" class="chip" data-status="zibo_prossimo" style="--chip-c:#60a5fa;">ZIBO anno prossimo</button>
|
||||||
<button type="button" class="chip" data-status="ritardo_cliente" style="--chip-c:#ea580c;">Oltre data cliente</button>
|
<button type="button" class="chip" data-status="ritardo_cliente" style="--chip-c:#ea580c;">Oltre data cliente</button>
|
||||||
<button type="button" class="chip" data-status="bloccato" style="--chip-c:var(--c-block);">Bloccati</button>
|
<button type="button" class="chip" data-status="bloccato" style="--chip-c:var(--c-block);">Bloccati</button>
|
||||||
<button type="button" class="chip" data-status="evaso" style="--chip-c:var(--c-done);">Evasi</button>
|
<button type="button" class="chip" data-status="evaso" style="--chip-c:var(--c-done);">Evasi</button>
|
||||||
@@ -1385,6 +1460,7 @@ if ($action === 'order') {
|
|||||||
<div class="kpi-label" data-help="st.toship">Da evadere</div>
|
<div class="kpi-label" data-help="st.toship">Da evadere</div>
|
||||||
<div class="kpi-value" id="kOpenValue">—</div>
|
<div class="kpi-value" id="kOpenValue">—</div>
|
||||||
<div class="kpi-sub" id="kOpenValueSub"> </div>
|
<div class="kpi-sub" id="kOpenValueSub"> </div>
|
||||||
|
<div class="kpi-years" id="kOpenYears"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="kpi" data-status="aperto" style="--k:var(--c-open);">
|
<div class="kpi" data-status="aperto" style="--k:var(--c-open);">
|
||||||
<div class="kpi-icon"><i class="fa-solid fa-hourglass-half"></i></div>
|
<div class="kpi-icon"><i class="fa-solid fa-hourglass-half"></i></div>
|
||||||
@@ -1722,8 +1798,8 @@ if ($action === 'order') {
|
|||||||
|
|
||||||
// evidenzio il KPI corrispondente allo stato filtrato
|
// evidenzio il KPI corrispondente allo stato filtrato
|
||||||
$('.kpi').removeClass('selected');
|
$('.kpi').removeClass('selected');
|
||||||
$('.kpi-week').removeClass('selected');
|
$('.kpi-week, .kpi-years .ky').removeClass('selected');
|
||||||
if (f.statuses.length === 1) $(`.kpi[data-status="${f.statuses[0]}"], .kpi-week[data-status="${f.statuses[0]}"]`).addClass('selected');
|
if (f.statuses.length === 1) $(`.kpi[data-status="${f.statuses[0]}"], .kpi-week[data-status="${f.statuses[0]}"], .kpi-years .ky[data-status="${f.statuses[0]}"]`).addClass('selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
// aperta da link (?q=numero ordine): non sovrascrivo i filtri salvati dell'utente
|
// aperta da link (?q=numero ordine): non sovrascrivo i filtri salvati dell'utente
|
||||||
@@ -1885,6 +1961,34 @@ if ($action === 'order') {
|
|||||||
$('#ttlItems').text(v ? 'Top 10 articoli per valore ordinato' : 'Top 10 articoli per numero ordini');
|
$('#ttlItems').text(v ? 'Top 10 articoli per valore ordinato' : 'Top 10 articoli per numero ordini');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// box "Da evadere": residuo delle righe aperte diviso per anno della data ZIBO
|
||||||
|
function renderToShipYears(t) {
|
||||||
|
const y = +t.year || new Date().getFullYear();
|
||||||
|
const cur = +t.y_cur || 0,
|
||||||
|
next = +t.y_next || 0,
|
||||||
|
later = +t.y_later || 0,
|
||||||
|
nodate = +t.y_nodate || 0;
|
||||||
|
const tot = cur + next + later + nodate;
|
||||||
|
if (tot <= 0) {
|
||||||
|
$('#kOpenYears').html('<span class="text-muted">nessuna riga da consegnare</span>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const w = v => (v / tot * 100).toFixed(1) + '%';
|
||||||
|
let html = '<div class="ky-bar">' +
|
||||||
|
'<i style="width:' + w(cur) + ';background:#1d4ed8"></i>' +
|
||||||
|
'<i style="width:' + w(next) + ';background:#60a5fa"></i>' +
|
||||||
|
'<i style="width:' + w(later + nodate) + ';background:#cbd5e1"></i></div>';
|
||||||
|
html += '<div class="ky" data-status="zibo_anno" title="Righe aperte con data ZIBO nel ' + y + ', ritardi compresi: clic per vedere gli ordini">' +
|
||||||
|
'<span><span class="ky-dot" style="background:#1d4ed8"></span>' + y + ' <span class="text-muted">(ritardi compresi)</span></span><b>' + fmtEurShort(cur) + '</b></div>';
|
||||||
|
html += '<div class="ky" data-status="zibo_prossimo" title="Righe aperte con data ZIBO nel ' + (y + 1) + ': clic per vedere gli ordini">' +
|
||||||
|
'<span><span class="ky-dot" style="background:#60a5fa"></span>' + (y + 1) + '</span><b>' + fmtEurShort(next) + '</b></div>';
|
||||||
|
const other = [];
|
||||||
|
if (later > 0) other.push('dal ' + (y + 2) + ' ' + fmtEurShort(later));
|
||||||
|
if (nodate > 0) other.push('senza data ZIBO ' + fmtEurShort(nodate));
|
||||||
|
if (other.length) html += '<div class="ky-other">' + other.join(' · ') + '</div>';
|
||||||
|
$('#kOpenYears').html(html).attr('title', 'Residuo da consegnare: ' + fmtEur(tot, 2));
|
||||||
|
}
|
||||||
|
|
||||||
function renderKpi(k) {
|
function renderKpi(k) {
|
||||||
const orders = +k.orders || 0;
|
const orders = +k.orders || 0;
|
||||||
$('#kOrders').text(fmtNum(orders));
|
$('#kOrders').text(fmtNum(orders));
|
||||||
@@ -1905,6 +2009,7 @@ if ($action === 'order') {
|
|||||||
$('#kOpenValue').text(fmtEurShort(k.value_open)).attr('title', fmtEur(k.value_open, 2));
|
$('#kOpenValue').text(fmtEurShort(k.value_open)).attr('title', fmtEur(k.value_open, 2));
|
||||||
$('#kOpenValueSub').html(+k.value_late > 0 ?
|
$('#kOpenValueSub').html(+k.value_late > 0 ?
|
||||||
`<span class="delta-down">${fmtEurShort(k.value_late)}</span> in ritardo` : 'nessun importo in ritardo');
|
`<span class="delta-down">${fmtEurShort(k.value_late)}</span> in ritardo` : 'nessun importo in ritardo');
|
||||||
|
renderToShipYears(k.toship || {});
|
||||||
$('#kToInvoiceSub').html(+k.value_to_invoice > 0 ? `evasi non fatturati · ${fmtEurShort(k.value_to_invoice)}` : 'evasi non fatturati');
|
$('#kToInvoiceSub').html(+k.value_to_invoice > 0 ? `evasi non fatturati · ${fmtEurShort(k.value_to_invoice)}` : 'evasi non fatturati');
|
||||||
|
|
||||||
const miss = +k.missing_amounts || 0;
|
const miss = +k.missing_amounts || 0;
|
||||||
@@ -2694,6 +2799,15 @@ if ($action === 'order') {
|
|||||||
$('#fSearch').on('input', () => scheduleLoad(450));
|
$('#fSearch').on('input', () => scheduleLoad(450));
|
||||||
|
|
||||||
// striscia "in consegna questa settimana" dentro il box rosso: filtra solo quegli ordini
|
// striscia "in consegna questa settimana" dentro il box rosso: filtra solo quegli ordini
|
||||||
|
// righe "anno" dentro il box Da evadere: filtrano gli ordini con consegne ZIBO in quell'anno
|
||||||
|
$('#kpiGrid').on('click', '.kpi-years .ky', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleStatus($(this).data('status'), true);
|
||||||
|
});
|
||||||
|
$('#kpiGrid').on('click', '.kpi-years', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
$('#kpiGrid').on('click', '.kpi-week', function(e) {
|
$('#kpiGrid').on('click', '.kpi-week', function(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleStatus('settimana', true);
|
toggleStatus('settimana', true);
|
||||||
@@ -2778,7 +2892,7 @@ if ($action === 'order') {
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script src="sales_help.js?v=3"></script>
|
<script src="sales_help.js?v=7"></script>
|
||||||
<script src="ui_layout.js?v=1"></script>
|
<script src="ui_layout.js?v=1"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user