einvoice / EN 16931 / XRechnung rule reference

BR-DE-14

So beheben Sie den Fehler

Das Element "VAT category rate" (BT-119) muss übermittelt werden.

Deutsche Fassung: Amtlicher KoSIT-Text (official KoSIT assert text).

VAT category rate (BT-119) must be transmitted (non-empty) in every top-level VAT breakdown row.

Requires
VAT category rate (BT-119) must be transmitted (non-empty) in every top-level VAT breakdown row.
Business terms
BT-119
Syntax
Binds the UBL-2.1 Invoice / CreditNote syntax and the UN/CEFACT-CII syntax
Location (UBL-2.1 path)
/ubl:Invoice/cac:TaxTotal/cac:TaxSubtotal
Fix (Deutsch)
Ergänzen Sie das erforderliche Element bei `/ubl:Invoice/cac:TaxTotal/cac:TaxSubtotal`: Das Element "VAT category rate" (BT-119) muss übermittelt werden.
Fix
Add the required element at `/ubl:Invoice/cac:TaxTotal/cac:TaxSubtotal`: VAT category rate (BT-119) must be transmitted (non-empty) in every top-level VAT breakdown row.
Severity
fatal
Provenance source
xrechnung-ubl
Provenance assert

Das Element "VAT category rate" (BT-119) muss übermittelt werden.

The Location above is a UBL-2.1 path, and no UN/CEFACT-CII path for this rule is published here; Fix and Fix (Deutsch), verbatim from remediation_catalog.json and not reworded here; the UN/CEFACT-CII binding of this rule is differentially proven against the official KoSIT XRechnung 2.5.0 (XRechnung 3.0.2) Schematron.

Korrektur prüfen: Laden Sie die geänderte Rechnung in den Browser-Validator unter /einvoice/validate/ — er führt dieselbe Engine lokal im Browser aus, ohne Upload, und meldet BR-DE-14 nicht mehr, sobald die Korrektur greift.

Where to check the fix: paste the corrected invoice into the browser validator at /einvoice/validate/ — it runs this same engine locally in your browser, with no upload, and stops reporting BR-DE-14 once the edit lands.

The same invoice, failing and fixed

Neither block below is hand-written. Both are cut verbatim from a vendored KoSIT test instance — one this engine already grades clean under --profile xrechnung — at the element this rule's own Schematron context names. The failing variant is that element with one mechanical change, spliced back into the whole instance and re-graded: it is published only because the engine reported BR-DE-14 for the changed document and did not report it for the untouched one. Both official XRechnung syntaxes are shown, because the same rule id is asserted in each: UBL (the KoSIT default) and UN/CEFACT CII (the syntax inside a ZUGFeRD / Factur-X PDF).

UBL — fails

The cac:TaxSubtotal element of the vendored UBL instance 01.06_minimal_test_ubl.xml, with exactly one change: its cac:TaxCategory/cbc:Percent child is emptied — the element stays in the document, its text is gone.

<cac:TaxSubtotal>
  <cbc:TaxableAmount currencyID="EUR">3986.34</cbc:TaxableAmount>
  <cbc:TaxAmount currencyID="EUR">757.41</cbc:TaxAmount>
  <cac:TaxCategory>
    <cbc:ID>S</cbc:ID>
    <cbc:Percent></cbc:Percent>
    <cac:TaxScheme>
      <cbc:ID>VAT</cbc:ID>
    </cac:TaxScheme>
  </cac:TaxCategory>
</cac:TaxSubtotal>

UBL — passes

<cac:TaxSubtotal>
  <cbc:TaxableAmount currencyID="EUR">3986.34</cbc:TaxableAmount>
  <cbc:TaxAmount currencyID="EUR">757.41</cbc:TaxAmount>
  <cac:TaxCategory>
    <cbc:ID>S</cbc:ID>
    <cbc:Percent>19</cbc:Percent>
    <cac:TaxScheme>
      <cbc:ID>VAT</cbc:ID>
    </cac:TaxScheme>
  </cac:TaxCategory>
</cac:TaxSubtotal>

An element that is present but empty is not a pass here: the vendored assert is cac:TaxCategory/cbc:Percent[boolean(normalize-space(.))], and its normalize-space() test rejects an empty or whitespace-only value exactly as it rejects a missing element.

What the engine reports for the failing UBL invoice

{
  "element": "cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent",
  "field": "cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent",
  "fix_hint": "Add the required element at `/ubl:Invoice/cac:TaxTotal/cac:TaxSubtotal`: VAT category rate (BT-119) must be transmitted (non-empty) in every top-level VAT breakdown row.",
  "location": "/ubl:Invoice/cac:TaxTotal/cac:TaxSubtotal",
  "message": "The element 'VAT category rate' (BT-119) must be transmitted.",
  "rule": "BR-DE-14",
  "severity": "fatal",
  "terms": [
    "BT-119"
  ],
  "title": "VAT category rate (BT-119) must be transmitted (non-empty) in every top-level VAT breakdown row."
}

Rule ids reported for the failing document: BR-CO-17 BR-DE-14 BR-S-09. For the corrected document: none. (BR-DE-TMP-32, an information-level finding about the delivery date, is reported for both documents and is not affected by this edit.)

CII — fails

The ram:ApplicableTradeTax element of the vendored CII instance 01.06_minimal_test_uncefact.xml, with exactly one change: its ram:RateApplicablePercent child is emptied — the element stays in the document, its text is gone.

<ram:ApplicableTradeTax>
<!-- BT-117 -->
    <ram:CalculatedAmount>757.41</ram:CalculatedAmount>
<!-- BT-118 -->
    <ram:TypeCode>VAT</ram:TypeCode>
<!-- BT-116 -->
    <ram:BasisAmount>3986.34</ram:BasisAmount>
<!-- BT-118 -->
    <ram:CategoryCode>S</ram:CategoryCode>
<!-- BT-119 -->
    <ram:RateApplicablePercent></ram:RateApplicablePercent>
</ram:ApplicableTradeTax>

CII — passes

<ram:ApplicableTradeTax>
<!-- BT-117 -->
    <ram:CalculatedAmount>757.41</ram:CalculatedAmount>
<!-- BT-118 -->
    <ram:TypeCode>VAT</ram:TypeCode>
<!-- BT-116 -->
    <ram:BasisAmount>3986.34</ram:BasisAmount>
<!-- BT-118 -->
    <ram:CategoryCode>S</ram:CategoryCode>
<!-- BT-119 -->
    <ram:RateApplicablePercent>19</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>

The CII run reports BR-DE-14 at ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax/ram:RateApplicablePercent and, for the corrected document, none — the same rule id, a different syntax and a different element path.

What conformant invoices actually carry here

UBL — every distinct cbc:Percent value at cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent across the 43 vendored UBL instances this engine grades clean, 31 of which carry the element:

CII — every distinct ram:RateApplicablePercent value at rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax/ram:RateApplicablePercent across the 39 vendored CII instances this engine grades clean, 28 of which carry the element:

EN 16931 itself does not ask for this element — the German CIUS is what makes it mandatory, and the vendored CEN corpus shows the gap. Of the 41 CEN EN 16931 instances this engine grades clean under --profile en16931, 19 carry cbc:Percent here and 22 do not. Re-graded under --profile xrechnung, ubl-tc434-example7.xml — a clean EN 16931 invoice — reports BR-DE-14 BR-DE-15 BR-DE-21, BR-DE-14 among them.

The 5 distinct values that corpus carries at this element, most common first:

Note what those lists do not show: the assert tests non-emptiness and nothing else, so every value above passes. XRechnung places no constraint on the shape of this value, so BR-DE-14 cannot catch an exporter that writes the wrong field into it.

The rule as the vendored Schematron states it

UBL context
/ubl:Invoice/cac:TaxTotal/cac:TaxSubtotal | /cn:CreditNote/cac:TaxTotal/cac:TaxSubtotal
UBL assert
cac:TaxCategory/cbc:Percent[boolean(normalize-space(.))]
CII context
/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax
CII assert
ram:RateApplicablePercent[boolean(normalize-space(.))]
Artifact
corpus/xrechnung-schematron/schematron/ubl/XRechnung-UBL-validation.sch

Reproduce it yourself: put the failing block into 01.06_minimal_test_ubl.xml in place of its cac:TaxSubtotal element and run einvoice validate invoice.xml --profile xrechnung --format json, or paste the file into the browser validator, which runs the same engine locally with no upload.

Everything here is free and open source — pick up whatever helps, at your own pace: