Jump to content

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


Recommended Posts

  • 3 weeks later...

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
Link to comment
Share on other sites

  • 4 months later...

Urakawa41 : Ca c'est dans une version 1.4 non ?

Je cherche également à rendre non cumulable les bons de réduction. Il me semble que dans l'onglet condition, en bas se trouve plusieurs cases. Et plus précisément celle-ci : Compatibilité avec les autres règles paniers.

 

Il faut donc enlever les bons de réductions et les mettre dans la colonne non cumulables. Si quelqu'un peut confirmer ma manipulation.

 

Par contre, comment faire pour rendre directement un bon de réduction créé 'en code' non cumulable ?

Link to comment
Share on other sites

  • 2 months later...
  • 1 month later...

Je vous pose la question à vous.

 

Vous êtes dans la zone de rapport de bug, ce forum à des règles, en voici la substantifique moëlle :

 

Ainsi, avant de poster ici, il convient désormais de :

I - poster dans un autre forum.

II - vérifier que c'est bien un bug (en comparant avec d'autres utilisateurs)

III - si le bug est avéré, poster ici en n'oubliant pas de faire référence au post initial.

IV - déclarer le bug dans le bug tracker (en anglais) - si vous ne vous sentez pas de le faire (pas super doué/e en anglais), l'un des visiteurs le fera pour vous. Attention : les bugs postés en français dans le BT seront effacés sans pitié. ;-)

 

Sans ces prérequis la team risque fort de ne pas vous répondre.

Postez donc dans une partie plus appropriée, comme ici : http://www.prestashop.com/forums/forum/20-configuration-et-utilisation-de-prestashop/

Link to comment
Share on other sites

au cas ou vous n'auriez pas remarqué ce n'est pas moi qui ai posté là en 1er lieu.

et comme déjà dit plus haut cela a déjà été posté dans le bug tracker.

 

 

enfin, pour moi il s'agit d'un bug ou d'un oubli dans le sens ou cette fonctionnalité existait avant donc pour moi c'est pas une amélioration mais bien la correction d'un manque survenu après la mise à jour.

c'est donc effectivement un souhait de ma part de rétablir une fonctionnalité qui existait auparavant.

donc c'est à la fois un souhait et un bug...

Link to comment
Share on other sites

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)
Link to comment
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.

Link to comment
Share on other sites

  • 3 weeks later...

je relance un peu ce post car toujours pas de news. j'ai essayé de trifouiller du coté de cartrules.php

j'ai créé un bouton dans l'admin, et mis une dondition mais du coup j'ai le message d'erreur si le bouton est coché et même si c'est un produit non soldé ou sans promo.

il me manque la condition de l'article en promo.

 

un petit coup de pouce serait le bienvenu, vu que pas moyen d'obtenir la solution autrement, faut bien mettre les mains dans le camboui...

com d'hab...

Link to comment
Share on other sites

  • 1 month later...

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)
Link to comment
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

Link to comment
Share on other sites

  • 1 month later...

Bjr,

pour j'ai résolu, les fonctions de ps 1.5 ne permettant pas de régler les bons de réductions, de façon simple et claire,

et fonctionnant correctement, j'ai fais modifier par mes dev, un module que j'avais, pour l'utiliser en bon de réductions réglable et fonctionnel.

Il est possible de contacter les dev pour acheter le module, si vous en avez marre de galérer !

Link to comment
Share on other sites

le module je l'ai fait développer, donc a moi il m'a coûté plus chère que si vous l'achetez maintenant qu'il est fait!

 

Je ne sais pas combien ils le vendent, mais le prix doit être très correcte, contactez moi par MP pour avoir les coordonnées

de la société concerné.

Link to comment
Share on other sites

  • 1 month later...

hé bien ca n'est pas normal de payer pour une option qui est en natif sur la version 1.4.

 

ca n'est toujours pas résolu en 1.5 et franchement je désespère je ne sais pas en quelle langue il faut s'exprimer pour être entendu.

au moins si c'est fait exprès pour nous faire payer des modules qu'ils aient l'honneté de le dire mais là ca fait 1 an que j'attends (et je suis sure que je suis pas la seule) pour que cette option soit rétablie.

et là toujours rien...

Link to comment
Share on other sites

oui il y a plusieurs options qui devrait être d'origine sur une application de cette envergure, et qui nous oblige à acheter des modules, qui ne fonctionnent pas toujours très bien.

 

J'ai acheté aussi des modules qui ne fonctionnent pas sur addons, et pas de réponses des dev, du coups maintenant j'ai trouvé une société sérieuse et compétente, avec des prix très raisonnables, je préfère faire développer mes modules maintenant,

c'est plus sûr et au moins il y a un suivi dessus !

Link to comment
Share on other sites

  • 3 weeks later...

J'ai acheté aussi des modules qui ne fonctionnent pas sur addons, et pas de réponses des dev,

 

bonjour,

je suis dans le meme cas, j'ai acheté 2 modules sur addons, dont 1 avec l'option sérénité (j'aurai du prendre l'option "réponse aux emails des clients"...) et qui ont chacun un problème, mais je n'ai pas de réponse de presta ni de personne, après 4 ou 5 messages, dont 1 avec des codes.....

 

pourriez vous me donner le nom de cette société pour passer par eux ? ou un email, le site, etc...

 

merci d'avance

Link to comment
Share on other sites

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
Link to comment
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.

Link to comment
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
Link to comment
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
Link to comment
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
Link to comment
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
Link to comment
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 [email protected] so we can send you a copy 502immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
*  @author PrestaShop SA <[email protected]>
*  @copyright  2007-2013 PrestaShop SA
*  @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
*  International Registered Trademark & Property of PrestaShop SA
*/
 
class CartRuleCore extends ObjectModel
{
/* Filters used when retrieving the cart rules applied to a cart of when calculating the value of a reduction */
const FILTER_ACTION_ALL = 1;
const FILTER_ACTION_SHIPPING = 2;
const FILTER_ACTION_REDUCTION = 3;
const FILTER_ACTION_GIFT = 4;
const FILTER_ACTION_ALL_NOCAP = 5;
 
const BO_ORDER_CODE_PREFIX = 'BO_ORDER_';
 
/* This variable controls that a free gift is offered only once, even when multi-shippping is activated and the same product is delivered in both addresses */
protected static $only_one_gift = array();
 
public $id;
public $name;
public $id_customer;
public $date_from;
public $date_to;
public $description;
public $quantity = 1;
public $quantity_per_user = 1;
public $priority = 1;
public $partial_use = 1;
public $code;
public $minimum_amount;
public $minimum_amount_tax;
public $minimum_amount_currency;
public $minimum_amount_shipping;
public $country_restriction;
public $carrier_restriction;
public $group_restriction;
public $cart_rule_restriction;
public $product_restriction;
public $shop_restriction;
public $free_shipping;
public $reduction_percent;
public $reduction_amount;
public $reduction_tax;
public $reduction_currency;
public $reduction_product;
public $gift_product;
public $gift_product_attribute;
public $highlight;
public $active = 1;
public $date_add;
public $date_upd;
 
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'cart_rule',
'primary' => 'id_cart_rule',
'multilang' => true,
'fields' => array(
'id_customer' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'date_from' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => true),
'date_to' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => true),
'description' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 65534),
'quantity' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'quantity_per_user' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'priority' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'partial_use' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'code' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 254),
'minimum_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'minimum_amount_tax' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'minimum_amount_currency' =>array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'minimum_amount_shipping' =>array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'country_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'carrier_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'group_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'cart_rule_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'product_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'shop_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'free_shipping' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'reduction_percent' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPercentage'),
'reduction_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'reduction_tax' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'reduction_currency' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'reduction_product' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'gift_product' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'gift_product_attribute' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'highlight' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
 
// Lang fields
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCleanHtml', 'required' => true, 'size' => 254),
),
);
 
/**
* @see ObjectModel::add()
*/
public function add($autodate = true, $null_values = false)
{
if (!parent::add($autodate, $null_values))
return false;
 
Configuration::updateGlobalValue('PS_CART_RULE_FEATURE_ACTIVE', '1');
return true;
}
 
public function update($null_values = false)
{
Cache::clean('getContextualValue_'.$this->id.'_*');
return parent::update($null_values);
}
 
/**
* @see ObjectModel::delete()
*/
public function delete()
{
if (!parent::delete())
return false;
 
Configuration::updateGlobalValue('PS_CART_RULE_FEATURE_ACTIVE', CartRule::isCurrentlyUsed($this->def['table'], true));
 
$r = Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_cart_rule` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_carrier` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_shop` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_group` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_country` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_combination` WHERE `id_cart_rule_1` = '.(int)$this->id.' OR `id_cart_rule_2` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_group` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule` WHERE `id_product_rule_group` NOT IN (SELECT `id_product_rule_group` FROM `'._DB_PREFIX_.'cart_rule_product_rule_group`)');
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_value` WHERE `id_product_rule` NOT IN (SELECT `id_product_rule` FROM `'._DB_PREFIX_.'cart_rule_product_rule`)');
 
return $r;
}
 
/**
* Copy conditions from one cart rule to an other
*
* @static
* @param int $id_cart_rule_source
* @param int $id_cart_rule_destination
*/
public static function copyConditions($id_cart_rule_source, $id_cart_rule_destination)
{
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_shop` (`id_cart_rule`, `id_shop`)
(SELECT '.(int)$id_cart_rule_destination.', id_shop FROM `'._DB_PREFIX_.'cart_rule_shop` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')');
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_carrier` (`id_cart_rule`, `id_carrier`)
(SELECT '.(int)$id_cart_rule_destination.', id_carrier FROM `'._DB_PREFIX_.'cart_rule_carrier` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')');
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_group` (`id_cart_rule`, `id_group`)
(SELECT '.(int)$id_cart_rule_destination.', id_group FROM `'._DB_PREFIX_.'cart_rule_group` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')');
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_country` (`id_cart_rule`, `id_country`)
(SELECT '.(int)$id_cart_rule_destination.', id_country FROM `'._DB_PREFIX_.'cart_rule_country` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')');
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_combination` (`id_cart_rule_1`, `id_cart_rule_2`)
(SELECT '.(int)$id_cart_rule_destination.', IF(id_cart_rule_1 != '.(int)$id_cart_rule_source.', id_cart_rule_1, id_cart_rule_2) FROM `'._DB_PREFIX_.'cart_rule_combination`
WHERE `id_cart_rule_1` = '.(int)$id_cart_rule_source.' OR `id_cart_rule_2` = '.(int)$id_cart_rule_source.')');
 
// Todo : should be changed soon, be must be copied too
// Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule` WHERE `id_cart_rule` = '.(int)$this->id);
// Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_value` WHERE `id_product_rule` NOT IN (SELECT `id_product_rule` FROM `'._DB_PREFIX_.'cart_rule_product_rule`)');
}
 
/**
* Retrieves the id associated to the given code
*
* @static
* @param string $code
* @return int|bool
*/
public static function getIdByCode($code)
{
if (!Validate::isCleanHtml($code))
return false;
return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('SELECT `id_cart_rule` FROM `'._DB_PREFIX_.'cart_rule` WHERE `code` = \''.pSQL($code).'\'');
}
 
/**
* @static
* @param $id_lang
* @param $id_customer
* @param bool $active
* @param bool $includeGeneric
* @param bool $inStock
* @param Cart|null $cart
* @return array
*/
public static function getCustomerCartRules($id_lang, $id_customer, $active = false, $includeGeneric = true, $inStock = false, Cart $cart = null)
{
if (!CartRule::isFeatureActive())
return array();
 
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT *
FROM `'._DB_PREFIX_.'cart_rule` cr
LEFT JOIN `'._DB_PREFIX_.'cart_rule_lang` crl ON (cr.`id_cart_rule` = crl.`id_cart_rule` AND crl.`id_lang` = '.(int)$id_lang.')
WHERE (
cr.`id_customer` = '.(int)$id_customer.' OR cr.group_restriction = 1
'.($includeGeneric ? 'OR cr.`id_customer` = 0' : '').'
)
AND cr.date_from < "'.date('Y-m-d H:i:s').'"
AND cr.date_to > "'.date('Y-m-d H:i:s').'"
'.($active ? 'AND cr.`active` = 1' : '').'
'.($inStock ? 'AND cr.`quantity` > 0' : ''));
 
// Remove cart rule that does not match the customer groups
$customerGroups = Customer::getGroupsStatic($id_customer);
foreach ($result as $key => $cart_rule)
if ($cart_rule['group_restriction'])
{
$cartRuleGroups = Db::getInstance()->executeS('SELECT id_group FROM '._DB_PREFIX_.'cart_rule_group WHERE id_cart_rule = '.(int)$cart_rule['id_cart_rule']);
foreach ($cartRuleGroups as $cartRuleGroup)
if (in_array($cartRuleGroup['id_group'], $customerGroups))
continue 2;
 
unset($result[$key]);
}
 
foreach ($result as &$cart_rule)
if ($cart_rule['quantity_per_user'])
{
$quantity_used = Order::getDiscountsCustomer((int)$id_customer, (int)$cart_rule['id_cart_rule']);
if (isset($cart) && isset($cart->id))
$quantity_used += $cart->getDiscountsCustomer((int)$cart_rule['id_cart_rule']);
$cart_rule['quantity_for_user'] = $cart_rule['quantity_per_user'] - $quantity_used;
}
else
$cart_rule['quantity_for_user'] = 0;
 
// Retrocompatibility with 1.4 discounts
foreach ($result as &$cart_rule)
{
$cart_rule['value'] = 0;
$cart_rule['minimal'] = $cart_rule['minimum_amount'];
$cart_rule['cumulable'] = !$cart_rule['cart_rule_restriction'];
$cart_rule['id_discount_type'] = false;
if ($cart_rule['free_shipping'])
$cart_rule['id_discount_type'] = Discount::FREE_SHIPPING;
elseif ($cart_rule['reduction_percent'] > 0)
{
$cart_rule['id_discount_type'] = Discount::PERCENT;
$cart_rule['value'] = $cart_rule['reduction_percent'];
}
elseif ($cart_rule['reduction_amount'] > 0)
{
$cart_rule['id_discount_type'] = Discount::AMOUNT;
$cart_rule['value'] = $cart_rule['reduction_amount'];
}
}
 
return $result;
}
 
/**
* @param $id_customer
* @return bool
*/
public function usedByCustomer($id_customer)
{
return (bool)Db::getInstance()->getValue('
SELECT id_cart_rule
FROM `'._DB_PREFIX_.'order_cart_rule` ocr
LEFT JOIN `'._DB_PREFIX_.'orders` o ON ocr.`id_order` = o.`id_order`
WHERE ocr.`id_cart_rule` = '.(int)$this->id.'
AND o.`id_customer` = '.(int)$id_customer);
}
 
/**
* @static
* @param $name
* @return bool
*/
public static function cartRuleExists($name)
{
if (!CartRule::isFeatureActive())
return false;
 
return (bool)Db::getInstance()->getValue('
SELECT `id_cart_rule`
FROM `'._DB_PREFIX_.'cart_rule`
WHERE `code` = \''.pSQL($name).'\'');
}
 
/**
* @static
* @param $id_customer
* @return bool
*/
public static function deleteByIdCustomer($id_customer)
{
$return = true;
$cart_rules = new Collection('CartRule');
$cart_rules->where('id_customer', '=', $id_customer);
foreach ($cart_rules as $cart_rule)
$return &= $cart_rule->delete();
return $return;
}
 
/**
* @return array
*/
public function getProductRuleGroups()
{
if (!Validate::isLoadedObject($this) || $this->product_restriction == 0)
return array();
 
$productRuleGroups = array();
$results = Db::getInstance()->executeS('
SELECT *
FROM '._DB_PREFIX_.'cart_rule_product_rule_group prg
WHERE prg.id_cart_rule = '.(int)$this->id, false);
foreach ($results as $row)
{
if (!isset($productRuleGroups[$row['id_product_rule_group']]))
$productRuleGroups[$row['id_product_rule_group']] = array('id_product_rule_group' => $row['id_product_rule_group'], 'quantity' => $row['quantity']);
$productRuleGroups[$row['id_product_rule_group']]['product_rules'] = $this->getProductRules($row['id_product_rule_group']);
}
return $productRuleGroups;
}
 
/**
* @param $id_product_rule_group
* @return array ('type' => ? , 'values' => ?)
*/
public function getProductRules($id_product_rule_group)
{
if (!Validate::isLoadedObject($this) || $this->product_restriction == 0)
return array();
 
$productRules = array();
$results = Db::getInstance()->executeS('
SELECT *
FROM '._DB_PREFIX_.'cart_rule_product_rule pr
LEFT JOIN '._DB_PREFIX_.'cart_rule_product_rule_value prv ON pr.id_product_rule = prv.id_product_rule
WHERE pr.id_product_rule_group = '.(int)$id_product_rule_group);
foreach ($results as $row)
{
if (!isset($productRules[$row['id_product_rule']]))
$productRules[$row['id_product_rule']] = array('type' => $row['type'], 'values' => array());
$productRules[$row['id_product_rule']]['values'][] = $row['id_item'];
}
return $productRules;
}
 
/**
* Check if this cart rule can be applied
*
* @param Context $context
* @param bool $alreadyInCart Check if the voucher is already on the cart
* @param bool $display_error Display error
* @return bool|mixed|string
*/
public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true)
{
if (!CartRule::isFeatureActive())
return false;
 
if (!$this->active)
return (!$display_error) ? false : Tools::displayError('This voucher is disabled');
if (!$this->quantity)
return (!$display_error) ? false : Tools::displayError('This voucher has already been used');
if (strtotime($this->date_from) > time())
return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet');
if (strtotime($this->date_to) < time())
return (!$display_error) ? false : Tools::displayError('This voucher has expired');
 
if ($context->cart->id_customer)
{
$quantityUsed = Db::getInstance()->getValue('
SELECT count(*)
FROM '._DB_PREFIX_.'orders o
LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order
WHERE o.id_customer = '.$context->cart->id_customer.'
AND od.id_cart_rule = '.(int)$this->id.'
AND '.(int)Configuration::get('PS_OS_ERROR').' != (
SELECT oh.id_order_state
FROM '._DB_PREFIX_.'order_history oh
WHERE oh.id_order = o.id_order
ORDER BY oh.date_add DESC
LIMIT 1
)');
if ($quantityUsed + 1 > $this->quantity_per_user)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)');
}
 
// Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1)
if ($this->group_restriction)
{
$id_cart_rule = (int)Db::getInstance()->getValue('
SELECT crg.id_cart_rule
FROM '._DB_PREFIX_.'cart_rule_group crg
WHERE crg.id_cart_rule = '.(int)$this->id.'
AND crg.id_group '.($context->cart->id_customer ? 'IN (SELECT cg.id_group FROM '._DB_PREFIX_.'customer_group cg WHERE cg.id_customer = '.(int)$context->cart->id_customer.')' : '= 1'));
if (!$id_cart_rule)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
}
 
// Check if the customer delivery address is usable with the cart rule
if ($this->country_restriction)
{
if (!$context->cart->id_address_delivery)
return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order');
$id_cart_rule = (int)Db::getInstance()->getValue('
SELECT crc.id_cart_rule
FROM '._DB_PREFIX_.'cart_rule_country crc
WHERE crc.id_cart_rule = '.(int)$this->id.'
AND crc.id_country = (SELECT a.id_country FROM '._DB_PREFIX_.'address a WHERE a.id_address = '.(int)$context->cart->id_address_delivery.' LIMIT 1)');
if (!$id_cart_rule)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher in your country of delivery');
}
 
// Check if the carrier chosen by the customer is usable with the cart rule
if ($this->carrier_restriction)
{
if (!$context->cart->id_carrier)
return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order');
$id_cart_rule = (int)Db::getInstance()->getValue('
SELECT crc.id_cart_rule
FROM '._DB_PREFIX_.'cart_rule_carrier crc
INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0)
WHERE crc.id_cart_rule = '.(int)$this->id.'
AND c.id_carrier = '.(int)$context->cart->id_carrier);
if (!$id_cart_rule)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with this carrier');
}
 
// Check if the cart rules appliy to the shop browsed by the customer
if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive())
{
$id_cart_rule = (int)Db::getInstance()->getValue('
SELECT crs.id_cart_rule
FROM '._DB_PREFIX_.'cart_rule_shop crs
WHERE crs.id_cart_rule = '.(int)$this->id.'
AND crs.id_shop = '.(int)$context->shop->id);
if (!$id_cart_rule)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
}
 
// Check if the products chosen by the customer are usable with the cart rule
if ($this->product_restriction)
{
$r = $this->checkProductRestrictions($context, false, $display_error);
if ($r !== false && $display_error)
return $r;
elseif (!$r && !$display_error)
return false;
}
 
// Check if the cart rule is only usable by a specific customer, and if the current customer is the right one
if ($this->id_customer && $context->cart->id_customer != $this->id_customer)
{
if (!Context::getContext()->customer->isLogged())
return (!$display_error) ? false : (Tools::displayError('You cannot use this voucher').' - '.Tools::displayError('Please log in'));
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
}
 
if ($this->minimum_amount)
{
// Minimum amount is converted to the default currency
$minimum_amount = $this->minimum_amount;
if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT'))
{
$minimum_amount_currency = new Currency($this->minimum_amount_currency);
if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0)
$minimum_amount = 0;
else
$minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate;
}
 
$cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS);
if ($this->minimum_amount_shipping)
$cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING);
 
// If a product is given for free in this rule and already in the cart, the price is subtracted
if ($this->gift_product && $alreadyInCart)
{
$query = new DbQuery();
 
$query->select('id_product');
$query->from('cart_product');
$query->where('id_product = '.(int)$this->gift_product);
$query->where('id_cart = '.(int)$context->cart->id);
 
if ((int)$this->gift_product_attribute)
$query->where('id_product_attribute = '.(int)$this->gift_product_attribute);
 
if (Db::getInstance()->getValue($query))
{
$ref = false;
$product_price = Product::getPriceStatic(
$this->gift_product,
$this->minimum_amount_tax,
$this->gift_product_attribute,
null, null, false, true, 1, null,
$context->cart->id_customer ? $context->cart->id_customer : null,
$context->cart->id,
(int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null,
$ref, true, true, $context, true
);
$cartTotal -= $product_price;
}
}
 
if ($cartTotal < $minimum_amount)
return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher');
}
 
// Check if the voucher is already in the cart of if a non compatible voucher is in the cart
// Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them
$otherCartRules = $context->cart->getCartRules();
if (count($otherCartRules))
foreach ($otherCartRules as $otherCartRule)
{
if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart)
return (!$display_error) ? false : Tools::displayError('This voucher is already in your cart');
if ($this->cart_rule_restriction && $otherCartRule['cart_rule_restriction'] && $otherCartRule['id_cart_rule'] != $this->id)
{
$combinable = Db::getInstance()->getValue('
SELECT id_cart_rule_1
FROM '._DB_PREFIX_.'cart_rule_combination
WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].')
OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')');
if (!$combinable)
{
$cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang);
// The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested
if ($cart_rule->priority <= $this->priority)
return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name;
// But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one
else
$context->cart->removeCartRule($cart_rule->id);
}
}
}
 
if (!$display_error)
return true;
}
 
protected function checkProductRestrictions(Context $context, $return_products = false, $display_error = true)
{
$selectedProducts = array();
 
// Check if the products chosen by the customer are usable with the cart rule
if ($this->product_restriction)
{
$productRuleGroups = $this->getProductRuleGroups();
foreach ($productRuleGroups as $id_product_rule_group => $productRuleGroup)
{
$eligibleProductsList = array();
foreach ($context->cart->getProducts() as $product)
$eligibleProductsList[] = (int)$product['id_product'].'-'.(int)$product['id_product_attribute'];
if (!count($eligibleProductsList))
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher in an empty cart');
 
$productRules = $this->getProductRules($id_product_rule_group);
foreach ($productRules as $productRule)
{
switch ($productRule['type'])
{
case 'attributes':
$cartAttributes = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`, pac.`id_attribute`, cp.`id_product_attribute`
FROM `'._DB_PREFIX_.'cart_product` cp
LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON cp.id_product_attribute = pac.id_product_attribute
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')
AND cp.id_product_attribute > 0');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartAttributes as $cartAttribute)
if (in_array($cartAttribute['id_attribute'], $productRule['values']))
{
$countMatchingProducts += $cartAttribute['quantity'];
$matchingProductsList[] = $cartAttribute['id_product'].'-'.$cartAttribute['id_product_attribute'];
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
case 'products':
$cartProducts = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`
FROM `'._DB_PREFIX_.'cart_product` cp
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartProducts as $cartProduct)
if (in_array($cartProduct['id_product'], $productRule['values']))
{
$countMatchingProducts += $cartProduct['quantity'];
$matchingProductsList[] = $cartProduct['id_product'].'-0';
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
case 'categories':
$cartCategories = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`, cp.`id_product_attribute`, catp.`id_category`
FROM `'._DB_PREFIX_.'cart_product` cp
LEFT JOIN `'._DB_PREFIX_.'category_product` catp ON cp.id_product = catp.id_product
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartCategories as $cartCategory)
if (in_array($cartCategory['id_category'], $productRule['values'])
// We also check that the product is not already in the matching product list, because there are doubles in the query results (when the product is in multiple categories)
&& !in_array($cartCategory['id_product'].'-'.$cartCategory['id_product_attribute'], $matchingProductsList))
{
$countMatchingProducts += $cartCategory['quantity'];
$matchingProductsList[] = $cartCategory['id_product'].'-'.$cartCategory['id_product_attribute'];
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
// Attribute id is not important for this filter in the global list, so the ids are replaced by 0
foreach ($matchingProductsList as &$matchingProduct)
$matchingProduct = preg_replace('/^([0-9]+)-[0-9]+$/', '$1-0', $matchingProduct);
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
case 'manufacturers':
$cartManufacturers = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`, p.`id_manufacturer`
FROM `'._DB_PREFIX_.'cart_product` cp
LEFT JOIN `'._DB_PREFIX_.'product` p ON cp.id_product = p.id_product
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartManufacturers as $cartManufacturer)
if (in_array($cartManufacturer['id_manufacturer'], $productRule['values']))
{
$countMatchingProducts += $cartManufacturer['quantity'];
$matchingProductsList[] = $cartManufacturer['id_product'].'-0';
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
case 'suppliers':
$cartSuppliers = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`, p.`id_supplier`
FROM `'._DB_PREFIX_.'cart_product` cp
LEFT JOIN `'._DB_PREFIX_.'product` p ON cp.id_product = p.id_product
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartSuppliers as $cartSupplier)
if (in_array($cartSupplier['id_supplier'], $productRule['values']))
{
$countMatchingProducts += $cartSupplier['quantity'];
$matchingProductsList[] = $cartSupplier['id_product'].'-0';
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
}
 
if (!count($eligibleProductsList))
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
}
$selectedProducts = array_merge($selectedProducts, $eligibleProductsList);
}
}
 
if ($return_products)
return $selectedProducts;
return (!$display_error) ? true : false;
}
 
protected static function array_uintersect($array1, $array2)
{
$intersection = array();
foreach ($array1 as $value1)
foreach ($array2 as $value2)
if (CartRule::array_uintersect_compare($value1, $value2) == 0)
{
$intersection[] = $value1;
break 1;
}
return $intersection;
}
 
protected static function array_uintersect_compare($a, $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).'%\'
');
}
}
Link to comment
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. 

Link to comment
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)
Link to comment
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.

Link to comment
Share on other sites

  • 2 weeks later...

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 [email protected] so we can send you a copy 502immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
*  @author PrestaShop SA <[email protected]>
*  @copyright  2007-2013 PrestaShop SA
*  @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
*  International Registered Trademark & Property of PrestaShop SA
*/
 
class CartRuleCore extends ObjectModel
{
/* Filters used when retrieving the cart rules applied to a cart of when calculating the value of a reduction */
const FILTER_ACTION_ALL = 1;
const FILTER_ACTION_SHIPPING = 2;
const FILTER_ACTION_REDUCTION = 3;
const FILTER_ACTION_GIFT = 4;
const FILTER_ACTION_ALL_NOCAP = 5;
 
const BO_ORDER_CODE_PREFIX = 'BO_ORDER_';
 
/* This variable controls that a free gift is offered only once, even when multi-shippping is activated and the same product is delivered in both addresses */
protected static $only_one_gift = array();
 
public $id;
public $name;
public $id_customer;
public $date_from;
public $date_to;
public $description;
public $quantity = 1;
public $quantity_per_user = 1;
public $priority = 1;
public $partial_use = 1;
public $code;
public $minimum_amount;
public $minimum_amount_tax;
public $minimum_amount_currency;
public $minimum_amount_shipping;
public $country_restriction;
public $carrier_restriction;
public $group_restriction;
public $cart_rule_restriction;
public $product_restriction;
public $shop_restriction;
public $free_shipping;
public $reduction_percent;
public $reduction_amount;
public $reduction_tax;
public $reduction_currency;
public $reduction_product;
public $gift_product;
public $gift_product_attribute;
public $highlight;
public $active = 1;
public $date_add;
public $date_upd;
 
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'cart_rule',
'primary' => 'id_cart_rule',
'multilang' => true,
'fields' => array(
'id_customer' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'date_from' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => true),
'date_to' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => true),
'description' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 65534),
'quantity' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'quantity_per_user' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'priority' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'partial_use' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'code' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 254),
'minimum_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'minimum_amount_tax' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'minimum_amount_currency' =>array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'minimum_amount_shipping' =>array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'country_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'carrier_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'group_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'cart_rule_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'product_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'shop_restriction' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'free_shipping' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'reduction_percent' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPercentage'),
'reduction_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'reduction_tax' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'reduction_currency' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'reduction_product' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'gift_product' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'gift_product_attribute' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'highlight' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
 
// Lang fields
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCleanHtml', 'required' => true, 'size' => 254),
),
);
 
/**
* @see ObjectModel::add()
*/
public function add($autodate = true, $null_values = false)
{
if (!parent::add($autodate, $null_values))
return false;
 
Configuration::updateGlobalValue('PS_CART_RULE_FEATURE_ACTIVE', '1');
return true;
}
 
public function update($null_values = false)
{
Cache::clean('getContextualValue_'.$this->id.'_*');
return parent::update($null_values);
}
 
/**
* @see ObjectModel::delete()
*/
public function delete()
{
if (!parent::delete())
return false;
 
Configuration::updateGlobalValue('PS_CART_RULE_FEATURE_ACTIVE', CartRule::isCurrentlyUsed($this->def['table'], true));
 
$r = Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_cart_rule` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_carrier` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_shop` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_group` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_country` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_combination` WHERE `id_cart_rule_1` = '.(int)$this->id.' OR `id_cart_rule_2` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_group` WHERE `id_cart_rule` = '.(int)$this->id);
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule` WHERE `id_product_rule_group` NOT IN (SELECT `id_product_rule_group` FROM `'._DB_PREFIX_.'cart_rule_product_rule_group`)');
$r &= Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_value` WHERE `id_product_rule` NOT IN (SELECT `id_product_rule` FROM `'._DB_PREFIX_.'cart_rule_product_rule`)');
 
return $r;
}
 
/**
* Copy conditions from one cart rule to an other
*
* @static
* @param int $id_cart_rule_source
* @param int $id_cart_rule_destination
*/
public static function copyConditions($id_cart_rule_source, $id_cart_rule_destination)
{
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_shop` (`id_cart_rule`, `id_shop`)
(SELECT '.(int)$id_cart_rule_destination.', id_shop FROM `'._DB_PREFIX_.'cart_rule_shop` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')');
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_carrier` (`id_cart_rule`, `id_carrier`)
(SELECT '.(int)$id_cart_rule_destination.', id_carrier FROM `'._DB_PREFIX_.'cart_rule_carrier` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')');
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_group` (`id_cart_rule`, `id_group`)
(SELECT '.(int)$id_cart_rule_destination.', id_group FROM `'._DB_PREFIX_.'cart_rule_group` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')');
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_country` (`id_cart_rule`, `id_country`)
(SELECT '.(int)$id_cart_rule_destination.', id_country FROM `'._DB_PREFIX_.'cart_rule_country` WHERE `id_cart_rule` = '.(int)$id_cart_rule_source.')');
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'cart_rule_combination` (`id_cart_rule_1`, `id_cart_rule_2`)
(SELECT '.(int)$id_cart_rule_destination.', IF(id_cart_rule_1 != '.(int)$id_cart_rule_source.', id_cart_rule_1, id_cart_rule_2) FROM `'._DB_PREFIX_.'cart_rule_combination`
WHERE `id_cart_rule_1` = '.(int)$id_cart_rule_source.' OR `id_cart_rule_2` = '.(int)$id_cart_rule_source.')');
 
// Todo : should be changed soon, be must be copied too
// Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule` WHERE `id_cart_rule` = '.(int)$this->id);
// Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'cart_rule_product_rule_value` WHERE `id_product_rule` NOT IN (SELECT `id_product_rule` FROM `'._DB_PREFIX_.'cart_rule_product_rule`)');
}
 
/**
* Retrieves the id associated to the given code
*
* @static
* @param string $code
* @return int|bool
*/
public static function getIdByCode($code)
{
if (!Validate::isCleanHtml($code))
return false;
return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('SELECT `id_cart_rule` FROM `'._DB_PREFIX_.'cart_rule` WHERE `code` = \''.pSQL($code).'\'');
}
 
/**
* @static
* @param $id_lang
* @param $id_customer
* @param bool $active
* @param bool $includeGeneric
* @param bool $inStock
* @param Cart|null $cart
* @return array
*/
public static function getCustomerCartRules($id_lang, $id_customer, $active = false, $includeGeneric = true, $inStock = false, Cart $cart = null)
{
if (!CartRule::isFeatureActive())
return array();
 
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT *
FROM `'._DB_PREFIX_.'cart_rule` cr
LEFT JOIN `'._DB_PREFIX_.'cart_rule_lang` crl ON (cr.`id_cart_rule` = crl.`id_cart_rule` AND crl.`id_lang` = '.(int)$id_lang.')
WHERE (
cr.`id_customer` = '.(int)$id_customer.' OR cr.group_restriction = 1
'.($includeGeneric ? 'OR cr.`id_customer` = 0' : '').'
)
AND cr.date_from < "'.date('Y-m-d H:i:s').'"
AND cr.date_to > "'.date('Y-m-d H:i:s').'"
'.($active ? 'AND cr.`active` = 1' : '').'
'.($inStock ? 'AND cr.`quantity` > 0' : ''));
 
// Remove cart rule that does not match the customer groups
$customerGroups = Customer::getGroupsStatic($id_customer);
foreach ($result as $key => $cart_rule)
if ($cart_rule['group_restriction'])
{
$cartRuleGroups = Db::getInstance()->executeS('SELECT id_group FROM '._DB_PREFIX_.'cart_rule_group WHERE id_cart_rule = '.(int)$cart_rule['id_cart_rule']);
foreach ($cartRuleGroups as $cartRuleGroup)
if (in_array($cartRuleGroup['id_group'], $customerGroups))
continue 2;
 
unset($result[$key]);
}
 
foreach ($result as &$cart_rule)
if ($cart_rule['quantity_per_user'])
{
$quantity_used = Order::getDiscountsCustomer((int)$id_customer, (int)$cart_rule['id_cart_rule']);
if (isset($cart) && isset($cart->id))
$quantity_used += $cart->getDiscountsCustomer((int)$cart_rule['id_cart_rule']);
$cart_rule['quantity_for_user'] = $cart_rule['quantity_per_user'] - $quantity_used;
}
else
$cart_rule['quantity_for_user'] = 0;
 
// Retrocompatibility with 1.4 discounts
foreach ($result as &$cart_rule)
{
$cart_rule['value'] = 0;
$cart_rule['minimal'] = $cart_rule['minimum_amount'];
$cart_rule['cumulable'] = !$cart_rule['cart_rule_restriction'];
$cart_rule['id_discount_type'] = false;
if ($cart_rule['free_shipping'])
$cart_rule['id_discount_type'] = Discount::FREE_SHIPPING;
elseif ($cart_rule['reduction_percent'] > 0)
{
$cart_rule['id_discount_type'] = Discount::PERCENT;
$cart_rule['value'] = $cart_rule['reduction_percent'];
}
elseif ($cart_rule['reduction_amount'] > 0)
{
$cart_rule['id_discount_type'] = Discount::AMOUNT;
$cart_rule['value'] = $cart_rule['reduction_amount'];
}
}
 
return $result;
}
 
/**
* @param $id_customer
* @return bool
*/
public function usedByCustomer($id_customer)
{
return (bool)Db::getInstance()->getValue('
SELECT id_cart_rule
FROM `'._DB_PREFIX_.'order_cart_rule` ocr
LEFT JOIN `'._DB_PREFIX_.'orders` o ON ocr.`id_order` = o.`id_order`
WHERE ocr.`id_cart_rule` = '.(int)$this->id.'
AND o.`id_customer` = '.(int)$id_customer);
}
 
/**
* @static
* @param $name
* @return bool
*/
public static function cartRuleExists($name)
{
if (!CartRule::isFeatureActive())
return false;
 
return (bool)Db::getInstance()->getValue('
SELECT `id_cart_rule`
FROM `'._DB_PREFIX_.'cart_rule`
WHERE `code` = \''.pSQL($name).'\'');
}
 
/**
* @static
* @param $id_customer
* @return bool
*/
public static function deleteByIdCustomer($id_customer)
{
$return = true;
$cart_rules = new Collection('CartRule');
$cart_rules->where('id_customer', '=', $id_customer);
foreach ($cart_rules as $cart_rule)
$return &= $cart_rule->delete();
return $return;
}
 
/**
* @return array
*/
public function getProductRuleGroups()
{
if (!Validate::isLoadedObject($this) || $this->product_restriction == 0)
return array();
 
$productRuleGroups = array();
$results = Db::getInstance()->executeS('
SELECT *
FROM '._DB_PREFIX_.'cart_rule_product_rule_group prg
WHERE prg.id_cart_rule = '.(int)$this->id, false);
foreach ($results as $row)
{
if (!isset($productRuleGroups[$row['id_product_rule_group']]))
$productRuleGroups[$row['id_product_rule_group']] = array('id_product_rule_group' => $row['id_product_rule_group'], 'quantity' => $row['quantity']);
$productRuleGroups[$row['id_product_rule_group']]['product_rules'] = $this->getProductRules($row['id_product_rule_group']);
}
return $productRuleGroups;
}
 
/**
* @param $id_product_rule_group
* @return array ('type' => ? , 'values' => ?)
*/
public function getProductRules($id_product_rule_group)
{
if (!Validate::isLoadedObject($this) || $this->product_restriction == 0)
return array();
 
$productRules = array();
$results = Db::getInstance()->executeS('
SELECT *
FROM '._DB_PREFIX_.'cart_rule_product_rule pr
LEFT JOIN '._DB_PREFIX_.'cart_rule_product_rule_value prv ON pr.id_product_rule = prv.id_product_rule
WHERE pr.id_product_rule_group = '.(int)$id_product_rule_group);
foreach ($results as $row)
{
if (!isset($productRules[$row['id_product_rule']]))
$productRules[$row['id_product_rule']] = array('type' => $row['type'], 'values' => array());
$productRules[$row['id_product_rule']]['values'][] = $row['id_item'];
}
return $productRules;
}
 
/**
* Check if this cart rule can be applied
*
* @param Context $context
* @param bool $alreadyInCart Check if the voucher is already on the cart
* @param bool $display_error Display error
* @return bool|mixed|string
*/
public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true)
{
if (!CartRule::isFeatureActive())
return false;
 
if (!$this->active)
return (!$display_error) ? false : Tools::displayError('This voucher is disabled');
if (!$this->quantity)
return (!$display_error) ? false : Tools::displayError('This voucher has already been used');
if (strtotime($this->date_from) > time())
return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet');
if (strtotime($this->date_to) < time())
return (!$display_error) ? false : Tools::displayError('This voucher has expired');
$products = $context->cart->getProducts();
$product_on_sale = false;
foreach($products as $product){
if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0)
$product_on_sale = true;
}
if ($product_on_sale)
return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale');
if ($context->cart->id_customer)
{
$quantityUsed = Db::getInstance()->getValue('
SELECT count(*)
FROM '._DB_PREFIX_.'orders o
LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order
WHERE o.id_customer = '.$context->cart->id_customer.'
AND od.id_cart_rule = '.(int)$this->id.'
AND '.(int)Configuration::get('PS_OS_ERROR').' != (
SELECT oh.id_order_state
FROM '._DB_PREFIX_.'order_history oh
WHERE oh.id_order = o.id_order
ORDER BY oh.date_add DESC
LIMIT 1
)');
if ($quantityUsed + 1 > $this->quantity_per_user)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)');
}
 
// Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1)
if ($this->group_restriction)
{
$id_cart_rule = (int)Db::getInstance()->getValue('
SELECT crg.id_cart_rule
FROM '._DB_PREFIX_.'cart_rule_group crg
WHERE crg.id_cart_rule = '.(int)$this->id.'
AND crg.id_group '.($context->cart->id_customer ? 'IN (SELECT cg.id_group FROM '._DB_PREFIX_.'customer_group cg WHERE cg.id_customer = '.(int)$context->cart->id_customer.')' : '= 1'));
if (!$id_cart_rule)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
}
 
// Check if the customer delivery address is usable with the cart rule
if ($this->country_restriction)
{
if (!$context->cart->id_address_delivery)
return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order');
$id_cart_rule = (int)Db::getInstance()->getValue('
SELECT crc.id_cart_rule
FROM '._DB_PREFIX_.'cart_rule_country crc
WHERE crc.id_cart_rule = '.(int)$this->id.'
AND crc.id_country = (SELECT a.id_country FROM '._DB_PREFIX_.'address a WHERE a.id_address = '.(int)$context->cart->id_address_delivery.' LIMIT 1)');
if (!$id_cart_rule)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher in your country of delivery');
}
 
// Check if the carrier chosen by the customer is usable with the cart rule
if ($this->carrier_restriction)
{
if (!$context->cart->id_carrier)
return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order');
$id_cart_rule = (int)Db::getInstance()->getValue('
SELECT crc.id_cart_rule
FROM '._DB_PREFIX_.'cart_rule_carrier crc
INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0)
WHERE crc.id_cart_rule = '.(int)$this->id.'
AND c.id_carrier = '.(int)$context->cart->id_carrier);
if (!$id_cart_rule)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with this carrier');
}
 
// Check if the cart rules appliy to the shop browsed by the customer
if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive())
{
$id_cart_rule = (int)Db::getInstance()->getValue('
SELECT crs.id_cart_rule
FROM '._DB_PREFIX_.'cart_rule_shop crs
WHERE crs.id_cart_rule = '.(int)$this->id.'
AND crs.id_shop = '.(int)$context->shop->id);
if (!$id_cart_rule)
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
}
 
// Check if the products chosen by the customer are usable with the cart rule
if ($this->product_restriction)
{
$r = $this->checkProductRestrictions($context, false, $display_error);
if ($r !== false && $display_error)
return $r;
elseif (!$r && !$display_error)
return false;
}
 
// Check if the cart rule is only usable by a specific customer, and if the current customer is the right one
if ($this->id_customer && $context->cart->id_customer != $this->id_customer)
{
if (!Context::getContext()->customer->isLogged())
return (!$display_error) ? false : (Tools::displayError('You cannot use this voucher').' - '.Tools::displayError('Please log in'));
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
}
 
if ($this->minimum_amount)
{
// Minimum amount is converted to the default currency
$minimum_amount = $this->minimum_amount;
if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT'))
{
$minimum_amount_currency = new Currency($this->minimum_amount_currency);
if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0)
$minimum_amount = 0;
else
$minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate;
}
 
$cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS);
if ($this->minimum_amount_shipping)
$cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING);
 
// If a product is given for free in this rule and already in the cart, the price is subtracted
if ($this->gift_product && $alreadyInCart)
{
$query = new DbQuery();
 
$query->select('id_product');
$query->from('cart_product');
$query->where('id_product = '.(int)$this->gift_product);
$query->where('id_cart = '.(int)$context->cart->id);
 
if ((int)$this->gift_product_attribute)
$query->where('id_product_attribute = '.(int)$this->gift_product_attribute);
 
if (Db::getInstance()->getValue($query))
{
$ref = false;
$product_price = Product::getPriceStatic(
$this->gift_product,
$this->minimum_amount_tax,
$this->gift_product_attribute,
null, null, false, true, 1, null,
$context->cart->id_customer ? $context->cart->id_customer : null,
$context->cart->id,
(int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null,
$ref, true, true, $context, true
);
$cartTotal -= $product_price;
}
}
 
if ($cartTotal < $minimum_amount)
return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher');
}
 
// Check if the voucher is already in the cart of if a non compatible voucher is in the cart
// Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them
$otherCartRules = $context->cart->getCartRules();
if (count($otherCartRules))
foreach ($otherCartRules as $otherCartRule)
{
if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart)
return (!$display_error) ? false : Tools::displayError('This voucher is already in your cart');
if ($this->cart_rule_restriction && $otherCartRule['cart_rule_restriction'] && $otherCartRule['id_cart_rule'] != $this->id)
{
$combinable = Db::getInstance()->getValue('
SELECT id_cart_rule_1
FROM '._DB_PREFIX_.'cart_rule_combination
WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].')
OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')');
if (!$combinable)
{
$cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang);
// The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested
if ($cart_rule->priority <= $this->priority)
return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name;
// But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one
else
$context->cart->removeCartRule($cart_rule->id);
}
}
}
 
if (!$display_error)
return true;
}
protected function checkProductRestrictions(Context $context, $return_products = false, $display_error = true)
{
$selectedProducts = array();
 
// Check if the products chosen by the customer are usable with the cart rule
if ($this->product_restriction)
{
$productRuleGroups = $this->getProductRuleGroups();
foreach ($productRuleGroups as $id_product_rule_group => $productRuleGroup)
{
$eligibleProductsList = array();
foreach ($context->cart->getProducts() as $product)
$eligibleProductsList[] = (int)$product['id_product'].'-'.(int)$product['id_product_attribute'];
if (!count($eligibleProductsList))
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher in an empty cart');
 
$productRules = $this->getProductRules($id_product_rule_group);
foreach ($productRules as $productRule)
{
switch ($productRule['type'])
{
case 'attributes':
$cartAttributes = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`, pac.`id_attribute`, cp.`id_product_attribute`
FROM `'._DB_PREFIX_.'cart_product` cp
LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON cp.id_product_attribute = pac.id_product_attribute
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')
AND cp.id_product_attribute > 0');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartAttributes as $cartAttribute)
if (in_array($cartAttribute['id_attribute'], $productRule['values']))
{
$countMatchingProducts += $cartAttribute['quantity'];
$matchingProductsList[] = $cartAttribute['id_product'].'-'.$cartAttribute['id_product_attribute'];
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
case 'products':
$cartProducts = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`
FROM `'._DB_PREFIX_.'cart_product` cp
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartProducts as $cartProduct)
if (in_array($cartProduct['id_product'], $productRule['values']))
{
$countMatchingProducts += $cartProduct['quantity'];
$matchingProductsList[] = $cartProduct['id_product'].'-0';
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
case 'categories':
$cartCategories = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`, cp.`id_product_attribute`, catp.`id_category`
FROM `'._DB_PREFIX_.'cart_product` cp
LEFT JOIN `'._DB_PREFIX_.'category_product` catp ON cp.id_product = catp.id_product
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartCategories as $cartCategory)
if (in_array($cartCategory['id_category'], $productRule['values'])
// We also check that the product is not already in the matching product list, because there are doubles in the query results (when the product is in multiple categories)
&& !in_array($cartCategory['id_product'].'-'.$cartCategory['id_product_attribute'], $matchingProductsList))
{
$countMatchingProducts += $cartCategory['quantity'];
$matchingProductsList[] = $cartCategory['id_product'].'-'.$cartCategory['id_product_attribute'];
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
// Attribute id is not important for this filter in the global list, so the ids are replaced by 0
foreach ($matchingProductsList as &$matchingProduct)
$matchingProduct = preg_replace('/^([0-9]+)-[0-9]+$/', '$1-0', $matchingProduct);
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
case 'manufacturers':
$cartManufacturers = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`, p.`id_manufacturer`
FROM `'._DB_PREFIX_.'cart_product` cp
LEFT JOIN `'._DB_PREFIX_.'product` p ON cp.id_product = p.id_product
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartManufacturers as $cartManufacturer)
if (in_array($cartManufacturer['id_manufacturer'], $productRule['values']))
{
$countMatchingProducts += $cartManufacturer['quantity'];
$matchingProductsList[] = $cartManufacturer['id_product'].'-0';
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
case 'suppliers':
$cartSuppliers = Db::getInstance()->executeS('
SELECT cp.quantity, cp.`id_product`, p.`id_supplier`
FROM `'._DB_PREFIX_.'cart_product` cp
LEFT JOIN `'._DB_PREFIX_.'product` p ON cp.id_product = p.id_product
WHERE cp.`id_cart` = '.(int)$context->cart->id.'
AND cp.`id_product` IN ('.implode(array_map('intval', $eligibleProductsList), ',').')');
$countMatchingProducts = 0;
$matchingProductsList = array();
foreach ($cartSuppliers as $cartSupplier)
if (in_array($cartSupplier['id_supplier'], $productRule['values']))
{
$countMatchingProducts += $cartSupplier['quantity'];
$matchingProductsList[] = $cartSupplier['id_product'].'-0';
}
if ($countMatchingProducts < $productRuleGroup['quantity'])
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
$eligibleProductsList = CartRule::array_uintersect($eligibleProductsList, $matchingProductsList);
break;
}
 
if (!count($eligibleProductsList))
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with these products');
}
$selectedProducts = array_merge($selectedProducts, $eligibleProductsList);
}
}
 
if ($return_products)
return $selectedProducts;
return (!$display_error) ? true : false;
}
 
protected static function array_uintersect($array1, $array2)
{
$intersection = array();
foreach ($array1 as $value1)
foreach ($array2 as $value2)
if (CartRule::array_uintersect_compare($value1, $value2) == 0)
{
$intersection[] = $value1;
break 1;
}
return $intersection;
}
 
protected static function array_uintersect_compare($a, $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).'%\'
');
}
}
Link to comment
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.

Link to comment
Share on other sites

  • 2 weeks later...
  • 1 month later...
  • 3 weeks later...

c'est scandaleux que cette option même sur la 1.5.6.1 ne soit pas présente et qu'il faut modifier!
J'ai passé le site d'un client d'une 1.4 à une 1.5.6.1 tout semblait fonctionner je me suis absenté et il s'est retrouvé avec une dizaines de commandes qui ont cumulé bon de réduction et promotions !!!

Soit ne pas mettre cette fonctionnalité du tout soit la corriger ! Mais svp ne pas laisser des bugs aussi gros comme ça! Ca représente des heures de prises de tête pour des centaines de personnes juste car cette modif gentillement proposée par Manuel Corbet n'a pas été faite dans le code du site!

Est-ce que Prestashop est au courant de ce bug? Ils pensent le corriger ou il va y avoir encore des pages de forum écrites par des utilisateurs qui perdent la tête ?

Link to comment
Share on other sites

  • 2 months later...

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

Link to comment
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...

Link to comment
Share on other sites

  • 3 weeks later...

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
Link to comment
Share on other sites

  • 6 months later...

Bonjour,

 

en effet cela était possible en 1.4 mais pas en 1.5 ...

 

En faisant l'override de la classe CartRule on s'en sort très bien !

Donc si votre besoin est seulement de permettre de bloquer les bons sur les produits en promos, ne vous faite pas "arnaquer" avec l'achat d'un module, il suffit de rajouter quelques lignes de codes, rien de bien sorcié ...

 

Il s'agit de la méthode "public function checkValidity" :

il faut rajouter : 

$products = $context->cart->getProducts();
$product_on_sale = false;
foreach($products as $product){
	if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0)
		$product_on_sale = true;
}
if ($product_on_sale)
	return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale');

Il faut place cela après le code suivant : (je vous incite fortement à utiliser l'override pour faire la modification.)

if (strtotime($this->date_to) < time())
     return (!$display_error) ? false : Tools::displayError('This voucher has expired');

Cordialement,

Bonjour,

 

Merci beaucoup !

Edited by popeyerubis (see edit history)
Link to comment
Share on other sites

je viens de faire la modif sur 1.6.0.1 en local et ca fonctionne.

maintenant qqun saurait il comment faire pour que le code promo soit valable sur un panier qui contient une promo mais qui ne s'applique que sur le produit pas en promo.

ex 'ai un produit à -50% et un autre sans reduc dans mon panier, mais j'ai aussi un code promo de -10%, je voudrais que ce code s'applique au produit pas en promo seulement.

 

sinon

j'ai voté pour ce post: http://feedback.pres...ouchers-coupons

 

ce serait bien que d'autres le fasse si on veut que ca change de ce coté là.

Edited by cockpitinferno (see edit history)
  • Like 1
Link to comment
Share on other sites

  • 2 months later...
  • 4 weeks later...

Je viens de trouver une solution que je teste. C'est un peu emm*dant.

1- Il faut dans l'onglet "conditions" sélectionner les produits qui seront impactés par la bon de réduction et retirer les produits déjà soldés manuellement.

2- Dans un second temps, il faut passer à l'onglet "actions" toujours dans les "règles paniers" et activer "Le(s) produit(s) sélectionné(s)". Comme les produits "soldés" n'ont pas été sélectionnés, ils n'entrent pas dans le bon de réduction et les produits non soldés subissent eux bien la réduction que vous avez décidé ^^

 

PS: Un pti bouton radio comme dans la PS 1.4 serait plus pratique amha

Link to comment
Share on other sites

Ben si tu n'as plus de solde ni de promotion, il suffit de faire "sauter" ces critères restrictifs (icône croix ) pour retrouver ta boutique avec des bons de réduction classiques qui s'appliquent à tous les produits.

La chose à faire en période de solde, c'est de sélectionner les produits qui n'entrent pas dans le bon de réduction édité. Ca peut être assez galère si tu as beaucoup de produits en promotion.

Une autre solution est de créer , si tu ne t'en sers pas, un fabriquant appelé "solde" par exemple et d'y associer touts les produits en promotion, tu fais une exclusion du fabriquant "solde"...

  • Like 1
Link to comment
Share on other sites

  • 6 months later...
  • 1 month later...

Bonjour,

J'avais le même problème sur la version 1.6.0.9 que j'ai résolue avec un petit module développé par IBS on line (bizarrement impossible de retrouver ce module dans addons.) qui fonctionnait super bien jusqu'à ce que je passe sur la dernière version 1.6.1.1 

Je me retrouve à nouveau avec des codes promo cumulable avec mes promotions.

Si quelqu'un à une solution ???

Merci d'avance

Link to comment
Share on other sites

  • 3 weeks later...

Pour ma part, je n'autorise pas les codes promos sur les paniers contenant un article avec un prix réduit.

 

Si on ajout un article en promo après avoir ajouté un code de réduction dans le panier, le code de réduction est retiré. 

 

Si on veut rajouter le code a nouveau on obtient un message d'erreur.

 

Voici mon code. Il faut bien suppimer le fichier /cache/class_index.php quand on ajoute une surcharge comme celle-ci

Je pense me pencher rapidement vers une acceptation du code promo mais une application uniquement sur les articles sans prix réduit.

/override/classes/CartRule.php :

<?php
 
class CartRule extends CartRuleCore
{
 
    /**
     * Check if this cart rule can be applied
     *
     * @param Context $context
     * @param bool $alreadyInCart Check if the voucher is already on the cart
     * @param bool $display_error Display error
     * @return bool|mixed|string
     */
    public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true, $check_carrier = true)
    { 
// on reprend le traitement de base et si il passe on vérifie alors les promotions
$returnParent = parent::checkValidity($context, $alreadyInCart, $display_error, $check_carrier);
        if ($returnParent === NULL) {
$products = $context->cart->getProducts();
$product_on_sale = false;
foreach($products as $product){
if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0)
$product_on_sale = true;
}
if ($product_on_sale) {
return (!$display_error) ? false : Tools::displayError('Ce code n\'est pas cumulable avec des produits déjà en promotion');
}
}
return $returnParent;
    }
}
Edited by adrien russo (see edit history)
  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

 

Bonjour tout le monde,

 

pour info le client pour qui j'avais effectué cette modification m'a demandé de laissé la possibilité de faire les bons de réduction sur les promos si il s'agit d'un bon proposant une réduction par "montant". En gros d'interdire seulement les bons en pourcentage du prix pour les produits soldés.

 

Voici donc la nouvelle version avec ce feature en plus :

public function checkValidity(Context $context, $alreadyInCart = false, $display_error = true)
{
		if (!CartRule::isFeatureActive())
			return false;

		if (!$this->active)
			return (!$display_error) ? false : Tools::displayError('This voucher is disabled');
		if (!$this->quantity)
			return (!$display_error) ? false : Tools::displayError('This voucher has already been used');
		if (strtotime($this->date_from) > time())
			return (!$display_error) ? false : Tools::displayError('This voucher is not valid yet');
		if (strtotime($this->date_to) < time())
			return (!$display_error) ? false : Tools::displayError('This voucher has expired');
		
		$product_on_sale = false;
		$amount = false;
		if($this->reduction_percent === '0.00' && $this->reduction_amount !== '0.00')
			$amount = true;
		if(!$amount){
			$products = $context->cart->getProducts();
			foreach($products as $product){
				if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0)
					$product_on_sale = true;
			}
			if ($product_on_sale)
				return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale');
		}
		if ($context->cart->id_customer)
		{
			$quantityUsed = Db::getInstance()->getValue('
			SELECT count(*)
			FROM '._DB_PREFIX_.'orders o
			LEFT JOIN '._DB_PREFIX_.'order_cart_rule od ON o.id_order = od.id_order
			WHERE o.id_customer = '.$context->cart->id_customer.'
			AND od.id_cart_rule = '.(int)$this->id.'
			AND '.(int)Configuration::get('PS_OS_ERROR').' != (
				SELECT oh.id_order_state
				FROM '._DB_PREFIX_.'order_history oh
				WHERE oh.id_order = o.id_order
				ORDER BY oh.date_add DESC
				LIMIT 1
			)');
			if ($quantityUsed + 1 > $this->quantity_per_user)
				return (!$display_error) ? false : Tools::displayError('You cannot use this voucher anymore (usage limit reached)');
		}

		// Get an intersection of the customer groups and the cart rule groups (if the customer is not logged in, the default group is 1)
		if ($this->group_restriction)
		{
			$id_cart_rule = (int)Db::getInstance()->getValue('
			SELECT crg.id_cart_rule
			FROM '._DB_PREFIX_.'cart_rule_group crg
			WHERE crg.id_cart_rule = '.(int)$this->id.'
			AND crg.id_group '.($context->cart->id_customer ? 'IN (SELECT cg.id_group FROM '._DB_PREFIX_.'customer_group cg WHERE cg.id_customer = '.(int)$context->cart->id_customer.')' : '= 1'));
			if (!$id_cart_rule)
				return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
		}

		// Check if the customer delivery address is usable with the cart rule
		if ($this->country_restriction)
		{
			if (!$context->cart->id_address_delivery)
				return (!$display_error) ? false : Tools::displayError('You must choose a delivery address before applying this voucher to your order');
			$id_cart_rule = (int)Db::getInstance()->getValue('
			SELECT crc.id_cart_rule
			FROM '._DB_PREFIX_.'cart_rule_country crc
			WHERE crc.id_cart_rule = '.(int)$this->id.'
			AND crc.id_country = (SELECT a.id_country FROM '._DB_PREFIX_.'address a WHERE a.id_address = '.(int)$context->cart->id_address_delivery.' LIMIT 1)');
			if (!$id_cart_rule)
				return (!$display_error) ? false : Tools::displayError('You cannot use this voucher in your country of delivery');
		}

		// Check if the carrier chosen by the customer is usable with the cart rule
		if ($this->carrier_restriction)
		{
			if (!$context->cart->id_carrier)
				return (!$display_error) ? false : Tools::displayError('You must choose a carrier before applying this voucher to your order');
			$id_cart_rule = (int)Db::getInstance()->getValue('
			SELECT crc.id_cart_rule
			FROM '._DB_PREFIX_.'cart_rule_carrier crc
			INNER JOIN '._DB_PREFIX_.'carrier c ON (c.id_reference = crc.id_carrier AND c.deleted = 0)
			WHERE crc.id_cart_rule = '.(int)$this->id.'
			AND c.id_carrier = '.(int)$context->cart->id_carrier);
			if (!$id_cart_rule)
				return (!$display_error) ? false : Tools::displayError('You cannot use this voucher with this carrier');
		}

		// Check if the cart rules appliy to the shop browsed by the customer
		if ($this->shop_restriction && $context->shop->id && Shop::isFeatureActive())
		{
			$id_cart_rule = (int)Db::getInstance()->getValue('
			SELECT crs.id_cart_rule
			FROM '._DB_PREFIX_.'cart_rule_shop crs
			WHERE crs.id_cart_rule = '.(int)$this->id.'
			AND crs.id_shop = '.(int)$context->shop->id);
			if (!$id_cart_rule)
				return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
		}

		// Check if the products chosen by the customer are usable with the cart rule
		if ($this->product_restriction)
		{
			$r = $this->checkProductRestrictions($context, false, $display_error);
			if ($r !== false && $display_error)
				return $r;
			elseif (!$r && !$display_error)
				return false;
		}

		// Check if the cart rule is only usable by a specific customer, and if the current customer is the right one
		if ($this->id_customer && $context->cart->id_customer != $this->id_customer)
		{
			if (!Context::getContext()->customer->isLogged())
				return (!$display_error) ? false : (Tools::displayError('You cannot use this voucher').' - '.Tools::displayError('Please log in'));
			return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
		}

		if ($this->minimum_amount)
		{
			// Minimum amount is converted to the default currency
			$minimum_amount = $this->minimum_amount;
			if ($this->minimum_amount_currency != Configuration::get('PS_CURRENCY_DEFAULT'))
			{
				$minimum_amount_currency = new Currency($this->minimum_amount_currency);
				if ($this->minimum_amount == 0 || $minimum_amount_currency->conversion_rate == 0)
					$minimum_amount = 0;
				else
					$minimum_amount = $this->minimum_amount / $minimum_amount_currency->conversion_rate;
			}

			$cartTotal = $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_PRODUCTS);
			if ($this->minimum_amount_shipping)
				$cartTotal += $context->cart->getOrderTotal($this->minimum_amount_tax, Cart::ONLY_SHIPPING);

			// If a product is given for free in this rule and already in the cart, the price is subtracted
			if ($this->gift_product && $alreadyInCart)
			{
				$query = new DbQuery();
				
				$query->select('id_product');
				$query->from('cart_product');
				$query->where('id_product = '.(int)$this->gift_product);
				$query->where('id_cart = '.(int)$context->cart->id);
				
				if ((int)$this->gift_product_attribute)
					$query->where('id_product_attribute = '.(int)$this->gift_product_attribute);
				
				if (Db::getInstance()->getValue($query))
				{
					$ref = false;
					$product_price = Product::getPriceStatic(
						$this->gift_product,
						$this->minimum_amount_tax,
						$this->gift_product_attribute,
						null, null, false, true, 1, null,
						$context->cart->id_customer ? $context->cart->id_customer : null,
						$context->cart->id,
						(int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} ? (int)$context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')} : null,
						$ref, true, true, $context, true
					);
					$cartTotal -= $product_price;
				}
			}

			if ($cartTotal < $minimum_amount)
				return (!$display_error) ? false : Tools::displayError('You have not reached the minimum amount required to use this voucher');
		}
		
		// Check if the voucher is already in the cart of if a non compatible voucher is in the cart
		// Important note: this MUST be the last check, because if the tested cart rule has priority over a non combinable one in the cart, we will switch them
		$otherCartRules = $context->cart->getCartRules();
		if (count($otherCartRules))
			foreach ($otherCartRules as $otherCartRule)
			{
				if ($otherCartRule['id_cart_rule'] == $this->id && !$alreadyInCart)
					return (!$display_error) ? false : Tools::displayError('This voucher is already in your cart');
				if ($this->cart_rule_restriction && $otherCartRule['cart_rule_restriction'] && $otherCartRule['id_cart_rule'] != $this->id)
				{
					$combinable = Db::getInstance()->getValue('
					SELECT id_cart_rule_1
					FROM '._DB_PREFIX_.'cart_rule_combination
					WHERE (id_cart_rule_1 = '.(int)$this->id.' AND id_cart_rule_2 = '.(int)$otherCartRule['id_cart_rule'].')
					OR (id_cart_rule_2 = '.(int)$this->id.' AND id_cart_rule_1 = '.(int)$otherCartRule['id_cart_rule'].')');
					if (!$combinable)
					{
						$cart_rule = new CartRule((int)$otherCartRule['id_cart_rule'], $context->cart->id_lang);
						// The cart rules are not combinable and the cart rule currently in the cart has priority over the one tested
						if ($cart_rule->priority <= $this->priority)
							return (!$display_error) ? false : Tools::displayError('This voucher is not combinable with an other voucher already in your cart:').' '.$cart_rule->name;
						// But if the cart rule that is tested has priority over the one in the cart, we remove the one in the cart and keep this new one
						else
							$context->cart->removeCartRule($cart_rule->id);
					}
				}
			}
		
		if (!$display_error)
			return true;
}

Merci Manuel, ça fonctionne nickel PS 1.5.6.2

Link to comment
Share on other sites

  • 2 weeks later...
  • 2 weeks later...
  • 5 weeks later...
  • 5 months later...

Hello ! moi aussi je trouve ça aberrant de laisser couler ce bug/oubli...pitoyable.

 

J'ai pas testé la méthode du bout de code mais c'est surtout pour le programme de parrainage le soucis...car ce base il les créés compatibles !! (la blague!!)

 

Quelqu'un a une idée pour le referral programme ?

Link to comment
Share on other sites

  • 4 weeks later...

Bonjour à tous, 

 

Je viens effectivement de m'apercevoir de ce rpoblème mais ce que je souhaite est en sens inverse.

C'est à dire que j'ai des articles en promos/soldes, accessibles à tous les clients de la même façon,

 

Hors je veux donner à certains clients privilégier un code réduction plus important que les soldes déjà en cours.

 

Du coup, j'ai besoin que si le client saisit son bon de réduction, la promo est supprimée.

 

Si quelqu'un à une solution, je suis preneuse!

 

MJ

Link to comment
Share on other sites

  • 3 weeks later...

Bonjour,

je suis en 1.6.1.4 et j'ai le même problème de tout le monde, impossible de proposer un code réduction non cumulable avec les promotiions. D'autant qu'actuellement c'est  les soldes, on a 2000 produits soldés et qu'une centaine non soldés, comment faire pour retrouver cette fonction présente avant sur le 1.4

C'est plutôt inciter les gens à acheter un module alors que cette fonction était gratuite!!

Link to comment
Share on other sites

  • 3 months later...
  • 2 months later...

Bonjour, je remonte ce sujet, merci à Manuel Corbet pour cette modif, que j'ai appliquée sur PS 1.6.0.14 :)

 

j'y ai apporté une modification pour permettre l'application d'une règle de panier de type "montant" (je n'utilise pas les % alors je n'ai pas testé) quand dans le panier il y a des produits promos/soldés ET des produits éligibles (sans réduction).

$products = $context->cart->getProducts();
		$product_on_sale = false;
		foreach($products as $product){
			if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0)
				$product_on_sale = true;
			// ajout de la condition suivante dans le code de Manuel Corbet
			if(empty($product["reduction_applies"]))
				$product_on_sale = false;
			
		}
		if ($product_on_sale)
			return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale');	

Voici des captures pour montrer le résultat :

 

post-364844-0-00171300-1485167254_thumb.png

 

post-364844-0-26409500-1485167255_thumb.png

 

la condition fonctionne quand le(s) produit(s) non soldés sont à la fin du panier mais je vais remodeler pour que ça fonctionne quelque soit l'ordre. J'aimerai à terme pouvoir activer cette option au cas par cas dans chaque règle panier. (en passant par une case à cocher et un champ supplémentaire en base de données comme dans Presta 1.4). Voilà mon projet

bonne journée, bonnes ventes ;)

Edited by Photon (see edit history)
Link to comment
Share on other sites

Voilà la première modif permettant au client d'utiliser un bon de réduction (en montant) sur un ou des produit(s) non soldés dans un panier qui contient également des produits promos/soldés à prix barrés.

                $products = $context->cart->getProducts();
                $product_on_sale = false;
		$product_not_sale = false; // ajout d'une variable
		foreach($products as $product){
			if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0)
				$product_on_sale = true;
			// utilisation de cette nouvelle variable	
			if(empty($product["reduction_applies"]))
				$product_not_sale = true;
			
		}
		if ($product_on_sale && !$product_not_sale) // condition qui affichera l'erreur
			return (!$display_error) ? false : Tools::displayError('This voucher isn\'t cumulative on products with reduction or marked as on sale');	

en espérant que ça aidera. ^_^

Edited by Photon (see edit history)
Link to comment
Share on other sites

C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier).

Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas !

Si ça intéresse, je ferai un tuto.

Edited by Photon (see edit history)
  • Like 3
Link to comment
Share on other sites

C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier).

Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas !

Si ça intéresse, je ferai un tuto.

Ca m’intéresse grave :)

Link to comment
Share on other sites

  • 2 weeks later...

C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier).

Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas !

Si ça intéresse, je ferai un tuto.

Bonjour Photon,

Cela m'intéresse aussi ; et je suis sûr que nous sommes nombreux à espérer cette solution...

Merci d'avance pour le tuto !

Link to comment
Share on other sites

  • 1 month later...

C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier).

Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas !

Si ça intéresse, je ferai un tuto.

Comme l'ont dit les personnes avant moi, je suis aussi impatient de voir votre tuto...

 

Merci d'avance !

Link to comment
Share on other sites

  • 1 year later...
Quote

C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier).

Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas !

Si ça intéresse, je ferai un tuto.

Bonjour, 

Très intéressée par le tuto aussi!

Je viens d'avoir une commande pour 2 bracelets à 0,30€ car les régles et soldes s'étaient cumulées :(

Prévenez-nous quand il sera prêt!!

Bonne journée

Link to comment
Share on other sites

  • 4 months later...
On 1/24/2017 at 11:27 AM, Photon said:

C'est fait, ajout du champ en base de données, une variable dans cartRule.php ainsi qu'une condition supplémentaire dans checkValidity. Affichage de l'option OUI/NON dans le BO (règle de panier).

Testé et fonctionnel dans Presta 1.6.0.14 pour les réductions en montant. Désormais par défaut nos règles panier ne sont pas cumulable avec les soldes et on peut activer au cas par cas !

Si ça intéresse, je ferai un tuto.

Bonjour,

Je ne sais pas si vous l'avez fait mais moi aussi je serai intéressé par un tuto.

Merci

Link to comment
Share on other sites

  • 1 year later...

Bonjour,

En effet je reviens vers ce sujet car je cherchais aussi une solution sur Prestashop 1.5 pour appliquer une remise de 10% sur la commande sauf sur certain produit (déjà remisé ou autres).

La solution évoqué plus en haut est une bonne solution mais en effet bloque totalement le code promo dans ce cas la.

On 1/6/2015 at 4:04 PM, cockpitinferno said:

ben si, il suffit de faire la modif proposée plus haut. par contre effectivement si tu as un produit en solde dans le panier + un autre sans reduc ton code promo marchera pas.

 

Du coup petite solution rapide pour quand même appliqué la remise aux produit sans réduc

Toujours dans la même classe mais dans la fonction : getContextualValue()

 

J'ajoute :


$products = $context->cart->getProducts();

foreach($products as $product){
	if(!empty($product["reduction_applies"]) && $product["reduction_applies"] > 0)
		$order_total -= $product["total_wt"];
}

Après le code :

// Discount (%) on the whole order
if ($this->reduction_percent && $this->reduction_product == 0)
{
	// Do not give a reduction on free products!
	$order_total = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS, $package_products);
	foreach ($context->cart->getCartRules(CartRule::FILTER_ACTION_GIFT) as $cart_rule)
		$order_total -= Tools::ps_round($cart_rule['obj']->getContextualValue($use_tax, $context, CartRule::FILTER_ACTION_GIFT, $package), 2);
.
.
.
.
.

 

Ce qui enlève tout simplement le prix du produit que je ne veux pas remiser au prix total de la commande.

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...