0

I am working on a website for financial calculations. The best practice for valuta is using decimals and no floats so I am aware of it. When all values have been calculated I validate my total, sub and vat.

For example: I have the following values:

  • Totalprice: 10.00
  • Vat rate: 21%
  • Subtotal is: 8.26
  • Vat is: 1.74

When I calculate the values this is the output. One of the failing validation rules which goes wrong by rounding:

Subtotal * vat rate should get the total amount

$calculateVatRate = ($vatRate + 100) / 100; // (21 + 100) / 100 = 1.21
$output = round($subTotal * $calculateVatRate, 2); //8.26 * 1.21 = 9.9946 -> round will 9.99 instead of 10.00

I tried with:

any suggestions?

-- Edit Rounding is 9.9946, I expect it should be 10.00 or 10

eL-Prova
  • 1,084
  • 11
  • 27
  • I need to see if i got it, you for your example you need an output like that: VAT rate : 21% VAT : $2.1 SubTotal: $7.9 , right? – Angelo Berçacola Jan 04 '16 at 23:58
  • @AngeloBerzacola Total is 10.00, subtotal should be 8.26, vat is 1.74 by vatrate of 21%. To be clear, 8.26 = 100%, 1.74 = 21%, 10.00 = 121% – eL-Prova Jan 05 '16 at 00:03
  • @BillWoodger yes, we work with 2 digits not four :) its money. – eL-Prova Jan 05 '16 at 00:18
  • As well, you should include at least an example of a calculation for a case that is accepted, and at least one that is rejected. – Bill Woodger Jan 05 '16 at 10:05

2 Answers2

2

A price including VAT has two components. The actual price, and the VAT amount.

For a 21% rate, divide by 1.21 is correct, what you need to check is how to round/truncate (some people like to call the latter "round to zero", apparently). Check with the accountant responsible for the project on how the calculated VAT amount should be treated.

Once you have that cracked, don't do any more multiplication/division or rounding of any sort. Simple addition/subtraction with the actual official calculated amount of VAT will get you everything you need. Multiplication/division with or without rounding will get you lost, losing pennies/cents here and there and sometimes being "correct" (but only by coincidence).

When receiving invoice amounts, which include VAT calculated by the invoicer, external to your system, there are two general approaches, one of which I now realise you are using.

Although VAT is a standard calculation, there is more than one way that any given company is allowed to do the calculation. This means VAT you are invoiced for may be calculated (the rounding/truncation) differently from the way your accountant wants it done in your system, and that is OK with the VAT people.

What you need to do with the VAT on an invoice is process it as fact, but you do need to verify it is correct, or at least reasonable (the approach you are using).

To verify that invoiced VAT is correct, you need to know how the supplier is calculating their VAT. There are a limited number of ways which are valid, so this is not as complex as it sounds. On your "supplier table" you have a flag/indicator which says how they round. Once you know this, you can verify absolutely that the VAT invoiced to you is correct.

The other way is the tolerance. Personally, I don't like that, but it is how it was done for invoices received at the last place I worked. One hundredth of a currency-unit was the tolerance that was applied.

If you calculate the VAT and round to nearest 100th of a currency-unit you should be able to verify the VAT being charged to you. At that point, again, don't do more multiplication/division/rounding, but use addition/subtraction as appropriate.

I have no clue as to how rounding of decimals works in PHP.

24 / 1.21 = 19.8347 to four decimal places. = 19.834 to three decimal places (truncation of intermediate result)

If you round the first to two decimal places, manually, you'd get 19.84. If you round the second, you'd get 19.83.

Although different, still within the tolerance. However, if you multiply/divide/round twice, you could be 0.02 out (if your code doesn't happen to coincide with the code of the supplier).

Bill Woodger
  • 12,968
  • 4
  • 38
  • 47
  • Bill, that's the other way I was trying to do. In my case I import invoices so the price is exact, 0.01 difference is allowed, more is throwing a warning for check :-) – eL-Prova Jan 05 '16 at 00:28
  • @eL-Prova Wow. I know an accountant who used to bring a 10cm-deep report to each meeting, to emphasise that he was left hold the can for one-hundredth of a currency-unit "differences". That was on trades at an international bank. He'd have a complete cow at the idea of being 0.01 off on a price of ten dollars. Since he's not here, I'm having a cow on his behalf :-) – Bill Woodger Jan 05 '16 at 00:33
  • To put it another way, there is no excuse for less than 100% accuracy. At least no good excuse. Your website can be ripped-off for 0.01 of currency per transaction, with no-one being aware of it. Your VAT reporting can be off (and that is *never* good). It looks shoddy and confuses customers. – Bill Woodger Jan 05 '16 at 00:35
  • @eL-Prova Ah. Re-reading your comment this morning (I guess I'm only an hour behind your time) I think you need to put that information into your question. Updating. – Bill Woodger Jan 05 '16 at 09:31
0

You are creating a rounding error when calculating the vat percentage or the sub total amount. If your sub total is 8.26 and vat is 1.74, your vat rate is 21.06% not 21%.

$calculateVatRat = 10 / 8.26; // 1.2106

You need to consider the decimals here if you want the result to be accurate.

$output = round($subTotal * $calculateVatRate, 2); // 9.9999 rounded as 10.00.

But if you want the vat rate to be 21%, then you need to take extra digits for sub totals to keep the calculations accurate.

$subTotal = 8.2645; 
$calculateVatRat = 1.21; // 10 / 8.2645
$output = round($subTotal * $calculateVatRate, 2); // 9.9999 rounded as 10.00.

Now, if you can't display 4 digits, you need to keep separate value for display and calculations.

Better, always keep the original calculating values in variables ( without any rounding). Only round each variable when displayed (keeping the variable unchanged).

$subTotal = 10/1.21; //8.264462809917355
$vatTotal = 10 - $subTotal; // 1.735537190082646
$output = $subTotal * $calculateVatRate; //10
$subTotalDisplay = round($subTotal, 2); //8.26
$vatTotalDisplay = round($vatTotal, 2); //1.74
$outputDisplay = round($output, 2); //10.00
  • VAT-rates are fixed numbers, dictated by governments. You can't just use a different one when the numbers aren't kind. – Bill Woodger Jan 05 '16 at 00:16
  • Hi Tareq, thanks for your answer. I am aware of the 1.2106, but if my subtotal is already 2 digits, and my vatrate also 2 digits, how is it possible that the 4th digits makes trouble? – eL-Prova Jan 05 '16 at 00:16
  • @eL-Prova The 4th digit will make trouble because you have a rounding when calculating the sub total, wait a minute. I am editing the answer. – Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ Jan 05 '16 at 00:20
  • @TareqMahmood I will investigate tomorrow, thanks in advance for your reply / example! – eL-Prova Jan 05 '16 at 00:39
  • Which value are you going to store? Which value hits the accounts? Showing one value and using a different one internally is going to lead to all sorts of errors, confusions and queries. Worst thing is, it is a value that customers will see, and then they'll come across a different value later, or a total won't "add up". – Bill Woodger Jan 05 '16 at 00:39
  • @BillWoodger You can never be accurate if you store 2 decimals in variables. Better to store the original values in variables and only round it when displayed. There will be no errors/confusions because keeping the original values will always give accurate rounded values. – Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ Jan 05 '16 at 00:44
  • No, that's silly. This is real money. 1.74 (or whatever the account says it should be) is the amount. Nothing more, nothing less, 100% accurate. 10.00 - 1.74 (or whatever) is 100% accurate. The rules for what "whatever" is are what is important. If you muck about calculating all the time, you will be inaccurate as in different from what is reported. You'll constantly need to assume that those small errors in totals are just "rounding errors". You accountants and auditors should be... concerned. – Bill Woodger Jan 05 '16 at 00:48
  • See the update in my last part of answer. I think it will remove your confusions. – Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ Jan 05 '16 at 01:03
  • All should know that they see the rounded values always. – Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ Jan 05 '16 at 01:06
  • It's getting better. VAT is reported to the tax/revenue collector, which is a very, very serious body. These are guys you don't want to annoy. At least in some jurisdictions, if your company goes bust, they are the people who have the first call on your assets. So don't mess with them. The amount which should be stored, is the amount of VAT collected. Which is the value calculated by applying the VAT percentage and then perforce rounded/truncated. Which is why you involve the accountant, to get that absolutely correct. – Bill Woodger Jan 05 '16 at 07:24
  • All should know it is rounded? No. Consider a 90-year-old person, or an eight-year-old, who buys something in a shop in the EU and who gets given a till receipt showing the breakdown of VAT on their purchases. They don't know "rounded" from pickles, and don't need to. But, those VAT amounts on the receipt are going to have to be the ones reported to the VAT people. What you collect as VAT has to be passed on (net of your own VAT charges) otherwise the VAT people get upset. Consider a supermarket chain with 2m items sold per day. Can't have up to 20,000,000 euros going astray for "rounding". – Bill Woodger Jan 05 '16 at 07:28
  • @BillWoodger, I guess, you are talking about storing into database, which wasn't my concern, I was only talking about storing into php variables and my purpose is to fix the mismatch in OP's calculations. But if you want to save it into database for future use, you can store the rounded value after you have finished all calculations. (After you have finished calculations, you can use rounded values, because, it is not going to mess up any more calculations). And if you are concerned about the VAT authority, you can anyhow use the rounded value, which will be 1.74 anyhow. – Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ Jan 05 '16 at 07:58