I have the strangest problem ever:
When using the same coupon code with different customers logged in, for some of the customer the coupon code is valid and for others it's not.
There is no limits set for this coupon.
I had started to drop log calls and managed to narrow the problem to a single function located at app/code/core/Mage/SalesRule/Model/Validator.php:297
I am using Magento CE 1.9.0.1.
Following is the code and the log is produce.
Please take a closer look at two points DFDF1 and DDD. You can see that at DFDF1 the quote still has the coupon code but at DDD it's gone. The strange thing is that there is no functionality between those points that might remove the coupon code from quote (or maybe there is......)
I will appreciate any help to solve the mystery.
Thanks...
Here is the code:
/**
* 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 );
$itemPrice = $this->_getItemPrice( $item );
$baseItemPrice = $this->_getItemBasePrice( $item );
$itemOriginalPrice = $this->_getItemOriginalPrice( $item );
$baseItemOriginalPrice = $this->_getItemBaseOriginalPrice( $item );
Mage::log( 'CCC ' . $address->getQuote()->getCouponCode() );
if ( $itemPrice < 0 ) {
return $this;
}
$appliedRuleIds = array();
foreach ( $this->_getRules() as $rule ) {
Mage::log( $rule->getRuleId() );
if ( $this->_stopFurtherRules ) {
break;
}
/* @var $rule Mage_SalesRule_Model_Rule */
if ( ! $this->_canProcessRule( $rule, $address ) ) {
continue;
}
Mage::log( 'FFFF ' . $address->getQuote()->getCouponCode() );
if ( ! $rule->getActions()->validate( $item ) ) {
continue;
}
Mage::log( 'FFFF1 ' . $address->getQuote()->getCouponCode() );
Mage::log( $rule->getSimpleAction() );
$qty = $this->_getItemQty( $item, $rule );
$rulePercent = min( 100, $rule->getDiscountAmount() );
$discountAmount = 0;
$baseDiscountAmount = 0;
//discount for original price
$originalDiscountAmount = 0;
$baseOriginalDiscountAmount = 0;
switch ( $rule->getSimpleAction() ) {
case Mage_SalesRule_Model_Rule::TO_PERCENT_ACTION:
$rulePercent = max( 0, 100 - $rule->getDiscountAmount() );
//no break;
case Mage_SalesRule_Model_Rule::BY_PERCENT_ACTION:
Mage::log( 'DFDF ' . $address->getQuote()->getCouponCode() );
$step = $rule->getDiscountStep();
if ( $step ) {
$qty = floor( $qty / $step ) * $step;
}
$_rulePct = $rulePercent / 100;
$discountAmount = ( $qty * $itemPrice - $item->getDiscountAmount() ) * $_rulePct;
$baseDiscountAmount = ( $qty * $baseItemPrice - $item->getBaseDiscountAmount() ) * $_rulePct;
//get discount for original price
$originalDiscountAmount = ( $qty * $itemOriginalPrice - $item->getDiscountAmount() ) * $_rulePct;
$baseOriginalDiscountAmount =
( $qty * $baseItemOriginalPrice - $item->getDiscountAmount() ) * $_rulePct;
if ( ! $rule->getDiscountQty() || $rule->getDiscountQty() > $qty ) {
$discountPercent = min( 100, $item->getDiscountPercent() + $rulePercent );
$item->setDiscountPercent( $discountPercent );
}
Mage::log( 'DDD ID1 ' . $address->getQuote()->getId() );
Mage::log( 'DFDF1 ' . $address->getQuote()->getCouponCode() );
break;
case Mage_SalesRule_Model_Rule::TO_FIXED_ACTION:
$quoteAmount = $quote->getStore()->convertPrice( $rule->getDiscountAmount() );
$discountAmount = $qty * ( $itemPrice - $quoteAmount );
$baseDiscountAmount = $qty * ( $baseItemPrice - $rule->getDiscountAmount() );
//get discount for original price
$originalDiscountAmount = $qty * ( $itemOriginalPrice - $quoteAmount );
$baseOriginalDiscountAmount = $qty * ( $baseItemOriginalPrice - $rule->getDiscountAmount() );
Mage::log( 'TO_FIXED_ACTION ' . $address->getQuote()->getCoupon() );
break;
case Mage_SalesRule_Model_Rule::BY_FIXED_ACTION:
$step = $rule->getDiscountStep();
if ( $step ) {
$qty = floor( $qty / $step ) * $step;
}
$quoteAmount = $quote->getStore()->convertPrice( $rule->getDiscountAmount() );
$discountAmount = $qty * $quoteAmount;
$baseDiscountAmount = $qty * $rule->getDiscountAmount();
Mage::log( 'BY_FIXED_ACTION ' . $address->getQuote()->getCoupon() );
break;
case Mage_SalesRule_Model_Rule::CART_FIXED_ACTION:
if ( empty( $this->_rulesItemTotals[ $rule->getId() ] ) ) {
Mage::throwException( Mage::helper( 'salesrule' )->__( 'Item totals are not set for rule.' ) );
}
/**
* prevent applying whole cart discount for every shipping order, but only for first order
*/
if ( $quote->getIsMultiShipping() ) {
$usedForAddressId = $this->getCartFixedRuleUsedForAddress( $rule->getId() );
if ( $usedForAddressId && $usedForAddressId != $address->getId() ) {
break;
} else {
$this->setCartFixedRuleUsedForAddress( $rule->getId(), $address->getId() );
}
}
$cartRules = $address->getCartFixedRules();
if ( ! isset( $cartRules[ $rule->getId() ] ) ) {
$cartRules[ $rule->getId() ] = $rule->getDiscountAmount();
}
if ( $cartRules[ $rule->getId() ] > 0 ) {
if ( $this->_rulesItemTotals[ $rule->getId() ]['items_count'] <= 1 ) {
$quoteAmount = $quote->getStore()->convertPrice( $cartRules[ $rule->getId() ] );
$baseDiscountAmount = min( $baseItemPrice * $qty, $cartRules[ $rule->getId() ] );
} else {
$discountRate = $baseItemPrice * $qty /
$this->_rulesItemTotals[ $rule->getId() ]['base_items_price'];
$maximumItemDiscount = $rule->getDiscountAmount() * $discountRate;
$quoteAmount = $quote->getStore()->convertPrice( $maximumItemDiscount );
$baseDiscountAmount = min( $baseItemPrice * $qty, $maximumItemDiscount );
$this->_rulesItemTotals[ $rule->getId() ]['items_count'] --;
}
$discountAmount = min( $itemPrice * $qty, $quoteAmount );
$discountAmount = $quote->getStore()->roundPrice( $discountAmount );
$baseDiscountAmount = $quote->getStore()->roundPrice( $baseDiscountAmount );
//get discount for original price
$originalDiscountAmount = min( $itemOriginalPrice * $qty, $quoteAmount );
$baseOriginalDiscountAmount = $quote->getStore()->roundPrice( $baseItemOriginalPrice );
$cartRules[ $rule->getId() ] -= $baseDiscountAmount;
}
$address->setCartFixedRules( $cartRules );
Mage::log( 'CART_FIXED_ACTION ' . $address->getQuote()->getCoupon() );
break;
case Mage_SalesRule_Model_Rule::BUY_X_GET_Y_ACTION:
$x = $rule->getDiscountStep();
$y = $rule->getDiscountAmount();
if ( ! $x || $y > $x ) {
break;
}
$buyAndDiscountQty = $x + $y;
$fullRuleQtyPeriod = floor( $qty / $buyAndDiscountQty );
$freeQty = $qty - $fullRuleQtyPeriod * $buyAndDiscountQty;
$discountQty = $fullRuleQtyPeriod * $y;
if ( $freeQty > $x ) {
$discountQty += $freeQty - $x;
}
$discountAmount = $discountQty * $itemPrice;
$baseDiscountAmount = $discountQty * $baseItemPrice;
//get discount for original price
$originalDiscountAmount = $discountQty * $itemOriginalPrice;
$baseOriginalDiscountAmount = $discountQty * $baseItemOriginalPrice;
Mage::log( 'BUY_X_GET_Y_ACTION ' . $address->getQuote()->getCoupon() );
break;
}
Mage::log( 'DDD ID2 ' . $address->getQuote()->getId() );
Mage::log( 'DDD ' . $address->getQuote()->getCoupon() );
$result = new Varien_Object( array(
'discount_amount' => $discountAmount,
'base_discount_amount' => $baseDiscountAmount,
) );
Mage::log( 'DDD1 ' . $address->getQuote()->getCoupon() );
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
*/
$itemDiscountAmount = $item->getDiscountAmount();
$itemBaseDiscountAmount = $item->getBaseDiscountAmount();
$discountAmount = min( $itemDiscountAmount + $discountAmount, $itemPrice * $qty );
$baseDiscountAmount = min( $itemBaseDiscountAmount + $baseDiscountAmount, $baseItemPrice * $qty );
$item->setDiscountAmount( $discountAmount );
$item->setBaseDiscountAmount( $baseDiscountAmount );
$item->setOriginalDiscountAmount( $originalDiscountAmount );
$item->setBaseOriginalDiscountAmount( $baseOriginalDiscountAmount );
$appliedRuleIds[ $rule->getRuleId() ] = $rule->getRuleId();
Mage::log( 'YYY ' . $address->getQuote()->getCouponCode() );
$this->_maintainAddressCouponCode( $address, $rule );
Mage::log( 'XXX ' . $address->getQuote()->getCouponCode() );
$this->_addDiscountDescription( $address, $rule );
if ( $rule->getStopRulesProcessing() ) {
$this->_stopFurtherRules = true;
break;
}
}
$item->setAppliedRuleIds( join( ',', $appliedRuleIds ) );
$address->setAppliedRuleIds( $this->mergeIds( $address->getAppliedRuleIds(), $appliedRuleIds ) );
$quote->setAppliedRuleIds( $this->mergeIds( $quote->getAppliedRuleIds(), $appliedRuleIds ) );
return $this;
}
Here is the log:
2015-02-05T18:10:54+00:00 DEBUG (7): 21
2015-02-05T18:10:54+00:00 DEBUG (7): FFFF Yaelmodli2015
2015-02-05T18:10:54+00:00 DEBUG (7): FFFF1 Yaelmodli2015
2015-02-05T18:10:54+00:00 DEBUG (7): by_percent
2015-02-05T18:10:54+00:00 DEBUG (7): DFDF Yaelmodli2015
2015-02-05T18:10:54+00:00 DEBUG (7): DDD ID1 338
2015-02-05T18:10:54+00:00 DEBUG (7): DFDF1 Yaelmodli2015
2015-02-05T18:10:54+00:00 DEBUG (7): DDD ID2 338
2015-02-05T18:10:54+00:00 DEBUG (7): DDD