renderInvoiceEInvoice()/renderCorrectionInvoiceEInvoice() produce a
Factur-X-EN16931 hybrid PDF/A-3 (existing @react-pdf/renderer PDF +
embedded EN16931 XML) via @e-invoice-eu/core, instead of a plain PDF.
The plain renderInvoicePdf()/renderCorrectionInvoicePdf() stay unchanged
and are still what Live Preview uses — this only adds a post-processing
step for the actual send/download paths.
buildEInvoiceData()/buildCorrectionEInvoiceData() map InvoiceOrder/
CorrectionInvoiceOrder + InvoiceSeller into the library's raw UBL-shaped
Invoice object, reusing computeTaxBreakdown() for the tax math — one
implementation feeding both the human-readable and machine-readable side
of the same document. Verified end-to-end: rendered a sample invoice and
correction invoice, inflated the embedded XML stream out of the resulting
PDF/A-3 by hand (the library has no attachment-reading API to check
against), confirmed correct CrossIndustryInvoice XML, EN16931 guideline
reference, per-rate tax breakdown matching the order totals exactly, and
payment means with the IBAN from Phase 2 — not just "it didn't throw."
Found only through actually running it (not documented anywhere): every
EN16931 amount field requires a sibling `*@currencyID` key via the
library's runtime ajv validation, invisible in its TypeScript types.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dropped by accident when bankDetails split into iban/bic — a bank name
has no fixed format to validate, so it stays free text, but it's still
useful context next to the account numbers in the invoice footer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
InvoiceSeller.bankDetails becomes iban/bic (EN16931 wants discrete
PaymentMeans data, not a paragraph a human formatted by hand). The
footer's bank-details line also drops the misleading "(für Überweisung)"
qualifier — it was never actually conditional on the order's payment
method (only on whether the field was set at all), just worded as if it
were. Now shown whenever iban or bic is set, regardless of payment
method.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>