ZATCA rejette les factures avec des codes d'erreur laconiques, et les décoder sous pression de deadline est brutal. Voici les sept que nous voyons le plus en production, classés par fréquence, avec un fix éprouvé pour chacun.
1. ENT_ICV-001 — Invoice Counter Value hors séquence
L'ICV doit augmenter de façon monotone par appareil. La cause est presque toujours une émission parallèle depuis deux processus sur le même EGS. Fix : sérialisez l'attribution de l'ICV derrière une source de vérité unique (une séquence de base de données suffit).
2. ENT_PIH-002 — Previous Invoice Hash ne correspond pas
Le hash que vous avez soumis comme précédent ne correspond pas à celui que ZATCA a en mémoire. Cause : quelqu'un a re-soumis une vieille facture ou le cache local a pris du retard. Fix : interrogez Fatoora pour le dernier hash cleared et réamorcez votre chaîne.
3. KSA-25 — Code de catégorie de taxe manquant ou invalide
Chaque ligne d'item a besoin d'un code de catégorie UNCL5305 : S, Z, E, O ou AE. Glissade fréquente : le laisser vide pour les lignes à taux zéro. Fix : émettez Z explicitement, ne l'omettez pas.
4. KSA-12 — Numéro de TVA vendeur malformé
Les numéros de TVA saoudiens font 15 chiffres, commencent par 3 et finissent par un checksum. Erreur fréquente : soumettre le Commercial Registration Number à 10 chiffres à la place. Fix : lisez la TVA depuis la table tax_registrations avec kind='VAT', pas depuis le champ licence commerciale.
5. CLOCK_DRIFT — IssueDateTime désynchronisé de plus de 30 secondes
Drift d'horloge serveur. Fix : synchro NTP avec pool.ntp.org toutes les minutes, sur chaque hôte qui émet des factures.
6. KSA-08 — Facture standard sans TVA acheteur
Les factures B2B en KSA exigent le numéro de TVA (TaxID) de l'acheteur. Les simplifiées (B2C) non. Fix : branchez sur l'InvoiceTypeCode dans votre sérialiseur (388 = standard, 388 avec subtype 02 = simplifiée).
7. KSA-19 — Montant de taxe incohérent avec les totaux de ligne
La somme des taxes par ligne ≠ TaxTotal. La cause est presque toujours l'arrondi en cours de calcul. Fix : arrondissez uniquement le sous-total final par taux (banker's rounding), jamais par ligne.