Add Kleinunternehmerregelung (§19 UStG) support
Validate e-invoices / mustang (push) Successful in 43s

InvoiceOrder/CorrectionInvoiceOrder gain an optional order-level
kleinunternehmer flag, snapshotted per order (same pattern as vatExempt)
so a later toggle of the tenant's setting never rewrites an
already-issued invoice. Takes precedence over vatExempt.

- Visual PDF: "enthält X% MwSt." becomes the §19 UStG notice.
- E-invoice XML: new UNTDID 5305 category "E" with a free-text exemption
  reason (no VATEX code — §19 UStG has none, BR-E-10 allows text alone).
- New Mustang CI fixture + buildEInvoiceData unit test for the "E" path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Marco
2026-07-24 12:51:13 +00:00
parent c28ceb7bd3
commit 51ae8a9c0a
7 changed files with 202 additions and 38 deletions
+33 -1
View File
@@ -85,6 +85,35 @@ const CORRECTION_ORDER: CorrectionInvoiceOrder = {
total: ORDER.total,
};
// §19 UStG Kleinunternehmer — every item snapshotted at 0% (exactly what
// api/checkout/route.ts forces when the tenant has company-settings.
// kleinunternehmer set), UNTDID 5305 category "E" with a free-text
// exemption reason instead of "S"/percent-rated lines. Own fixture rather
// than a variant of ORDER above, since a real Kleinunternehmer order never
// has a positive rate to begin with — mixing that into the 19%/7% fixture
// would test a combination (kleinunternehmer + a nonzero catalog rate)
// that can't actually happen in production.
const KLEINUNTERNEHMER_ORDER: InvoiceOrder = {
orderNumber: "#EP-MUSTANG-0002",
invoiceNumber: "RE-MUSTANG-0002",
invoiceIssuedAt: new Date().toISOString(),
customerFirstName: "Erika",
customerLastName: "Musterfrau",
deliveryMethod: "address",
street: "Kundenweg 2",
zip: "80331",
city: "München",
country: "Deutschland",
paymentMethodTitle: "Kreditkarte",
kleinunternehmer: true,
items: [{ productName: "ToDo-Karten Set", quantity: 2, unitPrice: 12.9, taxRatePercent: 0, bundleContents: null }],
subtotal: 25.8,
shippingCost: 4.95,
discountAmount: 0,
discountCode: null,
total: 30.75,
};
async function main() {
await mkdir(OUT_DIR, { recursive: true });
@@ -100,7 +129,10 @@ async function main() {
const gutschrift = await renderCorrectionInvoiceEInvoice("gutschrift", CORRECTION_ORDER, SELLER);
await writeFile(new URL("gutschrift.pdf", OUT_DIR), gutschrift);
console.log(`Wrote 3 e-invoice fixtures to ${OUT_DIR.pathname}`);
const kleinunternehmerInvoice = await renderInvoiceEInvoice(KLEINUNTERNEHMER_ORDER, SELLER);
await writeFile(new URL("kleinunternehmer-invoice.pdf", OUT_DIR), kleinunternehmerInvoice);
console.log(`Wrote 4 e-invoice fixtures to ${OUT_DIR.pathname}`);
}
main().catch((err) => {