Attestwire › Rule reference › BR-CO-17
BR-CO-17 The VAT in each breakdown group must equal base × rate
noun · EN 16931 · fatal · BT-117
base times rate that did not give the VAT you wrote.
Your invoice was refused because, for one VAT rate, the VAT amount shown is not the taxable amount times the rate. The check is done per rate group, with a tolerance of just under one unit of currency, so a failure here is normally a real calculation error rather than rounding. In the standard the group VAT amount is field 117, written BT-117, and BR-CO-17 is the rule that recomputes it.
- Business term
BT-117— VAT category tax amount- Severity
fatal- Applies to
All profiles
The fix
Normalise the rate first, then compute the amount from the normalised rate, so both come from one number. A rate carrying more decimals than the printed rate is the usual cause: 19.000001 stored as a float multiplies out to something that rounds differently from the 19 you print. Round half-up to two decimals, once, at the group, and state the result as that group’s taxAmount in declaredTotals.subtotals.
What the rule requires
Inside a single VAT breakdown group (BG-23), the VAT category tax amount (BT-117) equals the VAT category taxable amount (BT-116) multiplied by the VAT category rate (BT-119) divided by 100, rounded to two decimals.
It is a per-group rule, not a per-line one and not a per-document one. The base is that group’s own taxable amount; the rate is that group’s own rate. Take either from somewhere else on the invoice and the numbers stop meaning anything.
The tolerance is generous: strictly less than one whole unit of currency. It exists so that computing VAT line by line and computing it on the group total both pass; those are two defensible methods that disagree by cents on long invoices.
The rule needs the group’s figures stated, in declaredTotals.subtotals.
VAT category tax amount (BT-117) = VAT category taxable amount (BT-116) x (VAT category rate (BT-119) / 100), rounded to two decimals.
Failing and passing
validateInput({
// ...
lines: [{ id: "1", description: "Consulting", quantity: 10,
unitCode: "HUR", unitPrice: 150,
vatCategory: "S", vatRate: 19 }],
declaredTotals: {
subtotals: [{ category: "S", rate: 19,
taxableAmount: 1500.00,
taxAmount: 270.00 }], // <- BR-CO-17
},
});
// -> { valid: false, errors: [ { rule: "BR-CO-17", field: "BT-117", ... } ] }validateInput({
// ...
declaredTotals: {
subtotals: [{ category: "S", rate: 19,
taxableAmount: 1500.00,
taxAmount: 285.00 }],
},
});
// -> { valid: true, errors: [] }Why it exists
This is the one piece of arithmetic on the invoice that a tax authority will redo. Everything else is addition; this is the calculation of the tax itself. Pinning it to the group’s own base and its own rate means that whatever happened elsewhere on the document (a mis-stated total, a line in the wrong category) the tax charged at each rate can still be checked against the base it was charged on, which is the pair of numbers a VAT return is built from.
What the library returns
The full error returned by @attestwire/en16931. It includes the rule ID,
affected field and suggested correction. Developers can use this object in their application:
{
"rule": "BR-CO-17",
"field": "BT-117",
"severity": "fatal",
"message": "BR-CO-17 requires the VAT category tax amount (BT-117) to equal BT-116 × (BT-119 / 100). This group states 0.00 against a stated taxable amount of 55.55 at 19%, which is 10.55 EUR. The rule's tolerance is a whole unit of currency, exclusive, so this is outside it.",
"fix": "Compute BT-117 from the group's own BT-116 and BT-119, rounded half-up to two decimals. A rate carrying more decimals than BT-119 is written to is the usual cause: normalise the rate first, then compute the amount from the normalised rate, so the two come from one number.",
"example": "\"vatRate\": 19",
"xpath": "/ubl:Invoice/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount",
"docsUrl": "https://attestwire.com/rules/BR-CO-17"
}
xpath is always a UBL path. On a CII invoice, look for the
matching CII field instead.
How our check differs
There is a defect in the reference schematron here, and we reproduce it rather than silently fixing it. BR-CO-17’s first branch is written as round(BT-119) = 0, using XPath’s round-to-nearest-integer. So any rate below 0.5% rounds to zero, and the rule then demands that the tax amount round to zero as well.
A real sub-1% rate on a base large enough to yield half a unit of currency cannot satisfy BR-CO-17 at all. When you hit that case the library says so in the message, because passing a document the receiving validator will reject helps nobody.
As with every rule in this family, it needs stated figures. Omit declaredTotals.subtotals and the library computes the breakdown itself, so there is nothing to check it against.
See also: BR-CO-14 — the group VAT amounts summed into BT-110; BR-S-08 — whether the group’s taxable amount matches the lines behind it.