Playwright Tests / test (push) Has been cancelled
- Modified the stored procedure `fds__admin_getReportCatalog.sql` to use the correct schema for `all_objects`. - Added new folders and projects for `eRechnungLib` in the solution file `Fuchs_Intranet.slnx`, including validation and test projects. - Updated submodule reference for `OCORE`. - Added new submodule `eRechnungLib` with initial commit.
85 lines
4.7 KiB
Markdown
85 lines
4.7 KiB
Markdown
---
|
|
status: Accepted
|
|
date: 2026-07-05
|
|
applyTo:
|
|
- "Fuchs/code/FuchsPdf.cs"
|
|
- "Fuchs/Services/FuchsPdfService.cs"
|
|
- "Fuchs/Services/InvoiceService.cs"
|
|
- "Fuchs/Services/ReminderService.cs"
|
|
- "eRechnungLib/**"
|
|
supersededBy: ""
|
|
---
|
|
|
|
# 0005 — PDF generation, rendering, and eRechnung output
|
|
|
|
## Context
|
|
Fuchs produces letters, invoices, and reminders as PDFs. The layout is a faithful
|
|
port of the legacy VB module `fuchs_fds_pdf.vb` (letterhead, DIN address window,
|
|
admin block, four-block footer with page numbers, invoice item table, GiroCode).
|
|
The port had silently drifted — wrong letterhead image filenames (`image1.png`
|
|
instead of the shipped `image1.jpeg`, which `AddHeaderImage` skips via
|
|
`File.Exists`), a too-small bottom margin, and a reworked footer/admin block — so
|
|
generated PDFs (e.g. the `sprep` invoice preview) rendered broken.
|
|
|
|
Separately, German B2B/B2G invoicing now requires **eRechnung** (structured
|
|
electronic invoices). The company direction is that **all invoices are emitted as
|
|
eRechnung**, not just human-readable PDFs.
|
|
|
|
Rendering also depends on **Spire.PDF** (commercial, licensed) for PDF/A
|
|
conversion and rasterising PDFs to preview images.
|
|
|
|
## Decision
|
|
- **PDF layout stays a 1:1 port of the legacy `fuchs_fds_pdf.vb`.** `FuchsPdf`
|
|
(MigraDoc/PdfSharp) is the single source of the visual layout. When changing
|
|
the letter/invoice/reminder layout, compare against the legacy module and keep
|
|
the letterhead assets (`Fuchs/Data/image1-3.jpeg`, `image4.png`, `overlay.png`),
|
|
margins, sender line, label-over-value admin block, absolutely-positioned
|
|
four-block footer, and `Seite X von Y` page numbers aligned with it. Reference
|
|
the shipped asset filenames exactly — `AddHeaderImage` no-ops on a missing file,
|
|
so a wrong extension silently drops a logo.
|
|
- **Rendering pipeline:** `FuchsPdf.DocToPdfBytes` renders MigraDoc → PDF and
|
|
post-processes to PDF/A; `DocToImageCollection` / `BytesToImageCollection`
|
|
rasterise via Spire for the on-screen invoice preview (`sprep`/`sedit`). The
|
|
OCORE `OCOREFontResolver` must be installed before any PdfSharp rendering.
|
|
- **Spire license comes from a managed secret.** `FuchsPdfService` reads the
|
|
license from configuration key `SpirePdf_License` (Key Vault secret
|
|
`fuchs--SpirePdf-License`, registered in `ManagedSecretKeys`) and passes it to
|
|
`FuchsPdf.SetLicense(key)`. An embedded fallback key keeps local/dev rendering
|
|
working without Key Vault.
|
|
- **eRechnung via `eRechnungLib`.** The `eRechnungLib` submodule is the single
|
|
library for structured invoices. Invoices are to be produced as eRechnung:
|
|
build an `eRechnungLib.Model.Invoice` from the Fuchs invoice data, then
|
|
`EInvoice.CreateInvoice(model).ToZugferd(ZugferdProfile.EN16931, visualPdfBytes)`
|
|
to embed the CII XML into the FuchsPdf-rendered visual PDF (ZUGFeRD/Factur-X
|
|
hybrid PDF/A-3), or `ToXRechnung(...)` for pure UBL/CII XML. The visual PDF is
|
|
the FuchsPdf output — the two layers stay consistent (same amounts/parties).
|
|
Default `ConversionOptions` runs model + XSD validation; use `StrictValidation`
|
|
when a malformed invoice must withhold output rather than ship with findings.
|
|
|
|
## Consequences
|
|
- Layout edits must be validated against the legacy reference and the shipped
|
|
`Data/` assets; do not invent new positions/sizes. The pipeline test
|
|
`Fuchs.Tests/PdfPipelineTests.cs` exercises the full chain (PdfSharp visual PDF
|
|
→ Spire preview images → eRechnung hybrid/XML) and must stay green.
|
|
- Do **not** upgrade Spire.PDF beyond 8.10.5 (see project libraries rule). The
|
|
license must never be hard-coded in new code paths — read it from
|
|
`SpirePdf_License`.
|
|
- Wiring the app's invoice flow to emit eRechnung is the follow-up: map
|
|
`FdsInvoiceData`/`InvoiceRegistration` → `eRechnungLib.Model.Invoice`
|
|
(parties, lines, VAT breakdown, payment/IBAN, buyer reference, seller
|
|
electronic address) and persist/deliver the ZUGFeRD PDF and/or XRechnung XML.
|
|
- eRechnungLib depends only on open-source libraries (PDFsharp/MigraDoc; optional
|
|
SaxonCS-HE for Schematron) — no new commercial dependency for the structured
|
|
output itself.
|
|
|
|
## Alternatives considered
|
|
- **Hand-rolling ZUGFeRD/XRechnung XML** in Fuchs: rejected — EN 16931 + CIUS
|
|
validation, multiple profiles/syntaxes, and PDF/A-3 embedding are error-prone;
|
|
a dedicated, validated library is safer.
|
|
- **Rewriting the PDF layout from scratch** rather than porting the legacy module:
|
|
rejected — the letterhead is a fixed corporate design; the legacy VB is the
|
|
authoritative spec, so faithful porting avoids visual regressions.
|
|
- **Bundling a Spire license file / hard-coding the key**: rejected in favor of
|
|
the managed-secret path so the production key is centrally rotated and never
|
|
committed, with the embedded key only as a dev fallback.
|