fix: correctly split and display one-time and monthly recurring items in purchase order pdf
All checks were successful
Staging Build / build (push) Successful in 2m46s
All checks were successful
Staging Build / build (push) Successful in 2m46s
This commit is contained in:
@@ -99,9 +99,29 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => {
|
||||
const taxRate = orderSnapshot?.tax_rate ?? 19;
|
||||
const isSubscription = order?.type === 'subscription' || orderSnapshot?.billing_cycle === 'monthly';
|
||||
|
||||
const totalNet = items.reduce((sum: number, item: any) => sum + (item.item_total || 0), 0);
|
||||
const totalTax = Math.round(totalNet * (taxRate / 100) * 100) / 100;
|
||||
const totalGross = Math.round((totalNet + totalTax) * 100) / 100;
|
||||
let oneTimeNet = 0;
|
||||
let monthlyNet = 0;
|
||||
|
||||
items.forEach((item: any) => {
|
||||
if (item.billing_interval === 'monthly') {
|
||||
monthlyNet += item.base_price || 0;
|
||||
} else {
|
||||
oneTimeNet += item.base_price || 0;
|
||||
}
|
||||
|
||||
item.selected_modules?.forEach((mod: any) => {
|
||||
const qty = mod.quantity || 1;
|
||||
const price = mod.total_price ?? (mod.price * qty);
|
||||
// Module sind monatliche wiederkehrende Beträge (Abo/Miete)
|
||||
monthlyNet += price;
|
||||
});
|
||||
});
|
||||
|
||||
const oneTimeTax = Math.round(oneTimeNet * (taxRate / 100) * 100) / 100;
|
||||
const oneTimeGross = Math.round((oneTimeNet + oneTimeTax) * 100) / 100;
|
||||
|
||||
const monthlyTax = Math.round(monthlyNet * (taxRate / 100) * 100) / 100;
|
||||
const monthlyGross = Math.round((monthlyNet + monthlyTax) * 100) / 100;
|
||||
|
||||
const formattedPrice = (val: number) =>
|
||||
new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(val);
|
||||
@@ -170,7 +190,7 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => {
|
||||
</View>
|
||||
<View style={styles.tableColPrice}>
|
||||
<Text>
|
||||
{formattedPrice(item.base_price)} {isSubscription ? 'mtl.' : 'einmalig'}
|
||||
{formattedPrice(item.base_price)} {item.billing_interval === 'one_time' ? 'einmalig' : 'mtl.'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -186,7 +206,7 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => {
|
||||
</View>
|
||||
<View style={styles.tableColPrice}>
|
||||
<Text style={{ color: '#666' }}>
|
||||
+{formattedPrice(price)}
|
||||
+{formattedPrice(price)} mtl.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -199,23 +219,42 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => {
|
||||
</View>
|
||||
|
||||
<View style={styles.total}>
|
||||
<View style={{ width: '70%' }}>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 3 }}>
|
||||
<Text>Netto-Zwischensumme:</Text>
|
||||
<Text>{formattedPrice(totalNet)}{isSubscription ? ' / mtl.' : ''}</Text>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 3 }}>
|
||||
<Text>zzgl. {taxRate}% USt:</Text>
|
||||
<Text>{formattedPrice(totalTax)}{isSubscription ? ' / mtl.' : ''}</Text>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: 5, borderTopWidth: 1, borderTopColor: '#000', paddingTop: 5 }}>
|
||||
<Text style={styles.totalLabel}>
|
||||
Gesamtbetrag (brutto):
|
||||
</Text>
|
||||
<Text style={styles.totalLabel}>
|
||||
{formattedPrice(totalGross)}{isSubscription ? ' / mtl.' : ''}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ width: '75%' }}>
|
||||
{oneTimeNet > 0 && (
|
||||
<View style={{ marginBottom: 6 }}>
|
||||
<Text style={{ fontSize: 9, fontWeight: 'bold', color: '#1e293b', marginBottom: 2 }}>Einmalige Beträge:</Text>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 2 }}>
|
||||
<Text>Netto-Zwischensumme:</Text>
|
||||
<Text>{formattedPrice(oneTimeNet)}</Text>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 2 }}>
|
||||
<Text>zzgl. {taxRate}% USt:</Text>
|
||||
<Text>{formattedPrice(oneTimeTax)}</Text>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', fontWeight: 'bold' }}>
|
||||
<Text>Gesamt einmalig (brutto):</Text>
|
||||
<Text>{formattedPrice(oneTimeGross)}</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{monthlyNet > 0 && (
|
||||
<View style={{ marginTop: 4, paddingTop: 4, borderTopWidth: oneTimeNet > 0 ? 1 : 0, borderTopColor: '#e2e8f0' }}>
|
||||
<Text style={{ fontSize: 9, fontWeight: 'bold', color: '#1e293b', marginBottom: 2 }}>Monatlich wiederkehrende Beträge:</Text>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 2 }}>
|
||||
<Text>Netto-Zwischensumme:</Text>
|
||||
<Text>{formattedPrice(monthlyNet)} / mtl.</Text>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 2 }}>
|
||||
<Text>zzgl. {taxRate}% USt:</Text>
|
||||
<Text>{formattedPrice(monthlyTax)} / mtl.</Text>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', fontWeight: 'bold' }}>
|
||||
<Text>Gesamt monatlich (brutto):</Text>
|
||||
<Text>{formattedPrice(monthlyGross)} / mtl.</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user