Jump to content

[SOLVED] I got a small big problem - Wrong calculation of shipping tax (rounding)

Recommended Posts

Hi there

I am trying to help a client move over to a new accounting system, but without having to change cart system.

So I found an integration provider that could connect the new accounting system to the webshop.

But the integration provider stops orders with wrong tax calculation (wich they should), but this problem is a bit unique:





When Prestashop calculates the tax of the shipping, wich in my case is 25%, it rounds the total incl. tax.

How it should look:

199 * 1.25 = 248.750000

What Prestashop calculates:

199 * 1.25 = 249.000000






And that in turn gives a wrong total that the customer is paying.

They should be paying:

3,112 * 1.25 =  3,890.000000

But they end up paying 3,890.250000


Does anyone know which file and/or line that rounds the shipping price, or have any suggestions to how else I could solve this?

Thank you.

Edited by d3m0t3x
Problem solved (see edit history)
Link to comment
Share on other sites

Hi there,

which version of Prestashop are you using?

Supposing you are using PS 1.6.1.X you can check your rounding preferences in the backoffice under Preferences -> General.

Then, if you want to have a look at the code, you'll find the functions relative to the shipping costs under Classes->Carrier.php (mostly DB functions here) and Classes->Cart.php (various shipping costs calculations relative to the client address).

I hope this helps!
Have a nice day,

  • Thanks 1
Link to comment
Share on other sites

Thank you for the really quick response :) 

Yes, the client's version is

I have tried all of the different combinations of the rounding options, but it still rounds the price of shipping incl. tax.


But thanks a lot for a point in the right direction, I'll go dig for a bit :D 

Link to comment
Share on other sites

I am one step closer, thanks to @fedesib!


I found the code in Cart.php starting at line 3025:

        if (Configuration::get('PS_ATCP_SHIPWRAP')) {
            if (!$use_tax) {
                // With PS_ATCP_SHIPWRAP, we deduce the pre-tax price from the post-tax
                    // price. This is on purpose and required in Germany.
                    $shipping_cost /= (1 + $this->getAverageProductsTaxRate());
        } else {
            // Apply tax
            if ($use_tax && isset($carrier_tax)) {
                $shipping_cost *= 1 + ($carrier_tax / 100);

        $shipping_cost = (float)Tools::ps_round((float)$shipping_cost, (Currency::getCurrencyInstance((int)$this->id_currency)->decimals * _PS_PRICE_DISPLAY_PRECISION_));
        Cache::store($cache_id, $shipping_cost);

        return $shipping_cost;


As far as I can see, it does calculate the correct price for shipping (tax incl.), but rounds the number before sending it back.

What I'm wondering about now is this line:

$shipping_cost = (float)Tools::ps_round((float)$shipping_cost, (Currency::getCurrencyInstance((int)$this->id_currency)->decimals * _PS_PRICE_DISPLAY_PRECISION_));


The getCurrencyInstance method, is it connected to the decimal option in "Localization > Currencies"? If so, does would this mean a solution might be to enable decimals showing on the front-end of the shop for all of the products and rather edit the template to hide the decimals? Or is there a way to have it send back the $shipping_cost without rounding?


Thanks for the help so far!

Link to comment
Share on other sites

Hi there,

I think you should also have a look at what the function Tools::ps_round does, because it is actually this function that does the rounding (by using $shipping_cost and taking into account your decimal preferences). As by its name, this function can be found in the class Tools.php.

Then you can decide whether to modify the function in the cart class or to hide/show things in the template it depends on your goal.

I hope this helps!
Have a nice day,

Link to comment
Share on other sites

I think I found the easiest and hopefully best solution, @fedesib :)

I changed:

$shipping_cost = (float)Tools::ps_round((float)$shipping_cost, (Currency::getCurrencyInstance((int)$this->id_currency)->decimals * _PS_PRICE_DISPLAY_PRECISION_));


$shipping_cost = (float)Tools::ps_round((float)$shipping_cost, _PS_PRICE_DISPLAY_PRECISION_);

The ps_round function (in this instance) takes in two parameter, the shipping cost and the decimal precision (integer). Originally it would check if "Localization > Currency > Decimals" is enabled true/false (which is turned off in my case) and multiply the bool value by the decimal precision integer (Set in "Settings > General > Number of decimals").


The line would therefore equate to: ps_round($shipping_cost, false). And false/null for the second parameter which would default it to 0 decimal precision (which would end in rounding the whole primary number (248.750000 to 249, instead of 248.750000 to 248.75) 

This solution worked for me, but I also had to change rounding precision in the paypal module in the following files:



It "works" without changing the PayPal files, but then orders would come in with the following error, which is also sent in the order confirmation email to the customers: "Payment error: Price paid on paypal is not the same that on PrestaShop.", because the PayPal module were rounding up the total the same way as Prestashop (checking first if decimals are enabled for the front of the shop).


I hope that any of this made sense to the readers :P 

If anyone else runs in to this or a similar problem, don't think twice, just leave a post here and I'll do my best to help you out!


Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...