บล็อก

Validate ZUGFeRD ด้วย Mustang: อะไรผ่าน อะไร fail และเพราะอะไร

Mustang คือ reference checker ของ Factur-X / ZUGFeRD ที่ใช้จริง บทนี้สรุป failure mode เมื่อต้อง embed CII XML ใน PDF/A-3 และวิธี verify ก่อนส่ง

ถ้าคุณส่ง e-invoices ให้ลูกค้า B2B ในเยอรมนีในปี 2026 ไฟล์นั้นต้อง ZUGFeRD-compliant ไม่อย่างนั้นจะถูก bounce ตอนรับเอกสาร ฝรั่งเศสกับ Factur-X ก็มีตรรกะเดียวกัน Format คือ PDF/A-3 wrapper พร้อม EN 16931 CII XML attached การ generate ตั้งแต่ศูนย์ไม่ง่าย และการ validate ต้องใช้ reference engine

ในทางปฏิบัติ engine นั้นคือ Mustang (mustangproject.org) ซึ่งเป็น open-source Java project ที่ extract embedded XML จาก PDF/A-3 แล้ว validate กับ EN 16931 Schematron Mustang มี support ลึกที่สุดสำหรับ ZUGFeRD และ Factur-X ในกลุ่ม open-source tools และ independent verifiers จำนวนมากก็ใช้งานมัน

บทความนี้อธิบาย failure modes ที่ Mustang flag และวิธี run ที่เร็วกว่า

Mustang ตรวจอะไรจริง ๆ

เมื่อส่ง Factur-X หรือ ZUGFeRD PDF ให้ Mustang มันจะทำประมาณนี้:

  1. Extract 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. Check AFRelationship Attached file ต้องประกาศเป็น AFRelationship="Alternative" ตาม baseline ของ Factur-X / ZUGFeRD ค่าอื่น (Source, Data, Supplement) fail
  3. Check 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. Parse XML เป็น Cross-Industry Invoice (CII) XML ต้อง well-formed และเริ่มด้วย CII root element ที่ถูกต้อง (rsm:CrossIndustryInvoice)
  5. Run EN 16931 Schematron นี่คือส่วนหลักของ validation: business rules ประมาณ 200 ข้อ ครอบคลุม field semantics, mandatory codes, totals math, VAT logic, party identifiers และอื่น ๆ

Pass หมายถึง invoice ยอมรับได้สำหรับ AP system ที่ conform กับ EN 16931 ทั่ว EU ส่วน Fail หมายถึง AP automation ของลูกค้าจะ reject 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 ของ visible 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 /api/v1/e-invoice/render ของ gPdf จะ 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.

นี่คือ failure ส่วนใหญ่ในโลกจริง XML valid ทาง syntax แต่ business rules fail 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 ถูกต้อง แต่ output เป็น ordinary PDF ไม่ใช่ PDF/A-3 Embedded file มีอยู่ แต่ archival wrapper rules ไม่ครบ Validator ที่ gpdf.com/validator/ จับได้โดย run 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 วิธีแก้คือ strip BOM ก่อน embedding endpoint e-invoice ของ gPdf normalise กรณีนี้ให้

Run Mustang โดยไม่ต้องติดตั้ง Java

การติดตั้ง Java + Mustang CLI ใช้ได้สำหรับ one-off check แต่ถ้าต้อง ongoing verification เช่นทุก invoice ที่ generate หรือทุก CI run ที่ assert e-invoice compliance นี่คือ friction ที่ไม่จำเป็น

gpdf.com/validator/ run Mustang ใน browser:

  1. Drag Factur-X / ZUGFeRD PDF ไปที่ upload zone
  2. Validator extract embedded XML แล้ว run Schematron engine ของ Mustang (compiled เป็น JavaScript / WebAssembly และ run ใน Cloudflare Worker)
  3. Mustang report กลับมาพร้อม veraPDF PDF/A-3 report แบบ side-by-side เพราะทั้งสอง layer ต้อง pass
  4. Download JSON report เพื่อเป็น QA evidence

ไม่มี login ไม่มี quota เป็น Mustang ประเภทเดียวกับที่ติดตั้งผ่าน Maven แต่ให้ใช้เป็น free public service

TL;DR

Mustang flag 5 common failure modes ส่วนใหญ่สรุปได้ว่า “ไฟล์ถูก generated ด้วย tool ที่ไม่ emit fully-conformant Factur-X / ZUGFeRD PDF/A-3” E-invoice API ของ gPdf emit ได้ใน call เดียว ส่วน validator verify ผลลัพธ์ด้วย Mustang + veraPDF แบบ parallel

Bug ส่วนใหญ่ที่ Mustang จับได้อยู่ที่ wrapper หรือ AFRelationship ไม่ใช่ XML semantics อย่างเดียว การ generate file ให้ถูกต้องคือส่วนใหญ่ของงาน และ validator คือ receipt ที่พิสูจน์ว่าทำถูกแล้ว