This invoice carries a charge, and the published validation rules refuse every charge
Reported ascharge_indicator_truethe indicator marks a charge
What is wrong
A cac:AllowanceCharge in this document has a cbc:ChargeIndicator of true, which marks it as a charge rather than an allowance; the value 1 means the same thing and is reported the same way. ZATCA's rule BR-KSA-F-02 requires every charge indicator in the document to be false, wherever the block sits - at document level, on an invoice line, on a line's price, under cac:DeliveryTerms, under a billing reference line - so a charge is refused in every place UBL allows one. Measured: a document with a single document-level charge, written in the shape ZATCA's own XML Implementation Standard prints as its example of one, comes back carrying BR-KSA-F-02 and nothing else. This is the point at which two published ZATCA documents contradict each other, and you need to know that before you go looking for a defect in your mapping. The XML Implementation Standard v1.2 of 19 May 2023 is built on charges being permitted: its change log lists the inclusion of the charges specification as a headline addition of that version (page 1), section 9.2 gives a calculation formula that sums the cac:AllowanceCharge amounts whose indicator is true (page 16), section 11.2.8 supplies a recommended code list for the reason for a charge (page 34), and the worked invoice in it carries an indicator of true at line level (page 18) and again at document level (page 26). The same standard's own rule table then restates this very rule with its polarity reversed: section 13.3.5, page 68, says the indicator must equal false or True respectively. The published validation rule files accept only false. The checker is what decides, because it is what the document is put through and what accepts or refuses it. So a system that implemented the 2023 charges specification correctly, to the letter, is refused - and that is what has happened here. Nothing in your mapping is wrong in the sense of disagreeing with a published document; it disagrees with the other published document.
What to check in your ERP
Settle first which of the two this block really is. If the amount is a discount, the indicator is the wrong way round and setting it to false clears the note; the usual causes are an export template that writes true on every cac:AllowanceCharge it emits, and a discount stored as a negative amount whose sign is used to set the indicator. If it genuinely is a charge, no value you can put in this block will clear the note, so the question becomes where else the amount can go. Two routes exist and they answer different needs. The measured one is cac:FreightAllowanceCharge under cac:Delivery/cac:Shipment. It is the same UBL type as cac:AllowanceCharge, with the same mandatory indicator, under a different element name, and both published templates match on the name - so a freight charge of twenty-five riyals with an indicator of true was measured returning no findings at all, with every stage of the check passing. cac:ExtraAllowanceCharge and cac:ServiceAllowanceCharge sit outside both rules for the same reason. Read the limit along with it: in that measured document the amount does not enter the sum of line amounts, the tax-exclusive total, the payable amount or the VAT breakdown, so this records a delivery charge on the document without billing it or taxing it. It is a place to put a freight charge, not a general home for any charge. The second route is to bill the charge as an ordinary invoice line of its own, with its own item name, quantity, tax category and rate. That is what puts the amount inside the totals and the VAT breakdown where it is taxed, and it is the route to take when the customer is genuinely being charged. One thing to avoid while you work on this. A document-level charge written beside a document-level allowance was measured breaking the check outright: it returns a stack trace from the EN 16931 stage and no rule code at all, so you get no diagnosis of anything in the document. Two allowance blocks at line level, one on each of two lines, end the KSA-side checks the same way. Change one thing at a time, and keep a single block at each level.