ZATCA 退回发票时只丢出简短的错误码,在 deadline 压力下解码这些码非常折磨。下面是我们在生产里看到最多的七个,按频次排,每条都给出经过验证的修复方案。
1. ENT_ICV-001 —— 发票计数器值乱序
ICV 必须在每台设备上单调递增。原因几乎总是同一个 EGS 上有两个进程在并行开票。修复:把 ICV 的分配串行化到一个唯一来源后面(数据库序列就够用)。
2. ENT_PIH-002 —— Previous Invoice Hash 不匹配
你提交的「上一张」哈希和 ZATCA 那边记录的对不上。原因:有人重新提交了一张旧发票,或者本地缓存掉队了。修复:向 Fatoora 查询最新的 cleared 哈希,然后给你的链重新打种子。
3. KSA-25 —— 税务类别码缺失或无效
每行明细都需要一个 UNCL5305 类别码:S、Z、E、O 或 AE。常见疏忽:零税率行直接留空。修复:零税率行就显式写 Z,而不是省略。
4. KSA-12 —— 卖家 VAT 号格式错误
沙特 VAT 注册号是 15 位、以 3 开头、末位是校验位。常见错误:把 10 位的工商登记号当 VAT 提交。修复:从 tax_registrations 表里按 kind='VAT' 取号,而不是从工商执照字段。
5. CLOCK_DRIFT —— IssueDateTime 与参考时钟相差超过 30 秒
服务器时钟漂移。修复:每个开票主机每分钟与 pool.ntp.org 做一次 NTP 同步。
6. KSA-08 —— 标准发票缺少买家 VAT
沙特 B2B 发票必须带买家 VAT(TaxID),简化(B2C)发票则不需要。修复:在序列化器里基于 InvoiceTypeCode 分支(388 = 标准,388 + subtype 02 = 简化)。
7. KSA-19 —— 税额与明细合计不一致
明细税额之和 ≠ TaxTotal。原因几乎总是中途做了四舍五入。修复:只对每个税率的最终 subtotal 做一次四舍五入(银行家舍入),不要逐行舍入。