ใบแจ้งหนี้อิเล็กทรอนิกส์ (electronic invoice) ที่ปฏิบัติตามข้อกำหนดไม่ใช่แค่ไฟล์ PDF ที่มีไฟล์ XML เย็บติดมาทางด้านข้าง มันคือเอกสาร PDF/A-3 เดี่ยวๆ ที่บรรทุกใบแจ้งหนี้เอาไว้ถึงสองครั้ง: ครั้งแรกในฐานะหน้าเพจให้มนุษย์ได้อ่าน และครั้งที่สองในฐานะ XML ประเภท Cross Industry Invoice ที่เครื่องจักรอ่านได้ (machine-readable) ซึ่งถูกจัดเก็บไว้ภายในไฟล์ในฐานะไฟล์ที่เกี่ยวข้อง (associated file) ตัวแทนทั้งสองนี้ทำหน้าที่อธิบายใบแจ้งหนี้ใบเดียวกัน ธรรมชาติแบบคู่ขนาน (dual nature) ที่ว่านี้คือประเด็นสำคัญทั้งหมดทั้งมวลของตระกูลรูปแบบที่ข้อบังคับของยุโรปกำลังเรียกร้องอยู่ในขณะนี้ ไม่ว่าจะเป็น Factur-X ในฝรั่งเศสและเยอรมนี ZUGFeRD ทั่วตลาดที่พูดภาษาเยอรมัน และ XRechnung สำหรับการเรียกเก็บเงินของภาครัฐในเยอรมนี บทความนี้จะพาคุณไปดูว่า PDFlibPas ทำการประกอบใบแจ้งหนี้แบบไฮบริด (hybrid invoice) ใน Delphi อย่างไร มาตรฐานเปิดช่องว่างให้เกิดความผิดพลาดได้ที่ตรงไหนบ้าง และเพราะเหตุใดโปรไฟล์ (profile) หนึ่งในแคตตาล็อกจึงมีความจำเป็นที่จะต้องใช้ตัวสร้าง (builder) XML ที่แยกส่วนออกมาโดยสิ้นเชิง
ใบแจ้งหนี้แบบไฮบริด (hybrid invoice) แท้จริงแล้วคืออะไร
หน้าเพจที่มองเห็นได้กับ XML ที่ฝังอยู่ต่างก็รับใช้ผู้อ่านที่แตกต่างกัน เสมียน (clerk) ที่กำลังอนุมัติการชำระเงินจะมองไปที่หน้าเพจซึ่งถูกเรนเดอร์ (rendered) ออกมา ส่วนระบบเจ้าหนี้การค้า (accounts-payable system) จะดูดซับ XML เข้าไป อ่านยอดรวมและการแจกแจงภาษีในฐานะฟิลด์ที่มีโครงสร้าง และทำการบันทึกรายการบัญชีโดยปราศจากมนุษย์ที่ต้องมากดปุ่มคีย์อะไรเลย เนื้อหาเชิงความหมาย (semantic content) ของ XML นั้นอยู่ภายใต้การควบคุมของ EN 16931 ซึ่งเป็นมาตรฐานยุโรปที่ให้คำจำกัดความโมเดลข้อมูลของใบแจ้งหนี้ว่า: มีฟิลด์ไหนบ้างที่มีตัวตนอยู่ พวกมันมีความหมายว่าอย่างไร และฟิลด์ใดบ้างที่เป็นข้อบังคับ (mandatory) EN 16931 คือโมเดลเชิงความหมาย (semantic model) ไม่ใช่รูปแบบของไฟล์ (file format) ทั้ง Factur-X, ZUGFeRD 2.x และ XRechnung ล้วนตระหนักถึงโมเดลนั้นในฐานะที่เป็นเอกสารแบบ UN/CEFACT Cross Industry Invoice ซึ่งเป็นวากยสัมพันธ์ (syntax) ที่บรรทุกฟิลด์ต่างๆ ของ EN 16931 ให้อยู่บนเส้นทางที่รับส่งข้อมูล (on the wire)
เพื่อให้เอกสารเป็นได้ทั้งสิ่งที่มีความสามารถในการเก็บถาวร (archivable) และอธิบายตัวเองได้ (self-describing) ตัวคอนเทนเนอร์ (container) จึงเป็นแบบ PDF/A-3 ซึ่งถูกนิยามเอาไว้โดย ISO 19005-3 PDF/A-3 คือระดับการปฏิบัติตามข้อกำหนดที่อนุญาตให้มีไฟล์ฝังตัวแบบใดก็ได้ (arbitrary embedded files) ซึ่งนั่นก็คือสิ่งที่ XML ใบแจ้งหนี้จำเป็นต้องเป็นพอดิบพอดี PDF/A-2 นั้นห้ามไม่ให้ฝังไฟล์ใดๆ ก็ตามที่ตัวมันเองไม่ได้เป็น PDF/A ดังนั้นใบแจ้งหนี้ Factur-X จึงไม่สามารถเป็น PDF/A-2 ได้ ตัวเลือกที่เป็น PDF/A-3 จึงไม่ใช่เรื่องของความชอบ แต่มันเป็นข้อกำหนดซึ่งเป็นผลลัพธ์ที่ตามมาโดยตรงจากการที่ต้องการฝังข้อมูลที่ไม่ใช่ PDF เอาไว้ในเอกสารเพื่อการเก็บถาวร
เหตุใดความสัมพันธ์จึงเป็น Alternative (ทางเลือก)
การฝังไบต์ (bytes) เป็นส่วนที่ง่าย ISO 32000 §7.11.4 ได้ให้คำจำกัดความของสตรีมของไฟล์ที่ฝังไว้ (embedded file stream) ซึ่งก็คืออ็อบเจ็กต์ (object) ที่ถือครอง XML ดิบ (raw XML) ตลอดจนพารามิเตอร์ (parameters) ของมันเอาไว้ ส่วนที่ทำให้ไฟล์กลายเป็นไฟล์ที่เกี่ยวข้องอย่างถูกต้อง (valid associated file) ก็คือ §14.13 ซึ่งได้ทำการเพิ่มแนวคิดของไฟล์ที่เกี่ยวข้องและคีย์ /AFRelationship เข้ามา คีย์ดังกล่าวทำหน้าที่ประกาศให้ทราบว่าข้อมูลที่ถูกฝังมีความสัมพันธ์อย่างไรกับเนื้อหาที่มันแนบตัวอยู่ และค่าที่ Factur-X บังคับใช้ก็คือ Alternative (ทางเลือก)
ตัวเลือกนี้มีความสำคัญ เนื่องจากค่าอื่นๆ จะเป็นการยืนยันในสิ่งที่เป็นเท็จเกี่ยวกับตัวเอกสาร Source จะหมายความว่า XML คือวัสดุต้นทางที่ใช้สร้างเนื้อหาที่มองเห็นได้ เป็นต้นฉบับหลัก (master) ที่หน้าเพจถูกสกัดออกมา Supplement จะหมายความว่า XML ทำการเพิ่มข้อมูลที่นอกเหนือไปจากสิ่งที่หน้าเพจแสดงให้เห็น เป็นส่วนพิเศษเสริมที่ไม่ได้มีอยู่ในการเรนเดอร์ ซึ่งทั้งคู่ไม่ใช่สิ่งที่ใบแจ้งหนี้แบบ Factur-X เป็น XML กับหน้าเพจคือสองการแสดงออกที่มีความเท่าเทียมกันของใบแจ้งหนี้ใบหนึ่ง ซึ่งบรรทุกเนื้อหาทางกฎหมายแบบเดียวกันในสองรูปแบบ Alternative คือค่าที่กล่าวในสิ่งนั้นอย่างตรงไปตรงมา: ตัวแทนทางเลือกที่เทียบเท่า (equivalent alternative representation) ของเนื้อหาที่มองเห็นได้ ตัวตรวจสอบความถูกต้อง (validator) ใดๆ ที่อ่านพบความสัมพันธ์ในรูปแบบอื่นใดบนไฟล์ Factur-X จะทำการปฏิเสธไฟล์นั้น และก็เป็นการถูกต้องแล้วที่จะทำเช่นนั้น เนื่องจากความสัมพันธ์ (relationship) ก็คือคำกล่าวอ้างแบบที่เครื่องจักรอ่านได้ (machine-readable claim) ที่ระบุว่าสิ่งที่แนบมาด้วยนั้นมีไว้เพื่อการใด
แคตตาล็อกโปรไฟล์ (profile catalog)
E-Invoice sample (ตัวอย่างของใบแจ้งหนี้อิเล็กทรอนิกส์) ที่จัดส่งมาพร้อมกับ PDFlibPas ได้ขับเคลื่อนเส้นทางการสร้าง (generation path) ในรูปแบบเดียวกันครอบคลุมโปรไฟล์หกรายการ ซึ่งถูกนิยามไว้ในฐานะอาร์เรย์ของระเบียน (array of records) ใน InvoiceModel.pas แต่ละโปรไฟล์จะบรรทุกค่าที่ผู้เขียนต้องการเอาไว้: ชื่อที่ใช้แสดงผล (display name), ชื่อของไฟล์ที่ถูกฝังไว้ (embedded file name), ระดับการปฏิบัติตามข้อกำหนด (conformance level), /AFRelationship, เวอร์ชัน, รหัสประเทศที่เป็นทางเลือก (optional country code) และ URN ของ GuidelineID ซึ่ง XML เป็นผู้ประกาศแจ้งไว้ภายในบริบทเอกสารของตน
หกรายการที่ว่านี้ได้แก่ Factur-X EN16931, Factur-X BASIC, Factur-X EXTENDED สำหรับประเทศฝรั่งเศส, XRechnung 3.0, ZUGFeRD 1.0 COMFORT และ ZUGFeRD 2.0 BASIC ตัว GuidelineID คือฟิลด์ที่ทำหน้าที่บอกให้ผู้รับ (receiver) ทราบอย่างแม่นยำว่าจะต้องคาดหวังโปรไฟล์รูปแบบใด และค่าต่างๆ ก็มีความเฉพาะเจาะจง Factur-X EN16931 จะประกาศ urn:cen.eu:en16931:2017 XRechnung 3.0 จะประกาศ urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 ZUGFeRD 2.0 BASIC จะประกาศ urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic ชื่อของไฟล์ที่ฝังไว้ก็เป็นส่วนหนึ่งของสัญญาด้วยเช่นกัน โปรไฟล์ตระกูล Factur-X จะฝัง factur-x.xml ตระกูล XRechnung จะฝัง xrechnung.xml และโปรไฟล์ตระกูล ZUGFeRD จะฝัง ZUGFeRD-invoice.xml หรือ zugferd-invoice.xml ผู้รับจะทำการสแกนรายชื่อสิ่งที่แนบมาด้วย (attachment names) เพื่อที่จะหาใบแจ้งหนี้ ดังนั้นชื่อไฟล์จึงไม่ได้เป็นแค่เรื่องของความสวยงามตกแต่งเอาไว้เฉยๆ (cosmetic)
รายละเอียดหนึ่งในแคตตาล็อกนั้นคุ้มค่าที่จะอ่านอย่างถี่ถ้วน โปรไฟล์ส่วนใหญ่จะใช้ความสัมพันธ์แบบ Alternative ทว่ารายการสำหรับ XRechnung 3.0 ในตัวอย่างนั้นกลับใช้ Source ทั้งสองรูปแบบนี้มีการตอบสนองต่อตัวตรวจสอบความถูกต้องและธรรมเนียมปฏิบัติที่แตกต่างกันออกไป และตัวอย่างได้ทำการตั้งค่าความสัมพันธ์ของแต่ละโปรไฟล์จากในแคตตาล็อก แทนที่จะเขียนโค้ดผูกมัดค่าเดียวตายตัวลงไป (hard-coding) ซึ่งนั่นก็คือเหตุผลที่ว่าทำไมฟิลด์ในระดับต่อโปรไฟล์ (per-profile field) จึงมีอยู่แทนที่จะเป็นค่าคงที่ (constant)
กับดักของ ZUGFeRD 1.0 (The ZUGFeRD 1.0 trap)
มันเป็นเรื่องน่าดึงดูดใจที่จะถือเอาว่าทุกโปรไฟล์ก็คือ EN 16931 Cross Industry Invoice โดยมีความผันแปรเล็กๆ น้อยๆ ตรงที่ว่าคุณจะทำการป้อนข้อมูล (populate) ลงในฟิลด์ที่เป็นทางเลือกจำนวนกี่ช่อง สิ่งนี้เป็นความจริงสำหรับห้าในหกรายการ แต่มันกลับไม่เป็นความจริงเลยสำหรับ ZUGFeRD 1.0 COMFORT และเหตุผลก็เป็นเรื่องของโครงสร้างมากกว่าที่จะเป็นเรื่องของความสวยงามตกแต่ง
โปรไฟล์ยุคใหม่จะทำการปล่อย (emit) UN/CEFACT Cross Industry Invoice ในเวอร์ชันของเนมสเปซ (namespace version) เป็น :100 ซึ่งมีเอลิเมนต์ราก (root element) คือ rsm:CrossIndustryInvoice ZUGFeRD 1.0 มีมาก่อนที่สคีมา (schema) นั้นจะถือกำเนิดขึ้น มันคือ 2014 CrossIndustryDocument ซึ่งมีเวอร์ชันของเนมสเปซเป็น :1p0 และมีเอลิเมนต์รากเป็น rsm:CrossIndustryDocument URN ของเนมสเปซก็มีความแตกต่างกัน เอลิเมนต์รากก็มีความแตกต่างกัน และโครงสร้างต้นไม้ของเอลิเมนต์ (element tree) ก็ยังมีความแตกต่างกันไปตลอดทั้งแนว: สคีมาแบบ :1p0 จะจับกลุ่มข้อมูลต่างๆ ภายใต้ ApplicableSupplyChainTradeAgreement, ApplicableSupplyChainTradeDelivery และ ApplicableSupplyChainTradeSettlement ในขณะที่แบบ :100 กลับใช้ ApplicableHeaderTradeAgreement, ApplicableHeaderTradeDelivery และ ApplicableHeaderTradeSettlement การตั้งชื่อนั้นมีความคล้ายคลึงกันมากพอที่จะทำให้เข้าใจผิด และก็มีความแตกต่างกันมากพอที่จะทำให้มันพังได้
คำว่า COMFORT ในชื่อโปรไฟล์อธิบายให้ทราบว่าข้อมูลนั้นมีความอุดมสมบูรณ์เพียงใด โดยเป็นโปรไฟล์ระดับระบบอัตโนมัติ (automation-grade profile) ที่มีรายการสินค้าครบถ้วนสมบูรณ์ มีการแจกแจงภาษี และเงื่อนไขการชำระเงิน แต่มันไม่ได้บอกว่าสคีมาใดเป็นตัวบรรทุกข้อมูลดังกล่าว ดังนั้นคุณจึงไม่สามารถนำเอาเอกสารแบบ :100 มาทำการติดป้ายชื่อ (relabel) ใหม่ให้กลายเป็น ZUGFeRD 1.0 ตัวอย่าง (sample) จัดการกับเรื่องนี้ด้วยฟล็ก (flag) อันหนึ่งที่อยู่บนระเบียน (record) ของแต่ละโปรไฟล์ ควบคู่ไปกับฟังก์ชันของตัวสร้าง (builder functions) สองตัวที่แยกส่วนกัน โดยทำการคัดเลือกตัวที่ถูกต้องขึ้นมาก่อนที่จะมีการสร้าง (generated) XML ใดๆ
function BuildInvoiceXMLText(const AProfile: TeInvoiceProfile;
const Data: TInvoiceData): string;
begin
// XMLFamily = 1 means the legacy ZUGFeRD 1.0 :1p0 schema; every
// other profile is the modern UN/CEFACT :100 Cross Industry Invoice.
if AProfile.XMLFamily = 1 then
Result := BuildZUGFeRD1Text(AProfile, Data)
else
Result := BuildCII100Text(AProfile, Data);
end;
การแบ่งส่วนไม่ได้เป็นแค่เรื่องของความพิถีพิถันในการอิมพลีเมนต์ (implementation nicety) การป้อนโครงสร้างต้นไม้แบบ :100 ให้กับผู้รับระดับ ZUGFeRD 1.0 จะสร้างเอกสารที่ล้มเหลวในการตรวจสอบความถูกต้องของสคีมา (schema validation) นับตั้งแต่เอลิเมนต์รากเลยทีเดียว ดังนั้นทั้งสองตระกูลจึงจำเป็นที่จะต้องถูกสร้างขึ้นด้วยโค้ด (code) ที่ทราบว่าตนกำลังเขียนตระกูลใดอยู่
การเลือกระดับของ PDF/A-3
PDF/A-3 มีระดับการปฏิบัติตามข้อกำหนดอยู่ด้วยกันสามระดับ และ PDFlibPas ก็ทำการเลือกพวกมันผ่านทาง SetPDFAMode โหมด 5 (Mode 5) คือ PDF/A-3b ซึ่งเป็นระดับที่รับประกันว่าจะมีการผลิตการมองเห็นซ้ำได้อย่างน่าเชื่อถือ (reliable visual reproduction) โหมด 6 (Mode 6) คือ PDF/A-3a ซึ่งจะทำการเพิ่มข้อกำหนดในส่วนของโครงสร้างแบบติดแท็ก (tagged-structure) และการเข้าถึงได้ (accessibility) ของระดับ a เข้าไป โหมด 7 (Mode 7) คือ PDF/A-3u ซึ่งบังคับว่าข้อความทั้งหมดจะต้องถูกจับคู่ (mapped) ไปยัง Unicode การเปิดใช้งาน (enabling) โหมดนี้ยังเป็นการฝังเป้าหมายที่ตั้งใจในการส่งออก (output intent) แบบ sRGB ในตัวของไลบรารีเข้าไปด้วย ซึ่งนั่นก็คือการระบุลักษณะสีที่ PDF/A มีความต้องการ เพื่อที่จะให้สีที่ถูกเรนเดอร์ได้รับการนิยามขึ้นมา แทนที่จะต้องมาพึ่งพาขึ้นอยู่กับอุปกรณ์ปลายทาง (device-dependent)
โฟลว์ (flows) ของใบแจ้งหนี้ส่วนใหญ่จะรันอยู่ที่ระดับ 3b ซึ่งถือว่ามีความเพียงพอสำหรับหน้าเพจที่มองเห็นได้อย่างซื่อตรง ควบคู่ไปกับตัว XML ที่ถูกฝังอยู่ หากคุณต้องการใช้โปรไฟล์ ICC ที่ระบุแบบชัดแจ้ง (explicit) แทนที่จะเป็นแบบที่มีอยู่ในตัว LoadOutputIntentProfile ก็จะทำการสลับตัวมันเข้าไปแทนที่ (swaps it in) หลังจากที่ได้ทำการตั้งค่าโหมดเรียบร้อยแล้ว ตัวอย่างได้ทำการโหลดโปรไฟล์แบบ sRGB จากคลัง (repository) ด้วยวิธีนี้ และจะล่าถอย (falls back) กลับไปใช้เป้าหมายที่ตั้งใจแบบที่มีอยู่ในตัวเมื่อตัวไฟล์นั้นไม่สามารถเข้าถึงได้ (not reachable) ดังนั้นเป้าหมายที่ตั้งใจในการส่งออก (output intent) จึงมีปรากฏตัวอยู่เสมอ
PDF := TPDFlib.Create;
try
// Mode 5 = PDF/A-3b, 6 = PDF/A-3a, 7 = PDF/A-3u.
if PDF.SetPDFAMode(5) <> 1 then
raise Exception.Create('PDF/A-3 mode could not be enabled');
// Optional: swap the built-in sRGB intent for an explicit ICC profile.
if PDF.LoadOutputIntentProfile(ICCFile, 'DeviceRGB') <> 1 then
{ fall back to the built-in sRGB intent that SetPDFAMode embedded };
finally
// ... continue building the document
end;
การสร้างใบแจ้งหนี้แบบไฮบริด (hybrid invoice)
เมื่อตัวคอนเทนเนอร์ (container) ได้รับการกำหนดค่า (configured) เรียบร้อยแล้ว ส่วนที่เหลือก็คือสามขั้นตอนที่ต้องทำตามลำดับ: ตั้งค่าโหมดแบบ PDF/A-3 ทำการวาดหน้าเพจแบบที่มนุษย์สามารถอ่านได้ (human-readable) จากนั้นก็แนบตัว XML ไปในฐานะเป็นไฟล์ที่เกี่ยวข้อง หน้าเพจที่มองเห็นได้นั้นเป็นเพียงเนื้อหาตามปกติธรรมดา มีเพียงข้อจำกัด (constraint) เดียวที่ควรค่าแก่การจดจำนั่นก็คือ PDF/A มีข้อห้ามในส่วนของ Standard 14 fonts ที่ไม่ได้รับการฝังตัว ดังนั้นหน้าเพจจึงจำเป็นที่จะต้องทำการฝังหน้าตาของฟอนต์ (font face) ลงไปจริงๆ แทนที่จะใช้วิธีอ้างอิงไปถึงสิ่งที่ถูกสร้างติดตั้งอยู่ในตัว (built-in)
การแนบไฟล์ที่ว่านั้นเป็นการเรียกใช้ (call) เพียงแค่ครั้งเดียว AddFacturXAssociatedFileFromString จะนำเอาไบต์ XML ดิบที่เป็นแบบ UTF-8 บวกเข้ากับเมทาดาตา (metadata) ของโปรไฟล์ ทำการเขียนสตรีมไฟล์ที่ฝังไว้ ลงทะเบียนมันลงไปในอาร์เรย์ (array) /AF ในแคตตาล็อกซึ่งเป็นสิ่งที่ PDF/A-3 เรียกร้อง ปรับใช้ /AFRelationship และทำหน้าที่สร้างเมทาดาตาของ e-invoice แบบ XMP ที่จะช่วยระบุได้ว่าเอกสารชิ้นนั้นๆ เป็น Factur-X, ZUGFeRD หรือ XRechnung นอกจากนี้มันยังตรวจสอบด้วยว่า guideline ID ของตัว XML นั้นมีลักษณะตรงกันกับระดับการปฏิบัติตามข้อกำหนดที่คุณร้องขอหรือไม่ ดังนั้นความไม่สอดคล้องกัน (mismatch) ที่เกิดขึ้นระหว่าง XML ที่คุณทำการสร้างขึ้นมากับโปรไฟล์ที่คุณได้ทำการระบุชื่อไว้จะถูกจับตัวได้ แทนที่จะหลุดรอดถูกจัดส่งออกไปแบบเงียบๆ
// 1. PDF/A-3 mode and output intent are already set.
// 2. Draw the visible page (embeds a real TrueType font).
DrawInvoicePage(PDF, AProfile, Data);
// 3. Build the profile-correct XML and attach it as an
// associated file with /AFRelationship = Alternative.
InvoiceXML := BuildInvoiceXML(AProfile, Data); // AnsiString of UTF-8 bytes
FileID := PDF.AddFacturXAssociatedFileFromString(
InvoiceXML,
AProfile.ConformanceLevel, // e.g. 'EN16931'
AProfile.FileName, // 'factur-x.xml'
AProfile.Description,
AProfile.Relationship, // 'Alternative'
AProfile.Version, // '1.0'
AProfile.CountryCode); // '' or 'DE' or 'FR'
if FileID <= 0 then
raise Exception.Create('Invoice XML could not be attached');
PDF.SaveToFile(TargetFile);
รายละเอียดอันละเอียดอ่อนประการหนึ่งในเส้นทางข้อมูล (data path) ก็คือการเข้ารหัส (encoding) XML ที่ถูกฝังไว้ประกาศว่าใช้ encoding="UTF-8" และเมธอด (method) ก็รับไบต์ (bytes) ของมันเข้ามาในฐานะที่เป็น AnsiString ดังนั้นชื่อของผู้ขายหรือผู้ซื้อที่ไม่ใช่ตัวอักษรแบบ ASCII (non-ASCII) จะต้องเดินทางมาถึงจุดที่มีการเรียกใช้ (call) ในฐานะกลุ่มแปดบิต (octets) ดิบๆ แบบ UTF-8 การแปลงประเภทแบบเรียบง่าย (plain cast) โดยส่งผ่านหน้าโค้ด ANSI (ANSI code page) ของระบบ จะเข้าไปทำให้อักขระ (characters) เหล่านั้นเสียหาย และมันก็จะทำการผลิตใบแจ้งหนี้ออกมาเงียบๆ โดยที่ XML ของมันจะไม่มีทางจับคู่เข้ากันได้กับสิ่งที่มีการประกาศเอาไว้อีกต่อไป ตัวอย่างได้ทำการเข้ารหัส (encodes) เป็น UTF-8 แบบชัดแจ้ง (explicitly) ก่อนที่จะทำการส่งมอบไบต์ (bytes) ต่อไป ซึ่งเป็นวิธีที่ปลอดภัยสำหรับการป้อน API ที่เป็นแบบมุ่งเน้นไปที่ไบต์ (byte-oriented) ของ PDF จาก string ที่เป็น Unicode
สำหรับการแนบ XML ซึ่งไม่ใช่โปรไฟล์ (profile) แบบ e-invoice ที่เป็นที่รู้จัก AddPDFA3AssociatedFileFromString ถือเป็นคู่หูในระดับแบบทั่วไป (generic counterpart) มันจะรับเอาชื่อไฟล์ (file name), ชนิดของ MIME (MIME type), คำอธิบาย (description), ความสัมพันธ์ (relationship) ตลอดจนบรรดาไบต์ (bytes) และเขียนไฟล์ที่เกี่ยวข้องแบบ PDF/A-3 ธรรมดาๆ ลงไปโดยปราศจากการมีเมทาดาตาที่เฉพาะเจาะจงกับใบแจ้งหนี้ (invoice-specific metadata) หรือการตรวจสอบแนวทาง (guideline checks) ใดๆ ให้ใช้งานมันสำหรับข้อมูลเสริม (supplementary data) และใช้วิธี (method) ของ Factur-X สำหรับบรรดาใบแจ้งหนี้ เพื่อที่ตัวเมทาดาตาของโปรไฟล์และการตรวจสอบคู่ความสอดคล้องของแนวทางจะถูกเขียนลงไปให้แก่คุณ
เมื่อตัวเอกสารถูกผลิตออกมา คำถามต่อไปก็คือว่า มันจะสามารถผ่านการตรวจสอบความถูกต้องแบบ PDF/A รวมทั้งเรื่องของการเข้าถึงได้ (accessibility) หรือไม่ และมันจะสามารถรับการลงลายเซ็น (signed) ได้โดยที่ไม่มีการทำลายความเป็นไปตามข้อกำหนด (compliance) ใช่หรือไม่ คำถามเหล่านั้นได้รับความคุ้มครองอยู่ใน คำแนะนำเบื้องต้นเกี่ยวกับ PDF/A และการตรวจสอบก่อนบินของ PDF/UA และ ม้านั่งทำงานสำหรับการปฏิบัติตามข้อกำหนดและการลงลายเซ็น สิ่งเหล่านี้ทั้งหมดถูกจัดส่งมาในฐานะส่วนหนึ่งของ PDFlibPas Delphi PDF Library โดยเคียงคู่มากับ PDF/A, tagging และ document-property APIs ที่บรรดาเส้นทาง (path) ของ e-invoice เข้าไปสร้างตัวอยู่บนนั้น