Articolo tecnico

Fatture elettroniche ZUGFeRD e Factur-X in Delphi con HotPDF

HotPDF genera, rileva e convalida le fatture elettroniche ZUGFeRD e Factur-X da Delphi e C++Builder. AddFacturXAssociatedFile incorpora l'XML della fattura EN 16931 in un contenitore PDF/A-3, DetectFacturXInvoice riconosce una fattura ibrida in entrata e HPDFValidateEInvoice esegue le regole aziendali ufficiali EN 16931 Schematron sull'XML incorporato. Questo articolo illustra tutti e tre i passaggi ed espone chiaramente i limiti del motore di convalida

La spinta all'adozione di questa funzionalità è normativa e non tecnica. La Germania e la Francia stanno introducendo gradualmente la fatturazione elettronica strutturata obbligatoria per le transazioni B2B nazionali, ed entrambi i mandati convergono sullo stesso modello ibrido: la fattura PDF già generata dal tuo ERP deve contenere un equivalente XML leggibile dalla macchina al suo interno. Un'applicazione contabile o ERP sviluppata in Delphi che oggi produce semplici fatture PDF ha una scadenza improrogabile per iniziare a generare Factur-X o ZUGFeRD, e la differenza tra questi due nomi è inferiore a quanto suggerisca il marketing — Factur-X e ZUGFeRD rappresentano lo stesso standard franco-tedesco pubblicato sotto due etichette diverse

Cosa rende un PDF una fattura Factur-X valida?

Una fattura Factur-X valida è un file PDF/A-3 (ISO 19005-3) che incorpora esattamente un file XML strutturato come file associato, lo collega dal catalogo del documento e lo dichiara nei metadati di estensione XMP. Tre livelli devono concordare. In primo luogo, the contenitore deve essere conforme allo standard PDF/A-3, il profilo di archiviazione che — a differenza di PDF/A-1 e PDF/A-2 — consente file incorporati di qualsiasi tipo. In secondo luogo, l'XML della fattura, denominato factur-x.xml per i profili standard o xrechnung.xml per la variante tedesca XRechnung, deve essere registrato nell'array /AF del catalogo e nell'albero /Names /EmbeddedFiles, con una voce AFRelationship che indica il ruolo dell'allegato: Alternative significa che l'XML rappresenta una rappresentazione equivalente della fattura visibile, che è la semantica richiesta dalla maggior parte dei profili. In terzo luogo, lo schema di estensione Factur-X XMP deve indicare il file incorporato, il suo livello di conformità e il tipo di documento, in modo che un sistema ricevente possa classificare la fattura senza dover analizzare l'XML

Perché ZUGFeRD 2.5 non necessita di un nuovo contenitore

ZUGFeRD 2.5 non introduce modifiche a livello di contenitore PDF: gli URN delle linee guida, lo schema XMP e il token di versione sono identici a quelli di ZUGFeRD 2.3 / Factur-X 1.0. Questo sorprende la maggior parte degli sviluppatori, ed è utile citare la fonte. La specifica Factur-X 1.09 stabilisce che il numero di versione nell'URI dello schema di estensione PDF/A non è correlato al numero di versione della specifica dei dati XML, e che il versionamento delle istanze di fattura Factur-X rimane 1.0 — sia in XMP fx:Version che nel campo BT-24 di factur-x.xml. Il corpus ufficiale di campioni ZUGFeRD 2.5 lo conferma: ogni campione incorpora factur-x.xml sotto un URN di linea guida urn:factur-x.eu:1p0 con fx:Version impostata su 1.0. Ciò che la versione 2.5 effettivamente aggiunge risiede all'interno del modello dati XML — nuovi elementi come righe di sotto-fatturazione e identificatori di lotto — che rappresentano il livello aziendale generato dalla tua applicazione, non il livello del contenitore gestito dalla libreria PDF

Incorporamento dell'XML della fattura da Delphi

THotPDF.AddFacturXAssociatedFile turns a regular PDF/A-3 generation run into a Factur-X invoice with one call: it embeds the XML bytes as an associated file, registers factur-x.xml in the catalog /AF array and the /Names /EmbeddedFiles tree, and emits the matching Factur-X XMP extension metadata. You draw the human-readable invoice page with the normal HotPDF canvas API; the container work is a single line between BeginDoc and 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;

I valori predefiniti seguono le specifiche: nome file factur-x.xml, relazione Alternative, versione 1.0. AddUBLSupplementaryFile implementa la sezione 6.4 delle specifiche Factur-X 1.09, che consente a una rappresentazione UBL della stessa fattura di viaggiare come secondo allegato denominato factur-xubl.xml con tipo MIME application/xml e relazione Alternative. L'ordine è importante, e HotPDF applica il vincolo previsto dalle specifiche: il file UBL rappresenta una vista supplementare, mai la fattura principale, quindi deve essere aggiunto dopo che AddFacturXAssociatedFile ha registrato il file CII master. Si noti che la pagina disegnata e l'XML incorporato devono contenere la stessa fattura — un PDF che mostra un totale e ne codifica un altro rappresenta esattamente l'incoerenza che la fatturazione ibrida intende evitare. La gestione di PDF/A-3 di questo flusso di lavoro, inclusi OutputIntent e l'incorporamento dei font, è trattata in dettaglio nell'articolo correlato sulla convalida PDF/A, PDF/X e PDF/UA in Delphi

Come si rileva una fattura Factur-X in un PDF in entrata?

THotPDF.DetectFacturXInvoice risponde all'esigenza lato ricezione: carica qualsiasi PDF e scopri con un'unica chiamata se si tratta di una fattura ibrida, quale profilo dichiara e quali allegati trasporta. La funzione restituisce un record THPDFFacturXInvoiceInfo con il nome del file XML incorporato, il nome e il tipo di file del documento dichiarato in XMP, il token di versione, il livello di conformità, l'URN della linea guida e il valore AFRelationship. Altri due campi segnalano viste supplementari: UBLFileName viene compilato quando è presente un allegato factur-xubl.xml, ed EDIFACTFileName quando è presente una vista EDIFACT — nessuno dei due influisce sull'esito del rilevamento, poiché una rappresentazione supplementare non può esistere senza la fattura master CII primaria

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;

Il rilevamento legge gli stessi segnali letti da un convalidatore conforme — lo schema di estensione XMP e il registro dei file associati — anziché affidarsi esclusivamente ai nomi dei file. Lo stesso oggetto del documento caricato espone anche i metadati XMP e del dizionario Info per l'ispezione o la correzione, un flusso di lavoro descritto nell'articolo sulla modifica dei metadati nei documenti PDF caricati

Regole aziendali o schema: cosa significa la convalida EN 16931?

HPDFValidateEInvoice, una funzione autonoma nell'unità HPDFEInvoiceValidator, esegue entrambi i livelli di convalida in sequenza: prima il controllo della struttura del contenitore tramite ValidateFacturXInvoice, quindi le regole aziendali EN 16931 Schematron sull'XML estratto della fattura. HotPDF fornisce i cinque file di regole ufficiali Factur-X 1.09 — MINIMUM, BASIC WL, BASIC, EN 16931 ed EXTENDED — sotto Lib/resources/Schematron/, e HPDFSchematronFileForProfile seleziona il file corrispondente al livello di conformità rilevato, per cui una fattura conforme a EN 16931 viene automaticamente convalidata rispetto a Factur-X_1.09_EN16931.sch. La funzione restituisce True solo se il contenitore è valido e non viene attivata alcuna regola aziendale

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;

Ciascuna voce in BusinessRules contiene l'identificatore della regola derivato dal testo dell'asserzione — BR-45, BR-CO-17 e il resto dello schema di denominazione EN 16931 — oltre all'XPath del contesto della regola, l'espressione di test e una gravità (severity) che rispecchia l'attributo flag di Schematron. Questo rende il report operativo: invece di un semplice esito positivo/negativo, si ottiene il termine esatto non coerente, che è ciò di cui il team di supporto ha bisogno quando un cliente chiede perché una fattura sia stata rifiutata. I team che già generano report strutturati di conformità per i PDF archiviati possono integrare questi risultati nella stessa pipeline descritta nell'articolo sull'automazione dei report di preflight PDF

Limiti oggettivi del convalidatore

Il motore Schematron si basa su MSXML, che valuta XPath 1.0. Il file delle regole EN 16931 dichiara queryBinding="xslt2" e contiene 424 asserzioni, la maggior parte delle quali utilizza solo funzioni XPath 1.0 come string-length e substring-after — che vengono eseguite nativamente. Una minoranza si affida a costrutti XPath 2.0 come i cast xs:decimal o exists(); HotPDF esegue una scansione preliminare di ciascuna espressione di test per individuare token XPath 2.0 noti e contrassegna tali regole come Skipped con gravità informativa, anziché tentare una valutazione che fallirebbe silenziosamente. Il record di riepilogo riporta separatamente i conteggi delle regole valutate e saltate, in modo che il registro indichi sempre con precisione quale porzione delle regole è stata verificata. In Delphi 7, dove i binding MSXML non sono disponibili, l'unità compila uno stub che segnala il motore come non disponibile senza influire sull'esito della conformità del contenitore; il motore completo richiede Delphi XE2 o versioni successive

Il secondo limite è ancora più importante. Un esito positivo da HPDFValidateEInvoice indica che la struttura del contenitore è conforme e che nessuna regola aziendale valutata ha riscontrato errori — non costituisce una certificazione di conformità fiscale. Le regole di estensione nazionali, i requisiti specifici del ricevente e gli obblighi legali relativi al contenuto della fattura si collocano al di sopra del nucleo EN 16931 e al di fuori di qualsiasi libreria. Utilizza il convalidatore come filtro per escludere le fatture strutturalmente non valide in uscita e per segnalare quelle incoerenti in entrata, esegui un convalidatore XPath 2.0 completo nella pipeline di rilascio se la certificazione lo richiede, e affida la conformità fiscale alla consulenza dei tuoi esperti. Le API di incorporamento, rilevamento e convalida mostrate qui fanno parte del Componente HotPDF standard per Delphi e C++Builder, con un campione completo di fatturazione elettronica che copre tutti e sette i profili ZUGFeRD e Factur-X