Skip to content

PEPPOL-EN16931-R046Fix a net price that is not the gross price minus the price discount

When a line price states a gross price, the net price must equal the gross price minus the price discount exactly. There is no tolerance.

Peppol BIS BillingFatal: the document is invalidLines and pricesAllowances and charges

The short answer

PEPPOL-EN16931-R046 fails when the cac:AllowanceCharge inside cac:Price gives a gross price in cbc:BaseAmount, and cbc:PriceAmount is not exactly that gross price minus the discount in cbc:Amount. Correct whichever of the three figures is wrong so that net price = gross price - discount.

The comparison is exact. A difference in the fourth decimal place fails.

What the rule checks

The rule runs on the cac:AllowanceCharge inside cac:Price, not on line-level or document-level allowances.

If that element has no cbc:BaseAmount, no gross price has been stated and the rule passes without comparing anything. Confirmed with the validator.

Otherwise the sibling cbc:PriceAmount must equal cbc:BaseAmount minus cbc:Amount. The values are compared as decimals with no rounding and no tolerance. Against a discount of 2.5 and a net price of 12.5, the validator rejects a gross price of 15.01, 14.99 and 15.0001.

Because the comparison is numeric, trailing zeros do not matter: 12.50 and 15.00 behave the same as 12.5 and 15.

TermMeaningUBL element
BT-146Item net pricecac:InvoiceLine/cac:Price/cbc:PriceAmount
BT-147Item price discountcac:InvoiceLine/cac:Price/cac:AllowanceCharge/cbc:Amount
BT-148Item gross pricecac:InvoiceLine/cac:Price/cac:AllowanceCharge/cbc:BaseAmount

How an integration ends up here

Possible causes, from the shape of the rule rather than from measured usage:

  • The net price is rounded to two decimals while the gross price and discount keep more, or the other way round, so the subtraction no longer lands exactly.
  • The discount is calculated as a percentage of the gross price and rounded, and the net price is computed separately from unrounded figures.
  • The gross price comes from the current price list while the net price and discount come from the order, and the list price has changed since.
  • A discount for the whole line is written into the price-level allowance, which is a discount per price base quantity.
  • Binary floating point subtraction produces a value such as 12.499999 that is serialised as it stands.

How to fix it

  1. For the line in the finding, read cbc:PriceAmount, and the cbc:BaseAmount and cbc:Amount of the allowance inside cac:Price.
  2. Treat the net price as the anchor: it is the figure the line net amount is calculated from. If the line amounts are right, the gross price or the discount is the value to correct.
  3. Derive one figure from the other two in decimal arithmetic rather than sourcing all three independently, for example discount = gross price - net price, and serialise with enough decimals that nothing is lost. Prices are not limited to two decimals by this rule.
  4. If the source system cannot supply a reliable gross price, leave out the price-level cac:AllowanceCharge and send the net price alone. The line is still valid without it.

The recorded example has a net price of 12.5 and a price discount of 2.5.

Failing: gross price 16 - discount 2.5 = 13.5, net price sent 12.5
Corrected: gross price 15 - discount 2.5 = 12.5, net price sent 12.5

Validate your corrected invoice

Before and after

These are fragments, not complete documents. The complete synthetic documents they come from are linked below.

Fragment of the failing invoice line: 16 minus 2.5 is 13.5, not the net price of 12.5

<cac:Price>
  <cbc:PriceAmount currencyID="GBP">12.5</cbc:PriceAmount>
  <cbc:BaseQuantity unitCode="C62">1</cbc:BaseQuantity>
  <cac:AllowanceCharge>
    <cbc:ChargeIndicator>false</cbc:ChargeIndicator>
    <cbc:Amount currencyID="GBP">2.5</cbc:Amount>
    <cbc:BaseAmount currencyID="GBP">16</cbc:BaseAmount>
  </cac:AllowanceCharge>
</cac:Price>

Fragment of the corrected invoice line: 15 minus 2.5 is 12.5

<cac:Price>
  <cbc:PriceAmount currencyID="GBP">12.5</cbc:PriceAmount>
  <cbc:BaseQuantity unitCode="C62">1</cbc:BaseQuantity>
  <cac:AllowanceCharge>
    <cbc:ChargeIndicator>false</cbc:ChargeIndicator>
    <cbc:Amount currencyID="GBP">2.5</cbc:Amount>
    <cbc:BaseAmount currencyID="GBP">15</cbc:BaseAmount>
  </cac:AllowanceCharge>
</cac:Price>

Only the gross price in cbc:BaseAmount differs: 16 in the failing document, 15 in the corrected one. The failing document reports only PEPPOL-EN16931-R046. The line net amount of 25.00 is calculated from the net price of 12.5 and a quantity of 2, so the wrong gross price disturbs no other total.

What the validator reported

Recorded on phive 12.1.0 / phive-rules-peppol 4.5.6 / Saxon-HE 12.10, the engine behind the free validator, using synthetic data. A recorded result is regression evidence for these documents; it is not a certification.

Where it applies

  • Applies to the price of a cac:InvoiceLine in an Invoice and of a cac:CreditNoteLine in a CreditNote. Confirmed with the validator on a credit note.
  • The gross price and price discount are informational. PEPPOL-EN16931-R120 calculates the line net amount from the net price only and does not subtract the price-level discount again.
  • Only an allowance is accepted inside cac:Price. Setting cbc:ChargeIndicator to true there is reported as PEPPOL-EN16931-R044.
  • The full pipeline refuses a price-level cac:AllowanceCharge with no cbc:Amount at the XSD layer, before this rule runs.

Scope and source

Written for Peppol BIS Billing 3.0.21 (May 2026), EN 16931 1.3.16, as applied to UBL 2.1 Invoice and CreditNote documents. Other profiles, syntaxes and releases can define this identifier differently. Guidance version 2026-09-20.1: source checked 2026-09-20, explanation last updated 2026-09-20.

The official definition of PEPPOL-EN16931-R046 carries the normative wording and test. This page is our explanation of it, not a copy.

Guidance does not change the engine verdict. Fixing this finding does not mean the document passes every layer, and validation does not certify legal or tax compliance or transmit a document over Peppol.