On VAT Calculation / Rounding Monetary Values
Thursday, April 18. 2024
Yesterday API design was hard, today creating invoice line items with VAT on them is hard.
When calculating taxes on items, a very careful approach must be taken on rounding. Line items of an invoice need to be stand-alone units and special care must be taken when calculating sum of rounded values. For unaware developer, this could be trickier than expected.
Products
I'll demonstrate the problem with a ficticous invoice. Let's say I have five different products to sell with following unit prices:
- Product 1 1.24 €
- Product 2 2.77 €
- Product 3 3.31 €
- Product 4 4.01 €
- Product 5 5.12 €
Example invoice #1
A happy customer bought ten of Product 1. Following invoice could be generated from the transaction:
Rather trivial arithmetic with value added tax being 24% can be made. 10 units costing 1,24€ each will total 12,40€. Adding 24% tax on them will result VAT amount of 2,976€. As €-cents really needs to be between 0 and 99 rounding is needed on total amount. Minor numeric cruelty will be needed to make result feasible as money. That's ok. The end result is correct and everybody are happy.
Example invoice #2
Second happy customer bought same as the first customer and additionally 14 of Product 2. Following invoice could be generated from the transaction:
Looking at columns total and total rounded reveal the unpleasant surprise. If rounding is done once, after sum, the rounded value isn't 63,47 as expected. When rounding the total sum into two decimals 63,4632 will result 63,46. There is a cent missing! Where did it go? Or ... alternatively, where did the extra cent appear into total rounded column?
Example invoice #3
Let's escalate. A really good customer bought everything. Lots of everything. Invoice will look like this:
Whoooo! It escalates. Now we're missing two cents already. Total sum of 342,3144€ will round down to 342,31€.
Lesson Learned
Doing one rounding at the end is mathematically sound. Arithmetic really works like that. However, when working with money, there are additional constraints. Each line needs to be real and could be a separate invoice. Because this constraint, we're rounding on each line. Calculating sum of rounding stops making sense mathematically.
Please note, these numbers were semi-randomly selected to demonstrate the problem. In real world scenario roundings can easily cancel each other and detecting this problem will be much more difficult.
Modeling real-world into computer software is surprisingly tricky.
- Anonymous
On API design
Wednesday, April 17. 2024
API design is hard.
If your software makes the behavior hard to change, your software thwarts the very reason that software exists.
- Robert C. Martin
ref. Sandia LabNews on February 14, 2019
What happens when in a design meeting, you're sure that a thing will NEVER happen? Until it does!
What if you were adamant, a value added tax percentage will NEVER be anything else than an integer? Until it does!
From news on 16th Apr 2024: Reports: Finnish government to raise general value-added tax rate to 25.5%
Meanwhile...
At Paytrail API (https://docs.paytrail.com/#/):
At Visma Netvisor API (https://support.netvisor.fi/en/support/solutions/articles/77000554152-import-sales-invoice-or-order-salesinvoice-nv):
I don't think there is much to do. You take yout your humility hat and start eating the bitter oat porridge to get the thing fixed.
Btw. thanks to Afterdawn on bringing this to our attention.
Bottom line: It shouldn't be too hard to figure out what politicians do. They don't think rational (thoughts nor numbers).
Examples from France and Monaco (VAT rates 20%, 10%, 5.5%, 2.1%), Ireland (VAT rates 23%, 13.5%, 9%, 4.8%), Liechtenstein (VAT rates 8.1%, 2.6%, 3.8%), Slovenia (VAT rates 22%, 9.5%, 5%) or Switzerland (VAT 8.1%, 2.6%, 3.8%).