Règle EN 16931 · calculs

BR-CO-10 — la somme des lignes ne tombe pas juste

C'est le rejet le plus courant, et le plus déroutant : la facture est correcte à l'écran, les montants sont ceux attendus, et pourtant la validation échoue sur une égalité arithmétique.

Ce que la règle exige. Le montant total des lignes du document (BT-106) doit être égal à la somme des montants nets de chaque ligne de facture (BT-131). Égalité exacte, sans tolérance.

À quoi ça ressemble

Dans le rapport de validation, la règle apparaît sous une forme proche de :

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

Aucune valeur n'est affichée : il faut aller comparer soi-même le total déclaré et la somme réelle des lignes du XML.

Les trois causes réelles

1. Des montants manipulés en virgule flottante

De loin la première cause. Les montants d'une facture sont des décimaux ; les représenter en float ou double introduit des écarts invisibles à l'affichage mais bien présents dans le XML.

>>> 0.1 + 0.2
0.30000000000000004

>>> round(19.99 * 3, 2)      # 59.97 à l'écran…
59.97
>>> 19.99 * 3               # …mais pas dans le fichier
59.970000000000006

Le PDF affiche 59,97 parce que la mise en forme arrondit. Le XML, lui, transporte la valeur exacte, et le Schematron compare la valeur exacte.

Correction : des décimaux de bout en bout — Decimal en Python, BCMath ou des entiers de centimes en PHP, une bibliothèque décimale en JavaScript. Et sérialiser les montants sous forme de chaînes dans votre JSON ("450.00", pas 450.0) pour ne pas repasser par un flottant à la traversée.

2. Un total historisé qui ne suit plus les lignes

Beaucoup de bases stockent un total_ht calculé au moment de l'émission. Si une ligne est corrigée ensuite — une quantité, une remise — sans recalcul du total, les deux divergent. La facture reste cohérente dans l'application, qui affiche le total stocké, et devient invalide dans le XML, qui porte les deux.

Correction : recalculer le total à partir des lignes au moment de construire le document, plutôt que de transmettre la valeur stockée.

3. Une remise ou une charge rangée au mauvais niveau

Une remise commerciale appliquée au pied de facture n'est pas une remise de ligne. Si on la soustrait du total des lignes au lieu de la déclarer comme remise au niveau document, BR-CO-10 tombe — et, si on la déclare deux fois, c'est BR-CO-13 qui tombe à sa place.

Correction : une remise globale se déclare au niveau document ; le total des lignes reste la somme brute des lignes.

Arrondir plus fort n'est pas une correction

Le réflexe fréquent est d'ajouter un round(…, 2) sur le total. Ça fait parfois passer la règle, et ça déplace le problème : la ventilation de TVA (BR-S-08) ou le total TTC (BR-CO-15) échouera ensuite, cette fois-ci d'un centime inexplicable. La cohérence doit venir du calcul, pas de l'arrondi.

Vérifier que c'est corrigé

  1. Extraire le XML embarqué et comparer à la main le total des lignes et la somme des montants nets — ou plus simplement :
  2. déposer le PDF sur le validateur Factur-X, qui rejoue XSD et Schematron et liste les règles restantes.

Un contrôle qui ne prouve rien : ouvrir le PDF et lire les montants. Ils seront justes — l'écart vit dans le XML, pas dans le rendu.

Ne plus se poser la question

Quand la facture est générée par notre API, les totaux et la ventilation de TVA sont recalculés côté serveur à partir des lignes : la cohérence n'est pas quelque chose que votre code doit garantir. Et si le document échouait malgré tout à la validation, il ne serait pas livré — l'API répond 422 avec le rapport, jamais un PDF invalide.

Tester votre facture

Déposez le PDF rejeté : vous saurez en quelques secondes s'il reste d'autres règles en échec derrière celle-ci.

Ouvrir le validateur Obtenir une clé API