Tehnični članek

Validacija e-računov: veraPDF in Mustang v Delphiju

Račun Factur-X ali ZUGFeRD sta dva dokumenta z enim imenom datoteke. Zunanji dokument je vsebnik PDF/A-3, ki ga mora arhivski bralnik sprejeti za naslednjih deset let. Notranji dokument je XML-račun, ki ga mora računovodski sistem kupca razčleniti v skladu z EN 16931. Napaka, ki v produkcijo pošlje pokvarjene račune, je vera, da pravilna izvedba prve plasti samodejno zagotovi pravilnost druge. To ne drži. Datoteka je lahko brezhibna PDF/A-3, a hkrati vsebuje XML, ki ga noben davčni organ ne bo sprejel; ali pa vsebuje učbeniški XML po EN 16931, zavit v vsebnik, ki ne prestane arhivske validacije. Obe plasti preverjata dve različni orodji, ki se med seboj ne poznata, in resnični cevovod mora zadostiti obema

Dva validatorja, dve različni vprašanji

veraPDF je referenčna implementacija za PDF/A. Usmerite ga na račun in odgovoril bo na eno vprašanje: ali je to skladna datoteka PDF/A-3. Preverja, kar zanima ISO 19005-3: ali so vse pisave vgrajene, ali je prisoten OutputIntent, ali XMP-metapodatki razglašajo pravi del in raven skladnosti. Za e-račun preverja tudi napeljavo za pridružene datoteke, ki jo zahteva PDF/A-3, ker XML potuje kot vgrajena datoteka z /AFRelationship in vnosom v polje /AF kataloga dokumenta. veraPDF ne pove ničesar o tem, ali se skupni znesek računa ujema, ker to ni v njegovi pristojnosti

Mustang je odprtokodni validator iz projekta Mustangproject. Postavlja nasprotno vprašanje: ali je vgrajeni XML veljaven račun. Izvaja XML glede na shemo za razglašeni profil in nato uveljavlja poslovna pravila EN 16931 ter specifična pravila za posamezne države, dodana na vrh - med njimi CIUS za XRechnung. Preverja, ali je prisoten DDV-identifikator prodajalca, ko to zahtevajo skupni zneski, ali se zneski doplačil in popustov ujemajo s skupnim zneskom dokumenta in ali se URN profila v XML ujema s tem, za kar se datoteka razglaša. Mustangu ni mar, ali okoliški PDF vgrajuje pisave, ker je to naloga veraPDF

Nobeno orodje ni nadnabor drugega. veraPDF sprejme strukturno popoln vsebnik z nesmiselnim XML. Mustang sprejme popoln XML, zavit v vsebnik z manjkajočim OutputIntent. Vsako ujame natanko tisto vrsto napake, ki je za drugo nevidna - to je ves razlog, da resen validacijski sistem zažene oba in datoteko šteje za primerno za pošiljanje šele, ko se oba strinjata

Validacijska matrika

Da bi dokazali, da knjižnica proizvaja datoteke, ki prestanejo oba prehoda, matrika zajema šest profilov računov, ki pokrivajo obseg, s katerim se sooča evropski cevovod: Factur-X EN 16931, Factur-X BASIC, različica Factur-X EXTENDED Francija B2B, XRechnung 3.0, ZUGFeRD 1.0 COMFORT in ZUGFeRD 2.0 BASIC. Vsak profil se generira glede na dve ravni podzahtevnosti PDF/A - 3b in 3u - ker se zahteve za raven B in raven U razlikujejo glede na preslikavo Unicode, datoteka, ki prestane eno, pa lahko ne prestane druge. Šest profilov krat dve ravni je dvanajst datotek; vsaka je bila ustvarjena brez glave po isti kodni poti, ki jo vzorec GUI prinaša, tako da artefakti pod testom niso ročno prilagojeni za preskus

Generator zapiše vseh dvanajst datotek, skript pa vsako poda obema validatorjema. V prvem polnem zagonu je veraPDF prestal vseh dvanajst. Napeljava vsebnika je bila pravilna v celotnem obsegu: pridružene datoteke registrirane, XMP-skladnost razglašena, izhodni nameni prisotni. Mustang je prestal osem. Štiri datoteke so bile strukturno veljavne PDF/A-3, ki so vsebovale XML, ki ga je validator poslovnih pravil zavrnil - to je natanko tista razdelitev, ki jo pristop z dvema orodjema razkriva. Če bi se matrika zanesla samo na veraPDF, bi se tisti štirje zdeli dokončani

Dve popravili, ki sta zaprli vrzel

Štiri napake Mustanga so izhajale iz dveh različnih vzrokov, in popravilo za vsakega je podrobnost, ki jo je vredno poznati, preden sami generirate te profile

Prva je bil profil Factur-X EXTENDED Francija B2B. Izvirni generator je kot raven skladnosti podal interno oznako in kot smernico interno URN, Mustang pa je datoteko zavrnil z napako neveljavne vrednosti skladnosti, ki ji je sledila napaka nepodprtega tipa profila. Razlog je, da polje XMP fx:ConformanceLevel ni prosto besedilno polje za vaše lastno poimenovanje profila. Factur-X definira natanko pet standardnih vrednosti: MINIMUM, BASIC WL, BASIC, EN 16931 in EXTENDED. Račun, specifičen za Francijo B2B, je z vidika XMP-metapodatkov še vedno dokument profila EXTENDED. Francoski značaj računa ni izražen z izmišljanjem šeste vrednosti skladnosti. Izražen je z oznako države, FR, in z identifikatorjem smernice znotraj XML, ki mora nositi predpono urn:cen.eu:en16931:2017#conformant#, ki označuje CIUS, skladen z EN 16931. Posredovanje standardne vrednosti EXTENDED z FR kot oznako države in pravilnim URN smernice je datoteko naredilo skladno

V API knjižnice je to klic AddFacturXAssociatedFileFromString z usklajeno skladnostjo, državo in smernico. Argument ravni skladnosti nosi standardni žeton, argument oznake države nosi FR, URN smernice pa živi v bajtih XML, ki jih posredujete

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 vzrok je bil profil ZUGFeRD 1.0 COMFORT in ni imel nobene zveze z metapodatki. ZUGFeRD 1.0 se validira glede na XSD :1p0, ki je glede kardinalnosti strožji, kot povzetki v prozi nakazujejo. XSD zahteva, da povzetek poravnave glave, ram:SpecifiedTradeSettlementMonetarySummation, vsebuje ram:ChargeTotalAmount in ram:AllowanceTotalAmount vsak natanko enkrat. Generirani XML je oba izpustil, zato je Mustang poročal, da morata elementa nastopiti natanko enkrat. Ti nista izbirni, ko shema določa, da je minOccurs ena. Oddajanje obeh v zaporedju XSD, takoj za ram:LineTotalAmount, z vrednostjo 0.00, kadar ni doplačil ali popustov, je zadostilo shemi. Nič je prisoten element; odsoten element je kršitev sheme. S tema dvema popravkoma je matrika dosegla dvanajst od dvanajstih pri Mustangu in hkrati ostala pri dvanajstih od dvanajstih pri veraPDF

Polja XRechnung, ki obrnejo neveljavno v veljavno

XRechnung si zasluži svojo opombo, ker nemški CIUS dodaja poslovna pravila, ki niso prisotna v osnovnem naboru EN 16931, in ta pravila kažejo napake na načine, ki na prvi pogled ne razkrijejo ničesar narobe z dokumentom. Dve od njih zadevata elektronske naslove. BT-34 je elektronski naslov prodajalca, BT-49 pa elektronski naslov kupca - to sta usmerjevalni končni točki, ki ju nemško javno-sektorsko spletišče uporablja za dostavo in potrditev računa. Osnovni model EN 16931 ju obravnava kot izbirni. XRechnung ne. Izpustite katerega koli in račun je oblikovno pravilen, shematsko veljaven - in zavrnjen

Tretje je pravilo BR-DE-6, ki zahteva prisotnost telefonske številke stika prodajalca. To je vrsta polja, ki ga razvijalec opusti, ker se zdi bolj prikazno kot podatkovno, in njegova odsotnost povzroči napako validacije, ki kaže na skupino stika prodajalca in ne na kar koli očitno manjkajočega. Posredovanje BT-34, BT-49 in telefonske številke prodajalca je tisto, kar prestavi datoteko XRechnung iz neveljavne v veljavno po Mustangu, in nič od tega ne spremeni česar koli, kar veraPDF vidi, ker vse tri vrednosti živijo v XML

Povezava izhoda knjižnice z validatorjem

Arhitekturna ugotovitev za matrico se posploši na kateri koli poslovni sistem. Knjižnica PDF zapiše skladen vsebnik in vgradi XML. Ne poskuša biti - in ne bi smela biti - avtoriteta za poslovna pravila EN 16931. ValidateFacturXInvoice v knjižnici preverja doslednost vsebnika - da se polje /AF kataloga, drevo imen vgrajenih datotek, XMP DocumentFileName, profil, smernica in /AFRelationship vsi ujemajo - ne pa validira davčnih kod ali usklajuje zneskov. Pravilna delitev dela je, da poslovni sistem izvleče XML in ga preda namenjenemu validatorju računov, natanko tako kot matrika preda Mustangu

Branje datoteke nazaj pove, kaj je bilo dejansko zapisano. DetectFacturXInvoice poroča, ali je bil račun prepoznan, GetFacturXInvoiceInfo pa prebere polja metapodatkov po oznaki: oznaka 1 je ime vgrajene datoteke, oznaka 2 XMP DocumentFileName, oznaka 5 raven skladnosti, oznaka 6 identifikator smernice in oznaka 7 /AFRelationship. Potrditev, da je raven skladnosti, ki jo preberete nazaj, standardni žeton in ne interna oznaka, je najcenejši način za odkritje napake EXTENDED, preden datoteka zapusti vaš sistem gradnje

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 vrne surove bajte XML kot AnsiString, pripravljene za zapis v datoteko ali pretok v validatorski proces. V testni matrici je ta cilj Mustang, ki se kliče prek ukaznega vmesnika jar, pri čemer se veraPDF zažene v istem prehodu nad isto datoteko. Napeljava je majhna: konzolni generator EInvoiceValidation.dpr zapiše dvanajst datotek z uporabo skupnega modela računa iz vzorca, skript run-validation.ps1 pa zažene oba validatorja nad izhodnim imenikom in natisne tabelo uspehov in neuspehov. Enaka dvostopenjska oblika - generiraj s knjižnico in preveri z zunanjimi validatorji - je tisto, kar bi moralo opraviti opravilo zvezne integracije ob vsaki spremembi generiranja računov, saj je edini način, da preverite, ali datoteka zadosti obema plastema, vprašati oba orodja

Če vaš cevovod prav tako zahteva potrditev vsebnika pred podpisom, je stran predkontroliranja tega dela obravnavana v našem vodičtu za predkontroliranje PDF/A in PDF/UA v Delphiju, širši tok potrditve in podpisovanja pa je opisan v delavnici za skladnost in podpisovanje. Oba gradita na isti poti generiranja, ki se prinaša kot del knjižnice Delphi PDF za Delphi in C++Builder, skupaj z API-ji PDF/A, pridruženih datotek in metapodatkov, ki se uporabljajo tukaj