From de14683e098fc8877fd2d6deb11640362b401cff Mon Sep 17 00:00:00 2001 From: Dicken Date: Wed, 17 Jun 2026 20:48:03 +0200 Subject: [PATCH] fix: Nettogewinn-Linie zieht Materialkosten ab, Bestellungen nach Status gruppiert mit Summen --- frontend/src/tools/statistik.jsx | 80 ++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/frontend/src/tools/statistik.jsx b/frontend/src/tools/statistik.jsx index 731fc22..398d34e 100644 --- a/frontend/src/tools/statistik.jsx +++ b/frontend/src/tools/statistik.jsx @@ -106,38 +106,70 @@ function OrdersInPeriod({ period, custom }) { api(`/tools/statistik/month-orders${q}`).then(setOrders).catch(()=>setOrders([])); }, [period, custom]); - const statusColor = { warteliste:'#ffe66d', in_arbeit:'#4ecdc4', fertig:'#6bcb77' }; + const STATUS_ORDER = ['warteliste','in_arbeit','fertig','bezahlt','abgeschlossen']; + const STATUS_COLOR = { warteliste:'#ffe66d', in_arbeit:'#4ecdc4', fertig:'#6bcb77', bezahlt:'#c084fc', abgeschlossen:'#4ade80' }; + const STATUS_LABEL = { warteliste:'Warteliste', in_arbeit:'In Arbeit', fertig:'Fertig', bezahlt:'Bezahlt', abgeschlossen:'Abgeschlossen' }; + const periodLabel = period==='week'?'DIESER WOCHE':period==='month'?'DIESEM MONAT':period==='year'?'DIESEM JAHR':period==='all'?'GESAMT':'IM ZEITRAUM'; + // Gruppieren nach Status + const grouped = {}; + (orders||[]).forEach(o => { + const st = !!o.bezahlt && !!o.abgeholt ? 'abgeschlossen' : !!o.bezahlt ? 'bezahlt' : o.status; + if (!grouped[st]) grouped[st] = []; + grouped[st].push({ ...o, _st: st }); + }); + + // Innerhalb jeder Gruppe nach Datum sortieren (neueste zuerst) + Object.values(grouped).forEach(g => g.sort((a,b) => new Date(b.created_at) - new Date(a.created_at))); + return (
-
- BESTELLUNGEN {periodLabel} {orders ? `(${orders.length})` : ''} -
+
BESTELLUNGEN {periodLabel} {orders ? `(${orders.length})` : ''}
{!orders ?
Lädt…
: !orders.length - ?
Keine Bestellungen diesen Monat.
- : orders.map(o => { - const st = !!o.bezahlt && !!o.abgeholt ? 'abgeschlossen' : !!o.bezahlt ? 'bezahlt' : o.status; - const col = st==='abgeschlossen'?'#4ade80': st==='bezahlt'?'#c084fc': statusColor[st]||'#888'; + ?
Keine Bestellungen im Zeitraum.
+ : STATUS_ORDER.filter(st => grouped[st]?.length).map(st => { + const col = STATUS_COLOR[st]; + const group = grouped[st]; + const total = group.reduce((s,o)=>s+(o.revenue||0),0); return ( -
- - {new Date(o.created_at).toLocaleDateString('de-DE')} - - - {o.name} - - - {st} - - 0?'#4ade80':'rgba(255,255,255,0.3)', - fontFamily:"'Space Mono',monospace",fontSize:12,fontWeight:700,flexShrink:0}}> - {fmt(o.revenue||0)} - +
+ {/* Status-Header mit Summe */} +
+
+ + {STATUS_LABEL[st]} + + + {group.length} Bestellung{group.length!==1?'en':''} + +
+ {total > 0 && ( + + Σ {fmt(total)} + + )} +
+ {/* Einträge */} + {group.map(o => ( +
+ + {new Date(o.created_at).toLocaleDateString('de-DE',{day:'2-digit',month:'2-digit'})} + + + {o.name} + + 0?'#4ade80':'rgba(255,255,255,0.25)', + fontFamily:"'Space Mono',monospace",fontSize:12,fontWeight:700,flexShrink:0}}> + {fmt(o.revenue||0)} + +
+ ))}
); })