currencies, taxes and rounding
I have a problem with rounding and have come up with a solution, but would like to hear thoughts about it, and if it could cause any issues down the road.
Here's the story: we enter product prices in net and prices are displayed with tax (GST = 10%).
I put 3 products to cart:
item 1 (on sale 10%, regular price $107.25) = $96.53 (qty 1) = $96.53
item 2 (on sale 10%, regular price $62.76) = $56.48 (qty 3) = $169.44
item 3 (on sale 10%, regular price $62.76) = $56.48 (qty 1) = $56.48
At checkout, my subtotal shows as $322.47 which is obviously incorrect ($322.45 is expected).
So, includes/classes/order.php at line 537 calculates the totals, but this doesn't match the $_SESSION['cart']->show_total() for some reason. I'm guessing the sale has something to do with it, but I'm not sure.
My question - why is the subtotal re-calculated in the order class, why not use $_SESSION['cart']->show_total() ? What's the difference and what can go wrong if I replace the line from
Code:
$shown_price = (zen_add_tax($this->products[$index]['final_price'] * $this->products[$index]['qty'], $this->products[$index]['tax']))
+ zen_add_tax($this->products[$index]['onetime_charges'], $this->products[$index]['tax']);
$this->info['subtotal'] += $shown_price;
to
Code:
$this->info['subtotal'] = $currencies->value($_SESSION['cart']->show_total());
Re: currencies, taxes and rounding
I haven't done a detailed review of the suggestion. I do believe (right or wrong) that part of the intention (though I was not involved in any original development) was to provide two "independent" means to arrive at a final display so that there could always be a sort of check or balance about the data. That said and as previously also discussed elsewhere, too many different ways of attempting to find a solution then there are likely to be conflicts as a result.I do look forwards though to seeing if this is generally a broader solution than just the conditions identified above.
Re: currencies, taxes and rounding
Quote:
Originally Posted by
mc12345678
I do believe (right or wrong) that part of the intention (though I was not involved in any original development) was to provide two "independent" means to arrive at a final display so that there could always be a sort of check or balance about the data.
I thought the same, but there's absolutely no check anywhere. IMHO, this would make sense if there was something like
Code:
$subtotal += $shown_price;
if($subtotal == $currencies->value($_SESSION['cart']->show_total())) {
$this->info['subtotal'] = $subtotal;
} else {
}
and then have something in the else{}part to re-calculate and see what went wrong...
Thing is - at the moment I'm even getting different values on the shopping cart page. With the specific case as described above, item prices are calculated differently on cart page and at checkout.
Item 2 is $56.48 on cart page, but comes up as $56.49 on checkout. Times 3, makes is $169.47. And Item 3 also comes up as $56.49, but subtotal comes up as $322.47... :wacko:
So, cart page:
item 1: $96.53
item 2: $169.44
item 3: $56.48
-----------
subtotal: $322.45
I go to checkout and the numbers change to:
item 1: $96.53
item 2: $169.47
item 3: $56.49
-----------
subtotal: $322.47
And the new subtotal is incorrect, just do the math - 2 cents are lost. So, not only it calculates wrong, but it also changes values between pages... Total nightmare...
I have changed the order.php class again to get the totals on checkout corrected, and it works on my specific case, although I'm not sure if it's a universal solution. I went from:
Code:
$shown_price = (zen_add_tax($this->products[$index]['final_price'] * $this->products[$index]['qty'], $this->products[$index]['tax']))
+ zen_add_tax($this->products[$index]['onetime_charges'], $this->products[$index]['tax']);
$this->info['subtotal'] += $shown_price;
to:
Code:
$shown_price = (zen_add_tax($this->products[$index]['final_price'], $this->products[$index]['tax']))
+ zen_add_tax($this->products[$index]['onetime_charges'], $this->products[$index]['tax']);
$this->info['subtotal'] += $currencies->value($shown_price)* $this->products[$index]['qty'];
Basically, I don't multiply qty and net price, then add tax, but instead I add tax to each item first, then do the rounding and then multiply with qty. This way I actually DO get the correct subtotal ($322.49) and this works, but I'm still trying to see how to change the shopping_cart.php class to work the same way because we're still getting $322.45 on cart page (and it's not really friendly to add 4 cents out of the blue...).
Re: currencies, taxes and rounding
Quote:
Originally Posted by
balihr
... Basically, I don't multiply qty and net price, then add tax, but instead I add tax to each item first, then do the rounding and then multiply with qty. This way I actually DO get the correct subtotal ($322.49) and this works, but I'm still trying to see how to change the shopping_cart.php class to work the same way because we're still getting $322.45 on cart page (and it's not really friendly to add 4 cents out of the blue...).
But ... isn't the traditional way of handling taxes to apply the tax to the total rather than individual items, like the following "high level" statement for a currency that uses 2 decimal places?
sub_total = round(qty * unit_cost, 2)
tax = round(sub_total * tax_rate/100, 2)
total = sub_total + tax
Re: currencies, taxes and rounding
Quote:
Originally Posted by
lat9
But ... isn't the traditional way of handling taxes to apply the tax to the total rather than individual items, like the following "high level" statement for a currency that uses 2 decimal places?
Probably is in the US, but this is Australia. Taxes are not added at the end, but instead prices are displayed with tax. So, if you see a price tag that says $10, that's NOT $10 + tax. And then, when you have 10x in cart and come to checkout, you expect to pay $10x10 - $100. If using the US tax logic, this can easily come to $99.99 because of rounding. Please note that I'm not using real life examples, but my first post really does describe a real life situation...
Here's a breakdown:
Using original code, if I do echo $shown_price I get the following:
item 1: 96.525
item 2: 169.455
item 3: 56.485
EDIT: item 2 is 56.485 (and that's 56.49), there's 3 in cart so it comes out as 56.485*3 = 169.455, but item price is 56.49, and 56.49*3 = 169.47
I'm pretty sure you can already see the outcome thanks to rounding. But, think of it this way - shelf price was 96.53, 56.49 (times 3) and 56.49. The "times 3" is where it happens - 56.49 * 3 = 169.47 and the output above (with rounding) is 169.46... Yet, my shopping_cart page shows 169.45 and checkout shows 169.47 :frusty:
I hope I'm making sense here. But, point is - we have to use round((unit_price + tax),2)*qty because that's how it works in real life, on any cash register... Unlike the US, gross price is the main value to use during checkout... From what I know, the entire Europe is exactly the same.
Re: currencies, taxes and rounding
That's why, when prices are displayed with tax, the Zen Cart handling pulls the tax out of the product price before re-doing the taxes.
That said, there have been many discussions/threads throughout the Zen Cart forums regarding theses rounding issues.
Re: currencies, taxes and rounding
I know there's a different method for calculating TAXES if prices are displayed with tax, but this is an issue with subtotals. I've searched the forum quite a lot, but haven't found a discussion with this specific issue.
Anyways, I did solve our problem and this approach does work for us (as described in post #3) - perhaps the Team might consider implementing this in core code same as handling taxes... Like this:
Code:
/*********************************************
* Calculate taxes for this product
*********************************************/
if (DISPLAY_PRICE_WITH_TAX == 'true') {
$shown_price = (zen_add_tax($this->products[$index]['final_price'], $this->products[$index]['tax']))
+ zen_add_tax($this->products[$index]['onetime_charges'], $this->products[$index]['tax']);
$this->info['subtotal'] += $currencies->value($shown_price)* $this->products[$index]['qty'];
} else {
$shown_price = (zen_add_tax($this->products[$index]['final_price'] * $this->products[$index]['qty'], $this->products[$index]['tax']))
+ zen_add_tax($this->products[$index]['onetime_charges'], $this->products[$index]['tax']);
$this->info['subtotal'] += $shown_price;
}
$this->notify('NOTIFIY_ORDER_CART_SUBTOTAL_CALCULATE', array('shown_price'=>$shown_price));
Just a suggestion... :smile:
Re: currencies, taxes and rounding
Quote:
Originally Posted by
balihr
I know there's a different method for calculating TAXES if prices are displayed with tax, but this is an issue with subtotals. I've searched the forum quite a lot, but haven't found a discussion with this specific issue.
Anyways, I did solve our problem and this approach does work for us (as described in post #3) - perhaps the Team might consider implementing this in core code same as handling taxes... Like this:
Code:
/*********************************************
* Calculate taxes for this product
*********************************************/
if (DISPLAY_PRICE_WITH_TAX == 'true') {
$shown_price = (zen_add_tax($this->products[$index]['final_price'], $this->products[$index]['tax']))
+ zen_add_tax($this->products[$index]['onetime_charges'], $this->products[$index]['tax']);
$this->info['subtotal'] += $currencies->value($shown_price)* $this->products[$index]['qty'];
} else {
$shown_price = (zen_add_tax($this->products[$index]['final_price'] * $this->products[$index]['qty'], $this->products[$index]['tax']))
+ zen_add_tax($this->products[$index]['onetime_charges'], $this->products[$index]['tax']);
$this->info['subtotal'] += $shown_price;
}
$this->notify('NOTIFIY_ORDER_CART_SUBTOTAL_CALCULATE', array('shown_price'=>$shown_price));
Just a suggestion... :smile:
Hello!
Can you point me to the file where this code is, please? And yes, it's European way to show tax including prices unless you are not in wholesale business :)
I have this situation here (155e): I'm located in Finland and we do show prices with tax here for consumers, always! So, it is important that this rounding thing works.
When adding a product, I insert Gross value 35,00€ to the product and it calculates Net value automatically. Our VAT is 24%. This product might have attributes that increases Total amount, for example +7,00€. When adding this product to the cart, Total is 42,01€ and not 42,00€. This can't happen here by the law. If I show prices 35€ + 7€ the total amount cannot be 42,01€. So, how do I fix this?
Re: currencies, taxes and rounding
Took me forever to reply, sorry...
That would be in includes/classes/order.php but please edit carefully because you might break your site. So, make sure you backup the file and after you apply the edits, test it thoroughly. Would be nice if you could report back and let us know if this worked for you.
Re: currencies, taxes and rounding
@balihr
Thank you very much for posting this solution which works for our UK test site.
Prices including tax were not being calculated correctly in checkout process.
In includes/classes/order.php replaced all lines between
/*********************************************
* Calculate taxes for this product
*********************************************/
and
/*********************************************
* END: Calculate taxes for this product
*********************************************/