inveostore.com Posted January 28, 2011 Share Posted January 28, 2011 The aim of this post is to explain the fix for Quantity Discounts to PS developers (in Bugtracker under 6792 & 6827) and show how to fix it.Description: Quantity Discounts do not work properly -> currently they only work correctly for percentage discounts and with a Tax assigned to product which "correct" the final price so everything looks almost fine (sorry for description - it is too much time ago we debug this problem and I do not really remember more details).Reason: The reason why it does not work is basically due to the design of code located in classes/PaymentModule.php: $reduc = QuantityDiscount::getValue($price_wt, $qtyD->id_discount_type, $qtyD->value, new Currency(intval($order->id_currency))); This code INCORRECTLY computes quantity discount amount for product_quantity_discount field in order_details table, because it computes the discount from price ($price_wt variable) to which was Quantity Discount already applied (and also Group Reduction applied what is wrong as well).The problem with "Quantity Discount already applied" can easily be solved by getting the price of product by calling Product::getPriceStatic() method with 1 quantity of product (currently it uses variable with price computed for multiple products).The problem with "Group Reduction already applied" has to be solved by adding new argument to Product::getPriceStatic() (there is no other way).Here is a fix:Open classes/PaymentModule.phpThis fixes how product_quantity_discount field is computed (need also changes in Product::getPriceStatic() - described below):Find: $reduc = QuantityDiscount::getValue($price_wt, $qtyD->id_discount_type, $qtyD->value, new Currency(intval($order->id_currency))); Replace with: $price_wt_no_qtyD = Product::getPriceStatic(intval($product['id_product']), true, ($product['id_product_attribute'] ? intval($product['id_product_attribute']) : NULL), 6, NULL, false, true, 1, false, NULL, NULL, NULL, false); $reduc = QuantityDiscount::getValue($price_wt_no_qtyD, $qtyD->id_discount_type, $qtyD->value, ($tax) ? true : false, $tax, $currency); This fixes the price inserted to product_price field in order_details table which needs to be pure price without any reductions applied:Find: '.floatval(Product::getPriceStatic(intval($product['id_product']), false, ($product['id_product_attribute'] ? intval($product['id_product_attribute']) : NULL), (Product::getTaxCalculationMethod(intval($order->id_customer)) == PS_TAX_EXC ? 2 : 6), NULL, false, false, $product['cart_quantity'], false, intval($order->id_customer), intval($order->id_cart), intval($order->id_address_delivery))).', Replace with: '.floatval(Product::getPriceStatic(intval($product['id_product']), false, ($product['id_product_attribute'] ? intval($product['id_product_attribute']) : NULL), (Product::getTaxCalculationMethod(intval($order->id_customer)) == PS_TAX_EXC ? 2 : 6), NULL, false, false, 1, false, intval($order->id_customer), intval($order->id_cart), intval($order->id_address_delivery))).', This fixes strange warning but not required I think:Find: '.(int)QuantityDiscount::getDiscountFromQuantity(intval($product['id_product']), intval($product['cart_quantity'])).', Replace with: '.((!QuantityDiscount::getDiscountFromQuantity(intval($product['id_product']), intval($product['cart_quantity']))) ? '0' : '1').', Now we need to add new argument to Product::getPriceStatic() method in classes/Product.php file:(to be able to get price without Group Reduction discount applied - this fix does not change the behavior of this method so any old code will work exactly same as before)Find: public static function getPriceStatic($id_product, $usetax = true, $id_product_attribute = NULL, $decimals = 6, $divisor = NULL, $only_reduc = false, $usereduc = true, $quantity = 1, $forceAssociatedTax = false, $id_customer = NULL, $id_cart = NULL, $id_address_delivery = NULL) Replace with: public static function getPriceStatic($id_product, $usetax = true, $id_product_attribute = NULL, $decimals = 6, $divisor = NULL, $only_reduc = false, $usereduc = true, $quantity = 1, $forceAssociatedTax = false, $id_customer = NULL, $id_cart = NULL, $id_address_delivery = NULL, $group_reduc = true) Find: if ($usereduc) $price -= Tools::ps_round($price * Group::getReduction(((isset($id_customer) AND $id_customer) ? $id_customer : 0)) / 100, 2); Replace with: if ($usereduc && $group_reduc) $price -= Tools::ps_round($price * Group::getReduction(((isset($id_customer) AND $id_customer) ? $id_customer : 0)) / 100, 2); Find: $cacheId = $id_product.'-'.($usetax?'1':'0').'-'.$id_product_attribute.'-'.$decimals.'-'.$divisor.'-'.($only_reduc?'1':'0').'-'.($usereduc?'1':'0').'-'.$quantity.'-'.($id_customer ? $id_customer : '0'); Replace with: $cacheId = $id_product.'-'.($usetax?'1':'0').'-'.$id_product_attribute.'-'.$decimals.'-'.$divisor.'-'.($only_reduc?'1':'0').'-'.($usereduc?'1':'0').'-'.($group_reduc?'1':'0').'-'.$quantity.'-'.($id_customer ? $id_customer : '0'); All is now FINALLY correctly inserted to database and only last two issues needs to be corrected:Order::_deleteProduct() and Order::setProductPrices() method in classes/Order.php. This fix will be posted in next post because there is a limit of post size. Link to comment Share on other sites More sharing options...
inveostore.com Posted January 28, 2011 Author Share Posted January 28, 2011 Open classes/Order.php file and replace complete Order::setProductPrices() method with following code: public function setProductPrices(&$row) { if ($this->_taxCalculationMethod == PS_TAX_EXC) $row['product_price'] = Tools::ps_round($row['product_price'], 2); else $row['product_price_wt'] = Tools::ps_round($row['product_price'] * (1 + $row['tax_rate'] / 100), 2); if ($row['reduction_percent']) { if ($this->_taxCalculationMethod == PS_TAX_EXC) $row['product_price'] = $row['product_price'] - $row['product_price'] * ($row['reduction_percent'] * 0.01); else $row['product_price_wt'] = Tools::ps_round($row['product_price_wt'] - $row['product_price_wt'] * ($row['reduction_percent'] * 0.01), 2); } if ($row['reduction_amount']) { if ($this->_taxCalculationMethod == PS_TAX_EXC) $row['product_price'] = $row['product_price'] - $row['reduction_amount']; else $row['product_price_wt'] = Tools::ps_round($row['product_price_wt'] - $row['reduction_amount'] * (1 + ($row['tax_rate'] * 0.01)), 2); } // Added - makes Qty discounts work properly - BEGIN if ($row['product_quantity_discount']) { if ($this->_taxCalculationMethod == PS_TAX_EXC) $row['product_price'] = Tools::ps_round($row['product_price'] - $row['product_quantity_discount'] / (1 + ($row['tax_rate'] * 0.01)), 2); else $row['product_price_wt'] = $row['product_price_wt'] - $row['product_quantity_discount']; } // Added - makes Qty discounts work properly - END if ($row['group_reduction']) { if ($this->_taxCalculationMethod == PS_TAX_EXC) $row['product_price'] = $row['product_price'] - $row['product_price'] * ($row['group_reduction'] * 0.01); else $row['product_price_wt'] = Tools::ps_round($row['product_price_wt'] - $row['product_price_wt'] * ($row['group_reduction'] * 0.01), 2); } if (($row['reduction_percent'] OR $row['reduction_amount'] OR $row['group_reduction']) AND $this->_taxCalculationMethod == PS_TAX_EXC) $row['product_price'] = Tools::ps_round($row['product_price'], 2); // Added - makes Qty discounts work properly - BEGIN if($row['product_quantity_discount'] AND $this->_taxCalculationMethod == PS_TAX_INC) $row['product_price'] = Tools::ps_round($row['product_price'], 2); // Added - makes Qty discounts work properly - END if ($this->_taxCalculationMethod == PS_TAX_EXC) $row['product_price_wt'] = Tools::ps_round($row['product_price'] * (1 + ($row['tax_rate'] * 0.01)), 2) + Tools::ps_round($row['ecotax'] * (1 + $row['ecotax_tax_rate'] / 100), 2); else { $row['product_price_wt_but_ecotax'] = $row['product_price_wt']; $row['product_price_wt'] = Tools::ps_round($row['product_price_wt'] + $row['ecotax'] * (1 + $row['ecotax_tax_rate'] / 100), 2); } $row['total_wt'] = $row['product_quantity'] * $row['product_price_wt']; $row['total_price'] = $row['product_quantity'] * $row['product_price_wt']; } Link to comment Share on other sites More sharing options...
inveostore.com Posted January 28, 2011 Author Share Posted January 28, 2011 Open classes/Order.php file and replace complete Order::_deleteProduct() method with following code: private function _deleteProduct($orderDetail, $quantity) { $row = Db::getInstance()->getRow(' SELECT * FROM `'._DB_PREFIX_.'order_detail` od WHERE od.`id_order_detail` = '.intval($orderDetail->id)); $this->setProductPrices($row); /* Update cart */ $cart = new Cart($this->id_cart); $cart->updateQty($quantity, $orderDetail->product_id, $orderDetail->product_attribute_id, false, 'down'); // customization are deleted in deleteCustomization $cart->update(); /* Update order */ $shippingDiff = $this->total_shipping - $cart->getOrderShippingCost(); $price = $row['product_price_wt'] * $quantity; $this->total_products -= $row['product_price'] * $quantity; $this->total_products_wt -= $row['product_price_wt'] * $quantity; $this->total_shipping = $cart->getOrderShippingCost(); $this->total_paid -= ($price + $shippingDiff); $this->total_paid_real -= ($price + $shippingDiff); /* Prevent from floating precision issues (total_products has only 2 decimals) */ if ($this->total_products < 0) $this->total_products = 0; /* Prevent from floating precision issues */ $this->total_paid = number_format($this->total_paid, 2, '.', ''); $this->total_paid_real = number_format($this->total_paid_real, 2, '.', ''); $this->total_products = number_format($this->total_products, 2, '.', ''); $this->total_products_wt = number_format($this->total_products_wt, 2, '.', ''); /* Update order detail */ $orderDetail->product_quantity -= intval($quantity); if (!$orderDetail->product_quantity) { if (!$orderDetail->delete()) return false; if (count($this->getProductsDetail()) == 0) { global $cookie; $history = new OrderHistory(); $history->id_order = intval($this->id); $history->changeIdOrderState(_PS_OS_CANCELED_, intval($this->id)); if (!$history->addWithemail()) return false; } return $this->update(); } return $orderDetail->update() AND $this->update(); } Thats all. Now Quantity Discounts start to work properly. According to what we see in forums, integrating this fix to PS help a LOT of people. It was very common problem which reached many PS users.If anything is not clear, feel free to ask us. I will reply ASAP.BTW we made about 200 test orders during debugging this bug... :-) Link to comment Share on other sites More sharing options...
inveostore.com Posted January 28, 2011 Author Share Posted January 28, 2011 Updated all 3 posts and added fix for Order::setProductPrices() method (we thought it is already included in PS). Link to comment Share on other sites More sharing options...
DomsAdmin Posted February 1, 2011 Share Posted February 1, 2011 Hello! will these fixes work with prestashop version 1.3.2x or are they necessary for that version. Thanks for the advice! Link to comment Share on other sites More sharing options...
inveostore.com Posted February 1, 2011 Author Share Posted February 1, 2011 Basically it may work. Link to comment Share on other sites More sharing options...
DomsAdmin Posted February 1, 2011 Share Posted February 1, 2011 i tried the fix as instructed. I keep getting a parse error T_Publicon on line 348. I cannot imagine at this point what the error could be... Link to comment Share on other sites More sharing options...
inveostore.com Posted February 1, 2011 Author Share Posted February 1, 2011 It means you have applied these fixes incorrectly. This type of problem depends on how your code look in result. It is not related to posted fixes in any way.Please keep this thread clean.You have already asked for help at Parse error:syntax error in T_PUBLIC in classes/order.php on line 348 Link to comment Share on other sites More sharing options...
DomsAdmin Posted February 1, 2011 Share Posted February 1, 2011 Thank you for the explanation! Link to comment Share on other sites More sharing options...
mingwireless Posted February 25, 2011 Share Posted February 25, 2011 can any one has the complete files that already customize / fixed these problems , and upload to here pleasesomething like this i don't know how to changeThank you very much! Link to comment Share on other sites More sharing options...
inveostore.com Posted February 25, 2011 Author Share Posted February 25, 2011 Since 1.3.0.7 is the last official PS version in 1.3 branch we plan in March to re-release this version with our additional fixes which were not included (for people who want to stay with 1.3). Link to comment Share on other sites More sharing options...
mingwireless Posted February 25, 2011 Share Posted February 25, 2011 Can you tell when is the date will be release with the fixed version?Thanks Link to comment Share on other sites More sharing options...
jolvil Posted April 3, 2011 Share Posted April 3, 2011 Because I have error on total calculation using discount per quantity without taxe, I could be happy with your corrected 1.3 PS version, Team will not update anymore 1.3 version.I made all these modifications but this doesn't resolve miscalculation on total with percent quantity discount when taxe is not activated.product A, price 2.50, discount 5% from 2I added 2 on cart, price for each is 2.38, for 2 4.76 but total is 4.75 ! WRONG !This issue cause a Paypal error on paiement (Paypal calculate right price 4.76)Could it be possible to have a fix for it too? Link to comment Share on other sites More sharing options...
inveostore.com Posted May 1, 2011 Author Share Posted May 1, 2011 Can you tell when is the date will be release with the fixed version? We have just did so. Please see PrestaShop 1.3.7.0 SP1 (UNOFFICIAL UPDATE) thread. Link to comment Share on other sites More sharing options...
inweb Posted March 10, 2015 Share Posted March 10, 2015 An updated version of this Quantity Discount fix is available at http://www.inveostore.com/blog/prestashop-quantity-discounts/ Link to comment Share on other sites More sharing options...
Medea Web Agency Posted March 10, 2015 Share Posted March 10, 2015 An updated version of this Quantity Discount fix is available at http://www.inveostore.com/blog/prestashop-quantity-discounts/ I've a similar issue with 1.6 version Quantity discounts are right in the cart, but not in the discount table in product view Does this fix the 1.6 version too? Thanks! Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now