لقد قمت ببناء فاتورة Factur-X وتجاوزت كل فحوصات الحاوية بنجاح. يحمل الكتالوج مصفوفة /AF، وتحل شجرة أسماء EmbeddedFiles إلى مواصفات الملف الصحيحة، ويحتوي factur-x.xml المضمن على /AFRelationship الصحيح وهو Alternative، وترجع الدالة المدمجة ValidateFacturXInvoice القيمة 1. ثم تقوم بتشغيل نفس الملف عبر veraPDF، وهي الأداة المرجعية للتحقق التي تستخدمها البوابات الضريبية، وتحكم بأن المستند بأكمله ليس بتنسيق PDF/A-3 صالح. الهيكل صحيح. المشكلة في البيانات الوصفية، وهذا الفشل هو أحد أسهل الأخطاء التي يمكن تفويتها في مسار عمل الفاتورة الإلكترونية بأكمله
السبب يستحق الفهم بالكامل، لأنه يفسر فئة من عيوب PDF/A لا علاقة لها بالصفحة المرئية أو المرفق وكل العلاقة بكيفية وصف XMP لنفسه. هذا هو الفخ الذي يختبئ خلف فحص الحاوية الأخضر
الخصائص الأربع التي تُفشل الملف
تكتب فاتورة Factur-X أربع خصائص مخصصة في حزمة XMP الخاصة بها بحيث يمكن لبرامج المصب قراءة الملف الشخصي للفاتورة دون تحليل ملف XML المضمن. توجد هذه الخصائص في مساحة اسم Factur-X تحت البادئة fx: fx:DocumentFileName، و fx:DocumentType، و fx:Version، و fx:ConformanceLevel. إنها بالضبط البيانات الوصفية التي يحتاجها القارئ ليعرف أن ملف PDF هذا يحمل فاتورة EN 16931 تسمى factur-x.xml في الإصدار 1.0
لا يشكل أي من تلك الخصائص الأربع جزءاً من أي مخطط XMP يحدده PDF/A مسبقاً. تُعرف مخططات Dublin Core، و XMP Basic، و PDF، وتحديد PDF/A للقارئ المتوافق، ولكن fx: غير معروف. عندما يمر veraPDF عبر XMP ويصل إلى خاصية لا يتعرف على مساحة الاسم الخاصة بها، فإنه يبحث عن إعلان يخبره بما تعنيه الخاصية. إذا غاب هذا الإعلان، فإنه يبلغ عن فشل مقابل بند ISO 19005-3 رقم 6.6.2.3.1، والذي يتطلب وصف كل خاصية غير مستمدة من مخطط محدد مسبقاً في مخطط امتداد PDF/A. أربع خصائص غير معلنة، أربع طرق لرفض الملف، ولا تظهر أي منها لفحص الحاوية
لماذا يرفض PDF/A خاصية مخصصة مجردة
تبدو القاعدة متحذلقة حتى تتذكر الغرض من PDF/A. التنسيق موجود حتى يمكن فتح ملف وفهمه بعد عقود من الآن، بواسطة برنامج لم يتم إخباره أبداً عن اصطلاحات عام 2026. من المتوقع أن يفهم القارئ المتوافق المستند من المستند وحده، دون الحاجة إلى الرجوع إلى سجل خارجي
تكسر البيانات الوصفية المخصصة هذا الوعد ما لم يحمل الملف وصفه الخاص. بالنظر إلى خاصية fx:ConformanceLevel مجردة، لا يمكن لقارئ مستقبلي أن يعرف URI لمساحة الاسم الذي ترتبط به البادئة fx، أو ما إذا كانت القيمة عبارة عن نص أو تاريخ أو عدد صحيح، أو ما إذا كانت الخاصية تصف المستند نفسه أو مورداً خارجياً. تسد آلية مخطط امتداد PDF/A هذه الفجوة. إنها تتيح للملف أن يعلن، في بنية XMP ثابتة، عن مساحة الاسم والبادئة، ولكل خاصية نوع القيمة وفئة internal أو external. بمجرد وجود هذا الإعلان، تصبح الخاصية واصفة لنفسها، ويتم استيفاء البند 6.6.2.3.1. بدونه، لا يوجد خيار أمام أداة التحقق سوى معاملة الخاصية على أنها غير مفهومة وإفشال الملف. تمييز الفئة مهم هنا: خصائص الفاتورة مثل هذه تصف البيانات التي تأتي من خارج معالج PDF، لذلك يتم الإعلان عنها كـ external بدلاً من internal
ما يحتويه إعلان مخطط الامتداد
الإعلان عبارة عن rdf:Description في حزمة XMP يستخدم مساحات الأسماء الثلاث المحددة بواسطة AIIM وهي pdfaExtension و pdfaSchema و pdfaProperty. داخل حقيبة pdfaExtension:schemas يوجد إدخال مخطط واحد يسمي مخطط Factur-X، ويعطي pdfaSchema:namespaceURI و pdfaSchema:prefix الخاصين به، ثم يسرد الخصائص الأربع في تسلسل pdfaSchema:property. تحمل كل خاصية اسماً، و pdfaProperty:valueType من نوع Text، و pdfaProperty:category بقيمة external. يوضح التوصيف التوضيحي أدناه شكل هذه الكتلة
<rdf:Description rdf:about=""
xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/"
xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#"
xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">
<pdfaExtension:schemas>
<rdf:Bag>
<rdf:li rdf:parseType="Resource">
<pdfaSchema:schema>Factur-X PDFA Extension Schema</pdfaSchema:schema>
<pdfaSchema:namespaceURI>urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#</pdfaSchema:namespaceURI>
<pdfaSchema:prefix>fx</pdfaSchema:prefix>
<pdfaSchema:property>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<pdfaProperty:name>DocumentFileName</pdfaProperty:name>
<pdfaProperty:valueType>Text</pdfaProperty:valueType>
<pdfaProperty:category>external</pdfaProperty:category>
<pdfaProperty:description>name of the embedded XML invoice file</pdfaProperty:description>
</rdf:li>
<!-- DocumentType, Version, ConformanceLevel declared the same way -->
</rdf:Seq>
</pdfaSchema:property>
</rdf:li>
</rdf:Bag>
</pdfaExtension:schemas>
</rdf:Description>
إن URI الخاص بمساحة الاسم والبادئة ليسا سلاسل ثابتة. إنهما يتبعان الملف الشخصي. يستخدم مستند Factur-X urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0# مع البادئة fx، بينما يتم حل ملف ZUGFeRD 2.0 المحدد من خلال zugferd-invoice.xml إلى URI مختلف تحت اسم المخطط الخاص به. يجب أن يعلن مخطط الامتداد عن نفس URI لمساحة الاسم الذي تستخدمه كتلة الخصائص بالفعل، وإلا فإن أداة التحقق ستظل غير قادرة على ربط الاثنين. يستمد PDFlibPas كلتا القيمتين من اسم الملف والإصدار اللذين تقوم بتمريرهما، لذلك يتفق الإعلان وكتلة الخصائص دائماً
كيف يكتب المساعد كلا النصفين معاً
في PDFlibPas لا تقوم بتجميع ملف XML يدوياً. تضع المستند في وضع PDF/A-3 وتستدعي طريقة واحدة. أول شيء يجب تسويته هو علامة التوافق، لأن Factur-X يتطلب PDF/A-3. يؤدي استدعاء SetPDFAMode(7) إلى تحديد مستوى PDF/A-3u، مما يعين pdfaid:part إلى 3 و pdfaid:conformance إلى U في مخطط التعريف. تحمل حزمة XMP الآن الجزء والتوافق الصحيحين قبل إضافة أي بيانات وصفية للفاتورة
var
FileID: Integer;
begin
PDF.SetPDFAMode(7); // PDF/A-3u: pdfaid:part=3, conformance=U
PDF.NewDocument;
// draw the human-readable invoice page here
FileID := PDF.AddFacturXAssociatedFileFromString(
InvoiceXML, // raw UTF-8 XML bytes
'EN16931', // ConformanceLevel
'factur-x.xml', // embedded file name
'Factur-X invoice XML', // /Desc text
'Alternative', // /AFRelationship
'1.0', // profile version
''); // optional country code
if FileID = 0 then
Exit; // not PDF/A-3, or XML/profile mismatch
PDF.SaveToFile('factur-x.pdf');
end;
استدعاء واحد لـ AddFacturXAssociatedFileFromString يقوم بالعمل الذي كان مفقوداً في الملف الفاشل. إنه يضمن XML كملف مرتبط بـ PDF/A-3 بالعلاقة التي قمت بتسميتها، ويسجل خصائص fx الأربع جنباً إلى جنب مع اسم المخطط و URI لمساحة الاسم والبادئة للملف الشخصي المختار. عند حفظ المستند، تقوم خطوة داخلية تسمى ApplyFacturXMetadata بحقن كل من كتلة الخصائص والإعلان المطابق لـ pdfaExtension:schemas في حزمة XMP، لذلك تصل الخصائص المخصصة وهي موصوفة بالفعل. ترجع الطريقة 0 إذا لم يكن المستند في وضع PDF/A-3 أو إذا لم يتطابق ملف XML مع الملف الشخصي المعلن، وهو نفس الحارس الذي يمنع الفاتورة المشوهة من الوصول إلى الملف في المقام الأول
البقعة العمياء التي لا يمكن لفحص الحاوية رؤيتها
هذا هو الجزء الذي يجب تسميته بوضوح، لأنه السبب الذي يجعل الخطأ يختبئ. يتحقق ValidateFacturXInvoice من الحاوية. ويؤكد أن الكتالوج يحتوي على إدخال /AF، وأن شجرة أسماء EmbeddedFiles موجودة، وأن ملف XML للفاتورة موجود، وأن اسم الملف المضمن يطابق الملف الشخصي، وأن مُعرّف المبدأ التوجيهي في XML يتفق مع مستوى التوافق، وأن /AFRelationship هو ما يسمح به PDF/A-3. هذه فحوصات حقيقية وهي تلتقط عيوباً حقيقية. يُبلغ GetFacturXValidationIssues عنها بالاسم، بمعرفات مثل MissingCatalogAF و NotPDFA3 و ConformanceGuidelineMismatch و InvalidAFRelationship و InvalidFileNameProfile
ما لا يتحقق منه هو ما إذا كان مخطط امتداد XMP موجوداً وصحيحاً. إن الملف الذي تكون حاويته خالية من العيوب ولكن خصائص fx الخاصة به غير معلنة يجتاز كل فحص للمشاكل ويرجع 1، لأنه لا يوجد شيء في تلك القائمة يفحص كتلة pdfaExtension:schemas. هذا هو بالضبط سبب قدرة فاتورة مبنية يدوياً، أو واحدة منتجة بواسطة مسار عمل كتب كتلة الخصائص بدون الإعلان، على المرور بسلاسة عبر أداة التحقق المدمجة ولا تزال تفشل في veraPDF بشأن البند 6.6.2.3.1. تُجيب أداة التحقق من الحاوية وأداة التحقق من البيانات الوصفية لـ PDF/A على أسئلة مختلفة، وفقط فاحص PDF/A الكامل هو من يجيب على السؤال الثاني
قراءة المشاكل لتعرف أي طبقة تعطلت
نظراً لأن الطبقتين تفشلان بشكل مستقل، فإن عادة التشخيص الصحيحة هي قراءة مشاكل الحاوية أولاً ومعاملة النتيجة النظيفة على أنها بيان حول الحاوية فقط، وليس أبداً حول البيانات الوصفية لـ PDF/A. قم بتشغيل التحقق المدمج، واجمع قائمة المشاكل، وتصرف بناءً عليها قبل الوصول إلى أداة خارجية
var
Issues: WideString;
begin
if PDF.ValidateFacturXInvoice = 0 then
begin
Issues := PDF.GetFacturXValidationIssues('|');
// container-level identifiers, for example:
// MissingCatalogAF, NotPDFA3, MissingEmbeddedFilesNameTree,
// ConformanceGuidelineMismatch, InvalidAFRelationship
WriteLn('Container issues: ', Issues);
end
else
WriteLn('Container OK; verify XMP extension schema with a PDF/A checker.');
end;
عندما يُرجع هذا الاستدعاء اسم مشكلة، يكون الخطأ في الحاوية وتخبرك الرسالة بأي جزء. عندما يعود نظيفاً ولا يزال veraPDF يرفض الملف، يكون الخطأ في الغالب هو مخطط امتداد XMP، ويتمثل الإصلاح في السماح لـ AddFacturXAssociatedFileFromString بكتابة البيانات الوصفية بدلاً من إنشاء كتلة الخصائص بنفسك. إن إبقاء السؤالين منفصلين في ذهنك هو ما يحول الرفض المحير إلى تشخيص من سطر واحد: تظهر مشاكل الحاوية من خلال قائمة المشاكل، وتظهر مشاكل إعلان المخطط فقط من خلال أداة التحقق من PDF/A، والخلط بين الاثنين هو ما يسمح للخطأ بالاختباء
تتم تغطية صورة توافق PDF/A و PDF/UA الأوسع، بما في ذلك كيفية تشغيل تمريرة فحص ما قبل الاختبار (preflight) قبل أن يغادر الملف البناء الخاص بك، في الجولة التفصيلية حول فحص ما قبل الاختبار لـ PDF/A و PDF/UA. إذا كان يجب أن تكون فاتورتك قابلة للوصول أيضاً، فإن شجرة البنية التي يعتمد عليها PDF/A-3a و PDF ذو العلامات (tagged PDF) هي موضوع مقال إمكانية الوصول لـ PDF ذي العلامات. يتم شحن معالجة مخطط الامتداد الموضحة هنا كجزء من PDFlibPas Delphi PDF Library جنباً إلى جنب مع دعم الملف الشخصي لـ Factur-X و ZUGFeRD و XRechnung الموثق عبر هذه المدونة