BR-S-08Standard-rated VAT breakdown with nothing standard-rated on the invoice
Mutabiq checks Saudi ZATCA Phase 2 e-invoice XML before you submit it: pre-validation against published ZATCA requirements, not an approval by the authority. This page explains one rule, BR-S-08.
Five checks a month on the Free plan. The file is checked in memory and is never stored.
The message ZATCA prints
[BR-S-08]-In a VAT breakdown (BG-23) where the VAT category code (BT-118) is " Standard rated" the VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum of Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT category codes (BT-151, BT-95, BT-102) are "Standard Rate".
What Mutabiq reports
One entry for each way this rule can be reported.
Reported as
What kind of value was found — empty, not_15_digits and the like — never the value itself.
Standard-rated VAT breakdown with nothing standard-rated on the invoice
Reported ascategory_unuseda breakdown for a category nothing on the invoice uses
What is wrong
The invoice's VAT breakdown has a cac:TaxSubtotal coded S - standard rated - under the VAT scheme, but no line item and no document-level allowance or charge is coded S under the VAT scheme. EN 16931 rule BR-S-08, which ZATCA's checker runs since SDK 3.4.8, checks that the standard-rated taxable amount equals the standard-rated lines less allowances plus charges, and reports a breakdown with nothing to add up. ZATCA flags this as a warning, which does not by itself reject the document.
What to check in your ERP
Either the breakdown should not be there, or the lines it summarises are coded with another category. Check that the category code on each line item (cac:ClassifiedTaxCategory/cbc:ID), and its tax scheme, match the breakdown the line is totalled into; a line recoded as zero-rated, exempt or out of scope while the breakdown stayed S is the usual cause.
Standard-rated VAT breakdown's taxable amount does not match its lines
Reported astaxable_amount_mismatchthe taxable amount does not match the lines
What is wrong
The standard-rated (S) VAT breakdown's taxable amount - the cbc:TaxableAmount of the cac:TaxSubtotal coded S under the VAT scheme, directly under the invoice's own cac:TaxTotal - does not equal the sum of the standard-rated line amounts, plus standard-rated document charges, minus standard-rated document allowances. EN 16931 rule BR-S-08, which ZATCA's checker runs since SDK 3.4.8, compares the two exactly: there is no tolerance and no rounding step, unlike BR-S-09 and BR-CO-17, which allow a band of one currency unit around a category's VAT amount, so a difference of one halalah draws this note. One thing is particular to the standard-rated rule: where the invoice carries more than one standard-rated breakdown - a 15% group and a 5% group, say - ZATCA adds the taxable amounts of all of them under the same cac:TaxTotal before comparing, so the groups are judged together and not one by one, and a breakdown with no taxable amount simply adds nothing. ZATCA flags this as a warning, which does not by itself reject the document. Two things about the sums, because they are narrower than the words suggest: they are taken from the direct children of the document root only, so an allowance attached to an invoice line is not in them; and the contributing lines, charges and allowances are picked up by the category letter alone, with no test that the tax scheme is VAT.
What to check in your ERP
Rebuild the figure by hand from the exported file: add up cbc:LineExtensionAmount on every line whose category is S, add the document-level charges coded S, subtract the document-level allowances coded S, and compare the result with the breakdown's cbc:TaxableAmount, or with the sum of the S breakdowns' amounts if there are several. The frequent causes are a document-level allowance whose own cac:TaxCategory carries a different letter so the rule does not subtract it, a discount applied to the breakdown but not to the line's cbc:LineExtensionAmount, a line net amount rounded differently from the breakdown, and a breakdown carried over from an earlier version of the document after a line changed. Start at the per-category tax summary, which is where a breakdown and its lines stop agreeing.
The clause that runs
Quoted from the validation-rule stylesheet ZATCA publishes, at the file and line named below. The executed guard is what the check runs; the reported test is what it prints when it fails, and the two are not always the same.
Executed guard
count(/*/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory[normalize-space(cbc:ID) = 'S'][cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT'])> 0 and not(exists(../../../cac:AllowanceCharge/cac:TaxCategory[cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']/cbc:ID[normalize-space(.) = 'S']) or exists(../../../cac:InvoiceLine[cac:Item/cac:ClassifiedTaxCategory[cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']/cbc:ID[normalize-space(.) = 'S']])) or not( sum((../../cac:TaxSubtotal[cac:TaxCategory/normalize-space(cbc:ID)='S']/xs:decimal(cbc:TaxableAmount)))=(sum(../../../cac:InvoiceLine[cac:Item/cac:ClassifiedTaxCategory/normalize-space(cbc:ID)='S']/xs:decimal(cbc:LineExtensionAmount) ) + sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=true()][cac:TaxCategory/normalize-space(cbc:ID)='S']/xs:decimal(cbc:Amount)) - sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=false()][cac:TaxCategory/normalize-space(cbc:ID)='S']/xs:decimal(cbc:Amount)) ))
Reported test
count(/*/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory[normalize-space(cbc:ID) = 'S'][cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT'])> 0 and (exists(../../../cac:AllowanceCharge/cac:TaxCategory[cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']/cbc:ID[normalize-space(.) = 'S']) or exists(../../../cac:InvoiceLine[cac:Item/cac:ClassifiedTaxCategory[cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']/cbc:ID[normalize-space(.) = 'S']])) or ((xs:decimal(../cbc:TaxableAmount) =(sum(../../../cac:InvoiceLine[cac:Item/cac:ClassifiedTaxCategory/normalize-space(cbc:ID)='S']/xs:decimal(cbc:LineExtensionAmount)) + sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=true()][cac:TaxCategory/normalize-space(cbc:ID)='S']/xs:decimal(cbc:Amount)) - sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=false()][cac:TaxCategory/normalize-space(cbc:ID)='S']/xs:decimal(cbc:Amount)) )))
As shipped in ZATCA SDK 3.4.8: the copy quoted here is, byte for byte, the file that release ships. The date in the file name is the name ZATCA gives the file; the rules in it are those of SDK 3.4.8.
A worked example
A synthetic document from the measured test corpus that trips this rule, shown where it differs from one that passed. Mutabiq's report names the class of the value, never the value itself.
Document
bad-113-s-taxable-amount-off-by-hundredth.xml
Mutabiq's verdict
Passed
Reported as
taxable_amount_mismatchthe taxable amount does not match the lines