fixed sommario and added queue mago
This commit is contained in:
@@ -389,6 +389,56 @@ if ($action === 'data') {
|
||||
return $m['delta'] < 0;
|
||||
}));
|
||||
|
||||
// ---------------- ORDINI IN ARRIVO: oggi, 7 giorni, 30 giorni (vs periodo precedente) ----------------
|
||||
$fl = MagoSalesStats::fetchAllQ($pdo, "
|
||||
SELECT
|
||||
SUM(x.order_date = CURDATE()) AS n0,
|
||||
SUM(CASE WHEN x.order_date = CURDATE() THEN x.taxable_amount ELSE 0 END) AS v0,
|
||||
SUM(x.order_date = CURDATE() - INTERVAL 7 DAY) AS n0p,
|
||||
SUM(CASE WHEN x.order_date = CURDATE() - INTERVAL 7 DAY THEN x.taxable_amount ELSE 0 END) AS v0p,
|
||||
SUM(x.order_date > CURDATE() - INTERVAL 7 DAY) AS n7,
|
||||
SUM(CASE WHEN x.order_date > CURDATE() - INTERVAL 7 DAY THEN x.taxable_amount ELSE 0 END) AS v7,
|
||||
SUM(x.order_date <= CURDATE() - INTERVAL 7 DAY AND x.order_date > CURDATE() - INTERVAL 14 DAY) AS n7p,
|
||||
SUM(CASE WHEN x.order_date <= CURDATE() - INTERVAL 7 DAY AND x.order_date > CURDATE() - INTERVAL 14 DAY THEN x.taxable_amount ELSE 0 END) AS v7p,
|
||||
SUM(x.order_date > CURDATE() - INTERVAL 30 DAY) AS n30,
|
||||
SUM(CASE WHEN x.order_date > CURDATE() - INTERVAL 30 DAY THEN x.taxable_amount ELSE 0 END) AS v30,
|
||||
SUM(x.order_date <= CURDATE() - INTERVAL 30 DAY AND x.order_date > CURDATE() - INTERVAL 60 DAY) AS n30p,
|
||||
SUM(CASE WHEN x.order_date <= CURDATE() - INTERVAL 30 DAY AND x.order_date > CURDATE() - INTERVAL 60 DAY THEN x.taxable_amount ELSE 0 END) AS v30p,
|
||||
COUNT(DISTINCT CASE WHEN x.order_date > CURDATE() - INTERVAL 30 DAY THEN x.customer END) AS c30
|
||||
FROM $from
|
||||
WHERE x.status <> 'annullato' AND x.order_date > CURDATE() - INTERVAL 60 DAY AND x.order_date <= CURDATE()
|
||||
", [])[0];
|
||||
$flow = [
|
||||
[
|
||||
'key' => 'today',
|
||||
'title' => 'Oggi',
|
||||
'n' => (int)$fl['n0'],
|
||||
'v' => (float)$fl['v0'],
|
||||
'np' => (int)$fl['n0p'],
|
||||
'vp' => (float)$fl['v0p'],
|
||||
'vs' => 'stesso giorno della settimana scorsa'
|
||||
],
|
||||
[
|
||||
'key' => 'week',
|
||||
'title' => 'Ultimi 7 giorni',
|
||||
'n' => (int)$fl['n7'],
|
||||
'v' => (float)$fl['v7'],
|
||||
'np' => (int)$fl['n7p'],
|
||||
'vp' => (float)$fl['v7p'],
|
||||
'vs' => '7 giorni precedenti'
|
||||
],
|
||||
[
|
||||
'key' => 'month',
|
||||
'title' => 'Ultimi 30 giorni',
|
||||
'n' => (int)$fl['n30'],
|
||||
'v' => (float)$fl['v30'],
|
||||
'np' => (int)$fl['n30p'],
|
||||
'vp' => (float)$fl['v30p'],
|
||||
'vs' => '30 giorni precedenti',
|
||||
'customers' => (int)$fl['c30']
|
||||
],
|
||||
];
|
||||
|
||||
// ---------------- GIUDIZIO COMPLESSIVO ----------------
|
||||
$score = ['green' => 0, 'yellow' => 0, 'red' => 0, 'grey' => 0];
|
||||
foreach ($T as $t) $score[$t['light']]++;
|
||||
@@ -402,6 +452,7 @@ if ($action === 'data') {
|
||||
'year' => $curY,
|
||||
'inv_ok' => $invOk,
|
||||
'tiles' => $T,
|
||||
'flow' => $flow,
|
||||
'score' => $score,
|
||||
'points' => $points === null ? null : round($points),
|
||||
'overall' => $overall,
|
||||
@@ -1290,6 +1341,99 @@ if ($action === 'data') {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.flow-head {
|
||||
font-weight: 900;
|
||||
font-size: 1.05rem;
|
||||
color: var(--c-ink);
|
||||
margin: 4px 0 10px;
|
||||
}
|
||||
|
||||
.flow-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.fl-card {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
background: linear-gradient(135deg, #eff6ff, #fff);
|
||||
border: 1px solid #dbeafe;
|
||||
border-radius: 16px;
|
||||
padding: 14px 16px;
|
||||
box-shadow: 0 6px 18px rgba(15, 23, 42, .05);
|
||||
transition: transform .15s ease, box-shadow .15s ease;
|
||||
}
|
||||
|
||||
.fl-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 12px 26px rgba(15, 23, 42, .1);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.fl-t {
|
||||
font-size: .78rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .5px;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.fl-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
gap: 10px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.fl-n {
|
||||
font-size: 2.1rem;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
color: var(--c-ink);
|
||||
}
|
||||
|
||||
.fl-v {
|
||||
font-size: 1.35rem;
|
||||
font-weight: 800;
|
||||
color: var(--c-ink);
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.fl-l {
|
||||
font-size: .8rem;
|
||||
color: var(--c-muted);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.fl-d {
|
||||
font-weight: 800;
|
||||
margin-left: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.fl-d.up {
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.fl-d.down {
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.fl-d.flat {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.fl-vs {
|
||||
font-size: .76rem;
|
||||
color: var(--c-muted);
|
||||
margin-top: 8px;
|
||||
border-top: 1px dashed #dbeafe;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.goodbad {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
@@ -1688,6 +1832,10 @@ if ($action === 'data') {
|
||||
<div class="ring" id="heroRing" style="--p:0;"><span id="heroPoints">—<small>PUNTEGGIO</small></span></div>
|
||||
</div>
|
||||
|
||||
<!-- ORDINI IN ARRIVO -->
|
||||
<div class="flow-head"><span data-help="sm.flow"><i class="fa-solid fa-inbox me-2"></i>Nuovi ordini</span></div>
|
||||
<div class="flow-grid mb-3" id="flow"></div>
|
||||
|
||||
<div class="goodbad mb-2">
|
||||
<div class="gb-card good">
|
||||
<h6><i class="fa-solid fa-circle-check me-1"></i> Cosa va bene</h6>
|
||||
@@ -1720,7 +1868,7 @@ if ($action === 'data') {
|
||||
<div class="legend-strip">
|
||||
<span><span class="dot green"></span> Bene</span>
|
||||
<span><span class="dot yellow"></span> Così così: da tenere d'occhio</span>
|
||||
<span><span class="dot red"></span> Da Migliorare: serve un intervento</span>
|
||||
<span><span class="dot red"></span> Male: serve un intervento</span>
|
||||
<span><span class="dot grey"></span> Dato non disponibile</span>
|
||||
<span class="ms-auto">Clicca una tessera per i dettagli · ⓘ per la spiegazione</span>
|
||||
</div>
|
||||
@@ -1754,7 +1902,7 @@ if ($action === 'data') {
|
||||
const LIGHT_LABEL = {
|
||||
green: 'Bene',
|
||||
yellow: 'Così così',
|
||||
red: 'Da Migliorare',
|
||||
red: 'Male',
|
||||
grey: 'n.d.'
|
||||
};
|
||||
const LIGHT_ICON = {
|
||||
@@ -1816,6 +1964,7 @@ if ($action === 'data') {
|
||||
}
|
||||
$('#content').show();
|
||||
renderHero(d);
|
||||
renderFlow(d);
|
||||
renderGoodBad(d);
|
||||
renderTiles(d);
|
||||
renderLists(d);
|
||||
@@ -1859,6 +2008,39 @@ if ($action === 'data') {
|
||||
$('#heroPoints').html(`${d.points === null ? '—' : d.points}<small>SU 100</small>`);
|
||||
}
|
||||
|
||||
/* ---------------- NUOVI ORDINI ---------------- */
|
||||
function arrow(cur, prev) {
|
||||
if (!prev && !cur) return '<span class="fl-d flat">= come prima</span>';
|
||||
if (!prev) return '<span class="fl-d up">▲ nuovo</span>';
|
||||
const p = (cur - prev) / Math.abs(prev) * 100;
|
||||
const r = Math.round(p);
|
||||
if (Math.abs(r) < 1) return '<span class="fl-d flat">= stabile</span>';
|
||||
return `<span class="fl-d ${r > 0 ? 'up' : 'down'}">${r > 0 ? '▲' : '▼'} ${Math.abs(r)}%</span>`;
|
||||
}
|
||||
|
||||
function renderFlow(d) {
|
||||
const icons = {
|
||||
today: 'fa-sun',
|
||||
week: 'fa-calendar-week',
|
||||
month: 'fa-calendar'
|
||||
};
|
||||
$('#flow').html((d.flow || []).map(f => `
|
||||
<a class="fl-card" href="sales_orders_stats.php" title="Apri Andamento ordini">
|
||||
<div class="fl-top"><span class="fl-t"><i class="fa-solid ${icons[f.key]} me-1"></i>${esc(f.title)}</span></div>
|
||||
<div class="fl-row">
|
||||
<div>
|
||||
<div class="fl-n">${f.n.toLocaleString('it-IT')}</div>
|
||||
<div class="fl-l">ordini ${arrow(f.n, f.np)}</div>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="fl-v">${fmtEurShort(f.v)}</div>
|
||||
<div class="fl-l">valore ${arrow(f.v, f.vp)}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fl-vs">vs ${esc(f.vs)}: ${f.np.toLocaleString('it-IT')} ordini · ${fmtEurShort(f.vp)}${f.customers !== undefined ? ` · ${f.customers} clienti nel mese` : ''}</div>
|
||||
</a>`).join(''));
|
||||
}
|
||||
|
||||
function renderGoodBad(d) {
|
||||
const ok = d.tiles.filter(t => t.light === 'green' && t.verdict);
|
||||
const ko = d.tiles.filter(t => (t.light === 'red' || t.light === 'yellow') && t.verdict)
|
||||
@@ -2019,7 +2201,7 @@ if ($action === 'data') {
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<script src="sales_help.js?v=2"></script>
|
||||
<script src="sales_help.js?v=3"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user