diff --git a/src/correctionInvoicePdf.tsx b/src/correctionInvoicePdf.tsx
index e021804..49a27af 100644
--- a/src/correctionInvoicePdf.tsx
+++ b/src/correctionInvoicePdf.tsx
@@ -65,7 +65,9 @@ const styles = StyleSheet.create({
tableHeader: { flexDirection: "row", backgroundColor: BG_MUTED, paddingVertical: 8, paddingHorizontal: 10 },
tableRow: { flexDirection: "row", paddingVertical: 8, paddingHorizontal: 10, borderTopWidth: 1, borderTopColor: BORDER },
tableRowAlt: { backgroundColor: BG_MUTED },
- colImage: { width: 28 },
+ // marginRight (not a tableRow `gap`) — see invoicePdf.tsx's own comment
+ // on this same style, kept identical between the two documents.
+ colImage: { width: 28, marginRight: 10 },
itemImage: { width: 28, height: 28, borderRadius: 3 },
colName: { flex: 3 },
colQty: { flex: 1, textAlign: "right" },
@@ -75,6 +77,9 @@ const styles = StyleSheet.create({
bundleLine: { fontSize: 8, color: TEXT_MUTED, marginTop: 2 },
summary: { alignItems: "flex-end", marginBottom: 24 },
summaryBox: { width: 240, backgroundColor: BG_MUTED, borderRadius: 6, padding: 14 },
+ // See invoicePdf.tsx's own comment on this same style — groups rows that
+ // belong together with a bit of breathing room between groups.
+ summaryCluster: { marginBottom: 6 },
summaryRow: { flexDirection: "row", justifyContent: "space-between", paddingVertical: 2 },
summaryLabel: { fontSize: 10, color: TEXT_MUTED },
summaryValue: { fontSize: 10 },
@@ -85,7 +90,7 @@ const styles = StyleSheet.create({
// pinned to the bottom of the page regardless of content height above,
// same as invoicePdf.tsx's own footer. (One of the two pre-package
// copies this file replaces was missing `fixed` — see this package's
- // README.)
+ // README.) Centered, same reasoning as invoicePdf.tsx's own footer.
footer: {
position: "absolute",
bottom: 32,
@@ -96,6 +101,7 @@ const styles = StyleSheet.create({
paddingTop: 12,
fontSize: 8,
color: TEXT_MUTED,
+ textAlign: "center",
},
});
@@ -173,6 +179,21 @@ function groupByTaxRate(
);
}
+// Same split as invoicePdf.tsx's own DeliveryLines — Packstation number
+// and Postnummer each get their own line rather than one combined
+// "Packstation X · Postnummer Y" line.
+function DeliveryLines({ deliveryMethod, street, packstationNumber, postNumber }: { deliveryMethod?: string | null; street?: string | null; packstationNumber?: string | null; postNumber?: string | null }) {
+ if (deliveryMethod === "packstation") {
+ return (
+ <>
+ Packstation {packstationNumber}
+ Postnummer {postNumber}
+ >
+ );
+ }
+ return {street};
+}
+
function CorrectionInvoiceDocument({ kind, order, seller }: { kind: CorrectionInvoiceKind; order: CorrectionInvoiceOrder; seller: InvoiceSeller }) {
const kindLabel = kind === "storno" ? "Stornorechnung" : "Gutschrift";
const lines = resolveLineItems(kind, order.items);
@@ -182,8 +203,6 @@ function CorrectionInvoiceDocument({ kind, order, seller }: { kind: CorrectionIn
kind === "storno"
? "vollständige Stornierung des ursprünglichen Rechnungsbetrags (inkl. Versand)."
: "Gutschrift für die zurückgesendeten Artikel — ohne Versandkosten, der ursprüngliche Rabatt bleibt unverändert bei den behaltenen Artikeln.";
- const deliveryLine =
- order.deliveryMethod === "address" ? order.street : `Packstation ${order.packstationNumber} · Postnummer ${order.postNumber}`;
return (
@@ -213,7 +232,7 @@ function CorrectionInvoiceDocument({ kind, order, seller }: { kind: CorrectionIn
{order.customerFirstName} {order.customerLastName}
- {deliveryLine}
+
{order.zip} {order.city}
@@ -268,13 +287,13 @@ function CorrectionInvoiceDocument({ kind, order, seller }: { kind: CorrectionIn
the original invoice's own Versand row. Gutschrift never
reverses shipping, so this never renders for it. */}
{kind === "storno" && order.shippingCost > 0 && (
-
+
Versand
-{formatPrice(order.shippingCost)}
)}
{rateGroups.map((g) => (
-
+
Netto
-{formatPrice(g.net)}
@@ -283,7 +302,7 @@ function CorrectionInvoiceDocument({ kind, order, seller }: { kind: CorrectionIn
zzgl. {g.rate}% MwSt.
-{formatPrice(g.tax)}
-
+
))}
Gesamt
diff --git a/src/invoicePdf.tsx b/src/invoicePdf.tsx
index acc65e0..68504d9 100644
--- a/src/invoicePdf.tsx
+++ b/src/invoicePdf.tsx
@@ -56,7 +56,11 @@ const styles = StyleSheet.create({
tableHeader: { flexDirection: "row", backgroundColor: BG_MUTED, paddingVertical: 8, paddingHorizontal: 10 },
tableRow: { flexDirection: "row", paddingVertical: 8, paddingHorizontal: 10, borderTopWidth: 1, borderTopColor: BORDER },
tableRowAlt: { backgroundColor: BG_MUTED },
- colImage: { width: 28 },
+ // marginRight (not a tableRow `gap`) — explicit and unambiguous across
+ // react-pdf's flexbox implementation for a mixed Image/Text row, rather
+ // than relying on a row-level `gap` to apply consistently between an
+ // empty-when-no-image colImage and colName.
+ colImage: { width: 28, marginRight: 10 },
itemImage: { width: 28, height: 28, borderRadius: 3 },
colName: { flex: 3 },
colQty: { flex: 1, textAlign: "right" },
@@ -66,15 +70,29 @@ const styles = StyleSheet.create({
bundleLine: { fontSize: 8, color: TEXT_MUTED, marginTop: 2 },
summary: { alignItems: "flex-end", marginBottom: 24 },
summaryBox: { width: 240, backgroundColor: BG_MUTED, borderRadius: 6, padding: 14 },
+ // Groups rows that belong together (Rabatt+Versand; each rate's own
+ // Netto/MwSt pair) with a bit of breathing room between groups, while
+ // rows *within* a group stay at the original tight spacing — a visual
+ // cue that e.g. "Netto"/"zzgl. 19% MwSt." are one line item's two halves,
+ // not just an undifferentiated stack of numbers.
+ summaryCluster: { marginBottom: 6 },
summaryRow: { flexDirection: "row", justifyContent: "space-between", paddingVertical: 2 },
summaryLabel: { fontSize: 10, color: TEXT_MUTED },
summaryValue: { fontSize: 10 },
grandTotalRow: { flexDirection: "row", justifyContent: "space-between", paddingTop: 8, marginTop: 6, borderTopWidth: 1, borderTopColor: BORDER },
grandTotalLabel: { fontSize: 12, fontFamily: "Helvetica-Bold" },
grandTotalValue: { fontSize: 12, fontFamily: "Helvetica-Bold" },
+ // Moved here (below Gesamt) from the top meta row — reads more naturally
+ // right next to the amount it's confirming was paid, and keeps the meta
+ // row itself to just the three reference numbers.
+ paidBadgeRow: { alignItems: "flex-end", marginTop: 10 },
// `fixed` (below, on the element) + absolute positioning — always pinned
// to the bottom of the page regardless of how much content is above it,
// rather than just following wherever the content flow happens to end.
+ // Centered (not left-aligned) — reads as a formal closing block rather
+ // than a stray left-hanging line once the page's content above is itself
+ // centered around the summary box on the right and the table spanning
+ // full width.
footer: {
position: "absolute",
bottom: 32,
@@ -85,6 +103,7 @@ const styles = StyleSheet.create({
paddingTop: 12,
fontSize: 8,
color: TEXT_MUTED,
+ textAlign: "center",
},
});
@@ -185,6 +204,23 @@ function groupByTaxRate(order: InvoiceOrder, defaultRate: number): { rate: numbe
);
}
+// Packstation deliveries show number and Postnummer on their own lines
+// (not one combined "Packstation X · Postnummer Y" line) — each is looked
+// up independently at a DHL Packstation, easier to scan stacked than
+// split by a middle dot in running text. A plain street address stays a
+// single line, same as before.
+function DeliveryLines({ deliveryMethod, street, packstationNumber, postNumber }: { deliveryMethod?: string | null; street?: string | null; packstationNumber?: string | null; postNumber?: string | null }) {
+ if (deliveryMethod === "packstation") {
+ return (
+ <>
+ Packstation {packstationNumber}
+ Postnummer {postNumber}
+ >
+ );
+ }
+ return {street};
+}
+
// Exported (not just used internally by renderInvoicePdf below) so
// /company-settings-preview's client component can mount it directly with
// @react-pdf/renderer's browser-side — a live, in-browser
@@ -194,12 +230,6 @@ function groupByTaxRate(order: InvoiceOrder, defaultRate: number): { rate: numbe
export function InvoiceDocument({ order, seller }: { order: InvoiceOrder; seller: InvoiceSeller }) {
const rateGroups = groupByTaxRate(order, seller.taxRatePercent);
const paid = isPaidImmediately(order.paymentMethodTitle);
- const deliveryLine =
- order.deliveryMethod === "address" ? order.street : `Packstation ${order.packstationNumber} · Postnummer ${order.postNumber}`;
- const shippingLine =
- order.shippingDeliveryMethod === "packstation"
- ? `Packstation ${order.shippingPackstationNumber} · Postnummer ${order.shippingPostNumber}`
- : order.shippingStreet;
const addressBlockStyle = order.hasDifferentShippingAddress ? styles.addressBlockThird : styles.addressBlock;
return (
@@ -226,7 +256,7 @@ export function InvoiceDocument({ order, seller }: { order: InvoiceOrder; seller
{order.customerFirstName} {order.customerLastName}
- {deliveryLine}
+
{order.zip} {order.city}
@@ -238,7 +268,12 @@ export function InvoiceDocument({ order, seller }: { order: InvoiceOrder; seller
{order.shippingFirstName} {order.shippingLastName}
- {shippingLine}
+
{order.shippingZip} {order.shippingCity}
@@ -260,11 +295,6 @@ export function InvoiceDocument({ order, seller }: { order: InvoiceOrder; seller
Bestellnummer
{order.orderNumber}
- {paid && (
-
- ✓ Bereits beglichen ({order.paymentMethodTitle})
-
- )}
@@ -296,18 +326,20 @@ export function InvoiceDocument({ order, seller }: { order: InvoiceOrder; seller
- {order.discountAmount > 0 && (
+
+ {order.discountAmount > 0 && (
+
+ Rabatt{order.discountCode ? ` (${order.discountCode})` : ""}
+ -{formatPrice(order.discountAmount)}
+
+ )}
- Rabatt{order.discountCode ? ` (${order.discountCode})` : ""}
- -{formatPrice(order.discountAmount)}
+ Versand
+ {order.shippingCost === 0 ? "Kostenlos" : formatPrice(order.shippingCost)}
- )}
-
- Versand
- {order.shippingCost === 0 ? "Kostenlos" : formatPrice(order.shippingCost)}
{rateGroups.map((g) => (
-
+
Netto
{formatPrice(g.net)}
@@ -316,15 +348,21 @@ export function InvoiceDocument({ order, seller }: { order: InvoiceOrder; seller
zzgl. {g.rate}% MwSt.
{formatPrice(g.tax)}
-
+
))}
Gesamt
{formatPrice(order.total)}
+ {paid && (
+
+
+ ✓ Bereits beglichen ({order.paymentMethodTitle})
+
+
+ )}
-