Knihovna HotPDF generuje, detekuje a validuje elektronické faktury ZUGFeRD a Factur-X z Delphi a C++Builderu. Metoda AddFacturXAssociatedFile vkládá fakturační XML podle EN 16931 do kontejneru PDF/A-3, DetectFacturXInvoice rozpoznává příchozí hybridní fakturu a HPDFValidateEInvoice spouští oficiální obchodní pravidla Schematron EN 16931 proti vloženému XML. Tento článek vás provede všemi třemi kroky a upřímně popíše, kde možnosti validačního jádra končí
Problém se objevuje v okamžiku, kdy formulář přestane být plochý. Přiznání k DPH nebo celní prohlášení vytvořené jako dynamický formulář XFA nemá dvanáct polí s názvy Total_Price_1 až Total_Price_12; má jeden dílčí formulář (subform) Detail deklarovaný jednou v šabloně DOM a vytvořený v tolika instancích, kolik data vyžadují. Hodnoty žijí ve druhém stromu, Data DOM, uvnitř balíčku datasets, kde každá položka řádku představuje opakovaný element <Detail> pod <Receipt>. Ploché názvy polí nedokážou adresovat „cenu na třetím řádku“ nebo „každý řádek nad 200“; to je přesně úkol, který kapitola Scripting Object Model specifikace Adobe XFA 3.3 přiděluje výrazům SOM, a je to syntaxe, kterou hovoří rozhraní API XFA pro hodnoty polí losLab PDF Library
Co dělá z PDF platnou fakturu Factur-X?
Platná faktura Factur-X je soubor PDF/A-3 (ISO 19005-3), který obsahuje právě jedno strukturované fakturační XML jako přidružený soubor, odkazuje na něj z katalogu dokumentu a deklaruje jej v rozšiřujících metadatech XMP. Tři vrstvy musí být v souladu. Za prvé, kontejner must conform to PDF/A-3, the archival profile that — unlike PDF/A-1 and PDF/A-2 — permits embedded files of any type. Second, the invoice XML, named factur-x.xml for standard profiles or xrechnung.xml for the German XRechnung variant, must be registered in the catalog /AF array and the /Names /EmbeddedFiles tree, with an AFRelationship entry that states what the attachment is: Alternative means the XML is an equivalent representation of the visible invoice, which is the semantics most profiles require. Third, the Factur-X XMP extension schema must name the embedded file, its conformance level, and the document type, so a receiving system can classify the invoice without parsing the XML at all
Samotný obsah XML se řídí sémantickým modelem EN 16931, evropskou normou, která definuje jádro faktury: kupujícího, prodávajícího, položky řádků, rozpis daní, splatnou částku, z nichž každý prvek má své číslo obchodního termínu (např. BT-1 pro číslo faktury, BT-5 pro měnu atd.). Validace podle EN 16931 proto probíhá na dvou odlišných vrstvách. Validace schématu XML ověřuje, zda je dokument správně strukturovaným CII s odpovídajícími názvy prvků. Obchodní pravidla Schematron kontrolují koherenci obsahu — například zda platí pravidlo BR-CO-15 a celková částka faktury skutečně odpovídá součtu čistých částek řádků plus DPH, nebo zda jsou přítomny povinné údaje pro deklarovaný profil. Soubor může projít validací schématu a přesto být neplatnou fakturou, a proto existuje vrstva obchodních pravidel
Proč ZUGFeRD 2.5 nepotřebuje nový kontejner
ZUGFeRD 2.5 nemění nic na úrovni PDF kontejneru: doporučené URN, XMP schéma i token verze jsou identické se ZUGFeRD 2.3 / Factur-X 1.0. To překvapuje většinu vývojářů, proto stojí za to citovat zdroj. Specifikace Factur-X 1.09 uvádí, že číslo verze v URI rozšiřujícího schématu PDF/A nesouvisí s číslem verze specifikace dat XML a že verzování instancí faktur Factur-X zůstává 1.0 — v XMP poli fx:Version i v BT-24 v souboru factur-x.xml. Oficiální vzorová data ZUGFeRD 2.5 to potvrzují: každý vzorek obsahuje factur-x.xml pod doporučeným URN urn:factur-x.eu:1p0 s verzí fx:Version rovnu 1.0. To, co verze 2.5 skutečně přináší, žije uvnitř datového modelu XML — nové elementy, jako jsou podřízené řádky faktury a identifikátory šarží — což je obchodní vrstva, kterou generuje vaše aplikace, a nikoli vrstva kontejneru, kterou spravuje knihovna PDF
HotPDF toto zjištění implementuje přímo. Metoda AddFacturXAssociatedFile přijímá argument Version a normalizuje jej pomocí HPDFFacturXNormalizeVersion před zápisem XMP, so a caller passing the 2p5 alias still emits the spec-compliant token instead of inventing a 2p5 XMP version that no validator would accept. The detection helpers treat 2p5 as equivalent when reading, so round-trips stay symmetric. If a library or tool tells you it writes a special ZUGFeRD 2.5 container, the specification itself says there is no such thing
Vkládání fakturačního XML z Delphi
Metoda THotPDF.AddFacturXAssociatedFile promění běžný proces generování PDF/A-3 ve fakturu Factur-X jediným voláním: vloží bajty XML jako přidružený soubor, zaregistruje factur-x.xml v poli katalogu /AF a ve stromu /Names /EmbeddedFiles a vygeneruje odpovídající rozšiřující metadata XMP Factur-X. Lidsky čitelnou stránku faktury vykreslíte běžným rozhraním API plátna HotPDF; práce s kontejnerem představuje jediný řádek mezi BeginDoc and EndDoc
var
Pdf: THotPDF;
InvoiceXML, UBLXML: TBytes;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'invoice-2026-0042.pdf';
Pdf.PDFACompliance := '3B'; // PDF/A-3b container
Pdf.BeginDoc;
// embed the EN 16931 CII invoice XML as factur-x.xml
InvoiceXML := BuildInvoiceXML; // produced by your business layer
Pdf.AddFacturXAssociatedFile(InvoiceXML, 'EN 16931');
// optional: attach a UBL view as a supplementary representation
UBLXML := BuildUBLXML;
Pdf.AddUBLSupplementaryFile(UBLXML); // factur-xubl.xml, Alternative
// ... draw the visible invoice page here ...
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Výchozí nastavení odpovídají specifikaci: název souboru factur-x.xml, vztah Alternative, verze 1.0. Metoda AddUBLSupplementaryFile implementuje článek 6.4 specifikace Factur-X 1.09, který umožňuje, aby byla reprezentace UBL stejné faktury připojena jako druhá příloha s názvem factur-xubl.xml, s typem MIME application/xml a vztahem Alternative. Na pořadí zde záleží a HotPDF vynucuje omezení plynoucí ze specifikace: soubor UBL je doplňkovým zobrazením, nikoli primární fakturou, takže musí být přidán až poté, co AddFacturXAssociatedFile zaregistrovala hlavní CII fakturu. Mějte na paměti, že vykreslená stránka a vložené XML musí uvádět stejnou fakturu — PDF zobrazující jednu částku a kódující jinou je přesně chybovým stavem, kterému má hybridní fakturace zabránit. The PDF/A-3 side of this workflow, OutputIntent and font embedding included, is covered in more depth in the companion article on PDF/A, PDF/X, and PDF/UA validation in Delphi
Jak v příchozím PDF rozpoznat fakturu Factur-X?
Metoda THotPDF.DetectFacturXInvoice řeší přijímací stranu nařízení: načte jakékoli PDF a jediným voláním zjistí, zda se jedná o hybridní fakturu, jaký profil deklaruje a jaké přílohy nese. Funkce vrací záznam THPDFFacturXInvoiceInfo s názvem vloženého souboru XML, názvem a typem dokumentu deklarovaným v XMP, tokenem verze, úrovní shody, doporučeným URN a hodnotou AFRelationship. Dvě další pole hlásí doplňková zobrazení: UBLFileName se naplní, pokud je přítomna příloha factur-xubl.xml, a EDIFACTFileName při přítomnosti zobrazení EDIFACT — ani jedno z nich neovlivňuje výsledek detekce, protože doplňková reprezentace nemůže existovat bez primární CII faktury
var
Reader: THotPDF;
Info: THPDFFacturXInvoiceInfo;
begin
Reader := THotPDF.Create(nil);
try
if Reader.LoadFromFile('incoming-invoice.pdf') <= 0 then
raise Exception.Create('No pages loaded.');
if Reader.DetectFacturXInvoice(Info) then
begin
Writeln('Invoice XML: ', string(Info.FileName));
Writeln('Conformance: ', string(Info.ConformanceLevel));
Writeln('Guideline URN: ', string(Info.GuidelineID));
Writeln('Relationship: ', string(Info.AFRelationship));
if Info.UBLFileName <> '' then
Writeln('UBL view: ', string(Info.UBLFileName));
end
else
Writeln('Not a Factur-X / ZUGFeRD hybrid invoice.');
finally
Reader.Free;
end;
end;
Detekce čte stejné signály, jaké čte vyhovující validátor — rozšiřující schéma XMP a registr přidružených souborů — namísto pouhého hádání podle názvů souborů. Stejný načtený objekt dokumentu také zpřístupňuje metadata XMP a Info slovníku pro kontrolu nebo opravu, což je postup popsaný v článku o úpravě metadat v načtených dokumentech PDF
Obchodní pravidla nebo schéma: co znamená validace podle EN 16931?
Samostatná funkce HPDFValidateEInvoice v jednotce HPDFEInvoiceValidator spouští obě validační vrstvy v pořadí: nejprve kontrolu struktury kontejneru pomocí ValidateFacturXInvoice a poté obchodní pravidla Schematron EN 16931 proti extrahovanému fakturačnímu XML. HotPDF dodává pět oficiálních souborů pravidel Factur-X 1.09 — MINIMUM, BASIC WL, BASIC, EN 16931 a EXTENDED — v adresáři Lib/resources/Schematron/ a funkce HPDFSchematronFileForProfile vybere soubor odpovídající detekované úrovni shody, takže faktura EN 16931 je automaticky kontrolována proti Factur-X_1.09_EN16931.sch. Funkce vrátí hodnotu True pouze tehdy, když je kontejner platný a nebyla porušena žádná obchodní pravidla
uses HPDFEInvoiceValidator;
var
Reader: THotPDF;
Report: THPDFEInvoiceValidationReport;
I: Integer;
begin
Reader := THotPDF.Create(nil);
try
Reader.LoadFromFile('incoming-invoice.pdf');
if HPDFValidateEInvoice(Reader, SchematronDir, Report) then
Writeln('Container and business rules: OK')
else
Writeln('Validation found issues.');
if Report.BusinessRulesEvaluated then
begin
Writeln(Report.BusinessSummary.Evaluated, ' rules evaluated, ',
Report.BusinessSummary.Skipped, ' skipped (XPath 2.0)');
for I := 0 to High(Report.BusinessRules) do
if (not Report.BusinessRules[I].Skipped) and
(Report.BusinessRules[I].Severity = stsError) then
Writeln(string(Report.BusinessRules[I].RuleID), ': ',
string(Report.BusinessRules[I].Message));
end;
finally
Reader.Free;
end;
end;
Každá položka v BusinessRules nese identifikátor pravidla analyzovaný z textu tvrzení (assertion) — BR-45, BR-CO-17 a zbytek pojmenovacího schématu EN 16931 — plus kontextový XPath pravidla, testovaný výraz a závažnost zrcadlící atribut flag systému Schematron. Díky tomu je protokol prakticky využitelný: namísto prostého výsledku úspěch/selhání obdržíte přesný obchodní údaj, který je nekonzistentní, což je přesně to, co váš tým podpory potřebuje, když se zákazník ptá, proč byla faktura odmítnuta. Vývojové týmy, které již generují strukturované zprávy o shodě pro archivační PDF, mohou tyto výsledky začlenit do stejného procesu popsaného v článku o automatizaci předtiskových zpráv (preflight reports) PDF
Kde validátor končí, upřímně
Jádro Schematron je postaveno na technologii MSXML, která vyhodnocuje XPath 1.0. Soubor pravidel EN 16931 deklaruje queryBinding="xslt2" a obsahuje 424 tvrzení, z nichž většina používá pouze funkce XPath 1.0 jako string-length a substring-after — ty se provádějí nativně. Menšina závisí na konstrukcích XPath 2.0, jako jsou přetypování xs:decimal nebo funkce exists(); HotPDF předem prohledá každý testovaný výraz na známé tokeny XPath 2.0 og označí tato pravidla jako Skipped se závažností info, místo aby se pokoušelo o vyhodnocení, které by tiše selhalo. Souhrnný záznam hlásí počty vyhodnocených a přeskočených pravidel samostatně, takže váš log vždy přesně uvádí, jaká část sady pravidel byla vykonána. V prostředí Delphi 7, kde nejsou vazby MSXML k dispozici, jednotka zkompiluje zástupnou proceduru (stub), která hlásí nedostupnost jádra, aniž by narušila výsledek kontroly kontejneru; plnohodnotné jádro vyžaduje Delphi XE2 nebo novější
Druhé omezení je ještě důležitější. Úspěšný výsledek z HPDFValidateEInvoice znamená, že struktura kontejneru vyhovuje a žádné vyhodnocené obchodní pravidlo nebylo porušeno — nejedná se o potvrzení daňové shody. Národní rozšiřující pravidla, specifické požadavky příjemců a právní povinnosti týkající se obsahu faktur stojí nad jádrem EN 16931 a mimo jakoukoli knihovnu. Považujte validátor za bránu, která zabrání odeslání strukturálně chybných faktur z vaší pošty a označí nekonzistentní faktury ve vaší doručené poště. Pokud certifikace vyžaduje plnohodnotný validátor XPath 2.0, zařaďte jej do svého procesu vydávání a otázku právní shody ponechte na svých daňových poradcích. Zde uvedená rozhraní API pro vkládání, detekci a validaci jsou součástí standardního produktu HotPDF Component pro Delphi a C++Builder, s kompletní ukázkou e-fakturace pokrývající všech sedm profilů ZUGFeRD a Factur-X