- Created a new function `fds__getCompanyAddressJson` to return a company's postal address as a structured JSON object. - Modified stored procedures `fds__createInvoice`, `fds__setInvoice`, and `fds__prepInvoice` to include a new parameter `@SendToAddressJson` for handling the address data. - Updated the invoice table and user-defined types to accommodate the new `SendToAddressJson` field. - Ensured that the address data is properly retrieved and stored in the invoice records.
82 lines
4.4 KiB
Markdown
82 lines
4.4 KiB
Markdown
---
|
|
status: Accepted
|
|
date: 2026-07-17
|
|
applyTo:
|
|
- "Fuchs/code/FuchsPdf.cs"
|
|
- "Fuchs/Services/FuchsPdfService.cs"
|
|
- "Fuchs/Services/InvoiceService.cs"
|
|
- "Fuchs/Services/ERechnungSettings.cs"
|
|
- "eRechnungLib/**"
|
|
supersededBy: ""
|
|
---
|
|
|
|
# 0012 — eRechnung uses a single PDF/A engine (eRechnungLib owns PDF/A-3)
|
|
|
|
## Context
|
|
ADR 0005 established that invoices are emitted as eRechnung by embedding the CII
|
|
XML into the FuchsPdf-rendered visual PDF via `eRechnungLib.ToZugferd(...)`.
|
|
|
|
Two hard requirements then surfaced: the emitted invoice must (a) satisfy the
|
|
**ZUGFeRD 2.4 / Factur-X** standard for **DATEV** ingestion, and (b) be a
|
|
**formally verifiable PDF/A-3** (veraPDF-clean).
|
|
|
|
A conflict became apparent in the rendering pipeline. `FuchsPdf.DocToPdfBytes`
|
|
post-processes its MigraDoc/PdfSharp output to **PDF/A via Spire**
|
|
(`OCORE…pdfAFileContent`). `eRechnungLib`'s `FacturXPdfBuilder` **also** produces
|
|
a PDF/A layer (raises to PDF 1.7, writes `pdfaid` XMP, adds an sRGB output
|
|
intent, embeds `factur-x.xml` in `/AF`). Feeding a Spire-made PDF/A into
|
|
eRechnungLib stacks **two** PDF/A conversions → duplicate/*conflicting* output
|
|
intents and `pdfaid` markers, which veraPDF rejects. Spire's output is also
|
|
PDF/A-1/2 and does **not** carry the `/AF` associated-file structure ZUGFeRD
|
|
requires (PDF/A-3).
|
|
|
|
Separately, `eRechnungLib` shipped **no** sRGB ICC profile, so its output intent
|
|
was silently omitted (`PDFA-ICC` warning) — never formally PDF/A-3 conformant.
|
|
|
|
## Decision
|
|
- **eRechnungLib is the single PDF/A engine for eRechnung output.** The invoice
|
|
visual PDF is rendered by `FuchsPdf` **without** the Spire PDF/A step and handed
|
|
to `eRechnungLib.ToZugferd(ZugferdProfile.EN16931, rawPdfBytes)`, which owns the
|
|
one PDF/A-3 conversion and embeds the CII XML. The render-only path is
|
|
`FuchsPdf.DocToPdfBytesRaw` / `IPdfService.DocToPdfBytesRaw` (fonts still
|
|
embedded via `OCOREFontResolver`, no PDF/A post-processing).
|
|
- **Spire stays only for on-screen preview rasterisation** (`DocToImageCollection`
|
|
/ `BytesToImageCollection` for `sprep`/`sedit`). It is **not** part of the
|
|
eRechnung file's PDF/A path. `DocToPdfBytes` (render + Spire PDF/A) is unchanged
|
|
and remains the path for non-eRechnung documents (e.g. reminders).
|
|
- **A bundled sRGB ICC profile is required.** `eRechnungLib` ships
|
|
`Resources/Color/sRGB.icc` (sRGB IEC61966-2.1) so the PDF/A output intent is
|
|
always attached. A caller may override it per conversion via
|
|
`ConversionOptions.IccProfile`.
|
|
- **Profile is EN 16931.** MINIMUM / BASIC WL are not offered for real invoices —
|
|
DATEV needs at least EN 16931 (COMFORT) for full booking.
|
|
- **Formal conformance is verified by an external online service** (veraPDF for
|
|
PDF/A-3 + a ZUGFeRD/EN 16931 validator), behind the configurable
|
|
`Fuchs:ERechnung:Validation:ServiceUrl` seam. Until the URL is provisioned,
|
|
verification reports "not configured / skipped".
|
|
|
|
## Consequences
|
|
- The eRechnung invoice PDF and a plain Spire PDF/A must never both be produced
|
|
for the same document — pick the render-only path when emitting eRechnung.
|
|
- The incoming visual PDF must itself be PDF/A-friendly (fonts embedded —
|
|
handled; letterhead images must be **RGB, not CMYK**; transparency is allowed
|
|
because we target PDF/A-**3**).
|
|
- `Fuchs:ERechnung:Enabled` gates emission and stays `false` until the
|
|
`FdsInvoiceData` → `eRechnungLib.Model.Invoice` mapping is wired (the ADR 0005
|
|
follow-up). Open item for that mapping: the buyer address is currently a
|
|
free-text block (`SendToAddress`); EN 16931 needs **structured** buyer
|
|
fields (name/postcode/city/country, VAT id), so structured customer master
|
|
data must feed the mapping. Seller data (currently hard-coded in `FuchsPdf`:
|
|
name, address, tax number, IBAN/BIC) must be lifted into the seller model.
|
|
- `Fuchs.csproj` must add a project reference to `eRechnungLib` when the flow is
|
|
wired (not present yet).
|
|
|
|
## Alternatives considered
|
|
- **Keep Spire PDF/A and have eRechnungLib only embed the XML:** rejected — Spire
|
|
produces the wrong PDF/A part (1/2, no `/AF`) and a second conversion collides
|
|
with eRechnungLib's own output intent/XMP, failing veraPDF.
|
|
- **Drop Spire entirely:** rejected — Spire is still needed to rasterise PDFs to
|
|
the on-screen invoice/reminder preview images; PdfSharp/eRechnungLib cannot.
|
|
- **Ship no ICC and rely on callers:** rejected — formal PDF/A-3 requires an
|
|
output intent; bundling a profile makes conformance the default.
|