Miria Posted July 12, 2012 Share Posted July 12, 2012 (edited) Bonjour, J'ai créé un code de réduction avec les règles de prix panier mais je ne vois à aucun endroit la possiblité de rendre le bon non cumulable avec les promotions... Une idée ? Edited July 12, 2012 by Miria (see edit history) Link to comment Share on other sites More sharing options...
Urakawa41 Posted July 28, 2012 Share Posted July 28, 2012 Bonjour, Quand tu paramètres ton bon de réduction, tu as en dessous des catégories, les paramètres "Quantité par personne", "Quantité totale disponible" et "Montant minimum d'achat". En dessous, il y a deux carrés à cocher : "Cumulable avec d'autres bons de réductions" et "Cumulable avec les promotions". Normalement, il te suffit juste de ne pas cocher ce dernier. C'est moi ça marche. Si ça ne marche pas comme ça, alors je ne vois pas :/ Désolé. 1 Link to comment Share on other sites More sharing options...
kittypaw Posted December 4, 2012 Share Posted December 4, 2012 Urakawa41 : Ca c'est dans une version 1.4 non ? Je cherche également à rendre non cumulable les bons de réduction. Il me semble que dans l'onglet condition, en bas se trouve plusieurs cases. Et plus précisément celle-ci : Compatibilité avec les autres règles paniers. Il faut donc enlever les bons de réductions et les mettre dans la colonne non cumulables. Si quelqu'un peut confirmer ma manipulation. Par contre, comment faire pour rendre directement un bon de réduction créé 'en code' non cumulable ? Link to comment Share on other sites More sharing options...
cockpitinferno Posted February 19, 2013 Share Posted February 19, 2013 idem, en fait on peut rendre les bon non cumulables entre eux mais on ne peut pas les rendre non cumulables avec les autres type de promos. est ce que qqun aurait une solution pour ca, moi je souhaite que mes bons de reduction ne soient pas tous cumulables avec les autres promos. Link to comment Share on other sites More sharing options...
cockpitinferno Posted March 29, 2013 Share Posted March 29, 2013 un petit up, pb non résolu avec la v 1.5.4. que faut il faire pour que ce soit pris en compte c'est déjà posté sur la forge! Link to comment Share on other sites More sharing options...
Julie S. Posted March 29, 2013 Share Posted March 29, 2013 est-ce un bug ou un souhait de votre part ? Link to comment Share on other sites More sharing options...
cockpitinferno Posted March 30, 2013 Share Posted March 30, 2013 a qui posez vous la question? à moi ou à la team? si c'est un souhait de leur part c'est un peu débile donc a mon avis c'est un oubli. car c'est pas vraiment un bug non plus. c'est peut etre pour ca qe tout le monde s'en fou d'ailleurs... Link to comment Share on other sites More sharing options...
Julie S. Posted March 30, 2013 Share Posted March 30, 2013 Je vous pose la question à vous. Vous êtes dans la zone de rapport de bug, ce forum à des règles, en voici la substantifique moëlle : Ainsi, avant de poster ici, il convient désormais de : I - poster dans un autre forum. II - vérifier que c'est bien un bug (en comparant avec d'autres utilisateurs) III - si le bug est avéré, poster ici en n'oubliant pas de faire référence au post initial. IV - déclarer le bug dans le bug tracker (en anglais) - si vous ne vous sentez pas de le faire (pas super doué/e en anglais), l'un des visiteurs le fera pour vous. Attention : les bugs postés en français dans le BT seront effacés sans pitié. ;-) Sans ces prérequis la team risque fort de ne pas vous répondre. Postez donc dans une partie plus appropriée, comme ici : http://www.prestashop.com/forums/forum/20-configuration-et-utilisation-de-prestashop/ Link to comment Share on other sites More sharing options...
cockpitinferno Posted April 2, 2013 Share Posted April 2, 2013 au cas ou vous n'auriez pas remarqué ce n'est pas moi qui ai posté là en 1er lieu. et comme déjà dit plus haut cela a déjà été posté dans le bug tracker. enfin, pour moi il s'agit d'un bug ou d'un oubli dans le sens ou cette fonctionnalité existait avant donc pour moi c'est pas une amélioration mais bien la correction d'un manque survenu après la mise à jour. c'est donc effectivement un souhait de ma part de rétablir une fonctionnalité qui existait auparavant. donc c'est à la fois un souhait et un bug... Link to comment Share on other sites More sharing options...
Julie S. Posted April 2, 2013 Share Posted April 2, 2013 (edited) c'est bien vous qui demandez pourquoi personne ne répond, j'essaie de vous apporter une réponse. Je suis d'avis que tant que les membres posteront leurs désidératas sans respecter le protocole lié à la soumission d'un bug, nous aurons ici de moins en moins de réponse de la part de la team. Maintenant, si vous l'avez soumis sur la forge, consultez son état et la réponse de la team là-bas... Il n'y a que là bas que vous aurez une réponse claire de la team en charge du développement. Et lorsque vous aurez la réponse, venez nous dire ce qu'il en est, c'est toujours intéressant pour la communauté. Edited April 2, 2013 by juliettte (see edit history) Link to comment Share on other sites More sharing options...
cockpitinferno Posted April 3, 2013 Share Posted April 3, 2013 oui mais je remarque que dès qu'on critique presta sur ce forum tout le monde réponds, c'est le seul moyen en ce moment d'obtenir une réaction. je consulte la forge tous les jours, le pb était assigné à qqun et il ne l'est plus. j'ai envoyé un mail à la personne de la team qui m'a aidé sur un autre bug (bien plus problématique) mais pas de réponse. bref, c'est encore une fois du grand n'importe quoi. Link to comment Share on other sites More sharing options...
cockpitinferno Posted April 18, 2013 Share Posted April 18, 2013 je relance un peu ce post car toujours pas de news. j'ai essayé de trifouiller du coté de cartrules.php j'ai créé un bouton dans l'admin, et mis une dondition mais du coup j'ai le message d'erreur si le bouton est coché et même si c'est un produit non soldé ou sans promo. il me manque la condition de l'article en promo. un petit coup de pouce serait le bienvenu, vu que pas moyen d'obtenir la solution autrement, faut bien mettre les mains dans le camboui... com d'hab... Link to comment Share on other sites More sharing options...
eric69 Posted May 25, 2013 Share Posted May 25, 2013 (edited) c'est cool je viens de découvrir que je suis pas le seul dans ce cas sous ps 1.5 un moment je croyait que c'était moi qui ne comprenait pas, mais après une demi journée de recherche sous ps 1.5 effectivement la création de bons non cumulables n'est pas possible ?? quand on voie toutes les options qu'il ont ajouter par rapport à la version 1.4, c'est super bisard qu'ils n'est pas laissé la fonction basique qui était sous ps 1.4 ? Edited May 25, 2013 by eric69 (see edit history) Link to comment Share on other sites More sharing options...
eric69 Posted May 29, 2013 Share Posted May 29, 2013 Bonjour, alors j'ai fini par trouver, en fait c'est super simple, mais il fallait le savoir. il faut mettre sur 2 la priorité du bon que vous voulez créer, pour qu'il ne soit pas applicable sur les produits déjà soldé! si vous mettez bien priorité (2) le bon ne sera pas valable sur vos produits en promotions voilà, dommage que le team ps n'est pas le temps de répondre sur le forum pour ce genre de questions Link to comment Share on other sites More sharing options...
cockpitinferno Posted May 31, 2013 Share Posted May 31, 2013 vous êtes sur? je vais de ce pas aller regarder ca... si c'est ca ce serait super cool. Link to comment Share on other sites More sharing options...
cockpitinferno Posted May 31, 2013 Share Posted May 31, 2013 je viens d'essayer et le bon est cumulable même en mettant 2 sur la priorité. avez vous fait autre chose en plus? Link to comment Share on other sites More sharing options...
laurent65200 Posted July 10, 2013 Share Posted July 10, 2013 up toujours le problème mes bons de réduction reste cumulable entre eux presta 1.5.4.1 avant il y avais un bouton cumulable ou pas help me Link to comment Share on other sites More sharing options...
eric69 Posted July 10, 2013 Share Posted July 10, 2013 Bjr, pour j'ai résolu, les fonctions de ps 1.5 ne permettant pas de régler les bons de réductions, de façon simple et claire, et fonctionnant correctement, j'ai fais modifier par mes dev, un module que j'avais, pour l'utiliser en bon de réductions réglable et fonctionnel. Il est possible de contacter les dev pour acheter le module, si vous en avez marre de galérer ! Link to comment Share on other sites More sharing options...
laurent65200 Posted July 10, 2013 Share Posted July 10, 2013 il est a combien et qui contacter ? Link to comment Share on other sites More sharing options...
eric69 Posted July 10, 2013 Share Posted July 10, 2013 le module je l'ai fait développer, donc a moi il m'a coûté plus chère que si vous l'achetez maintenant qu'il est fait! Je ne sais pas combien ils le vendent, mais le prix doit être très correcte, contactez moi par MP pour avoir les coordonnées de la société concerné. Link to comment Share on other sites More sharing options...
cockpitinferno Posted August 30, 2013 Share Posted August 30, 2013 hé bien ca n'est pas normal de payer pour une option qui est en natif sur la version 1.4. ca n'est toujours pas résolu en 1.5 et franchement je désespère je ne sais pas en quelle langue il faut s'exprimer pour être entendu. au moins si c'est fait exprès pour nous faire payer des modules qu'ils aient l'honneté de le dire mais là ca fait 1 an que j'attends (et je suis sure que je suis pas la seule) pour que cette option soit rétablie. et là toujours rien... Link to comment Share on other sites More sharing options...
eric69 Posted August 30, 2013 Share Posted August 30, 2013 oui il y a plusieurs options qui devrait être d'origine sur une application de cette envergure, et qui nous oblige à acheter des modules, qui ne fonctionnent pas toujours très bien. J'ai acheté aussi des modules qui ne fonctionnent pas sur addons, et pas de réponses des dev, du coups maintenant j'ai trouvé une société sérieuse et compétente, avec des prix très raisonnables, je préfère faire développer mes modules maintenant, c'est plus sûr et au moins il y a un suivi dessus ! Link to comment Share on other sites More sharing options...
manulito Posted September 17, 2013 Share Posted September 17, 2013 J'ai acheté aussi des modules qui ne fonctionnent pas sur addons, et pas de réponses des dev, bonjour, je suis dans le meme cas, j'ai acheté 2 modules sur addons, dont 1 avec l'option sérénité (j'aurai du prendre l'option "réponse aux emails des clients"...) et qui ont chacun un problème, mais je n'ai pas de réponse de presta ni de personne, après 4 ou 5 messages, dont 1 avec des codes..... pourriez vous me donner le nom de cette société pour passer par eux ? ou un email, le site, etc... merci d'avance Link to comment Share on other sites More sharing options...
eric69 Posted September 17, 2013 Share Posted September 17, 2013 Bonjour, ok par MP Link to comment Share on other sites More sharing options...
cockpitinferno Posted September 18, 2013 Share Posted September 18, 2013 c'est plutôt honteux ce qui se passe là! déjà c'est pas normal de payer pour ne fonction qui d'après moi est une fonction de base puisqu'en plus elle est d'une logique implacable. mais si en plus tu paye et que ca ne fonctionne pas , là on marche sur la tête! j'espère que vous vous êtes fait remboursés... 1 Link to comment Share on other sites More sharing options...
eric69 Posted September 18, 2013 Share Posted September 18, 2013 Et non pas de remboursement ! J'ai fais appel a une société enfin sérieuse qui m'a débloqué mon problème. par contre venant du dev et du team Prestashop le suivi est vraiment déplorable. Heureusement que je ne m'occupe pas de mes clients comme eux, sinon j'aurais fermé mes boutique depuis longtemps moi au moins je fais le SAV sur mes produits. Link to comment Share on other sites More sharing options...
Manuel Corbet Posted September 18, 2013 Share Posted September 18, 2013 (edited) Bonjour, en effet cela était possible en 1.4 mais pas en 1.5 ... En faisant l'override de la classe CartRule on s'en sort très bien ! Donc si votre besoin est seulement de permettre de bloquer les bons sur les produits en promos, ne vous faite pas "arnaquer" avec l'achat d'un module, il suffit de rajouter quelques lignes de codes, rien de bien sorcié ... Il s'agit de la méthode "public function checkValidity" : il faut rajouter : $products = $context->cart->getProducts(); $product_on_sale = false; foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; } if ($product_on_sale) return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); Il faut place cela après le code suivant : (je vous incite fortement à utiliser l'override pour faire la modification.) if (strtotime($this->date_to) < time()) return (!$display_error) ? false : Tools::displayError('This voucher has expired'); Cordialement, Edited September 18, 2013 by Manuel Corbet (see edit history) 3 Link to comment Share on other sites More sharing options...
Manuel Corbet Posted September 18, 2013 Share Posted September 18, 2013 (edited) Cela donne pour l'ensemble de la méthode checkValidity public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true) { if (!CartRule::isFeatureActive()) return false; if (!$this->active) return (!$display_error) ? false : Tools::displayError('This voucher is disabled'); if (!$this->quantity) return (!$display_error) ? false : Tools::displayError('This voucher has already been used'); if (strtotime($this->date_from) > time()) return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet'); if (strtotime($this->date_to) < time()) return (!$display_error) ? false : Tools::displayError('This voucher has expired'); $products = $context->cart->getProducts(); $product_on_sale = false; foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; } if ($product_on_sale) return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); if ($context->cart->id_customer) { $quantityUsed = Db::getInstance()->getValue(' SELECT count(*) FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order WHERE o.id_customer = '.$context->cart->id_customer.' AND od.id_cart_rule = '.(int)$this->id.' AND '.(int)Configuration::get('PS_OS_ERROR').' != ( SELECT oh.id_order_state FROM '._DB_PREFIX_.'order_history oh WHERE oh.id_order = o.id_order ORDER BY oh.date_add DESC LIMIT 1 )'); if ($quantityUsed + 1 > $this->quantity_per_user) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)'); } // Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1) if ($this->group_restriction) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crg.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_group crg 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 (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } // Check if the customer delivery address is usable with the cart rule if ($this->country_restriction) { if (!$context->cart->id_address_delivery) return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_country crc 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 (!$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 if ($this->carrier_restriction) { if (!$context->cart->id_carrier) return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_carrier crc INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0) WHERE crc.id_cart_rule = '.(int)$this->id.' AND c.id_carrier = '.(int)$context->cart->id_carrier); if (!$id_cart_rule) 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 if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive()) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crs.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_shop crs WHERE crs.id_cart_rule = '.(int)$this->id.' AND crs.id_shop = '.(int)$context->shop->id); if (!$id_cart_rule) 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, $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 (!$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) { // Minimum amount is converted to the default currency $minimum_amount = $this->minimum_amount; if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT')) { $minimum_amount_currency = new Currency($this->minimum_amount_currency); if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0) $minimum_amount = 0; else $minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate; } $cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS); if ($this->minimum_amount_shipping) $cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING); // If a product is given for free in this rule and already in the cart, the price is subtracted if ($this->gift_product && $alreadyInCart) { $query = new DbQuery(); $query->select('id_product'); $query->from('cart_product'); $query->where('id_product = '.(int)$this->gift_product); $query->where('id_cart = '.(int)$context->cart->id); if ((int)$this->gift_product_attribute) $query->where('id_product_attribute = '.(int)$this->gift_product_attribute); if (Db::getInstance()->getValue($query)) { $ref = false; $product_price = Product::getPriceStatic( $this->gift_product, $this->minimum_amount_tax, $this->gift_product_attribute, null, null, false, true, 1, null, $context->cart->id_customer ? $context->cart->id_customer : null, $context->cart->id, (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null, $ref, true, true, $context, true ); $cartTotal -= $product_price; } } if ($cartTotal < $minimum_amount) return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher'); } // Check if the voucher is already in the cart of if a non compatible voucher is in the cart // Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them $otherCartRules = $context->cart->getCartRules(); if (count($otherCartRules)) foreach ($otherCartRules as $otherCartRule) { if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart) 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 FROM '._DB_PREFIX_.'cart_rule_combination WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].') OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')'); if (!$combinable) { $cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang); // The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested if ($cart_rule->priority <= $this->priority) return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name; // But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one else $context->cart->removeCartRule($cart_rule->id); } } } if (!$display_error) return true; } PS : pensez à traduire le message dans les traductions des messages d'erreur ! Cordialement, Edited September 18, 2013 by Manuel Corbet (see edit history) 2 Link to comment Share on other sites More sharing options...
cockpitinferno Posted September 18, 2013 Share Posted September 18, 2013 (edited) super ca fonctionne (mais pas en override) merci tu es mon sauveur, ca fait 6 mois que je réclme ca!! mille milliards de milles mercis... je vais enfin pouvoir passer à la 1.5 Edited September 18, 2013 by cockpitinferno (see edit history) 1 Link to comment Share on other sites More sharing options...
laurent65200 Posted September 18, 2013 Share Posted September 18, 2013 bonjour dans quel fichier stp Link to comment Share on other sites More sharing options...
cockpitinferno Posted September 18, 2013 Share Posted September 18, 2013 tout est noté: cartrules.php 1 Link to comment Share on other sites More sharing options...
Manuel Corbet Posted September 19, 2013 Share Posted September 19, 2013 (edited) Bonjour, aucun problème ça fait toujours plaisir de pouvoir aider la communauté !! Surtout qu'en on voit tout le monde essayer de vendre ses modules alors qu'il s'agit d'une petite modification à faire ... Bizarre que ça ne fonctionne pas en Override... Peut être les cache il y a un fichier cache/classe_index.php qu'il faut supprimer pour prendre en compte les classes de l'override au moment de l'ajout d'une nouvelle (pas la peine lorsque l'on modifie déjà une classe en Override). Ça pourrait être aussi un soucis avec l'entête de votre fichier override/classes/CartRule.php il faut bien que ce soit dans ce cas : class CartRule extends CartRuleCore et non : class CartRuleCore extends ObjectModel Mais je pense plutôt qu'il s'agit du cache/classe_index.php Edited September 19, 2013 by Manuel Corbet (see edit history) 1 Link to comment Share on other sites More sharing options...
manulito Posted September 19, 2013 Share Posted September 19, 2013 Bonjour, votre solution marche très bien en override. sur ps 1.5.4.1 merci beaucoup Link to comment Share on other sites More sharing options...
cockpitinferno Posted September 23, 2013 Share Posted September 23, 2013 oui c'est peut etre ca mais j'ai pas pris le temps d'approfondir car bcp de taf en ce moment. je verrai cela plus posément que je changerai de version c'est à dire dans un mois au mieux sinon pendant les vac de noel; Link to comment Share on other sites More sharing options...
Manuel Corbet Posted September 30, 2013 Share Posted September 30, 2013 Bonjour tout le monde, pour info le client pour qui j'avais effectué cette modification m'a demandé de laissé la possibilité de faire les bons de réduction sur les promos si il s'agit d'un bon proposant une réduction par "montant". En gros d'interdire seulement les bons en pourcentage du prix pour les produits soldés. Voici donc la nouvelle version avec ce feature en plus : public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true) { if (!CartRule::isFeatureActive()) return false; if (!$this->active) return (!$display_error) ? false : Tools::displayError('This voucher is disabled'); if (!$this->quantity) return (!$display_error) ? false : Tools::displayError('This voucher has already been used'); if (strtotime($this->date_from) > time()) return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet'); if (strtotime($this->date_to) < time()) return (!$display_error) ? false : Tools::displayError('This voucher has expired'); $product_on_sale = false; $amount = false; if($this->reduction_percent === '0.00' && $this->reduction_amount !== '0.00') $amount = true; if(!$amount){ $products = $context->cart->getProducts(); foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; } if ($product_on_sale) return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); } if ($context->cart->id_customer) { $quantityUsed = Db::getInstance()->getValue(' SELECT count(*) FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order WHERE o.id_customer = '.$context->cart->id_customer.' AND od.id_cart_rule = '.(int)$this->id.' AND '.(int)Configuration::get('PS_OS_ERROR').' != ( SELECT oh.id_order_state FROM '._DB_PREFIX_.'order_history oh WHERE oh.id_order = o.id_order ORDER BY oh.date_add DESC LIMIT 1 )'); if ($quantityUsed + 1 > $this->quantity_per_user) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)'); } // Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1) if ($this->group_restriction) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crg.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_group crg 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 (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } // Check if the customer delivery address is usable with the cart rule if ($this->country_restriction) { if (!$context->cart->id_address_delivery) return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_country crc 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 (!$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 if ($this->carrier_restriction) { if (!$context->cart->id_carrier) return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_carrier crc INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0) WHERE crc.id_cart_rule = '.(int)$this->id.' AND c.id_carrier = '.(int)$context->cart->id_carrier); if (!$id_cart_rule) 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 if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive()) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crs.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_shop crs WHERE crs.id_cart_rule = '.(int)$this->id.' AND crs.id_shop = '.(int)$context->shop->id); if (!$id_cart_rule) 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, $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 (!$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) { // Minimum amount is converted to the default currency $minimum_amount = $this->minimum_amount; if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT')) { $minimum_amount_currency = new Currency($this->minimum_amount_currency); if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0) $minimum_amount = 0; else $minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate; } $cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS); if ($this->minimum_amount_shipping) $cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING); // If a product is given for free in this rule and already in the cart, the price is subtracted if ($this->gift_product && $alreadyInCart) { $query = new DbQuery(); $query->select('id_product'); $query->from('cart_product'); $query->where('id_product = '.(int)$this->gift_product); $query->where('id_cart = '.(int)$context->cart->id); if ((int)$this->gift_product_attribute) $query->where('id_product_attribute = '.(int)$this->gift_product_attribute); if (Db::getInstance()->getValue($query)) { $ref = false; $product_price = Product::getPriceStatic( $this->gift_product, $this->minimum_amount_tax, $this->gift_product_attribute, null, null, false, true, 1, null, $context->cart->id_customer ? $context->cart->id_customer : null, $context->cart->id, (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null, $ref, true, true, $context, true ); $cartTotal -= $product_price; } } if ($cartTotal < $minimum_amount) return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher'); } // Check if the voucher is already in the cart of if a non compatible voucher is in the cart // Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them $otherCartRules = $context->cart->getCartRules(); if (count($otherCartRules)) foreach ($otherCartRules as $otherCartRule) { if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart) 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 FROM '._DB_PREFIX_.'cart_rule_combination WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].') OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')'); if (!$combinable) { $cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang); // The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested if ($cart_rule->priority <= $this->priority) return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name; // But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one else $context->cart->removeCartRule($cart_rule->id); } } } if (!$display_error) return true; } 1 Link to comment Share on other sites More sharing options...
laurent65200 Posted October 2, 2013 Share Posted October 2, 2013 bonjour je n'est pas trouver ou modifier complexe voici mon fichier quelqu un peut m'integrer se qui faut svp <?php /* * 2007-2013 PrestaShop * * 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: * http://opensource.org/licenses/osl-3.0.php * 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 502immediately. * * 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 http://www.prestashop.com for more information. * * @author PrestaShop SA <[email protected]> * @copyright 2007-2013 PrestaShop SA * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ class CartRuleCore extends ObjectModel { /* Filters used when retrieving the cart rules applied to a cart of when calculating the value of a reduction */ const FILTER_ACTION_ALL = 1; const FILTER_ACTION_SHIPPING = 2; const FILTER_ACTION_REDUCTION = 3; const FILTER_ACTION_GIFT = 4; const FILTER_ACTION_ALL_NOCAP = 5; const BO_ORDER_CODE_PREFIX = 'BO_ORDER_'; /* This variable controls that a free gift is offered only once, even when multi-shippping is activated and the same product is delivered in both addresses */ protected static $only_one_gift = array(); public $id; public $name; public $id_customer; public $date_from; public $date_to; public $description; public $quantity = 1; public $quantity_per_user = 1; public $priority = 1; public $partial_use = 1; public $code; public $minimum_amount; public $minimum_amount_tax; public $minimum_amount_currency; public $minimum_amount_shipping; public $country_restriction; public $carrier_restriction; public $group_restriction; public $cart_rule_restriction; public $product_restriction; public $shop_restriction; public $free_shipping; public $reduction_percent; public $reduction_amount; public $reduction_tax; public $reduction_currency; public $reduction_product; public $gift_product; public $gift_product_attribute; public $highlight; public $active = 1; public $date_add; public $date_upd; /** * @see ObjectModel::$definition */ public static $definition = array( 'table' => 'cart_rule', 'primary' => 'id_cart_rule', 'multilang' => true, 'fields' => array( 'id_customer' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'), 'date_from' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => true), 'date_to' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => true), 'description' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 65534), 'quantity' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'quantity_per_user' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'priority' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'partial_use' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'code' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 254), 'minimum_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'), 'minimum_amount_tax' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'minimum_amount_currency' =>array('type' => self::TYPE_INT, 'validate' => 'isInt'), 'minimum_amount_shipping' =>array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'country_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'carrier_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'group_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'cart_rule_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'product_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'shop_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'free_shipping' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'reduction_percent' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPercentage'), 'reduction_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'), 'reduction_tax' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'reduction_currency' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'), 'reduction_product' => array('type' => self::TYPE_INT, 'validate' => 'isInt'), 'gift_product' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'), 'gift_product_attribute' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'), 'highlight' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'), 'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'), // Lang fields 'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCleanHtml', 'required' => true, 'size' => 254), ), ); /** * @see ObjectModel::add() */ public function add($autodate = true, $null_values = false) { if (!parent::add($autodate, $null_values)) return false; Configuration::updateGlobalValue('PS_CART_RULE_FEATURE_ACTIVE', '1'); return true; } public function update($null_values = false) { Cache::clean('getContextualValue_'.$this->id.'_*'); return parent::update($null_values); } /** * @see ObjectModel::delete() */ public function delete() { if (!parent::delete()) return false; Configuration::updateGlobalValue('PS_CART_RULE_FEATURE_ACTIVE', CartRule::isCurrentlyUsed($this->def['table'], true)); $r = Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_cart_rule` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_carrier` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_shop` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_group` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_country` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_combination` WHERE `id_cart_rule_1` = '.(int)$this->id.' OR `id_cart_rule_2` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_group` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule` WHERE `id_product_rule_group` NOT IN (SELECT `id_product_rule_group` FROM `'._DB_PREFIX_.'cart_rule_product_rule_group`)'); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_value` WHERE `id_product_rule` NOT IN (SELECT `id_product_rule` FROM `'._DB_PREFIX_.'cart_rule_product_rule`)'); return $r; } /** * Copy conditions from one cart rule to an other * * @static * @param int $id_cart_rule_source * @param int $id_cart_rule_destination */ public static function copyConditions($id_cart_rule_source, $id_cart_rule_destination) { Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_shop` (`id_cart_rule`, `id_shop`) (SELECT '.(int)$id_cart_rule_destination.', id_shop FROM `'._DB_PREFIX_.'cart_rule_shop` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_carrier` (`id_cart_rule`, `id_carrier`) (SELECT '.(int)$id_cart_rule_destination.', id_carrier FROM `'._DB_PREFIX_.'cart_rule_carrier` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_group` (`id_cart_rule`, `id_group`) (SELECT '.(int)$id_cart_rule_destination.', id_group FROM `'._DB_PREFIX_.'cart_rule_group` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_country` (`id_cart_rule`, `id_country`) (SELECT '.(int)$id_cart_rule_destination.', id_country FROM `'._DB_PREFIX_.'cart_rule_country` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_combination` (`id_cart_rule_1`, `id_cart_rule_2`) (SELECT '.(int)$id_cart_rule_destination.', IF(id_cart_rule_1 != '.(int)$id_cart_rule_source.', id_cart_rule_1, id_cart_rule_2) FROM `'._DB_PREFIX_.'cart_rule_combination` WHERE `id_cart_rule_1` = '.(int)$id_cart_rule_source.' OR `id_cart_rule_2` = '.(int)$id_cart_rule_source.')'); // Todo : should be changed soon, be must be copied too // Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule` WHERE `id_cart_rule` = '.(int)$this->id); // Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_value` WHERE `id_product_rule` NOT IN (SELECT `id_product_rule` FROM `'._DB_PREFIX_.'cart_rule_product_rule`)'); } /** * Retrieves the id associated to the given code * * @static * @param string $code * @return int|bool */ public static function getIdByCode($code) { if (!Validate::isCleanHtml($code)) return false; return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('SELECT `id_cart_rule` FROM `'._DB_PREFIX_.'cart_rule` WHERE `code` = \''.pSQL($code).'\''); } /** * @static * @param $id_lang * @param $id_customer * @param bool $active * @param bool $includeGeneric * @param bool $inStock * @param Cart|null $cart * @return array */ public static function getCustomerCartRules($id_lang, $id_customer, $active = false, $includeGeneric = true, $inStock = false, Cart $cart = null) { if (!CartRule::isFeatureActive()) return array(); $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT * FROM `'._DB_PREFIX_.'cart_rule` cr LEFT JOIN `'._DB_PREFIX_.'cart_rule_lang` crl ON (cr.`id_cart_rule` = crl.`id_cart_rule` AND crl.`id_lang` = '.(int)$id_lang.') WHERE ( cr.`id_customer` = '.(int)$id_customer.' OR cr.group_restriction = 1 '.($includeGeneric ? 'OR cr.`id_customer` = 0' : '').' ) AND cr.date_from < "'.date('Y-m-d H:i:s').'" AND cr.date_to > "'.date('Y-m-d H:i:s').'" '.($active ? 'AND cr.`active` = 1' : '').' '.($inStock ? 'AND cr.`quantity` > 0' : '')); // Remove cart rule that does not match the customer groups $customerGroups = Customer::getGroupsStatic($id_customer); foreach ($result as $key => $cart_rule) if ($cart_rule['group_restriction']) { $cartRuleGroups = Db::getInstance()->executeS('SELECT id_group FROM '._DB_PREFIX_.'cart_rule_group WHERE id_cart_rule = '.(int)$cart_rule['id_cart_rule']); foreach ($cartRuleGroups as $cartRuleGroup) if (in_array($cartRuleGroup['id_group'], $customerGroups)) continue 2; unset($result[$key]); } foreach ($result as &$cart_rule) if ($cart_rule['quantity_per_user']) { $quantity_used = Order::getDiscountsCustomer((int)$id_customer, (int)$cart_rule['id_cart_rule']); if (isset($cart) && isset($cart->id)) $quantity_used += $cart->getDiscountsCustomer((int)$cart_rule['id_cart_rule']); $cart_rule['quantity_for_user'] = $cart_rule['quantity_per_user'] - $quantity_used; } else $cart_rule['quantity_for_user'] = 0; // Retrocompatibility with 1.4 discounts foreach ($result as &$cart_rule) { $cart_rule['value'] = 0; $cart_rule['minimal'] = $cart_rule['minimum_amount']; $cart_rule['cumulable'] = !$cart_rule['cart_rule_restriction']; $cart_rule['id_discount_type'] = false; if ($cart_rule['free_shipping']) $cart_rule['id_discount_type'] = Discount::FREE_SHIPPING; elseif ($cart_rule['reduction_percent'] > 0) { $cart_rule['id_discount_type'] = Discount::PERCENT; $cart_rule['value'] = $cart_rule['reduction_percent']; } elseif ($cart_rule['reduction_amount'] > 0) { $cart_rule['id_discount_type'] = Discount::AMOUNT; $cart_rule['value'] = $cart_rule['reduction_amount']; } } return $result; } /** * @param $id_customer * @return bool */ public function usedByCustomer($id_customer) { return (bool)Db::getInstance()->getValue(' SELECT id_cart_rule FROM `'._DB_PREFIX_.'order_cart_rule` ocr LEFT JOIN `'._DB_PREFIX_.'orders` o ON ocr.`id_order` = o.`id_order` WHERE ocr.`id_cart_rule` = '.(int)$this->id.' AND o.`id_customer` = '.(int)$id_customer); } /** * @static * @param $name * @return bool */ public static function cartRuleExists($name) { if (!CartRule::isFeatureActive()) return false; return (bool)Db::getInstance()->getValue(' SELECT `id_cart_rule` FROM `'._DB_PREFIX_.'cart_rule` WHERE `code` = \''.pSQL($name).'\''); } /** * @static * @param $id_customer * @return bool */ public static function deleteByIdCustomer($id_customer) { $return = true; $cart_rules = new Collection('CartRule'); $cart_rules->where('id_customer', '=', $id_customer); foreach ($cart_rules as $cart_rule) $return &= $cart_rule->delete(); return $return; } /** * @return array */ public function getProductRuleGroups() { if (!Validate::isLoadedObject($this) || $this->product_restriction == 0) return array(); $productRuleGroups = array(); $results = Db::getInstance()->executeS(' SELECT * FROM '._DB_PREFIX_.'cart_rule_product_rule_group prg WHERE prg.id_cart_rule = '.(int)$this->id, false); foreach ($results as $row) { if (!isset($productRuleGroups[$row['id_product_rule_group']])) $productRuleGroups[$row['id_product_rule_group']] = array('id_product_rule_group' => $row['id_product_rule_group'], 'quantity' => $row['quantity']); $productRuleGroups[$row['id_product_rule_group']]['product_rules'] = $this->getProductRules($row['id_product_rule_group']); } return $productRuleGroups; } /** * @param $id_product_rule_group * @return array ('type' => ? , 'values' => ?) */ public function getProductRules($id_product_rule_group) { if (!Validate::isLoadedObject($this) || $this->product_restriction == 0) return array(); $productRules = array(); $results = Db::getInstance()->executeS(' SELECT * FROM '._DB_PREFIX_.'cart_rule_product_rule pr LEFT JOIN '._DB_PREFIX_.'cart_rule_product_rule_value prv ON pr.id_product_rule = prv.id_product_rule WHERE pr.id_product_rule_group = '.(int)$id_product_rule_group); foreach ($results as $row) { if (!isset($productRules[$row['id_product_rule']])) $productRules[$row['id_product_rule']] = array('type' => $row['type'], 'values' => array()); $productRules[$row['id_product_rule']]['values'][] = $row['id_item']; } return $productRules; } /** * Check if this cart rule can be applied * * @param Context $context * @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, $display_error = true) { if (!CartRule::isFeatureActive()) return false; if (!$this->active) return (!$display_error) ? false : Tools::displayError('This voucher is disabled'); if (!$this->quantity) return (!$display_error) ? false : Tools::displayError('This voucher has already been used'); if (strtotime($this->date_from) > time()) return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet'); if (strtotime($this->date_to) < time()) return (!$display_error) ? false : Tools::displayError('This voucher has expired'); if ($context->cart->id_customer) { $quantityUsed = Db::getInstance()->getValue(' SELECT count(*) FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order WHERE o.id_customer = '.$context->cart->id_customer.' AND od.id_cart_rule = '.(int)$this->id.' AND '.(int)Configuration::get('PS_OS_ERROR').' != ( SELECT oh.id_order_state FROM '._DB_PREFIX_.'order_history oh WHERE oh.id_order = o.id_order ORDER BY oh.date_add DESC LIMIT 1 )'); if ($quantityUsed + 1 > $this->quantity_per_user) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)'); } // Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1) if ($this->group_restriction) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crg.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_group crg 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 (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } // Check if the customer delivery address is usable with the cart rule if ($this->country_restriction) { if (!$context->cart->id_address_delivery) return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_country crc 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 (!$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 if ($this->carrier_restriction) { if (!$context->cart->id_carrier) return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_carrier crc INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0) WHERE crc.id_cart_rule = '.(int)$this->id.' AND c.id_carrier = '.(int)$context->cart->id_carrier); if (!$id_cart_rule) 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 if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive()) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crs.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_shop crs WHERE crs.id_cart_rule = '.(int)$this->id.' AND crs.id_shop = '.(int)$context->shop->id); if (!$id_cart_rule) 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, $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 (!$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) { // Minimum amount is converted to the default currency $minimum_amount = $this->minimum_amount; if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT')) { $minimum_amount_currency = new Currency($this->minimum_amount_currency); if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0) $minimum_amount = 0; else $minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate; } $cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS); if ($this->minimum_amount_shipping) $cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING); // If a product is given for free in this rule and already in the cart, the price is subtracted if ($this->gift_product && $alreadyInCart) { $query = new DbQuery(); $query->select('id_product'); $query->from('cart_product'); $query->where('id_product = '.(int)$this->gift_product); $query->where('id_cart = '.(int)$context->cart->id); if ((int)$this->gift_product_attribute) $query->where('id_product_attribute = '.(int)$this->gift_product_attribute); if (Db::getInstance()->getValue($query)) { $ref = false; $product_price = Product::getPriceStatic( $this->gift_product, $this->minimum_amount_tax, $this->gift_product_attribute, null, null, false, true, 1, null, $context->cart->id_customer ? $context->cart->id_customer : null, $context->cart->id, (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null, $ref, true, true, $context, true ); $cartTotal -= $product_price; } } if ($cartTotal < $minimum_amount) return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher'); } // Check if the voucher is already in the cart of if a non compatible voucher is in the cart // Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them $otherCartRules = $context->cart->getCartRules(); if (count($otherCartRules)) foreach ($otherCartRules as $otherCartRule) { if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart) 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 FROM '._DB_PREFIX_.'cart_rule_combination WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].') OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')'); if (!$combinable) { $cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang); // The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested if ($cart_rule->priority <= $this->priority) return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name; // But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one else $context->cart->removeCartRule($cart_rule->id); } } } if (!$display_error) return true; } protected function checkProductRestrictions(Context $context, $return_products = false, $display_error = true) { $selectedProducts = array(); // Check if the products chosen by the customer are usable with the cart rule if ($this->product_restriction) { $productRuleGroups = $this->getProductRuleGroups(); foreach ($productRuleGroups as $id_product_rule_group => $productRuleGroup) { $eligibleProductsList = array(); foreach ($context->cart->getProducts() as $product) $eligibleProductsList[] = (int)$product['id_product'].'-'.(int)$product['id_product_attribute']; if (!count($eligibleProductsList)) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher in an empty cart'); $productRules = $this->getProductRules($id_product_rule_group); foreach ($productRules as $productRule) { switch ($productRule['type']) { case 'attributes': $cartAttributes = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product`, pac.`id_attribute`, cp.`id_product_attribute` FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON cp.id_product_attribute = pac.id_product_attribute WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').') AND cp.id_product_attribute > 0'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartAttributes as $cartAttribute) if (in_array($cartAttribute['id_attribute'], $productRule['values'])) { $countMatchingProducts += $cartAttribute['quantity']; $matchingProductsList[] = $cartAttribute['id_product'].'-'.$cartAttribute['id_product_attribute']; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; case 'products': $cartProducts = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product` FROM `'._DB_PREFIX_.'cart_product` cp WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartProducts as $cartProduct) if (in_array($cartProduct['id_product'], $productRule['values'])) { $countMatchingProducts += $cartProduct['quantity']; $matchingProductsList[] = $cartProduct['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; case 'categories': $cartCategories = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product`, cp.`id_product_attribute`, catp.`id_category` FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'category_product` catp ON cp.id_product = catp.id_product WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartCategories as $cartCategory) if (in_array($cartCategory['id_category'], $productRule['values']) // We also check that the product is not already in the matching product list, because there are doubles in the query results (when the product is in multiple categories) && !in_array($cartCategory['id_product'].'-'.$cartCategory['id_product_attribute'], $matchingProductsList)) { $countMatchingProducts += $cartCategory['quantity']; $matchingProductsList[] = $cartCategory['id_product'].'-'.$cartCategory['id_product_attribute']; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); // Attribute id is not important for this filter in the global list, so the ids are replaced by 0 foreach ($matchingProductsList as &$matchingProduct) $matchingProduct = preg_replace('/^([0-9]+)-[0-9]+$/', '$1-0', $matchingProduct); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; case 'manufacturers': $cartManufacturers = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product`, p.`id_manufacturer` FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON cp.id_product = p.id_product WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartManufacturers as $cartManufacturer) if (in_array($cartManufacturer['id_manufacturer'], $productRule['values'])) { $countMatchingProducts += $cartManufacturer['quantity']; $matchingProductsList[] = $cartManufacturer['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; case 'suppliers': $cartSuppliers = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product`, p.`id_supplier` FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON cp.id_product = p.id_product WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartSuppliers as $cartSupplier) if (in_array($cartSupplier['id_supplier'], $productRule['values'])) { $countMatchingProducts += $cartSupplier['quantity']; $matchingProductsList[] = $cartSupplier['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; } if (!count($eligibleProductsList)) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); } $selectedProducts = array_merge($selectedProducts, $eligibleProductsList); } } if ($return_products) return $selectedProducts; return (!$display_error) ? true : false; } protected static function array_uintersect($array1, $array2) { $intersection = array(); foreach ($array1 as $value1) foreach ($array2 as $value2) if (CartRule::array_uintersect_compare($value1, $value2) == 0) { $intersection[] = $value1; break 1; } return $intersection; } protected static function array_uintersect_compare($a, $ { if ($a == $ return 0; $asplit = explode('-', $a); $bsplit = explode('-', $; if ($asplit[0] == $bsplit[0] && (!(int)$asplit[1] || !(int)$bsplit[1])) return 0; return 1; } /** * The reduction value is POSITIVE * * @param bool $use_tax * @param Context $context * @param boolean $use_cache Allow using cache to avoid multiple free gift using multishipping * @return float|int|string */ public function getContextualValue($use_tax, Context $context = null, $filter = null, $package = null, $use_cache = true) { if (!CartRule::isFeatureActive()) return 0; if (!$context) $context = Context::getContext(); if (!$filter) $filter = CartRule::FILTER_ACTION_ALL; $all_products = $context->cart->getProducts(); $package_products = (is_null($package) ? $all_products : $package['products']); $reduction_value = 0; $cache_id = 'getContextualValue_'.(int)$this->id.'_'.(int)$use_tax.'_'.(int)$context->cart->id.'_'.(int)$filter; foreach ($package_products as $product) $cache_id .= '_'.(int)$product['id_product'].'_'.(int)$product['id_product_attribute']; if (Cache::isStored($cache_id)) return Cache::retrieve($cache_id); // Free shipping on selected carriers if ($this->free_shipping && in_array($filter, array(CartRule::FILTER_ACTION_ALL, CartRule::FILTER_ACTION_ALL_NOCAP, CartRule::FILTER_ACTION_SHIPPING))) { if (!$this->carrier_restriction) $reduction_value += $context->cart->getOrderTotal($use_tax, Cart::ONLY_SHIPPING, is_null($package) ? null : $package['products'], is_null($package) ? null : $package['id_carrier']); else { $data = Db::getInstance()->executeS(' SELECT crc.id_cart_rule, c.id_carrier FROM '._DB_PREFIX_.'cart_rule_carrier crc INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0) WHERE crc.id_cart_rule = '.(int)$this->id.' AND c.id_carrier = '.(int)$context->cart->id_carrier); if ($data) foreach ($data as $cart_rule) $reduction_value += $context->cart->getCarrierCost((int)$cart_rule['id_carrier'], $use_tax, $context->country); } } if (in_array($filter, array(CartRule::FILTER_ACTION_ALL, CartRule::FILTER_ACTION_ALL_NOCAP, CartRule::FILTER_ACTION_REDUCTION))) { // Discount (%) on the whole order if ($this->reduction_percent && $this->reduction_product == 0) { // Do not give a reduction on free products! $order_total = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS, $package_products); foreach ($context->cart->getCartRules(CartRule::FILTER_ACTION_GIFT) as $cart_rule) $order_total -= Tools::ps_round($cart_rule['obj']->getContextualValue($use_tax, $context, CartRule::FILTER_ACTION_GIFT, $package), 2); $reduction_value += $order_total * $this->reduction_percent / 100; } // Discount (%) on a specific product if ($this->reduction_percent && $this->reduction_product > 0) { foreach ($package_products as $product) if ($product['id_product'] == $this->reduction_product) $reduction_value += ($use_tax ? $product['total_wt'] : $product['total']) * $this->reduction_percent / 100; } // Discount (%) on the cheapest product if ($this->reduction_percent && $this->reduction_product == -1) { $minPrice = false; $cheapest_product = null; foreach ($all_products as $product) { $price = ($use_tax ? $product['price_wt'] : $product['price']); if ($price > 0 && ($minPrice === false || $minPrice > $price)) { $minPrice = $price; $cheapest_product = $product['id_product'].'-'.$product['id_product_attribute']; } } // Check if the cheapest product is in the package $in_package = false; foreach ($package_products as $product) if ($product['id_product'].'-'.$product['id_product_attribute'] == $cheapest_product || $product['id_product'].'-0' == $cheapest_product) $in_package = true; if ($in_package) $reduction_value += $minPrice * $this->reduction_percent / 100; } // Discount (%) on the selection of products if ($this->reduction_percent && $this->reduction_product == -2) { $selected_products_reduction = 0; $selected_products = $this->checkProductRestrictions($context, true); if (is_array($selected_products)) foreach ($package_products as $product) if (in_array($product['id_product'].'-'.$product['id_product_attribute'], $selected_products) || in_array($product['id_product'].'-0', $selected_products)) { $price = ($use_tax ? $product['price_wt'] : $product['price']); $selected_products_reduction += $price * $product['cart_quantity']; } $reduction_value += $selected_products_reduction * $this->reduction_percent / 100; } // Discount (¤) if ($this->reduction_amount) { $prorata = 1; if (!is_null($package) && count($all_products)) { $total_products = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS); if ($total_products) $prorata = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS, $package['products']) / $total_products; } $reduction_amount = $this->reduction_amount; // If we need to convert the voucher value to the cart currency if ($this->reduction_currency != $context->currency->id) { $voucherCurrency = new Currency($this->reduction_currency); // First we convert the voucher value to the default currency if ($reduction_amount == 0 || $voucherCurrency->conversion_rate == 0) $reduction_amount = 0; else $reduction_amount /= $voucherCurrency->conversion_rate; // Then we convert the voucher value in the default currency into the cart currency $reduction_amount *= $context->currency->conversion_rate; $reduction_amount = Tools::ps_round($reduction_amount); } // If it has the same tax application that you need, then it's the right value, whatever the product! if ($this->reduction_tax == $use_tax) { // The reduction cannot exceed the products total, except when we do not want it to be limited (for the partial use calculation) if ($filter != CartRule::FILTER_ACTION_ALL_NOCAP) { $cart_amount = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS); $reduction_amount = min($reduction_amount, $cart_amount); } $reduction_value += $prorata * $reduction_amount; } else { if ($this->reduction_product > 0) { foreach ($context->cart->getProducts() as $product) if ($product['id_product'] == $this->reduction_product) { $product_price_ti = $product['price_wt']; $product_price_te = $product['price']; $product_vat_amount = $product_price_ti - $product_price_te; if ($product_vat_amount == 0 || $product_price_te == 0) $product_vat_rate = 0; else $product_vat_rate = $product_vat_amount / $product_price_te; if ($this->reduction_tax && !$use_tax) $reduction_value += $prorata * $reduction_amount / (1 + $product_vat_rate); elseif (!$this->reduction_tax && $use_tax) $reduction_value += $prorata * $reduction_amount * (1 + $product_vat_rate); } } // Discount (¤) on the whole order elseif ($this->reduction_product == 0) { $cart_amount_ti = $context->cart->getOrderTotal(true, Cart::ONLY_PRODUCTS); $cart_amount_te = $context->cart->getOrderTotal(false, Cart::ONLY_PRODUCTS); // The reduction cannot exceed the products total, except when we do not want it to be limited (for the partial use calculation) if ($filter != CartRule::FILTER_ACTION_ALL_NOCAP) $reduction_amount = min($reduction_amount, $this->reduction_tax ? $cart_amount_ti : $cart_amount_te); $cart_vat_amount = $cart_amount_ti - $cart_amount_te; if ($cart_vat_amount == 0 || $cart_amount_te == 0) $cart_average_vat_rate = 0; else $cart_average_vat_rate = Tools::ps_round($cart_vat_amount / $cart_amount_te, 3); if ($this->reduction_tax && !$use_tax) $reduction_value += $prorata * $reduction_amount / (1 + $cart_average_vat_rate); elseif (!$this->reduction_tax && $use_tax) $reduction_value += $prorata * $reduction_amount * (1 + $cart_average_vat_rate); } /* * 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) */ } } } // Free gift if ((int)$this->gift_product && in_array($filter, array(CartRule::FILTER_ACTION_ALL, CartRule::FILTER_ACTION_ALL_NOCAP, CartRule::FILTER_ACTION_GIFT))) { $id_address = (is_null($package) ? 0 : $package['id_address']); foreach ($package_products as $product) if ($product['id_product'] == $this->gift_product && ($product['id_product_attribute'] == $this->gift_product_attribute || !(int)$this->gift_product_attribute)) { // The free gift coupon must be applied to one product only (needed for multi-shipping which manage multiple product lists) if (!isset(CartRule::$only_one_gift[$this->id.'-'.$this->gift_product]) || CartRule::$only_one_gift[$this->id.'-'.$this->gift_product] == $id_address || CartRule::$only_one_gift[$this->id.'-'.$this->gift_product] == 0 || $id_address == 0 || !$use_cache) { $reduction_value += ($use_tax ? $product['price_wt'] : $product['price']); if ($use_cache && (!isset(CartRule::$only_one_gift[$this->id.'-'.$this->gift_product]) || CartRule::$only_one_gift[$this->id.'-'.$this->gift_product] == 0)) CartRule::$only_one_gift[$this->id.'-'.$this->gift_product] = $id_address; break; } } } Cache::store($cache_id, $reduction_value); return $reduction_value; } /** * Make sure caches are empty * Must be called before calling multiple time getContextualValue() */ public static function cleanCache() { self::$only_one_gift = array(); } protected function getCartRuleCombinations() { $array = array(); $array['selected'] = Db::getInstance()->executeS(' SELECT cr.*, crl.*, 1 as selected FROM '._DB_PREFIX_.'cart_rule cr LEFT JOIN '._DB_PREFIX_.'cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = '.(int)Context::getContext()->language->id.') WHERE cr.id_cart_rule != '.(int)$this->id.' AND ( cr.cart_rule_restriction = 0 OR cr.id_cart_rule IN ( SELECT IF(id_cart_rule_1 = '.(int)$this->id.', id_cart_rule_2, id_cart_rule_1) FROM '._DB_PREFIX_.'cart_rule_combination WHERE '.(int)$this->id.' = id_cart_rule_1 OR '.(int)$this->id.' = id_cart_rule_2 ) )'); $array['unselected'] = Db::getInstance()->executeS(' SELECT cr.*, crl.*, 1 as selected FROM '._DB_PREFIX_.'cart_rule cr LEFT JOIN '._DB_PREFIX_.'cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = '.(int)Context::getContext()->language->id.') WHERE cr.cart_rule_restriction = 1 AND cr.id_cart_rule != '.(int)$this->id.' AND cr.id_cart_rule NOT IN ( SELECT IF(id_cart_rule_1 = '.(int)$this->id.', id_cart_rule_2, id_cart_rule_1) FROM '._DB_PREFIX_.'cart_rule_combination WHERE '.(int)$this->id.' = id_cart_rule_1 OR '.(int)$this->id.' = id_cart_rule_2 )'); return $array; } public function getAssociatedRestrictions($type, $active_only, $i18n) { $array = array('selected' => array(), 'unselected' => array()); if (!in_array($type, array('country', 'carrier', 'group', 'cart_rule', 'shop'))) return false; $shop_list = ''; if ($type == 'shop') { $shops = Context::getContext()->employee->getAssociatedShops(); if (count($shops)) $shop_list = ' AND t.id_shop IN ('.implode(array_map('intval', $shops), ',').') '; } if (!Validate::isLoadedObject($this) OR $this->{$type.'_restriction'} == 0) { $array['selected'] = Db::getInstance()->executeS(' SELECT t.*'.($i18n ? ', tl.*' : '').', 1 as selected FROM `'._DB_PREFIX_.$type.'` t '.($i18n ? 'LEFT JOIN `'._DB_PREFIX_.$type.'_lang` tl ON (t.id_'.$type.' = tl.id_'.$type.' AND tl.id_lang = '.(int)Context::getContext()->language->id.')' : '').' WHERE 1 '.($active_only ? 'AND t.active = 1' : '').' '.(in_array($type, array('carrier', 'shop')) ? ' AND t.deleted = 0' : '').' '.($type == 'cart_rule' ? 'AND t.id_cart_rule != '.(int)$this->id : ''). $shop_list. ' ORDER BY name ASC'); } else { if ($type == 'cart_rule') $array = $this->getCartRuleCombinations(); else { $resource = Db::getInstance()->query(' SELECT t.*'.($i18n ? ', tl.*' : '').', IF(crt.id_'.$type.' IS NULL, 0, 1) as selected FROM `'._DB_PREFIX_.$type.'` t '.($i18n ? 'LEFT JOIN `'._DB_PREFIX_.$type.'_lang` tl ON (t.id_'.$type.' = tl.id_'.$type.' AND tl.id_lang = '.(int)Context::getContext()->language->id.')' : '').' LEFT JOIN (SELECT id_'.$type.' FROM `'._DB_PREFIX_.'cart_rule_'.$type.'` WHERE id_cart_rule = '.(int)$this->id.') crt ON t.id_'.($type == 'carrier' ? 'reference' : $type).' = crt.id_'.$type.' WHERE 1 '.($active_only ? ' AND t.active = 1' : ''). $shop_list .(in_array($type, array('carrier', 'shop')) ? ' AND t.deleted = 0' : ''). ' ORDER BY name ASC', false); while ($row = Db::getInstance()->nextRow($resource)) $array[($row['selected'] || $this->{$type.'_restriction'} == 0) ? 'selected' : 'unselected'][] = $row; } } return $array; } public static function autoRemoveFromCart($context = null) { if (!$context) $context = Context::getContext(); if (!CartRule::isFeatureActive() || !Validate::isLoadedObject($context->cart)) return array(); $errors = array(); foreach ($context->cart->getCartRules() as $cart_rule) { if ($error = $cart_rule['obj']->checkValidity($context, true)) { $context->cart->removeCartRule($cart_rule['obj']->id); $context->cart->update(); $errors[] = $error; } } return $errors; } /** * @static * @param Context|null $context * @return mixed */ public static function autoAddToCart(Context $context = null) { if ($context === null) $context = Context::getContext(); if (!CartRule::isFeatureActive() || !Validate::isLoadedObject($context->cart)) return; $sql = ' SELECT cr.* FROM '._DB_PREFIX_.'cart_rule cr LEFT JOIN '._DB_PREFIX_.'cart_rule_shop crs ON cr.id_cart_rule = crs.id_cart_rule LEFT JOIN '._DB_PREFIX_.'cart_rule_carrier crca ON cr.id_cart_rule = crca.id_cart_rule '.($context->cart->id_carrier ? 'LEFT JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crca.id_carrier AND c.deleted = 0)' : '').' LEFT JOIN '._DB_PREFIX_.'cart_rule_country crco ON cr.id_cart_rule = crco.id_cart_rule WHERE cr.active = 1 AND cr.code = "" 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_customer = 0 '.($context->customer->id ? 'OR cr.id_customer = '.(int)$context->cart->id_customer : '').' ) AND ( cr.carrier_restriction = 0 '.($context->cart->id_carrier ? 'OR c.id_carrier = '.(int)$context->cart->id_carrier : '').' ) AND ( cr.shop_restriction = 0 '.((Shop::isFeatureActive() && $context->shop->id) ? 'OR crs.id_shop = '.(int)$context->shop->id : '').' ) AND ( cr.group_restriction = 0 '.($context->customer->id ? 'OR 0 < ( SELECT cg.id_group FROM '._DB_PREFIX_.'customer_group cg LEFT JOIN '._DB_PREFIX_.'cart_rule_group crg ON (cg.id_group = crg.id_group AND cg.id_group = '.(int)$context->customer->id_default_group.') WHERE cr.id_cart_rule = crg.id_cart_rule AND cg.id_customer = '.(int)$context->customer->id.' LIMIT 1 )' : '').' ) AND ( cr.reduction_product <= 0 OR cr.reduction_product IN ( SELECT id_product FROM '._DB_PREFIX_.'cart_product WHERE id_cart = '.(int)$context->cart->id.' ) ) AND cr.id_cart_rule NOT IN (SELECT id_cart_rule FROM '._DB_PREFIX_.'cart_cart_rule WHERE id_cart = '.(int)$context->cart->id.') ORDER BY priority'; $result = Db::getInstance()->executeS($sql); if ($result) { $cart_rules = ObjectModel::hydrateCollection('CartRule', $result); if ($cart_rules) foreach ($cart_rules as $cart_rule) if ($cart_rule->public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true) { if (!CartRule::isFeatureActive()) return false; si (! $ this -> actif ) retour (! $ display_error ) ? faux : Outils :: DisplayError ( «Ce bon est désactivé ' ); si (! $ this -> quantité ) retour (! $ display_error ) ? faux : Outils :: DisplayError ( «Ce bon a déjà été utilisée ' ); si ( strtotime ( $ this -> date_from ) > temps ()) retour (! $ display_error ) ? faux : Outils :: DisplayError ( «Ce bon n'est pas encore valide ' ); si ( strtotime ( $ this -> date_to ) < temps ()) retour (! $ display_error ) ? faux : Outils :: DisplayError ( 'Cette réduction a expiré' ); coupon n \ 'est cumulative sur les produits avec réduction ou marqués comme disponibles à la vente' ); } si ( $ context -> panier -> id_customer ) { $ quantityUsed = Db :: getInstance () -> getValue ( ' SELECT COUNT (*) FROM ' . _DB_PREFIX_ . 'ordres o LEFT JOIN . _DB_PREFIX_ . 'order_cart_rule od ON o.id_order = od.id_order OÙ o.id_customer = ' . $ context -> panier -> id_customer . ' ET od.id_cart_rule = ' (. int ) $ this -> id . ' ET » . ( int ) Configuration :: obtenir ( 'PS_OS_ERROR' ). ' ! = ( SELECT oh.id_order_state FROM ' . _DB_PREFIX_ . «oh order_history OÙ oh.id_order = o.id_order ORDER BY DESC oh.date_add LIMIT 1 ne peut pas utiliser plus ce bon (limite d'utilisation atteint) ' ); } / / Obtenir une intersection des groupes de clients et les groupes de règles panier (si le client n'est pas connecté, le groupe 1 par défaut) si ( $ this -> group_restriction ) { id_cart_rule $ = ( int ) Db :: getInstance () -> getValue ( ' SELECT crg.id_cart_rule FROM ' . _DB_PREFIX_ . 'cart_rule_group CRG OÙ crg.id_cart_rule = ' (. int ) $ this -> id . ' ET crg.id_group ' (. $ context -> panier -> id_customer ? 'IN (SELECT cg.id_group FROM' . _DB_PREFIX_ . 'customer_group cg OÙ cg.id_customer =' (. int ) $ context -> panier -> id_customer . ')' : '= 1' )); si (! $ id_cart_rule ) retour (! $ display_error ) ? faux : Outils :: DisplayError ( «Vous ne pouvez pas utiliser ce bon ' ); } / / Vérifier si l'adresse de livraison du client est utilisable avec le panier doit choisir une adresse de livraison avant d'appliquer ce bon à votre commande ' ); id_cart_rule $ = ( int ) Db :: getInstance () -> getValue ( ' SELECT crc.id_cart_rule FROM ' . _DB_PREFIX_ . 'cart_rule_country CRC OÙ crc.id_cart_rule = ' (. int ) $ this -> id . ' ET crc.id_country = ('SELECT FROM a.id_country . _DB_PREFIX_ . »répondent à un WHERE a.id_address = ' (. int ) $ context -> panier -> id_address_delivery . 'LIMIT 1)' ); si (! $ id_cart_rule ) retour (! $ display_error ) ? faux : Outils :: DisplayError ( «Vous ne pouvez pas utiliser ce coupon dans votre pays de livraison ' ); } / / Vérifier si le transporteur choisi par le client est utilisable avec le panier doit choisir un transporteur avant d'appliquer ce bon à votre commande ' ); $ id_cart_rule = ( int ) Db :: getInstance () -> getValue ( ' SELECT crc.id_cart_rule FROM ' . _DB_PREFIX_ . 'cart_rule_carrier CRC INNER JOIN . _DB_PREFIX_ . «transporteur c ON (c.id_reference = crc.id_carrier ET c.deleted = 0) OÙ crc.id_cart_rule = ' (. int ) $ this -> id . ' ET c.id_carrier = ne peuvent pas utiliser ce coupon avec ce transporteur ' ); } / / Vérifier si le panier règles appliy la boutique parcouru par l' SELECT crs.id_cart_rule FROM ' . _DB_PREFIX_ . 'cart_rule_shop crs OÙ crs.id_cart_rule = ' (. int ) $ this -> id . ' ET crs.id_shop = ' (. int ) $ context -> boutique -> id ); si (! $ id_cart_rule ) retour (! $ display_error ) ? faux : Outils :: DisplayError ( «Vous ne pouvez pas utiliser ce bon ' ); } / / Vérifier si les produits choisis par le client sont utilisables avec le panier / / Vérifier si le panier règle n'est utilisable que par un client spécifique, et si le client actuel est le droit ne peuvent pas utiliser ce bon ' ). ' - ' . Outils :: DisplayError ( «S'il vous plaît Connectez ' )); retour (! $ display_error ) ? faux : Outils :: DisplayError ( «Vous ne pouvez pas utiliser ce bon ' ); } si ( $ this -> minimum_amount ) { / / Montant minimal est converti en défaut $cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS); if ($this->minimum_amount_shipping) $cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING); / / Si un produit est donné gratuitement à cette règle et déjà dans le panier, le prix est soustraite si ( $ this -> gift_product && $ alreadyInCart ) { $ query = nouveau DBQuery (); $ Query -> select ( 'id_product' ); $ query -> à partir de ( 'cart_product' ); $ query -> où ( 'id_product =' . ( int ) $ this -> gift_product ); requête $ -> où ( ' id_cart = ' (. int ) $ context -> panier -> id ); si (( int ) $ this -> gift_product_attribute ) $ query -> où ( 'id_product_attribute =' (. int ) $ this -> gift_product_attribute ); if (Db::getInstance()->getValue($query)) { $ref = false; $product_price = Product::getPriceStatic( $this->gift_product, $this->minimum_amount_tax, $this->gift_product_attribute, null, null, false, true, 1, null, $context->cart->id_customer ? $context->cart->id_customer : null, $context->cart->id, (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null, $ref, true, true, $context, true ); $cartTotal -= $product_price; } } si ( $ cartTotal < $ minimum_amount ) retour (! $ display_error ) ? faux : Outils :: DisplayError ( «Vous n'avez pas atteint le montant minimum requis pour utiliser ce bon ' ); } / / Vérifier si le coupon est déjà dans le panier de si un bon de réduction non compatible est dans le panier Note / / Important: ce doit être le dernier chèque, car si le panier règle testée a la priorité sur un combinable un non dans le panier, nous allons passer coupon est déjà dans votre SELECT id_cart_rule_1 FROM ' . _DB_PREFIX_ . 'cart_rule_combination WHERE (id_cart_rule_1 = ' (. int ) $ this -> id . 'ET id_cart_rule_2 = . ( int ) $ otherCartRule [ 'id_cart_rule' ]. ') OR (id_cart_rule_2 = ' (. int ) $ this -> id . 'ET id_cart_rule_1 = Les règles panier ne sont pas cumulables et le panier règle actuellement dans le panier a la priorité sur celui bon n'est pas cumulable avec un autre bon déjà dans votre panier: ' ). ' ' . $ cart_rule -> nom ; / / Mais si le panier règle qui est testé est prioritaire sur celui de la charrette, nous enlever celui dans le panier et maintenir cette nouvelle autre $ context -> panier -> removeCartRule ( $ cart_rule -> id ); } } } si (! $ display_error ) retourner vrai ; } /** * @static * @param $name * @param $id_lang * @return array */ public static function getCartsRuleByCode($name, $id_lang) { return Db::getInstance()->executeS(' SELECT cr.*, crl.* FROM '._DB_PREFIX_.'cart_rule cr LEFT JOIN '._DB_PREFIX_.'cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = '.(int)$id_lang.') WHERE code LIKE \'%'.pSQL($name).'%\' '); } } Link to comment Share on other sites More sharing options...
cockpitinferno Posted October 3, 2013 Share Posted October 3, 2013 ben c'est assez simple tu copie "public function checkValidity" tu fais ctrl+f une petite recherche et c'est bon. on va pas tout macher le boulot non plus, c'est déjà cool d'avoir qqun qui a pensé à nous. je l'ai trouvé en 5s dans ton fichier l'endroit ou faut faire la modif. un petit effort de relecture de ce qu'a écrit manuel corbet et je suis sure que tu vas t'en sortir. Link to comment Share on other sites More sharing options...
Lgfx13 Posted October 4, 2013 Share Posted October 4, 2013 Ca marche ici en 1.5.3, merci Manuel Link to comment Share on other sites More sharing options...
Manuel Corbet Posted October 4, 2013 Share Posted October 4, 2013 Pas de soucis ça me fait plaisir, bon weekend à tous le monde ! Link to comment Share on other sites More sharing options...
Manuel Corbet Posted October 4, 2013 Share Posted October 4, 2013 Sinon comme dit cockpitinferno, laurent65200 tu as juste à copier le contenu de ma fonction checkValidity et le coller dans la tienne. Link to comment Share on other sites More sharing options...
Lgfx13 Posted October 4, 2013 Share Posted October 4, 2013 (edited) J'ai répondu à chaud, je te remercie encore car ça fonctionne mais par contre, si il y a juste un article en promo dans le panier, le code ne fonctionne pas ? Si tu as une soluce, je suis preneuse. très bon weekend, Edited October 4, 2013 by Lgfx13 (see edit history) Link to comment Share on other sites More sharing options...
laurent65200 Posted October 4, 2013 Share Posted October 4, 2013 merci mais je vais rester comme cela car a chaque fois que j'ai touché a un script j'ai tout planté Link to comment Share on other sites More sharing options...
cockpitinferno Posted October 7, 2013 Share Posted October 7, 2013 (edited) laurent pourquoi tu fait pas la modif en local, c'est la "procédure standard" tu n'apprendras jamais à te débrouiller seul (ce qu'il faut apprendre avec presta sinon tu vas galérer) si tu n'essai pas toi même de faire les modifs. @lgfx: c'est déjà le cas dans la v1.4 le fait que quand il y a un produit en promo ca désactive le bon et effectivement le mieux serait d'appliquer le bon seulement sur le produit qui n'est pas en promo (si les autres conditions sont réunies bien sur) mais il semblerait que ca ne soit pas à l'ordre du jour de la team enfin, si manuel sait comment faire, on sait jamais... Edited October 7, 2013 by cockpitinferno (see edit history) Link to comment Share on other sites More sharing options...
Lgfx13 Posted October 9, 2013 Share Posted October 9, 2013 Merci pour cette précision cockpitinferno, à vrai dire, en 1.4, je n'ai jamais eu besoin de faire des bon de réduction, du coup je découvre. Mais si il y avait une solution concernant ce problème, ça serait pas mal En tous les cas, 10000 mercis à Manuel car ça faisait un moment que je m'arrachais les cheveux avec ce module. Link to comment Share on other sites More sharing options...
laurent65200 Posted October 21, 2013 Share Posted October 21, 2013 Cela donne pour l'ensemble de la méthode checkValidity public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true) { if (!CartRule::isFeatureActive()) return false; if (!$this->active) return (!$display_error) ? false : Tools::displayError('This voucher is disabled'); if (!$this->quantity) return (!$display_error) ? false : Tools::displayError('This voucher has already been used'); if (strtotime($this->date_from) > time()) return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet'); if (strtotime($this->date_to) < time()) return (!$display_error) ? false : Tools::displayError('This voucher has expired'); $products = $context->cart->getProducts(); $product_on_sale = false; foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; } if ($product_on_sale) return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); if ($context->cart->id_customer) { $quantityUsed = Db::getInstance()->getValue(' SELECT count(*) FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order WHERE o.id_customer = '.$context->cart->id_customer.' AND od.id_cart_rule = '.(int)$this->id.' AND '.(int)Configuration::get('PS_OS_ERROR').' != ( SELECT oh.id_order_state FROM '._DB_PREFIX_.'order_history oh WHERE oh.id_order = o.id_order ORDER BY oh.date_add DESC LIMIT 1 )'); if ($quantityUsed + 1 > $this->quantity_per_user) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)'); } // Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1) if ($this->group_restriction) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crg.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_group crg 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 (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } // Check if the customer delivery address is usable with the cart rule if ($this->country_restriction) { if (!$context->cart->id_address_delivery) return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_country crc 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 (!$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 if ($this->carrier_restriction) { if (!$context->cart->id_carrier) return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_carrier crc INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0) WHERE crc.id_cart_rule = '.(int)$this->id.' AND c.id_carrier = '.(int)$context->cart->id_carrier); if (!$id_cart_rule) 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 if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive()) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crs.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_shop crs WHERE crs.id_cart_rule = '.(int)$this->id.' AND crs.id_shop = '.(int)$context->shop->id); if (!$id_cart_rule) 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, $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 (!$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) { // Minimum amount is converted to the default currency $minimum_amount = $this->minimum_amount; if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT')) { $minimum_amount_currency = new Currency($this->minimum_amount_currency); if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0) $minimum_amount = 0; else $minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate; } $cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS); if ($this->minimum_amount_shipping) $cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING); // If a product is given for free in this rule and already in the cart, the price is subtracted if ($this->gift_product && $alreadyInCart) { $query = new DbQuery(); $query->select('id_product'); $query->from('cart_product'); $query->where('id_product = '.(int)$this->gift_product); $query->where('id_cart = '.(int)$context->cart->id); if ((int)$this->gift_product_attribute) $query->where('id_product_attribute = '.(int)$this->gift_product_attribute); if (Db::getInstance()->getValue($query)) { $ref = false; $product_price = Product::getPriceStatic( $this->gift_product, $this->minimum_amount_tax, $this->gift_product_attribute, null, null, false, true, 1, null, $context->cart->id_customer ? $context->cart->id_customer : null, $context->cart->id, (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null, $ref, true, true, $context, true ); $cartTotal -= $product_price; } } if ($cartTotal < $minimum_amount) return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher'); } // Check if the voucher is already in the cart of if a non compatible voucher is in the cart // Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them $otherCartRules = $context->cart->getCartRules(); if (count($otherCartRules)) foreach ($otherCartRules as $otherCartRule) { if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart) 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 FROM '._DB_PREFIX_.'cart_rule_combination WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].') OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')'); if (!$combinable) { $cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang); // The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested if ($cart_rule->priority <= $this->priority) return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name; // But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one else $context->cart->removeCartRule($cart_rule->id); } } } if (!$display_error) return true; } PS : pensez à traduire le message dans les traductions des messages d'erreur ! Cordialement, ok merci j'ai réussi cela fonctionne par contre une fois le bon de parrainage créé il faut que je passe par les règles pour enlever le cumul est t il possible que des la création d'un bon de parrainage celui ci ne soit pas cumulable sans passer par les règles voici mon fichier merci a vous de me dire. **************** <?php /* * 2007-2013 PrestaShop * * 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: * http://opensource.org/licenses/osl-3.0.php * 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 502immediately. * * 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 http://www.prestashop.com for more information. * * @author PrestaShop SA <[email protected]> * @copyright 2007-2013 PrestaShop SA * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ class CartRuleCore extends ObjectModel { /* Filters used when retrieving the cart rules applied to a cart of when calculating the value of a reduction */ const FILTER_ACTION_ALL = 1; const FILTER_ACTION_SHIPPING = 2; const FILTER_ACTION_REDUCTION = 3; const FILTER_ACTION_GIFT = 4; const FILTER_ACTION_ALL_NOCAP = 5; const BO_ORDER_CODE_PREFIX = 'BO_ORDER_'; /* This variable controls that a free gift is offered only once, even when multi-shippping is activated and the same product is delivered in both addresses */ protected static $only_one_gift = array(); public $id; public $name; public $id_customer; public $date_from; public $date_to; public $description; public $quantity = 1; public $quantity_per_user = 1; public $priority = 1; public $partial_use = 1; public $code; public $minimum_amount; public $minimum_amount_tax; public $minimum_amount_currency; public $minimum_amount_shipping; public $country_restriction; public $carrier_restriction; public $group_restriction; public $cart_rule_restriction; public $product_restriction; public $shop_restriction; public $free_shipping; public $reduction_percent; public $reduction_amount; public $reduction_tax; public $reduction_currency; public $reduction_product; public $gift_product; public $gift_product_attribute; public $highlight; public $active = 1; public $date_add; public $date_upd; /** * @see ObjectModel::$definition */ public static $definition = array( 'table' => 'cart_rule', 'primary' => 'id_cart_rule', 'multilang' => true, 'fields' => array( 'id_customer' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'), 'date_from' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => true), 'date_to' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => true), 'description' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 65534), 'quantity' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'quantity_per_user' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'priority' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'partial_use' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'code' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 254), 'minimum_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'), 'minimum_amount_tax' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'minimum_amount_currency' =>array('type' => self::TYPE_INT, 'validate' => 'isInt'), 'minimum_amount_shipping' =>array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'country_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'carrier_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'group_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'cart_rule_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'product_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'shop_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'free_shipping' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'reduction_percent' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPercentage'), 'reduction_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'), 'reduction_tax' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'reduction_currency' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'), 'reduction_product' => array('type' => self::TYPE_INT, 'validate' => 'isInt'), 'gift_product' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'), 'gift_product_attribute' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'), 'highlight' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'), 'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'), // Lang fields 'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCleanHtml', 'required' => true, 'size' => 254), ), ); /** * @see ObjectModel::add() */ public function add($autodate = true, $null_values = false) { if (!parent::add($autodate, $null_values)) return false; Configuration::updateGlobalValue('PS_CART_RULE_FEATURE_ACTIVE', '1'); return true; } public function update($null_values = false) { Cache::clean('getContextualValue_'.$this->id.'_*'); return parent::update($null_values); } /** * @see ObjectModel::delete() */ public function delete() { if (!parent::delete()) return false; Configuration::updateGlobalValue('PS_CART_RULE_FEATURE_ACTIVE', CartRule::isCurrentlyUsed($this->def['table'], true)); $r = Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_cart_rule` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_carrier` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_shop` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_group` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_country` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_combination` WHERE `id_cart_rule_1` = '.(int)$this->id.' OR `id_cart_rule_2` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_group` WHERE `id_cart_rule` = '.(int)$this->id); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule` WHERE `id_product_rule_group` NOT IN (SELECT `id_product_rule_group` FROM `'._DB_PREFIX_.'cart_rule_product_rule_group`)'); $r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_value` WHERE `id_product_rule` NOT IN (SELECT `id_product_rule` FROM `'._DB_PREFIX_.'cart_rule_product_rule`)'); return $r; } /** * Copy conditions from one cart rule to an other * * @static * @param int $id_cart_rule_source * @param int $id_cart_rule_destination */ public static function copyConditions($id_cart_rule_source, $id_cart_rule_destination) { Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_shop` (`id_cart_rule`, `id_shop`) (SELECT '.(int)$id_cart_rule_destination.', id_shop FROM `'._DB_PREFIX_.'cart_rule_shop` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_carrier` (`id_cart_rule`, `id_carrier`) (SELECT '.(int)$id_cart_rule_destination.', id_carrier FROM `'._DB_PREFIX_.'cart_rule_carrier` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_group` (`id_cart_rule`, `id_group`) (SELECT '.(int)$id_cart_rule_destination.', id_group FROM `'._DB_PREFIX_.'cart_rule_group` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_country` (`id_cart_rule`, `id_country`) (SELECT '.(int)$id_cart_rule_destination.', id_country FROM `'._DB_PREFIX_.'cart_rule_country` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'cart_rule_combination` (`id_cart_rule_1`, `id_cart_rule_2`) (SELECT '.(int)$id_cart_rule_destination.', IF(id_cart_rule_1 != '.(int)$id_cart_rule_source.', id_cart_rule_1, id_cart_rule_2) FROM `'._DB_PREFIX_.'cart_rule_combination` WHERE `id_cart_rule_1` = '.(int)$id_cart_rule_source.' OR `id_cart_rule_2` = '.(int)$id_cart_rule_source.')'); // Todo : should be changed soon, be must be copied too // Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule` WHERE `id_cart_rule` = '.(int)$this->id); // Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_value` WHERE `id_product_rule` NOT IN (SELECT `id_product_rule` FROM `'._DB_PREFIX_.'cart_rule_product_rule`)'); } /** * Retrieves the id associated to the given code * * @static * @param string $code * @return int|bool */ public static function getIdByCode($code) { if (!Validate::isCleanHtml($code)) return false; return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('SELECT `id_cart_rule` FROM `'._DB_PREFIX_.'cart_rule` WHERE `code` = \''.pSQL($code).'\''); } /** * @static * @param $id_lang * @param $id_customer * @param bool $active * @param bool $includeGeneric * @param bool $inStock * @param Cart|null $cart * @return array */ public static function getCustomerCartRules($id_lang, $id_customer, $active = false, $includeGeneric = true, $inStock = false, Cart $cart = null) { if (!CartRule::isFeatureActive()) return array(); $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT * FROM `'._DB_PREFIX_.'cart_rule` cr LEFT JOIN `'._DB_PREFIX_.'cart_rule_lang` crl ON (cr.`id_cart_rule` = crl.`id_cart_rule` AND crl.`id_lang` = '.(int)$id_lang.') WHERE ( cr.`id_customer` = '.(int)$id_customer.' OR cr.group_restriction = 1 '.($includeGeneric ? 'OR cr.`id_customer` = 0' : '').' ) AND cr.date_from < "'.date('Y-m-d H:i:s').'" AND cr.date_to > "'.date('Y-m-d H:i:s').'" '.($active ? 'AND cr.`active` = 1' : '').' '.($inStock ? 'AND cr.`quantity` > 0' : '')); // Remove cart rule that does not match the customer groups $customerGroups = Customer::getGroupsStatic($id_customer); foreach ($result as $key => $cart_rule) if ($cart_rule['group_restriction']) { $cartRuleGroups = Db::getInstance()->executeS('SELECT id_group FROM '._DB_PREFIX_.'cart_rule_group WHERE id_cart_rule = '.(int)$cart_rule['id_cart_rule']); foreach ($cartRuleGroups as $cartRuleGroup) if (in_array($cartRuleGroup['id_group'], $customerGroups)) continue 2; unset($result[$key]); } foreach ($result as &$cart_rule) if ($cart_rule['quantity_per_user']) { $quantity_used = Order::getDiscountsCustomer((int)$id_customer, (int)$cart_rule['id_cart_rule']); if (isset($cart) && isset($cart->id)) $quantity_used += $cart->getDiscountsCustomer((int)$cart_rule['id_cart_rule']); $cart_rule['quantity_for_user'] = $cart_rule['quantity_per_user'] - $quantity_used; } else $cart_rule['quantity_for_user'] = 0; // Retrocompatibility with 1.4 discounts foreach ($result as &$cart_rule) { $cart_rule['value'] = 0; $cart_rule['minimal'] = $cart_rule['minimum_amount']; $cart_rule['cumulable'] = !$cart_rule['cart_rule_restriction']; $cart_rule['id_discount_type'] = false; if ($cart_rule['free_shipping']) $cart_rule['id_discount_type'] = Discount::FREE_SHIPPING; elseif ($cart_rule['reduction_percent'] > 0) { $cart_rule['id_discount_type'] = Discount::PERCENT; $cart_rule['value'] = $cart_rule['reduction_percent']; } elseif ($cart_rule['reduction_amount'] > 0) { $cart_rule['id_discount_type'] = Discount::AMOUNT; $cart_rule['value'] = $cart_rule['reduction_amount']; } } return $result; } /** * @param $id_customer * @return bool */ public function usedByCustomer($id_customer) { return (bool)Db::getInstance()->getValue(' SELECT id_cart_rule FROM `'._DB_PREFIX_.'order_cart_rule` ocr LEFT JOIN `'._DB_PREFIX_.'orders` o ON ocr.`id_order` = o.`id_order` WHERE ocr.`id_cart_rule` = '.(int)$this->id.' AND o.`id_customer` = '.(int)$id_customer); } /** * @static * @param $name * @return bool */ public static function cartRuleExists($name) { if (!CartRule::isFeatureActive()) return false; return (bool)Db::getInstance()->getValue(' SELECT `id_cart_rule` FROM `'._DB_PREFIX_.'cart_rule` WHERE `code` = \''.pSQL($name).'\''); } /** * @static * @param $id_customer * @return bool */ public static function deleteByIdCustomer($id_customer) { $return = true; $cart_rules = new Collection('CartRule'); $cart_rules->where('id_customer', '=', $id_customer); foreach ($cart_rules as $cart_rule) $return &= $cart_rule->delete(); return $return; } /** * @return array */ public function getProductRuleGroups() { if (!Validate::isLoadedObject($this) || $this->product_restriction == 0) return array(); $productRuleGroups = array(); $results = Db::getInstance()->executeS(' SELECT * FROM '._DB_PREFIX_.'cart_rule_product_rule_group prg WHERE prg.id_cart_rule = '.(int)$this->id, false); foreach ($results as $row) { if (!isset($productRuleGroups[$row['id_product_rule_group']])) $productRuleGroups[$row['id_product_rule_group']] = array('id_product_rule_group' => $row['id_product_rule_group'], 'quantity' => $row['quantity']); $productRuleGroups[$row['id_product_rule_group']]['product_rules'] = $this->getProductRules($row['id_product_rule_group']); } return $productRuleGroups; } /** * @param $id_product_rule_group * @return array ('type' => ? , 'values' => ?) */ public function getProductRules($id_product_rule_group) { if (!Validate::isLoadedObject($this) || $this->product_restriction == 0) return array(); $productRules = array(); $results = Db::getInstance()->executeS(' SELECT * FROM '._DB_PREFIX_.'cart_rule_product_rule pr LEFT JOIN '._DB_PREFIX_.'cart_rule_product_rule_value prv ON pr.id_product_rule = prv.id_product_rule WHERE pr.id_product_rule_group = '.(int)$id_product_rule_group); foreach ($results as $row) { if (!isset($productRules[$row['id_product_rule']])) $productRules[$row['id_product_rule']] = array('type' => $row['type'], 'values' => array()); $productRules[$row['id_product_rule']]['values'][] = $row['id_item']; } return $productRules; } /** * Check if this cart rule can be applied * * @param Context $context * @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, $display_error = true) { if (!CartRule::isFeatureActive()) return false; if (!$this->active) return (!$display_error) ? false : Tools::displayError('This voucher is disabled'); if (!$this->quantity) return (!$display_error) ? false : Tools::displayError('This voucher has already been used'); if (strtotime($this->date_from) > time()) return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet'); if (strtotime($this->date_to) < time()) return (!$display_error) ? false : Tools::displayError('This voucher has expired'); $products = $context->cart->getProducts(); $product_on_sale = false; foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; } if ($product_on_sale) return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); if ($context->cart->id_customer) { $quantityUsed = Db::getInstance()->getValue(' SELECT count(*) FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order WHERE o.id_customer = '.$context->cart->id_customer.' AND od.id_cart_rule = '.(int)$this->id.' AND '.(int)Configuration::get('PS_OS_ERROR').' != ( SELECT oh.id_order_state FROM '._DB_PREFIX_.'order_history oh WHERE oh.id_order = o.id_order ORDER BY oh.date_add DESC LIMIT 1 )'); if ($quantityUsed + 1 > $this->quantity_per_user) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)'); } // Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1) if ($this->group_restriction) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crg.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_group crg 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 (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } // Check if the customer delivery address is usable with the cart rule if ($this->country_restriction) { if (!$context->cart->id_address_delivery) return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_country crc 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 (!$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 if ($this->carrier_restriction) { if (!$context->cart->id_carrier) return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_carrier crc INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0) WHERE crc.id_cart_rule = '.(int)$this->id.' AND c.id_carrier = '.(int)$context->cart->id_carrier); if (!$id_cart_rule) 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 if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive()) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crs.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_shop crs WHERE crs.id_cart_rule = '.(int)$this->id.' AND crs.id_shop = '.(int)$context->shop->id); if (!$id_cart_rule) 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, $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 (!$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) { // Minimum amount is converted to the default currency $minimum_amount = $this->minimum_amount; if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT')) { $minimum_amount_currency = new Currency($this->minimum_amount_currency); if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0) $minimum_amount = 0; else $minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate; } $cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS); if ($this->minimum_amount_shipping) $cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING); // If a product is given for free in this rule and already in the cart, the price is subtracted if ($this->gift_product && $alreadyInCart) { $query = new DbQuery(); $query->select('id_product'); $query->from('cart_product'); $query->where('id_product = '.(int)$this->gift_product); $query->where('id_cart = '.(int)$context->cart->id); if ((int)$this->gift_product_attribute) $query->where('id_product_attribute = '.(int)$this->gift_product_attribute); if (Db::getInstance()->getValue($query)) { $ref = false; $product_price = Product::getPriceStatic( $this->gift_product, $this->minimum_amount_tax, $this->gift_product_attribute, null, null, false, true, 1, null, $context->cart->id_customer ? $context->cart->id_customer : null, $context->cart->id, (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null, $ref, true, true, $context, true ); $cartTotal -= $product_price; } } if ($cartTotal < $minimum_amount) return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher'); } // Check if the voucher is already in the cart of if a non compatible voucher is in the cart // Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them $otherCartRules = $context->cart->getCartRules(); if (count($otherCartRules)) foreach ($otherCartRules as $otherCartRule) { if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart) 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 FROM '._DB_PREFIX_.'cart_rule_combination WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].') OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')'); if (!$combinable) { $cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang); // The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested if ($cart_rule->priority <= $this->priority) return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name; // But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one else $context->cart->removeCartRule($cart_rule->id); } } } if (!$display_error) return true; } protected function checkProductRestrictions(Context $context, $return_products = false, $display_error = true) { $selectedProducts = array(); // Check if the products chosen by the customer are usable with the cart rule if ($this->product_restriction) { $productRuleGroups = $this->getProductRuleGroups(); foreach ($productRuleGroups as $id_product_rule_group => $productRuleGroup) { $eligibleProductsList = array(); foreach ($context->cart->getProducts() as $product) $eligibleProductsList[] = (int)$product['id_product'].'-'.(int)$product['id_product_attribute']; if (!count($eligibleProductsList)) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher in an empty cart'); $productRules = $this->getProductRules($id_product_rule_group); foreach ($productRules as $productRule) { switch ($productRule['type']) { case 'attributes': $cartAttributes = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product`, pac.`id_attribute`, cp.`id_product_attribute` FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON cp.id_product_attribute = pac.id_product_attribute WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').') AND cp.id_product_attribute > 0'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartAttributes as $cartAttribute) if (in_array($cartAttribute['id_attribute'], $productRule['values'])) { $countMatchingProducts += $cartAttribute['quantity']; $matchingProductsList[] = $cartAttribute['id_product'].'-'.$cartAttribute['id_product_attribute']; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; case 'products': $cartProducts = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product` FROM `'._DB_PREFIX_.'cart_product` cp WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartProducts as $cartProduct) if (in_array($cartProduct['id_product'], $productRule['values'])) { $countMatchingProducts += $cartProduct['quantity']; $matchingProductsList[] = $cartProduct['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; case 'categories': $cartCategories = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product`, cp.`id_product_attribute`, catp.`id_category` FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'category_product` catp ON cp.id_product = catp.id_product WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartCategories as $cartCategory) if (in_array($cartCategory['id_category'], $productRule['values']) // We also check that the product is not already in the matching product list, because there are doubles in the query results (when the product is in multiple categories) && !in_array($cartCategory['id_product'].'-'.$cartCategory['id_product_attribute'], $matchingProductsList)) { $countMatchingProducts += $cartCategory['quantity']; $matchingProductsList[] = $cartCategory['id_product'].'-'.$cartCategory['id_product_attribute']; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); // Attribute id is not important for this filter in the global list, so the ids are replaced by 0 foreach ($matchingProductsList as &$matchingProduct) $matchingProduct = preg_replace('/^([0-9]+)-[0-9]+$/', '$1-0', $matchingProduct); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; case 'manufacturers': $cartManufacturers = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product`, p.`id_manufacturer` FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON cp.id_product = p.id_product WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartManufacturers as $cartManufacturer) if (in_array($cartManufacturer['id_manufacturer'], $productRule['values'])) { $countMatchingProducts += $cartManufacturer['quantity']; $matchingProductsList[] = $cartManufacturer['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; case 'suppliers': $cartSuppliers = Db::getInstance()->executeS(' SELECT cp.quantity, cp.`id_product`, p.`id_supplier` FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON cp.id_product = p.id_product WHERE cp.`id_cart` = '.(int)$context->cart->id.' AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')'); $countMatchingProducts = 0; $matchingProductsList = array(); foreach ($cartSuppliers as $cartSupplier) if (in_array($cartSupplier['id_supplier'], $productRule['values'])) { $countMatchingProducts += $cartSupplier['quantity']; $matchingProductsList[] = $cartSupplier['id_product'].'-0'; } if ($countMatchingProducts < $productRuleGroup['quantity']) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); $eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList); break; } if (!count($eligibleProductsList)) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products'); } $selectedProducts = array_merge($selectedProducts, $eligibleProductsList); } } if ($return_products) return $selectedProducts; return (!$display_error) ? true : false; } protected static function array_uintersect($array1, $array2) { $intersection = array(); foreach ($array1 as $value1) foreach ($array2 as $value2) if (CartRule::array_uintersect_compare($value1, $value2) == 0) { $intersection[] = $value1; break 1; } return $intersection; } protected static function array_uintersect_compare($a, $ { if ($a == $ return 0; $asplit = explode('-', $a); $bsplit = explode('-', $; if ($asplit[0] == $bsplit[0] && (!(int)$asplit[1] || !(int)$bsplit[1])) return 0; return 1; } /** * The reduction value is POSITIVE * * @param bool $use_tax * @param Context $context * @param boolean $use_cache Allow using cache to avoid multiple free gift using multishipping * @return float|int|string */ public function getContextualValue($use_tax, Context $context = null, $filter = null, $package = null, $use_cache = true) { if (!CartRule::isFeatureActive()) return 0; if (!$context) $context = Context::getContext(); if (!$filter) $filter = CartRule::FILTER_ACTION_ALL; $all_products = $context->cart->getProducts(); $package_products = (is_null($package) ? $all_products : $package['products']); $reduction_value = 0; $cache_id = 'getContextualValue_'.(int)$this->id.'_'.(int)$use_tax.'_'.(int)$context->cart->id.'_'.(int)$filter; foreach ($package_products as $product) $cache_id .= '_'.(int)$product['id_product'].'_'.(int)$product['id_product_attribute']; if (Cache::isStored($cache_id)) return Cache::retrieve($cache_id); // Free shipping on selected carriers if ($this->free_shipping && in_array($filter, array(CartRule::FILTER_ACTION_ALL, CartRule::FILTER_ACTION_ALL_NOCAP, CartRule::FILTER_ACTION_SHIPPING))) { if (!$this->carrier_restriction) $reduction_value += $context->cart->getOrderTotal($use_tax, Cart::ONLY_SHIPPING, is_null($package) ? null : $package['products'], is_null($package) ? null : $package['id_carrier']); else { $data = Db::getInstance()->executeS(' SELECT crc.id_cart_rule, c.id_carrier FROM '._DB_PREFIX_.'cart_rule_carrier crc INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0) WHERE crc.id_cart_rule = '.(int)$this->id.' AND c.id_carrier = '.(int)$context->cart->id_carrier); if ($data) foreach ($data as $cart_rule) $reduction_value += $context->cart->getCarrierCost((int)$cart_rule['id_carrier'], $use_tax, $context->country); } } if (in_array($filter, array(CartRule::FILTER_ACTION_ALL, CartRule::FILTER_ACTION_ALL_NOCAP, CartRule::FILTER_ACTION_REDUCTION))) { // Discount (%) on the whole order if ($this->reduction_percent && $this->reduction_product == 0) { // Do not give a reduction on free products! $order_total = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS, $package_products); foreach ($context->cart->getCartRules(CartRule::FILTER_ACTION_GIFT) as $cart_rule) $order_total -= Tools::ps_round($cart_rule['obj']->getContextualValue($use_tax, $context, CartRule::FILTER_ACTION_GIFT, $package), 2); $reduction_value += $order_total * $this->reduction_percent / 100; } // Discount (%) on a specific product if ($this->reduction_percent && $this->reduction_product > 0) { foreach ($package_products as $product) if ($product['id_product'] == $this->reduction_product) $reduction_value += ($use_tax ? $product['total_wt'] : $product['total']) * $this->reduction_percent / 100; } // Discount (%) on the cheapest product if ($this->reduction_percent && $this->reduction_product == -1) { $minPrice = false; $cheapest_product = null; foreach ($all_products as $product) { $price = ($use_tax ? $product['price_wt'] : $product['price']); if ($price > 0 && ($minPrice === false || $minPrice > $price)) { $minPrice = $price; $cheapest_product = $product['id_product'].'-'.$product['id_product_attribute']; } } // Check if the cheapest product is in the package $in_package = false; foreach ($package_products as $product) if ($product['id_product'].'-'.$product['id_product_attribute'] == $cheapest_product || $product['id_product'].'-0' == $cheapest_product) $in_package = true; if ($in_package) $reduction_value += $minPrice * $this->reduction_percent / 100; } // Discount (%) on the selection of products if ($this->reduction_percent && $this->reduction_product == -2) { $selected_products_reduction = 0; $selected_products = $this->checkProductRestrictions($context, true); if (is_array($selected_products)) foreach ($package_products as $product) if (in_array($product['id_product'].'-'.$product['id_product_attribute'], $selected_products) || in_array($product['id_product'].'-0', $selected_products)) { $price = ($use_tax ? $product['price_wt'] : $product['price']); $selected_products_reduction += $price * $product['cart_quantity']; } $reduction_value += $selected_products_reduction * $this->reduction_percent / 100; } // Discount (¤) if ($this->reduction_amount) { $prorata = 1; if (!is_null($package) && count($all_products)) { $total_products = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS); if ($total_products) $prorata = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS, $package['products']) / $total_products; } $reduction_amount = $this->reduction_amount; // If we need to convert the voucher value to the cart currency if ($this->reduction_currency != $context->currency->id) { $voucherCurrency = new Currency($this->reduction_currency); // First we convert the voucher value to the default currency if ($reduction_amount == 0 || $voucherCurrency->conversion_rate == 0) $reduction_amount = 0; else $reduction_amount /= $voucherCurrency->conversion_rate; // Then we convert the voucher value in the default currency into the cart currency $reduction_amount *= $context->currency->conversion_rate; $reduction_amount = Tools::ps_round($reduction_amount); } // If it has the same tax application that you need, then it's the right value, whatever the product! if ($this->reduction_tax == $use_tax) { // The reduction cannot exceed the products total, except when we do not want it to be limited (for the partial use calculation) if ($filter != CartRule::FILTER_ACTION_ALL_NOCAP) { $cart_amount = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS); $reduction_amount = min($reduction_amount, $cart_amount); } $reduction_value += $prorata * $reduction_amount; } else { if ($this->reduction_product > 0) { foreach ($context->cart->getProducts() as $product) if ($product['id_product'] == $this->reduction_product) { $product_price_ti = $product['price_wt']; $product_price_te = $product['price']; $product_vat_amount = $product_price_ti - $product_price_te; if ($product_vat_amount == 0 || $product_price_te == 0) $product_vat_rate = 0; else $product_vat_rate = $product_vat_amount / $product_price_te; if ($this->reduction_tax && !$use_tax) $reduction_value += $prorata * $reduction_amount / (1 + $product_vat_rate); elseif (!$this->reduction_tax && $use_tax) $reduction_value += $prorata * $reduction_amount * (1 + $product_vat_rate); } } // Discount (¤) on the whole order elseif ($this->reduction_product == 0) { $cart_amount_ti = $context->cart->getOrderTotal(true, Cart::ONLY_PRODUCTS); $cart_amount_te = $context->cart->getOrderTotal(false, Cart::ONLY_PRODUCTS); // The reduction cannot exceed the products total, except when we do not want it to be limited (for the partial use calculation) if ($filter != CartRule::FILTER_ACTION_ALL_NOCAP) $reduction_amount = min($reduction_amount, $this->reduction_tax ? $cart_amount_ti : $cart_amount_te); $cart_vat_amount = $cart_amount_ti - $cart_amount_te; if ($cart_vat_amount == 0 || $cart_amount_te == 0) $cart_average_vat_rate = 0; else $cart_average_vat_rate = Tools::ps_round($cart_vat_amount / $cart_amount_te, 3); if ($this->reduction_tax && !$use_tax) $reduction_value += $prorata * $reduction_amount / (1 + $cart_average_vat_rate); elseif (!$this->reduction_tax && $use_tax) $reduction_value += $prorata * $reduction_amount * (1 + $cart_average_vat_rate); } /* * 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) */ } } } // Free gift if ((int)$this->gift_product && in_array($filter, array(CartRule::FILTER_ACTION_ALL, CartRule::FILTER_ACTION_ALL_NOCAP, CartRule::FILTER_ACTION_GIFT))) { $id_address = (is_null($package) ? 0 : $package['id_address']); foreach ($package_products as $product) if ($product['id_product'] == $this->gift_product && ($product['id_product_attribute'] == $this->gift_product_attribute || !(int)$this->gift_product_attribute)) { // The free gift coupon must be applied to one product only (needed for multi-shipping which manage multiple product lists) if (!isset(CartRule::$only_one_gift[$this->id.'-'.$this->gift_product]) || CartRule::$only_one_gift[$this->id.'-'.$this->gift_product] == $id_address || CartRule::$only_one_gift[$this->id.'-'.$this->gift_product] == 0 || $id_address == 0 || !$use_cache) { $reduction_value += ($use_tax ? $product['price_wt'] : $product['price']); if ($use_cache && (!isset(CartRule::$only_one_gift[$this->id.'-'.$this->gift_product]) || CartRule::$only_one_gift[$this->id.'-'.$this->gift_product] == 0)) CartRule::$only_one_gift[$this->id.'-'.$this->gift_product] = $id_address; break; } } } Cache::store($cache_id, $reduction_value); return $reduction_value; } /** * Make sure caches are empty * Must be called before calling multiple time getContextualValue() */ public static function cleanCache() { self::$only_one_gift = array(); } protected function getCartRuleCombinations() { $array = array(); $array['selected'] = Db::getInstance()->executeS(' SELECT cr.*, crl.*, 1 as selected FROM '._DB_PREFIX_.'cart_rule cr LEFT JOIN '._DB_PREFIX_.'cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = '.(int)Context::getContext()->language->id.') WHERE cr.id_cart_rule != '.(int)$this->id.' AND ( cr.cart_rule_restriction = 0 OR cr.id_cart_rule IN ( SELECT IF(id_cart_rule_1 = '.(int)$this->id.', id_cart_rule_2, id_cart_rule_1) FROM '._DB_PREFIX_.'cart_rule_combination WHERE '.(int)$this->id.' = id_cart_rule_1 OR '.(int)$this->id.' = id_cart_rule_2 ) )'); $array['unselected'] = Db::getInstance()->executeS(' SELECT cr.*, crl.*, 1 as selected FROM '._DB_PREFIX_.'cart_rule cr LEFT JOIN '._DB_PREFIX_.'cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = '.(int)Context::getContext()->language->id.') WHERE cr.cart_rule_restriction = 1 AND cr.id_cart_rule != '.(int)$this->id.' AND cr.id_cart_rule NOT IN ( SELECT IF(id_cart_rule_1 = '.(int)$this->id.', id_cart_rule_2, id_cart_rule_1) FROM '._DB_PREFIX_.'cart_rule_combination WHERE '.(int)$this->id.' = id_cart_rule_1 OR '.(int)$this->id.' = id_cart_rule_2 )'); return $array; } public function getAssociatedRestrictions($type, $active_only, $i18n) { $array = array('selected' => array(), 'unselected' => array()); if (!in_array($type, array('country', 'carrier', 'group', 'cart_rule', 'shop'))) return false; $shop_list = ''; if ($type == 'shop') { $shops = Context::getContext()->employee->getAssociatedShops(); if (count($shops)) $shop_list = ' AND t.id_shop IN ('.implode(array_map('intval', $shops), ',').') '; } if (!Validate::isLoadedObject($this) OR $this->{$type.'_restriction'} == 0) { $array['selected'] = Db::getInstance()->executeS(' SELECT t.*'.($i18n ? ', tl.*' : '').', 1 as selected FROM `'._DB_PREFIX_.$type.'` t '.($i18n ? 'LEFT JOIN `'._DB_PREFIX_.$type.'_lang` tl ON (t.id_'.$type.' = tl.id_'.$type.' AND tl.id_lang = '.(int)Context::getContext()->language->id.')' : '').' WHERE 1 '.($active_only ? 'AND t.active = 1' : '').' '.(in_array($type, array('carrier', 'shop')) ? ' AND t.deleted = 0' : '').' '.($type == 'cart_rule' ? 'AND t.id_cart_rule != '.(int)$this->id : ''). $shop_list. ' ORDER BY name ASC'); } else { if ($type == 'cart_rule') $array = $this->getCartRuleCombinations(); else { $resource = Db::getInstance()->query(' SELECT t.*'.($i18n ? ', tl.*' : '').', IF(crt.id_'.$type.' IS NULL, 0, 1) as selected FROM `'._DB_PREFIX_.$type.'` t '.($i18n ? 'LEFT JOIN `'._DB_PREFIX_.$type.'_lang` tl ON (t.id_'.$type.' = tl.id_'.$type.' AND tl.id_lang = '.(int)Context::getContext()->language->id.')' : '').' LEFT JOIN (SELECT id_'.$type.' FROM `'._DB_PREFIX_.'cart_rule_'.$type.'` WHERE id_cart_rule = '.(int)$this->id.') crt ON t.id_'.($type == 'carrier' ? 'reference' : $type).' = crt.id_'.$type.' WHERE 1 '.($active_only ? ' AND t.active = 1' : ''). $shop_list .(in_array($type, array('carrier', 'shop')) ? ' AND t.deleted = 0' : ''). ' ORDER BY name ASC', false); while ($row = Db::getInstance()->nextRow($resource)) $array[($row['selected'] || $this->{$type.'_restriction'} == 0) ? 'selected' : 'unselected'][] = $row; } } return $array; } public static function autoRemoveFromCart($context = null) { if (!$context) $context = Context::getContext(); if (!CartRule::isFeatureActive() || !Validate::isLoadedObject($context->cart)) return array(); $errors = array(); foreach ($context->cart->getCartRules() as $cart_rule) { if ($error = $cart_rule['obj']->checkValidity($context, true)) { $context->cart->removeCartRule($cart_rule['obj']->id); $context->cart->update(); $errors[] = $error; } } return $errors; } /** * @static * @param Context|null $context * @return mixed */ public static function autoAddToCart(Context $context = null) { if ($context === null) $context = Context::getContext(); if (!CartRule::isFeatureActive() || !Validate::isLoadedObject($context->cart)) return; $sql = ' SELECT cr.* FROM '._DB_PREFIX_.'cart_rule cr LEFT JOIN '._DB_PREFIX_.'cart_rule_shop crs ON cr.id_cart_rule = crs.id_cart_rule LEFT JOIN '._DB_PREFIX_.'cart_rule_carrier crca ON cr.id_cart_rule = crca.id_cart_rule '.($context->cart->id_carrier ? 'LEFT JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crca.id_carrier AND c.deleted = 0)' : '').' LEFT JOIN '._DB_PREFIX_.'cart_rule_country crco ON cr.id_cart_rule = crco.id_cart_rule WHERE cr.active = 1 AND cr.code = "" 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_customer = 0 '.($context->customer->id ? 'OR cr.id_customer = '.(int)$context->cart->id_customer : '').' ) AND ( cr.carrier_restriction = 0 '.($context->cart->id_carrier ? 'OR c.id_carrier = '.(int)$context->cart->id_carrier : '').' ) AND ( cr.shop_restriction = 0 '.((Shop::isFeatureActive() && $context->shop->id) ? 'OR crs.id_shop = '.(int)$context->shop->id : '').' ) AND ( cr.group_restriction = 0 '.($context->customer->id ? 'OR 0 < ( SELECT cg.id_group FROM '._DB_PREFIX_.'customer_group cg LEFT JOIN '._DB_PREFIX_.'cart_rule_group crg ON (cg.id_group = crg.id_group AND cg.id_group = '.(int)$context->customer->id_default_group.') WHERE cr.id_cart_rule = crg.id_cart_rule AND cg.id_customer = '.(int)$context->customer->id.' LIMIT 1 )' : '').' ) AND ( cr.reduction_product <= 0 OR cr.reduction_product IN ( SELECT id_product FROM '._DB_PREFIX_.'cart_product WHERE id_cart = '.(int)$context->cart->id.' ) ) AND cr.id_cart_rule NOT IN (SELECT id_cart_rule FROM '._DB_PREFIX_.'cart_cart_rule WHERE id_cart = '.(int)$context->cart->id.') ORDER BY priority'; $result = Db::getInstance()->executeS($sql); if ($result) { $cart_rules = ObjectModel::hydrateCollection('CartRule', $result); if ($cart_rules) foreach ($cart_rules as $cart_rule) if ($cart_rule->checkValidity($context, false, false)) $context->cart->addCartRule($cart_rule->id); } } /** * @static * @return bool */ public static function isFeatureActive() { static $is_feature_active = null; if ($is_feature_active === null) $is_feature_active = (bool)Configuration::get('PS_CART_RULE_FEATURE_ACTIVE'); return $is_feature_active; } /* When an entity associated to a product rule (product, category, attribute, supplier, manufacturer...) is deleted, the product rules must be updated */ public static function cleanProductRuleIntegrity($type, $list) { // Type must be available in the 'type' enum of the table cart_rule_product_rule if (!in_array($type, array('products', 'categories', 'attributes', 'manufacturers', 'suppliers'))) return false; // This check must not be removed because this var is used a few lines below $list = (is_array($list) ? implode(',', array_map('intval', $list)) : (int)$list); if (!preg_match('/^[0-9,]+$/', $list)) return false; // Delete associated restrictions on cart rules Db::getInstance()->execute(' DELETE crprv FROM `'._DB_PREFIX_.'cart_rule_product_rule` crpr LEFT JOIN `'._DB_PREFIX_.'cart_rule_product_rule_value` crprv ON crpr.`id_product_rule` = crprv.`id_product_rule` WHERE crpr.`type` = "'.pSQL($type).'" AND crprv.`id_item` IN ('.$list.')'); // $list is checked a few lines above // Delete the product rules that does not have any values if (Db::getInstance()->Affected_Rows() > 0) Db::getInstance()->execute(' DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule` WHERE `id_product_rule` NOT IN (SELECT id_product_rule FROM `'._DB_PREFIX_.'cart_rule_product_rule_value`)'); // If the product rules were the only conditions of a product rule group, delete the product rule group if (Db::getInstance()->Affected_Rows() > 0) Db::getInstance()->execute(' DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_group` WHERE `id_product_rule_group` NOT IN (SELECT id_product_rule_group FROM `'._DB_PREFIX_.'cart_rule_product_rule`)'); // If the product rule group were the only restrictions of a cart rule, update de cart rule restriction cache if (Db::getInstance()->Affected_Rows() > 0) Db::getInstance()->execute(' UPDATE `'._DB_PREFIX_.'cart_rule` cr LEFT JOIN `'._DB_PREFIX_.'cart_rule_product_rule_group` crprg ON cr.id_cart_rule = crprg.id_cart_rule SET product_restriction = IF(crprg.id_product_rule_group IS NULL, 0, 1)'); return true; } /** * @static * @param $name * @param $id_lang * @return array */ public static function getCartsRuleByCode($name, $id_lang) { return Db::getInstance()->executeS(' SELECT cr.*, crl.* FROM '._DB_PREFIX_.'cart_rule cr LEFT JOIN '._DB_PREFIX_.'cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = '.(int)$id_lang.') WHERE code LIKE \'%'.pSQL($name).'%\' '); } } Link to comment Share on other sites More sharing options...
laurent65200 Posted October 21, 2013 Share Posted October 21, 2013 bonjour up programme parrainage ref program presta 1.5.4 pour que les bons créé automatiquement via parrainage ne soit pas cumulable merci Link to comment Share on other sites More sharing options...
KevinNash Posted October 27, 2013 Share Posted October 27, 2013 Cela donne pour l'ensemble de la méthode checkValidity public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true) { if (!CartRule::isFeatureActive()) return false; if (!$this->active) return (!$display_error) ? false : Tools::displayError('This voucher is disabled'); if (!$this->quantity) return (!$display_error) ? false : Tools::displayError('This voucher has already been used'); if (strtotime($this->date_from) > time()) return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet'); if (strtotime($this->date_to) < time()) return (!$display_error) ? false : Tools::displayError('This voucher has expired'); $products = $context->cart->getProducts(); $product_on_sale = false; foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; } if ($product_on_sale) return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); if ($context->cart->id_customer) { $quantityUsed = Db::getInstance()->getValue(' SELECT count(*) FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order WHERE o.id_customer = '.$context->cart->id_customer.' AND od.id_cart_rule = '.(int)$this->id.' AND '.(int)Configuration::get('PS_OS_ERROR').' != ( SELECT oh.id_order_state FROM '._DB_PREFIX_.'order_history oh WHERE oh.id_order = o.id_order ORDER BY oh.date_add DESC LIMIT 1 )'); if ($quantityUsed + 1 > $this->quantity_per_user) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)'); } // Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1) if ($this->group_restriction) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crg.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_group crg 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 (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } // Check if the customer delivery address is usable with the cart rule if ($this->country_restriction) { if (!$context->cart->id_address_delivery) return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_country crc 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 (!$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 if ($this->carrier_restriction) { if (!$context->cart->id_carrier) return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_carrier crc INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0) WHERE crc.id_cart_rule = '.(int)$this->id.' AND c.id_carrier = '.(int)$context->cart->id_carrier); if (!$id_cart_rule) 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 if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive()) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crs.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_shop crs WHERE crs.id_cart_rule = '.(int)$this->id.' AND crs.id_shop = '.(int)$context->shop->id); if (!$id_cart_rule) 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, $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 (!$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) { // Minimum amount is converted to the default currency $minimum_amount = $this->minimum_amount; if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT')) { $minimum_amount_currency = new Currency($this->minimum_amount_currency); if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0) $minimum_amount = 0; else $minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate; } $cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS); if ($this->minimum_amount_shipping) $cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING); // If a product is given for free in this rule and already in the cart, the price is subtracted if ($this->gift_product && $alreadyInCart) { $query = new DbQuery(); $query->select('id_product'); $query->from('cart_product'); $query->where('id_product = '.(int)$this->gift_product); $query->where('id_cart = '.(int)$context->cart->id); if ((int)$this->gift_product_attribute) $query->where('id_product_attribute = '.(int)$this->gift_product_attribute); if (Db::getInstance()->getValue($query)) { $ref = false; $product_price = Product::getPriceStatic( $this->gift_product, $this->minimum_amount_tax, $this->gift_product_attribute, null, null, false, true, 1, null, $context->cart->id_customer ? $context->cart->id_customer : null, $context->cart->id, (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null, $ref, true, true, $context, true ); $cartTotal -= $product_price; } } if ($cartTotal < $minimum_amount) return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher'); } // Check if the voucher is already in the cart of if a non compatible voucher is in the cart // Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them $otherCartRules = $context->cart->getCartRules(); if (count($otherCartRules)) foreach ($otherCartRules as $otherCartRule) { if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart) 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 FROM '._DB_PREFIX_.'cart_rule_combination WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].') OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')'); if (!$combinable) { $cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang); // The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested if ($cart_rule->priority <= $this->priority) return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name; // But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one else $context->cart->removeCartRule($cart_rule->id); } } } if (!$display_error) return true; } PS : pensez à traduire le message dans les traductions des messages d'erreur ! Cordialement, Aie ! Je viens d'essayer ça provoque un plantage si on a une condition de catégorie produits PS 1.5.4.1 J'ai essayé sur mon compte avec un code valable sur une catégorie uniquement, page blanche en validant le code, erreur : Fatal error: Call to undefined method CartRule::checkProductRestrictions() in /classes/CartRule.php on line 477 Autre chose, si je mets CartRule.php dans override/classes/ ça ne fonctionne pas, je suis obligé d'écraser le fichier habituel. Link to comment Share on other sites More sharing options...
laurent65200 Posted October 27, 2013 Share Posted October 27, 2013 bonjour up programme parrainage ref program presta 1.5.4 pour que les bons créé automatiquement via parrainage ne soit pas cumulable merci Link to comment Share on other sites More sharing options...
laurent65200 Posted November 5, 2013 Share Posted November 5, 2013 bonjour up programme parrainage ref program presta 1.5.4 pour que les bons créé automatiquement via parrainage ne soit pas cumulable merci personne pour aider ? Link to comment Share on other sites More sharing options...
Tia© Posted December 6, 2013 Share Posted December 6, 2013 Thank's a lot! It's works for me too P.S. Version 1.5.6 Link to comment Share on other sites More sharing options...
fulviods Posted December 26, 2013 Share Posted December 26, 2013 c'est scandaleux que cette option même sur la 1.5.6.1 ne soit pas présente et qu'il faut modifier!J'ai passé le site d'un client d'une 1.4 à une 1.5.6.1 tout semblait fonctionner je me suis absenté et il s'est retrouvé avec une dizaines de commandes qui ont cumulé bon de réduction et promotions !!!Soit ne pas mettre cette fonctionnalité du tout soit la corriger ! Mais svp ne pas laisser des bugs aussi gros comme ça! Ca représente des heures de prises de tête pour des centaines de personnes juste car cette modif gentillement proposée par Manuel Corbet n'a pas été faite dans le code du site!Est-ce que Prestashop est au courant de ce bug? Ils pensent le corriger ou il va y avoir encore des pages de forum écrites par des utilisateurs qui perdent la tête ? Link to comment Share on other sites More sharing options...
KevinNash Posted December 26, 2013 Share Posted December 26, 2013 Le pire c'est le code promo pour une catégorie, si le client met 1 article de la bonne catégorie et d'autres de catégories différentes, la remise s'applique sur l'ensemble Impossible d'imposer un code promo sur une seule catégorie... Link to comment Share on other sites More sharing options...
cockpitinferno Posted December 28, 2013 Share Posted December 28, 2013 @fulviods oui ils sont au courant il y a plein de posts sur la forge mais on dirait qu'ils s'en foutent complètement! 1 Link to comment Share on other sites More sharing options...
KevinNash Posted March 14, 2014 Share Posted March 14, 2014 Le pire c'est le code promo pour une catégorie, si le client met 1 article de la bonne catégorie et d'autres de catégories différentes, la remise s'applique sur l'ensemble Impossible d'imposer un code promo sur une seule catégorie... Pareil avec la 1.6 ? Merveilleux ! Impeccable de faire des jolis back-office avec des fonctions essentielles manquantes. J'imagine qu'il en est de même avec les promos par catégorie... Link to comment Share on other sites More sharing options...
cockpitinferno Posted March 18, 2014 Share Posted March 18, 2014 je suis quand même contente d'être passée à 1.5 car ca a relancé mon site (ils ont du faire du taf sur le référencement a mon avis). pour le moment je ne pense même pas à la 1.6. mais c'est vrai on dirait qu'ils pensent avant tout à l'esthétique du bo plutôt qu'à faire des trucs pratiques, comme dupliquer les bon achats etc... personnellement je me contrefiche de l'interface, je préférais d'ailleurs celle d'avant. au moins sur la fiche produit tout était au même endroit, il suffisait de scroller, maintenant y a plein d'onglets qu'il faut tout le temps enregistrer et pour les gens qui ont une connexion de merde comme moi ca fait perdre plein de temps... mais bon on peut pas tout avoir... Link to comment Share on other sites More sharing options...
Kloan Posted April 4, 2014 Share Posted April 4, 2014 Bonjour, Avec le code fourni par Manuel Corbet il est maintenant possible de faire en sorte qu'un bon de réduction ne s'applique pas sur le panier si un produit en promotion se trouve dedans. Mais Est-ce que quelqu'un à trouvé comment faire pour que le code de réduction s'applique quand même sur le produit qui n'est pas en promotion s'il y a deux ou plusieurs produits ? 1 Link to comment Share on other sites More sharing options...
Blawdi Posted October 9, 2014 Share Posted October 9, 2014 1.6.0.9 même problème! Prestashop ça devient vraiment n'importe quoi!!!! Sans compter le support du forum inexistant! Link to comment Share on other sites More sharing options...
popeyerubis Posted October 17, 2014 Share Posted October 17, 2014 (edited) Bonjour, en effet cela était possible en 1.4 mais pas en 1.5 ... En faisant l'override de la classe CartRule on s'en sort très bien ! Donc si votre besoin est seulement de permettre de bloquer les bons sur les produits en promos, ne vous faite pas "arnaquer" avec l'achat d'un module, il suffit de rajouter quelques lignes de codes, rien de bien sorcié ... Il s'agit de la méthode "public function checkValidity" : il faut rajouter : $products = $context->cart->getProducts(); $product_on_sale = false; foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; } if ($product_on_sale) return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); Il faut place cela après le code suivant : (je vous incite fortement à utiliser l'override pour faire la modification.) if (strtotime($this->date_to) < time()) return (!$display_error) ? false : Tools::displayError('This voucher has expired'); Cordialement, Bonjour, Merci beaucoup ! Edited October 17, 2014 by popeyerubis (see edit history) Link to comment Share on other sites More sharing options...
cockpitinferno Posted October 21, 2014 Share Posted October 21, 2014 (edited) je viens de faire la modif sur 1.6.0.1 en local et ca fonctionne. maintenant qqun saurait il comment faire pour que le code promo soit valable sur un panier qui contient une promo mais qui ne s'applique que sur le produit pas en promo. ex 'ai un produit à -50% et un autre sans reduc dans mon panier, mais j'ai aussi un code promo de -10%, je voudrais que ce code s'applique au produit pas en promo seulement. sinon j'ai voté pour ce post: http://feedback.pres...ouchers-coupons ce serait bien que d'autres le fasse si on veut que ca change de ce coté là. Edited October 21, 2014 by cockpitinferno (see edit history) 1 Link to comment Share on other sites More sharing options...
laurent75014 Posted January 4, 2015 Share Posted January 4, 2015 Bonjour, Dommage, le père Noël ne nous a pas apporter la solution à ce problème de code de réduction non cumulable. Quelques jours avant les soldes, un espoir de solution est il envisageable ? Merci pour tous ceux qui attendent. 1 Link to comment Share on other sites More sharing options...
cockpitinferno Posted January 6, 2015 Share Posted January 6, 2015 ben si, il suffit de faire la modif proposée plus haut. par contre effectivement si tu as un produit en solde dans le panier + un autre sans reduc ton code promo marchera pas. Link to comment Share on other sites More sharing options...
cherubin66 Posted January 28, 2015 Share Posted January 28, 2015 salut, moi aussi, j'ai le même problème. impossible de séparer les produits en solde afin que les bons de réduction ne s'appliquent pas à eux. Link to comment Share on other sites More sharing options...
cherubin66 Posted January 28, 2015 Share Posted January 28, 2015 Je viens de trouver une solution que je teste. C'est un peu emm*dant. 1- Il faut dans l'onglet "conditions" sélectionner les produits qui seront impactés par la bon de réduction et retirer les produits déjà soldés manuellement. 2- Dans un second temps, il faut passer à l'onglet "actions" toujours dans les "règles paniers" et activer "Le(s) produit(s) sélectionné(s)". Comme les produits "soldés" n'ont pas été sélectionnés, ils n'entrent pas dans le bon de réduction et les produits non soldés subissent eux bien la réduction que vous avez décidé ^^ PS: Un pti bouton radio comme dans la PS 1.4 serait plus pratique amha Link to comment Share on other sites More sharing options...
popeyerubis Posted January 29, 2015 Share Posted January 29, 2015 Cherubin66, tu sélectionnes TOUS le produits de ta boutique dans l'onglet actions SAUF les soldés et en promo ? Mais alors quand les soldes et les promos sont terminées, il faut encore faire le changement sens inverse ? Link to comment Share on other sites More sharing options...
cherubin66 Posted January 29, 2015 Share Posted January 29, 2015 Ben si tu n'as plus de solde ni de promotion, il suffit de faire "sauter" ces critères restrictifs (icône croix ) pour retrouver ta boutique avec des bons de réduction classiques qui s'appliquent à tous les produits. La chose à faire en période de solde, c'est de sélectionner les produits qui n'entrent pas dans le bon de réduction édité. Ca peut être assez galère si tu as beaucoup de produits en promotion. Une autre solution est de créer , si tu ne t'en sers pas, un fabriquant appelé "solde" par exemple et d'y associer touts les produits en promotion, tu fais une exclusion du fabriquant "solde"... 1 Link to comment Share on other sites More sharing options...
popeyerubis Posted January 29, 2015 Share Posted January 29, 2015 Ca marche, je te remercie pour le truc !!! Link to comment Share on other sites More sharing options...
cockpitinferno Posted August 14, 2015 Share Posted August 14, 2015 oui bien sur ca marche mais franchement en période de soldes bonjours le bordel, en plus si tu change souvent tes promos il faut refaire la manip à chaque fois... Link to comment Share on other sites More sharing options...
rodloft Posted October 3, 2015 Share Posted October 3, 2015 Bonjour, J'avais le même problème sur la version 1.6.0.9 que j'ai résolue avec un petit module développé par IBS on line (bizarrement impossible de retrouver ce module dans addons.) qui fonctionnait super bien jusqu'à ce que je passe sur la dernière version 1.6.1.1 Je me retrouve à nouveau avec des codes promo cumulable avec mes promotions. Si quelqu'un à une solution ??? Merci d'avance Link to comment Share on other sites More sharing options...
rodloft Posted October 6, 2015 Share Posted October 6, 2015 Pourquoi ce problème n'est toujours pas pris en compte depuis 2012 ??? Allo y a quelqu'un ?? Link to comment Share on other sites More sharing options...
adrien russo Posted October 23, 2015 Share Posted October 23, 2015 (edited) Pour ma part, je n'autorise pas les codes promos sur les paniers contenant un article avec un prix réduit. Si on ajout un article en promo après avoir ajouté un code de réduction dans le panier, le code de réduction est retiré. Si on veut rajouter le code a nouveau on obtient un message d'erreur. Voici mon code. Il faut bien suppimer le fichier /cache/class_index.php quand on ajoute une surcharge comme celle-ci Je pense me pencher rapidement vers une acceptation du code promo mais une application uniquement sur les articles sans prix réduit. /override/classes/CartRule.php : <?php class CartRule extends CartRuleCore { /** * Check if this cart rule can be applied * * @param Context $context * @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, $display_error = true, $check_carrier = true) { // on reprend le traitement de base et si il passe on vérifie alors les promotions $returnParent = parent::checkValidity($context, $alreadyInCart, $display_error, $check_carrier); if ($returnParent === NULL) { $products = $context->cart->getProducts(); $product_on_sale = false; foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; } if ($product_on_sale) { return (!$display_error) ? false : Tools::displayError('Ce code n\'est pas cumulable avec des produits déjà en promotion'); } } return $returnParent; } } Edited October 23, 2015 by adrien russo (see edit history) 1 Link to comment Share on other sites More sharing options...
Patrick_64 Posted November 7, 2015 Share Posted November 7, 2015 Bonjour tout le monde, pour info le client pour qui j'avais effectué cette modification m'a demandé de laissé la possibilité de faire les bons de réduction sur les promos si il s'agit d'un bon proposant une réduction par "montant". En gros d'interdire seulement les bons en pourcentage du prix pour les produits soldés. Voici donc la nouvelle version avec ce feature en plus : public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true) { if (!CartRule::isFeatureActive()) return false; if (!$this->active) return (!$display_error) ? false : Tools::displayError('This voucher is disabled'); if (!$this->quantity) return (!$display_error) ? false : Tools::displayError('This voucher has already been used'); if (strtotime($this->date_from) > time()) return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet'); if (strtotime($this->date_to) < time()) return (!$display_error) ? false : Tools::displayError('This voucher has expired'); $product_on_sale = false; $amount = false; if($this->reduction_percent === '0.00' && $this->reduction_amount !== '0.00') $amount = true; if(!$amount){ $products = $context->cart->getProducts(); foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; } if ($product_on_sale) return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); } if ($context->cart->id_customer) { $quantityUsed = Db::getInstance()->getValue(' SELECT count(*) FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order WHERE o.id_customer = '.$context->cart->id_customer.' AND od.id_cart_rule = '.(int)$this->id.' AND '.(int)Configuration::get('PS_OS_ERROR').' != ( SELECT oh.id_order_state FROM '._DB_PREFIX_.'order_history oh WHERE oh.id_order = o.id_order ORDER BY oh.date_add DESC LIMIT 1 )'); if ($quantityUsed + 1 > $this->quantity_per_user) return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)'); } // Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1) if ($this->group_restriction) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crg.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_group crg 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 (!$display_error) ? false : Tools::displayError('You cannot use this voucher'); } // Check if the customer delivery address is usable with the cart rule if ($this->country_restriction) { if (!$context->cart->id_address_delivery) return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_country crc 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 (!$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 if ($this->carrier_restriction) { if (!$context->cart->id_carrier) return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order'); $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crc.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_carrier crc INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0) WHERE crc.id_cart_rule = '.(int)$this->id.' AND c.id_carrier = '.(int)$context->cart->id_carrier); if (!$id_cart_rule) 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 if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive()) { $id_cart_rule = (int)Db::getInstance()->getValue(' SELECT crs.id_cart_rule FROM '._DB_PREFIX_.'cart_rule_shop crs WHERE crs.id_cart_rule = '.(int)$this->id.' AND crs.id_shop = '.(int)$context->shop->id); if (!$id_cart_rule) 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, $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 (!$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) { // Minimum amount is converted to the default currency $minimum_amount = $this->minimum_amount; if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT')) { $minimum_amount_currency = new Currency($this->minimum_amount_currency); if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0) $minimum_amount = 0; else $minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate; } $cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS); if ($this->minimum_amount_shipping) $cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING); // If a product is given for free in this rule and already in the cart, the price is subtracted if ($this->gift_product && $alreadyInCart) { $query = new DbQuery(); $query->select('id_product'); $query->from('cart_product'); $query->where('id_product = '.(int)$this->gift_product); $query->where('id_cart = '.(int)$context->cart->id); if ((int)$this->gift_product_attribute) $query->where('id_product_attribute = '.(int)$this->gift_product_attribute); if (Db::getInstance()->getValue($query)) { $ref = false; $product_price = Product::getPriceStatic( $this->gift_product, $this->minimum_amount_tax, $this->gift_product_attribute, null, null, false, true, 1, null, $context->cart->id_customer ? $context->cart->id_customer : null, $context->cart->id, (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null, $ref, true, true, $context, true ); $cartTotal -= $product_price; } } if ($cartTotal < $minimum_amount) return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher'); } // Check if the voucher is already in the cart of if a non compatible voucher is in the cart // Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them $otherCartRules = $context->cart->getCartRules(); if (count($otherCartRules)) foreach ($otherCartRules as $otherCartRule) { if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart) 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 FROM '._DB_PREFIX_.'cart_rule_combination WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].') OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')'); if (!$combinable) { $cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang); // The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested if ($cart_rule->priority <= $this->priority) return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name; // But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one else $context->cart->removeCartRule($cart_rule->id); } } } if (!$display_error) return true; } Merci Manuel, ça fonctionne nickel PS 1.5.6.2 Link to comment Share on other sites More sharing options...
rodloft Posted November 17, 2015 Share Posted November 17, 2015 (edited) Bonjour, Je reviens sur ce poste avec espoir que quelqu'un nous vienne en aide pour régler ce problème de bon de réduction non cumulable avec les promotions sur 1.6.1.1 avant Noël ça serait super SVP Merci pour tous ceux qui attendent... Edited November 17, 2015 by rodloft (see edit history) Link to comment Share on other sites More sharing options...
fherrard Posted November 26, 2015 Share Posted November 26, 2015 Oui ce qu'il serait bien c'est que le bon s'applique sur tous les produits du panier sauf ceux qui beneficie déjà d'une promo.. Car là on bloque tout le panier et le client ne beneficie même pas de la remise du coup . Link to comment Share on other sites More sharing options...
kiteman Posted December 26, 2015 Share Posted December 26, 2015 Bonjour, Bon, pour ma part, je me suis résigné à acheter le module "Non Cumulative Cart Rules with other Discounts", qui effectivement fonctionne avec des produits en soldes et d'autre pas Link to comment Share on other sites More sharing options...
samjouzel Posted June 7, 2016 Share Posted June 7, 2016 Hello ! moi aussi je trouve ça aberrant de laisser couler ce bug/oubli...pitoyable. J'ai pas testé la méthode du bout de code mais c'est surtout pour le programme de parrainage le soucis...car ce base il les créés compatibles !! (la blague!!) Quelqu'un a une idée pour le referral programme ? Link to comment Share on other sites More sharing options...
Lyn&Or Bijoux Posted June 30, 2016 Share Posted June 30, 2016 Bonjour à tous, Je viens effectivement de m'apercevoir de ce rpoblème mais ce que je souhaite est en sens inverse. C'est à dire que j'ai des articles en promos/soldes, accessibles à tous les clients de la même façon, Hors je veux donner à certains clients privilégier un code réduction plus important que les soldes déjà en cours. Du coup, j'ai besoin que si le client saisit son bon de réduction, la promo est supprimée. Si quelqu'un à une solution, je suis preneuse! MJ Link to comment Share on other sites More sharing options...
optim56 Posted July 22, 2016 Share Posted July 22, 2016 Bonjour, je suis en 1.6.1.4 et j'ai le même problème de tout le monde, impossible de proposer un code réduction non cumulable avec les promotiions. D'autant qu'actuellement c'est les soldes, on a 2000 produits soldés et qu'une centaine non soldés, comment faire pour retrouver cette fonction présente avant sur le 1.4 C'est plutôt inciter les gens à acheter un module alors que cette fonction était gratuite!! Link to comment Share on other sites More sharing options...
Christelle-MCD Posted November 16, 2016 Share Posted November 16, 2016 Bonjour, Excusez moi pourquoi je n'est pas ces boutons moi ! J'aimerais que mes règles paniers ne soit pas cumulable entre eux ... Je ne trouve pas de solution Link to comment Share on other sites More sharing options...
Photon Posted January 23, 2017 Share Posted January 23, 2017 (edited) Bonjour, je remonte ce sujet, merci à Manuel Corbet pour cette modif, que j'ai appliquée sur PS 1.6.0.14 j'y ai apporté une modification pour permettre l'application d'une règle de panier de type "montant" (je n'utilise pas les % alors je n'ai pas testé) quand dans le panier il y a des produits promos/soldés ET des produits éligibles (sans réduction). $products = $context->cart->getProducts(); $product_on_sale = false; foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; // ajout de la condition suivante dans le code de Manuel Corbet if(empty($product["reduction_applies"])) $product_on_sale = false; } if ($product_on_sale) return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); Voici des captures pour montrer le résultat : la condition fonctionne quand le(s) produit(s) non soldés sont à la fin du panier mais je vais remodeler pour que ça fonctionne quelque soit l'ordre. J'aimerai à terme pouvoir activer cette option au cas par cas dans chaque règle panier. (en passant par une case à cocher et un champ supplémentaire en base de données comme dans Presta 1.4). Voilà mon projet bonne journée, bonnes ventes Edited January 23, 2017 by Photon (see edit history) Link to comment Share on other sites More sharing options...
Photon Posted January 23, 2017 Share Posted January 23, 2017 (edited) Voilà la première modif permettant au client d'utiliser un bon de réduction (en montant) sur un ou des produit(s) non soldés dans un panier qui contient également des produits promos/soldés à prix barrés. $products = $context->cart->getProducts(); $product_on_sale = false; $product_not_sale = false; // ajout d'une variable foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $product_on_sale = true; // utilisation de cette nouvelle variable if(empty($product["reduction_applies"])) $product_not_sale = true; } if ($product_on_sale && !$product_not_sale) // condition qui affichera l'erreur return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale'); en espérant que ça aidera. Edited January 23, 2017 by Photon (see edit history) Link to comment Share on other sites More sharing options...
Photon Posted January 24, 2017 Share Posted January 24, 2017 (edited) C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier). Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas ! Si ça intéresse, je ferai un tuto. Edited January 24, 2017 by Photon (see edit history) 3 Link to comment Share on other sites More sharing options...
samjouzel Posted January 24, 2017 Share Posted January 24, 2017 C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier). Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas ! Si ça intéresse, je ferai un tuto. Ca m’intéresse grave Link to comment Share on other sites More sharing options...
zaye Posted February 6, 2017 Share Posted February 6, 2017 C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier). Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas ! Si ça intéresse, je ferai un tuto. Bonjour Photon, Cela m'intéresse aussi ; et je suis sûr que nous sommes nombreux à espérer cette solution... Merci d'avance pour le tuto ! Link to comment Share on other sites More sharing options...
dadou6 Posted March 31, 2017 Share Posted March 31, 2017 C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier). Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas ! Si ça intéresse, je ferai un tuto. Comme l'ont dit les personnes avant moi, je suis aussi impatient de voir votre tuto... Merci d'avance ! Link to comment Share on other sites More sharing options...
Lyn&Or Bijoux Posted July 5, 2018 Share Posted July 5, 2018 Quote C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier). Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas ! Si ça intéresse, je ferai un tuto. Bonjour, Très intéressée par le tuto aussi! Je viens d'avoir une commande pour 2 bracelets à 0,30€ car les régles et soldes s'étaient cumulées Prévenez-nous quand il sera prêt!! Bonne journée Link to comment Share on other sites More sharing options...
jdo-cecile Posted November 23, 2018 Share Posted November 23, 2018 On 1/24/2017 at 11:27 AM, Photon said: C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier). Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas ! Si ça intéresse, je ferai un tuto. Bonjour, Je ne sais pas si vous l'avez fait mais moi aussi je serai intéressé par un tuto. Merci Link to comment Share on other sites More sharing options...
BacKick Posted September 18, 2020 Share Posted September 18, 2020 Bonjour, En effet je reviens vers ce sujet car je cherchais aussi une solution sur Prestashop 1.5 pour appliquer une remise de 10% sur la commande sauf sur certain produit (déjà remisé ou autres). La solution évoqué plus en haut est une bonne solution mais en effet bloque totalement le code promo dans ce cas la. On 1/6/2015 at 4:04 PM, cockpitinferno said: ben si, il suffit de faire la modif proposée plus haut. par contre effectivement si tu as un produit en solde dans le panier + un autre sans reduc ton code promo marchera pas. Du coup petite solution rapide pour quand même appliqué la remise aux produit sans réduc Toujours dans la même classe mais dans la fonction : getContextualValue() J'ajoute : $products = $context->cart->getProducts(); foreach($products as $product){ if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0) $order_total -= $product["total_wt"]; } Après le code : // Discount (%) on the whole order if ($this->reduction_percent && $this->reduction_product == 0) { // Do not give a reduction on free products! $order_total = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS, $package_products); foreach ($context->cart->getCartRules(CartRule::FILTER_ACTION_GIFT) as $cart_rule) $order_total -= Tools::ps_round($cart_rule['obj']->getContextualValue($use_tax, $context, CartRule::FILTER_ACTION_GIFT, $package), 2); . . . . . Ce qui enlève tout simplement le prix du produit que je ne veux pas remiser au prix total de la commande. 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