BR-CO-15No VAT total is stated in the invoice's own currency
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-CO-15.
Five checks a month on the Free plan. The file is checked in memory and is never stored.
The message ZATCA prints
[BR-CO-15]-Invoice total amount with VAT (BT-112) = Invoice total amount without VAT (BT-109) + Invoice total VAT amount (BT-110).
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.
No VAT total is stated in the invoice's own currency
Reported asno_tax_amount_in_document_currencyno VAT total in the invoice currency
What is wrong
None of the document-level cac:TaxTotal blocks carries a cbc:TaxAmount whose currencyID attribute matches the invoice's cbc:DocumentCurrencyCode. EN 16931 rule BR-CO-15, which ZATCA runs, requires at least one VAT total denominated in the document's own currency before it will check the arithmetic at all. This is not a problem with your figures: the amounts may be perfectly correct and still fail here, because what is wrong is the currency they are labelled with.
What to check in your ERP
Compare two things: the code in cbc:DocumentCurrencyCode and the currencyID attribute on the document-level cbc:TaxAmount. They must be the same code. On a domestic invoice both are SAR. This normally means the currency is configured in two places in your system - one for the document and one for the amounts - and only one of them has been set. It also appears when the document currency itself is not a code ZATCA recognises, in which case nothing can match it and that is the defect to fix first.
Tax-inclusive total is missing from the document totals
Reported astotal_missingthe total is missing
What is wrong
The document totals block, cac:LegalMonetaryTotal, carries no cbc:TaxInclusiveAmount. That field is the invoice total including VAT (BT-112), and EN 16931 rule BR-CO-15, which ZATCA runs, requires it to equal the tax-exclusive total plus the VAT subtotals. With no value written there is nothing to compare and the rule fails.
What to check in your ERP
Check the export template in your e-invoicing module: the totals block must carry the amount before VAT, the amount including VAT and the payable amount, and this is the one most often left out because it duplicates the payable amount on an invoice with nothing prepaid. The element is required by the UBL schema as well, so a document in this state is usually reported here and by the schema check together.
Tax-inclusive total does not equal the total before VAT plus the VAT
Reported asnot_exclusive_plus_subtotalsnot the total before VAT plus the VAT
What is wrong
The cbc:TaxInclusiveAmount in cac:LegalMonetaryTotal is not the cbc:TaxExclusiveAmount plus the sum of the VAT breakdown amounts. EN 16931 rule BR-CO-15, which ZATCA runs, adds the tax-exclusive total to the cbc:TaxAmount of every cac:TaxSubtotal, rounds the result to two decimals and requires an exact match.
What to check in your ERP
The three figures usually come from different places, so check which one is out rather than adjusting the total to fit. A frequent cause is VAT computed per line and rounded there, while the breakdown is computed per category: ZATCA adds first and rounds once, so per-line rounding can differ by a hundredth or two. Another is a document-level discount applied after the VAT was computed. Note that this rule reads the VAT breakdown entries, so a document whose totals are right but whose breakdown is incomplete fails here too.
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
not(every $Currency in cbc:DocumentCurrencyCode satisfies (count(cac:TaxTotal/xs:decimal(cbc:TaxAmount[@currencyID=$Currency])) >= 1) and (cac:LegalMonetaryTotal/xs:decimal(cbc:TaxInclusiveAmount) = round( (cac:LegalMonetaryTotal/xs:decimal(cbc:TaxExclusiveAmount) + sum(cac:TaxTotal/cac:TaxSubtotal/xs:decimal(cbc:TaxAmount))) * 10 * 10) div 100))
Reported test
every $Currency in cbc:DocumentCurrencyCode satisfies (count(cac:TaxTotal/xs:decimal(cbc:TaxAmount[@currencyID=$Currency])) >= 1) and (cac:LegalMonetaryTotal/xs:decimal(cbc:TaxInclusiveAmount) = round( (cac:LegalMonetaryTotal/xs:decimal(cbc:TaxExclusiveAmount) + sum(cac:TaxTotal/cac:TaxSubtotal/xs:decimal(cbc:TaxAmount))) * 10 * 10) div 100)
Evaluated against
/ubl:Invoice | /cn:CreditNote
Source
vendor/zatca/schematron/CEN-EN16931-UBL.xsl:775
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.