Marco 9336cfd0ba Initial commit: shared invoice/correction-invoice PDF generation
Consolidates code previously hand-duplicated between the einfach-produktiv
frontend and payload backend repos into one canonical implementation,
consumed as a git dependency by both instead of being kept in sync by eye.

While merging the two correction-invoice copies, found and fixed three
real drifts between them:
- variantName was silently dropped in the backend's emailed Stornorechnung/
  Gutschrift, but present in the frontend's re-download copy
- the backend's correction-invoice footer wasn't position:fixed, unlike
  the original invoice and the frontend's copy
- the backend used a numeric date format (03.07.2025) while the original
  invoice and the frontend's copy both used a spelled-out month (03. Juli
  2025) — a re-download didn't visually match what was emailed

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 08:33:12 +00:00

@einfach-produktiv/invoicing

Shared invoice / correction-invoice (Stornorechnung, Gutschrift) PDF generation and VAT-breakdown math, used by both:

  • einfach-produktiv (the Next.js storefront — generates the original invoice at checkout, plus on-demand re-downloads of both document types)
  • payload (the Payload CMS backend — generates the authoritative Stornorechnung/Gutschrift the moment an order's status changes)

Why this exists

Before this package, taxBreakdown.ts and correctionInvoicePdf.tsx were hand-duplicated between both repos ("kept in sync by eye"). That drifted in three concrete, customer-visible ways before this package fixed it:

  1. The backend's emailed correction invoice silently dropped each line item's variantName (the frontend's re-download copy showed it).
  2. The backend's correction-invoice footer wasn't position: fixed, unlike the original invoice and the frontend's copy.
  3. The backend's correction invoice used a numeric date format (03.07.2025); the original invoice and the frontend's re-download copy both used a spelled-out month (03. Juli 2025) — so a re-downloaded document didn't match what was originally emailed.

One canonical implementation, consumed by both repos, makes this class of drift structurally impossible instead of relying on manual vigilance.

How this is consumed

Not published to npm — installed as a git dependency:

"@einfach-produktiv/invoicing": "git+https://git.mk360.de/Marco/einfach-produktiv-invoicing.git"

Ships raw TypeScript/TSX source (no build step) via main/types pointing straight at src/index.ts. Each consuming Next.js app must add this package to its own next.config.ts's transpilePackages array so its own bundler compiles the source — the same pattern a monorepo tool like Turborepo uses for internal packages, just without the monorepo.

react and @react-pdf/renderer are peer dependencies — each consumer supplies its own copy rather than this package pinning a version that could conflict.

Layout

  • taxBreakdown.tscomputeTaxBreakdown(), the per-VAT-rate net/tax grouping math shared by every document type here.
  • formatters.tsformatPrice()/formatDate(), canonical formatting for every document.
  • invoicePdf.tsx — the original invoice ("Rechnung"): InvoiceDocument, renderInvoicePdf(), plus SAMPLE_INVOICE_ORDER (used by the frontend's Payload Live Preview for company-settings).
  • correctionInvoicePdf.tsx — Stornorechnung/Gutschrift: renderCorrectionInvoicePdf().
  • seller.ts — the shared InvoiceSeller type both document types render in their footer.
S
Description
Shared invoice/correction-invoice PDF generation + VAT breakdown, used by both einfach-produktiv (frontend) and payload (backend) — internal git dependency, not published to npm.
Readme 1.1 MiB
Languages
TypeScript 100%