← Back to all articles

Erreurs de validation Peppol BIS 3.0 courantes et comment les corriger

SealDoc Team · · 7 min read

Les échecs de validation Peppol BIS 3.0 tombent dans un ensemble prévisible de catégories. Les messages d’erreur référencent des codes de règles métier (BR-xx) et des numéros de termes métier (BT-xx) de la norme EN16931, dont la compréhension nécessite de consulter la spécification. Cet article associe les erreurs les plus courantes à leurs causes et fournit des corrections concrètes.

Tous les exemples utilisent la syntaxe UBL 2.1. Pour les équivalents CII, voir UBL vs CII.

BR-01 à BR-06 : champs d’en-tête obligatoires manquants

Ces règles imposent la présence des champs obligatoires de niveau supérieur. Elles échouent lorsqu’un élément est absent ou vide.

RègleChampBTCorrection
BR-01Identifiant de spécificationBT-24Ajouter CustomizationID avec l’URI Peppol BIS 3.0 exact
BR-02Numéro de factureBT-1Ajouter un élément ID non vide
BR-03Date d’émission de la factureBT-2Ajouter IssueDate au format AAAA-MM-JJ
BR-04Code de devise de la factureBT-5Ajouter DocumentCurrencyCode avec le code ISO 4217
BR-05Nom du vendeurBT-27Ajouter AccountingSupplierParty/Party/PartyName/Name
BR-06Nom de l’acheteurBT-44Ajouter AccountingCustomerParty/Party/PartyName/Name

BR-01 en particulier : la cause la plus fréquente est l’utilisation de l’URI de base EN16931 au lieu de l’URI Peppol BIS 3.0. Ces deux URI se ressemblent mais sont différents :

Incorrect (base EN16931) :

<cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>

Correct (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>

Le validateur vérifie la chaîne exacte. Voir l’introduction à Peppol BIS 3.0 pour comprendre pourquoi c’est important.

BR-CO-10 : la somme des montants de lignes ne correspond pas au total

[BR-CO-10]-Sum of Invoice line net amount (BT-106) = 
sum of Invoice line net amount (BT-131).

Cette règle exige que LegalMonetaryTotal/LineExtensionAmount (BT-106) soit égal à la somme de toutes les valeurs InvoiceLine/LineExtensionAmount (BT-131).

L’échec est presque toujours une erreur d’arrondi. Si vous arrondissez chaque montant de ligne indépendamment avant de les additionner, la somme des valeurs arrondies peut différer de la somme arrondie des valeurs brutes.

Incorrect (arrondi par ligne, puis addition) :

// 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

L’échec est plus visible avec des taux comme 7 % de TVA sur des quantités variables, où les arrondis s’accumulent sur de nombreuses lignes.

Approche correcte : additionner les valeurs brutes non arrondies de toutes les lignes, puis arrondir l’agrégat une seule fois :

var lineNetTotal = invoiceLines.Sum(l => l.Quantity * l.UnitPrice);  // raw
var lineNetTotalRounded = Math.Round(lineNetTotal, 2, MidpointRounding.AwayFromZero);

BR-CO-15 : échec arithmétique du montant de TVA de la facture

[BR-CO-15]-Invoice total VAT amount (BT-110) = 
sum of VAT category tax amount (BT-117).

Le montant total de TVA dans TaxTotal/TaxAmount doit être égal à la somme des valeurs TaxTotal/TaxSubtotal/TaxAmount pour toutes les catégories fiscales.

Pour une facture à taux unique, cela semble trivial, mais des échecs se produisent lorsque :

  • Il y a plusieurs taux de TVA et l’arrondi est appliqué par catégorie plutôt qu’à l’agrégat
  • Une catégorie à taux zéro ou exonérée est présente et son TaxAmount est 0.00 plutôt qu’absent
  • Le TaxAmount au niveau TaxTotal est calculé indépendamment des montants TaxSubtotal

Correction : calculer d’abord toutes les valeurs TaxSubtotal/TaxAmount, les additionner et utiliser cette somme comme valeur TaxTotal/TaxAmount. Ne pas calculer TaxTotal/TaxAmount séparément.

BR-CO-16 : montant dû au paiement

[BR-CO-16]-Amount due for payment (BT-115) = 
Invoice total with VAT (BT-112) - Paid amount (BT-113) + Rounding amount (BT-114).

Si BT-113 (montant payé) et BT-114 (montant d’arrondi) ne sont pas présents, cela se simplifie en BT-115 = BT-112. L’échec survient lorsque PayableAmount et TaxInclusiveAmount diffèrent de plus de la tolérance d’arrondi autorisée.

Cause courante : calculer PayableAmount à partir des montants de ligne arrondis et TaxInclusiveAmount à partir d’un calcul de total séparé qui produit un résultat légèrement différent.

Correction : calculer un total général canonique unique et l’utiliser à la fois pour TaxInclusiveAmount et PayableAmount.

BR-S-08 et BR-S-09 : cohérence du taux et du montant de TVA

[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.

Cette règle regroupe toutes les lignes par taux de TVA et vérifie que le montant imposable dans chaque TaxSubtotal correspond à la somme des lignes à ce taux. Elle échoue lorsque :

  • Une ligne a un taux de TVA sans TaxSubtotal correspondant
  • Un TaxSubtotal existe pour un taux mais aucune ligne n’utilise ce taux
  • Les différences d’arrondi s’accumulent entre les calculs au niveau des lignes et des sous-totaux

Correction : construire les éléments TaxSubtotal dynamiquement à partir des lignes, en regroupant par (code de catégorie TVA, taux TVA), plutôt que de les construire indépendamment.

BR-E-01 / BR-AE-01 : autoliquidation et factures exonérées de TVA

[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...

Les factures avec TVA exonérée (E), autoliquidation (AE) ou taux zéro (Z) nécessitent des structures TaxCategory spécifiques qui diffèrent des factures à taux standard (S).

Erreurs courantes :

  • Utiliser la valeur S pour ID sur toutes les lignes quel que soit le traitement TVA réel
  • Omettre les éléments TaxExemptionReasonCode ou TaxExemptionReason requis pour les catégories exonérées
  • Absence de AccountingSupplierParty/Party/PartyTaxScheme lorsque la facture utilise l’autoliquidation

Pour l’autoliquidation (AE), l’identifiant TVA du schéma fiscal de l’acheteur doit être présent, et l’identifiant TVA du vendeur doit également être présent.

Règles d’extension Peppol spécifiques à l’Allemagne

Les profils Peppol allemands ajoutent des règles au-delà de la base EN16931. Erreurs courantes :

BR-DE-TMP-32 : la date de livraison (BT-72) est obligatoire pour les factures B2G allemandes. Ajouter Delivery/ActualDeliveryDate au format AAAA-MM-JJ.

BR-DE-18 : l’identifiant TVA du vendeur (BT-31) ou un numéro d’immatriculation fiscale (BT-32) doit être présent. L’absence des deux entraîne un rejet. Si le vendeur est exonéré de TVA, fournir BT-32 avec le numéro d’immatriculation fiscale.

BR-DE-16 : la référence acheteur (BT-10, Leitweg-ID) est obligatoire pour les factures B2G allemandes. Le format du Leitweg-ID est validé : il doit correspondre au motif \d{2,12}-\d{4,12}-\d{2}.

Déboguer efficacement

La sortie d’erreur Schematron inclut un emplacement 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>

Utilisez l’emplacement XPath pour naviguer directement vers l’élément défaillant. Pour les règles arithmétiques, ajoutez une sortie de débogage qui enregistre les valeurs brutes avant arrondi pour tracer l’origine de la divergence.

Les fichiers XSLT précompilés des versions GitHub de Peppol BIS sont les artefacts de validation de référence. Exécutez-les avec Saxon HE comme décrit dans la génération de factures Peppol BIS 3.0 en C#. Utiliser la dernière version est important : les ensembles de règles sont mis à jour à chaque version de Peppol BIS, et une règle qui passe sur un ancien XSLT peut échouer sur la version actuelle.

SealDoc et les erreurs de validation

SealDoc exécute la validation Schematron EN16931 et Peppol BIS 3.0 sur chaque facture avant livraison. En cas d’échec de validation, l’API retourne une réponse d’erreur structurée associant chaque échec à son code BR, au BT violé et à l’emplacement XPath dans le document soumis.

Pour les organisations qui déboguent un pipeline de génération de factures existant, le validateur public SealDoc accepte les fichiers de factures UBL et CII, exécute le XSLT Peppol BIS 3.0 actuel et retourne la liste complète des échecs avec des descriptions en langage clair. Les ensembles de règles sont maintenus à jour avec les versions de Peppol BIS, de sorte que le validateur reflète toujours les règles qu’un Access Point destinataire appliquera.


← Back to all articles