Blog

Validate ZUGFeRD bằng Mustang: cái gì pass, cái gì fail và vì sao

Mustang là checker tham chiếu de-facto cho Factur-X / ZUGFeRD. Các kiểu lỗi phổ biến khi embed CII XML trong PDF/A-3, và cách verify trước khi gửi vào production.

Nếu bạn gửi e-invoice cho khách hàng B2B ở Đức trong năm 2026, file hoặc ZUGFeRD-compliant, hoặc bị bounce ở bước nhận. Ở Pháp với Factur-X cũng vậy. Format là một wrapper PDF/A-3 có EN 16931 CII XML attach; tự generate từ đầu không đơn giản, và validate cần một reference engine.

Reference engine đó, trong thực tế, là Mustang (mustangproject.org): một dự án Java open-source extract XML nhúng từ PDF/A-3 và validate nó theo EN 16931 Schematron. Mustang có hỗ trợ sâu nhất cho ZUGFeRD và Factur-X trong số các công cụ open-source, và là thứ nhiều verifier độc lập chạy.

Bài này đi qua các kiểu lỗi Mustang flag, và một cách nhanh hơn để chạy nó.

Mustang thật sự kiểm tra gì

Khi bạn đưa một PDF Factur-X hoặc ZUGFeRD vào Mustang, nó đại khái làm:

  1. Extract embedded file. PDF/A-3 lưu attachment trong name tree /EmbeddedFiles. Mustang tìm filename canonical (factur-x.xml cho Factur-X, zugferd-invoice.xml cho ZUGFeRD 2.x) và lấy bytes.
  2. Check AFRelationship. File attach phải được khai báo với AFRelationship="Alternative" theo baseline Factur-X / ZUGFeRD. Bất kỳ giá trị nào khác (Source, Data, Supplement) đều fail.
  3. Check XMP namespace và version. Factur-X 1.0 dùng urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#. ZUGFeRD 2.x dùng urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#. Sai namespace hoặc version string đều fail.
  4. Parse XML như Cross-Industry Invoice (CII). Nó phải là XML well-formed và bắt đầu bằng root element CII đúng (rsm:CrossIndustryInvoice).
  5. Chạy EN 16931 Schematron. Đây là phần chính của validation: khoảng 200 business rule bao phủ semantics của field, mandatory codes, phép tính totals, VAT logic, party identifiers, v.v.

Pass nghĩa là invoice được chấp nhận bởi bất kỳ AP system nào conform EN 16931 trên khắp EU. Fail nghĩa là automation AP của khách hàng sẽ reject invoice ở bước nhận và đội AR phải xử lý exception thủ công.

Năm kiểu lỗi chúng tôi thấy nhiều nhất

Những lỗi này xuất hiện lặp lại ở phía Mustang của validator khi đội thử e-invoice đầu tiên.

1. Sai AFRelationship

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

PDF spec cho phép nhiều relationship type cho attached files. Factur-X / ZUGFeRD yêu cầu cụ thể Alternative, nghĩa là XML attach là biểu diễn thay thế của nội dung PDF nhìn thấy. Nếu PDF generator của bạn đặt Data, là mặc định trong nhiều thư viện, Mustang fail ngay. Visual PDF vẫn render đúng; structured payload thì vô hình với AP system.

2. Sai hoặc thiếu XMP namespace

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

XMP packet của PDF phải khai báo đây là profile Factur-X nào, ví dụ MINIMUM, BASIC, EN 16931, EXTENDED, và filename nào cần tìm. Rất dễ bỏ sót khi tự viết wrapper PDF/A-3; endpoint /api/v1/e-invoice/render của gPdf tự emit các phần này.

3. CII XML well-formed nhưng 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.

Đây là phần lớn failure thực tế. XML của bạn đúng cú pháp; business rules mới fail. Rule EN 16931 Schematron có ID ổn định (BR-01, BR-CO-25, v.v.) để bạn tra trong spec EN 16931. Các lỗi phổ biến:

  • BR-01: invoice phải có số invoice duy nhất.
  • BR-04: invoice phải có issue date.
  • BR-05: invoice phải có invoice type code.
  • BR-CO-25: payment terms bắt buộc khi document type là “Commercial invoice”.
  • BR-Z-01: VAT category codes phải là một trong S, Z, E, AE, K, G, O, L, M.

Sửa source data; build lại; validate lại.

4. Wrapper PDF/A thật ra không validate

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

Đây là trường hợp XML check của Mustang pass nhưng wrapper PDF/A-3 nền fail. Nguyên nhân thường gặp: ai đó viết XML đúng nhưng emit PDF thường thay vì PDF/A-3. Embedded file có mặt, nhưng quy tắc archival wrapper không đạt. Validator tại gpdf.com/validator/ bắt lỗi này bằng cách chạy veraPDF song song: PDF/A-3 fail hiện ở cột veraPDF trong khi Mustang báo XML pass.

5. Mismatch encoding / declaration

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.

Một lỗi phổ biến bất ngờ khi XML được tạo bởi tool emit UTF-8 BOM rồi được embed raw. Cách sửa: strip BOM trước khi embed; endpoint e-invoice của gPdf normalize việc này.

Chạy Mustang mà không cần cài Java

Cài Java + Mustang CLI ổn cho một lần check. Nhưng với verification liên tục, mỗi lần generate invoice hoặc mỗi CI run assert compliance e-invoice, đó là friction không cần thiết.

gpdf.com/validator/ chạy Mustang trong browser:

  1. Kéo PDF Factur-X / ZUGFeRD vào upload zone.
  2. Validator extract XML nhúng và chạy Schematron engine của Mustang trên đó, được compile sang JavaScript / WebAssembly và chạy trong Cloudflare Worker.
  3. Report Mustang trả về cạnh report PDF/A-3 của veraPDF, vì cả hai lớp đều phải pass.
  4. Tải JSON report xuống làm bằng chứng QA.

Không login. Không quota. Cùng Mustang bạn cài qua Maven, nhưng được phục vụ như một service public miễn phí.

TL;DR

Mustang flag 5 kiểu lỗi phổ biến; phần lớn quy về việc file được generate bởi công cụ không emit PDF/A-3 Factur-X / ZUGFeRD fully conformant. E-invoice API của gPdf emit file đó trong một call. validator verify kết quả bằng hai engine (Mustang + veraPDF) song song.

Phần lớn bug Mustang bắt là vấn đề với wrapper hoặc AFRelationship, không phải semantics XML. Generate file đúng là phần lớn trận chiến; validator là biên nhận chứng minh bạn đã làm đúng.