Блог

Валідація ZUGFeRD через Mustang: що проходить, що падає і чому

Mustang — de-facto reference checker для Factur-X / ZUGFeRD. Типові помилки під час embed CII XML у PDF/A-3 і спосіб перевірки перед відправкою.

Якщо у 2026 ви надсилаєте e-invoices німецькому B2B-клієнту, файл або ZUGFeRD-compliant, або буде відхилений під час receipt. У Франції з Factur-X логіка така сама. Формат — PDF/A-3 wrapper із вкладеним EN 16931 CII XML; згенерувати його з нуля непросто, а для перевірки потрібен reference engine.

На практиці цей engine — Mustang (mustangproject.org): open-source Java project, який витягує embedded XML із PDF/A-3 і validate його за EN 16931 Schematron. Mustang має найглибшу підтримку ZUGFeRD і Factur-X серед open-source tools, і саме його запускають багато independent verifiers.

Нижче — failure modes, які показує Mustang, і швидший спосіб запуску.

Що Mustang реально перевіряє

Коли ви даєте Mustang PDF Factur-X або ZUGFeRD, він приблизно робить таке:

  1. Витягує embedded file. PDF/A-3 зберігає attachments у name tree /EmbeddedFiles. Mustang шукає canonical filename (factur-x.xml для Factur-X, zugferd-invoice.xml для ZUGFeRD 2.x) і читає bytes.
  2. Перевіряє AFRelationship. Attached file має бути оголошений як AFRelationship="Alternative" відповідно до Factur-X / ZUGFeRD baseline. Інші значення (Source, Data, Supplement) fail.
  3. Перевіряє XMP namespace і version. Factur-X 1.0 використовує urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#. ZUGFeRD 2.x використовує urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#. Неправильний namespace або version string fail.
  4. Парсить XML як Cross-Industry Invoice (CII). XML має бути well-formed і починатися з правильного CII root element (rsm:CrossIndustryInvoice).
  5. Запускає EN 16931 Schematron. Це основна частина validation: приблизно 200 business rules щодо field semantics, mandatory codes, totals math, VAT logic, party identifiers тощо.

Pass = invoice прийнятний для будь-якого EN 16931-conformant AP system у ЄС. Fail = AP automation клієнта відхилить invoice під час receipt, а AR team отримає manual exception.

П’ять найчастіших failure modes

Вони постійно з’являються в колонці Mustang на validator, коли команди тестують перші e-invoices.

1. Wrong AFRelationship

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

PDF spec дозволяє кілька relationship types для attached files. Factur-X / ZUGFeRD вимагають саме Alternative: attached XML є alternative representation видимого PDF content. Якщо ваш PDF generator використовує Data (частий default у libraries), Mustang одразу fail. Видимий PDF ще renderиться, але structured payload недійсний для 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 має оголошувати, який це Factur-X profile (MINIMUM, BASIC, EN 16931, EXTENDED) і який filename шукати. Під час ручного написання PDF/A-3 wrapper це легко пропустити; endpoint gPdf /api/v1/e-invoice/render auto-emit ці поля.

3. CII XML well-formed, але EN 16931 Schematron fail

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

Це більшість реальних failures. XML синтаксично valid; падають business rules. EN 16931 Schematron rules мають stable IDs (BR-01, BR-CO-25 тощо), які можна lookup у specification. Часті:

  • BR-01: invoice має мати unique invoice number.
  • BR-04: invoice має мати issue date.
  • BR-05: invoice має мати invoice type code.
  • BR-CO-25: payment terms required, коли document type — “Commercial invoice”.
  • BR-Z-01: VAT category codes мають бути одним із S, Z, E, AE, K, G, O, L, M.

Виправте source data, rebuild, потім re-validate.

4. PDF/A wrapper не validate

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

Тут XML check Mustang pass, але underlying PDF/A-3 wrapper fail. Типова причина: XML правильний, але emit відбувся як ordinary PDF, не PDF/A-3. Embedded file є, але archival wrapper rules не виконані. Validator на gpdf.com/validator/ ловить це, запускаючи veraPDF parallel: PDF/A-3 fail видно в колонці veraPDF, тоді як Mustang показує 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.

Досить часта проблема, коли XML tool emit UTF-8 BOM, а ці bytes embed raw. Fix: strip BOM перед embedding. gPdf e-invoice endpoint normalise це.

Як запускати Mustang без Java

Java + Mustang CLI підходять для one-off check. Але для ongoing verification — кожен generated invoice, кожен CI run із e-invoice compliance — це зайве friction.

gpdf.com/validator/ запускає Mustang у browser:

  1. Перетягніть Factur-X / ZUGFeRD PDF в upload zone.
  2. Validator витягує embedded XML і запускає Mustang Schematron engine (compiled to JavaScript / WebAssembly, running in the Cloudflare Worker).
  3. Mustang report повертається side-by-side з veraPDF PDF/A-3 report, бо обидва layers мають pass.
  4. Завантажте JSON report як QA evidence.

Без login. Без quota. Такий самий тип Mustang, який ви встановили б через Maven, але як free public service.

TL;DR

Mustang flag 5 common failure modes; здебільшого це означає, що файл generated інструментом, який не emit fully-conformant Factur-X / ZUGFeRD PDF/A-3. E-invoice API gPdf emit це одним call. validator verify результат через Mustang + veraPDF parallel.

Більшість bugs, які ловить Mustang, стосуються wrapper або AFRelationship, а не лише XML semantics. Правильно generate file — це більшість роботи; validator є receipt, який це доводить.