Errori comuni di validazione Peppol BIS 3.0 e come risolverli
I fallimenti di validazione di Peppol BIS 3.0 rientrano in una serie prevedibile di categorie. I messaggi di errore fanno riferimento a codici di regola aziendale (BR-xx) e numeri di termine aziendale (BT-xx) dallo standard EN16931, che richiedono la lettura della specifica per essere compresi. Questo articolo mappa le anomalie più comuni alle loro cause e fornisce correzioni concrete.
Tutti gli esempi utilizzano la sintassi UBL 2.1. Per gli equivalenti CII, vedi UBL vs CII.
BR-01 fino a BR-06: campi header obbligatori mancanti
Queste regole verificano la presenza dei campi obbligatori di primo livello. Falliscono quando un elemento è assente o vuoto.
| Regola | Campo | BT | Correzione |
|---|---|---|---|
| BR-01 | Identificatore della specifica | BT-24 | Aggiungere CustomizationID con l’URI Peppol BIS 3.0 esatto |
| BR-02 | Numero fattura | BT-1 | Aggiungere elemento ID non vuoto |
| BR-03 | Data di emissione della fattura | BT-2 | Aggiungere IssueDate nel formato YYYY-MM-DD |
| BR-04 | Codice valuta della fattura | BT-5 | Aggiungere DocumentCurrencyCode con codice ISO 4217 |
| BR-05 | Nome del venditore | BT-27 | Aggiungere AccountingSupplierParty/Party/PartyName/Name |
| BR-06 | Nome dell’acquirente | BT-44 | Aggiungere AccountingCustomerParty/Party/PartyName/Name |
BR-01 nello specifico: la causa più comune è l’utilizzo dell’URI base EN16931 invece dell’URI Peppol BIS 3.0. Questi sembrano simili ma sono diversi:
Errato (base EN16931):
<cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
Corretto (Peppol BIS 3.0):
<cbc:CustomizationID>
urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1
</cbc:CustomizationID>
Il validatore controlla la stringa esatta. Vedi Introduzione a Peppol BIS 3.0 per capire perché questo è importante.
BR-CO-10: la somma degli importi di riga non corrisponde al totale
[BR-CO-10]-Sum of Invoice line net amount (BT-106) =
sum of Invoice line net amount (BT-131).
Questa regola richiede che LegalMonetaryTotal/LineExtensionAmount (BT-106) sia uguale alla somma di tutti i valori InvoiceLine/LineExtensionAmount (BT-131).
Il fallimento è quasi sempre un errore di arrotondamento. Se si arrotonda ogni importo di riga indipendentemente prima di sommarli, la somma dei valori arrotondati può differire dalla somma arrotondata dei valori grezzi.
Errato (arrotondamento per riga, poi somma):
// Line 1: 3 × 33.333... = 100.00 (rounded)
// Line 2: 3 × 33.333... = 100.00 (rounded)
// Sum of rounded: 200.00
// But raw sum: 3 × 33.333... + 3 × 33.333... = 200.00 exactly in this case
Il fallimento è più evidente con aliquote come il 7% IVA su quantità variabili dove l’arrotondamento si accumula su molte righe.
Approccio corretto: sommare i valori grezzi non arrotondati su tutte le righe, poi arrotondare l’aggregato una sola volta:
var lineNetTotal = invoiceLines.Sum(l => l.Quantity * l.UnitPrice); // raw
var lineNetTotalRounded = Math.Round(lineNetTotal, 2, MidpointRounding.AwayFromZero);
BR-CO-15: errore aritmetico sull’importo IVA della fattura
[BR-CO-15]-Invoice total VAT amount (BT-110) =
sum of VAT category tax amount (BT-117).
L’importo IVA totale in TaxTotal/TaxAmount deve essere uguale alla somma dei valori TaxTotal/TaxSubtotal/TaxAmount in tutte le categorie fiscali.
Per una fattura a aliquota singola questo sembra banale, ma i fallimenti si verificano quando:
- Ci sono più aliquote IVA e l’arrotondamento viene applicato per categoria invece che all’aggregato
- È presente una categoria a tasso zero o esente e il suo
TaxAmountè0.00invece di essere assente - Il
TaxAmountal livelloTaxTotalviene calcolato indipendentemente dagli importiTaxSubtotal
Correzione: calcolare prima tutti i valori TaxSubtotal/TaxAmount, sommarli e utilizzare quella somma come valore TaxTotal/TaxAmount. Non calcolare TaxTotal/TaxAmount separatamente.
BR-CO-16: importo dovuto per il pagamento
[BR-CO-16]-Amount due for payment (BT-115) =
Invoice total with VAT (BT-112) - Paid amount (BT-113) + Rounding amount (BT-114).
Se BT-113 (importo pagato) e BT-114 (importo di arrotondamento) non sono presenti, questo si semplifica in BT-115 = BT-112. Il fallimento si verifica quando PayableAmount e TaxInclusiveAmount differiscono di più della tolleranza di arrotondamento consentita.
Causa comune: calcolare PayableAmount dagli importi di riga arrotondati e TaxInclusiveAmount da un calcolo totale separato che produce un risultato leggermente diverso.
Correzione: calcolare un unico totale generale canonico, usarlo sia per TaxInclusiveAmount che per PayableAmount.
BR-S-08 e BR-S-09: coerenza tra aliquota IVA e importo
[BR-S-08]-For each different value of VAT category rate (BT-119) where the
VAT category code (BT-118) is "S", the VAT category taxable amount (BT-116)
in a VAT breakdown (BG-23) shall equal the sum of Invoice line net amounts
(BT-131) where the VAT category code of the Invoice line (BT-151) is "S"
and the VAT rate for the Invoice line (BT-152) equals the VAT category rate.
Questa regola raggruppa tutte le righe per aliquota IVA e verifica che l’imponibile in ogni TaxSubtotal corrisponda alla somma delle righe con quella aliquota. Fallisce quando:
- Una riga ha un’aliquota IVA per cui non esiste un corrispondente
TaxSubtotal - Esiste un
TaxSubtotalper un’aliquota ma nessuna riga usa quell’aliquota - Le differenze di arrotondamento si accumulano tra i calcoli a livello di riga e di subtotale
Correzione: costruire gli elementi TaxSubtotal dinamicamente a partire dalle voci di riga, raggruppando per (codice categoria IVA, aliquota IVA), invece di costruirli indipendentemente.
BR-E-01 / BR-AE-01: fatture in reverse charge ed esenti
[BR-E-01]-An Invoice that contains an Invoice line (BG-25), a Document level
allowance (BG-20) or a Document level charge (BG-21) where the VAT category
code (BT-151) is "E" shall contain exactly one VAT breakdown...
Le fatture con IVA esente (E), reverse charge (AE) o aliquota zero (Z) richiedono strutture TaxCategory specifiche diverse dalle fatture a aliquota standard (S).
Errori comuni:
- Usare il valore
IDSper tutte le righe indipendentemente dal trattamento IVA effettivo - Omettere gli elementi
TaxExemptionReasonCodeoTaxExemptionReasonobbligatori per le categorie esenti AccountingSupplierParty/Party/PartyTaxSchememancante quando la fattura utilizza il reverse charge
Per il reverse charge (AE), deve essere presente l’identificatore IVA dello schema fiscale dell’acquirente, e anche l’identificatore IVA del venditore deve essere presente.
Regole di estensione specifiche per la Germania
I profili Peppol tedeschi aggiungono regole sopra la base EN16931. Fallimenti comuni:
BR-DE-TMP-32: la data di consegna (BT-72) è obbligatoria per le fatture B2G tedesche. Aggiungere Delivery/ActualDeliveryDate nel formato YYYY-MM-DD.
BR-DE-18: deve essere presente o l’identificatore IVA del venditore (BT-31) o un numero di registrazione fiscale (BT-32). La mancanza di entrambi causa il rifiuto. Se il venditore è esente da IVA, fornire BT-32 con il numero di registrazione fiscale.
BR-DE-16: il riferimento dell’acquirente (BT-10, Leitweg-ID) è obbligatorio per le fatture B2G tedesche. Il formato Leitweg-ID è validato: deve corrispondere al pattern \d{2,12}-\d{4,12}-\d{2}.
Debug efficiente
L’output degli errori Schematron include una posizione XPath:
<svrl:failed-assert location="/Invoice[1]/cac:LegalMonetaryTotal[1]">
<svrl:text>[BR-CO-10]-Sum of Invoice line net amounts...</svrl:text>
</svrl:failed-assert>
Usa la posizione XPath per navigare direttamente all’elemento che genera l’errore. Per le regole aritmetiche, aggiungi output di debug che registri i valori grezzi prima dell’arrotondamento in modo da poter tracciare l’origine della discrepanza.
I file XSLT precompilati dalle release di GitHub di Peppol BIS sono gli artefatti di validazione autorevoli. Eseguili con Saxon HE come descritto in generare fatture Peppol BIS 3.0 in C#. Usare l’ultima release è importante: i set di regole vengono aggiornati con ogni release di Peppol BIS, e una regola che supera la validazione rispetto a un XSLT precedente potrebbe fallire rispetto a quello attuale.
SealDoc e gli errori di validazione
SealDoc esegue la validazione Schematron EN16931 e Peppol BIS 3.0 su ogni fattura prima della consegna. Quando la validazione fallisce, l’API restituisce una risposta di errore strutturata che mappa ogni fallimento al suo codice BR, al BT violato e alla posizione XPath nel documento inviato.
Per le organizzazioni che fanno debug di un pipeline di generazione fatture esistente, il validatore pubblico SealDoc accetta file di fattura UBL e CII, esegue l’XSLT Peppol BIS 3.0 corrente e restituisce l’elenco completo dei fallimenti con descrizioni in linguaggio semplice. I set di regole vengono mantenuti aggiornati con le release di Peppol BIS, quindi il validatore riflette sempre le regole che un Access Point ricevente applicherà.