BR-CO-16Amount due for payment (BT-115) = Invoice total amount with VAT (BT-112) -Paid amount (BT-113) +Rounding amount (BT-114).

Official rule text

The amount due for payment (BT-115) must add up: invoice total with VAT (BT-112) minus any amount already paid (BT-113) plus the rounding amount (BT-114).

Severity
Error
Applies to
CII, UBL
Rule set
v2026-08-31
Checked on

Written and checked against the official KoSIT rule set by Dmytro Yalanskyi, NormAPI.

Why does BR-CO-16 happen?

The expression tests four cases, depending on whether a prepaid amount (BT-113) and a rounding amount (BT-114) are present. With neither, what remains is simply BT-115 = BT-112 — miss that and the payable amount was computed independently instead of derived. Only with a prepaid amount is anything rounded, and there the classic floating-point drift is the usual cause: one cent, invisible until validation.

What the validator checks

The expression the official KoSIT rule set evaluates — not paraphrased, but read from the Schematron file it ships. UBL and CII address different document trees, so the same rule reads differently in each.

UBL
(exists(cbc:PrepaidAmount) and not(exists(cbc:PayableRoundingAmount)) and (xs:decimal(cbc:PayableAmount) = (round((xs:decimal(cbc:TaxInclusiveAmount) - xs:decimal(cbc:PrepaidAmount)) * 10 * 10) div 100))) or (not(exists(cbc:PrepaidAmount)) and not(exists(cbc:PayableRoundingAmount)) and xs:decimal(cbc:PayableAmount) = xs:decimal(cbc:TaxInclusiveAmount)) or (exists(cbc:PrepaidAmount) and exists(cbc:PayableRoundingAmount) and ((round((xs:decimal(cbc:PayableAmount) - xs:decimal(cbc:PayableRoundingAmount)) * 10 * 10) div 100) = (round((xs:decimal(cbc:TaxInclusiveAmount) - xs:decimal(cbc:PrepaidAmount)) * 10 * 10) div 100))) or (not(exists(cbc:PrepaidAmount)) and exists(cbc:PayableRoundingAmount) and ((round((xs:decimal(cbc:PayableAmount) - xs:decimal(cbc:PayableRoundingAmount)) * 10 * 10) div 100) = xs:decimal(cbc:TaxInclusiveAmount)))
CII
(xs:decimal(ram:DuePayableAmount[1]) = xs:decimal(ram:GrandTotalAmount[1]) - xs:decimal(ram:TotalPrepaidAmount[1]) + xs:decimal(ram:RoundingAmount[1])) or ((xs:decimal(ram:DuePayableAmount[1]) = xs:decimal(ram:GrandTotalAmount[1]) + xs:decimal(ram:RoundingAmount[1])) and not(ram:TotalPrepaidAmount)) or ((xs:decimal(ram:DuePayableAmount[1]) = xs:decimal(ram:GrandTotalAmount[1]) - xs:decimal(ram:TotalPrepaidAmount[1])) and not(ram:RoundingAmount)) or ((xs:decimal(ram:DuePayableAmount[1]) = xs:decimal(ram:GrandTotalAmount[1])) and not(ram:TotalPrepaidAmount) and not(ram:RoundingAmount))

Source: rule set v2026-08-31

How do you fix BR-CO-16?

Use decimal arithmetic throughout rather than float or double, and round only when writing the output to two decimal places. Also check whether a prepaid amount (BT-113) is set that your calculation ignores.

In the XML

A UBL fragment. The CII path is named above — same change, different element names.

Fails
<cac:LegalMonetaryTotal>
  <cbc:TaxInclusiveAmount currencyID="EUR">1190.00</cbc:TaxInclusiveAmount>
  <cbc:PrepaidAmount currencyID="EUR">200.00</cbc:PrepaidAmount>
  <cbc:PayableAmount currencyID="EUR">1190.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
Fixed
<cac:LegalMonetaryTotal>
  <cbc:TaxInclusiveAmount currencyID="EUR">1190.00</cbc:TaxInclusiveAmount>
  <cbc:PrepaidAmount currencyID="EUR">200.00</cbc:PrepaidAmount>
  <cbc:PayableAmount currencyID="EUR">990.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>

Download an example invoice that triggers BR-CO-16 ↓

Related rules

NormAPI provides technical validation, not tax or legal advice.