| Server IP : 213.186.33.4 / Your IP : 216.73.216.59 Web Server : Apache System : Linux webm006.cluster103.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64 User : awebpaca ( 35430) PHP Version : 8.5.0 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/awebpaca/boutiques/app/code/core/Mage/SalesRule/Model/ |
Upload File : |
<?php
/**
* Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@magentocommerce.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magentocommerce.com for more information.
*
* @category Mage
* @package Mage_SalesRule
* @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
/**
* SalesRule Validator Model
*
* Allows dispatching before and after events for each controller action
*
* @category Mage
* @package Mage_SalesRule
* @author Magento Core Team <core@magentocommerce.com>
*/
class Mage_SalesRule_Model_Validator extends Mage_Core_Model_Abstract
{
/**
* Rule source collection
*
* @var Mage_SalesRule_Model_Mysql4_Rule_Collection
*/
protected $_rules;
protected $_roundingDeltas = array();
protected $_baseRoundingDeltas = array();
/**
* Defines if method Mage_SalesRule_Model_Validator::process() was already called
* Used for clearing applied rule ids in Quote and in Address
*
* @var bool
*/
protected $_isFirstTimeProcessRun = false;
protected function _construct()
{
parent::_construct();
$this->_init('salesrule/validator');
}
/**
* Init validator
* Init process load collection of rules for specific website,
* customer group and coupon code
*
* @param int $websiteId
* @param int $customerGroupId
* @param string $couponCode
* @return Mage_SalesRule_Model_Validator
*/
public function init($websiteId, $customerGroupId, $couponCode)
{
$this->setWebsiteId($websiteId)
->setCustomerGroupId($customerGroupId)
->setCouponCode($couponCode);
$key = $websiteId . '_' . $customerGroupId . '_' . $couponCode;
if (!isset($this->_rules[$key])) {
$this->_rules[$key] = Mage::getResourceModel('salesrule/rule_collection')
->setValidationFilter($websiteId, $customerGroupId, $couponCode)
->load();
}
return $this;
}
/**
* Get rules collection for current object state
*
* @return Mage_SalesRule_Model_Mysql4_Rule_Collection
*/
protected function _getRules()
{
$key = $this->getWebsiteId() . '_' . $this->getCustomerGroupId() . '_' . $this->getCouponCode();
return $this->_rules[$key];
}
/**
* Get address object which can be used for discount calculation
*
* @param Mage_Sales_Model_Quote_Item_Abstract $item
* @return Mage_Sales_Model_Quote_Address
*/
protected function _getAddress(Mage_Sales_Model_Quote_Item_Abstract $item)
{
if ($item instanceof Mage_Sales_Model_Quote_Address_Item) {
$address = $item->getAddress();
} elseif ($item->getQuote()->isVirtual()) {
$address = $item->getQuote()->getBillingAddress();
} else {
$address = $item->getQuote()->getShippingAddress();
}
return $address;
}
/**
* Check if rule can be applied for specific address/quote/customer
*
* @param Mage_SalesRule_Model_Rule $rule
* @param Mage_Sales_Model_Quote_Address $address
* @return bool
*/
protected function _canProcessRule($rule, $address)
{
if (!$rule->hasIsValid()) {
/**
* check per coupon usage limit
*/
$couponCode = $address->getQuote()->getCouponCode();
if ($couponCode) {
$coupon = Mage::getModel('salesrule/coupon');
$coupon->load($couponCode, 'code');
if ($coupon->getId()) {
// check entire usage limit
if ($coupon->getUsageLimit() && $coupon->getTimesUsed() >= $coupon->getUsageLimit()) {
$rule->setIsValid(false);
return false;
}
// check per customer usage limit
$customerId = $address->getQuote()->getCustomerId();
if ($customerId && $coupon->getUsagePerCustomer()) {
$couponUsage = new Varien_Object();
Mage::getResourceModel('salesrule/coupon_usage')->loadByCustomerCoupon(
$couponUsage, $customerId, $coupon->getId());
if ($couponUsage->getCouponId() && $couponUsage->getTimesUsed() >= $coupon->getUsagePerCustomer()) {
$rule->setIsValid(false);
return false;
}
}
}
}
/**
* check per rule usage limit
*/
$ruleId = $rule->getId();
if ($ruleId && $rule->getUsesPerCustomer()) {
$customerId = $address->getQuote()->getCustomerId();
$ruleCustomer = Mage::getModel('salesrule/rule_customer');
$ruleCustomer->loadByCustomerRule($customerId, $ruleId);
if ($ruleCustomer->getId()) {
if ($ruleCustomer->getTimesUsed() >= $rule->getUsesPerCustomer()) {
$rule->setIsValid(false);
return false;
}
}
}
$rule->afterLoad();
/**
* quote does not meet rule's conditions
*/
if (!$rule->validate($address)) {
$rule->setIsValid(false);
return false;
}
/**
* passed all validations, remember to be valid
*/
$rule->setIsValid(true);
}
return $rule->getIsValid();
}
/**
* Quote item free shipping ability check
* This process not affect information about applied rules, coupon code etc.
* This information will be added during discount amounts processing
*
* @param Mage_Sales_Model_Quote_Item_Abstract $item
* @return Mage_SalesRule_Model_Validator
*/
public function processFreeShipping(Mage_Sales_Model_Quote_Item_Abstract $item)
{
$address = $this->_getAddress($item);
$item->setFreeShipping(false);
foreach ($this->_getRules() as $rule) {
/* @var $rule Mage_SalesRule_Model_Rule */
if (!$this->_canProcessRule($rule, $address)) {
continue;
}
if (!$rule->getActions()->validate($item)) {
continue;
}
switch ($rule->getSimpleFreeShipping()) {
case Mage_SalesRule_Model_Rule::FREE_SHIPPING_ITEM:
$item->setFreeShipping($rule->getDiscountQty() ? $rule->getDiscountQty() : true);
break;
case Mage_SalesRule_Model_Rule::FREE_SHIPPING_ADDRESS:
$address->setFreeShipping(true);
break;
}
if ($rule->getStopRulesProcessing()) {
break;
}
}
return $this;
}
/**
* Quote item discount calculation process
*
* @param Mage_Sales_Model_Quote_Item_Abstract $item
* @return Mage_SalesRule_Model_Validator
*/
public function process(Mage_Sales_Model_Quote_Item_Abstract $item)
{
$item->setDiscountAmount(0);
$item->setBaseDiscountAmount(0);
$item->setDiscountPercent(0);
$quote = $item->getQuote();
$address = $this->_getAddress($item);
//Clearing applied rule ids for quote and address
if ($this->_isFirstTimeProcessRun !== true){
$this->_isFirstTimeProcessRun = true;
$quote->setAppliedRuleIds('');
$address->setAppliedRuleIds('');
}
$itemPrice = $item->getDiscountCalculationPrice();
if ($itemPrice !== null) {
$baseItemPrice = $item->getBaseDiscountCalculationPrice();
} else {
$itemPrice = $item->getCalculationPrice();
$baseItemPrice = $item->getBaseCalculationPrice();
}
$appliedRuleIds = array();
foreach ($this->_getRules() as $rule) {
/* @var $rule Mage_SalesRule_Model_Rule */
if (!$this->_canProcessRule($rule, $address)) {
continue;
}
if (!$rule->getActions()->validate($item)) {
continue;
}
$qty = $item->getTotalQty();
$qty = $rule->getDiscountQty() ? min($qty, $rule->getDiscountQty()) : $qty;
$rulePercent = min(100, $rule->getDiscountAmount());
$discountAmount = 0;
$baseDiscountAmount = 0;
switch ($rule->getSimpleAction()) {
case 'to_percent':
$rulePercent = max(0, 100-$rule->getDiscountAmount());
//no break;
case 'by_percent':
$step = $rule->getDiscountStep();
if ($step) {
$qty = floor($qty/$step)*$step;
}
$discountAmount = ($qty*$itemPrice - $item->getDiscountAmount()) * $rulePercent/100;
$baseDiscountAmount= ($qty*$baseItemPrice - $item->getBaseDiscountAmount()) * $rulePercent/100;
if (!$rule->getDiscountQty() || $rule->getDiscountQty()>$qty) {
$discountPercent = min(100, $item->getDiscountPercent()+$rulePercent);
$item->setDiscountPercent($discountPercent);
}
break;
case 'to_fixed':
$quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount());
$discountAmount = $qty*($itemPrice-$quoteAmount);
$baseDiscountAmount= $qty*($baseItemPrice-$rule->getDiscountAmount());
break;
case 'by_fixed':
$step = $rule->getDiscountStep();
if ($step) {
$qty = floor($qty/$step)*$step;
}
$quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount());
$discountAmount = $qty*$quoteAmount;
$baseDiscountAmount = $qty*$rule->getDiscountAmount();
break;
case 'cart_fixed':
$cartRules = $address->getCartFixedRules();
if (!isset($cartRules[$rule->getId()])) {
$cartRules[$rule->getId()] = $rule->getDiscountAmount();
}
if ($cartRules[$rule->getId()] > 0) {
$quoteAmount = $quote->getStore()->convertPrice($cartRules[$rule->getId()]);
/**
* We can't use row total here because row total not include tax
*/
$discountAmount = min($itemPrice*$qty - $item->getDiscountAmount(), $quoteAmount);
$baseDiscountAmount = min($baseItemPrice*$qty - $item->getBaseDiscountAmount(), $cartRules[$rule->getId()]);
$cartRules[$rule->getId()] -= $baseDiscountAmount;
}
$address->setCartFixedRules($cartRules);
break;
case 'buy_x_get_y':
$x = $rule->getDiscountStep();
$y = $rule->getDiscountAmount();
if (!$x || $y>=$x) {
break;
}
$buy = 0; $free = 0;
while ($buy+$free<$qty) {
$buy += $x;
if ($buy+$free>=$qty) {
break;
}
$free += min($y, $qty-$buy-$free);
if ($buy+$free>=$qty) {
break;
}
}
$discountAmount = $free*$itemPrice;
$baseDiscountAmount= $free*$baseItemPrice;
break;
}
$result = new Varien_Object(array(
'discount_amount' => $discountAmount,
'base_discount_amount' => $baseDiscountAmount,
));
Mage::dispatchEvent('salesrule_validator_process', array(
'rule' => $rule,
'item' => $item,
'address' => $address,
'quote' => $quote,
'qty' => $qty,
'result' => $result,
));
$discountAmount = $result->getDiscountAmount();
$baseDiscountAmount = $result->getBaseDiscountAmount();
$percentKey = $item->getDiscountPercent();
/**
* Process "delta" rounding
*/
if ($percentKey) {
$delta = isset($this->_roundingDeltas[$percentKey]) ? $this->_roundingDeltas[$percentKey] : 0;
$baseDelta = isset($this->_baseRoundingDeltas[$percentKey]) ? $this->_baseRoundingDeltas[$percentKey] : 0;
$discountAmount+= $delta;
$baseDiscountAmount+=$baseDelta;
$this->_roundingDeltas[$percentKey] = $discountAmount - $quote->getStore()->roundPrice($discountAmount);
$this->_baseRoundingDeltas[$percentKey] = $baseDiscountAmount - $quote->getStore()->roundPrice($baseDiscountAmount);
$discountAmount = $quote->getStore()->roundPrice($discountAmount);
$baseDiscountAmount = $quote->getStore()->roundPrice($baseDiscountAmount);
} else {
$discountAmount = $quote->getStore()->roundPrice($discountAmount);
$baseDiscountAmount = $quote->getStore()->roundPrice($baseDiscountAmount);
}
/**
* We can't use row total here because row total not include tax
* Discount can be applied on price included tax
*/
$discountAmount = min($item->getDiscountAmount()+$discountAmount, $itemPrice*$qty);
$baseDiscountAmount = min($item->getBaseDiscountAmount()+$baseDiscountAmount, $baseItemPrice*$qty);
$item->setDiscountAmount($discountAmount);
$item->setBaseDiscountAmount($baseDiscountAmount);
$appliedRuleIds[$rule->getRuleId()] = $rule->getRuleId();
$this->_maintainAddressCouponCode($address, $rule);
$this->_addDiscountDescription($address, $rule);
if ($rule->getStopRulesProcessing()) {
break;
}
}
$item->setAppliedRuleIds(join(',',$appliedRuleIds));
$address->setAppliedRuleIds($this->mergeIds($address->getAppliedRuleIds(), $appliedRuleIds));
$quote->setAppliedRuleIds($this->mergeIds($quote->getAppliedRuleIds(), $appliedRuleIds));
return $this;
}
/**
* Apply discounts to shipping amount
*
* @param Mage_Sales_Model_Quote_Address $address
* @return Mage_SalesRule_Model_Validator
*/
public function processShippingAmount(Mage_Sales_Model_Quote_Address $address)
{
$shippingAmount = $address->getShippingAmountForDiscount();
if ($shippingAmount!==null) {
$baseShippingAmount = $address->getBaseShippingAmountForDiscount();
} else {
$shippingAmount = $address->getShippingAmount();
$baseShippingAmount = $address->getBaseShippingAmount();
}
$quote = $address->getQuote();
$appliedRuleIds = array();
foreach ($this->_getRules() as $rule) {
/* @var $rule Mage_SalesRule_Model_Rule */
if (!$rule->getApplyToShipping() || !$this->_canProcessRule($rule, $address)) {
continue;
}
$discountAmount = 0;
$baseDiscountAmount = 0;
$rulePercent = min(100, $rule->getDiscountAmount());
switch ($rule->getSimpleAction()) {
case 'to_percent':
$rulePercent = max(0, 100-$rule->getDiscountAmount());
case 'by_percent':
$discountAmount = ($shippingAmount - $address->getShippingDiscountAmount()) * $rulePercent/100;
$baseDiscountAmount= ($baseShippingAmount - $address->getBaseShippingDiscountAmount()) * $rulePercent/100;
$discountPercent = min(100, $address->getShippingDiscountPercent()+$rulePercent);
$address->setShippingDiscountPercent($discountPercent);
break;
case 'to_fixed':
$quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount());
$discountAmount = $shippingAmount-$quoteAmount;
$baseDiscountAmount= $baseShippingAmount-$rule->getDiscountAmount();
break;
case 'by_fixed':
$quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount());
$discountAmount = $quoteAmount;
$baseDiscountAmount = $rule->getDiscountAmount();
break;
case 'cart_fixed':
$cartRules = $address->getCartFixedRules();
if (!isset($cartRules[$rule->getId()])) {
$cartRules[$rule->getId()] = $rule->getDiscountAmount();
}
if ($cartRules[$rule->getId()] > 0) {
$quoteAmount = $quote->getStore()->convertPrice($cartRules[$rule->getId()]);
$discountAmount = min($shippingAmount-$address->getShippingDiscountAmount(), $quoteAmount);
$baseDiscountAmount = min($baseShippingAmount-$address->getBaseShippingDiscountAmount(), $cartRules[$rule->getId()]);
$cartRules[$rule->getId()] -= $baseDiscountAmount;
}
$address->setCartFixedRules($cartRules);
break;
}
$discountAmount = min($address->getShippingDiscountAmount()+$discountAmount, $shippingAmount);
$baseDiscountAmount = min($address->getBaseShippingDiscountAmount()+$baseDiscountAmount, $baseShippingAmount);
$address->setShippingDiscountAmount($discountAmount);
$address->setBaseShippingDiscountAmount($baseDiscountAmount);
$appliedRuleIds[$rule->getRuleId()] = $rule->getRuleId();
$this->_maintainAddressCouponCode($address, $rule);
$this->_addDiscountDescription($address, $rule);
if ($rule->getStopRulesProcessing()) {
break;
}
}
$address->setAppliedRuleIds($this->mergeIds($address->getAppliedRuleIds(), $appliedRuleIds));
$quote->setAppliedRuleIds($this->mergeIds($quote->getAppliedRuleIds(), $appliedRuleIds));
return $this;
}
public function mergeIds($a1, $a2, $asString=true)
{
if (!is_array($a1)) {
$a1 = empty($a1) ? array() : explode(',', $a1);
}
if (!is_array($a2)) {
$a2 = empty($a2) ? array() : explode(',', $a2);
}
$a = array_unique(array_merge($a1, $a2));
if ($asString) {
$a = implode(',', $a);
}
return $a;
}
/**
* Retrieve subordinate coupon IDs
*
* @return array
*/
protected function _maintainAddressCouponCode($address, $rule)
{
foreach ($rule->getCoupons() as $coupon) {
if (strtolower($coupon->getCode()) == strtolower($this->getCouponCode())) {
$address->setCouponCode($this->getCouponCode());
break;
}
}
}
/**
* Add rule discount description label to address object
*
* @param Mage_Sales_Model_Quote_Address $address
* @param Mage_SalesRule_Model_Rule $rule
* @return Mage_SalesRule_Model_Validator
*/
protected function _addDiscountDescription($address, $rule)
{
$description = $address->getDiscountDescriptionArray();
$ruleLabel = $rule->getStoreLabel($address->getQuote()->getStore());
$label = '';
if ($ruleLabel) {
$label = $ruleLabel;
} else if ($address->getCouponCode()) {
$label = $address->getCouponCode();
}
if (!empty($label)) {
$description[$rule->getId()] = $label;
}
$address->setDiscountDescriptionArray($description);
return $this;
}
/**
* Convert address discount description array to string
*
* @param Mage_Sales_Model_Quote_Address $address
* @param string $separator
* @return Mage_SalesRule_Model_Validator
*/
public function prepareDescription($address, $separator=', ')
{
$description = $address->getDiscountDescriptionArray();
if (is_array($description) && !empty($description)) {
$description = array_unique($description);
$description = implode($separator, $description);
} else {
$description = '';
}
$address->setDiscountDescription($description);
return $this;
}
}