ZATCA rechaza las facturas con códigos de error escuetos, y decodificarlos bajo presión de deadline es brutal. Aquí van los siete principales que vemos en producción, por frecuencia, con un fix probado para cada uno.
1. ENT_ICV-001 — Invoice Counter Value fuera de secuencia
El ICV debe crecer monótonamente por dispositivo. La causa casi siempre es emisión paralela desde dos procesos contra el mismo EGS. Fix: serializa la asignación del ICV detrás de una única fuente de verdad (una secuencia de BBDD vale).
2. ENT_PIH-002 — Previous Invoice Hash no coincide
El hash que enviaste como anterior no coincide con el que ZATCA tiene registrado. Causa: alguien reenvió una factura vieja o la caché local se quedó atrás. Fix: consulta a Fatoora el último hash clearado y reseméa tu cadena.
3. KSA-25 — Código de categoría fiscal ausente o inválido
Cada línea necesita un código UNCL5305: S, Z, E, O o AE. Resbalón habitual: dejarlo vacío para líneas a tasa cero. Fix: emite Z explícitamente, no lo omitas.
4. KSA-12 — Número de VAT del vendedor mal formado
Los números de registro VAT saudíes tienen 15 dígitos, empiezan por 3 y terminan en checksum. Error común: enviar el Commercial Registration Number de 10 dígitos en su lugar. Fix: lee el VAT desde la tabla tax_registrations con kind='VAT', no del campo de licencia comercial.
5. CLOCK_DRIFT — IssueDateTime fuera de sincronización por más de 30 segundos
Drift del reloj del servidor. Fix: sincronización NTP a pool.ntp.org cada minuto, en cada host que emita facturas.
6. KSA-08 — Factura estándar sin VAT del comprador
Las facturas B2B en KSA exigen el VAT (TaxID) del comprador. Las simplificadas (B2C) no. Fix: bifurca por InvoiceTypeCode en tu serializador (388 = estándar, 388 con subtype 02 = simplificada).
7. KSA-19 — Importe de impuestos inconsistente con totales de línea
La suma de los impuestos por línea ≠ TaxTotal. La causa casi siempre es redondear a mitad de cálculo. Fix: redondea solo el subtotal final por tasa (banker's rounding), nunca por línea.