BR-CL-19 The document level allowance at allowances[0] carries the reason code "FC", which is not in UNCL 5189, the list BR-CL-19 admits for allowance reason codes
The document level allowance at allowances[0] carries the reason code "FC", which is not in UNCL 5189, the list BR-CL-19 admits for allowance reason codes. It *is* in the charge list — and that is the trap this rule exists to catch. EN 16931 uses two different code lists for the two directions: allowance reason codes come from UNCL 5189, charge reason codes from UNCL 7161. Moving an entry between the allowances and charges arrays without changing its code turns a valid document into a rejected one, because the same string means something else in the other list. The whole list is short enough to read: "41", "42", "60", "62", "63", "64", "65", "66", "67", "68", "70", "71", "88", "95", "100", "102", "103", "104", "105" — nineteen codes, and none of them is a free-text escape hatch.
This rule is implemented and its error payload below is real, but the long-form write-up — normative text, worked example, divergence note — is not written yet. Everything the library knows about this rule is on this page. Ask and we will prioritise it.
- Business term
BT-98- Severity
fatal
What the library returns
The exact object in result.errors when this rule fires.
Generated by running @attestwire/en16931, not transcribed:
{
"rule": "BR-CL-19",
"field": "BT-98",
"severity": "fatal",
"message": "The document level allowance at allowances[0] carries the reason code \"FC\", which is not in UNCL 5189, the list BR-CL-19 admits for allowance reason codes. It *is* in the charge list — and that is the trap this rule exists to catch. EN 16931 uses two different code lists for the two directions: allowance reason codes come from UNCL 5189, charge reason codes from UNCL 7161. Moving an entry between the allowances and charges arrays without changing its code turns a valid document into a rejected one, because the same string means something else in the other list. The whole list is short enough to read: \"41\", \"42\", \"60\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"70\", \"71\", \"88\", \"95\", \"100\", \"102\", \"103\", \"104\", \"105\" — nineteen codes, and none of them is a free-text escape hatch.",
"fix": "Either set allowances[0].reasonCode to a UNCL 5189 code, or remove it and describe the allowance in allowances[0].reason instead — free text on its own satisfies BR-33 and BR-CO-21, and is better than a code that means the wrong thing.",
"example": "\"allowances\": [{ \"amount\": 15.00, \"vatCategory\": \"S\", \"vatRate\": 19, \"reasonCode\": \"95\", \"reason\": \"Discount\" }]",
"xpath": "/ubl:Invoice/cac:AllowanceCharge[1]/cbc:AllowanceChargeReasonCode",
"docsUrl": "https://attestwire.com/rules/BR-CL-19"
}
xpath locates the element in the generated UBL document,
which is where a KoSIT or Peppol validator will report the same problem.
A passing value
"allowances": [{ "amount": 15.00, "vatCategory": "S", "vatRate": 19, "reasonCode": "95", "reason": "Discount" }]The fix
Either set allowances[0].reasonCode to a UNCL 5189 code, or remove it and describe the allowance in allowances[0].reason instead — free text on its own satisfies BR-33 and BR-CO-21, and is better than a code that means the wrong thing.