feat(rechnung): branded invoice with VAT ID and per-rate grouping

The invoice PDF and the invoice page now share one branded layout:
logo (uploaded brand logo, otherwise the drawn honeycomb mark) and
wordmark in the header, honey accents, a forest-green table header,
a meta box with invoice number, date, order number and VAT ID, and a
footer with address, contact, VAT ID and page numbers on every page.

A mixed cart (e.g. honey at 7 % and a beeswax candle at 19 %) lists
its items in one block per VAT rate with a subtotal each. Next to the
totals, a VAT table shows net, VAT and gross per rate plus a sum row.
Long invoices continue on further pages with the table header repeated.

The VAT identification number is a new company field
(company.vatId), editable in Admin > Inhalte, defaulting to the
number already stated in the imprint.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-01 00:49:59 +02:00
1 parent 1daef79026
commit 77bdd9958c
12 files changed
+965 -246

No files matched your search

+19 -7
View File
@@ -1561,21 +1561,33 @@ export const en: Dictionary = {
loginRequiredError: "Please sign in to view the invoice.",
backToOrders: "Back to my orders",
downloadPdf: "Download PDF",
invoiceLabel: (invoiceNumber) => `Invoice ${invoiceNumber}`,
orderLabel: (orderNumber) => `Order ${orderNumber}`,
dateLabel: "Date:",
documentTitle: "Invoice",
billedToLabel: "Billed to",
invoiceNumberLabel: "Invoice number",
invoiceDateLabel: "Invoice date",
orderNumberLabel: "Order number",
vatIdLabel: "VAT ID",
itemHeader: "Item",
vatRateHeader: "VAT",
quantityHeader: "Qty",
priceHeader: "Price",
priceHeader: "Unit price",
totalHeader: "Total",
groupHeading: (ratePercent) => `Items at ${ratePercent}% VAT`,
groupSubtotalLabel: (ratePercent) => `Subtotal ${ratePercent}%`,
subtotalLabel: "Subtotal",
shippingLabel: "Shipping",
freeShipping: "free",
discountLabel: "Discount",
netLabel: "Net amount",
vatLabel: (ratePercent) => `plus ${ratePercent}% VAT`,
taxSummaryHeading: "VAT included",
taxRateHeader: "Rate",
netHeader: "Net",
vatAmountHeader: "VAT",
grossHeader: "Gross",
smallBusinessNote: "No VAT is charged (small-business scheme, § 19 German VAT Act).",
totalLabel: "Total",
totalLabel: "Total amount",
pricesIncludeVat: "All prices include statutory VAT.",
thankYou: "Thank you for supporting our apiary!",
pageLabel: (page, total) => `Page ${page} of ${total}`,
legalNote: "This invoice was generated automatically and is valid without a signature.",
},
addressesPage: {