บล็อก

อธิบาย PDF/A และ Factur-X สำหรับวิศวกร โดยไม่ใช้ภาษากฎหมาย

PDF/A profile จำกัดอะไรจริง ๆ เหตุใด Factur-X จึงสำคัญต่อ e-invoicing ในยุโรป และ pipeline ที่เล็กที่สุดสำหรับ PDF ที่ compliant จาก JSON renderer.

ถ้าคุณเป็น engineer ที่เพิ่งถูกบอกว่า “invoices ต้องเป็น PDF/A-3 with Factur-X ภายใน quarter หน้า” และ context ทั้งหมดที่มีคือฝ่ายกฎหมายพูดคำเหล่านี้ บทความนี้เขียนสำหรับคุณ

เราจะตัดภาษาของ standards documents ออก แล้วอธิบายว่า profiles เหล่านี้จำกัดอะไรจริง ๆ ทำไม governments จึงเริ่ม mandate และ pipeline ที่เล็กที่สุดสำหรับ emit PDF ที่ compliant จาก structured-data renderer เป็นอย่างไร

PDF/A ในสองย่อหน้า

PDF เป็น format ที่ flexible มาก มากเกินไป ด้วยซ้ำ — PDF spec เดียวกันอนุญาตให้ embed JavaScript, link ไปยัง external resources ที่อาจไม่มีอยู่ในอีก 50 ปี, encrypt content ด้วย cryptography ที่ย้อนกลับได้, reference external fonts และอีกหลายอย่างที่ทำให้ document ไม่ self-contained

PDF/A โดย “A” หมายถึง Archival คือ profile ของ PDF ที่ห้ามส่วนที่อาจทำให้ document ไม่สามารถ render ได้เหมือนเดิมในอีก 50 ปี Rules ระดับสูงคือ:

  • fonts ทั้งหมดต้อง embedded
  • ไม่มี JavaScript, external links หรือ audio/video
  • ไม่มี encryption
  • transparency ทั้งหมดต้อง flatten หรือ supported โดย profile version
  • colours ต้อง device-independent และต้องมี ICC profile
  • content ทั้งหมดต้องอยู่ใน file ไม่มี references ที่ต้องพึ่ง network

มีหลาย versions และแต่ละ version เพิ่ม tolerance สำหรับ features ที่ใหม่ขึ้น:

ProfileYearเพิ่มอะไร
PDF/A-1b2005Original baseline เข้มงวดที่สุด
PDF/A-2b2011อนุญาต JPEG2000, transparency, layers
PDF/A-3b2012อนุญาต arbitrary file attachments ซึ่งเป็น foundation ของ Factur-X
PDF/A-42020ใช้ ISO 32000-2 (PDF 2.0) เป็นฐาน และมี conformance levels ที่ง่ายขึ้น

suffix “b” หมายถึง “basic” conformance หรือ visual fidelity ยังมี variants “u” สำหรับ unicode-mapped และ “a” สำหรับ accessibility-tagged แต่สำหรับ invoice/receipt workflows ส่วนใหญ่ “b” คือสิ่งที่ต้องใช้ เพราะ tax archival สนใจ visual reproducibility ไม่ใช่ screen-reader semantics

Practical takeaway: ถ้า renderer บอกว่า support PDF/A-3b ควรเป็น single config flag เช่น { profile: "PDF/A-3b" } หรือเทียบเท่า ถ้าคุณต้อง run tool ที่สอง เช่น Ghostscript, qpdf หรือ Acrobat เพื่อ convert ภายหลัง นั่นคือ workflow gap ที่ต้องคำนวณใน ops

ทำไม PDF/A-3 จึงสำคัญโดยเฉพาะ: มันเป็น carrier ของ e-invoices

PDF/A-3 เพิ่ม capability หนึ่งที่ฟังดูธรรมดา แต่สำคัญมาก: arbitrary file attachments ภายใน PDF

ฟังดูน่าเบื่อ แต่ไม่ใช่ นี่คือ technical foundation ทั้งหมดของ e-invoice mandates ที่กำลัง rollout ทั่วยุโรป

Architecture คือ PDF file เดียวที่เป็น ทั้งสองอย่าง:

  1. Human-readable invoice ที่มี visual layout, totals และ branding
  2. Machine-readable XML invoice ซึ่งเป็นส่วนที่ software ของ tax authority parse

ทั้งสองอยู่ใน file เดียว ทั้งสอง represent invoice เดียวกัน และ PDF/A-3 wrapper guarantee ว่า file จะยัง parseable ได้อีกหลายสิบปี

XML formats หลัก:

  • Factur-X (France) เป็น XML profile ที่อิง UN/CEFACT Cross Industry Invoice
  • ZUGFeRD (Germany) แทบเหมือน Factur-X ในสาระสำคัญ หลังจากสอง standards merge กันทางเทคนิคในปี 2018
  • EN 16931 คือ European norm ที่ implementations เหล่านี้ conform

ใน workflows ส่วนใหญ่ “Factur-X” และ “ZUGFeRD” ใช้แทนกันได้ ทั้งสอง share schema, share embedding mechanism และ PDF ที่ compliant กับอันหนึ่งโดยทั่วไปก็ compliant กับอีกอัน

อะไร mandatory ที่ไหน และเมื่อไร

Snapshot แบบไม่ exhaustive สำหรับ engineers ที่วางแผน rollout ใน Q2/Q3 2026:

CountryStatusRequired format
GermanyB2B mandatory สำหรับ invoice receipt ตั้งแต่ 2025-01-01; issuing ตั้งแต่ 2027EN 16931 (Factur-X / ZUGFeRD / XRechnung)
Francemandatory issuing สำหรับ large enterprises 2026-09; SMEs 2027-09Factur-X via Chorus Pro
ItalyB2B mandatory since 2019FatturaPA via SDI
PolandMandatory since 2024-07KSeF
SpainMandatory from 2026 (B2B)Facturae via FACe
BelgiumMandatory from 2026-01Peppol BIS 3

Pattern คือ EU member state ทุกประเทศกำลัง implement e-invoicing ที่ compatible กับ EN 16931 บางรูปแบบบน timeline 2024-2027 ถ้า customers ของคุณ operate ใน markets เหล่านี้ PDF generator ของคุณจะต้อง emit attached XML ควบคู่กับ visual invoice

Pipeline ที่เล็กที่สุดในทางปฏิบัติ

ลืมสิ่งที่ standards documents prescribe ไปก่อน นี่คือ engineering view:

   ┌─────────────────────┐
   │  Your invoice data  │  (มักเป็น JSON object อยู่แล้ว)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Build EN 16931 XML  │  (deterministic mapping; มี libs ที่ผ่านการทดสอบ)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Render PDF/A-3b +   │
   │ attach the XML      │  (single API call ไป gPdf หรือ two-step ที่อื่น)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │  Hand off to        │
   │  Chorus Pro / SDI / │
   │  Peppol / etc       │
   └─────────────────────┘

สองขั้นตอนที่ไม่ trivial:

Step 1: build XML

ขั้นตอนนี้น่ารำคาญแต่ mechanical คุณ map invoice data เช่น lines, taxes, totals และ parties ไปยัง field names ของ EN 16931 XML มี Java/Node/Python libraries หลายตัวที่ทำสิ่งนี้ให้ ลอง search “factur-x library” ใน language ของคุณ อย่าเขียนเองจาก scratch เว้นแต่คุณชอบ XML schema specs จริง ๆ

Step 2: render PDF/A-3 และ attach XML

ตรงนี้ renderer choice สำคัญ

ไม่มี built-in support: คุณ render ordinary PDF แล้ว post-process ด้วย tool ที่ convert เป็น PDF/A-3 และ attach XML เป็น embedded file Common stacks คือ Ghostscript + qpdf หรือ paid tool อย่าง Aspose นี่คือสองขั้นตอนเพิ่ม สองจุดที่ fail ได้เพิ่ม และคุณต้อง ensure ว่า post-processing ไม่ทำให้ visual layout drift

มี built-in support แบบ approach ของ gPdf: one call

curl -X POST https://gpdf.com/api/v1/e-invoice/render \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "document": {
      "pages": [{ "size": "a4", "elements": [...] }]
    },
    "einvoice": {
      "format": "factur-x",
      "profile": "BASIC",
      "xml": "<rsm:CrossIndustryInvoice>...</rsm:CrossIndustryInvoice>"
    }
  }' \
  --output invoice-with-einvoice.pdf

นั่นคือ pipeline ทั้งหมด Renderer emit PDF/A-3b, attach XML ของคุณเป็น factur-x.xml หรือ zugferd-invoice.xml ซึ่ง consumers ทุกตัวรู้จัก แล้ว return bytes

Gotchas ที่พบบ่อย

บางเรื่องคนมักเรียนรู้หลังเจ็บตัว:

“PDF/A” กับ “มี PDF/A-compliant fonts” ไม่ใช่เรื่องเดียวกัน

PDF/A-3 file ต้องมี fonts ทั้งหมด embedded พร้อม character coverage เต็มสำหรับ glyphs ที่ใช้ ถ้า invoice มีชื่อลูกค้าเป็นภาษาญี่ปุ่น แล้ว renderer fallback ไปยัง font ที่ embed ได้ไม่ครบ validation tools จะ reject ตรวจว่า renderer ของคุณ embed CJK fonts ใน PDF/A mode หรือไม่ เพราะหลายตัวไม่ได้ทำเป็น default

Visual + XML ต้องตรงกัน

XML invoice และ visual invoice ควร represent invoice เดียวกัน Tax auditors จะ diff สองอย่างนี้ ถ้า code emit XML ที่มี total: 119.00 แต่ visual PDF แสดง Total: 120.00 เพราะ rounding bug หรือ stale template คุณมี tax discrepancy อยู่ใน file ควร generate ทั้งสองจาก source-of-truth เดียวกัน ideally ใน code path เดียวกัน

”Profile” levels ใน EN 16931

Factur-X มี profiles: MINIMUM, BASIC, EN 16931, EXTENDED ต่างกันที่ปริมาณ data ใน XML ใช้ BASIC เว้นแต่ customer จะ specifically require มากกว่านั้น เพราะมัน cover tax codes, line items, parties และ totals ซึ่งพอสำหรับประมาณ 95% ของ B2B invoicing EN 16931 profile เพิ่ม detail สำหรับ edge cases

Validation ก่อน submission

Always validate generated PDF ด้วย PDF/A validator เช่น veraPDF ซึ่งเป็น open-source standard และ validate XML กับ EN 16931 schema ก่อน ship ไป tax authority Failed submissions ไป Chorus Pro / SDI จะกระทบ reliability metrics ของคุณกับ regulator

TL;DR

PDF/A คือ self-contained-document profile PDF/A-3 ทำให้ attach files ได้ Factur-X / ZUGFeRD คือ “EN 16931 XML ที่ attached ภายใน PDF/A-3” E-invoice mandates ทั่วยุโรปทำให้ combination นี้กลายเป็น de facto B2B invoice format ในช่วง 2025-2027

ถ้า renderer ของคุณ treat PDF/A-3 + Factur-X เป็น single config flag การ migration เป็น mechanical ถ้าไม่ใช่ คุณกำลังสร้าง multi-step ops pipeline endpoint /api/v1/e-invoice/render ของ gPdf คือ single-flag version ดู full schema ได้ใน API reference หรือทดลอง sample render ใน Playground