Блог

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

Mustang — фактический reference checker для Factur-X / ZUGFeRD. Разбор типичных ошибок при вложении CII XML в PDF/A-3 и способ проверки перед отправкой.

Если в 2026 году вы отправляете e-invoices немецкому B2B-клиенту, файл либо ZUGFeRD-compliant, либо будет отклонен при получении. Во Франции с Factur-X та же логика. Формат — PDF/A-3 wrapper с вложенным EN 16931 CII XML; сгенерировать его с нуля непросто, а для проверки нужен reference engine.

На практике этот engine — Mustang (mustangproject.org): open-source Java-проект, который извлекает embedded XML из PDF/A-3 и валидирует его по EN 16931 Schematron. У Mustang самая глубокая поддержка ZUGFeRD и Factur-X среди open-source инструментов, и именно его запускают многие независимые валидаторы.

Ниже — типичные failures, которые показывает Mustang, и более быстрый способ запускать проверку.

Что Mustang реально проверяет

Когда вы даете Mustang PDF Factur-X или ZUGFeRD, он примерно делает следующее:

  1. Извлекает embedded file. PDF/A-3 хранит attachments в name tree /EmbeddedFiles. Mustang ищет каноническое имя (factur-x.xml для Factur-X, zugferd-invoice.xml для ZUGFeRD 2.x) и читает bytes.
  2. Проверяет AFRelationship. Attached file должен быть объявлен как AFRelationship="Alternative" по baseline Factur-X / ZUGFeRD. Любое другое значение (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. Это основная часть проверки: около 200 business rules по семантике полей, обязательным кодам, математике totals, VAT logic, party identifiers и т. д.

Pass = invoice приемлем для любого EN 16931-conformant AP system в ЕС. Fail = AP automation клиента отклонит invoice при получении, а AR team получит manual exception.

Пять самых частых failures

Они постоянно появляются в колонке 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 является альтернативным представлением видимого PDF content. Если ваш PDF generator использует Data (частый default в libraries), Mustang сразу падает. Видимый PDF все еще рендерится, но 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) и имя файла, которое нужно искать. Это легко забыть при ручной сборке PDF/A-3 wrapper; endpoint gPdf /api/v1/e-invoice/render автоматически emits эти поля.

3. CII XML well-formed, но EN 16931 Schematron падает

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

Это основная масса реальных failures. XML синтаксически валиден; падают business rules. У EN 16931 Schematron rules есть стабильные IDs (BR-01, BR-CO-25 и т. д.), которые можно искать в спецификации. Частые:

  • BR-01: invoice должен иметь уникальный номер.
  • BR-04: invoice должен иметь issue date.
  • BR-05: invoice должен иметь invoice type code.
  • BR-CO-25: payment terms обязательны, когда document type — “Commercial invoice”.
  • BR-Z-01: VAT category codes должны быть одним из S, Z, E, AE, K, G, O, L, M.

Исправьте source data, пересоберите и провалидируйте снова.

4. PDF/A wrapper не валидируется

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

Здесь XML check в Mustang проходит, но underlying PDF/A-3 wrapper падает. Частая причина: XML написали правильно, но выпустили обычный PDF вместо PDF/A-3. Embedded file есть, но archival wrapper rules не выполнены. Validator на gpdf.com/validator/ ловит это параллельным veraPDF: 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 встраиваются raw. Исправление: удалить BOM перед embedding. E-invoice endpoint gPdf нормализует это.

Как запускать Mustang без установки Java

Java + Mustang CLI подходят для разовой проверки. Но для постоянной верификации — каждый generated invoice, каждый CI run для e-invoice compliance — это лишнее friction.

gpdf.com/validator/ запускает Mustang в браузере:

  1. Перетащите Factur-X / ZUGFeRD PDF в upload zone.
  2. Validator извлекает embedded XML и запускает Schematron engine Mustang (compiled to JavaScript / WebAssembly, runs in the Cloudflare Worker).
  3. Report Mustang возвращается рядом с veraPDF PDF/A-3 report, потому что обе layers должны пройти.
  4. Скачайте JSON report как QA evidence.

Без login. Без quota. Та же проверка Mustang, которую вы поставили бы через Maven, просто как бесплатный публичный сервис.

TL;DR

Mustang показывает 5 common failure modes; чаще всего это означает, что файл сгенерирован инструментом, который не emit-ит полностью conformant Factur-X / ZUGFeRD PDF/A-3. E-invoice API gPdf делает это одним вызовом. validator проверяет результат Mustang + veraPDF параллельно.

Большинство багов, которые ловит Mustang, связаны с wrapper или AFRelationship, а не только с XML semantics. Правильная генерация файла — большая часть работы; validator — receipt, который это доказывает.