fix: Nettogewinn-Linie zieht Materialkosten ab, Bestellungen nach Status gruppiert mit Summen

This commit is contained in:
2026-06-17 20:48:03 +02:00
parent 19dbdbeea7
commit de14683e09

View File

@@ -106,38 +106,70 @@ function OrdersInPeriod({ period, custom }) {
api(`/tools/statistik/month-orders${q}`).then(setOrders).catch(()=>setOrders([])); api(`/tools/statistik/month-orders${q}`).then(setOrders).catch(()=>setOrders([]));
}, [period, custom]); }, [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'; 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 ( return (
<div style={S.card}> <div style={S.card}>
<div style={S.head}> <div style={S.head}>BESTELLUNGEN {periodLabel} {orders ? `(${orders.length})` : ''}</div>
BESTELLUNGEN {periodLabel} {orders ? `(${orders.length})` : ''}
</div>
{!orders {!orders
? <div style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:12}}>Lädt</div> ? <div style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:12}}>Lädt</div>
: !orders.length : !orders.length
? <div style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:12}}>Keine Bestellungen diesen Monat.</div> ? <div style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:12}}>Keine Bestellungen im Zeitraum.</div>
: orders.map(o => { : STATUS_ORDER.filter(st => grouped[st]?.length).map(st => {
const st = !!o.bezahlt && !!o.abgeholt ? 'abgeschlossen' : !!o.bezahlt ? 'bezahlt' : o.status; const col = STATUS_COLOR[st];
const col = st==='abgeschlossen'?'#4ade80': st==='bezahlt'?'#c084fc': statusColor[st]||'#888'; const group = grouped[st];
const total = group.reduce((s,o)=>s+(o.revenue||0),0);
return ( return (
<div key={o.id} style={{display:'flex',alignItems:'center',gap:10,padding:'8px 0', <div key={st} style={{marginBottom:16}}>
borderBottom:'1px solid rgba(255,255,255,0.05)',flexWrap:'wrap'}}> {/* Status-Header mit Summe */}
<span style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:10,flexShrink:0}}> <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',
{new Date(o.created_at).toLocaleDateString('de-DE')} padding:'6px 10px',background:`${col}10`,borderRadius:8,marginBottom:6}}>
</span> <div style={{display:'flex',alignItems:'center',gap:8}}>
<span style={{color:'rgba(255,255,255,0.8)',fontFamily:'monospace',fontSize:12,flex:1}}> <span style={{background:`${col}20`,border:`1px solid ${col}44`,borderRadius:10,
{o.name} padding:'2px 10px',color:col,fontFamily:'monospace',fontSize:10}}>
</span> {STATUS_LABEL[st]}
<span style={{background:`${col}18`,border:`1px solid ${col}44`,borderRadius:6, </span>
padding:'2px 8px',color:col,fontFamily:'monospace',fontSize:9,flexShrink:0}}> <span style={{color:'rgba(255,255,255,0.35)',fontFamily:'monospace',fontSize:10}}>
{st} {group.length} Bestellung{group.length!==1?'en':''}
</span> </span>
<span style={{color:o.revenue>0?'#4ade80':'rgba(255,255,255,0.3)', </div>
fontFamily:"'Space Mono',monospace",fontSize:12,fontWeight:700,flexShrink:0}}> {total > 0 && (
{fmt(o.revenue||0)} <span style={{color:col,fontFamily:"'Space Mono',monospace",fontSize:12,fontWeight:700}}>
</span> Σ {fmt(total)}
</span>
)}
</div>
{/* Einträge */}
{group.map(o => (
<div key={o.id} style={{display:'flex',alignItems:'center',gap:10,padding:'7px 10px',
borderBottom:'1px solid rgba(255,255,255,0.04)'}}>
<span style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:10,flexShrink:0,width:60}}>
{new Date(o.created_at).toLocaleDateString('de-DE',{day:'2-digit',month:'2-digit'})}
</span>
<span style={{color:'rgba(255,255,255,0.8)',fontFamily:'monospace',fontSize:12,flex:1}}>
{o.name}
</span>
<span style={{color:o.revenue>0?'#4ade80':'rgba(255,255,255,0.25)',
fontFamily:"'Space Mono',monospace",fontSize:12,fontWeight:700,flexShrink:0}}>
{fmt(o.revenue||0)}
</span>
</div>
))}
</div> </div>
); );
}) })