Replace algorithm

This commit is contained in:
Raphael Michel
2025-08-13 15:23:32 +02:00
parent cb2815a7f0
commit 900540f032
8 changed files with 180 additions and 79 deletions

View File

@@ -198,7 +198,9 @@ pretix internally always stores taxes on a per-line level, like this:
Sum 420.15 79.85 500.00
========== ========== =========== ======= =============
This has a few significant advantages:
Whether the net price is computed from the gross price or vice versa is configured on the tax rule and may differ for every line.
The line-based computation has a few significant advantages:
- We can report both net and gross prices for every individual ticket.
@@ -207,42 +209,33 @@ This has a few significant advantages:
- When splitting the order into two, both net price and gross price are split without any changes in rounding.
The main problem with this approach is that some external systems, formats, or jurisdictions expect a rounding scheme
that works differently. For example, the EN 16931 standard for electronic invoicing expects us to build the sum of
net values and then compute the tax on the document level, like this:
The main disadvantage is that the tax looks "wrong" when computed from the sum. Taking the sum of net prices (420.15)
and multiplying it with the tax rate (19%) yields a tax amount of 79.83 (instead of 79.85) and a gross sum of 499.98
(instead of 499.98). This becomes a problem when juristictions, data formats, or external systems expect this calculation
to work on the level of the entire order. A prominent example is the EN 16931 standard for e-invoicing that
does not allow the computation as created by pretix.
================= ========== ===========
Product Tax rate Net price
================= ========== ===========
Ticket A 19 % 84.03
Ticket B 19 % 84.03
Ticket C 19 % 84.03
Ticket D 19 % 84.03
Ticket E 19 % 84.03
Net sum 420.15
Taxes on 420.15 79.83
Gross sum 499.98
================= ========== ===========
As the example shows, this causes a difference in the end price that needs to be paid by the end user.
So depending on the rounding scheme, a different payment amount might be due.
This has significant disadvantages:
However, calculating the tax rate from the net total has significant disadvantages:
- It is impossible to guarantee a stable gross price this way, i.e. if you advertise a price of €100 per ticket to
consumers, they will be confused when they only need to pay €499.98.
consumers, they will be confused when they only need to pay €499.98 for 5 tickets.
- When splitting the order, the sum of the new orders might require additional payment or refund of a few cents.
- Some prices are impossible, e.g. you cannot sell a ticket for a gross price of €99.99 at a 19% tax rate, since there
is no two-decimal net price that would be computed to a gross price of €99.99.
pretix therefore allows you to choose between the following options:
- When splitting an order into two, the combined of the new orders is not guaranteed to be the same as the total of the
original order. Therefore, additional payments or refunds of very small amounts might be necessary.
Rounding every line individually
""""""""""""""""""""""""""""""""
To allow organizers to make your own choices on this matter, pretix provides following options:
Compute taxes for every line individually
"""""""""""""""""""""""""""""""""""""""""
Algorithm identifier: ``line``
This is our original algorithm where the tax value is rounded for every line individually.
**This is our current algorithm and we recommend it whenever you do not have different requirements.**
**This is our current default algorithm and we recommend it whenever you do not have different requirements** (see below).
For the example above:
========== ========== =========== ======= =============
@@ -257,17 +250,19 @@ For the example above:
========== ========== =========== ======= =============
Rounding by order total, keeping net prices stable
""""""""""""""""""""""""""""""""""""""""""""""""""
Compute taxes based on net total
""""""""""""""""""""""""""""""""
Algorithm identifier: ``sum_by_net``
In this algorithm, the gross prices of some the individual lines will be modified such that the end value will be
compliant with the computation scheme expected by e.g. EN16931. This will lead to different gross prices to be shown
for tickets of the same type, but the net price will stay always the same.
In this algorithm, the tax value and gross total are computed from the sum of the net prices. To accomplish this within
our data model, the gross price and tax of some of the tickets will be changed by the minimum currency unit (e.g. €0.01).
The net price of the tickets always stay the same.
**This is our current algorithm and we recommend it whenever you need to round taxes on document-level and primarily deal with business customers.**
For the example above:
**This is the algorithm intended by EN 16931 invoices and our recommendation to use for e-invoicing when (primarily) business customers are involved.**
The main downside is that it might be confusing when selling to consumers, since the amounts to be paid change in unexpected ways.
For the example above, the customer expects to pay 5 times 500.00, but they are are in fact charged 499.98:
========== ========== =========== ============================== ==============================
Product Tax rate Net price Tax Gross price
@@ -280,18 +275,19 @@ For the example above:
Sum 420.15 78.83 499.98
========== ========== =========== ============================== ==============================
Compute taxes based on net total with stable gross prices
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Rounding by order total, keeping gross prices stable
""""""""""""""""""""""""""""""""""""""""""""""""""""
Algorithm identifier: ``sum_by_net_keep_gross``
Algorithm identifier: ``sum_by_gross``
In this algorithm, the tax value and gross total are computed from the sum of the net prices. However, the net prices
of some of the tickets will be changed automatically by the minimum currency unit (e.g. €0.01) such that the resulting
gross prices stay the same.
In this algorithm, the net prices of some the individual lines will be modified such that the end value will be
compliant with the computation scheme expected by e.g. EN16931. This will lead to different net prices to be shown
for tickets of the same type, but the gross price will stay always the same.
**This is less confusing to consumers and the end result is still compliant to EN 16931, so we recommend this for e-invoicing when (primarily) consumers are involved.**
**This is our current algorithm and we recommend it whenever you need to round taxes on document-level and primarily deal with consumers.**
For the example above:
The main downside is that it might be confusing when sellin got business customers, since the prices of the identical tickets appear to be different.
Full computation for the example above:
========== ========== ============================= ============================== =============
Product Tax rate Net price Tax Gross price