Blog

Walidacja ZUGFeRD w Mustang: co przechodzi, co odpada i dlaczego

Mustang to de-facto reference checker dla Factur-X / ZUGFeRD. Typowe błędy przy osadzaniu CII XML w PDF/A-3 i sposób weryfikacji przed wysyłką.

Jeśli w 2026 wysyłasz e-invoices do niemieckiego klienta B2B, plik jest ZUGFeRD-compliant albo zostanie odbity przy odbiorze. We Francji z Factur-X jest tak samo. Format to PDF/A-3 wrapper z dołączonym EN 16931 CII XML; generowanie od zera nie jest trywialne, a walidacja wymaga reference engine.

W praktyce tym engine jest Mustang (mustangproject.org): open-source Java project, który wyciąga embedded XML z PDF/A-3 i waliduje go wobec EN 16931 Schematron. Mustang ma najgłębsze wsparcie dla ZUGFeRD i Factur-X wśród otwartych narzędzi, i to jego uruchamia wiele independent verifiers.

Ten tekst przechodzi przez failure modes, które Mustang zgłasza, oraz szybszy sposób jego uruchomienia.

Co Mustang naprawdę sprawdza

Gdy podasz Mustangowi PDF Factur-X albo ZUGFeRD, robi mniej więcej:

  1. Wyciąga embedded file. PDF/A-3 przechowuje attachments w name tree /EmbeddedFiles. Mustang szuka kanonicznej nazwy (factur-x.xml dla Factur-X, zugferd-invoice.xml dla ZUGFeRD 2.x) i czyta bytes.
  2. Sprawdza AFRelationship. Attached file musi być zadeklarowany jako AFRelationship="Alternative" zgodnie z baseline Factur-X / ZUGFeRD. Inne wartości (Source, Data, Supplement) failują.
  3. Sprawdza XMP namespace i version. Factur-X 1.0 używa urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#. ZUGFeRD 2.x używa urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#. Zły namespace albo version string failuje.
  4. Parsuje XML jako Cross-Industry Invoice (CII). XML musi być well-formed i zaczynać się od właściwego CII root element (rsm:CrossIndustryInvoice).
  5. Uruchamia EN 16931 Schematron. To główna część walidacji: około 200 business rules dotyczących semantyki pól, obowiązkowych kodów, totals math, VAT logic, party identifiers itd.

Pass = faktura jest akceptowalna dla każdego EN 16931-conformant AP system w UE. Fail = AP automation klienta odrzuci invoice przy odbiorze, a AR team dostanie manual exception.

Pięć najczęstszych failure modes

Pojawiają się regularnie po stronie Mustang w validator, gdy zespoły testują pierwsze e-invoices.

1. Wrong AFRelationship

ERROR: Embedded file factur-x.xml uses AFRelationship="Source",
expected "Alternative".

PDF spec dopuszcza kilka relationship types dla attached files. Factur-X / ZUGFeRD wymagają Alternative, czyli attached XML jest alternatywną reprezentacją visible PDF content. Jeśli PDF generator używa Data (default w wielu libraries), Mustang od razu failuje. Widoczny PDF nadal renderuje się poprawnie, ale structured payload nie działa dla AP system.

2. Wrong / missing XMP namespace

ERROR: XMP metadata missing fx:DocumentType or fx:DocumentFileName under
namespace urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#.

XMP packet PDF musi deklarować, który Factur-X profile to jest (MINIMUM, BASIC, EN 16931, EXTENDED) i jakiej nazwy pliku szukać. Łatwo to pominąć przy ręcznym pisaniu PDF/A-3 wrapper; endpoint gPdf /api/v1/e-invoice/render emituje te pola automatycznie.

3. CII XML well-formed, ale EN 16931 Schematron failuje

ERROR: BR-CO-25 — In an invoice (BR-01) the
  ram:SpecifiedTradePaymentTerms/ram:DueDateDateTime is required when
  ram:DocumentTypeCode is 380.

To większość realnych failures. XML jest składniowo valid; failują business rules. EN 16931 Schematron rules mają stable IDs (BR-01, BR-CO-25 itd.) do sprawdzenia w specyfikacji. Częste:

  • BR-01: invoice musi mieć unique invoice number.
  • BR-04: invoice musi mieć issue date.
  • BR-05: invoice musi mieć invoice type code.
  • BR-CO-25: payment terms required, gdy document type to “Commercial invoice”.
  • BR-Z-01: VAT category codes muszą być jednym z S, Z, E, AE, K, G, O, L, M.

Popraw source data, zbuduj ponownie i re-validate.

4. PDF/A wrapper nie waliduje się

INFO: CII XML extracted and validates against EN 16931.
ERROR: PDF/A-3b conformance check failed: missing Output Intent.

Tu XML check Mustanga przechodzi, ale underlying PDF/A-3 wrapper failuje. Częsta przyczyna: XML jest poprawny, ale wygenerowano zwykły PDF zamiast PDF/A-3. Embedded file istnieje, ale archival wrapper rules nie są spełnione. Validator na gpdf.com/validator/ łapie to przez równoległe veraPDF: PDF/A-3 fail jest w kolumnie veraPDF, a Mustang pokazuje XML pass.

5. Encoding / declaration mismatch

ERROR: XML declares <?xml version="1.0" encoding="UTF-8"?> but the
embedded byte stream is UTF-8 with BOM. Mustang strict mode rejects BOM.

Zaskakująco częste, gdy XML tool emituje UTF-8 BOM, a bytes są embedded raw. Fix: strip BOM przed embedding. gPdf e-invoice endpoint normalizuje ten przypadek.

Jak uruchomić Mustang bez instalacji Java

Java + Mustang CLI jest OK dla jednorazowego checku. Przy continuous verification — każda generowana invoice, każdy CI run assertujący e-invoice compliance — to niepotrzebne friction.

gpdf.com/validator/ uruchamia Mustang w przeglądarce:

  1. Przeciągnij PDF Factur-X / ZUGFeRD do upload zone.
  2. Validator wyciąga embedded XML i uruchamia Schematron engine Mustang (compiled to JavaScript / WebAssembly, działa w Cloudflare Worker).
  3. Report Mustang wraca obok veraPDF PDF/A-3 report, bo obie warstwy muszą przejść.
  4. Pobierz JSON report jako QA evidence.

Bez loginu. Bez quota. Ten sam typ Mustanga, który instalujesz przez Maven, podany jako darmowy public service.

TL;DR

Mustang flaguje 5 common failure modes; większość oznacza, że plik wygenerowało narzędzie, które nie emituje fully-conformant Factur-X / ZUGFeRD PDF/A-3. E-invoice API gPdf emituje go w jednym call. validator sprawdza wynik równolegle przez Mustang + veraPDF.

Większość błędów, które łapie Mustang, dotyczy wrappera albo AFRelationship, nie tylko XML semantics. Poprawne wygenerowanie pliku to większość pracy; validator jest receipt, który to potwierdza.