# PEPPOL-EN16931-R046: Fix 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.

- Layer: Peppol BIS Billing
- Severity: fatal (the document is invalid)
- Topics: Lines and prices, Allowances and charges
- Official definition: https://docs.peppol.eu/poacc/billing/3.0/rules/ubl-peppol/PEPPOL-EN16931-R046/
- Explanation last updated: 2026-09-20

## 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.

| Term | Meaning | UBL element |
|---|---|---|
| BT-146 | Item net price | `cac:InvoiceLine/cac:Price/cbc:PriceAmount` |
| BT-147 | Item price discount | `cac:InvoiceLine/cac:Price/cac:AllowanceCharge/cbc:Amount` |
| BT-148 | Item gross price | `cac: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.

```text
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
```

## 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

```xml
<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

```xml
<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

- The failing invoice reports **PEPPOL-EN16931-R046**. The corrected document passes every layer with no findings.
  - [Download the failing XML](https://ironfang.uk/finance/rule-examples/PEPPOL-EN16931-R046-invalid.xml)
  - [Download the corrected XML](https://ironfang.uk/finance/rule-examples/gross-price-valid.xml)

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.

## Related rules

- [PEPPOL-EN16931-R120 calculates the line net amount from the net price](https://ironfang.uk/docs/finance/rules/PEPPOL-EN16931-R120.md)
- [PEPPOL-EN16931-R121 requires the price base quantity to be above zero](https://ironfang.uk/docs/finance/rules/PEPPOL-EN16931-R121.md)
- [BR-27 rejects a negative net price](https://ironfang.uk/docs/finance/rules/BR-27.md)
- [PEPPOL-EN16931-R040 is the amount check for line-level and document-level allowances, which does allow 0.02](https://ironfang.uk/docs/finance/rules/PEPPOL-EN16931-R040.md)

## 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-24.1: source checked 2026-09-24, explanation last updated 2026-09-20.

[The official definition of PEPPOL-EN16931-R046](https://docs.peppol.eu/poacc/billing/3.0/rules/ubl-peppol/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.

## Links

- [This rule as a web page](https://ironfang.uk/docs/finance/rules/PEPPOL-EN16931-R046)
- [Free Peppol invoice validator](https://ironfang.uk/tools/peppol-validator)
- [Rule index](https://ironfang.uk/docs/finance/rules.md)
- [Ironfang Finance API docs](https://ironfang.uk/docs/finance)
- The same rule is available to MCP clients as the tool `finance.rule.get` on https://mcp.ironfang.uk/mcp
