mantas393 Posted May 29, 2019 Share Posted May 29, 2019 I created a voucher that should exclude products on sale. When I only have discounted products in my cart it works as expected. If I there are not-discounted products in cart, then the Voucher is applied to all cart, including products already on sale. I tried to implement code changes from this thread, but it doesn't seem to work for me: https://www.prestashop.com/forums/topic/290274-disabling-discounts-cart-rules-to-items-already-on-sale/ Maybe in 1.7 there is another way to solve this? Link to comment Share on other sites More sharing options...
Idyllic Posted January 20, 2020 Share Posted January 20, 2020 I am having the same issue. If only the product on sale is in the cart then the voucher won't work. However, as soon as I add another product to the cart then the discount is applied and should only be applied to the product that is not on sale. Also, the option "Exclude discounted products" in the Actions page of the cart rule is set to yes. I did find this thread on Github: https://github.com/PrestaShop/PrestaShop/issues/10300. This is the specific issue in question, unfortunately it looks like the fix got pushed back to the 1.7.7.0 milestone, which has still not been released. @mantas393were you able to find a fix for the time being? Does anyone know a fix that will work currently while we're waiting for the update? Link to comment Share on other sites More sharing options...
prus Posted April 27, 2020 Share Posted April 27, 2020 https://github.com/PrestaShop/PrestaShop/pull/13704 Working for 1.7.6.x Link to comment Share on other sites More sharing options...
Idyllic Posted April 29, 2020 Share Posted April 29, 2020 On 4/27/2020 at 5:28 PM, prus said: https://github.com/PrestaShop/PrestaShop/pull/13704 Working for 1.7.6.x No it doesn't work on 1.7.6.x... it's slated for the 1.7.7.0 release, which shows is 96% complete as of right now. It shows this release is due by June 1 but most releases are delayed several days, if not weeks. I was able to take the code from the merge on git that fixes this issue and replace the file with my 'cart/src/Core/Cart/CartRuleCalculator.php' file and that is currently working on 1.7.6.5. Here's the entire code from my CarRuleCalculator.php file that works for me: @@ -0,0 +1,308 @@ <?php /** * 2007-2019 PrestaShop and Contributors * * NOTICE OF LICENSE * * This source file is subject to the Open Software License (OSL 3.0) * that is bundled with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * https://opensource.org/licenses/OSL-3.0 * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to https://www.prestashop.com for more information. * * @author PrestaShop SA <[email protected]> * @copyright 2007-2019 PrestaShop SA and Contributors * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ namespace PrestaShop\PrestaShop\Core\Cart; use Cart; class CartRuleCalculator { /** * @var Calculator */ protected $calculator; /** * @var CartRowCollection */ protected $cartRows; /** * @var CartRuleCollection */ protected $cartRules; /** * @var Fees */ protected $fees; /** * process cartrules calculation */ public function applyCartRules() { foreach ($this->cartRules as $cartRule) { $this->applyCartRule($cartRule); } } /** * process cartrules calculation, excluding free-shipping processing */ public function applyCartRulesWithoutFreeShipping() { foreach ($this->cartRules as $cartRule) { $this->applyCartRule($cartRule, false); } } /** * @param \PrestaShop\PrestaShop\Core\Cart\CartRuleCollection $cartRules * * @return CartRuleCalculator */ public function setCartRules($cartRules) { $this->cartRules = $cartRules; return $this; } /** * @param CartRuleData $cartRuleData * @param bool $withFreeShipping used to calculate free shipping discount (avoid loop on shipping calculation) * * @throws \PrestaShopDatabaseException */ protected function applyCartRule(CartRuleData $cartRuleData, $withFreeShipping = true) { $cartRule = $cartRuleData->getCartRule(); $cart = $this->calculator->getCart(); if (!\CartRule::isFeatureActive()) { return; } // Free shipping on selected carriers if ($cartRule->free_shipping && $withFreeShipping) { $initialShippingFees = new AmountImmutable( $cart->getOrderTotal(true, Cart::ONLY_SHIPPING), $cart->getOrderTotal(false, Cart::ONLY_SHIPPING) ); $this->calculator->getFees()->subDiscountValueShipping($initialShippingFees); $cartRuleData->addDiscountApplied($initialShippingFees); } // Free gift if ((int) $cartRule->gift_product) { foreach ($this->cartRows as $cartRow) { $product = $cartRow->getRowData(); if ($product['id_product'] == $cartRule->gift_product && ($product['id_product_attribute'] == $cartRule->gift_product_attribute || !(int) $cartRule->gift_product_attribute) ) { $cartRuleData->addDiscountApplied($cartRow->getFinalUnitPrice()); $cartRow->applyFlatDiscount($cartRow->getFinalUnitPrice()); } } } // Discount (%) on the whole order if ($cartRule->reduction_percent && $cartRule->reduction_product == 0) { foreach ($this->cartRows as $cartRow) { $product = $cartRow->getRowData(); if ((($cartRule->reduction_exclude_special && !$product['reduction_applies']) || !$cartRule->reduction_exclude_special)) { $amount = $cartRow->applyPercentageDiscount($cartRule->reduction_percent); $cartRuleData->addDiscountApplied($amount); } } } // Discount (%) on a specific product if ($cartRule->reduction_percent && $cartRule->reduction_product > 0) { foreach ($this->cartRows as $cartRow) { if ($cartRow->getRowData()['id_product'] == $cartRule->reduction_product) { $amount = $cartRow->applyPercentageDiscount($cartRule->reduction_percent); $cartRuleData->addDiscountApplied($amount); } } } // Discount (%) on the cheapest product if ($cartRule->reduction_percent && $cartRule->reduction_product == -1) { /** @var CartRow|null $cartRowCheapest */ $cartRowCheapest = null; foreach ($this->cartRows as $cartRow) { $product = $cartRow->getRowData(); if (((($cartRule->reduction_exclude_special && !$product['reduction_applies']) || !$cartRule->reduction_exclude_special)) && ($cartRowCheapest === null || $cartRowCheapest->getInitialUnitPrice()->getTaxIncluded() > $cartRow->getInitialUnitPrice() ->getTaxIncluded()) ) { $cartRowCheapest = $cartRow; } } if ($cartRowCheapest !== null) { // apply only on one product of the cheapest row $discountTaxIncluded = $cartRowCheapest->getInitialUnitPrice()->getTaxIncluded() * $cartRule->reduction_percent / 100; $discountTaxExcluded = $cartRowCheapest->getInitialUnitPrice()->getTaxExcluded() * $cartRule->reduction_percent / 100; $amount = new AmountImmutable($discountTaxIncluded, $discountTaxExcluded); $cartRowCheapest->applyFlatDiscount($amount); $cartRuleData->addDiscountApplied($amount); } } // Discount (%) on the selection of products if ($cartRule->reduction_percent && $cartRule->reduction_product == -2) { $selected_products = $cartRule->checkProductRestrictionsFromCart($cart, true); if (is_array($selected_products)) { foreach ($this->cartRows as $cartRow) { $product = $cartRow->getRowData(); if (in_array($product['id_product'] . '-' . $product['id_product_attribute'], $selected_products) || in_array($product['id_product'] . '-0', $selected_products) && (($cartRule->reduction_exclude_special && !$product['reduction_applies']) || !$cartRule->reduction_exclude_special)) { $amount = $cartRow->applyPercentageDiscount($cartRule->reduction_percent); $cartRuleData->addDiscountApplied($amount); } } } } // Discount (¤) : weighted calculation on all concerned rows // weight factor got from price with same tax (incl/excl) as voucher if ((float) $cartRule->reduction_amount > 0) { $concernedRows = new CartRowCollection(); if ($cartRule->reduction_product > 0) { // discount on single product foreach ($this->cartRows as $cartRow) { if ($cartRow->getRowData()['id_product'] == $cartRule->reduction_product) { $concernedRows->addCartRow($cartRow); } } } elseif ($cartRule->reduction_product == 0) { // Discount (¤) on the whole order $concernedRows = $this->cartRows; } /* * Reduction on the cheapest or on the selection is not really meaningful and has been disabled in the backend * Please keep this code, so it won't be considered as a bug * elseif ($this->reduction_product == -1) * elseif ($this->reduction_product == -2) */ // currency conversion $discountConverted = $this->convertAmountBetweenCurrencies( $cartRule->reduction_amount, new \Currency($cartRule->reduction_currency), new \Currency($cart->id_currency) ); // get total of concerned rows $totalTaxIncl = $totalTaxExcl = 0; foreach ($concernedRows as $concernedRow) { $totalTaxIncl += $concernedRow->getFinalTotalPrice()->getTaxIncluded(); $totalTaxExcl += $concernedRow->getFinalTotalPrice()->getTaxExcluded(); } // The reduction cannot exceed the products total, except when we do not want it to be limited (for the partial use calculation) $discountConverted = min($discountConverted, $cartRule->reduction_tax ? $totalTaxIncl : $totalTaxExcl); // apply weighted discount : // on each line we apply a part of the discount corresponding to discount*rowWeight/total foreach ($concernedRows as $concernedRow) { // get current line tax rate $taxRate = 0; if ($concernedRow->getFinalTotalPrice()->getTaxExcluded() != 0) { $taxRate = ($concernedRow->getFinalTotalPrice()->getTaxIncluded() - $concernedRow->getFinalTotalPrice()->getTaxExcluded()) / $concernedRow->getFinalTotalPrice()->getTaxExcluded(); } $weightFactor = 0; if ($cartRule->reduction_tax) { // if cart rule amount is set tax included : calculate weight tax included if ($totalTaxIncl != 0) { $weightFactor = $concernedRow->getFinalTotalPrice()->getTaxIncluded() / $totalTaxIncl; } $discountAmountTaxIncl = $discountConverted * $weightFactor; // recalculate tax included $discountAmountTaxExcl = $discountAmountTaxIncl / (1 + $taxRate); } else { // if cart rule amount is set tax excluded : calculate weight tax excluded if ($totalTaxExcl != 0) { $weightFactor = $concernedRow->getFinalTotalPrice()->getTaxExcluded() / $totalTaxExcl; } $discountAmountTaxExcl = $discountConverted * $weightFactor; // recalculate tax excluded $discountAmountTaxIncl = $discountAmountTaxExcl * (1 + $taxRate); } $amount = new AmountImmutable($discountAmountTaxIncl, $discountAmountTaxExcl); $concernedRow->applyFlatDiscount($amount); $cartRuleData->addDiscountApplied($amount); } } } /** * @param \PrestaShop\PrestaShop\Core\Cart\Calculator $calculator * * @return CartRuleCalculator */ public function setCalculator($calculator) { $this->calculator = $calculator; return $this; } protected function convertAmountBetweenCurrencies($amount, \Currency $currencyFrom, \Currency $currencyTo) { if ($amount == 0 || $currencyFrom->conversion_rate == 0) { return 0; } // convert to default currency $amount /= $currencyFrom->conversion_rate; // convert to destination currency $amount *= $currencyTo->conversion_rate; return $amount; } /** * @param \PrestaShop\PrestaShop\Core\Cart\CartRowCollection $cartRows * * @return CartRuleCalculator */ public function setCartRows($cartRows) { $this->cartRows = $cartRows; return $this; } /** * @return CartRuleCollection */ public function getCartRulesData() { return $this->cartRules; } } 1 Link to comment Share on other sites More sharing options...
mattiak78 Posted July 7, 2020 Share Posted July 7, 2020 On 4/29/2020 at 7:26 PM, Idyllic said: No it doesn't work on 1.7.6.x... it's slated for the 1.7.7.0 release, which shows is 96% complete as of right now. It shows this release is due by June 1 but most releases are delayed several days, if not weeks. I was able to take the code from the merge on git that fixes this issue and replace the file with my 'cart/src/Core/Cart/CartRuleCalculator.php' file and that is currently working on 1.7.6.5. Here's the entire code from my CarRuleCalculator.php file that works for me: @@ -0,0 +1,308 @@ <?php /** * 2007-2019 PrestaShop and Contributors * * NOTICE OF LICENSE * * This source file is subject to the Open Software License (OSL 3.0) * that is bundled with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * https://opensource.org/licenses/OSL-3.0 * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to https://www.prestashop.com for more information. * * @author PrestaShop SA <[email protected]> * @copyright 2007-2019 PrestaShop SA and Contributors * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ namespace PrestaShop\PrestaShop\Core\Cart; use Cart; class CartRuleCalculator { /** * @var Calculator */ protected $calculator; /** * @var CartRowCollection */ protected $cartRows; /** * @var CartRuleCollection */ protected $cartRules; /** * @var Fees */ protected $fees; /** * process cartrules calculation */ public function applyCartRules() { foreach ($this->cartRules as $cartRule) { $this->applyCartRule($cartRule); } } /** * process cartrules calculation, excluding free-shipping processing */ public function applyCartRulesWithoutFreeShipping() { foreach ($this->cartRules as $cartRule) { $this->applyCartRule($cartRule, false); } } /** * @param \PrestaShop\PrestaShop\Core\Cart\CartRuleCollection $cartRules * * @return CartRuleCalculator */ public function setCartRules($cartRules) { $this->cartRules = $cartRules; return $this; } /** * @param CartRuleData $cartRuleData * @param bool $withFreeShipping used to calculate free shipping discount (avoid loop on shipping calculation) * * @throws \PrestaShopDatabaseException */ protected function applyCartRule(CartRuleData $cartRuleData, $withFreeShipping = true) { $cartRule = $cartRuleData->getCartRule(); $cart = $this->calculator->getCart(); if (!\CartRule::isFeatureActive()) { return; } // Free shipping on selected carriers if ($cartRule->free_shipping && $withFreeShipping) { $initialShippingFees = new AmountImmutable( $cart->getOrderTotal(true, Cart::ONLY_SHIPPING), $cart->getOrderTotal(false, Cart::ONLY_SHIPPING) ); $this->calculator->getFees()->subDiscountValueShipping($initialShippingFees); $cartRuleData->addDiscountApplied($initialShippingFees); } // Free gift if ((int) $cartRule->gift_product) { foreach ($this->cartRows as $cartRow) { $product = $cartRow->getRowData(); if ($product['id_product'] == $cartRule->gift_product && ($product['id_product_attribute'] == $cartRule->gift_product_attribute || !(int) $cartRule->gift_product_attribute) ) { $cartRuleData->addDiscountApplied($cartRow->getFinalUnitPrice()); $cartRow->applyFlatDiscount($cartRow->getFinalUnitPrice()); } } } // Discount (%) on the whole order if ($cartRule->reduction_percent && $cartRule->reduction_product == 0) { foreach ($this->cartRows as $cartRow) { $product = $cartRow->getRowData(); if ((($cartRule->reduction_exclude_special && !$product['reduction_applies']) || !$cartRule->reduction_exclude_special)) { $amount = $cartRow->applyPercentageDiscount($cartRule->reduction_percent); $cartRuleData->addDiscountApplied($amount); } } } // Discount (%) on a specific product if ($cartRule->reduction_percent && $cartRule->reduction_product > 0) { foreach ($this->cartRows as $cartRow) { if ($cartRow->getRowData()['id_product'] == $cartRule->reduction_product) { $amount = $cartRow->applyPercentageDiscount($cartRule->reduction_percent); $cartRuleData->addDiscountApplied($amount); } } } // Discount (%) on the cheapest product if ($cartRule->reduction_percent && $cartRule->reduction_product == -1) { /** @var CartRow|null $cartRowCheapest */ $cartRowCheapest = null; foreach ($this->cartRows as $cartRow) { $product = $cartRow->getRowData(); if (((($cartRule->reduction_exclude_special && !$product['reduction_applies']) || !$cartRule->reduction_exclude_special)) && ($cartRowCheapest === null || $cartRowCheapest->getInitialUnitPrice()->getTaxIncluded() > $cartRow->getInitialUnitPrice() ->getTaxIncluded()) ) { $cartRowCheapest = $cartRow; } } if ($cartRowCheapest !== null) { // apply only on one product of the cheapest row $discountTaxIncluded = $cartRowCheapest->getInitialUnitPrice()->getTaxIncluded() * $cartRule->reduction_percent / 100; $discountTaxExcluded = $cartRowCheapest->getInitialUnitPrice()->getTaxExcluded() * $cartRule->reduction_percent / 100; $amount = new AmountImmutable($discountTaxIncluded, $discountTaxExcluded); $cartRowCheapest->applyFlatDiscount($amount); $cartRuleData->addDiscountApplied($amount); } } // Discount (%) on the selection of products if ($cartRule->reduction_percent && $cartRule->reduction_product == -2) { $selected_products = $cartRule->checkProductRestrictionsFromCart($cart, true); if (is_array($selected_products)) { foreach ($this->cartRows as $cartRow) { $product = $cartRow->getRowData(); if (in_array($product['id_product'] . '-' . $product['id_product_attribute'], $selected_products) || in_array($product['id_product'] . '-0', $selected_products) && (($cartRule->reduction_exclude_special && !$product['reduction_applies']) || !$cartRule->reduction_exclude_special)) { $amount = $cartRow->applyPercentageDiscount($cartRule->reduction_percent); $cartRuleData->addDiscountApplied($amount); } } } } // Discount (¤) : weighted calculation on all concerned rows // weight factor got from price with same tax (incl/excl) as voucher if ((float) $cartRule->reduction_amount > 0) { $concernedRows = new CartRowCollection(); if ($cartRule->reduction_product > 0) { // discount on single product foreach ($this->cartRows as $cartRow) { if ($cartRow->getRowData()['id_product'] == $cartRule->reduction_product) { $concernedRows->addCartRow($cartRow); } } } elseif ($cartRule->reduction_product == 0) { // Discount (¤) on the whole order $concernedRows = $this->cartRows; } /* * Reduction on the cheapest or on the selection is not really meaningful and has been disabled in the backend * Please keep this code, so it won't be considered as a bug * elseif ($this->reduction_product == -1) * elseif ($this->reduction_product == -2) */ // currency conversion $discountConverted = $this->convertAmountBetweenCurrencies( $cartRule->reduction_amount, new \Currency($cartRule->reduction_currency), new \Currency($cart->id_currency) ); // get total of concerned rows $totalTaxIncl = $totalTaxExcl = 0; foreach ($concernedRows as $concernedRow) { $totalTaxIncl += $concernedRow->getFinalTotalPrice()->getTaxIncluded(); $totalTaxExcl += $concernedRow->getFinalTotalPrice()->getTaxExcluded(); } // The reduction cannot exceed the products total, except when we do not want it to be limited (for the partial use calculation) $discountConverted = min($discountConverted, $cartRule->reduction_tax ? $totalTaxIncl : $totalTaxExcl); // apply weighted discount : // on each line we apply a part of the discount corresponding to discount*rowWeight/total foreach ($concernedRows as $concernedRow) { // get current line tax rate $taxRate = 0; if ($concernedRow->getFinalTotalPrice()->getTaxExcluded() != 0) { $taxRate = ($concernedRow->getFinalTotalPrice()->getTaxIncluded() - $concernedRow->getFinalTotalPrice()->getTaxExcluded()) / $concernedRow->getFinalTotalPrice()->getTaxExcluded(); } $weightFactor = 0; if ($cartRule->reduction_tax) { // if cart rule amount is set tax included : calculate weight tax included if ($totalTaxIncl != 0) { $weightFactor = $concernedRow->getFinalTotalPrice()->getTaxIncluded() / $totalTaxIncl; } $discountAmountTaxIncl = $discountConverted * $weightFactor; // recalculate tax included $discountAmountTaxExcl = $discountAmountTaxIncl / (1 + $taxRate); } else { // if cart rule amount is set tax excluded : calculate weight tax excluded if ($totalTaxExcl != 0) { $weightFactor = $concernedRow->getFinalTotalPrice()->getTaxExcluded() / $totalTaxExcl; } $discountAmountTaxExcl = $discountConverted * $weightFactor; // recalculate tax excluded $discountAmountTaxIncl = $discountAmountTaxExcl * (1 + $taxRate); } $amount = new AmountImmutable($discountAmountTaxIncl, $discountAmountTaxExcl); $concernedRow->applyFlatDiscount($amount); $cartRuleData->addDiscountApplied($amount); } } } /** * @param \PrestaShop\PrestaShop\Core\Cart\Calculator $calculator * * @return CartRuleCalculator */ public function setCalculator($calculator) { $this->calculator = $calculator; return $this; } protected function convertAmountBetweenCurrencies($amount, \Currency $currencyFrom, \Currency $currencyTo) { if ($amount == 0 || $currencyFrom->conversion_rate == 0) { return 0; } // convert to default currency $amount /= $currencyFrom->conversion_rate; // convert to destination currency $amount *= $currencyTo->conversion_rate; return $amount; } /** * @param \PrestaShop\PrestaShop\Core\Cart\CartRowCollection $cartRows * * @return CartRuleCalculator */ public function setCartRows($cartRows) { $this->cartRows = $cartRows; return $this; } /** * @return CartRuleCollection */ public function getCartRulesData() { return $this->cartRules; } } great fix! also for me it solves ... with prestashop 1.7.5 . too many problems with discounts on ps 1.7.x?! .... there is also the problem with free shipping ... mah Link to comment Share on other sites More sharing options...
Gatto_Rosso Posted December 29, 2021 Share Posted December 29, 2021 (edited) The code posted by Idyllic fixes the problem! Use this code to replace the contents of file /src/Core/Cart/CartRuleCalculator.php Clear PS cache after editing the file! Edited December 29, 2021 by Gatto_Rosso (see edit history) 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