From 2d4ee95ab103f938ebb46e18e4ac8d1df16e7339 Mon Sep 17 00:00:00 2001 From: solocla Date: Wed, 28 Oct 2026 13:52:47 +0100 Subject: [PATCH] fixed orders --- public/userarea/class/MagoSalesStats.php | 3 + public/userarea/sales_help.js | 8 +- public/userarea/sales_orders_stats.php | 120 ++++++++++++++++++++++- 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/public/userarea/class/MagoSalesStats.php b/public/userarea/class/MagoSalesStats.php index 40aac5c4..0236b7bb 100644 --- a/public/userarea/class/MagoSalesStats.php +++ b/public/userarea/class/MagoSalesStats.php @@ -478,6 +478,9 @@ class MagoSalesStats 'ritardo' => "x.is_late = 1", 'ritardo_cliente' => "x.is_late_client = 1", '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)", 'fatturato' => "x.invoiced = 1", ]; diff --git a/public/userarea/sales_help.js b/public/userarea/sales_help.js index f8f255ac..e75bebc1 100644 --- a/public/userarea/sales_help.js +++ b/public/userarea/sales_help.js @@ -162,7 +162,13 @@ "st.toship": { t: "Da evadere", b: `

Valore degli ordini ancora aperti (non consegnati del tutto). In rosso la parte già in ritardo.

-

Cosa fare: se la quota in ritardo cresce, guarda la pagina Consegne.

`, +

Sotto, quello che resta da consegnare (solo la parte non ancora consegnata delle righe) diviso per anno della data ZIBO:

+ +

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.

`, }, "st.open": { t: "Aperti", diff --git a/public/userarea/sales_orders_stats.php b/public/userarea/sales_orders_stats.php index 8d9027d5..87dc9627 100644 --- a/public/userarea/sales_orders_stats.php +++ b/public/userarea/sales_orders_stats.php @@ -93,6 +93,22 @@ if ($action === 'data') { WHERE $where ", $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 --- $kpi['prev_orders'] = null; $kpi['prev_value'] = null; @@ -835,6 +851,63 @@ if ($action === 'order') { 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 { display: inline-block; background: #fef3c7; @@ -1336,6 +1409,8 @@ if ($action === 'order') { + + @@ -1385,6 +1460,7 @@ if ($action === 'order') {
Da evadere
—
 
+
@@ -1722,8 +1798,8 @@ if ($action === 'order') { // evidenzio il KPI corrispondente allo stato filtrato $('.kpi').removeClass('selected'); - $('.kpi-week').removeClass('selected'); - if (f.statuses.length === 1) $(`.kpi[data-status="${f.statuses[0]}"], .kpi-week[data-status="${f.statuses[0]}"]`).addClass('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]}"], .kpi-years .ky[data-status="${f.statuses[0]}"]`).addClass('selected'); } // 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'); } + // 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('nessuna riga da consegnare'); + return; + } + const w = v => (v / tot * 100).toFixed(1) + '%'; + let html = '
' + + '' + + '' + + '
'; + html += '
' + + '' + y + ' (ritardi compresi)' + fmtEurShort(cur) + '
'; + html += '
' + + '' + (y + 1) + '' + fmtEurShort(next) + '
'; + 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 += '
' + other.join(' · ') + '
'; + $('#kOpenYears').html(html).attr('title', 'Residuo da consegnare: ' + fmtEur(tot, 2)); + } + function renderKpi(k) { const orders = +k.orders || 0; $('#kOrders').text(fmtNum(orders)); @@ -1905,6 +2009,7 @@ if ($action === 'order') { $('#kOpenValue').text(fmtEurShort(k.value_open)).attr('title', fmtEur(k.value_open, 2)); $('#kOpenValueSub').html(+k.value_late > 0 ? `${fmtEurShort(k.value_late)} 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'); const miss = +k.missing_amounts || 0; @@ -2694,6 +2799,15 @@ if ($action === 'order') { $('#fSearch').on('input', () => scheduleLoad(450)); // 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) { e.stopPropagation(); toggleStatus('settimana', true); @@ -2778,7 +2892,7 @@ if ($action === 'order') { }); })(); - +