--- status: Active lastUpdated: 2026-07-18 applyTo: - "Fuchs/Services/ERechnungMapper.cs" - "Fuchs/Services/ERechnungService.cs" - "Fuchs/Services/ERechnungSettings.cs" - "Fuchs/Services/InvoiceRecipientAddress.cs" - "Fuchs/Services/InvoiceService.cs" - "Fuchs/code/FuchsPdf.cs" - "eRechnungLib/**" relatedDecisions: - "0005-pdf-generation-and-erechnung.md" - "0012-erechnung-single-pdfa-engine-pipeline.md" --- # eRechnung output (ZUGFeRD/Factur-X) ## Summary Finalized invoices are emitted as a **ZUGFeRD 2.4 / Factur-X** hybrid: the FuchsPdf visual PDF with the EN 16931 **CII XML** embedded, in a formally conformant **PDF/A-3**. This makes invoices DATEV-ingestible and satisfies the B2B/B2G e-invoicing mandate. The library doing the structured XML + PDF/A-3 work is the `eRechnungLib` submodule; Fuchs supplies the invoice data and the visual PDF. ## How it works ``` Editor (structured recipient dialog) → InvoiceDraftEditService (address delta = JSON object, stored in CustomValues.sendToAddress) → fds__setInvoice/… (persisted; dedicated SendToAddressJson column + composed SendToAddress) → InvoiceService.RenderInvoicePdfBytesAsync(final) ├─ FuchsPdf.DocToPdfBytesRaw(doc) → visual PDF (no Spire PDF/A) └─ IERechnungService.TryBuildHybridPdf ├─ ERechnungMapper.BuildEInvoice FdsInvoiceData → eRechnungLib.Model.Invoice └─ EInvoice.ToZugferd(EN16931, raw) → PDF/A-3 + Factur-X hybrid (bundled sRGB ICC) ``` - **Single PDF/A engine (ADR 0012).** eRechnungLib owns the one PDF/A-3 layer. For the eRechnung path the Spire PDF/A step is skipped (`DocToPdfBytesRaw`); Spire stays only for on-screen preview rasterisation. This avoids a conflicting second output intent / `pdfaid` marker. - **Structured recipient address.** `InvoiceRecipientAddress` holds the EN 16931 buyer fields (name, street, post code, city, country BT-55, optional VAT id BT-48). It is edited via a dialog form (`$inv.eAddress` in `fis.inv_shared.js`), prefilled from `fds__prepInvoice`'s `invoiceaddressData`, and carried as a JSON object through the draft cache. A private person (no VAT id) is fully valid — B2C stays effortless. The free-text `SendToAddress` is composed from it so the PDF layout is unchanged. - **Mapping.** `ERechnungMapper` maps the Fuchs invoice to the EN 16931 model: seller = Fuchs (from `Fuchs:ERechnung:Seller` config — name, address, Steuernummer BT-32, **USt-IdNr BT-31**, IBAN/BIC, contact; defaults mirror the FuchsPdf letterhead), buyer = the structured recipient, lines from the invoice items, §13b → reverse charge (category AE + exemption reason), payment terms BT-20/BT-9, and the service date/period (BT-72 or BG-14) parsed from the structured `ProvisionPeriod`. VAT breakdown and totals are recomputed by the library. - **Profile selection (B2B/B2C vs B2G).** Default is ZUGFeRD **EN 16931** (DATEV). When the recipient carries a **Leitweg-ID** (`InvoiceRecipientAddress.LeitwegId` → `BuyerReference` BT-10), the invoice is B2G and emitted as **XRechnung** (`ZugferdProfile.XRechnung`, embedded `xrechnung.xml`); the mapper then also fills the seller electronic address/contact (BT-34/BG-6) and buyer electronic address (BT-49) that XRechnung requires. - **Feature flag & fallback.** Emission is gated by `Fuchs:ERechnung:Enabled` (off until fully validated). `IERechnungService` returns `null` on disable **or any failure**, so `RenderInvoicePdfBytesAsync` falls back to the plain Spire PDF/A — invoicing never breaks. - **Formal verification.** `Fuchs:ERechnung:Validation` calls the ProcessWeb eInvoice service (`POST {ServiceUrl}/validatepdf`, raw `application/pdf`) which checks the EN 16931 XML **and** PDF/A-3 (veraPDF) in one call. Both the EN 16931-ZUGFeRD and the XRechnung 3.0 output are externally **ACCEPTED** (0 errors) and **PDF/A-3B COMPLIANT**. Getting there required fixing two eRechnungLib defects (CII root children must be `rsm:` not `ram:`; embedded-file `/Subtype` MIME encoding) and completing the mapper (seller VAT id BT-31, payment terms BT-20/BT-9). The validator's target feature scope is documented in [`../eRechnung-Validator-Requirements.md`](../eRechnung-Validator-Requirements.md). ## Key files - `Fuchs/Services/InvoiceRecipientAddress.cs` — structured buyer address, composition, conformity. - `Fuchs/Services/ERechnungMapper.cs` — `FdsInvoiceData` → `eRechnungLib.Model.Invoice`. - `Fuchs/Services/ERechnungService.cs` / `ERechnungSettings.cs` — hybrid production + config. - `Fuchs/Services/InvoiceService.cs` — wiring in `RenderInvoicePdfBytesAsync`. - `Fuchs/code/FuchsPdf.cs` — `DocToPdfBytesRaw` (render-only visual PDF). - `Fuchs/js/intranet/modules/fis.inv_shared.js` — `$inv.eAddress` structured dialog. - `Fuchs_Database` — `fds__invoices.SendToAddressJson`, `fds__getCompanyAddressJson`, `fds__prepInvoice.invoiceaddressData`, `fds__createInvoice`/`setInvoice`/`getInvoice`. - `eRechnungLib/**` — CII/UBL serialization, EN 16931 validation, `FacturXPdfBuilder` (PDF/A-3). ## Related decisions - [`0005-pdf-generation-and-erechnung.md`](../Decisions/0005-pdf-generation-and-erechnung.md) - [`0012-erechnung-single-pdfa-engine-pipeline.md`](../Decisions/0012-erechnung-single-pdfa-engine-pipeline.md)