Rule reference

BR-CL-20 The document level charge at charges[0] carries the reason code "95", which is not in UNCL 7161, the list BR-CL-20 admits for charge reason codes

The document level charge at charges[0] carries the reason code "95", which is not in UNCL 7161, the list BR-CL-20 admits for charge reason codes. It *is* in the allowance 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 list holds 178 codes, far more than the allowance list, because a charge can be almost any service added to a supply. The ones most often wanted: "FC" freight service, "PC" packing, "IAA" insurance, "ABK" miscellaneous, "SH" handling. Note "IN" is not among them — the plain two-letter abbreviation for insurance is exactly the kind of near-miss this rule exists to catch.

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-105
Severity
fatal

What the library returns

The exact object in result.errors when this rule fires. Generated by running @attestwire/en16931, not transcribed:

TeachingError
{
  "rule": "BR-CL-20",
  "field": "BT-105",
  "severity": "fatal",
  "message": "The document level charge at charges[0] carries the reason code \"95\", which is not in UNCL 7161, the list BR-CL-20 admits for charge reason codes. It *is* in the allowance 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 list holds 178 codes, far more than the allowance list, because a charge can be almost any service added to a supply. The ones most often wanted: \"FC\" freight service, \"PC\" packing, \"IAA\" insurance, \"ABK\" miscellaneous, \"SH\" handling. Note \"IN\" is not among them — the plain two-letter abbreviation for insurance is exactly the kind of near-miss this rule exists to catch.",
  "fix": "Either set charges[0].reasonCode to a UNCL 7161 code, or remove it and describe the charge in charges[0].reason instead — free text on its own satisfies BR-38 and BR-CO-22, and is better than a code that means the wrong thing.",
  "example": "\"charges\": [{ \"amount\": 15.00, \"vatCategory\": \"S\", \"vatRate\": 19, \"reasonCode\": \"FC\", \"reason\": \"Freight service\" }]",
  "xpath": "/ubl:Invoice/cac:AllowanceCharge[1]/cbc:AllowanceChargeReasonCode",
  "docsUrl": "https://attestwire.com/rules/BR-CL-20"
}

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

the shape this field expects
"charges": [{ "amount": 15.00, "vatCategory": "S", "vatRate": 19, "reasonCode": "FC", "reason": "Freight service" }]

The fix

Either set charges[0].reasonCode to a UNCL 7161 code, or remove it and describe the charge in charges[0].reason instead — free text on its own satisfies BR-38 and BR-CO-22, and is better than a code that means the wrong thing.

Arrived from a stack trace? The docsUrl on every error links straight here. Something wrong on this page — tell us.