Germany's B2B e-invoice transition ends on 1 Jan 2027 (1 Jan 2028 for issuers with turnover up to EUR 800k). France starts requiring large and mid-size companies to issue on 1 Sep 2026, and Belgium has been live since 1 Jan 2026. A lot of shops will be relying on an open-source library or plugin to produce XRechnung, ZUGFeRD/Factur-X or Peppol UBL.
So we built an open, reproducible matrix. It takes the same 600 synthetic tax-inclusive shop orders (19 %/7 % VAT, percentage coupons, shipping), runs them through each generator, and checks every invoice with pinned official rule sets: KoSIT 1.6.3 + XRechnung 3.0.2, CEN EN 16931 and Peppol BIS 3.0.20. On top of that we check whether the amount due matches what the customer was actually charged.
What we found (full table: https://kobima6813.github.io/einvoice-conformance-matrix/):
-
WooCommerce PDF Invoices 5.16.4, Factur-X: 39.7 % schema-invalid.
RoundingAmountis written in the wrong XSD position (reported upstream). -
Odoo 19, Factur-X: with
round_globally, 32.7 % (B2B) and 42.7 % (B2C) fail CEN calculation rules, and 80.7 % of B2B invoices fail Peppol R120. A follow-up fix is in progress upstream. - Mustang 2.26.0 and josemmo/einvoicing 0.3.1: both pass KoSIT 100 %, but when the library computes totals from net prices, the amount due differs from the charged amount in 90.7 % (B2B) and 66.7 % (B2C) of orders. Usually that is a few cents. It's the gap between tax-inclusive shop arithmetic and EN 16931 net arithmetic, and no validator flags it.
-
josemmo/einvoicing with no preset or rounding matrix: amounts are written with up to 8 decimals, so 98–99 % fail BR-DEC rules. Fix:
setRoundingMatrix(['' => 2]). - speedata/einvoice 0.0.23 (Go) computes the VAT breakdown and totals, and every CII/UBL invoice passes. The amount-due gap is the same as with Mustang.
-
ZUGFeRD-csharp 18.0.1 (.NET): UBL passes. CII without a delivery date is 100 % schema-invalid because the required empty
ApplicableHeaderTradeDeliveryis dropped. That's already known upstream (PR #981). Workaround: setActualDeliveryDate. - horstoeko/zugferd, drafthorse and ZUGFeRD-csharp: given correct totals, everything passes. The arithmetic is your job.
Several bugs found this way are already fixed in releases (speedata/einvoice v0.0.23, horstoeko/zugferd 1.0.133, Mustang master).
Run the same checks on your own invoices in CI:
- uses: kobima6813/einvoice-conformance-matrix@main
with:
invoices: out/invoices
Maintain a generator? Listing is free: open a Listing request issue or a PR (see CONTRIBUTING). Corrections are welcome.
Repo: https://github.com/kobima6813/einvoice-conformance-matrix
Top comments (1)
Your Peppol pin is one release behind. 3.0.21 has been mandatory since 17 August (docs.peppol.eu/poacc/billing/3.0/r...), and it also updates the EN 16931 rules bundled in the Peppol pack. I doubt it moves your amount-due column, but people will run the action in CI and trust the pin. If you took it from OpenPEPPOL/peppol-bis-invoice-3, that's an easy trap: the newest tag there is still v3.0.20, and 3.0.21 only lives on the 2026-Q2 branches.
Disclosure, I'm the founder of beliq.eu, an e-invoice validation API, which is how I ran into the missing tag. Do you plan to bump the pins on a schedule?