Jump to content

Tax is calculated wrong in Prestashop. It has to be. Not just me - but everyone!


Recommended Posts

I Fail to see why this isn't reported

 

Surely the whole way tax is worked out in prestashop is WRONG for everyone who uses it?

Tax is paid per product you sell not per order.

 

Prestashop works out tax by:

 

Tools::ps_round($row['price'] * (float)$row['cart_quantity'] * (1 + (float)$tax_rate / 100), 2);

 

Which is: Product * Quantity * Tax rate.

 

Should it not be: (Product * Tax Rate), rounded up 2 decimal places, multiplied by the quantity????

 

If a product in the UK is £99.31, and vat is 20% - you would not charge the customer £119.172, you would charge them £119.17.

It may appear ok to do it like that - but if they ordered 100 items, thats 20p more because of all the 0.002 Pences!

If you pay via paypal, there will be an error because the submitted paypal order paid total, will be more than the prestashop stored total required for that order

 

 

Should this not actually be worked out as:

$actualvalue= Tools::ps_round($row['price'] * (1 + (float)$tax_rate / 100), 2);

$actualtotal = $actualvalue* (float)$row['cart_quantity'];

 

Maybe someone with an accountancy background instead of a coding background can take a look at it for me - As Logically, my method makes more sense to me

 

**EDIT**

 

For Prestashop 1.5.4.1, current tax page display workaround is: This Updated Post!

Edited by mrotacon (see edit history)
  • Thanks 1
Link to comment
Share on other sites

Ok. You can work around this, as I just did.

 

If you created an extended method for getting order totals, it will sort it.

 

What I did was, inside the file: /override/classes/Cart.php

I added a method:

 

public function getOrderTotal($with_taxes = true, $type = Cart::BOTH, $products = null, $id_carrier = null, $use_cache = true)
{
 if (!$this->id)
  return 0;
 $type = (int)$type;
 $array_type = array(
  Cart::ONLY_PRODUCTS,
  Cart::ONLY_DISCOUNTS,
  Cart::BOTH,
  Cart::BOTH_WITHOUT_SHIPPING,
  Cart::ONLY_SHIPPING,
  Cart::ONLY_WRAPPING,
  Cart::ONLY_PRODUCTS_WITHOUT_SHIPPING,
  Cart::ONLY_PHYSICAL_PRODUCTS_WITHOUT_SHIPPING,
 );

 // Define virtual context to prevent case where the cart is not the in the global context
 $virtual_context = Context::getContext()->cloneContext();
 $virtual_context->cart = $this;
 if (!in_array($type, $array_type))
  die(Tools::displayError());
 $with_shipping = in_array($type, array(Cart::BOTH, Cart::ONLY_SHIPPING));

 // if cart rules are not used
 if ($type == Cart::ONLY_DISCOUNTS && !CartRule::isFeatureActive())
  return 0;
 // no shipping cost if is a cart with only virtuals products
 $virtual = $this->isVirtualCart();
 if ($virtual && $type == Cart::ONLY_SHIPPING)
  return 0;
 if ($virtual && $type == Cart::BOTH)
  $type = Cart::BOTH_WITHOUT_SHIPPING;
 if ($with_shipping)
 {
  if (is_null($products) && is_null($id_carrier))
   $shipping_fees = $this->getTotalShippingCost(null, (boolean)$with_taxes);
  else
   $shipping_fees = $this->getPackageShippingCost($id_carrier, (int)$with_taxes, null, $products);
 }
 else
  $shipping_fees = 0;
 if ($type == Cart::ONLY_PRODUCTS_WITHOUT_SHIPPING)
  $type = Cart::ONLY_PRODUCTS;
 $param_product = true;
 if (is_null($products))
 {
  $param_product = false;
  $products = $this->getProducts();
 }

 if ($type == Cart::ONLY_PHYSICAL_PRODUCTS_WITHOUT_SHIPPING)
 {
  foreach ($products as $key => $product)
   if ($product['is_virtual'])
 unset($products[$key]);
  $type = Cart::ONLY_PRODUCTS;
 }
 $order_total = 0;
 if (Tax::excludeTaxeOption())
  $with_taxes = false;
 foreach ($products as $product) // products refer to the cart details
 {
  if ($virtual_context->shop->id != $product['id_shop'])
   $virtual_context->shop = new Shop((int)$product['id_shop']);
  if (Configuration::get('PS_TAX_ADDRESS_TYPE') == 'id_address_invoice')
   $address_id = (int)$this->id_address_invoice;
  else
   $address_id = (int)$product['id_address_delivery']; // Get delivery address of the product from the cart
  if (!Address::addressExists($address_id))
   $address_id = null;

  if ($this->_taxCalculationMethod == PS_TAX_EXC)
  {
   // Here taxes are computed only once the quantity has been applied to the product price
   $price = Product::getPriceStatic(
 (int)$product['id_product'],
 false,
 (int)$product['id_product_attribute'],
 2,
 null,
 false,
 true,
 $product['cart_quantity'],
 false,
 (int)$this->id_customer ? (int)$this->id_customer : null,
 (int)$this->id,
 $address_id,
 $null,
 true,
 true,
 $virtual_context
   );
   $total_ecotax = $product['ecotax'] * (int)$product['cart_quantity'];
   $total_price = $price * (int)$product['cart_quantity'];
   if ($with_taxes)
   {
 $product_tax_rate = (float)Tax::getProductTaxRate((int)$product['id_product'], (int)$address_id, $virtual_context);
 $product_eco_tax_rate = Tax::getProductEcotaxRate((int)$address_id);   
 $total_price = Tools::ps_round(($price - $product['ecotax'])  * (1 + $product_tax_rate / 100),2);
 $total_price = $total_price * (int)$product['cart_quantity'];
   }
  }
  else
  {
   if ($with_taxes)
 $price = Product::getPriceStatic(
  (int)$product['id_product'],
  true,
  (int)$product['id_product_attribute'],
  2,
  null,
  false,
  true,
  $product['cart_quantity'],
  false,
  ((int)$this->id_customer ? (int)$this->id_customer : null),
  (int)$this->id,
  ((int)$address_id ? (int)$address_id : null),
  $null,
  true,
  true,
  $virtual_context
 );
   else
 $price = Product::getPriceStatic(
  (int)$product['id_product'],
  false,
  (int)$product['id_product_attribute'],
  2,
  null,
  false,
  true,
  $product['cart_quantity'],
  false,
  ((int)$this->id_customer ? (int)$this->id_customer : null),
  (int)$this->id,
  ((int)$address_id ? (int)$address_id : null),
  $null,
  true,
  true,
  $virtual_context
 );
   $total_price = Tools::ps_round($price * (int)$product['cart_quantity'], 2);
  }
  $order_total += $total_price;
 }
 $order_total_products = $order_total;
 if ($type == Cart::ONLY_DISCOUNTS)
  $order_total = 0;
 // Wrapping Fees
 $wrapping_fees = 0;
 if ($this->gift)
  $wrapping_fees = Tools::convertPrice(Tools::ps_round($this->getGiftWrappingPrice($with_taxes), 2), Currency::getCurrencyInstance((int)$this->id_currency));
 $order_total_discount = 0;
 if (!in_array($type, array(Cart::ONLY_SHIPPING, Cart::ONLY_PRODUCTS)) && CartRule::isFeatureActive())
 {
  // First, retrieve the cart rules associated to this "getOrderTotal"
  if ($with_shipping)
   $cart_rules = $this->getCartRules(CartRule::FILTER_ACTION_ALL);
  else
  {
   $cart_rules = $this->getCartRules(CartRule::FILTER_ACTION_REDUCTION);
   // Cart Rules array are merged manually in order to avoid doubles
   foreach ($this->getCartRules(CartRule::FILTER_ACTION_GIFT) as $tmp_cart_rule)
   {
 $flag = false;
 foreach ($cart_rules as $cart_rule)
  if ($tmp_cart_rule['id_cart_rule'] == $cart_rule['id_cart_rule'])
   $flag = true;
 if (!$flag)
  $cart_rules[] = $tmp_cart_rule;
   }
  }

  $id_address_delivery = 0;
  if (isset($products[0]))
   $id_address_delivery = (is_null($products) ? $this->id_address_delivery : $products[0]['id_address_delivery']);
  $package = array('id_carrier' => $id_carrier, 'id_address' => $id_address_delivery, 'products' => $products);

  // Then, calculate the contextual value for each one
  foreach ($cart_rules as $cart_rule)
  {
   // If the cart rule offers free shipping, add the shipping cost
   if ($with_shipping && $cart_rule['obj']->free_shipping)
 $order_total_discount += Tools::ps_round($cart_rule['obj']->getContextualValue($with_taxes, $virtual_context, CartRule::FILTER_ACTION_SHIPPING, ($param_product ? $package : null), $use_cache), 2);
   // If the cart rule is a free gift, then add the free gift value only if the gift is in this package
   if ((int)$cart_rule['obj']->gift_product)
   {
 $in_order = false;
 if (is_null($products))
  $in_order = true;
 else
  foreach ($products as $product)
   if ($cart_rule['obj']->gift_product == $product['id_product'] && $cart_rule['obj']->gift_product_attribute == $product['id_product_attribute'])
    $in_order = true;
 if ($in_order)
  $order_total_discount += $cart_rule['obj']->getContextualValue($with_taxes, $virtual_context, CartRule::FILTER_ACTION_GIFT, $package, $use_cache);
   }
   // If the cart rule offers a reduction, the amount is prorated (with the products in the package)
   if ($cart_rule['obj']->reduction_percent > 0 || $cart_rule['obj']->reduction_amount > 0)
 $order_total_discount += Tools::ps_round($cart_rule['obj']->getContextualValue($with_taxes, $virtual_context, CartRule::FILTER_ACTION_REDUCTION, $package, $use_cache), 2);
  }

  $order_total_discount = min(Tools::ps_round($order_total_discount, 2), $wrapping_fees + $order_total_products + $shipping_fees);
  $order_total -= $order_total_discount;
 }
 if ($type == Cart::ONLY_SHIPPING)
  return $shipping_fees;
 if ($type == Cart::ONLY_WRAPPING)
  return $wrapping_fees;
 if ($type == Cart::BOTH)
  $order_total += $shipping_fees + $wrapping_fees;
 if ($order_total < 0 && $type != Cart::ONLY_DISCOUNTS)
  return 0;
 if ($type == Cart::ONLY_DISCOUNTS)
  return $order_total_discount;
 return Tools::ps_round((float)$order_total, 2);
}

 

 

The only subtle changes here are around the first instance of if ($with_taxes)

 if ($with_taxes)
   {
 $product_tax_rate = (float)Tax::getProductTaxRate((int)$product['id_product'], (int)$address_id, $virtual_context);
 $product_eco_tax_rate = Tax::getProductEcotaxRate((int)$address_id);   
 $total_price = Tools::ps_round(($price - $product['ecotax'])  * (1 + $product_tax_rate / 100),2);
 $total_price = $total_price * (int)$product['cart_quantity'];
}

 

I work out the value for a single product with tax, and round it - then finally the total for all of them, but I do not round that - as the order total float is rounded later - so you do not need to!

 

Hopefully this helps you too!

Link to comment
Share on other sites

Sure no problem :)

 

this is the Cart.php file located at:

 

/override/classes/Cart.php

 

You can override or extend any functionality from the main class in this file, so your not changing the core of prestashop :)

 

Please MAKE NOTE of the PATH above to make sure you put this file in the right place :)

Cart.php

  • Like 1
Link to comment
Share on other sites

I'm sorry - I haven't tested it it yet and don't have access to diff atm (mobile).

Looking at the Cart.php from 1.5.4 now and the getOrderTotal() function looks pretty much the same. The changes if you want to implement direct are lines 1398, and 1405 -> 1407 :)

 

I will probably check tomorrow

Link to comment
Share on other sites

Hi Benjamin,

 

I haven't yet - as I wanted to make sure it was ok for others.

 

I have only changed the cart system here, nothing else. So invoicing will still need to be changed (which i plan to do over the weekend).

 

By profession, I'm the senior .net developer for our company, but one of our directors decided that it would fall onto me to sort the company website - which is why I implemented Prestashop - to save me time :D

And it has - a Lot!

 

I am only informed about the issues they are having at the end of every week, and so have been waiting for this weeks update from them to see if this caused them any issues (it shouldn't - its only extending the Cart classes)

 

I will gladly submit the changes over the weekend though :)

  • Like 1
Link to comment
Share on other sites

  • 3 months later...

Thanks for posting this! I'm VERY inexperienced in prestashop (and php), but am trying to help a friend with the same problem listed above.

 

Another question - would anyone happen to know if this change has been incorporated into the newest version 1.5.4.1?

 

I tested the change in the override/classes/cart.php (I just downloaded the cart.php file above and copied it into that folder) and got the same error that the person reported above.

 

EDIT: 2a8qddh.jpg

 

It's worth mentioning that we are using an old version of Prestashop 1.5.2.0

Edited by edanto (see edit history)
Link to comment
Share on other sites

Hi,

 

no, the same error with the tax is also in the prestashop version 1.5.4.1.

It was probable the same error always in previous versions of prestashop, but maybe it's just not noticed.

 

I want to use the prestashop too, but not with this bad error with the tax calculation.

 

In the german forum i opened a topic and the users there, have also incorporated in the bug tracker.

 

Here the link to the posting in the bug tracker: http://forge.prestashop.com/browse/PSCFV-7864

 

Maybe you can also write there a comment.

So the programmers see, that it is a problem for ALL prestashop users.

 

Sorry, for my terrible english and good night :-)

  • Like 1
Link to comment
Share on other sites

Hi,

Me too I have problem with taxes in v.1.5.4.1

My problem maybe a little bit diffetrent but for sure there is a problem with taxes.

I've already reported in Forge and replied sometimes later to get an answer but noboay responded.

It's very frustrating, I spent too much time for debugging and I have a bussines to run.

Honestly with my experience with Prestashop, that brings me to think seriously and take a decision if I continue with Prestashop or not. I thought this shopping-cart is built for selling and doing business.

I spent about 2 month just for debugging and I am wondering why they released this version 1.5 as a Stable version for production!

I have a topic about the taxes issue, here is the link:

http://www.prestashop.com/forums/topic/259354-tax-is-wrongly-calculated-tax-100000-and-more-for-any-subtotal/

 

Regards.

Link to comment
Share on other sites

  • 4 weeks later...

Hi Again!

 

Still tax trouble I see :(

 

Ok. In prestashop 1.5.4.1, find the file:

/classes/Cart.php

 

find and replace the section (in the public function GetOrderTotal) [LINES 1399 -> 1409]

$total_price = $price * (int)$product['cart_quantity'];
if ($with_taxes)
{
 $product_tax_rate = (float)Tax::getProductTaxRate((int)$product['id_product'], (int)$address_id, $virtual_context);
 $product_eco_tax_rate = Tax::getProductEcotaxRate((int)$address_id);
 $total_price = ($total_price - $total_ecotax) * (1 + $product_tax_rate / 100);
 $total_ecotax = $total_ecotax * (1 + $product_eco_tax_rate / 100);
 $total_price = Tools::ps_round($total_price + $total_ecotax, 2);
}

 

with the following (only slightly different, but it is a minor error)

$total_price = Tools::ps_round($price * (int)$product['cart_quantity'],2);
   if ($with_taxes)
   {
        $product_tax_rate = (float)Tax::getProductTaxRate((int)$product['id_product'], (int)$address_id, $virtual_context);
        $product_eco_tax_rate = Tax::getProductEcotaxRate((int)$address_id);
        $total_price = Tools::ps_round((($price - $total_ecotax) * (1 + $product_tax_rate / 100)),2);
        $total_price = $total_price * (int)$product['cart_quantity'];
        $total_ecotax = $total_ecotax * (1 + $product_eco_tax_rate / 100);
        $total_price = Tools::ps_round($total_price + $total_ecotax, 2);
   }

 

Now look towards the nearest person and demand they make you a coffee while you pat yourself on the back for making your tax actually work properly :)

Gratz

Edited by mrotacon (see edit history)
  • Like 2
Link to comment
Share on other sites

Hi mrotacon,

 

I would be very happy to solve the VAT issue in my webshop, but I'm not quite sure wether I should only make the changes in your latest post or also make the changes you have mentioned earlier in this topic in the override/classes/cart.php file?

 

Also does this change also solve the VAT issue on the invoice or just in de shopping cart?

 

Thank you for your help.

 

Kind regards.

Link to comment
Share on other sites

That's just in the shopping cart. I will look at invoices when I get back from holiday this weekend.

 

Please only apply the single edited for version 1.5.4.1 (my previous post). I will link it in my first post.

(/classes/Cart.php

 

Cheers :)

Link to comment
Share on other sites

Hi Mrotacon,

 

Thanks for your reply and your help. It would be great if you could also take a look at the invoices, because this causes my invoices to be wrong. That doesn't make the IRS in Holland very happy ;-)

 

Kind Regards.

Link to comment
Share on other sites

  • 1 month later...

Hello,

 

i did many tests. Environment is prestashop 1.5.4.1 and paypal europe module 3.6.1.

Single currency and single tax. Paypal set as paypal pro, set in module configuration paypal pro, live
Iframe works and is shown correctly. Payments are processed. I tried following  http://www.prestashop.com/forums/topic/235504-tax-is-calculated-wrong-in-prestashop-it-has-to-be-not-just-me-but-everyone/?do=findComment&comment=1333319

this too but no solution.

 

Here is the problem:

 

- If the cart is without specific price reduction or voucher payments appear to be processed correctly, Iframe behaves properly. Confirmation is right both in paypal iframe and in prestashop redirect and order appears in backoffice. Seems fine without voucher and price reductions

 

- If in the cart there is a voucher the behaviour is the same as above, but after the paypal confirmation in iframe (that is correct) when redirected to prestashop order confirmation gives the error: 1. An error occurred while processing payment
The order is created in backoffice with status payment error, and paypal leaves a message: Price paid on paypal is not the same that on PrestaShop.

 

- If the voucher covers the product cost completely so it costs 0 (i have loyalty program and one can accumulate point that cover the entire price of the product), the behaviour is still the same, but the error is 1043 directly in the iframe and payment is not processed.

There should be a transaction with the shipment only.

 

If i use paypal without the pro, with the web payment option, everything works fine without problems. This happens only when is set in paypal pro mode.

 

I don't understand if it is related to : rounding, taxes, both. The only resource i found really related is the post above, but it doesnt give any solution to me.

Link to comment
Share on other sites

  • 1 month later...
  • 3 months later...

Was a patch ever created for the Prestashop tax errors?

I have just set up a PS1.6.0.5 test site, ran a test transaction and the tax is wrong in both the front and back office

Widget = £50.99 with UK VAT at 20%
1 x Widget @ £50.99 exVat = £61.19 Inc VAT -  CORRECT
10 x Widget @ £509.90 exVat = £611.90 Inc VAT - INCORRECT

it should be £611.88 Inc VAT

 

Link to comment
Share on other sites

  • 4 months later...

Bumping this. I have no desire to install the latest version of Prestashop with this major bug. Every time a local customer pays via Paypal, they get a payment error because of taxing inconsistencies.  

 

What error do they receive? What version of PrestaShop are you using? What version of PayPal are you using? Does this happen every single time a local customer pays via PayPal?

 

Thanks for the additional information! 

Link to comment
Share on other sites

  • 2 weeks later...

I have a slightly different problem but still with tax.

 

In V1.6 I have 2 products, P1 and P2.  P1 costs $10 with 10% GST (Australia).  P2 costs also $10 but is tax free.

 

If a customer buys P1 the tax is correct and the price is $11.

 

If a customer buys P2 the tax is not charged and the price is $10.

 

BUT if the customer buys both in the same order, the tax is calculated on the sum of the items and not on the product line, so the price becomes $22 = (10+10) + (10+10)* 0.1.  It should be $21.

 

This is the same for shipping.  If the shipping charge is set to "no tax" the tax is still calculated on the total invoice not the individual line items.

 

Is there a way to tell Prestashop to calculate tax on each line?  This seems like a very fundamental problem so I expect that I am missing some basic configuration setting.

 

Cheers

 

Tim

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

Hi,

Me too I have problem with taxes in v.1.5.4.1

My problem maybe a little bit diffetrent but for sure there is a problem with taxes.

I've already reported in Forge and replied sometimes later to get an answer but noboay responded.

It's very frustrating, I spent too much time for debugging and I have a bussines to run.

Honestly with my experience with Prestashop, that brings me to think seriously and take a decision if I continue with Prestashop or not. I thought this shopping-cart is built for selling and doing business.

I spent about 2 month just for debugging and I am wondering why they released this version 1.5 as a Stable version for production!

I have a topic about the taxes issue, here is the link:

http://www.prestashop.com/forums/topic/259354-tax-is-wrongly-calculated-tax-100000-and-more-for-any-subtotal/

 

Regards.

 

I agree completely with you. 

 

I started seven months ago with our e-commerce. Our programmer recommend us Prestashop and version 1.4 because he explained that 1.5 has a lot of problems. So we made the investment. And now we realize that prestashop is unable to print correctly the bills. Yesterday I posted this mistake and finally a team member prestashop explained to me that there is no solution for this issue. She recommend upgrade to 1.6 and test if it is fixed.

 

The point is, how is possible that prestashop has this problem for so long? With this failure it is unable to be used for selling. I can't believe it !

 

 

Tilkar

Link to comment
Share on other sites

  • 3 weeks later...

This is the same for shipping.  If the shipping charge is set to "no tax" the tax is still calculated on the total invoice not the individual line items.

 

Is there a way to tell Prestashop to calculate tax on each line?  This seems like a very fundamental problem so I expect that I am missing some basic configuration setting.

 

Myself I think they are over thinking tax even on the shipping. Consider each product or shipping a single line item. Calculate the tax for each product if a product is taxable and keep a running tally of product tax. Calculate the shipping if taxed keep a running tally of shipping tax. Don't add the tax in until the end and forget about the tax incl tax excl bit. At the end add the product tax to the shipping tax and round to two decimal places.

 

That would fix just about every tax bug I have read about on the forums. Right now I get to fix shipping costs based on price because the tax is being added into price before shipping is calculated. Keep the taxes separate until the end, combine, round. Do it all in a ps_tax_cache table associated to the cart. Easy peezy.

 

Just my $0.02000

Link to comment
Share on other sites

  • 5 weeks later...

And unfortunately I have several customers that don't even like the look of 1.6. The templating is "clunky" so they figure it's full of bugs as well.  They are doing right waiting on .10 because they're moving too fast and not discovering or fixing the bugs in the previous versions.   

Link to comment
Share on other sites

  • 4 months later...

I dont aggre - i have spent 4 months removing bugs and issues on current version, so upgrading, no thanks, never. But please let me know what will need to be changed. Maybe its possible to view the changes made to fix these issues? is there a bug thread on github i can see?

  • Like 1
Link to comment
Share on other sites

  • 2 months later...

I ran into this problem the day before yesterday.

In denmark we have 25% tax.

I've got an item that cost 3,95 DKK, when selling this item without any discount, the tax is calculated correctly.

Price incl tax = 3,95 rounded 3,95

Tax: 3,95 * 0,25 = 0,79 rounded 0,79

Price excl. tax = 3,16 rounded 3,16

 

But when I give 10% discount, my troubles begin.

3,95*0,9 = 3,555

 

When the tax is calculated from 3,555 rather than 3,56, which is the amount the customer is actually paying, the tax is calculated wrong.

When calculating from 3,555:

Price incl. tax= 3,555 rounded to 3,56

Tax: 3,555*0,25 = 0,711 rounded to 0,71

Price excl. tax = 2,844 rounded to 2,84

 

When calculating from 3,56:

Price incl. tax = 3,56 rounded to 3,56

Tax: 3,56*0,25 = 0,712 rounded to 0,71

Price excl. tax = 2,848 rounded to 2,85

 

As you can see the calculation when calculating from 3,555 does not add up, when displaying the rounded numbers to the customer.

When using tax calculation from the actual amount beeing pay, 3,56, the calculation does indeed add up.

 

Just to check up on the calculation, I've done the same calculations when selling 10 of these items.

3,95*10*0,9 = 35,55

This does not give any rounding complications, but the calculation is as follows:

Price incl. tax = 35,55 rounded 35,55

Tax: 35,55*0,25 = 7,11 rounded 7,11

Price excl. tax = 28,44 rounded 28,44

 

Could the problem with tax calculations be that it is purly done from a mathimatical point of view, rather from the actual amount the customer is paying?

I'm currently using Prestashop 1.6.0.14

post-832278-0-38663300-1433675662_thumb.png

Edited by LeoFish (see edit history)
Link to comment
Share on other sites

  • 2 years later...
×
×
  • Create New...