Overview

Packages

  • currencysymbol
  • MAbout
  • Mage
    • Admin
    • Adminhtml
    • AdminNotification
    • Api
    • Api2
    • Authorizenet
    • Backup
    • Bundle
    • Captcha
    • Catalog
    • CatalogIndex
    • CatalogInventory
    • CatalogRule
    • CatalogSearch
    • Centinel
    • Checkout
    • Cms
    • Compiler
    • Connect
    • Contacts
    • Core
    • Cron
    • CurrencySymbol
    • Customer
    • Dataflow
    • Directory
    • DirtectPost
    • Downloadable
    • Eav
    • GiftMessage
    • GoogleAnalytics
    • GoogleBase
    • GoogleCheckout
    • ImportExport
    • Index
    • Install
    • Log
    • Media
    • Newsletter
    • Oauth
    • Page
    • PageCache
    • Paygate
    • Payment
    • Paypal
    • PaypalUk
    • Persistent
    • Poll
    • ProductAlert
    • Rating
    • Reports
    • Review
    • Rss
    • Rule
    • Sales
    • SalesRule
    • Sedfriend
    • Sendfriend
    • Shipping
    • Sitemap
    • Tag
    • Tax
    • Usa
    • Weee
    • Widget
    • Wishlist
    • XmlConnect
  • None
  • Phoenix
    • Moneybookers
  • PHP
  • Zend
    • Date
    • Mime
    • XmlRpc

Classes

  • Mage_SalesRule_Exception
  • Mage_SalesRule_Helper_Coupon
  • Mage_SalesRule_Helper_Data
  • Mage_SalesRule_Model_Coupon
  • Mage_SalesRule_Model_Coupon_Codegenerator
  • Mage_SalesRule_Model_Coupon_Massgenerator
  • Mage_SalesRule_Model_Mysql4_Coupon
  • Mage_SalesRule_Model_Mysql4_Coupon_Collection
  • Mage_SalesRule_Model_Mysql4_Coupon_Usage
  • Mage_SalesRule_Model_Mysql4_Report_Collection
  • Mage_SalesRule_Model_Mysql4_Report_Rule
  • Mage_SalesRule_Model_Mysql4_Report_Updatedat_Collection
  • Mage_SalesRule_Model_Mysql4_Rule
  • Mage_SalesRule_Model_Mysql4_Rule_Collection
  • Mage_SalesRule_Model_Mysql4_Rule_Customer
  • Mage_SalesRule_Model_Mysql4_Rule_Customer_Collection
  • Mage_SalesRule_Model_Mysql4_Rule_Product
  • Mage_SalesRule_Model_Mysql4_Rule_Product_Collection
  • Mage_SalesRule_Model_Observer
  • Mage_SalesRule_Model_Quote_Discount
  • Mage_SalesRule_Model_Quote_Freeshipping
  • Mage_SalesRule_Model_Quote_Nominal_Discount
  • Mage_SalesRule_Model_Resource_Coupon
  • Mage_SalesRule_Model_Resource_Coupon_Collection
  • Mage_SalesRule_Model_Resource_Coupon_Usage
  • Mage_SalesRule_Model_Resource_Report_Collection
  • Mage_SalesRule_Model_Resource_Report_Rule
  • Mage_SalesRule_Model_Resource_Report_Rule_Createdat
  • Mage_SalesRule_Model_Resource_Report_Rule_Updatedat
  • Mage_SalesRule_Model_Resource_Report_Updatedat_Collection
  • Mage_SalesRule_Model_Resource_Rule
  • Mage_SalesRule_Model_Resource_Rule_Collection
  • Mage_SalesRule_Model_Resource_Rule_Customer
  • Mage_SalesRule_Model_Resource_Rule_Customer_Collection
  • Mage_SalesRule_Model_Resource_Rule_Product
  • Mage_SalesRule_Model_Resource_Rule_Product_Collection
  • Mage_SalesRule_Model_Rule
  • Mage_SalesRule_Model_Rule_Action_Collection
  • Mage_SalesRule_Model_Rule_Action_Product
  • Mage_SalesRule_Model_Rule_Condition_Address
  • Mage_SalesRule_Model_Rule_Condition_Combine
  • Mage_SalesRule_Model_Rule_Condition_Product
  • Mage_SalesRule_Model_Rule_Condition_Product_Combine
  • Mage_SalesRule_Model_Rule_Condition_Product_Found
  • Mage_SalesRule_Model_Rule_Condition_Product_Subselect
  • Mage_SalesRule_Model_Rule_Customer
  • Mage_SalesRule_Model_Rule_Product
  • Mage_SalesRule_Model_System_Config_Source_Coupon_Format
  • Mage_SalesRule_Model_Validator

Interfaces

  • Mage_SalesRule_Model_Coupon_CodegeneratorInterface
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Magento
  4:  *
  5:  * NOTICE OF LICENSE
  6:  *
  7:  * This source file is subject to the Open Software License (OSL 3.0)
  8:  * that is bundled with this package in the file LICENSE.txt.
  9:  * It is also available through the world-wide-web at this URL:
 10:  * http://opensource.org/licenses/osl-3.0.php
 11:  * If you did not receive a copy of the license and are unable to
 12:  * obtain it through the world-wide-web, please send an email
 13:  * to license@magentocommerce.com so we can send you a copy immediately.
 14:  *
 15:  * DISCLAIMER
 16:  *
 17:  * Do not edit or add to this file if you wish to upgrade Magento to newer
 18:  * versions in the future. If you wish to customize Magento for your
 19:  * needs please refer to http://www.magentocommerce.com for more information.
 20:  *
 21:  * @category    Mage
 22:  * @package     Mage_SalesRule
 23:  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
 24:  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 25:  */
 26: 
 27: 
 28: /**
 29:  * SalesRule Validator Model
 30:  *
 31:  * Allows dispatching before and after events for each controller action
 32:  *
 33:  * @category   Mage
 34:  * @package    Mage_SalesRule
 35:  * @author     Magento Core Team <core@magentocommerce.com>
 36:  */
 37: class Mage_SalesRule_Model_Validator extends Mage_Core_Model_Abstract
 38: {
 39:     /**
 40:      * Rule source collection
 41:      *
 42:      * @var Mage_SalesRule_Model_Mysql4_Rule_Collection
 43:      */
 44:     protected $_rules;
 45: 
 46:     protected $_roundingDeltas = array();
 47: 
 48:     protected $_baseRoundingDeltas = array();
 49: 
 50:     /**
 51:      * Defines if method Mage_SalesRule_Model_Validator::process() was already called
 52:      * Used for clearing applied rule ids in Quote and in Address
 53:      *
 54:      * @deprecated since 1.4.2.0
 55:      * @var bool
 56:      */
 57:     protected $_isFirstTimeProcessRun = false;
 58: 
 59:     /**
 60:      * Defines if method Mage_SalesRule_Model_Validator::reset() wasn't called
 61:      * Used for clearing applied rule ids in Quote and in Address
 62:      *
 63:      * @var bool
 64:      */
 65:     protected $_isFirstTimeResetRun = true;
 66: 
 67:     /**
 68:      * Information about item totals for rules.
 69:      * @var array
 70:      */
 71:     protected $_rulesItemTotals = array();
 72: 
 73:     /**
 74:      * Store information about addresses which cart fixed rule applied for
 75:      *
 76:      * @var array
 77:      */
 78:     protected $_cartFixedRuleUsedForAddress = array();
 79: 
 80:     /**
 81:      * Init validator
 82:      * Init process load collection of rules for specific website,
 83:      * customer group and coupon code
 84:      *
 85:      * @param   int $websiteId
 86:      * @param   int $customerGroupId
 87:      * @param   string $couponCode
 88:      * @return  Mage_SalesRule_Model_Validator
 89:      */
 90:     public function init($websiteId, $customerGroupId, $couponCode)
 91:     {
 92:         $this->setWebsiteId($websiteId)
 93:             ->setCustomerGroupId($customerGroupId)
 94:             ->setCouponCode($couponCode);
 95: 
 96:         $key = $websiteId . '_' . $customerGroupId . '_' . $couponCode;
 97:         if (!isset($this->_rules[$key])) {
 98:             $this->_rules[$key] = Mage::getResourceModel('salesrule/rule_collection')
 99:                 ->setValidationFilter($websiteId, $customerGroupId, $couponCode)
100:                 ->load();
101:         }
102:         return $this;
103:     }
104: 
105:     /**
106:      * Get rules collection for current object state
107:      *
108:      * @return Mage_SalesRule_Model_Mysql4_Rule_Collection
109:      */
110:     protected function _getRules()
111:     {
112:         $key = $this->getWebsiteId() . '_' . $this->getCustomerGroupId() . '_' . $this->getCouponCode();
113:         return $this->_rules[$key];
114:     }
115: 
116:     /**
117:      * Get address object which can be used for discount calculation
118:      *
119:      * @param   Mage_Sales_Model_Quote_Item_Abstract $item
120:      * @return  Mage_Sales_Model_Quote_Address
121:      */
122:     protected function _getAddress(Mage_Sales_Model_Quote_Item_Abstract $item)
123:     {
124:         if ($item instanceof Mage_Sales_Model_Quote_Address_Item) {
125:             $address = $item->getAddress();
126:         } elseif ($item->getQuote()->getItemVirtualQty() > 0) {
127:             $address = $item->getQuote()->getBillingAddress();
128:         } else {
129:             $address = $item->getQuote()->getShippingAddress();
130:         }
131:         return $address;
132:     }
133: 
134:     /**
135:      * Check if rule can be applied for specific address/quote/customer
136:      *
137:      * @param   Mage_SalesRule_Model_Rule $rule
138:      * @param   Mage_Sales_Model_Quote_Address $address
139:      * @return  bool
140:      */
141:     protected function _canProcessRule($rule, $address)
142:     {
143:         if ($rule->hasIsValidForAddress($address) && !$address->isObjectNew()) {
144:             return $rule->getIsValidForAddress($address);
145:         }
146: 
147:         /**
148:          * check per coupon usage limit
149:          */
150:         if ($rule->getCouponType() != Mage_SalesRule_Model_Rule::COUPON_TYPE_NO_COUPON) {
151:             $couponCode = $address->getQuote()->getCouponCode();
152:             if (strlen($couponCode)) {
153:                 $coupon = Mage::getModel('salesrule/coupon');
154:                 $coupon->load($couponCode, 'code');
155:                 if ($coupon->getId()) {
156:                     // check entire usage limit
157:                     if ($coupon->getUsageLimit() && $coupon->getTimesUsed() >= $coupon->getUsageLimit()) {
158:                         $rule->setIsValidForAddress($address, false);
159:                         return false;
160:                     }
161:                     // check per customer usage limit
162:                     $customerId = $address->getQuote()->getCustomerId();
163:                     if ($customerId && $coupon->getUsagePerCustomer()) {
164:                         $couponUsage = new Varien_Object();
165:                         Mage::getResourceModel('salesrule/coupon_usage')->loadByCustomerCoupon(
166:                             $couponUsage, $customerId, $coupon->getId());
167:                         if ($couponUsage->getCouponId() &&
168:                             $couponUsage->getTimesUsed() >= $coupon->getUsagePerCustomer()
169:                         ) {
170:                             $rule->setIsValidForAddress($address, false);
171:                             return false;
172:                         }
173:                     }
174:                 }
175:             }
176:         }
177: 
178:         /**
179:          * check per rule usage limit
180:          */
181:         $ruleId = $rule->getId();
182:         if ($ruleId && $rule->getUsesPerCustomer()) {
183:             $customerId     = $address->getQuote()->getCustomerId();
184:             $ruleCustomer   = Mage::getModel('salesrule/rule_customer');
185:             $ruleCustomer->loadByCustomerRule($customerId, $ruleId);
186:             if ($ruleCustomer->getId()) {
187:                 if ($ruleCustomer->getTimesUsed() >= $rule->getUsesPerCustomer()) {
188:                     $rule->setIsValidForAddress($address, false);
189:                     return false;
190:                 }
191:             }
192:         }
193:         $rule->afterLoad();
194:         /**
195:          * quote does not meet rule's conditions
196:          */
197:         if (!$rule->validate($address)) {
198:             $rule->setIsValidForAddress($address, false);
199:             return false;
200:         }
201:         /**
202:          * passed all validations, remember to be valid
203:          */
204:         $rule->setIsValidForAddress($address, true);
205:         return true;
206:     }
207: 
208:     /**
209:      * Quote item free shipping ability check
210:      * This process not affect information about applied rules, coupon code etc.
211:      * This information will be added during discount amounts processing
212:      *
213:      * @param   Mage_Sales_Model_Quote_Item_Abstract $item
214:      * @return  Mage_SalesRule_Model_Validator
215:      */
216:     public function processFreeShipping(Mage_Sales_Model_Quote_Item_Abstract $item)
217:     {
218:         $address = $this->_getAddress($item);
219:         $item->setFreeShipping(false);
220: 
221:         foreach ($this->_getRules() as $rule) {
222:             /* @var $rule Mage_SalesRule_Model_Rule */
223:             if (!$this->_canProcessRule($rule, $address)) {
224:                 continue;
225:             }
226: 
227:             if (!$rule->getActions()->validate($item)) {
228:                 continue;
229:             }
230: 
231:             switch ($rule->getSimpleFreeShipping()) {
232:                 case Mage_SalesRule_Model_Rule::FREE_SHIPPING_ITEM:
233:                     $item->setFreeShipping($rule->getDiscountQty() ? $rule->getDiscountQty() : true);
234:                     break;
235: 
236:                 case Mage_SalesRule_Model_Rule::FREE_SHIPPING_ADDRESS:
237:                     $address->setFreeShipping(true);
238:                     break;
239:             }
240:             if ($rule->getStopRulesProcessing()) {
241:                 break;
242:             }
243:         }
244:         return $this;
245:     }
246: 
247:     /**
248:      * Reset quote and address applied rules
249:      *
250:      * @param Mage_Sales_Model_Quote_Address $address
251:      * @return Mage_SalesRule_Model_Validator
252:      */
253:     public function reset(Mage_Sales_Model_Quote_Address $address)
254:     {
255:         if ($this->_isFirstTimeResetRun) {
256:             $address->setAppliedRuleIds('');
257:             $address->getQuote()->setAppliedRuleIds('');
258:             $this->_isFirstTimeResetRun = false;
259:         }
260: 
261:         return $this;
262:     }
263: 
264:     /**
265:      * Quote item discount calculation process
266:      *
267:      * @param   Mage_Sales_Model_Quote_Item_Abstract $item
268:      * @return  Mage_SalesRule_Model_Validator
269:      */
270:     public function process(Mage_Sales_Model_Quote_Item_Abstract $item)
271:     {
272:         $item->setDiscountAmount(0);
273:         $item->setBaseDiscountAmount(0);
274:         $item->setDiscountPercent(0);
275:         $quote      = $item->getQuote();
276:         $address    = $this->_getAddress($item);
277: 
278:         $itemPrice              = $this->_getItemPrice($item);
279:         $baseItemPrice          = $this->_getItemBasePrice($item);
280:         $itemOriginalPrice      = $this->_getItemOriginalPrice($item);
281:         $baseItemOriginalPrice  = $this->_getItemBaseOriginalPrice($item);
282: 
283:         if ($itemPrice < 0) {
284:             return $this;
285:         }
286: 
287:         $appliedRuleIds = array();
288:         foreach ($this->_getRules() as $rule) {
289:             /* @var $rule Mage_SalesRule_Model_Rule */
290:             if (!$this->_canProcessRule($rule, $address)) {
291:                 continue;
292:             }
293: 
294:             if (!$rule->getActions()->validate($item)) {
295:                 continue;
296:             }
297: 
298:             $qty = $this->_getItemQty($item, $rule);
299:             $rulePercent = min(100, $rule->getDiscountAmount());
300: 
301:             $discountAmount = 0;
302:             $baseDiscountAmount = 0;
303:             //discount for original price
304:             $originalDiscountAmount = 0;
305:             $baseOriginalDiscountAmount = 0;
306: 
307:             switch ($rule->getSimpleAction()) {
308:                 case Mage_SalesRule_Model_Rule::TO_PERCENT_ACTION:
309:                     $rulePercent = max(0, 100-$rule->getDiscountAmount());
310:                 //no break;
311:                 case Mage_SalesRule_Model_Rule::BY_PERCENT_ACTION:
312:                     $step = $rule->getDiscountStep();
313:                     if ($step) {
314:                         $qty = floor($qty/$step)*$step;
315:                     }
316:                     $_rulePct = $rulePercent/100;
317:                     $discountAmount    = ($qty*$itemPrice - $item->getDiscountAmount()) * $_rulePct;
318:                     $baseDiscountAmount= ($qty*$baseItemPrice - $item->getBaseDiscountAmount()) * $_rulePct;
319:                     //get discount for original price
320:                     $originalDiscountAmount    = ($qty*$itemOriginalPrice - $item->getDiscountAmount()) * $_rulePct;
321:                     $baseOriginalDiscountAmount= ($qty*$baseItemOriginalPrice - $item->getDiscountAmount()) * $_rulePct;
322: 
323:                     if (!$rule->getDiscountQty() || $rule->getDiscountQty()>$qty) {
324:                         $discountPercent = min(100, $item->getDiscountPercent()+$rulePercent);
325:                         $item->setDiscountPercent($discountPercent);
326:                     }
327:                     break;
328:                 case Mage_SalesRule_Model_Rule::TO_FIXED_ACTION:
329:                     $quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount());
330:                     $discountAmount    = $qty*($itemPrice-$quoteAmount);
331:                     $baseDiscountAmount= $qty*($baseItemPrice-$rule->getDiscountAmount());
332:                     //get discount for original price
333:                     $originalDiscountAmount    = $qty*($itemOriginalPrice-$quoteAmount);
334:                     $baseOriginalDiscountAmount= $qty*($baseItemOriginalPrice-$rule->getDiscountAmount());
335:                     break;
336: 
337:                 case Mage_SalesRule_Model_Rule::BY_FIXED_ACTION:
338:                     $step = $rule->getDiscountStep();
339:                     if ($step) {
340:                         $qty = floor($qty/$step)*$step;
341:                     }
342:                     $quoteAmount        = $quote->getStore()->convertPrice($rule->getDiscountAmount());
343:                     $discountAmount     = $qty*$quoteAmount;
344:                     $baseDiscountAmount = $qty*$rule->getDiscountAmount();
345:                     break;
346: 
347:                 case Mage_SalesRule_Model_Rule::CART_FIXED_ACTION:
348:                     if (empty($this->_rulesItemTotals[$rule->getId()])) {
349:                         Mage::throwException(Mage::helper('salesrule')->__('Item totals are not set for rule.'));
350:                     }
351: 
352:                     /**
353:                      * prevent applying whole cart discount for every shipping order, but only for first order
354:                      */
355:                     if ($quote->getIsMultiShipping()) {
356:                         $usedForAddressId = $this->getCartFixedRuleUsedForAddress($rule->getId());
357:                         if ($usedForAddressId && $usedForAddressId != $address->getId()) {
358:                             break;
359:                         } else {
360:                             $this->setCartFixedRuleUsedForAddress($rule->getId(), $address->getId());
361:                         }
362:                     }
363:                     $cartRules = $address->getCartFixedRules();
364:                     if (!isset($cartRules[$rule->getId()])) {
365:                         $cartRules[$rule->getId()] = $rule->getDiscountAmount();
366:                     }
367: 
368:                     if ($cartRules[$rule->getId()] > 0) {
369:                         if ($this->_rulesItemTotals[$rule->getId()]['items_count'] <= 1) {
370:                             $quoteAmount = $quote->getStore()->convertPrice($cartRules[$rule->getId()]);
371:                             $baseDiscountAmount = min($baseItemPrice * $qty, $cartRules[$rule->getId()]);
372:                         } else {
373:                             $discountRate = $baseItemPrice * $qty /
374:                                             $this->_rulesItemTotals[$rule->getId()]['base_items_price'];
375:                             $maximumItemDiscount = $rule->getDiscountAmount() * $discountRate;
376:                             $quoteAmount = $quote->getStore()->convertPrice($maximumItemDiscount);
377: 
378:                             $baseDiscountAmount = min($baseItemPrice * $qty, $maximumItemDiscount);
379:                             $this->_rulesItemTotals[$rule->getId()]['items_count']--;
380:                         }
381: 
382:                         $discountAmount = min($itemPrice * $qty, $quoteAmount);
383:                         $discountAmount = $quote->getStore()->roundPrice($discountAmount);
384:                         $baseDiscountAmount = $quote->getStore()->roundPrice($baseDiscountAmount);
385: 
386:                         //get discount for original price
387:                         $originalDiscountAmount = min($itemOriginalPrice * $qty, $quoteAmount);
388:                         $baseOriginalDiscountAmount = $quote->getStore()->roundPrice($originalDiscountAmount);
389:                         $baseOriginalDiscountAmount = $quote->getStore()->roundPrice($baseItemOriginalPrice);
390: 
391:                         $cartRules[$rule->getId()] -= $baseDiscountAmount;
392:                     }
393:                     $address->setCartFixedRules($cartRules);
394: 
395:                     break;
396: 
397:                 case Mage_SalesRule_Model_Rule::BUY_X_GET_Y_ACTION:
398:                     $x = $rule->getDiscountStep();
399:                     $y = $rule->getDiscountAmount();
400:                     if (!$x || $y > $x) {
401:                         break;
402:                     }
403:                     $buyAndDiscountQty = $x + $y;
404: 
405:                     $fullRuleQtyPeriod = floor($qty / $buyAndDiscountQty);
406:                     $freeQty  = $qty - $fullRuleQtyPeriod * $buyAndDiscountQty;
407: 
408:                     $discountQty = $fullRuleQtyPeriod * $y;
409:                     if ($freeQty > $x) {
410:                         $discountQty += $freeQty - $x;
411:                     }
412: 
413:                     $discountAmount    = $discountQty * $itemPrice;
414:                     $baseDiscountAmount= $discountQty * $baseItemPrice;
415:                     //get discount for original price
416:                     $originalDiscountAmount    = $discountQty * $itemOriginalPrice;
417:                     $baseOriginalDiscountAmount= $discountQty * $baseItemOriginalPrice;
418:                     break;
419:             }
420: 
421:             $result = new Varien_Object(array(
422:                 'discount_amount'      => $discountAmount,
423:                 'base_discount_amount' => $baseDiscountAmount,
424:             ));
425:             Mage::dispatchEvent('salesrule_validator_process', array(
426:                 'rule'    => $rule,
427:                 'item'    => $item,
428:                 'address' => $address,
429:                 'quote'   => $quote,
430:                 'qty'     => $qty,
431:                 'result'  => $result,
432:             ));
433: 
434:             $discountAmount = $result->getDiscountAmount();
435:             $baseDiscountAmount = $result->getBaseDiscountAmount();
436: 
437:             $percentKey = $item->getDiscountPercent();
438:             /**
439:              * Process "delta" rounding
440:              */
441:             if ($percentKey) {
442:                 $delta      = isset($this->_roundingDeltas[$percentKey]) ? $this->_roundingDeltas[$percentKey] : 0;
443:                 $baseDelta  = isset($this->_baseRoundingDeltas[$percentKey])
444:                         ? $this->_baseRoundingDeltas[$percentKey]
445:                         : 0;
446:                 $discountAmount+= $delta;
447:                 $baseDiscountAmount+=$baseDelta;
448: 
449:                 $this->_roundingDeltas[$percentKey]     = $discountAmount -
450:                                                           $quote->getStore()->roundPrice($discountAmount);
451:                 $this->_baseRoundingDeltas[$percentKey] = $baseDiscountAmount -
452:                                                           $quote->getStore()->roundPrice($baseDiscountAmount);
453:                 $discountAmount = $quote->getStore()->roundPrice($discountAmount);
454:                 $baseDiscountAmount = $quote->getStore()->roundPrice($baseDiscountAmount);
455:             } else {
456:                 $discountAmount     = $quote->getStore()->roundPrice($discountAmount);
457:                 $baseDiscountAmount = $quote->getStore()->roundPrice($baseDiscountAmount);
458:             }
459: 
460:             /**
461:              * We can't use row total here because row total not include tax
462:              * Discount can be applied on price included tax
463:              */
464: 
465:             $itemDiscountAmount = $item->getDiscountAmount();
466:             $itemBaseDiscountAmount = $item->getBaseDiscountAmount();
467: 
468:             $discountAmount     = min($itemDiscountAmount + $discountAmount, $itemPrice * $qty);
469:             $baseDiscountAmount = min($itemBaseDiscountAmount + $baseDiscountAmount, $baseItemPrice * $qty);
470: 
471:             $item->setDiscountAmount($discountAmount);
472:             $item->setBaseDiscountAmount($baseDiscountAmount);
473: 
474:             $item->setOriginalDiscountAmount($originalDiscountAmount);
475:             $item->setBaseOriginalDiscountAmount($baseOriginalDiscountAmount);
476: 
477:             $appliedRuleIds[$rule->getRuleId()] = $rule->getRuleId();
478: 
479:             $this->_maintainAddressCouponCode($address, $rule);
480:             $this->_addDiscountDescription($address, $rule);
481: 
482:             if ($rule->getStopRulesProcessing()) {
483:                 break;
484:             }
485:         }
486: 
487:         $item->setAppliedRuleIds(join(',',$appliedRuleIds));
488:         $address->setAppliedRuleIds($this->mergeIds($address->getAppliedRuleIds(), $appliedRuleIds));
489:         $quote->setAppliedRuleIds($this->mergeIds($quote->getAppliedRuleIds(), $appliedRuleIds));
490: 
491:         return $this;
492:     }
493: 
494:     /**
495:      * Apply discounts to shipping amount
496:      *
497:      * @param   Mage_Sales_Model_Quote_Address $address
498:      * @return  Mage_SalesRule_Model_Validator
499:      */
500:     public function processShippingAmount(Mage_Sales_Model_Quote_Address $address)
501:     {
502:         $shippingAmount     = $address->getShippingAmountForDiscount();
503:         if ($shippingAmount!==null) {
504:             $baseShippingAmount = $address->getBaseShippingAmountForDiscount();
505:         } else {
506:             $shippingAmount     = $address->getShippingAmount();
507:             $baseShippingAmount = $address->getBaseShippingAmount();
508:         }
509:         $quote              = $address->getQuote();
510:         $appliedRuleIds = array();
511:         foreach ($this->_getRules() as $rule) {
512:             /* @var $rule Mage_SalesRule_Model_Rule */
513:             if (!$rule->getApplyToShipping() || !$this->_canProcessRule($rule, $address)) {
514:                 continue;
515:             }
516: 
517:             $discountAmount = 0;
518:             $baseDiscountAmount = 0;
519:             $rulePercent = min(100, $rule->getDiscountAmount());
520:             switch ($rule->getSimpleAction()) {
521:                 case Mage_SalesRule_Model_Rule::TO_PERCENT_ACTION:
522:                     $rulePercent = max(0, 100-$rule->getDiscountAmount());
523:                 case Mage_SalesRule_Model_Rule::BY_PERCENT_ACTION:
524:                     $discountAmount    = ($shippingAmount - $address->getShippingDiscountAmount()) * $rulePercent/100;
525:                     $baseDiscountAmount= ($baseShippingAmount -
526:                                           $address->getBaseShippingDiscountAmount()) * $rulePercent/100;
527:                     $discountPercent = min(100, $address->getShippingDiscountPercent()+$rulePercent);
528:                     $address->setShippingDiscountPercent($discountPercent);
529:                     break;
530:                 case Mage_SalesRule_Model_Rule::TO_FIXED_ACTION:
531:                     $quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount());
532:                     $discountAmount    = $shippingAmount-$quoteAmount;
533:                     $baseDiscountAmount= $baseShippingAmount-$rule->getDiscountAmount();
534:                     break;
535:                 case Mage_SalesRule_Model_Rule::BY_FIXED_ACTION:
536:                     $quoteAmount        = $quote->getStore()->convertPrice($rule->getDiscountAmount());
537:                     $discountAmount     = $quoteAmount;
538:                     $baseDiscountAmount = $rule->getDiscountAmount();
539:                     break;
540:                 case Mage_SalesRule_Model_Rule::CART_FIXED_ACTION:
541:                     $cartRules = $address->getCartFixedRules();
542:                     if (!isset($cartRules[$rule->getId()])) {
543:                         $cartRules[$rule->getId()] = $rule->getDiscountAmount();
544:                     }
545:                     if ($cartRules[$rule->getId()] > 0) {
546:                         $quoteAmount        = $quote->getStore()->convertPrice($cartRules[$rule->getId()]);
547:                         $discountAmount     = min(
548:                             $shippingAmount-$address->getShippingDiscountAmount(),
549:                             $quoteAmount
550:                         );
551:                         $baseDiscountAmount = min(
552:                             $baseShippingAmount-$address->getBaseShippingDiscountAmount(),
553:                             $cartRules[$rule->getId()]
554:                         );
555:                         $cartRules[$rule->getId()] -= $baseDiscountAmount;
556:                     }
557: 
558:                     $address->setCartFixedRules($cartRules);
559:                     break;
560:             }
561: 
562:             $discountAmount     = min($address->getShippingDiscountAmount()+$discountAmount, $shippingAmount);
563:             $baseDiscountAmount = min(
564:                 $address->getBaseShippingDiscountAmount()+$baseDiscountAmount,
565:                 $baseShippingAmount
566:             );
567:             $address->setShippingDiscountAmount($discountAmount);
568:             $address->setBaseShippingDiscountAmount($baseDiscountAmount);
569:             $appliedRuleIds[$rule->getRuleId()] = $rule->getRuleId();
570: 
571:             $this->_maintainAddressCouponCode($address, $rule);
572:             $this->_addDiscountDescription($address, $rule);
573:             if ($rule->getStopRulesProcessing()) {
574:                 break;
575:             }
576:         }
577: 
578:         $address->setAppliedRuleIds($this->mergeIds($address->getAppliedRuleIds(), $appliedRuleIds));
579:         $quote->setAppliedRuleIds($this->mergeIds($quote->getAppliedRuleIds(), $appliedRuleIds));
580: 
581:         return $this;
582:     }
583: 
584:     /**
585:      * Merge two sets of ids
586:      *
587:      * @param array|string $a1
588:      * @param array|string $a2
589:      * @param bool $asString
590:      * @return array
591:      */
592:     public function mergeIds($a1, $a2, $asString = true)
593:     {
594:         if (!is_array($a1)) {
595:             $a1 = empty($a1) ? array() : explode(',', $a1);
596:         }
597:         if (!is_array($a2)) {
598:             $a2 = empty($a2) ? array() : explode(',', $a2);
599:         }
600:         $a = array_unique(array_merge($a1, $a2));
601:         if ($asString) {
602:            $a = implode(',', $a);
603:         }
604:         return $a;
605:     }
606: 
607:     /**
608:      * Set information about usage cart fixed rule by quote address
609:      *
610:      * @param int $ruleId
611:      * @param int $itemId
612:      * @return void
613:      */
614:     public function setCartFixedRuleUsedForAddress($ruleId, $itemId)
615:     {
616:         $this->_cartFixedRuleUsedForAddress[$ruleId] = $itemId;
617:     }
618: 
619:     /**
620:      * Retrieve information about usage cart fixed rule by quote address
621:      *
622:      * @param int $ruleId
623:      * @return int|null
624:      */
625:     public function getCartFixedRuleUsedForAddress($ruleId)
626:     {
627:         if (isset($this->_cartFixedRuleUsedForAddress[$ruleId])) {
628:             return $this->_cartFixedRuleUsedForAddress[$ruleId];
629:         }
630:         return null;
631:     }
632: 
633:     /**
634:      * Calculate quote totals for each rule and save results
635:      *
636:      * @param mixed $items
637:      * @param Mage_Sales_Model_Quote_Address $address
638:      * @return Mage_SalesRule_Model_Validator
639:      */
640:     public function initTotals($items, Mage_Sales_Model_Quote_Address $address)
641:     {
642:         $address->setCartFixedRules(array());
643: 
644:         if (!$items) {
645:             return $this;
646:         }
647: 
648:         foreach ($this->_getRules() as $rule) {
649:             if (Mage_SalesRule_Model_Rule::CART_FIXED_ACTION == $rule->getSimpleAction()
650:                 && $this->_canProcessRule($rule, $address)) {
651: 
652:                 $ruleTotalItemsPrice = 0;
653:                 $ruleTotalBaseItemsPrice = 0;
654:                 $validItemsCount = 0;
655: 
656:                 foreach ($items as $item) {
657:                     //Skipping child items to avoid double calculations
658:                     if ($item->getParentItemId()) {
659:                         continue;
660:                     }
661:                     if (!$rule->getActions()->validate($item)) {
662:                         continue;
663:                     }
664:                     $qty = $this->_getItemQty($item, $rule);
665:                     $ruleTotalItemsPrice += $this->_getItemPrice($item) * $qty;
666:                     $ruleTotalBaseItemsPrice += $this->_getItemBasePrice($item) * $qty;
667:                     $validItemsCount++;
668:                 }
669: 
670:                 $this->_rulesItemTotals[$rule->getId()] = array(
671:                     'items_price' => $ruleTotalItemsPrice,
672:                     'base_items_price' => $ruleTotalBaseItemsPrice,
673:                     'items_count' => $validItemsCount,
674:                 );
675:             }
676:         }
677: 
678:         return $this;
679:     }
680: 
681:     /**
682:      * Set coupon code to address if $rule contains validated coupon
683:      *
684:      * @param  Mage_Sales_Model_Quote_Address $address
685:      * @param  Mage_SalesRule_Model_Rule $rule
686:      *
687:      * @return Mage_SalesRule_Model_Validator
688:      */
689:     protected function _maintainAddressCouponCode($address, $rule)
690:     {
691:         /*
692:         Rule is a part of rules collection, which includes only rules with 'No Coupon' type or with validated coupon.
693:         As a result, if rule uses coupon code(s) ('Specific' or 'Auto' Coupon Type), it always contains validated coupon
694:         */
695:         if ($rule->getCouponType() != Mage_SalesRule_Model_Rule::COUPON_TYPE_NO_COUPON) {
696:             $address->setCouponCode($this->getCouponCode());
697:         }
698: 
699:         return $this;
700:     }
701: 
702:     /**
703:      * Add rule discount description label to address object
704:      *
705:      * @param   Mage_Sales_Model_Quote_Address $address
706:      * @param   Mage_SalesRule_Model_Rule $rule
707:      * @return  Mage_SalesRule_Model_Validator
708:      */
709:     protected function _addDiscountDescription($address, $rule)
710:     {
711:         $description = $address->getDiscountDescriptionArray();
712:         $ruleLabel = $rule->getStoreLabel($address->getQuote()->getStore());
713:         $label = '';
714:         if ($ruleLabel) {
715:             $label = $ruleLabel;
716:         } else if (strlen($address->getCouponCode())) {
717:             $label = $address->getCouponCode();
718:         }
719: 
720:         if (strlen($label)) {
721:             $description[$rule->getId()] = $label;
722:         }
723: 
724:         $address->setDiscountDescriptionArray($description);
725: 
726:         return $this;
727:     }
728: 
729:     /**
730:      * Return item price
731:      *
732:      * @param Mage_Sales_Model_Quote_Item_Abstract $item
733:      * @return float
734:      */
735:     protected function _getItemPrice($item)
736:     {
737:         $price = $item->getDiscountCalculationPrice();
738:         $calcPrice = $item->getCalculationPrice();
739:         return ($price !== null) ? $price : $calcPrice;
740:     }
741: 
742:     /**
743:      * Return item original price
744:      *
745:      * @param Mage_Sales_Model_Quote_Item_Abstract $item
746:      * @return float
747:      */
748:     protected function _getItemOriginalPrice($item)
749:     {
750:         return Mage::helper('tax')->getPrice($item, $item->getOriginalPrice(), true);
751:     }
752: 
753:     /**
754:      * Return item base price
755:      *
756:      * @param Mage_Sales_Model_Quote_Item_Abstract $item
757:      * @return float
758:      */
759:     protected function _getItemBasePrice($item)
760:     {
761:         $price = $item->getDiscountCalculationPrice();
762:         return ($price !== null) ? $item->getBaseDiscountCalculationPrice() : $item->getBaseCalculationPrice();
763:     }
764: 
765:     /**
766:      * Return item base original price
767:      *
768:      * @param Mage_Sales_Model_Quote_Item_Abstract $item
769:      * @return float
770:      */
771:     protected function _getItemBaseOriginalPrice($item)
772:     {
773:         return Mage::helper('tax')->getPrice($item, $item->getBaseOriginalPrice(), true);
774:     }
775: 
776:     /**
777:      * Return discount item qty
778:      *
779:      * @param Mage_Sales_Model_Quote_Item_Abstract $item
780:      * @param Mage_SalesRule_Model_Rule $rule
781:      * @return int
782:      */
783:     protected function _getItemQty($item, $rule)
784:     {
785:         $qty = $item->getTotalQty();
786:         return $rule->getDiscountQty() ? min($qty, $rule->getDiscountQty()) : $qty;
787:     }
788: 
789:     /**
790:      * Convert address discount description array to string
791:      *
792:      * @param Mage_Sales_Model_Quote_Address $address
793:      * @param string $separator
794:      * @return Mage_SalesRule_Model_Validator
795:      */
796:     public function prepareDescription($address, $separator=', ')
797:     {
798:         $description = $address->getDiscountDescriptionArray();
799: 
800:         if (is_array($description) && !empty($description)) {
801:             $description = array_unique($description);
802:             $description = implode($separator, $description);
803:         } else {
804:             $description = '';
805:         }
806:         $address->setDiscountDescription($description);
807:         return $this;
808:     }
809: 
810: 
811: 
812: }
813: 
Magento 1.7.0.2 API documentation generated by ApiGen 2.8.0