Jump to content
Miria

1.5 Je ne trouve pas où rendre un bon de réduction non cumulable avec les promotions !

Recommended Posts

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 by Miria (see edit history)

Share this post


Link to post
Share on other sites

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é.

  • Like 1

Share this post


Link to post
Share on other sites

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 ?

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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!

Share this post


Link to post
Share on other sites

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...

Share this post


Link to post
Share on other sites

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/

Share this post


Link to post
Share on other sites

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...

Share this post


Link to post
Share on other sites

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 by juliettte (see edit history)

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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...

Share this post


Link to post
Share on other sites

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 by eric69 (see edit history)

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

je viens d'essayer et le bon est cumulable même en mettant 2 sur la priorité. avez vous fait autre chose en plus?

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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 !

Share this post


Link to post
Share on other sites

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é.

Share this post


Link to post
Share on other sites

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...

Share this post


Link to post
Share on other sites

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 !

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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...

  • Like 1

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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 by Manuel Corbet (see edit history)
  • Like 3

Share this post


Link to post
Share on other sites

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 by Manuel Corbet (see edit history)
  • Like 2

Share this post


Link to post
Share on other sites

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 by cockpitinferno (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites

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 by Manuel Corbet (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites

Bonjour,

 

votre solution marche très bien en override. sur ps 1.5.4.1

 

merci beaucoup

Share this post


Link to post
Share on other sites

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;

Share this post


Link to post
Share on other sites

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;
}
  • Like 1

Share this post


Link to post
Share on other sites

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:
* 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 license@prestashop.com 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 <contact@prestashop.com>
*  @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, $B)
{
if ($a == $B)
return 0;
 
$asplit = explode('-', $a);
$bsplit = explode('-', $B);
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).'%\'
');
}
}

Share this post


Link to post
Share on other sites

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. 

Share this post


Link to post
Share on other sites

Sinon comme dit cockpitinferno, laurent65200 tu as juste à copier le contenu de ma fonction checkValidity et le coller dans la tienne.

Share this post


Link to post
Share on other sites

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 by Lgfx13 (see edit history)

Share this post


Link to post
Share on other sites

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 by cockpitinferno (see edit history)

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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:
* 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 license@prestashop.com 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 <contact@prestashop.com>
*  @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, $B)
{
if ($a == $B)
return 0;
 
$asplit = explode('-', $a);
$bsplit = explode('-', $B);
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).'%\'
');
}
}

Share this post


Link to post
Share on other sites

bonjour

 

up

 

programme parrainage

 

ref program

 

presta 1.5.4

 

pour que les bons créé automatiquement via parrainage ne soit pas cumulable 

 

merci

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

bonjour


 


up


 


programme parrainage


 


ref program


 


presta 1.5.4


 


pour que les bons créé automatiquement via parrainage ne soit pas cumulable 


 


merci

Share this post


Link to post
Share on other sites

 

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 ?

Share this post


Link to post
Share on other sites

Thank's a lot! It's works for me too ;)

 

P.S. Version 1.5.6

Share this post


Link to post
Share on other sites

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 ?

Share this post


Link to post
Share on other sites

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 :blink:

 

Impossible d'imposer un code promo sur une seule catégorie...

Share this post


Link to post
Share on other sites

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 :blink:

 

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...

Share this post


Link to post
Share on other sites

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...

Share this post


Link to post
Share on other sites

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 ? 

  • Like 1

Share this post


Link to post
Share on other sites

1.6.0.9 même problème!

 

Prestashop ça devient vraiment n'importe quoi!!!!  Sans compter le support du forum inexistant!

Share this post


Link to post
Share on other sites

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 !