Tehnicki clanak

Factur-X i ZUGFeRD hibridne fakture u Delphi-ju

Uskladjena elektronska faktura nije PDF sa XML datotekom prikacenom sa strane. To je jedan PDF/A-3 dokument koji nosi fakturu dva puta: jednom kao stranicu koju covek cita, i jednom kao masinski citljiv Cross Industry Invoice XML pohranjen unutar datoteke kao pridrzena datoteka. Dva predstavljanja opisuju istu fakturu. Ta dualna priroda je cela poanta familija formata koje evropski propisi sada zahtevaju -- Factur-X u Francuskoj i Nemackoj, ZUGFeRD na trzistima nemackog govornog podrucja, i XRechnung za naplatu u nemackom javnom sektoru. Ovaj clanak prolazi kroz to kako PDFlibPas sastavlja takvu hibridnu fakturu u Delphi-ju, gde standardi ostavljaju prostora za gresku, i zasto jedan profil u katalogu treba potpuno poseban XML builder

Sta je hibridna faktura zapravo

Vidljiva stranica i ugradeni XML sluze razlicitim citaocima. Sluzbenik koji odobrava placanje gleda renderovanu stranicu. Sistem racunovodstva ingestuje XML, cita ukupne iznose i poresku rasclambu kao strukturisana polja, i knjizi unos bez da iko ista unosi. Semanticki sadrzaj tog XML-a uredjen je sa EN 16931, evropskim standardom koji definise model podataka fakture: koja polja postoje, sta znace i koja su obavezna. EN 16931 je semanticki model, ne format datoteke. Factur-X, ZUGFeRD 2.x i XRechnung svi realizuju taj model kao UN/CEFACT Cross Industry Invoice dokument, sintaksu koja nosi polja EN 16931

Da bi dokument bio i arhivabilan i samoopiszujuci, kontejner je PDF/A-3, definisan ISO 19005-3. PDF/A-3 je nivo konformnosti koji dozvoljava proizvoljne ugradene datoteke, sto je tacno ono sto XML faktura treba biti. PDF/A-2 zabranjuje ugradivanje datoteka koje same nisu PDF/A, pa faktura Factur-X ne moze biti PDF/A-2. Izbor PDF/A-3 stoga nije preferencija, to je zahtev koji direktno proistice iz zelje da se ugradi ne-PDF podaci u arhivski dokument

Zasto je veza Alternative

Ugradivanje bajtova je laki deo. ISO 32000 par.7.11.4 definise tok ugradene datoteke, objekat koji drzi sirovi XML i njegove parametre. Deo koji cini datoteku vazecim pridrzenom datotekom je par.14.13, koji dodaje koncept pridrzene datoteke i kljuc /AFRelationship. Taj kljuc navodi kako se ugradeni podaci odnose na sadrzaj za koji su pricvrsceni, a vrednost koju Factur-X propisuje je Alternative

Taj izbor je vazan jer bi druge vrednosti tvrdile nesto lazno o dokumentu. Source bi znacilo da je XML materijal iz kojeg je vidljivi sadrzaj generisan, master iz kojeg stranica izvodi. Supplement bi znacilo da XML dodaje informacije koje stranica ne pokazuje, dodatak koji nije sadrzaj u renderovanju. Ni jedno ni drugo nije ono sto Factur-X faktura jeste. XML i stranica su dva ekvivalentna izraza jedne fakture, koji nose isti pravni sadrzaj u dva oblika. Alternative je vrednost koja to kaze tacno: ekvivalentna alternativna reprezentacija vidljivog sadrzaja. Validator koji procita bilo koji drugi odnos na Factur-X datoteci odbacice je, i s pravom, jer je odnos masinski citljiva tvrdnja o tome cemu je privitak namenjen

Katalog profila

Uzorak E-faktura koji se isporucuje sa PDFlibPas pokrace istu putanju generisanja kroz sest profila, definisanih kao niz zapisa u InvoiceModel.pas. Svaki profil nosi vrednosti koje pisac treba: prikazano ime, naziv ugradene datoteke, nivo konformnosti, /AFRelationship, verziju, opcionalni kod drzave i URN GuidelineID koji XML najavljuje unutar konteksta svog dokumenta

Sest su Factur-X EN16931, Factur-X BASIC, Factur-X EXTENDED za Francusku, XRechnung 3.0, ZUGFeRD 1.0 COMFORT i ZUGFeRD 2.0 BASIC. GuidelineID je polje koje primaocu tacno govori koji profil da ocekuje, i vrednosti su specificne. Factur-X EN16931 najavljuje urn:cen.eu:en16931:2017. XRechnung 3.0 najavljuje urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0. ZUGFeRD 2.0 BASIC najavljuje urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic. Naziv ugradene datoteke je takodje deo ugovora. Factur-X profili ugraduju factur-x.xml, XRechnung ugradjuje xrechnung.xml, a ZUGFeRD profili ugraduju ZUGFeRD-invoice.xml ili zugferd-invoice.xml. Primalac skenira nazive privitaka da pronadje fakturu, tako da naziv datoteke nije kozmeticki

Jedan detalj u katalogu vredi pazljivo procitati. Vecina profila koristi Alternative vezu, ali unos XRechnung 3.0 u uzorku koristi Source. Dva formata odgovaraju razlicitim validatorima i konvencijama, a uzorak postavlja vezu svakog profila iz kataloga umesto da tvrdo kodira jednu vrednost, sto je razlog zasto polje po profilu postoji umesto konstante

Zamka ZUGFeRD 1.0

Mamljivo je pretpostaviti da je svaki profil EN 16931 Cross Industry Invoice sa manjim varijacijama u tome koliko opcionalnih polja popunjavate. To vazi za pet od sest. Ne vazi za ZUGFeRD 1.0 COMFORT, a razlog je strukturalan a ne kozmeticki

Moderni profili emituju UN/CEFACT Cross Industry Invoice sa verzijom imenskog prostora :100, ciji je korijenski element rsm:CrossIndustryInvoice. ZUGFeRD 1.0 datira pre te seme. To je CrossIndustryDocument iz 2014. sa verzijom imenskog prostora :1p0, a njegov korijenski element je rsm:CrossIndustryDocument. URN-ovi imenskog prostora se razlikuju, korijenski element se razlikuje, i stablo elemenata se razlikuje u celosti: sema :1p0 grupise podatke pod ApplicableSupplyChainTradeAgreement, ApplicableSupplyChainTradeDelivery i ApplicableSupplyChainTradeSettlement, gde :100 koristi ApplicableHeaderTradeAgreement, ApplicableHeaderTradeDelivery i ApplicableHeaderTradeSettlement. Imenovanje je dovoljno slicno da zavede i dovoljno razlicito da pokvari

Rec COMFORT u nazivu profila opisuje koliko su podaci bogati, profil automatizovanog stepena sa punim stavkama, poreskom rascambom i uslovima placanja, a ne koja sema ga nosi. Dakle ne mozete uzeti :100 dokument i prenazvati ga za ZUGFeRD 1.0. Uzorak to resava zastavicom na svakom zapisu profila i dve odvojene builder funkcije, birajuci ispravnu pre nego sto se bilo koji XML generise

function BuildInvoiceXMLText(const AProfile: TeInvoiceProfile;
  const Data: TInvoiceData): string;
begin
  // XMLFamily = 1 means the legacy ZUGFeRD 1.0 :1p0 schema; every
  // other profile is the modern UN/CEFACT :100 Cross Industry Invoice.
  if AProfile.XMLFamily = 1 then
    Result := BuildZUGFeRD1Text(AProfile, Data)
  else
    Result := BuildCII100Text(AProfile, Data);
end;

Podela nije implementacijska ulepasavica. Slanje :100 stabla ZUGFeRD 1.0 primaocu proizvodi dokument koji ne prolazi validaciju seme na korijenskom elementu, pa dve familije moraju biti izgradene kodom koji zna koju od njih pise

Odabir nivoa PDF/A-3

PDF/A-3 ima tri nivoa konformnosti, a PDFlibPas ih bira putem SetPDFAMode. Nacin 5 je PDF/A-3b, nivo koji garantuje pouzdanu vizualnu reprodukciju. Nacin 6 je PDF/A-3a, koji dodaje zahteve oznacene-strukture i pristupacnosti nivoa a. Nacin 7 je PDF/A-3u, koji zahteva da sav tekst bude mapiran na Unicode. Omogucavanje nacina takodje ugradjuje ugradeni sRGB izlazni intent biblioteke, karakterizaciju boja koju PDF/A zahteva da bude renderovana boja definisana a ne zavisna od uredjaja

Vecina tokova faktura radi na 3b, sto je dovoljno za verno vidljivu stranicu plus ugradeni XML. Ako trebate eksplicitni ICC profil umesto ugradenog, LoadOutputIntentProfile ga zamenjuje nakon sto je nacin postavljen. Uzorak ucitava sRGB profil repozitorija na ovaj nacin i pada nazad na ugradeni intent kada datoteka nije dostupna, pa je izlazni intent uvek prisutan

PDF := TPDFlib.Create;
try
  // Mode 5 = PDF/A-3b, 6 = PDF/A-3a, 7 = PDF/A-3u.
  if PDF.SetPDFAMode(5) <> 1 then
    raise Exception.Create('PDF/A-3 mode could not be enabled');

  // Optional: swap the built-in sRGB intent for an explicit ICC profile.
  if PDF.LoadOutputIntentProfile(ICCFile, 'DeviceRGB') <> 1 then
    { fall back to the built-in sRGB intent that SetPDFAMode embedded };
finally
  // ... continue building the document
end;

Izgradnja hibridne fakture

Sa konfigurisanim kontejnerom, ostatak su tri koraka redom: postavite PDF/A-3 nacin, nacrtajte coveku citljivu stranicu, a zatim prilosite XML kao pridrzenu datoteku. Vidljiva stranica je obicni sadrzaj. Jedno ogranicenje koje vredi zapamtiti je da PDF/A zabranjuje neugradenih Standard 14 fontova, pa stranica mora ugraditi pravo lice fonta umesto referenciranja ugradenog

Privitak je jedan poziv. AddFacturXAssociatedFileFromString uzima sirove UTF-8 XML bajtove plus metapodatke profila, zapisuje tok ugradene datoteke, registruje je u Catalog /AF nizu koji PDF/A-3 zahteva, primenjuje /AFRelationship, i generise XMP e-faktura metapodatke koji identifikuju dokument kao Factur-X, ZUGFeRD ili XRechnung. Takodje proverava da li se ID smernice XML-a slaze sa nivoom konformnosti koji ste zatrazili, pa je nepodudarnost izmedju XML-a koji ste izgradili i profila koji ste imenovali uhvacena umesto da se tiho salje

// 1. PDF/A-3 mode and output intent are already set.
// 2. Draw the visible page (embeds a real TrueType font).
DrawInvoicePage(PDF, AProfile, Data);

// 3. Build the profile-correct XML and attach it as an
//    associated file with /AFRelationship = Alternative.
InvoiceXML := BuildInvoiceXML(AProfile, Data);   // AnsiString of UTF-8 bytes
FileID := PDF.AddFacturXAssociatedFileFromString(
  InvoiceXML,
  AProfile.ConformanceLevel,   // e.g. 'EN16931'
  AProfile.FileName,           // 'factur-x.xml'
  AProfile.Description,
  AProfile.Relationship,       // 'Alternative'
  AProfile.Version,            // '1.0'
  AProfile.CountryCode);       // '' or 'DE' or 'FR'
if FileID <= 0 then
  raise Exception.Create('Invoice XML could not be attached');

PDF.SaveToFile(TargetFile);

Jedna suptilnost u putanji podataka je kodiranje. Ugradeni XML deklarise encoding="UTF-8", a metoda uzima bajtove kao AnsiString, pa ime prodavca ili kupca koji nisu ASCII moraju stici do poziva kao sirovi UTF-8 okteti. Obicno kastovanje kroz sistemsku ANSI kodnu stranicu bi pokvarilo te znakove i tiho proizvelo fakturu ciji XML vise ne odgovara vlastitoj deklaraciji. Uzorak kodira u UTF-8 eksplicitno pre predaje bajtova, sto je siguran nacin za hranjenje bilo kog bajt-orijentisanog PDF API-ja iz Unicode string-a

Za prilaganje XML koji nije prepoznati e-faktura profil, AddPDFA3AssociatedFileFromString je genericki pandan. Uzima naziv datoteke, MIME tip, opis, vezu i bajtove, i zapisuje obicnu PDF/A-3 pridrzenu datoteku bez ikakvih metapodataka specificnih za fakturu ili provere smernice. Koristite ga za dopunske podatke; koristite Factur-X metodu za fakture, pa su metapodaci profila i podudaranje smernice zapisani za vas

Kada je dokument proizveden, sledeca pitanja su da li prolazi PDF/A i validaciju pristupacnosti, i da li moze biti potpisan bez krsenja uskladjenosti. To je obradeno u PDF/A i PDF/UA predlet pregledu i radnoj stanici za uskladjenost i potpisivanje. Sve ovo se isporucuje kao deo PDFlibPas Delphi PDF Library, zajedno sa PDF/A, oznacavanjem i API-jevima svojstava dokumenta na kojima se putanja e-fakture gradi