Tehnički članak

ZUGFeRD i Factur-X elektronski računi u Delphi-ju pomoću HotPDF-a

HotPDF generiše, detektuje i validira ZUGFeRD i Factur-X elektronske račune iz Delphi-ja i C++Builder-a. Metoda AddFacturXAssociatedFile ugrađuje XML račun prema standardu EN 16931 u PDF/A-3 kontejner, DetectFacturXInvoice prepoznaje dolazni hibridni račun, a HPDFValidateEInvoice pokreće zvanična EN 16931 Schematron poslovna pravila nad ugrađenim XML-om. Ovaj članak vodi kroz sva tri koraka i iskreno govori o tome gde se mehanizam validacije zaustavlja

Pritisak iza ovog skupa funkcija je regulatorni, a ne tehnički. Nemačka i Francuska postepeno uvode obavezno strukturirano elektronsko fakturisanje za domaće B2B transakcije, i oba mandata konvergiraju ka istom hibridnom modelu: PDF račun koji vaš ERP već proizvodi mora da nosi mašinski čitljiv XML blizanac u sebi. Delphi računovodstvena ili ERP aplikacija koja danas izdaje obične PDF račune ima strogi rok da počne sa izdavanjem Factur-X ili ZUGFeRD računa, a razlika između ova dva naziva je manja nego što marketing sugeriše — Factur-X i ZUGFeRD su isti francusko-nemački standard objavljen pod dve oznake

Šta čini PDF važećim Factur-X računom?

Važeći Factur-X račun je PDF/A-3 fajl (ISO 19005-3) koji ugrađuje tačno jedan strukturirani XML račun kao pridruženi fajl, povezuje ga iz kataloga dokumenta i deklariše u metapodacima XMP ekstenzije. Tri sloja moraju da se usaglase. Prvo, kontejner mora biti u skladu sa PDF/A-3, arhivskim profilom koji — za razliku od PDF/A-1 i PDF/A-2 — dozvoljava ugrađene fajlove bilo kog tipa. Drugo, XML račun, nazvan factur-x.xml za standardne profile ili xrechnung.xml za nemačku XRechnung varijantu, mora biti registrovan u nizu kataloga /AF i stablu /Names /EmbeddedFiles, sa unosom AFRelationship koji navodi šta je prilog: Alternative znači da je XML ekvivalentan prikaz vidljivog računa, što je semantika koju većina profila zahteva. Treće, šema Factur-X XMP ekstenzije mora imenovati ugrađeni fajl, njegov nivo usklađenosti i tip dokumenta, tako da sistem primalac može da klasifikuje račun bez potrebe za analiziranjem samog XML-a

Sam XML sadržaj prati semantički model EN 16931, evropsku normu koja definiše suštinu računa: kupca, prodavca, stavke, raščlanjivanje poreza, iznos za plaćanje, svaki sa brojem poslovnog termina (BT-1 za broj računa, BT-5 za valutu, itd.). Validacija EN 16931 se stoga dešava na dva različita sloja. Validacija XML šeme proverava da li je dokument ispravno formiran CII sa ispravnim nazivima elemenata. Schematron poslovna pravila proveravaju da li je sadržaj koherentan — da li važi pravilo BR-CO-15 i da li je ukupna vrednost računa zaista jednaka zbiru neto iznosa stavki plus PDV, i da li su prisutni obavezni termini za deklarisani profil. Fajl može proći validaciju šeme i dalje biti nevažeći račun, zbog čega i postoji sloj poslovnih pravila

Zašto ZUGFeRD 2.5 ne zahteva novi kontejner

ZUGFeRD 2.5 ne menja ništa na nivou PDF kontejnera: URN-ovi smernica, XMP šema i token verzije su identični onima u ZUGFeRD 2.3 / Factur-X 1.0. Ovo iznenađuje većinu implementatora, pa je vredno citirati izvor. Specifikacija Factur-X 1.09 navodi da broj verzije u URI-ju PDF/A šeme ekstenzije nije povezan sa brojem verzije XML specifikacije podataka, i da verzija instanci Factur-X računa ostaje 1.0 — kako u XMP-u fx:Version, tako i u BT-24 polju u factur-x.xml. Zvanični ZUGFeRD 2.5 skup uzoraka to potvrđuje: svaki uzorak ugrađuje factur-x.xml pod URN-om smernice urn:factur-x.eu:1p0 sa fx:Version vrednošću 1.0. Ono što verzija 2.5 zapravo dodaje živi unutar XML modela podataka — novi elementi kao što su podredovi računa i identifikatori serije — što je poslovni sloj koji generiše vaša aplikacija, a ne sloj kontejnera kojim upravlja PDF biblioteka

HotPDF direktno kodira ovaj zaključak. AddFacturXAssociatedFile prihvata argument Version i normalizuje ga kroz HPDFFacturXNormalizeVersion pre pisanja XMP-a, tako da pozivalac koji prosledi alijas 2p5 i dalje emituje token koji je u skladu sa specifikacijom, umesto da izmišlja 2p5 XMP verziju koju nijedan validator ne bi prihvatio. Pomoćne funkcije za detekciju tretiraju 2p5 kao ekvivalentnu prilikom čitanja, pa procesi u oba smera ostaju simetrični. Ako vam neka biblioteka ili alat kaže da piše poseban ZUGFeRD 2.5 kontejner, sama specifikacija kaže da tako nešto ne postoji

Ugradnja XML-a računa iz Delphi-ja

Metoda THotPDF.AddFacturXAssociatedFile pretvara obično generisanje PDF/A-3 fajla u Factur-X račun jednim pozivom: ona ugrađuje bajtove XML-a kao pridruženi fajl, registruje factur-x.xml u nizu kataloga /AF i stablu /Names /EmbeddedFiles, i emituje odgovarajuće metapodatke Factur-X XMP ekstenzije. Vi crtate vizuelnu stranu računa čitljivu ljudima pomoću uobičajenog HotPDF canvas API-ja; rad na kontejneru je jedna linija koda između BeginDoc i 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;

Podrazumevane vrednosti prate specifikaciju: naziv fajla factur-x.xml, odnos Alternative, verzija 1.0. Metoda AddUBLSupplementaryFile implementira odeljak 6.4 specifikacije Factur-X 1.09, koji dozvoljava da UBL reprezentacija istog računa ide kao drugi prilog pod nazivom factur-xubl.xml sa MIME tipom application/xml i odnosom Alternative. Redosled je ovde važan, i HotPDF sprovodi ograničenje koje specifikacija podrazumeva: UBL fajl je dopunski prikaz, nikada primarni račun, tako da se mora dodati nakon što AddFacturXAssociatedFile registruje CII master. Imajte na umu da iscrtana stranica i ugrađeni XML moraju navesti isti račun — PDF koji prikazuje jednu ukupnu vrednost a kodira drugu je upravo onaj slučaj otkazivanja koji hibridno fakturisanje treba da spreči. PDF/A-3 strana ovog toka rada, uključujući OutputIntent i ugradnju fontova, detaljnije je pokrivena u pratećem članku o PDF/A, PDF/X i PDF/UA validaciji u Delphi-ju

Kako detektovati Factur-X račun u dolaznom PDF-u?

Metoda THotPDF.DetectFacturXInvoice odgovara na potrebe prijemne strane: učitajte bilo koji PDF i u jednom pozivu saznajte da li je reč o hibridnom računu, koji profil deklariše i koje priloge nosi. Funkcija vraća zapis THPDFFacturXInvoiceInfo sa nazivom ugrađenog XML fajla, nazivom i tipom dokumenta deklarisanim u XMP-u, tokenom verzije, nivoom usklađenosti, URN-om smernice i vrednošću AFRelationship. Još dva polja prijavljuju dopunske prikaze: UBLFileName se popunjava kada je prisutan prilog factur-xubl.xml, a EDIFACTFileName kada ide i EDIFACT prikaz — nijedan od njih ne utiče na ishod detekcije, jer dopunska reprezentacija ne može postojati bez primarnog CII računa

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;

Detekcija čita iste signale koje čita i usklađeni validator — šemu XMP ekstenzije i registar pridruženih fajlova — umesto da samo nagađa na osnovu naziva fajlova. Isti objekat učitanog dokumenta takođe izlaže metapodatke XMP-a i Info-rečnika radi inspekcije ili korekcije, što je proces opisan u članku o uređivanju metapodataka u učitanim PDF dokumentima

Poslovna pravila ili šema: šta znači validacija EN 16931?

Funkcija HPDFValidateEInvoice, samostalna funkcija u unitu HPDFEInvoiceValidator, pokreće oba sloja validacije u sekvenci: prvo proveru strukture kontejnera preko ValidateFacturXInvoice, a zatim poslovna pravila EN 16931 Schematron poslovna pravila nad izdvojenim XML-om računa. HotPDF isporučuje pet zvaničnih Factur-X 1.09 fajlova sa pravilima — MINIMUM, BASIC WL, BASIC, EN 16931 i EXTENDED — pod putanjom Lib/resources/Schematron/, a HPDFSchematronFileForProfile bira fajl koji odgovara detektovanom nivou usklađenosti, tako da se račun EN 16931 automatski proverava u odnosu na Factur-X_1.09_EN16931.sch. Funkcija vraća True samo kada je kontejner važeći i nijedno poslovno pravilo nije prekršeno

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;

Svaki unos u listi BusinessRules nosi identifikator pravila izdvojen iz teksta tvrdnje — BR-45, BR-CO-17 i ostatak EN 16931 šeme imenovanja — plus XPath kontekst pravila, testni izraz i ozbiljnost (severity) koja odražava atribut oznake Schematrona. To čini izveštaj primenjivim u praksi: umesto čiste ocene prolaz/pad, dobijate tačan poslovni termin koji je nedosledan, što je upravo ono što je potrebno vašem timu podrške kada kupac pita zašto je račun odbijen. Timovi koji već generišu strukturirane izveštaje o usklađenosti za arhivske PDF-ove mogu da ugrade ove rezultate u isti tok rada koji je opisan u članku o automatizaciji PDF preflight izveštaja

Gde se validator zaustavlja, iskreno

Schematron mehanizam je izgrađen na MSXML-u, koji evaluira XPath 1.0. EN 16931 fajl sa pravilima deklariše queryBinding="xslt2" i nosi 424 tvrdnje, od kojih većina koristi samo XPath 1.0 funkcije kao što su string-length i substring-after — one rade izvorno. Manji broj se oslanja na XPath 2.0 konstrukte kao što su xs:decimal kastovanja ili exists(); HotPDF unapred skenira svaki testni izraz tražeći poznate XPath 2.0 tokene i označava ta pravila kao preskočena (Skipped) sa ozbiljnošću info, umesto da pokušava evaluaciju koja bi tiho otkazala. Zbirni zapis izveštava o broju evaluiranih i preskočenih pravila odvojeno, tako da vaš log uvek tačno navodi koliki deo skupa pravila je proveren. Na Delphi 7 sistemu, gde MSXML povezivanja nisu dostupna, unit kompajlira stub koji prijavljuje da mehanizam nije dostupan bez narušavanja presude o samom kontejneru; kompletan mehanizam zahteva Delphi XE2 ili noviji

Drugo ograničenje je još važnije. Zeleni rezultat funkcije HPDFValidateEInvoice znači da je struktura kontejnera usklađena i da nijedno evaluirano poslovno pravilo nije prekršeno — to nije potvrda poreske usklađenosti. Nacionalna pravila za proširenje, specifični zahtevi primalaca i zakonske obaveze u vezi sa sadržajem računa nalaze se iznad jezgra EN 16931 i van bilo koje biblioteke. Tretirajte validator kao kapiju koja sprečava da strukturno neispravni računi odu iz vašeg outbox-a i označava nedosledne račune u vašem inbox-u. Pokrenite puni XPath 2.0 validator u svom procesu objavljivanja kada sertifikacija to zahteva, i prepustite poreskim savetnicima brigu o usklađenosti sa propisima. API-ji za ugradnju, detekciju i validaciju prikazani ovde su deo standardne HotPDF komponente za Delphi i C++Builder, uz kompletan primer elektronskog računa koji pokriva svih sedam ZUGFeRD i Factur-X profila