From 0cb73f9e130858ce1cb00a99ee9e4292302a63a1 Mon Sep 17 00:00:00 2001 From: mDeflotte Date: Thu, 19 Apr 2012 09:39:14 +0000 Subject: [PATCH] [-] Project : #PSFV-820 - Cartrules are now reapplied each time we add/remove a product on/from the cart --- classes/Cart.php | 11 +-- classes/CartRule.php | 81 +++++++++++-------- .../admin/AdminCartRulesController.php | 11 ++- controllers/admin/AdminCartsController.php | 6 +- controllers/front/CartController.php | 19 ++++- themes/default/shopping-cart-product-line.tpl | 2 +- 6 files changed, 80 insertions(+), 50 deletions(-) diff --git a/classes/Cart.php b/classes/Cart.php index b1cfae764..ef572c2fd 100644 --- a/classes/Cart.php +++ b/classes/Cart.php @@ -724,7 +724,7 @@ class CartCore extends ObjectModel Cache::clean('Cart::getCartRules'.$this->id); if ((int)$cartRule->gift_product) - $this->updateQty(1, $cartRule->gift_product, $cartRule->gift_product_attribute); + $this->updateQty(1, $cartRule->gift_product, $cartRule->gift_product_attribute, false, 0, 'up', null, false); return true; } @@ -761,7 +761,7 @@ class CartCore extends ObjectModel * @param string $operator Indicate if quantity must be increased or decreased */ public function updateQty($quantity, $id_product, $id_product_attribute = null, $id_customization = false, - $id_address_delivery = 0, $operator = 'up', Shop $shop = null) + $id_address_delivery = 0, $operator = 'up', Shop $shop = null, $auto_add_cart_rule = true) { if (!$shop) $shop = Context::getContext()->shop; @@ -853,7 +853,7 @@ class CartCore extends ObjectModel ); } /* Add product to the cart */ - else + elseif ($operator == 'up') { $sql = 'SELECT stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity FROM '._DB_PREFIX_.'product p @@ -893,7 +893,8 @@ class CartCore extends ObjectModel $this->update(true); $context = Context::getContext()->cloneContext(); $context->cart = $this; - CartRule::autoAddToCart($context); + if ($auto_add_cart_rule) + CartRule::autoAddToCart($context); if ($product->customizable) return $this->_updateCustomizationQuantity((int)$quantity, (int)$id_customization, (int)$id_product, (int)$id_product_attribute, (int)$id_address_delivery, $operator); @@ -1049,7 +1050,7 @@ class CartCore extends ObjectModel $cart_rule = new CartRule($id_cart_rule, Configuration::get('PS_LANG_DEFAULT')); if ((int)$cart_rule->gift_product) - $this->updateQty(1, $cart_rule->gift_product, $cart_rule->gift_product_attribute, null, null, 'down'); + $this->updateQty(1, $cart_rule->gift_product, $cart_rule->gift_product_attribute, null, null, 'down', null, false); return $result; } diff --git a/classes/CartRule.php b/classes/CartRule.php index 16594ecfd..c45b1fff8 100644 --- a/classes/CartRule.php +++ b/classes/CartRule.php @@ -361,22 +361,23 @@ class CartRuleCore extends ObjectModel * Check if this cart rule can be applied * * @param Context $context - * @param bool $alreadyInCart + * @param bool $alreadyInCart Check if the voucher is already on the cart + * @param bool $display_error Display error * @return bool|mixed|string */ - public function checkValidity(Context $context, $alreadyInCart = false) + public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true) { if (!CartRule::isFeatureActive()) return false; if (!$this->active) - return Tools::displayError('This voucher is disabled'); + return (!$display_error) ? false : Tools::displayError('This voucher is disabled'); if (!$this->quantity) - return Tools::displayError('This voucher has already been used'); + return (!$display_error) ? false : Tools::displayError('This voucher has already been used'); if (strtotime($this->date_from) > time()) - return Tools::displayError('This voucher is not valid yet'); + return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet'); if (strtotime($this->date_to) < time()) - return Tools::displayError('This voucher has expired'); + return (!$display_error) ? false : Tools::displayError('This voucher has expired'); if ($context->cart->id_customer) { @@ -394,7 +395,7 @@ class CartRuleCore extends ObjectModel LIMIT 1 )'); if ($quantityUsed + 1 > $this->quantity_per_user) - return Tools::displayError('You cannot use this voucher anymore (usage limit reached)'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)'); } $otherCartRules = $context->cart->getCartRules(); @@ -402,8 +403,8 @@ class CartRuleCore extends ObjectModel foreach ($otherCartRules as $otherCartRule) { if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart) - return Tools::displayError('This voucher is already in your cart'); - if ($this->cart_rule_restriction && $otherCartRule['cart_rule_restriction']) + return (!$display_error) ? false : Tools::displayError('This voucher is already in your cart'); + if ($this->cart_rule_restriction && $otherCartRule['cart_rule_restriction'] && $otherCartRule['id_cart_rule'] != $this->id) { $combinable = Db::getInstance()->getValue(' SELECT id_cart_rule_1 @@ -413,7 +414,7 @@ class CartRuleCore extends ObjectModel if (!$combinable) { $cart_rule = new CartRule($otherCartRule['cart_rule_restriction'], $context->cart->id_lang); - return Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name; + return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name; } } } @@ -427,7 +428,7 @@ class CartRuleCore extends ObjectModel WHERE crg.id_cart_rule = '.(int)$this->id.' AND crg.id_group '.($context->cart->id_customer ? 'IN (SELECT cg.id_group FROM '._DB_PREFIX_.'customer_group cg WHERE cg.id_customer = '.(int)$context->cart->id_customer.')' : '= 1')); if (!$id_cart_rule) - return Tools::displayError('You cannot use this voucher'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } // Check if the customer delivery address is usable with the cart rule @@ -439,7 +440,7 @@ class CartRuleCore extends ObjectModel WHERE crc.id_cart_rule = '.(int)$this->id.' AND crc.id_country = (SELECT a.id_country FROM '._DB_PREFIX_.'address a WHERE a.id_address = '.(int)$context->cart->id_address_delivery.' LIMIT 1)'); if (!$id_cart_rule) - return Tools::displayError('You cannot use this voucher in your country of delivery'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher in your country of delivery'); } // Check if the carrier chosen by the customer is usable with the cart rule @@ -451,7 +452,7 @@ class CartRuleCore extends ObjectModel WHERE crc.id_cart_rule = '.(int)$this->id.' AND crc.id_carrier = '.(int)$context->cart->id_carrier); if (!$id_cart_rule) - return Tools::displayError('You cannot use this voucher with this carrier'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with this carrier'); } // Check if the cart rules appliy to the shop browsed by the customer @@ -463,23 +464,25 @@ class CartRuleCore extends ObjectModel WHERE crs.id_cart_rule = '.(int)$this->id.' AND crs.id_shop = '.(int)$context->shop->id); if (!$id_cart_rule) - return Tools::displayError('You cannot use this voucher'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } // Check if the products chosen by the customer are usable with the cart rule if ($this->product_restriction) { - $r = $this->checkProductRestrictions($context, false); - if ($r !== false) + $r = $this->checkProductRestrictions($context, false, $display_error); + if ($r !== false && $display_error) return $r; + elseif (!$r && !$display_error) + return false; } // Check if the cart rule is only usable by a specific customer, and if the current customer is the right one if ($this->id_customer && $context->cart->id_customer != $this->id_customer) { if (!Context::getContext()->customer->isLogged()) - return Tools::displayError('You cannot use this voucher').' - '.Tools::displayError('Please log in'); - return Tools::displayError('You cannot use this voucher'); + return (!$display_error) ? false : (Tools::displayError('You cannot use this voucher').' - '.Tools::displayError('Please log in')); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } if ($this->minimum_amount) @@ -528,11 +531,13 @@ class CartRuleCore extends ObjectModel } if ($cartTotal < $minimum_amount) - return Tools::displayError('You have not reached the minimum amount required to use this voucher'); + return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher'); } + if (!$display_error) + return true; } - protected function checkProductRestrictions(Context $context, $return_products = false) + protected function checkProductRestrictions(Context $context, $return_products = false, $display_error = true) { $selectedProducts = array(); @@ -568,7 +573,7 @@ class CartRuleCore extends ObjectModel $matchingProductsList[] = $cartAttribute['id_product'].'-'.$cartAttribute['id_product_attribute']; } if ($countMatchingProducts < $productRuleGroup['quantity']) - return Tools::displayError('You cannot use this voucher with these products'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = array_uintersect($eligibleProductsList, $matchingProductsList, 'cartrule_products_intersect'); break; case 'products': @@ -586,7 +591,7 @@ class CartRuleCore extends ObjectModel $matchingProductsList[] = $cartProduct['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) - return Tools::displayError('You cannot use this voucher with these products'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = array_uintersect($eligibleProductsList, $matchingProductsList, 'cartrule_products_intersect'); break; case 'categories': @@ -605,7 +610,7 @@ class CartRuleCore extends ObjectModel $matchingProductsList[] = $cartCategory['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) - return Tools::displayError('You cannot use this voucher with these products'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = array_uintersect($eligibleProductsList, $matchingProductsList, 'cartrule_products_intersect'); break; case 'manufacturers': @@ -624,7 +629,7 @@ class CartRuleCore extends ObjectModel $matchingProductsList[] = $cartManufacturer['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) - return Tools::displayError('You cannot use this voucher with these products'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = array_uintersect($eligibleProductsList, $matchingProductsList, 'cartrule_products_intersect'); break; case 'suppliers': @@ -643,13 +648,13 @@ class CartRuleCore extends ObjectModel $matchingProductsList[] = $cartSupplier['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) - return Tools::displayError('You cannot use this voucher with these products'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = array_uintersect($eligibleProductsList, $matchingProductsList, 'cartrule_products_intersect'); break; } if (!count($eligibleProductsList)) - return Tools::displayError('You cannot use this voucher with these products'); + return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); } $selectedProducts = array_merge($selectedProducts, $eligibleProductsList); } @@ -657,7 +662,7 @@ class CartRuleCore extends ObjectModel if ($return_products) return $selectedProducts; - return false; + return ($display_error) ? true : false; } /** @@ -938,7 +943,6 @@ class CartRuleCore extends ObjectModel AND cr.quantity > 0 AND cr.date_from < "'.date('Y-m-d H:i:s').'" AND cr.date_to > "'.date('Y-m-d H:i:s').'" - AND cr.id_cart_rule NOT IN (SELECT id_cart_rule FROM '._DB_PREFIX_.'cart_cart_rule WHERE id_cart = '.(int)$context->cart->id.') AND ( cr.id_customer = 0 '.($context->customer->id ? 'OR cr.id_customer = '.(int)$context->cart->id_customer : '').' @@ -975,8 +979,15 @@ class CartRuleCore extends ObjectModel // Todo: consider optimization (we can avoid many queries in checkValidity) foreach ($cartRules as $cartRule) - if (!$cartRule->checkValidity($context)) - $context->cart->addCartRule($cartRule->id); + if (Db::getInstance()->getValue('SELECT count(*) + FROM '._DB_PREFIX_.'cart_cart_rule + WHERE id_cart = '.(int)$context->cart->id.' + AND id_cart_rule = '.(int)$cartRule->id)) + $context->cart->removeCartRule($cartRule->id); + + foreach ($cartRules as $cartRule) + if ($cartRule->checkValidity($context, true, false)) + $context->cart->addCartRule($cartRule->id); } /** @@ -1007,13 +1018,13 @@ class CartRuleCore extends ObjectModel function cartrule_products_intersect($a, $b) { - if ($a == $b) - return 0; + if ($a == $b) + return 0; $asplit = explode('-', $a); $bsplit = explode('-', $b); - if ($asplit[0] == $bsplit[0] && (!(int)$asplit[1] || !(int)$bsplit[1])) - return 0; + if ($asplit[0] == $bsplit[0] && (!(int)$asplit[1] || !(int)$bsplit[1])) + return 0; return 1; -} \ No newline at end of file +} diff --git a/controllers/admin/AdminCartRulesController.php b/controllers/admin/AdminCartRulesController.php index 7611a3c51..3ea7bd11a 100644 --- a/controllers/admin/AdminCartRulesController.php +++ b/controllers/admin/AdminCartRulesController.php @@ -168,8 +168,11 @@ class AdminCartRulesControllerCore extends AdminController { Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'cart_rule` SET cart_rule_restriction = 1 WHERE id_cart_rule = '.(int)$incompatibleRule['id_cart_rule'].' LIMIT 1'); Db::getInstance()->execute(' - INSERT INTO `'._DB_PREFIX_.'cart_rule_combination` (`id_cart_rule_1`, `id_cart_rule_2`) ( - SELECT id_cart_rule, '.(int)$incompatibleRule['id_cart_rule'].' FROM `'._DB_PREFIX_.'cart_rule` WHERE active = 1 AND id_cart_rule != '.(int)$currentObject->id.' + INSERT IGNORE INTO `'._DB_PREFIX_.'cart_rule_combination` (`id_cart_rule_1`, `id_cart_rule_2`) ( + SELECT id_cart_rule, '.(int)$incompatibleRule['id_cart_rule'].' FROM `'._DB_PREFIX_.'cart_rule` + WHERE active = 1 + AND id_cart_rule != '.(int)$currentObject->id.' + AND id_cart_rule != '.(int)$incompatibleRule['id_cart_rule'].' )'); } } @@ -474,6 +477,7 @@ class AdminCartRulesControllerCore extends AdminController } } + $product = new Product($current_object->gift_product); $this->context->smarty->assign( array( 'show_toolbar' => true, @@ -502,7 +506,8 @@ class AdminCartRulesControllerCore extends AdminController 'currentIndex' => self::$currentIndex, 'currentToken' => $this->token, 'currentObject' => $current_object, - 'currentTab' => $this + 'currentTab' => $this, + 'hasAttribute' => $product->hasAttributes(), ) ); diff --git a/controllers/admin/AdminCartsController.php b/controllers/admin/AdminCartsController.php index abdf5a8d3..dd32d550b 100755 --- a/controllers/admin/AdminCartsController.php +++ b/controllers/admin/AdminCartsController.php @@ -29,7 +29,7 @@ class AdminCartsControllerCore extends AdminController { public function __construct() { - $this->table = 'cart'; + $this->table = 'cart'; $this->className = 'Cart'; $this->lang = false; $this->requiredDatabase = true; @@ -44,7 +44,7 @@ class AdminCartsControllerCore extends AdminController LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_cart = a.id_cart) LEFT JOIN `'._DB_PREFIX_.'connections` co ON (a.id_guest = co.id_guest AND TIME_TO_SEC(TIMEDIFF(NOW(), co.`date_add`)) < 1800)'; - $this->fields_list = array( + $this->fields_list = array( 'id_cart' => array( 'title' => $this->l('ID'), 'align' => 'center', @@ -149,7 +149,7 @@ class AdminCartsControllerCore extends AdminController $image = Db::getInstance()->getRow('SELECT id_image FROM '._DB_PREFIX_.'product_attribute_image WHERE id_product_attribute = '.(int)$product['id_product_attribute']); - if (!isset($image['id_image'])) + if (!isset($image['id_image'])) $image = Db::getInstance()->getRow('SELECT id_image FROM '._DB_PREFIX_.'image WHERE id_product = '.(int)$product['id_product'].' AND cover = 1'); diff --git a/controllers/front/CartController.php b/controllers/front/CartController.php index bf243909c..02901010c 100644 --- a/controllers/front/CartController.php +++ b/controllers/front/CartController.php @@ -227,13 +227,26 @@ class CartControllerCore extends FrontController $minimal_quantity = ($this->id_product_attribute) ? Attribute::getAttributeMinimalQty($this->id_product_attribute) : $product->minimal_quantity; $this->errors[] = Tools::displayError('You must add', false).' '.$minimal_quantity.' '.Tools::displayError('Minimum quantity', false); } - else if (!$updateQuantity) + elseif (!$updateQuantity) $this->errors[] = Tools::displayError('You already have the maximum quantity available for this product.', false); - else + elseif ((int)Tools::getValue('allow_refresh')) { + // If the cart rules has changed, we need to refresh the whole cart $cart_rules2 = $this->context->cart->getCartRules(); - if (count($cart_rules2) != count($cart_rules) && (int)Tools::getValue('allow_refresh')) + if (count($cart_rules2) != count($cart_rules)) $this->ajax_refresh = true; + else + { + $rule_list = array(); + foreach ($cart_rules2 as $rule) + $rule_list[] = $rule['id_cart_rule']; + foreach ($cart_rules as $rule) + if (!in_array($rule['id_cart_rule'], $rule_list)) + { + $this->ajax_refresh = true; + break; + } + } } } } diff --git a/themes/default/shopping-cart-product-line.tpl b/themes/default/shopping-cart-product-line.tpl index 2dab8400d..e4ca798ee 100644 --- a/themes/default/shopping-cart-product-line.tpl +++ b/themes/default/shopping-cart-product-line.tpl @@ -71,7 +71,7 @@ {/if} - + {/if} {/if}