ব্লগ

ইঞ্জিনিয়ারদের জন্য PDF/A ও Factur-X, আইনি ভাষা ছাড়া

PDF/A profile আসলে কী সীমিত করে, EU e-invoicing-এ Factur-X কেন গুরুত্বপূর্ণ, এবং JSON renderer থেকে compliant PDF বের করার সবচেয়ে ছোট pipeline.

আপনি যদি এমন একজন engineer হন যাকে মাত্র বলা হয়েছে, “পরের quarter-এর মধ্যে invoices PDF/A-3 with Factur-X হতে হবে”, আর আপনার একমাত্র context হলো legal team এই শব্দগুলো বলেছে, তাহলে এই post আপনার জন্য।

আমরা standards document-এর ভাষা বাদ দিয়ে ব্যাখ্যা করব এই profiles আসলে কী constrain করে, governments কেন এগুলো mandate করছে, এবং structured-data renderer থেকে compliant PDF emit করার সবচেয়ে ছোট practical pipeline কী।

দুই অনুচ্ছেদে PDF/A

PDF একটি flexible format। অতিরিক্ত flexible — একই PDF spec আপনাকে JavaScript embed করতে, এমন external resource link করতে যা ৫০ বছর পরে নাও থাকতে পারে, reversible cryptography দিয়ে content encrypt করতে, external font reference করতে, এবং আরও অনেক কিছু করতে দেয় যা document-কে self-contained থাকতে দেয় না।

PDF/A-তে “A” মানে Archival। এটি PDF-এর একটি profile যা document-কে ৫০ বছর পরেও একইভাবে render হতে বাধা দিতে পারে এমন অংশগুলো নিষিদ্ধ করে। High-level rules:

  • সব fonts embedded হতে হবে।
  • JavaScript নয়, external links নয়, audio/video নয়।
  • Encryption নয়।
  • Transparency flatten হতে হবে অথবা profile version দ্বারা supported হতে হবে।
  • Colours device-independent হতে হবে; ICC profile required।
  • সব content file-এর ভেতরে থাকতে হবে; network-নির্ভর references নয়।

কয়েকটি version আছে, প্রত্যেকটি newer features-এর জন্য কিছু tolerance যোগ করে:

ProfileYearকী যোগ করে
PDF/A-1b2005Original baseline, সবচেয়ে strict
PDF/A-2b2011JPEG2000, transparency, layers allow করে
PDF/A-3b2012Arbitrary file attachments allow করে, যা Factur-X-এর foundation
PDF/A-42020ISO 32000-2 (PDF 2.0) base, simplified conformance levels

“b” suffix মানে “basic” conformance, অর্থাৎ visual fidelity। “u” অর্থ unicode-mapped এবং “a” অর্থ accessibility-tagged variants-ও আছে। বেশিরভাগ invoice/receipt workflow-এর জন্য “b” দরকার, কারণ tax archival visual reproducibility নিয়ে ভাবে, screen-reader semantics নিয়ে নয়।

Practical takeaway: আপনার renderer যদি বলে PDF/A-3b support করে, সেটা single config flag হওয়া উচিত, যেমন { profile: "PDF/A-3b" } বা equivalent। পরে convert করার জন্য Ghostscript, qpdf বা Acrobat-এর মতো দ্বিতীয় tool চালাতে হলে, সেটি ops-এ হিসাব করার মতো workflow gap।

PDF/A-3 কেন বিশেষভাবে গুরুত্বপূর্ণ: এটি e-invoices-এর carrier

PDF/A-3 একটি capability যোগ করেছে যা শুনতে সাধারণ, কিন্তু বাস্তবে অত্যন্ত গুরুত্বপূর্ণ: PDF-এর ভেতরে arbitrary file attachments

এটা boring শোনাতে পারে। আসলে তা নয়। Europe জুড়ে এখন rollout হওয়া e-invoice mandates-এর সম্পূর্ণ technical foundation এটি।

Architecture: একটি single PDF file যা একসঙ্গে:

  1. Human-readable invoice, অর্থাৎ visual layout, totals, branding।
  2. Machine-readable XML invoice, অর্থাৎ tax authority-এর software যে অংশ parse করে।

দুটিই একই file-এর ভেতরে, দুটিই একই invoice represent করে, আর PDF/A-3 wrapper guarantee দেয় যে file দশক পরেও parseable থাকবে।

মূল XML formats:

  • Factur-X (France), UN/CEFACT Cross Industry Invoice-ভিত্তিক XML profile।
  • ZUGFeRD (Germany), Factur-X-এর সঙ্গে substantively identical; দুই standard 2018 সালে technically merge হয়েছে।
  • EN 16931, European norm যার সঙ্গে দুই implementation conform করে।

Most workflows-এ “Factur-X” এবং “ZUGFeRD” interchangeable terms। তারা schema share করে, embedding mechanism share করে, এবং একটি PDF যদি একটির সঙ্গে compliant হয়, সাধারণত অন্যটির সঙ্গেও compliant।

কী mandatory, কোথায়, কখন

Q2/Q3 2026 rollout plan করা engineers-এর জন্য non-exhaustive snapshot:

CountryStatusRequired format
Germanyinvoice receipt-এর জন্য B2B mandatory from 2025-01-01; 2027 থেকে issuing-ওEN 16931 (Factur-X / ZUGFeRD / XRechnung)
Francelarge enterprises-এর জন্য mandatory issuing 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 2024-2027 timeline-এ EN 16931-compliant e-invoicing-এর কোনো না কোনো flavour implement করছে। আপনার customers যদি এই markets-এর কোনো একটিতে operate করে, আপনার PDF generator-কে visual invoice-এর পাশাপাশি attached XML emit করতে হবে।

সবচেয়ে ছোট practical pipeline

Standards documents কী prescribe করে, সেটা আপাতত ভুলে যান। Engineering view:

   ┌─────────────────────┐
   │  Your invoice data  │  (কোথাও আগেই JSON object)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Build EN 16931 XML  │  (deterministic mapping; tested libs আছে)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Render PDF/A-3b +   │
   │ attach the XML      │  (gPdf-এ single API call, বা elsewhere two-step)
   └─────────┬───────────┘


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

দুটি non-trivial step:

Step 1: XML build করুন

এটি annoying কিন্তু mechanical। আপনি invoice data, যেমন lines, taxes, totals এবং parties, EN 16931 XML field names-এ map করেন। Java/Node/Python-এর বেশ কয়েকটি library এটি করে; নিজের language-এ “factur-x library” search করুন। XML schema specs সত্যিই উপভোগ না করলে scratch থেকে লিখবেন না।

Step 2: PDF/A-3 render করুন এবং XML attach করুন

এখানে renderer choice গুরুত্বপূর্ণ।

Built-in support ছাড়া: আপনি ordinary PDF render করেন, তারপর এমন tool দিয়ে post-process করেন যা PDF/A-3-এ convert করে এবং XML embedded file হিসেবে attach করে। Common stacks: Ghostscript + qpdf, অথবা Aspose-এর মতো paid tool। দুটি extra step, দুটি extra failure point, এবং আপনাকে নিশ্চিত করতে হয় post-processing visual layout drift করাচ্ছে না।

Built-in support সহ (gPdf approach): 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 PDF/A-3b emit করে, আপনার XML factur-x.xml বা zugferd-invoice.xml হিসেবে attach করে, এবং bytes return করে। দুই নামই consumers চিনতে পারে।

Common gotchas

কিছু জিনিস মানুষ কঠিনভাবে শেখে:

“PDF/A” এবং “PDF/A-compliant fonts সহ” একই জিনিস নয়

PDF/A-3 file-এ সব fonts embedded থাকতে হবে এবং used glyphs-এর full character coverage থাকতে হবে। আপনার invoice-এ Japanese customer name থাকলে এবং renderer এমন fallback font নেয় যা fully embeddable নয়, validation tools reject করবে। আপনার renderer PDF/A mode-এ CJK fonts embed করে কি না check করুন; অনেকেই default-ভাবে করে না।

Visual + XML match করতে হবে

XML invoice এবং visual invoice same invoice represent করার কথা। Tax auditors এগুলোর diff করতে পারে। আপনার code যদি XML-এ total: 119.00 emit করে কিন্তু visual PDF Total: 120.00 দেখায়, rounding bug বা stale template-এর কারণে, তাহলে file-এ tax discrepancy আছে। দুটিই same source-of-truth থেকে generate করুন, ideally same code path-এ।

EN 16931-এ “profile” levels

Factur-X profiles: MINIMUM, BASIC, EN 16931, EXTENDED। পার্থক্য হলো XML-এ কত data আছে। BASIC ব্যবহার করুন যদি customer specifically বেশি না চায়; এটি tax codes, line items, parties, totals cover করে, যা প্রায় 95% B2B invoicing-এর জন্য যথেষ্ট। EN 16931 profile edge cases-এর জন্য আরও detail যোগ করে।

Submission-এর আগে validation

Generated PDF সবসময় PDF/A validator দিয়ে validate করুন; veraPDF open-source standard। XML-ও EN 16931 schema-এর বিরুদ্ধে validate করুন before tax authority-তে ship করেন। Chorus Pro / SDI-তে failed submissions regulator-এর কাছে আপনার reliability metrics প্রভাবিত করে।

TL;DR

PDF/A হলো self-contained-document profile। PDF/A-3 files attach করতে দেয়। Factur-X / ZUGFeRD মানে “PDF/A-3-এর ভেতরে attached EN 16931 XML”। EU e-invoice mandates 2025-2027-এর মধ্যে এই combination-কে de facto B2B invoice format বানাচ্ছে।

আপনার renderer যদি PDF/A-3 + Factur-X-কে single config flag হিসেবে treat করে, migration mechanical। না হলে আপনি multi-step ops pipeline তৈরি করছেন। gPdf-এর /api/v1/e-invoice/render single-flag version; API reference full schema দেয়, অথবা Playground-এ sample render try করুন।