fix: fix overlapping PDF labels and show net tax gross prices in wizard
All checks were successful
Staging Build / build (push) Successful in 3m25s

This commit is contained in:
DanielS
2026-07-03 01:13:16 +02:00
parent e67695e36e
commit 147dab5607
2 changed files with 118 additions and 51 deletions

View File

@@ -213,10 +213,7 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => {
<Text>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(taxAmount)}</Text> <Text>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(taxAmount)}</Text>
</View> </View>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: 5, borderTopWidth: 1, borderTopColor: '#000', paddingTop: 5 }}> <View style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: 5, borderTopWidth: 1, borderTopColor: '#000', paddingTop: 5 }}>
<Text style={styles.totalLabel}>Gesamtbetrag (netto):</Text>
<Text style={styles.totalLabel}>MwSt.Betrag:</Text>
<Text style={styles.totalLabel}>Gesamtbetrag (brutto):</Text> <Text style={styles.totalLabel}>Gesamtbetrag (brutto):</Text>
<Text style={styles.totalLabel}>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(total)}</Text> <Text style={styles.totalLabel}>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(total)}</Text>
</View> </View>
</View> </View>

View File

@@ -294,6 +294,14 @@ export function OrderWizard({
return { monthlyTotal: monthly, oneTimeTotal: oneTime } return { monthlyTotal: monthly, oneTimeTotal: oneTime }
}, [selections, products, categories, moduleQuantities, updatePriceModifier]) }, [selections, products, categories, moduleQuantities, updatePriceModifier])
const oneTimeNet = oneTimeTotal
const oneTimeTax = oneTimeNet * 0.19
const oneTimeGross = oneTimeNet + oneTimeTax
const monthlyNet = monthlyTotal
const monthlyTax = monthlyNet * 0.19
const monthlyGross = monthlyNet + monthlyTax
// Helper: update product selection for a category (resets modules) // Helper: update product selection for a category (resets modules)
function selectProduct(catId: string, productId: string) { function selectProduct(catId: string, productId: string) {
setSelections(prev => { setSelections(prev => {
@@ -981,35 +989,67 @@ export function OrderWizard({
})} })}
<Separator className="bg-white/10" /> <Separator className="bg-white/10" />
{oneTimeTotal > 0 && monthlyTotal > 0 ? ( {oneTimeTotal > 0 && monthlyTotal > 0 ? (
<div className="space-y-2"> <div className="space-y-3">
<div className="flex justify-between text-base font-semibold text-white"> <div className="space-y-1">
<span className="text-slate-400">Einmalig gesamt:</span> <p className="text-xs font-semibold text-slate-500 uppercase tracking-wider">Einmalig:</p>
<span> <div className="flex justify-between text-xs text-slate-400">
{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeTotal)} <span>Netto:</span>
</span> <span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeNet)}</span>
</div>
<div className="flex justify-between text-xs text-slate-400">
<span>zzgl. 19% MwSt.:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeTax)}</span>
</div>
<div className="flex justify-between text-sm font-bold text-white">
<span>Gesamt (brutto):</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeGross)}</span>
</div>
</div> </div>
<div className="flex justify-between text-base font-semibold text-white"> <div className="space-y-1 pt-2 border-t border-white/10">
<span className="text-slate-400">Monatlich gesamt:</span> <p className="text-xs font-semibold text-slate-500 uppercase tracking-wider">Monatlich:</p>
<span> <div className="flex justify-between text-xs text-slate-400">
{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyTotal)} <span>Netto:</span>
{' '}<span className="text-xs font-normal text-slate-400">/ Monat</span> <span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyNet)} / mtl.</span>
</span> </div>
<div className="flex justify-between text-xs text-slate-400">
<span>zzgl. 19% MwSt.:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyTax)} / mtl.</span>
</div>
<div className="flex justify-between text-sm font-bold text-white">
<span>Gesamt (brutto):</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyGross)} / mtl.</span>
</div>
</div> </div>
</div> </div>
) : oneTimeTotal > 0 ? ( ) : oneTimeTotal > 0 ? (
<div className="flex justify-between text-xl font-bold text-gradient"> <div className="space-y-1">
<span>Gesamt (einmalig):</span> <div className="flex justify-between text-xs text-slate-400">
<span> <span>Netto-Gesamtbetrag:</span>
{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeTotal)} <span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeNet)}</span>
</span> </div>
<div className="flex justify-between text-xs text-slate-400">
<span>zzgl. 19% MwSt.:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeTax)}</span>
</div>
<div className="flex justify-between text-base font-bold text-gradient">
<span>Gesamtbetrag (brutto):</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeGross)}</span>
</div>
</div> </div>
) : ( ) : (
<div className="flex justify-between text-xl font-bold text-gradient"> <div className="space-y-1">
<span>Gesamt:</span> <div className="flex justify-between text-xs text-slate-400">
<span> <span>Netto-Gesamtbetrag:</span>
{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyTotal)} <span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyNet)} / mtl.</span>
{' '}<span className="text-sm font-normal text-slate-400">/ Monat</span> </div>
</span> <div className="flex justify-between text-xs text-slate-400">
<span>zzgl. 19% MwSt.:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyTax)} / mtl.</span>
</div>
<div className="flex justify-between text-base font-bold text-gradient">
<span>Gesamtbetrag (brutto):</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyGross)} / mtl.</span>
</div>
</div> </div>
)} )}
{updatePriceModifier.label && ( {updatePriceModifier.label && (
@@ -1139,47 +1179,77 @@ export function OrderWizard({
</div> </div>
</div> </div>
{oneTimeTotal > 0 && monthlyTotal > 0 ? ( {oneTimeTotal > 0 && monthlyTotal > 0 ? (
<div className="space-y-2 border-t border-white/10 pt-4"> <div className="space-y-4 border-t border-white/10 pt-4">
<div className="flex justify-between text-lg font-bold text-white"> <div className="space-y-1">
<span className="text-slate-400">Einmaliger Gesamtbetrag:</span> <p className="text-xs font-semibold text-slate-500 uppercase tracking-wider">Einmaliger Betrag:</p>
<span> <div className="flex justify-between text-sm text-slate-400">
{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeTotal)} <span>Netto:</span>
</span> <span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeNet)}</span>
</div>
<div className="flex justify-between text-sm text-slate-400">
<span>zzgl. 19% MwSt.:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeTax)}</span>
</div>
<div className="flex justify-between text-base font-bold text-white">
<span>Brutto:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeGross)}</span>
</div>
</div> </div>
{updatePriceModifier.label && ( {updatePriceModifier.label && (
<div className="text-sm text-green-400 font-semibold bg-green-500/10 p-2 rounded border border-green-500/20 my-1"> <div className="text-sm text-green-400 font-semibold bg-green-500/10 p-2 rounded border border-green-500/20 my-1">
{updatePriceModifier.label} {updatePriceModifier.label}
</div> </div>
)} )}
<div className="flex justify-between text-lg font-bold text-white"> <div className="space-y-1 pt-2 border-t border-white/10">
<span className="text-slate-400">Monatlicher Gesamtbetrag:</span> <p className="text-xs font-semibold text-slate-500 uppercase tracking-wider">Monatlicher Betrag:</p>
<span> <div className="flex justify-between text-sm text-slate-400">
{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyTotal)} <span>Netto:</span>
{' '}<span className="text-sm font-normal text-slate-400">/ Monat</span> <span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyNet)} / mtl.</span>
</span> </div>
<div className="flex justify-between text-sm text-slate-400">
<span>zzgl. 19% MwSt.:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyTax)} / mtl.</span>
</div>
<div className="flex justify-between text-base font-bold text-white">
<span>Brutto:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyGross)} / mtl.</span>
</div>
</div> </div>
</div> </div>
) : oneTimeTotal > 0 ? ( ) : oneTimeTotal > 0 ? (
<div className="flex flex-col border-t border-white/10 pt-4 gap-1.5"> <div className="space-y-1 border-t border-white/10 pt-4">
<div className="flex justify-between text-xl font-bold text-gradient"> <div className="flex justify-between text-sm text-slate-400">
<span>Gesamtbetrag:</span> <span>Netto-Gesamtbetrag:</span>
<span> <span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeNet)}</span>
{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeTotal)} </div>
</span> <div className="flex justify-between text-sm text-slate-400">
<span>zzgl. 19% MwSt.:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeTax)}</span>
</div> </div>
{updatePriceModifier.label && ( {updatePriceModifier.label && (
<div className="text-sm text-green-400 font-semibold bg-green-500/10 p-2 rounded border border-green-500/20 self-end"> <div className="text-sm text-green-400 font-semibold bg-green-500/10 p-2 rounded border border-green-500/20 my-1">
{updatePriceModifier.label} {updatePriceModifier.label}
</div> </div>
)} )}
<div className="flex justify-between text-xl font-bold text-gradient pt-1 border-t border-white/5">
<span>Gesamtbetrag (brutto):</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(oneTimeGross)}</span>
</div>
</div> </div>
) : ( ) : (
<div className="flex justify-between text-xl font-bold text-gradient border-t border-white/10 pt-4"> <div className="space-y-1 border-t border-white/10 pt-4">
<span>Gesamtbetrag:</span> <div className="flex justify-between text-sm text-slate-400">
<span> <span>Netto-Gesamtbetrag:</span>
{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyTotal)} <span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyNet)} / mtl.</span>
{' '}<span className="text-sm font-normal text-slate-400">/ Monat</span> </div>
</span> <div className="flex justify-between text-sm text-slate-400">
<span>zzgl. 19% MwSt.:</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyTax)} / mtl.</span>
</div>
<div className="flex justify-between text-xl font-bold text-gradient pt-1 border-t border-white/5">
<span>Gesamtbetrag (brutto):</span>
<span>{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(monthlyGross)} / mtl.</span>
</div>
</div> </div>
)} )}
<p className="text-xs text-slate-500 italic"> <p className="text-xs text-slate-500 italic">