Tehnicki clanak

Validacija e-faktura: veraPDF i Mustang u Delphi-ju

Factur-X ili ZUGFeRD faktura su dva dokumenta pod jednim imenom datoteke. Spoljni dokument je PDF/A-3 kontejner koji arhivski citac mora prihvatiti narednih deset godina. Unutrasnji dokument je XML faktura koju sistem racunovodstva kupca mora parsirati prema EN 16931. Greska koja salje pokvarene fakture u produkciju je verovanje da ispravno resavanje prvog automatski resava i drugi. Nije tako. Datoteka moze biti besprekoran PDF/A-3 i istovremeno sadrzati XML koji nijedan poreski organ nece prihvatiti, i moze sadrzati udzbenicki EN 16931 XML unutar kontejnera koji ne prolazi arhivsku validaciju. Dva sloja validiraju dva razlicita alata koji nista ne znaju jedan o drugom, i pravi sistem mora zadovoljiti oba

Dva validatora, dva razlicita pitanja

veraPDF je referentna implementacija za PDF/A. Usmerite ga na fakturu i on odgovara na jedno pitanje: da li je ovo konformna PDF/A-3 datoteka. Proverava ono sto ISO 19005-3 zahteva. Da li je svaki font ugraden. Da li postoji OutputIntent. Da li XMP metapodaci deklarisu ispravan deo i nivo konformnosti. Za e-fakturu proverava i pridrzene datoteke koje PDF/A-3 zahteva, jer XML putuje kao ugradena datoteka sa /AFRelationship i unosom u /AF nizu kataloga dokumenta. veraPDF ne govori nista o tome da li se iznos fakture slaze, jer to nije u njegovoj nadleznosti

Mustang je validator otvorenog koda iz projekta Mustangproject. Postavlja ortogonalno pitanje: da li je ugradeni XML vazeca faktura. Pokrace XML prema semi za deklarisani profil, a zatim primenjuje EN 16931 poslovna pravila i skupove pravila specificnih za drzavu koji su na njima zaslonjeni, ukljucujuci XRechnung CIUS. Proverava da li je PDV identifikator prodavca prisutan kada ga ukupni iznosi zahtevaju, da li se iznosi popusta i naknada slazu sa ukupnim iznosom dokumenta, da li URN profila u XML-u odgovara onome sto datoteka tvrdi da jeste. Mustang ne brine da li okruzni PDF ugraduje svoje fontove, jer je to posao veraPDF-a

Nijedan alat nije nadskup drugog. veraPDF propusta strukturno savrsen kontejner oko besmislenog XML-a. Mustang propusta savrsen XML umotan u kontejner sa nedostajucim OutputIntent-om. Svaki hvata tacno onu klasu nedostataka kojoj je drugi slep, sto je ceo razlog zbog kojeg ozbiljan validacijski kadar pokrace oba i tretira datoteku kao podobnu za slanje samo kada se oba slazu

Matrica validacije

Da bi se dokazalo da biblioteka proizvodi datoteke koje prezivljavaju oba prolaza, kadar gradi matricu. Sest profila faktura pokriva raspon koji evropski sistem srece u praksi: Factur-X EN 16931, Factur-X BASIC, Factur-X EXTENDED varijanta za Francusku B2B, XRechnung 3.0, ZUGFeRD 1.0 COMFORT i ZUGFeRD 2.0 BASIC. Svaki profil se generise prema dva PDF/A nivoa konformnosti, 3b i 3u, jer se zahtevi nivoa B i nivoa U razilaze u pogledu Unicode mapiranja i datoteka koja prolazi jedan moze da ne prode drugi. Sest profila puta dva nivoa je dvanaest datoteka, svaka od njih izgradena bez zaglavlja istom putanjom koda koja se isporucuje sa grafickim uzorkom, tako da artefakti koji se testiraju nisu rucno podeseni za test

Generator zapisuje svih dvanaest i skripta svaku salje oba validatora. Na prvom potpunom pokretanju veraPDF je prosao svih dvanaest. Sistem kontejnera bio je ispravan: pridrzene datoteke registrovane, XMP konformnost deklarisana, izlazni intenti na svom mestu. Mustang je prosao osam. Cetiri fakture bile su strukturno vazece PDF/A-3 datoteke koje su nosile XML koji je validator poslovnih pravila odbio, sto je tacno podela koju pristup sa dva alata postoji da otkrije. Da je kadar verovao samo veraPDF-u, te cetiri bi izgledale kao zavrsene

Dva ispravka koja su zatvorila jaz

Cetiri Mustang neuspeha potekla su iz dva razlicita uzroka, i ispravak za svaki je detalj koji vredi znati pre nego sto sami generisete ove profile

Prvi je bio profil Factur-X EXTENDED Francuska B2B. Originalni generator je prosledjivao interni natpis kao nivo konformnosti i interni URN kao smernicu, a Mustang je odbio datoteku greskom nevazece-vrednosti-konformnosti pracenom greskom nepodrzanog-tipa-profila. Razlog je taj sto polje XMP fx:ConformanceLevel nije slobodan tekstualni prostor za vase vlastito imenovanje profila. Factur-X definise tacno pet standardnih vrednosti: MINIMUM, BASIC WL, BASIC, EN 16931 i EXTENDED. Faktura specificna za Francusku B2B je i dalje dokument EXTENDED profila u pogledu XMP metapodataka. Francuski karakter fakture nije izrazen izmisljenjem seste vrednosti konformnosti. Izrazen je kodom drzave, FR, i identifikatorom smernice unutar XML-a, koji mora nositi prefiks urn:cen.eu:en16931:2017#conformant# koji oznacava CIUS konforman sa EN 16931. Prosledjivanje standardne EXTENDED vrednosti sa FR kao kodom drzave i ispravnim URN smernicom ucinilo je datoteku konformnom

U API biblioteke to je poziv na AddFacturXAssociatedFileFromString sa uskladjenim konformnoscu, drzavom i smernicom. Argument nivoa konformnosti nosi standardni token, argument koda drzave nosi FR, a URN smernice zivi u XML bajtovima koje prosledjujete

var
  FileID: Integer;
begin
  PDF.SetPDFAMode(5);            // PDF/A-3b
  PDF.NewDocument;
  // ... draw the human-readable invoice page ...
  // ExtendedXML carries an EN 16931 guideline URN of the form
  //   urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
  FileID := PDF.AddFacturXAssociatedFileFromString(
    ExtendedXML,
    'EXTENDED',          // standard fx:ConformanceLevel, not an internal label
    'factur-x.xml',
    'Factur-X EXTENDED invoice',
    'Alternative',       // /AFRelationship
    '1.0',
    'FR');               // France B2B marked by country code, not by conformance
  if FileID = 0 then
    raise Exception.Create('Factur-X attachment rejected');
  PDF.SaveToFile('02_Factur-X-EXTENDED-FR_PDFA-3b.pdf');
end;

Drugi uzrok bio je profil ZUGFeRD 1.0 COMFORT, i nije imao nikakve veze sa metapodacima. ZUGFeRD 1.0 validira se prema XSD semi :1p0, koja je stroza po pitanju kardinalnosti nego sto to proze summary-ja sugerisu. XSD zahteva da sumarni iznos poravnanja zaglavlja, ram:SpecifiedTradeSettlementMonetarySummation, sadrzi ram:ChargeTotalAmount i ram:AllowanceTotalAmount svaki tacno jednom. Generisani XML je izostavio oboje, pa je Mustang prijavio da elementi moraju se pojaviti tacno jedan put. Ovi elementi nisu opcionalni kad sema kaze da je minOccurs jedan. Emitovanje obaju u redosledu XSD sekvence, odmah iza ram:LineTotalAmount, sa vrednoscu 0.00 kada nema naknada ili popusta, zadovoljilo je semu. Nula je prisutan element; odsutan element je krsenje seme. Sa ova dva ispravka na svom mestu, matrica je presla na dvanaest od dvanaest u Mustangu uz zadrzavanje dvanaest od dvanaest u veraPDF-u

XRechnung polja koja prelaze iz nevazeceg u vazece

XRechnung zasluzuje vlastitu napomenu jer njegov nemacki CIUS dodaje poslovna pravila koja nisu prisutna u baznom skupu EN 16931, i ona ne uspevaju na nacine koji na prvi pogled izgledaju kao da sa dokumentom nema nista lose. Dva od njih ticu se elektronskih adresa. BT-34 je elektronska adresa prodavca a BT-49 je elektronska adresa kupca, ruting krajnje tacke koje portal javnog sektora u Nemackoj koristi za isporuku i potvrdivanje fakture. Bazni EN 16931 model tretira ih kao opcione. XRechnung ne. Izostavite bilo koji i faktura je dobro formirana, vazeca prema semi i odbijena

Trece je pravilo BR-DE-6, koje zahteva da broj telefona kontakta prodavca bude prisutan. To je vrsta polja koje programer izostavi jer se cini kao prezentacija a ne podaci, a njegovo odsustvo proizvodi gresku validacije koja ukazuje na grupu kontakta prodavca a ne na isto sto je ocigledno nedostajalo. Pruzanje BT-34, BT-49 i broja telefona prodavca je ono sto premesta XRechnung datoteku iz nevazece u vazece u Mustangu, i nista od toga ne menja nista sto veraPDF vidi, jer sve troje zivi u XML-u

Povezivanje izlaza biblioteke sa validatorom

Arhitekturna poenta iza kadra generalizuje se na bilo koji poslovni sistem. PDF biblioteka zapisuje konformni kontejner i ugradjuje XML. Ona ne treba, i ne bi trebala, pokusavati biti organ poslovnih pravila EN 16931. ValidateFacturXInvoice u biblioteci proverava konzistentnost kontejnera, da se katalog /AF niz, stablo naziva ugradenih datoteka, XMP DocumentFileName, profil, smernica i /AFRelationship slazu, ali ne validira poreske kodove niti uskladjuje iznose. Ispravna podela rada je da poslovni sistem izvuce XML i preda ga namenskom validatoru faktura, tacno onako kako kadar predaje Mustangu

Citanje datoteke nazad govori vam sta je zapravo zapisano. DetectFacturXInvoice javlja da li je faktura prepoznata, a GetFacturXInvoiceInfo cita metapodatke po oznaci: oznaka 1 je naziv ugradene datoteke, oznaka 2 XMP DocumentFileName, oznaka 5 nivo konformnosti, oznaka 6 identifikator smernice, i oznaka 7 /AFRelationship. Potvrda da je nivo konformnosti koji citate nazad standardni token a ne interni natpis je najjeftiniji nacin da uhvatite EXTENDED gresku pre nego sto datoteka napusti vas build

function ExtractAndInspect(const PdfPath: string): AnsiString;
var
  Profile, Guideline: WideString;
begin
  Result := '';
  PDF.LoadFromFile(PdfPath);
  if PDF.DetectFacturXInvoice = 1 then
  begin
    Profile   := PDF.GetFacturXInvoiceInfo(5);  // fx:ConformanceLevel
    Guideline := PDF.GetFacturXInvoiceInfo(6);  // XML guideline ID
    Writeln('Profile:   ', Profile);
    Writeln('Guideline: ', Guideline);
    // Hand the raw XML to a dedicated EN 16931 / Mustang validator.
    Result := PDF.ExtractFacturXXMLToString;
  end;
end;

ExtractFacturXXMLToString vraca sirove XML bajtove kao AnsiString, spreman za zapisivanje u datoteku ili prosledjivanje validatoru. U test kadru ta ciljna tacka je Mustang, pozvan putem svog komandno-linijskog jar-a, sa veraPDF-om koji se pokrace u istom prolazu nad istom datotekom. Sistem je mali: konzolni generator, EInvoiceValidation.dpr, zapisuje dvanaest datoteka koristeci zajednicki model fakture iz uzorka, i skripta, run-validation.ps1, pokrace oba validatora nad izlaznim direktorijumom i ispisuje tabelu prolaza i padova. Isti dvostepeni oblik, generisanje sa bibliotekom i verifikacija sa spoljnim validatorima, je ono sto bi posao kontinuirane integracije trebao pokretati pri svakoj promeni generisanja fakture, jer jedini nacin da znate da datoteka zadovoljava oba sloja je pitati oba alata

Ako vas sistem mora i sertifikovati kontejner pre potpisivanja, pregled pretprolaza ovog rada je obradjeno u nasem pregledu PDF/A i PDF/UA predleta u Delphi-ju, a siri tok sertifikovanja-pa-potpisivanja je opisan u radnoj stanici za uskladjenost i potpisivanje. Oboje se grade na istoj putanji generisanja koja se isporucuje kao deo Delphi PDF Library za Delphi i C++Builder, zajedno sa PDF/A, pridrzenim datotekama i API-jevima metapodataka koji se koriste ovde