Technický článok

Schémy rozšírenia PDF/A-3 pre Factur-X XMP v Delphi

Vytvorili ste faktúru Factur-X a všetky kontroly kontajnera prešli úspešne. Katalóg obsahuje pole /AF, strom názvov EmbeddedFiles sa prekladá na správnu špecifikáciu súboru, vložený factur-x.xml má správny /AFRelationship s hodnotou Alternative a vstavaný ValidateFacturXInvoice vracia 1. Potom spustíte rovnaký súbor cez veraPDF, referenčný kontrolór, ktorý používajú daňové portály, a ten rozhodne, že celý dokument nie je platný PDF/A-3. Štruktúra je správna. Problémom sú metaúdaje a toto zlyhanie je jedným z najľahšie prehliadnuteľných v celom pracovnom postupe elektronickej faktúry

Dôvod stojí za to plne pochopiť, pretože vysvetľuje triedu chýb PDF/A, ktorá nemá nič spoločné s viditeľnou stránkou alebo prílohou, a má všetko spoločné s tým, ako XMP popisuje samo seba. Toto je pasca, ktorá sa skrýva za zelenou kontrolou kontajnera

Štyri vlastnosti, pre ktoré súbor zlyhá

Faktúra Factur-X zapisuje štyri vlastné vlastnosti do svojho paketu XMP, aby softvér v ďalších krokoch mohol prečítať profil faktúry bez parsovania vloženého XML. Žijú v mennom priestore Factur-X pod predponou fx: fx:DocumentFileName, fx:DocumentType, fx:Version a fx:ConformanceLevel. Sú to presne tie metaúdaje, ktoré čítačka potrebuje, aby vedela, že toto PDF nesie faktúru podľa EN 16931 s názvom factur-x.xml vo verzii 1.0

Žiadna z týchto štyroch vlastností nie je súčasťou žiadnej schémy XMP, ktorú PDF/A preddefinuje. Schémy Dublin Core, XMP Basic, PDF a identifikačné schémy PDF/A sú vyhovujúcej čítačke známe, ale fx: nie je. Keď veraPDF prechádza cez XMP a narazí na vlastnosť, ktorej menný priestor nerozpoznáva, hľadá deklaráciu, ktorá by mu povedala, čo daná vlastnosť znamená. Ak táto deklarácia chýba, nahlási zlyhanie voči článku 6.6.2.3.1 normy ISO 19005-3, ktorý vyžaduje, aby každá vlastnosť, ktorá nepochádza z preddefinovanej schémy, bola opísaná v schéme rozšírenia PDF/A. Štyri nedeklarované vlastnosti, štyri spôsoby, ako môže byť súbor odmietnutý, a ani jeden z nich nie je viditeľný pri kontrole kontajnera

Prečo PDF/A odmieta holú vlastnú vlastnosť

Toto pravidlo vyzerá pedantne, kým si nespomeniete, na čo PDF/A slúži. Formát existuje preto, aby bolo možné súbor otvoriť a pochopiť aj o niekoľko desaťročí neskôr, softvérom, ktorému nikdy nebolo povedané o konvenciách z roku 2026. Od vyhovujúcej čítačky sa očakáva, že pochopí dokument len na základe samotného dokumentu, bez nutnosti konzultácie s externým registrom

Vlastné metaúdaje porušujú tento sľub, pokiaľ súbor nenesie svoj vlastný opis. Pri samotnej vlastnosti fx:ConformanceLevel budúca čítačka nemôže vedieť, na aké URI menného priestoru sa viaže predpona fx, či je hodnotou text, dátum alebo celé číslo, alebo či vlastnosť opisuje samotný dokument alebo nejaký externý zdroj. Mechanizmus schémy rozšírenia PDF/A túto medzeru uzatvára. Umožňuje súboru deklarovať v pevnej štruktúre XMP menný priestor, predponu a pre každú vlastnosť typ hodnoty a kategóriu internal alebo external. Keď je táto deklarácia prítomná, vlastnosť je samoopisná a článok 6.6.2.3.1 je splnený. Bez nej validátor nemá inú možnosť, ako považovať vlastnosť za nezrozumiteľnú a zamietnuť súbor. Rozdiel v kategóriách je tu dôležitý: vlastnosti faktúry ako sú tieto opisujú dáta, ktoré pochádzajú zvonku procesora PDF, takže sa deklarujú ako external namiesto internal

Čo obsahuje deklarácia schémy rozšírenia

Deklarácia je rdf:Description v pakete XMP, ktorá používa tri menné priestory definované AIIM: pdfaExtension, pdfaSchema a pdfaProperty. Vo vnútri štruktúry bag pdfaExtension:schemas sa nachádza jedna položka schémy, ktorá pomenováva schému Factur-X, uvádza jej pdfaSchema:namespaceURI a pdfaSchema:prefix a potom zoznam štyroch vlastností v sekvencii pdfaSchema:property. Každá vlastnosť nesie meno, pdfaProperty:valueType s hodnotou Text a pdfaProperty:category s hodnotou external. Ilustračný markup nižšie ukazuje tvar tohto bloku

<rdf:Description rdf:about=""
    xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/"
    xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#"
    xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">
  <pdfaExtension:schemas>
    <rdf:Bag>
      <rdf:li rdf:parseType="Resource">
        <pdfaSchema:schema>Factur-X PDFA Extension Schema</pdfaSchema:schema>
        <pdfaSchema:namespaceURI>urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#</pdfaSchema:namespaceURI>
        <pdfaSchema:prefix>fx</pdfaSchema:prefix>
        <pdfaSchema:property>
          <rdf:Seq>
            <rdf:li rdf:parseType="Resource">
              <pdfaProperty:name>DocumentFileName</pdfaProperty:name>
              <pdfaProperty:valueType>Text</pdfaProperty:valueType>
              <pdfaProperty:category>external</pdfaProperty:category>
              <pdfaProperty:description>name of the embedded XML invoice file</pdfaProperty:description>
            </rdf:li>
            <!-- DocumentType, Version, ConformanceLevel declared the same way -->
          </rdf:Seq>
        </pdfaSchema:property>
      </rdf:li>
    </rdf:Bag>
  </pdfaExtension:schemas>
</rdf:Description>

URI menného priestoru a predpona nie sú pevné reťazce. Nasledujú daný profil. Dokument Factur-X používa urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0# s predponou fx, kým súbor ZUGFeRD 2.0 vybraný cez zugferd-invoice.xml sa preloží na iné URI pod svojím vlastným názvom schémy. Schéma rozšírenia musí deklarovať rovnaké URI menného priestoru, aké vlastne používa blok vlastností, inak validátor stále nebude môcť prepojiť tieto dve veci. PDFlibPas odvodzuje obe hodnoty z názvu súboru a verzie, ktoré odovzdáte, takže deklarácia a blok vlastností sa vždy zhodujú

Ako pomocník zapisuje obe polovice spoločne

V PDFlibPas toto XML nezostavujete ručne. Dokument uvediete do režimu PDF/A-3 a zavoláte jednu metódu. Prvá vec, ktorú treba vyriešiť, je príznak zhody, pretože Factur-X vyžaduje PDF/A-3. Volaním SetPDFAMode(7) sa vyberie úroveň PDF/A-3u, ktorá v identifikačnej schéme nastaví pdfaid:part na 3 a pdfaid:conformance na U. Paket XMP teraz nesie správnu časť a zhodu predtým, ako sa pridajú akékoľvek metaúdaje faktúry

var
  FileID: Integer;
begin
  PDF.SetPDFAMode(7);            // PDF/A-3u: pdfaid:part=3, conformance=U
  PDF.NewDocument;
  // draw the human-readable invoice page here

  FileID := PDF.AddFacturXAssociatedFileFromString(
    InvoiceXML,                  // raw UTF-8 XML bytes
    'EN16931',                   // ConformanceLevel
    'factur-x.xml',              // embedded file name
    'Factur-X invoice XML',      // /Desc text
    'Alternative',               // /AFRelationship
    '1.0',                       // profile version
    '');                         // optional country code
  if FileID = 0 then
    Exit;                        // not PDF/A-3, or XML/profile mismatch

  PDF.SaveToFile('factur-x.pdf');
end;

Jediné volanie AddFacturXAssociatedFileFromString vykoná prácu, ktorá zlyhávajúcemu súboru chýbala. Vloží XML ako pridružený súbor PDF/A-3 so vzťahom, ktorý ste pomenovali, a zaznamená štyri vlastnosti fx spolu s názvom schémy, URI menného priestoru a predponou pre vybraný profil. Pri uložení dokumentu vnútorný krok s názvom ApplyFacturXMetadata vloží blok vlastností aj zodpovedajúcu deklaráciu pdfaExtension:schemas do paketu XMP, takže vlastné vlastnosti dorazia už popísané. Metóda vráti 0, ak dokument nie je v režime PDF/A-3 alebo ak sa XML nezhoduje s deklarovaným profilom, čo je tá istá poistka, ktorá v prvom rade zabráni zle naformátovanej faktúre dostať sa do súboru

Slepý bod, ktorý kontrola kontajnera nevidí

Toto je časť, ktorú treba pomenovať jasne, pretože to je dôvod, prečo sa chyba skrýva. ValidateFacturXInvoice kontroluje kontajner. Potvrdzuje, že katalóg má položku /AF, že je prítomný strom názvov EmbeddedFiles, že existuje XML faktúry, že názov vloženého súboru sa zhoduje s profilom, že ID usmernenia v XML súhlasí s úrovňou zhody a že /AFRelationship je to, čo PDF/A-3 povoľuje. Sú to skutočné kontroly a zachytávajú skutočné chyby. GetFacturXValidationIssues ich nahlasuje podľa názvu s identifikátormi ako MissingCatalogAF, NotPDFA3, ConformanceGuidelineMismatch, InvalidAFRelationship a InvalidFileNameProfile

Čo nekontroluje je, či je prítomná a správna schéma rozšírenia XMP. Súbor, ktorého kontajner je bezchybný, ale ktorého vlastnosti fx sú nedeklarované, prejde každou kontrolou chýb a vráti 1, pretože nič v tomto zozname nekontroluje blok pdfaExtension:schemas. Presne to je dôvod, prečo ručne vytvorená faktúra alebo faktúra vyrobená procesom, ktorý zapísal blok vlastností bez deklarácie, môže bez problémov prejsť cez vstavaný validátor a napriek tomu zlyhať vo veraPDF na článku 6.6.2.3.1. Validátor kontajnerov a validátor metaúdajov PDF/A odpovedajú na rôzne otázky a iba úplný kontrolór PDF/A odpovedá na tú druhú

Čítanie chýb, aby ste vedeli, ktorá vrstva sa pokazila

Pretože tieto dve vrstvy zlyhávajú nezávisle od seba, správnym diagnostickým návykom je najskôr si prečítať problémy s kontajnerom a považovať čistý výsledok za vyhlásenie len o kontajneri, nikdy nie o metaúdajoch PDF/A. Spustite vstavanú validáciu, pozbierajte zoznam chýb a konajte na jeho základe predtým, ako siahnete po externom nástroji

var
  Issues: WideString;
begin
  if PDF.ValidateFacturXInvoice = 0 then
  begin
    Issues := PDF.GetFacturXValidationIssues('|');
    // container-level identifiers, for example:
    //   MissingCatalogAF, NotPDFA3, MissingEmbeddedFilesNameTree,
    //   ConformanceGuidelineMismatch, InvalidAFRelationship
    WriteLn('Container issues: ', Issues);
  end
  else
    WriteLn('Container OK; verify XMP extension schema with a PDF/A checker.');
end;

Keď toto volanie vráti názov chyby, chyba je v kontajneri a správa vám povie v ktorej časti. Keď sa vráti ako čisté a veraPDF stále zamietne súbor, chybou je takmer vždy schéma rozšírenia XMP a opravou je nechať AddFacturXAssociatedFileFromString zapísať metaúdaje, než aby ste si blok vlastností konštruovali sami. Udržiavanie týchto dvoch otázok oddelených vo vašej vlastnej mysli je to, čo premení mätúce odmietnutie na jednoriadkovú diagnózu: problémy s kontajnerom sa prejavia cez zoznam chýb, problémy s deklaráciou schémy sa prejavia iba cez validátor PDF/A a zamieňanie týchto dvoch vecí je to, čo umožňuje chybe sa skryť

Širší obraz zhody s PDF/A a PDF/UA, vrátane toho, ako spustiť preflight predtým, než súbor opustí vaše zostavenie, je pokrytý v prehľade preflightu PDF/A a PDF/UA v Delphi. Ak má byť vaša faktúra aj prístupná, strom štruktúry, od ktorého závisí PDF/A-3a a tagované PDF, je predmetom článku o prístupnosti tagovaného PDF. Tu popísané spracovanie schémy rozšírenia sa dodáva ako súčasť PDFlibPas Delphi PDF Library spolu s podporou profilov Factur-X, ZUGFeRD a XRechnung dokumentovaných v celom tomto blogu