I just read this post because we had an issue yesterday.
We are using ver. 1.4.9 (modified German OCIE) with 19% MwSt. VAT
All Product prices are enterd in the backend as ex VAT and then the Prices are displayed on the front end incl. VAT
Real life scenerio:
Product price in backend 16.3865 (+ 19% VAT 3.1134 = 19.4999 )
Product price in frontend 19.50 - perfect this is the price we want the customers to see.
With one product in the cart this works fine on PayPal the problem starts when two products are added to the cart.
2 x 16.3865 = 32.773 (+ 19% VAT (2x 3.1134 = 6.2268) = 38.9998 )
Product price in frontend 39.00 - nice
However in PayPal the cart says 39.01 (! wtf !)
So reading this thread it seems that the last 2 decimal places are being rounded
2x16.3865 becomes 32.78 (instead of 32.7730) and 2x3.1134 becomes 6.23 (instead of 6.2268) which gives PayPal cart total 39.01
This is ofcourse a total disaster for the shop wich leads to abandoned carts and unhappy customers who are feeling cheated on 1 cent. (a bit exaggerated, I know)
Has anyone been able to wrap their heads around this and have a quick fix?
We are using ver. 1.4.9 (modified German OCIE) with 19% MwSt. VAT
All Product prices are enterd in the backend as ex VAT and then the Prices are displayed on the front end incl. VAT
Real life scenerio:
Product price in backend 16.3865 (+ 19% VAT 3.1134 = 19.4999 )
Product price in frontend 19.50 - perfect this is the price we want the customers to see.
With one product in the cart this works fine on PayPal the problem starts when two products are added to the cart.
2 x 16.3865 = 32.773 (+ 19% VAT (2x 3.1134 = 6.2268) = 38.9998 )
Product price in frontend 39.00 - nice
However in PayPal the cart says 39.01 (! wtf !)
So reading this thread it seems that the last 2 decimal places are being rounded
2x16.3865 becomes 32.78 (instead of 32.7730) and 2x3.1134 becomes 6.23 (instead of 6.2268) which gives PayPal cart total 39.01
This is ofcourse a total disaster for the shop wich leads to abandoned carts and unhappy customers who are feeling cheated on 1 cent. (a bit exaggerated, I know)
Has anyone been able to wrap their heads around this and have a quick fix?
I think that the problem can be resolved by forcing OC to use 2 decimal for internal calculation instead of using 4 digit decimal. But I wonder how 

My website : http://www.proaudiohome.com
http://www.pristinenote.com
Hi folks,
i put up this topic again because i think this is a big issue (accounting problem,cart price not correct).
I have the same issue as TomTom. The problem is that the shop i have built sells items like screws, washers and with big numbers order of the same item the difference in the cart is really big.
Now i have solved this showing 4 digits in the price in the frontend with the correct item price, at least it's better than show up 50x0.06 = 3.01 or other wrong math in the cart, what you say to the customer?;but of course i cannot use Paypal because PP want 2 digits ( and using 2 digits the totals are different)..for this issue during the checkout a customer can still use PP choosing a " receiving a PP payment request".( he/she confirm an order and in the admin the shop owner send a payment request to the customer); a temporary solution.
But of course i don't like this situation, for this it would be really nice to know if someone has solved this problem.
Oc version is 1.5.4.
Thank you for any eventual responce.
Fabrizio
Ps: anyway i think that OC is a fantastic software, easy to understand and setting, if developers resolve this it will be the perfect solution for any kind of shop!.
i put up this topic again because i think this is a big issue (accounting problem,cart price not correct).
I have the same issue as TomTom. The problem is that the shop i have built sells items like screws, washers and with big numbers order of the same item the difference in the cart is really big.
Now i have solved this showing 4 digits in the price in the frontend with the correct item price, at least it's better than show up 50x0.06 = 3.01 or other wrong math in the cart, what you say to the customer?;but of course i cannot use Paypal because PP want 2 digits ( and using 2 digits the totals are different)..for this issue during the checkout a customer can still use PP choosing a " receiving a PP payment request".( he/she confirm an order and in the admin the shop owner send a payment request to the customer); a temporary solution.
But of course i don't like this situation, for this it would be really nice to know if someone has solved this problem.
Oc version is 1.5.4.
Thank you for any eventual responce.
Fabrizio
Ps: anyway i think that OC is a fantastic software, easy to understand and setting, if developers resolve this it will be the perfect solution for any kind of shop!.
It's my first time setting up an e-commerce website, and first time working with sql and php.
I'm working with 1.5.5.1
I went through the code, and I think currency conversion is already rounded per product price to the corresponding decimal place for the currency being used.
The problem is reduced if you use prices with 2 decimal places (such as 19.90, not 19.9125), or whatever paypal limits to for each currency.
There is a problem however, with tax.
If you want a 19% VAT price of 189.00, your product price would be 158.8235. But you can't enter this into your product price because you'll get the rounding error. If you entered 158.82, your VAT price would be 188.9958, and you'd get the rounding error again whenever taxes are being calculated for multiple quantities of the same product.
With the example from TomTom:
Opencart tax is 16.3865 x 0.19 x 2 = 6.2269 or 6.23
32.78+6.23 = 39.01
The error is the mismatch between the rounding of the product price.
So instead, what TomTom should do is set his product price to 16.39.
His VAT is 3.1141, and VAT incl. price is 19.5041. (frontend price of 19.50)
So if someone orders 2 products, they will get in opencart:
subtotal 16.39 * 2 = 32.78
tax 3.1141 *2 = 6.2282
opencart total = 39.0082, rounded to 39.01.
Paypal should technically charge the same, 39.01.
But TomTom wants to have 39.00.
So what we need to do is to round the tax for each quantity of the product, before it is totaled.
We want tax 3.1141 changed to 3.11.
Then 3.11 x 2 = 6.22
6.22 +32.78 = 39.00
Tax is calculated for each single product in the following function:
In system/library/tax.php, getRates()
For the following lines:
To round the tax to 2 decimal places, this could be changed to:
This should work if you are using USD and EURO where there are 2 decimal places.
However, if you switch to a currency with more than 2 decimal places, it will be a problem because the function structures do not pass down the currency desired.
Whereas, when currency is converted and calculated in system/library/currency.php, format(), the value is rounded to the decimal place that is pulled out of the database in reference to the currency that is passed down:
and
In order to get the currency code passed down to pull out the decimal place required during tax calculations, you'd have to change every call for tax->calculate, getTax, and getRates to include the currency required, and include the $currency variable in the function structures.
Then you have to pull out the currency info from the database
Then grab the required decimal place:
And then finally we can round to the required decimal place value:
I myself encountered the problem where for example I have a product which is:
price: 10.38
Incl. 19% vat price: 12.3522 (frontend 12.35)
quantity: 10
total price displayed: 123.52 (expected 123.50)
This is because the tax is 1.9722
1.9722 * 10 = 19.722
With the new rounding, we would get:
1.97 * 10 = 19.70
and the 2 cents are knocked off.
However, we have the problem that we can't get 19.95 incl. 19% VAT.
Because, 16.76 * 1.19 = 19.9444 (rounded to 19.94)
16.76 * 0.19 = 3.1844
and 16.77 * 1.19 = 19.9563 (rounded to 19.96)
16.77 * 0.19 = 3.1863
We shouldn't use more than 2 decimal places in the product price because this will introduce the same problem again with the mismatch in subtotal between opencart and PayPal.
Or if you really want that 19.95, you could try PHP_ROUND_HALF_ODD, but I don't know if this is acceptable in standard accounting, and this may not always give you a 0.95. You my end up with 0.94 or 0.96 with a different number, as ODD is always applied.
You could possibly insert a logic that calculates the final price and if either ODD or EVEN gets you the 0.95, then to apply the correct one.
But this solution only works for countries where the price must include VAT, like in Germany. Because in a country like the USA where prices are not displayed with tax, the tax should be calculated based on the final price, and not rounded values for each quantity of product.
So for example, if I'm in the US, and I want to buy something for 9.95 excl. tax, with a 9.5% tax.
If I applied the modification above, I would get:
price: 9.95
tax: 0.9453 (rounded to 0.95)
quantity: 10
total: (9.95 + 0.95) * 10 = 109.00
However, standard accounting practice requires calculating the tax on the total price:
10 * 9.95 * 1.095 = 108.9525 (rounded to 108.95)
So in effect, Opencart should work well out of the box for countries where tax is not displayed in the price, like the USA, because the tax is based on the subtotal, as long as you stay with 2 decimal place prices to match with PayPal. If you are in a country like Germany where you need to display prices with VAT, you need to make the modification above to round the tax for each item, and not the total, because the tax is based on the individual item.
My post is a bit long, because I'm sort of figuring it out as I type.
Ah, but then we have another problem, as in Germany it is allowed to display prices without VAT if you are a seller B2B, but if the business customer is located in Germany then VAT has to be charge. In this case, the VAT should then be calculated based on the subtotal, and not on the individual item.
In this case, opencart should be redesigned for allowing prices to be displayed with or without tax, based on the customer group, so with tax to consumers, and without tax for business customers, and then applying or disabling the tax rounding modifications above. However, as I look in the admin, the disabling or enabling of showing tax in prices is global and can't be set by customer group.
And so that's my insight into the calculation problems with opencart.
I haven't tried this modification.
Someone try it and let me know!
But I take no responsibility and make no warranty to its effects.
I'm working with 1.5.5.1
I went through the code, and I think currency conversion is already rounded per product price to the corresponding decimal place for the currency being used.
The problem is reduced if you use prices with 2 decimal places (such as 19.90, not 19.9125), or whatever paypal limits to for each currency.
There is a problem however, with tax.
If you want a 19% VAT price of 189.00, your product price would be 158.8235. But you can't enter this into your product price because you'll get the rounding error. If you entered 158.82, your VAT price would be 188.9958, and you'd get the rounding error again whenever taxes are being calculated for multiple quantities of the same product.
With the example from TomTom:
Paypal is taking 16.39 x 2 = 32.78Product price 16.3865 (+ 19% VAT = 19.4999 )
Product price in frontend 19.50
2 x 16.3865 = 32.773 (x 1.19 = 38.9998 )
Product price in frontend 39.00
However in PayPal the cart says 39.01 (! wtf !)
Opencart tax is 16.3865 x 0.19 x 2 = 6.2269 or 6.23
32.78+6.23 = 39.01
The error is the mismatch between the rounding of the product price.
So instead, what TomTom should do is set his product price to 16.39.
His VAT is 3.1141, and VAT incl. price is 19.5041. (frontend price of 19.50)
So if someone orders 2 products, they will get in opencart:
subtotal 16.39 * 2 = 32.78
tax 3.1141 *2 = 6.2282
opencart total = 39.0082, rounded to 39.01.
Paypal should technically charge the same, 39.01.
But TomTom wants to have 39.00.
So what we need to do is to round the tax for each quantity of the product, before it is totaled.
We want tax 3.1141 changed to 3.11.
Then 3.11 x 2 = 6.22
6.22 +32.78 = 39.00
Tax is calculated for each single product in the following function:
In system/library/tax.php, getRates()
For the following lines:
Code: Select all
if ($tax_rate['type'] == 'F') {
$amount += $tax_rate['rate'];
} elseif ($tax_rate['type'] == 'P') {
$amount += ($value / 100 * $tax_rate['rate']);
}
Code: Select all
if ($tax_rate['type'] == 'F') {
$amount += round($tax_rate['rate'], 2, PHP_ROUND_HALF_UP);
} elseif ($tax_rate['type'] == 'P') {
$amount += round(($value / 100 * $tax_rate['rate']), 2, PHP_ROUND_HALF_UP);
}
However, if you switch to a currency with more than 2 decimal places, it will be a problem because the function structures do not pass down the currency desired.
Whereas, when currency is converted and calculated in system/library/currency.php, format(), the value is rounded to the decimal place that is pulled out of the database in reference to the currency that is passed down:
Code: Select all
$decimal_place = $this->currencies[$currency]['decimal_place'];
Code: Select all
$string .= number_format(round($value, (int)$decimal_place), (int)$decimal_place, $decimal_point, $thousand_point);
Then you have to pull out the currency info from the database
Code: Select all
$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "currency");
foreach ($query->rows as $result) {
$this->currencies[$result['code']] = array(
'currency_id' => $result['currency_id'],
'title' => $result['title'],
'symbol_left' => $result['symbol_left'],
'symbol_right' => $result['symbol_right'],
'decimal_place' => $result['decimal_place'],
'value' => $result['value']
);
}
Code: Select all
$decimal_place = $this->currencies[$currency]['decimal_place'];
Code: Select all
if ($tax_rate['type'] == 'F') {
$amount += round($tax_rate['rate'], $decimal_place, PHP_ROUND_HALF_UP);
} elseif ($tax_rate['type'] == 'P') {
$amount += round(($value / 100 * $tax_rate['rate']), $decimal_place, PHP_ROUND_HALF_UP);
}
I myself encountered the problem where for example I have a product which is:
price: 10.38
Incl. 19% vat price: 12.3522 (frontend 12.35)
quantity: 10
total price displayed: 123.52 (expected 123.50)
This is because the tax is 1.9722
1.9722 * 10 = 19.722
With the new rounding, we would get:
1.97 * 10 = 19.70
and the 2 cents are knocked off.
However, we have the problem that we can't get 19.95 incl. 19% VAT.
Because, 16.76 * 1.19 = 19.9444 (rounded to 19.94)
16.76 * 0.19 = 3.1844
and 16.77 * 1.19 = 19.9563 (rounded to 19.96)
16.77 * 0.19 = 3.1863
We shouldn't use more than 2 decimal places in the product price because this will introduce the same problem again with the mismatch in subtotal between opencart and PayPal.
Or if you really want that 19.95, you could try PHP_ROUND_HALF_ODD, but I don't know if this is acceptable in standard accounting, and this may not always give you a 0.95. You my end up with 0.94 or 0.96 with a different number, as ODD is always applied.
You could possibly insert a logic that calculates the final price and if either ODD or EVEN gets you the 0.95, then to apply the correct one.
But this solution only works for countries where the price must include VAT, like in Germany. Because in a country like the USA where prices are not displayed with tax, the tax should be calculated based on the final price, and not rounded values for each quantity of product.
So for example, if I'm in the US, and I want to buy something for 9.95 excl. tax, with a 9.5% tax.
If I applied the modification above, I would get:
price: 9.95
tax: 0.9453 (rounded to 0.95)
quantity: 10
total: (9.95 + 0.95) * 10 = 109.00
However, standard accounting practice requires calculating the tax on the total price:
10 * 9.95 * 1.095 = 108.9525 (rounded to 108.95)
So in effect, Opencart should work well out of the box for countries where tax is not displayed in the price, like the USA, because the tax is based on the subtotal, as long as you stay with 2 decimal place prices to match with PayPal. If you are in a country like Germany where you need to display prices with VAT, you need to make the modification above to round the tax for each item, and not the total, because the tax is based on the individual item.
My post is a bit long, because I'm sort of figuring it out as I type.
Ah, but then we have another problem, as in Germany it is allowed to display prices without VAT if you are a seller B2B, but if the business customer is located in Germany then VAT has to be charge. In this case, the VAT should then be calculated based on the subtotal, and not on the individual item.
In this case, opencart should be redesigned for allowing prices to be displayed with or without tax, based on the customer group, so with tax to consumers, and without tax for business customers, and then applying or disabling the tax rounding modifications above. However, as I look in the admin, the disabling or enabling of showing tax in prices is global and can't be set by customer group.
And so that's my insight into the calculation problems with opencart.
I haven't tried this modification.
Someone try it and let me know!
But I take no responsibility and make no warranty to its effects.
So out of curiosity, I am looking at the invoices I've received from German ebay sellers, and they all have this calculation error, missing a few cents here and there. It's because they're required to display the inclusive tax price and whatever software they're using to calculate and generate the invoices are based on prices excluding tax.
This is why I don't understand why its required to display tax in the prices here. It introduces a lot of rounding problems. I wonder how the supermarkets handle this.
So what I think should change to the core, is that the 'sub_total' should be the sum of the data['total']. The data['total'] is not currently stored in the database, only the product['price'] and product['quantity'].
Every instance of data['total'] should be changed from
to
Then sub_total should be the sum of each data['total']. If tax is not displayed, then sub_total will be like what it was intended to be, the total without tax. If tax is displayed, the sub_total would include tax.
Then if tax is not displayed, then total _tax would be getRates('sub_total'). If tax is displayed, then total_tax would be 'subtotal' / (1 + tax_rate) * tax_rate, while the real-subtotal would be subtotal - total_tax.
In each case, either tax on or tax off, you would get different calculations, but at least the numbers add up for each situation.
This is why I don't understand why its required to display tax in the prices here. It introduces a lot of rounding problems. I wonder how the supermarkets handle this.
So what I think should change to the core, is that the 'sub_total' should be the sum of the data['total']. The data['total'] is not currently stored in the database, only the product['price'] and product['quantity'].
Every instance of data['total'] should be changed from
Code: Select all
'total' => $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')) * $product['quantity']),
Code: Select all
'total' => $this->currency->format(round($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')), 2) * $product['quantity']),
Then if tax is not displayed, then total _tax would be getRates('sub_total'). If tax is displayed, then total_tax would be 'subtotal' / (1 + tax_rate) * tax_rate, while the real-subtotal would be subtotal - total_tax.
In each case, either tax on or tax off, you would get different calculations, but at least the numbers add up for each situation.
So, from what I can see, Opencart generates 3 types of errors in pricing calculations and displayed prices on the frontend. Most of the problems are generated for people who need to display taxes in the prices, because Opencart is designed mainly for people who display prices without tax:
1) Error - taxes
- Problem A - when displaying prices including tax, the displayed product total doesn't match the individual price, when using 2 decimal places. Does not affect people who don't display tax in price.
Price: 10.24
incl 19% VAT: 10.24 * 1.19 = 12.1856 (frontend 12.19)
Customer orders 10: 12.1856 * 10 = 121.856 (frontend 121.86) (expected 121.90)
- Solution A - use 4 decimal points.
price: 10.2437
incl 19% VAT: 10.2437 * 1.19 = 12.190003 (frontend 12.19)
Customer order 10: 10.2437 * 1.19 * 10 = 121.90003 (frontend 121.90)
- Problem B - when a customer orders a large amount, the displayed price incl. tax doesn't match the total product price. Does not affect people who don't display tax in price.
Example:
price: 10.2437
incl 19% VAT: 10.2437 * 1.19 = 12.190003 (frontend 12.19)
Customer order 2000: 10.2437 * 1.19 * 2000 = 24380.006 (frontend 24380.01) (expected 24380.00)
- Solution B1 - limit orders to less than 1000 when using at least 4 decimal points, or 100 if using 3 decimal points.
- Solution B2 - change the opencart system to allow admin to enter price including VAT.
2) Error - Currency
Product price excl. tax is rounded to 2 decimal places during currency conversion, for each individual item, and then when taxes are displayed, the same problem occurs as in Error 1 - Tax - Problem A. Does not normally affect people who don't display taxes in prices, although the converted total may not equal to expected total, as rounding on conversion takes place on the individual quantity level, instead of applied to the pre-converted total.
Example:
Price: 10.24
Conversion rate: .746528
New Price: round(10.24 * .746528, 2) = 7.64
incl 19% VAT: 7.64 * 1.19 = 9.0916 (frontend 9.09)
Customer order 100: 7.64 * 1.19 * 100 = 909.16 (frontend 909.16) (expected 909.00)
For people who don't display taxes:
Price: 10.24
Conversion rate: .746528
New Price: round(10.24 * .746528, 2) = 7.64
Customer order 100: 7.64 * 100 = 764.00 (frontend 764.00)
Admin expects: 10.24 * .746528 * 100 = 764.44
- Solution - disable rounding in currency conversion
In system/library/currency.php
Change this:
to
Error 3) Paypal Price Mismatch - PayPal doesn't match the shopping cart, due to 2 decimal limitation.
Example:
price: 10.2437
incl 19% VAT: 10.2437 * 1.19 = 12.190003 (frontend 12.19)
Customer order 10: 10.2437 * 1.19 * 10 = 121.90003 (frontend 121.90)
Paypal: 10.24 * 10 = 102.40
Opencart passes tax to Paypal: 10.2437 * 0.19 * 10 = 19.46303 (passes 19.46)
Paypal total: 102.40 + 19.46 = 121.86 (mismatch)
-Solution A - (not effective) use 2 decimal places. However, people who display prices including tax will encounter the same problem in Error 1 - Tax - Problem A. People who don't display taxes, but need to use more than 2 decimal places, will encounter the same problem.
- Solution B1 including people with more than 2 decimal points - pass product total as one lot (including tax) to Paypal for each product. Quantity of 1 for each product. Item description is changed to "Lot of 'quantity' of product". Tax removed from "shipping, handing, tax" calculations, by adding tax to subtotal.
To remove the tax from the "shipping, handing, tax", in system/library/cart.php:
Find this function:
And change to:
To combine each product into one lot, and include the tax, find this code in catalog/controller/payment/pp_standard.php:
And change to:
- Solution B2 - (does not work with people using more than 2 decimal points, unless your product price including tax is limited to 2 decimal points) Send 'price' including tax, along with the original product quantity. Tax needs to be added to subtotal.
For changes to subtotal, follow the section in Solution B1 regarding subtotal.
For changes to the product price to include the tax, find the same code as in Solution B1 in catalog/controller/payment/pp_standard.php and change to :
However, there is still a problem with shipping and product options. The shipping should ideally be passed to PayPal as a product, including VAT. I haven't gone through the code yet, but it should be possible. I don't know how product options are calculated.
So, for people who are using shops that don't show tax in the prices, there isn't much to change except to disable the currency conversion rounding, as long as you are using 2 decimal place prices.
For people who display taxes in prices, the ideas above would be a temporary fix. A complete change of opencart to allow entry of prices including VAT would help fix a lot of the problems.
I haven't tried this modification. And I'm no expert. Just started with opencart, php, and sql 1 week ago.
And I take no responsibility and make no warranty to its effects.
1) Error - taxes
- Problem A - when displaying prices including tax, the displayed product total doesn't match the individual price, when using 2 decimal places. Does not affect people who don't display tax in price.
Price: 10.24
incl 19% VAT: 10.24 * 1.19 = 12.1856 (frontend 12.19)
Customer orders 10: 12.1856 * 10 = 121.856 (frontend 121.86) (expected 121.90)
- Solution A - use 4 decimal points.
price: 10.2437
incl 19% VAT: 10.2437 * 1.19 = 12.190003 (frontend 12.19)
Customer order 10: 10.2437 * 1.19 * 10 = 121.90003 (frontend 121.90)
- Problem B - when a customer orders a large amount, the displayed price incl. tax doesn't match the total product price. Does not affect people who don't display tax in price.
Example:
price: 10.2437
incl 19% VAT: 10.2437 * 1.19 = 12.190003 (frontend 12.19)
Customer order 2000: 10.2437 * 1.19 * 2000 = 24380.006 (frontend 24380.01) (expected 24380.00)
- Solution B1 - limit orders to less than 1000 when using at least 4 decimal points, or 100 if using 3 decimal points.
- Solution B2 - change the opencart system to allow admin to enter price including VAT.
2) Error - Currency
Product price excl. tax is rounded to 2 decimal places during currency conversion, for each individual item, and then when taxes are displayed, the same problem occurs as in Error 1 - Tax - Problem A. Does not normally affect people who don't display taxes in prices, although the converted total may not equal to expected total, as rounding on conversion takes place on the individual quantity level, instead of applied to the pre-converted total.
Example:
Price: 10.24
Conversion rate: .746528
New Price: round(10.24 * .746528, 2) = 7.64
incl 19% VAT: 7.64 * 1.19 = 9.0916 (frontend 9.09)
Customer order 100: 7.64 * 1.19 * 100 = 909.16 (frontend 909.16) (expected 909.00)
For people who don't display taxes:
Price: 10.24
Conversion rate: .746528
New Price: round(10.24 * .746528, 2) = 7.64
Customer order 100: 7.64 * 100 = 764.00 (frontend 764.00)
Admin expects: 10.24 * .746528 * 100 = 764.44
- Solution - disable rounding in currency conversion
In system/library/currency.php
Change this:
Code: Select all
$string .= number_format(round($value, (int)$decimal_place), (int)$decimal_place, $decimal_point, $thousand_point);
Code: Select all
$string .= number_format($value, (int)$decimal_place, $decimal_point, $thousand_point);
Error 3) Paypal Price Mismatch - PayPal doesn't match the shopping cart, due to 2 decimal limitation.
Example:
price: 10.2437
incl 19% VAT: 10.2437 * 1.19 = 12.190003 (frontend 12.19)
Customer order 10: 10.2437 * 1.19 * 10 = 121.90003 (frontend 121.90)
Paypal: 10.24 * 10 = 102.40
Opencart passes tax to Paypal: 10.2437 * 0.19 * 10 = 19.46303 (passes 19.46)
Paypal total: 102.40 + 19.46 = 121.86 (mismatch)
-Solution A - (not effective) use 2 decimal places. However, people who display prices including tax will encounter the same problem in Error 1 - Tax - Problem A. People who don't display taxes, but need to use more than 2 decimal places, will encounter the same problem.
- Solution B1 including people with more than 2 decimal points - pass product total as one lot (including tax) to Paypal for each product. Quantity of 1 for each product. Item description is changed to "Lot of 'quantity' of product". Tax removed from "shipping, handing, tax" calculations, by adding tax to subtotal.
To remove the tax from the "shipping, handing, tax", in system/library/cart.php:
Find this function:
Code: Select all
public function getSubTotal() {
$total = 0;
foreach ($this->getProducts() as $product) {
$total += $product['total'];
}
return $total;
}
Code: Select all
public function getSubTotal() {
$total = 0;
foreach ($this->getProducts() as $product) {
$total += $this->tax->calculate($product['total'], $product['tax_class_id'], $this->config->get('config_tax'));
}
return $total;
}
Code: Select all
'price' => $this->currency->format($product['price'], $order_info['currency_code'], false, false),
'quantity' => $product['quantity'],
Code: Select all
'price' => $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')) * $product['quantity'], $order_info['currency_code'], false, false),
'quantity' => 1,
For changes to subtotal, follow the section in Solution B1 regarding subtotal.
For changes to the product price to include the tax, find the same code as in Solution B1 in catalog/controller/payment/pp_standard.php and change to :
Code: Select all
'price' => $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')) , $order_info['currency_code'], false, false),
'quantity' => $product['quantity'],
However, there is still a problem with shipping and product options. The shipping should ideally be passed to PayPal as a product, including VAT. I haven't gone through the code yet, but it should be possible. I don't know how product options are calculated.
So, for people who are using shops that don't show tax in the prices, there isn't much to change except to disable the currency conversion rounding, as long as you are using 2 decimal place prices.
For people who display taxes in prices, the ideas above would be a temporary fix. A complete change of opencart to allow entry of prices including VAT would help fix a lot of the problems.
I haven't tried this modification. And I'm no expert. Just started with opencart, php, and sql 1 week ago.
And I take no responsibility and make no warranty to its effects.
Ok,
So it looks like the paypal shipping, handling, tax, is just calculated from the order.total subtracted by subtotal. In the previous solution, tax was included into the subtotal, which removes it from this calculation. That leaves shipping and handling and other fees, like minimum order fees.
So, just to have the paypal description make more sense, we can change this line of code in catalog/language/english/payment/pp_standard.php:
to
I looked into order_options, and the order_products, and the options are already calculated into the product prices.
I also looked into the currency conversions, and the rounding of currency doesn't actually affect the important calculations. So the fix proposed above shouldn't be used. The final converted displayed totals will come out correct.
However, the displayed unit price will be mismatched when tax is included, but that can't be avoided.
Example:
price: 4.9580
tax 19%: 0.9420
Price incl. VAT: 4.9580 * 1.19 = 5.90002 (frontend 5.90)
quantity 10: 4.9580 * 1.19 * 10 = 59.0002 (frontend 59.00)
currency conversion: 0.74725
price incl. VAT: 4.9580 * 1.19 * 0.74725 = 4.4088 (frontend 4.41)
quantity 10: 4.9580 * 1.19 * 10 * 0.74725 = 44.0879 (frontend 44.09) (expected frontend 44.10)
however, the actual total of 44.09 is correct because it is based on 4 decimals while the unit price 4.41 was rounded.
59.00 * 0.74725 = 44.08775 round to 44.09.
You can put a warning on the site that unit prices when shown in non-base currencies have additional decimals not shown, and the order totals may vary by a few cents when computed from the converted unit price that was rounded to 2 decimal points and shown on screen.
However, we have a problem with PayPal again.
Our theoretical converted unit prices are now more than 2 decimal points: 4.4088, which can't be passed to paypal, and is actually rounded to 2 decimal places by the format() function, to 4.41.
The solution above 2) Solution B2, passing the tax inclusive price to paypal only works if it contains 2 decimals, such as in our base currency: 5.90002, and if you order less than 100 units.
Example Error with modified code passing tax inclusive price:
Converted unit price including tax: 4.41
quantity 10. Paypal calculates 4.41 * 10 = 44.10, while our shopping cart shows 44.09.
Example Error with original code passing tax free price:
Converted unit price without tax: 4.9580 * .74725 = 3.70
quantity 10. Paypal calculates 3.70 * 10 = 37.00
opencart passes the tax to paypal as 4.9580 * 0.19 * 10 * .74725 = 7.04
Paypal total: 37.00 + 7.04 = 44.04, while our shopping chart shows 44.09.
So, the only way of matching 44.09, is if the entire product total, including tax, and converted, is passed as one lot to PayPal as a single quantity, as in 2) Solution B1.
But does this satisfy PayPal seller protection?
So it looks like the paypal shipping, handling, tax, is just calculated from the order.total subtracted by subtotal. In the previous solution, tax was included into the subtotal, which removes it from this calculation. That leaves shipping and handling and other fees, like minimum order fees.
So, just to have the paypal description make more sense, we can change this line of code in catalog/language/english/payment/pp_standard.php:
Code: Select all
$_['text_total'] = 'Shipping, Handling, Discounts & Taxes';
Code: Select all
$_['text_total'] = 'Shipping, Handling, & Discounts';
I also looked into the currency conversions, and the rounding of currency doesn't actually affect the important calculations. So the fix proposed above shouldn't be used. The final converted displayed totals will come out correct.
However, the displayed unit price will be mismatched when tax is included, but that can't be avoided.
Example:
price: 4.9580
tax 19%: 0.9420
Price incl. VAT: 4.9580 * 1.19 = 5.90002 (frontend 5.90)
quantity 10: 4.9580 * 1.19 * 10 = 59.0002 (frontend 59.00)
currency conversion: 0.74725
price incl. VAT: 4.9580 * 1.19 * 0.74725 = 4.4088 (frontend 4.41)
quantity 10: 4.9580 * 1.19 * 10 * 0.74725 = 44.0879 (frontend 44.09) (expected frontend 44.10)
however, the actual total of 44.09 is correct because it is based on 4 decimals while the unit price 4.41 was rounded.
59.00 * 0.74725 = 44.08775 round to 44.09.
You can put a warning on the site that unit prices when shown in non-base currencies have additional decimals not shown, and the order totals may vary by a few cents when computed from the converted unit price that was rounded to 2 decimal points and shown on screen.
However, we have a problem with PayPal again.
Our theoretical converted unit prices are now more than 2 decimal points: 4.4088, which can't be passed to paypal, and is actually rounded to 2 decimal places by the format() function, to 4.41.
The solution above 2) Solution B2, passing the tax inclusive price to paypal only works if it contains 2 decimals, such as in our base currency: 5.90002, and if you order less than 100 units.
Example Error with modified code passing tax inclusive price:
Converted unit price including tax: 4.41
quantity 10. Paypal calculates 4.41 * 10 = 44.10, while our shopping cart shows 44.09.
Example Error with original code passing tax free price:
Converted unit price without tax: 4.9580 * .74725 = 3.70
quantity 10. Paypal calculates 3.70 * 10 = 37.00
opencart passes the tax to paypal as 4.9580 * 0.19 * 10 * .74725 = 7.04
Paypal total: 37.00 + 7.04 = 44.04, while our shopping chart shows 44.09.
So, the only way of matching 44.09, is if the entire product total, including tax, and converted, is passed as one lot to PayPal as a single quantity, as in 2) Solution B1.
But does this satisfy PayPal seller protection?
You may find this helpful. https://github.com/ADDCreative/opencart ... 60b49465b0
This ensured the the final PayPal total equals the OpenCart total. It does this by calculating the subtotal the same as PayPal. This does mean that the subtotals and line prices might not match but the final total will.
This ensured the the final PayPal total equals the OpenCart total. It does this by calculating the subtotal the same as PayPal. This does mean that the subtotals and line prices might not match but the final total will.
I see, thanks for sharing.
I think I'll use your solution, in addition to passing the tax included in the price to Paypal. As my base currency is in euro, and I try to get the tax price as close to 2 decimal points (like 8.3697 excl. tax, 9.959943 incl. tax), passing the tax included price in euro will match with Paypal. But if it gets converted to USD, then your solution will make sure the final price matches, although the product price will not.
I wonder what German laws say about the mismatch of the subtotal though, even if the final price is the same.
Recently there was a lawsuit by some phishing lawyers who said that a Gambio webshop didn't have a shipping estimator included in the shopping cart, even though there was one in the checkout. They won the case, and got compensation for their legal expenses for pointing out the 'error'. And so now all the shops are scrambling to insert the estimator into the shopping cart before the other lawyers find them.
There were also cases where the required terms and conditions were changed by a few words the previous year, and a lawyer pointed it out to the a shop that didn't update it, and got several hundred dollars in compensation.
I wonder if there are cases about mismatching numbers that don't add up. I would be careful about these lawyers, if they would come across people using opencart straight out of the box, where rounding errors are caused by the inability to enter product prices including tax. In Germany it's required to display the tax in the price. So, having to enter into opencart the product price excluding tax, you get these fractional cents in the tax calculations, and you have to be careful trying to get them as close as possible to a whole cent, otherwise the unit price won't match the total price when ordering multiple quantities.
I had a quick look at the admin page in the Gambio demo, and the prices are entered with the tax included to the whole cent. Then the price excluding tax is automatically calculated for use on sales outside of EU where tax is zero rated. But I don't know how they handle rounding during currency conversion.
I think I'll use your solution, in addition to passing the tax included in the price to Paypal. As my base currency is in euro, and I try to get the tax price as close to 2 decimal points (like 8.3697 excl. tax, 9.959943 incl. tax), passing the tax included price in euro will match with Paypal. But if it gets converted to USD, then your solution will make sure the final price matches, although the product price will not.
I wonder what German laws say about the mismatch of the subtotal though, even if the final price is the same.
Recently there was a lawsuit by some phishing lawyers who said that a Gambio webshop didn't have a shipping estimator included in the shopping cart, even though there was one in the checkout. They won the case, and got compensation for their legal expenses for pointing out the 'error'. And so now all the shops are scrambling to insert the estimator into the shopping cart before the other lawyers find them.
There were also cases where the required terms and conditions were changed by a few words the previous year, and a lawyer pointed it out to the a shop that didn't update it, and got several hundred dollars in compensation.
I wonder if there are cases about mismatching numbers that don't add up. I would be careful about these lawyers, if they would come across people using opencart straight out of the box, where rounding errors are caused by the inability to enter product prices including tax. In Germany it's required to display the tax in the price. So, having to enter into opencart the product price excluding tax, you get these fractional cents in the tax calculations, and you have to be careful trying to get them as close as possible to a whole cent, otherwise the unit price won't match the total price when ordering multiple quantities.
I had a quick look at the admin page in the Gambio demo, and the prices are entered with the tax included to the whole cent. Then the price excluding tax is automatically calculated for use on sales outside of EU where tax is zero rated. But I don't know how they handle rounding during currency conversion.
If you follow ADD Creative's solution, it works perfectly to ensure the final price is the same as the OC price. The product totals will still be off by a few cents but I don't think it can be fixed.
I wanted to pass the taxed unit price to Paypal, and it also gets the unit prices a few cents closer to their real value, so using ADD Creative's solution as a reference, I created my own to include tax.
I wanted to pass the taxed unit price to Paypal, and it also gets the unit prices a few cents closer to their real value, so using ADD Creative's solution as a reference, I created my own to include tax.
Code: Select all
<file name="catalog/controller/payment/pp_standard.php">
<operation info="create paypal subtotal calc fix variable">
<search position="after"><![CDATA[
$this->data['products'] = array();
]]></search>
<add><![CDATA[
$subtotal = 0;
]]></add>
</operation>
<operation info="calculate price with tax, update subtotal">
<search position="before"><![CDATA[
$this->data['products'][] = array(
]]></search>
<add><![CDATA[
$price = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')), $order_info['currency_code'], false, false);
$subtotal += $price * $product['quantity'];
]]></add>
</operation>
<operation info="assign new price with tax">
<search position="replace"><![CDATA[
'price' => $this->currency->format($product['price'], $order_info['currency_code'], false, false),
]]></search>
<add><![CDATA[
'price' => $price,
]]></add>
</operation>
<operation info="calculate new other charges, excl tax">
<search position="replace"><![CDATA[
$total = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $order_info['currency_code'], false, false);
]]></search>
<add><![CDATA[
$total = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false) - $subtotal;
]]></add>
</operation>
</file>
<file name="catalog/language/english/payment/pp_standard.php">
<operation info="remove tax from text">
<search position="replace"><![CDATA[
$_['text_total'] = 'Shipping, Handling, Discounts & Taxes';
]]></search>
<add><![CDATA[
$_['text_total'] = 'Shipping, Handling, & Discounts';
]]></add>
</operation>
</file>
Thank you so much Thomash2, this has driven me mad since I discovered the problem with Paypal in final testing after building my store...now I can "un-fudge" my prices back to accurate 4 decimals (or greater if I buy a mod) and not cause problems taking payments 

Stokey
Does this work for your oc?stokeyblokey wrote:Thank you so much Thomash2, this has driven me mad since I discovered the problem with Paypal in final testing after building my store...now I can "un-fudge" my prices back to accurate 4 decimals (or greater if I buy a mod) and not cause problems taking payments
I'm using 1.5.5.1. when checkout, the error is email mismatch. and the total order is 0.01 difference with paypal. I don't know why.
thanks.rounding problem solved.thomash2 wrote:If you follow ADD Creative's solution, it works perfectly to ensure the final price is the same as the OC price. The product totals will still be off by a few cents but I don't think it can be fixed.
I wanted to pass the taxed unit price to Paypal, and it also gets the unit prices a few cents closer to their real value, so using ADD Creative's solution as a reference, I created my own to include tax.
Code: Select all
<file name="catalog/controller/payment/pp_standard.php"> <operation info="create paypal subtotal calc fix variable"> <search position="after"><![CDATA[ $this->data['products'] = array(); ]]></search> <add><![CDATA[ $subtotal = 0; ]]></add> </operation> <operation info="calculate price with tax, update subtotal"> <search position="before"><![CDATA[ $this->data['products'][] = array( ]]></search> <add><![CDATA[ $price = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')), $order_info['currency_code'], false, false); $subtotal += $price * $product['quantity']; ]]></add> </operation> <operation info="assign new price with tax"> <search position="replace"><![CDATA[ 'price' => $this->currency->format($product['price'], $order_info['currency_code'], false, false), ]]></search> <add><![CDATA[ 'price' => $price, ]]></add> </operation> <operation info="calculate new other charges, excl tax"> <search position="replace"><![CDATA[ $total = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $order_info['currency_code'], false, false); ]]></search> <add><![CDATA[ $total = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false) - $subtotal; ]]></add> </operation> </file> <file name="catalog/language/english/payment/pp_standard.php"> <operation info="remove tax from text"> <search position="replace"><![CDATA[ $_['text_total'] = 'Shipping, Handling, Discounts & Taxes'; ]]></search> <add><![CDATA[ $_['text_total'] = 'Shipping, Handling, & Discounts'; ]]></add> </operation> </file>
Thank you a lot.thomash2 wrote:If you follow ADD Creative's solution, it works perfectly to ensure the final price is the same as the OC price. The product totals will still be off by a few cents but I don't think it can be fixed.
I wanted to pass the taxed unit price to Paypal, and it also gets the unit prices a few cents closer to their real value, so using ADD Creative's solution as a reference, I created my own to include tax.
Code: Select all
<file name="catalog/controller/payment/pp_standard.php"> <operation info="create paypal subtotal calc fix variable"> <search position="after"><![CDATA[ $this->data['products'] = array(); ]]></search> <add><![CDATA[ $subtotal = 0; ]]></add> </operation> <operation info="calculate price with tax, update subtotal"> <search position="before"><![CDATA[ $this->data['products'][] = array( ]]></search> <add><![CDATA[ $price = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')), $order_info['currency_code'], false, false); $subtotal += $price * $product['quantity']; ]]></add> </operation> <operation info="assign new price with tax"> <search position="replace"><![CDATA[ 'price' => $this->currency->format($product['price'], $order_info['currency_code'], false, false), ]]></search> <add><![CDATA[ 'price' => $price, ]]></add> </operation> <operation info="calculate new other charges, excl tax"> <search position="replace"><![CDATA[ $total = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $order_info['currency_code'], false, false); ]]></search> <add><![CDATA[ $total = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false) - $subtotal; ]]></add> </operation> </file> <file name="catalog/language/english/payment/pp_standard.php"> <operation info="remove tax from text"> <search position="replace"><![CDATA[ $_['text_total'] = 'Shipping, Handling, Discounts & Taxes'; ]]></search> <add><![CDATA[ $_['text_total'] = 'Shipping, Handling, & Discounts'; ]]></add> </operation> </file>
Hi dynamoproductions,
There is an error with that bit of code that causes an error reported by frankleng above. The line:
Should now be:
There is an error with that bit of code that causes an error reported by frankleng above. The line:
Code: Select all
$total = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false) - $subtotal;
Code: Select all
$total = $this->currency->format($this->currency->convert($order_info['total'], $this->config->get('config_currency'), $order_info['currency_code']) - $subtotal, $order_info['currency_code'], 1.0, false);
Who is online
Users browsing this forum: No registered users and 7 guests