VirtueMart Forum

VirtueMart 2 + 3 + 4 => Administration & Configuration => Topic started by: Khaostar on October 05, 2016, 17:26:58 PM

Title: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on October 05, 2016, 17:26:58 PM
Hi all,

Just read some topics on rounding problems, taxes, shipping etc and unfortunatly I can't find a solution to my problem.
This seems to be a popular subject and there is a lot of differences between countries, law, etc.
On my side, i'm at Quebec, Canada and I can't get the taxes to be rounded correctly

Here is my problem, in short.

my taxes are the taxes from Quebec, Canada.
Tax 1 (GST) : 5.00%
Tax 2 (TVQ) : 9.975%

now, here is an example of my cart with an error.

Product price : 55,90$
shipping price :13,50$

subtotal : 69,40$

Tax 1 : 3,48$
Tax 2 : 6,93$

Total : 79,80$

as you can see, there is multiple error here.
The real values should be :

Tax 1 : 3,47$
Tax 2 : 6,92$

Total : 79,79$

So there is a error of one penny on each taxes and also an error of one penny on the total price.

The problem is not always there. It depend on the price of the products in the cart and the shipping. Sometimes everything is perfect, sometimes there is an error on one taxe, but not in the total... etc. 

I really don't know how i'm supposed to deal with it. If someone could help me, that would be really appriciated.

Thanks!

Joomla 3.6.2
Virtuemart 3.0.16

Title: Re: Canadian taxes on shipping : another rounding issue
Post by: GJC Web Design on October 05, 2016, 23:57:20 PM
isn't the vm admin -> prices  -> round only display setting?
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on October 07, 2016, 13:50:38 PM
Already tried. It doesn't change anything  :(
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on October 11, 2016, 14:27:32 PM
Anything else I can try?
This problem bothers me a lot!

Thanks
Title: Canadian taxes on shipping, another rounding issue - SOLVED VM update required!!
Post by: Khaostar on October 31, 2016, 19:35:18 PM
Finally, I managed to found the problem. It seems to be a bug directly in the core.

That's simple. Almost every calculations that need to be rounded use the "roundInternal" function. BUT, there is one place where the standard "round" php function is used and that's what is causing the problem.

In calculationh.php, arrond line 975.

Replace this :

$this->_cart->cartData['VatTax'][$rule['virtuemart_calc_id']]['result'] += round($this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'];

by this :

$this->_cart->cartData['VatTax'][$rule['virtuemart_calc_id']]['result'] += $this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'];

And arround line 1070, replace this :

$discount += round($this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'],$this->_currencyDisplay->_priceConfig['salesPrice'][1]);

By this :

$discount += $this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'];


This fix the rounding problem. I guess that another solution would be to replace the "round" function by the "roundInternal" function, but I haven't tried

So, if a Virtuemart developper could see this and fix it in the next version of virtuemart. That would be very appreciated.

Thanks!
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Milbo on November 01, 2016, 11:21:06 AM
Sounds very valid. I will replace it with the roundInternal. Lets see how it works then.
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on November 01, 2016, 12:50:02 PM
Thanks Milbo! Really appreciated.
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on November 04, 2016, 16:00:32 PM
Well, after some tests, I have another rounding issue. The problem seems to be really simple, but I can't manage to fix it.

Here wo go.

My taxes, using the same config as before :
Tax 1 (GST) : 5.00%
Tax 2 (TVQ) : 9.975%

Here is an example of what I get actually :
Product price : 13,50$
Tax 1 price : 0,68$
Tax 2 price : 1,35$
Total price : 15,52$

As you can see here, the total should be 15,53, not 15,52.

It seems that the taxes are diplayed rounded, but the total is calculted with the non rouded taxes.

Actually, this is what is happening

13,50*0,05 = 0,675 (tax 1 non rounded amount, displayed as 0,68 in the cart)
13,50*0.09975 = 1,346625 (tax 2 non rounded amount, displayed as 1,35 in the cart)
13,50+0,675+1,346625=15.521625.
So the rounded total is 15,52$

What I need is this :

13,50*0,05 = 0,68 (rounded)
13,50*0.09975 = 1,35 (rounded)
13,50+0,68+1,35=15.53$

So I need the taxes to be rounded when they are added together and added to the final price. I tried to uncheck the "round only display" in the config, but it doesn't change anything.

Am I missing something? Or is it something that can't be done actually? I'm not sure what to do with that.

Thanks!


Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Milbo on November 04, 2016, 19:42:58 PM
You may test http://dev.virtuemart.net/attachments/download/1029/com_virtuemart.3.0.18.3_extract_first.zip

Check the option "round only display".
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on November 10, 2016, 17:01:58 PM
Sadly, it seems the file you sent us still produces some 1 cent differences.

Also, we had a "problem" that the calculation was "too precise" if we compared it to the rounded up display.

Exemple:
subtotal: 13.50
tax 1(5%): 0.675(display:0.68)
tax 2(9,975%): 1.346625(display:1.35)
total: 15.52

So, the calculation is good, but the display makes it look like its not.

Because of that, I returned to the original file and continued modifying it, now trying to make the result with the displayed values.

So, here is what I did:

$this->_cart->cartData['VatTax'][$rule['virtuemart_calc_id']]['result'] += round($this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'],$this->_currencyDisplay->_priceConfig['salesPrice'][1]);
is now
$this->_cart->cartData['VatTax'][$rule['virtuemart_calc_id']]['result'] += $this->roundInternal($this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'], "taxAmount");

$this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'] = $this->roundInternal($this->roundInternal($cOut) - $cIn);
is now
$this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'] = $this->roundInternal($this->roundInternal($cOut) - $cIn, "taxAmount");

$discount += round($this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'],$this->_currencyDisplay->_priceConfig['salesPrice'][1]);
is now
$discount += $this->roundInternal($this->_cart->cartPrices[$rule['virtuemart_calc_id'] . 'Diff'], "taxAmount");

$tmp = $this->roundInternal($this->roundInternal($cOut) - $cIn);
is now
$tmp = $this->roundInternal($this->roundInternal($cOut) - $cIn, "taxAmount");

Basically, I just linked the rounding of taxes/calc_rules to something I could have a fair control from the admin panel.
To be fair, it may be because I do not quite know how $this->_internalDigits works but in the rounInternal function, it seems that if you don't have a "name" it rounds with the number of digits equal to this variable and it's seems always equal to 9 aka not really rounding(?)

As I said, I may be misunderstanding something.

In any way, this code is what I concluded to and it seems to work for me. What do you thing about it? I would truly like your opinion of those modifications.

Thank you!
Have a good day!



Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Milbo on November 15, 2016, 09:41:18 AM
Rounding is a complex issue and the main problem is that rounding is physics, not maths. When you round, you leave the exact math and you enter the natural space. the next problem is that a computer has problems to create an exact 2.0000.... You end up with 2.0000001 or so. Therefore we need the internal rounding.

When you use the internal rounding with "taxAmount" which is usually set to 2, then you just round to 2 numbers (the opposite of "round only display")

All what you did is to reduce the precision and that may work in your example, but is more wrong for other examples. The reason is that some mathematical basic rules do not work anylonger, when you round the numbers.

(a*c + b*c ) IS NOT [round(a) + round(b)] * round(c) !!!  Check the chapter "Distributivity and rounding" https://en.wikipedia.org/wiki/Distributive_property
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on December 19, 2016, 16:24:24 PM
It is true that the precision will be off by my last solution.

But, I didn't find a way to have both the precision of the calculation and the accuracy of the displayed calculation. My solution is far from perfect and I'd prefer being able to have precision and a good display.

If you have any idea of how to do so, I'm all ears.
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: encreplus on December 27, 2016, 20:52:18 PM
Im also from quebec could you share your solution ??

Also where you abble to put the taxes for shipping directly in TPS and TVQ or you use the standard option from VM ie ... total taxes for shipping beside shipping label on order page and invoice ?

Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on January 03, 2017, 16:04:11 PM
Unfortunately, we haven't a 100% working solution for now. We are still having some bad calculations.

Otherwise, we have spotted the problem. ( I think )

Here in Quebec, Canada, we are calculating the taxes on the subtotal only. In VirtueMart, the taxes are calculated for the products, then for the shipping, and also for the payment method, if needed. After that, all the taxes are added together. That's where the problem is. That way, that's almost impossible to have the same result as the taxes on the subtotal only.

A really good option that should be added is to be able to calculate the taxes on the subtotal directly. That would fix every problem for the Canadian taxes. Of course, doing that we will have some problems with different taxes on different products or things like that, but we don't care here in Quebec as almost everything is taxed the same way, except for some products that are not taxable.

In my case, everything is taxable.
In the case of someone who would have some non-taxable products, it's not very complicated either: a taxable subtotal and a non-taxable subtotal. The taxes should be calculated on the taxable subtotal only and that's it.

Milbo, do you think this is something possible? We should have an option to calculate the taxes based on the subtotal and ignore every other tax calculation. I'm sure it will be useful for many other users.

Mathematically, it's simple, but I know it's probably much more complicated to integrate that in VirtueMart. Let me know if you can do something or if I can do something to help, too.

Oh and by the way, Happy new Year! :)
Thanks!

Title: Re: Canadian taxes on shipping : another rounding issue
Post by: diri on January 04, 2017, 05:44:35 AM
Hi and happy new year to all :)

@Khaostar:
You will ever have rounding issues when you calculate with single prices, sum them up and recalculate. Onliest chance I see is to multiply prices with a factor moving rounding issues at the very end of a large number and divide it afterwards. Those issues can get "lost" or minimized after division of this large number to get real amount back.

Let's asume you have a tax of 5.00% (factor 0.05). You need a precission of two decimals for display, three digits in calculation.

Now, instead of multiplying with 0.05 you could try to multiply the price with 1,000.00 first. Than multiply price with 500.00 (tax factor 0.05 multiplied with 10,000.00). Than divide result two times: 1,000.00 and 10,000.00. Have a look what happens.

Ex for 5%:
Price: 13.50
13.50 x 1,000.00 = 13,500.00
tax factor = 0.05 -> 500.00
tax amount:
13,500.00 * 500 = 6,750,000.00
1st division (/ 1,000.00) = 6,750.000whatever
2nd division (/ 10,000.00) = 0.675whatever

Didn't try it now with VM but, maybe you can introduce a rule working this way for your taxes (might need another name and some overrides for naming while tax for VM = 0.00000%).
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on January 04, 2017, 15:46:19 PM
Hi diri

Thanks for the possible solutiuon, but I don't think this is the right one to use.

As I said in my last post, the solution is siimply to calculate the taxes on the subtotal only, like every canadian shops are doing right now.

in fact, this is not really a rounding issue, but a problem with the addition of multiple rouded numbers. If we just add everything (products price, shipping price, etc) BEFORE applying the taxes, the problem is solved. But there is no options for that in VirtueMart actually. 

For reference, here is a link that show what the taxes amounts are supposed to be based on the subtotal price : http://www.calculconversion.com/sales-tax-calculator-gst-qst.html
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: diri on January 05, 2017, 06:21:33 AM
Hi Khaostar,

if it would be that simple ...

Part of trouble is a legislative regulation in many countries to show price with tax for each position of an order first (product's end price) before order is submitted for normal customers and many different regulations for taxes all around the world. You will always have problems with rounding in this situation - sum of product's end prices and totals of bill might differ because of rounding issues.

And there we are at rounding in display over here as well - reverse calculation has always a rounding problem.

To make understanding trouble of all calculations more worse you must dive deep in technical (hardware) based fundamentals. You will be astonished when you discover real precision of any CPU at bit level.

You will discover that there is kind of obligation to avoid divisions (multiplying with eg 0.05 is a division in reality) whenever it's possible or to use it only when a division is a trivial bit shift left or right. My tip given before is based on this knowledge (see comment "whatever" behind the numbers, here you see the reason).
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on January 05, 2017, 14:24:34 PM
Hi diri,

I understand your legislative argument, but here, in Quebec Canada, this is how we work. We HAVE to use the right calculation to obtain the right result. We have a way to calculate the taxes and every shop is calculating it that way : sum up everything and apply the taxes. It's not that complicated. But VirtueMart does not offer this kind of solution right now. That's why i'm trying to explain everything.

Here is a really easy exemple, step by step, with random prices. This is how we work here :

product 1 price :    5,50$
product 2 price :  14,25$
Shipping price :     5,50$

Subtotal :            25,25$
Tax 1 (5,00%) :     1,26$   (25,25 * 0,05 = 1,2625 -> round that number)
Tax 2 (9,975%) :   2,52$   (25,25 * 0,09975 = 2,5186875 -> round that number)
Total :                 29,03$   (Subtotal + rounded taxes)

See? That simple. The taxes are calculated and rounded once on the subtotal only.

Actually, in virtuemart, the taxes are calculated on the products price, and then on the shipping price, and finally added together. It's not gonna give the same result. The way VirtueMart is calculating it is not an error, but that's not the way we need to calculate it here. This is why I ask for an option to calculate it the way we need.
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: diri on January 07, 2017, 05:26:48 AM
Khaostar,

thank you for detailled explanation and the link but, even when I understand your need better I have an additional question now:

Are you using mathematical (aka geodetic or undisturbed rounding) or commercial rounding in Canada?

In Germany one should use commercial rounding which is a bit different. Most prominent software doing it wrong in this case is MS Excel - it performs mathematical (or half-round?) rounding. Therefore it's not really allowed to use it to generate bills over here except you put special nested rounding in your calculation preventing issues at decimals with trailing 5.

To explain it an example with two decimal places at display.

Number to be rounded 0.445
Mathematical rounding: 0.44
Commercial rounding: 0.45
edit:
This example extended to more decimal places in calculation:
Number to be rounded 0.444445
Mathematical rounding: 0.44
Commercial rounding: 0.45

You see we are at precision and legislative regulations even when calculation rules work according your needs (which could be applied at B2B over here at least).
Title: Re: Canadian taxes on shipping : another rounding issue
Post by: Khaostar on January 09, 2017, 13:59:25 PM
Hi,

Thanks for your answer. You are right. The rounding mode is important too.

We are using the "round half up" method. (This is the default mode of php round function : http://php.net/manual/en/function.round.php)
So 0,445 become 0,45 and 0,444445 will be 0,44.
In fact, if the third digit is 5 or over, we add +1 to the second digit. If the third digit is 4 or under, the second digit stay the same.