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: * Shopping Cart Rule data model
30: *
31: * @method Mage_SalesRule_Model_Resource_Rule _getResource()
32: * @method Mage_SalesRule_Model_Resource_Rule getResource()
33: * @method string getName()
34: * @method Mage_SalesRule_Model_Rule setName(string $value)
35: * @method string getDescription()
36: * @method Mage_SalesRule_Model_Rule setDescription(string $value)
37: * @method string getFromDate()
38: * @method Mage_SalesRule_Model_Rule setFromDate(string $value)
39: * @method string getToDate()
40: * @method Mage_SalesRule_Model_Rule setToDate(string $value)
41: * @method int getUsesPerCustomer()
42: * @method Mage_SalesRule_Model_Rule setUsesPerCustomer(int $value)
43: * @method int getUsesPerCoupon()
44: * @method Mage_SalesRule_Model_Rule setUsesPerCoupon(int $value)
45: * @method string getCustomerGroupIds()
46: * @method Mage_SalesRule_Model_Rule setCustomerGroupIds(string $value)
47: * @method int getIsActive()
48: * @method Mage_SalesRule_Model_Rule setIsActive(int $value)
49: * @method string getConditionsSerialized()
50: * @method Mage_SalesRule_Model_Rule setConditionsSerialized(string $value)
51: * @method string getActionsSerialized()
52: * @method Mage_SalesRule_Model_Rule setActionsSerialized(string $value)
53: * @method int getStopRulesProcessing()
54: * @method Mage_SalesRule_Model_Rule setStopRulesProcessing(int $value)
55: * @method int getIsAdvanced()
56: * @method Mage_SalesRule_Model_Rule setIsAdvanced(int $value)
57: * @method string getProductIds()
58: * @method Mage_SalesRule_Model_Rule setProductIds(string $value)
59: * @method int getSortOrder()
60: * @method Mage_SalesRule_Model_Rule setSortOrder(int $value)
61: * @method string getSimpleAction()
62: * @method Mage_SalesRule_Model_Rule setSimpleAction(string $value)
63: * @method float getDiscountAmount()
64: * @method Mage_SalesRule_Model_Rule setDiscountAmount(float $value)
65: * @method float getDiscountQty()
66: * @method Mage_SalesRule_Model_Rule setDiscountQty(float $value)
67: * @method int getDiscountStep()
68: * @method Mage_SalesRule_Model_Rule setDiscountStep(int $value)
69: * @method int getSimpleFreeShipping()
70: * @method Mage_SalesRule_Model_Rule setSimpleFreeShipping(int $value)
71: * @method int getApplyToShipping()
72: * @method Mage_SalesRule_Model_Rule setApplyToShipping(int $value)
73: * @method int getTimesUsed()
74: * @method Mage_SalesRule_Model_Rule setTimesUsed(int $value)
75: * @method int getIsRss()
76: * @method Mage_SalesRule_Model_Rule setIsRss(int $value)
77: * @method string getWebsiteIds()
78: * @method Mage_SalesRule_Model_Rule setWebsiteIds(string $value)
79: * @method int getCouponType()
80: * @method Mage_SalesRule_Model_Rule setCouponType(int $value)
81: * @method int getUseAutoGeneration()
82: * @method Mage_SalesRule_Model_Rule setUseAutoGeneration(int $value)
83: * @method string getCouponCode()
84: * @method Mage_SalesRule_Model_Rule setCouponCode(string $value)
85: *
86: * @category Mage
87: * @package Mage_SalesRule
88: * @author Magento Core Team <core@magentocommerce.com>
89: */
90: class Mage_SalesRule_Model_Rule extends Mage_Rule_Model_Abstract
91: {
92: /**
93: * Free Shipping option "For matching items only"
94: */
95: const FREE_SHIPPING_ITEM = 1;
96:
97: /**
98: * Free Shipping option "For shipment with matching items"
99: */
100: const FREE_SHIPPING_ADDRESS = 2;
101:
102: /**
103: * Coupon types
104: */
105: const COUPON_TYPE_NO_COUPON = 1;
106: const COUPON_TYPE_SPECIFIC = 2;
107: const COUPON_TYPE_AUTO = 3;
108:
109: /**
110: * Rule type actions
111: */
112: const TO_PERCENT_ACTION = 'to_percent';
113: const BY_PERCENT_ACTION = 'by_percent';
114: const TO_FIXED_ACTION = 'to_fixed';
115: const BY_FIXED_ACTION = 'by_fixed';
116: const CART_FIXED_ACTION = 'cart_fixed';
117: const BUY_X_GET_Y_ACTION = 'buy_x_get_y';
118:
119: /**
120: * Store coupon code generator instance
121: *
122: * @var Mage_SalesRule_Model_Coupon_CodegeneratorInterface
123: */
124: protected static $_couponCodeGenerator;
125:
126: /**
127: * Prefix of model events names
128: *
129: * @var string
130: */
131: protected $_eventPrefix = 'salesrule_rule';
132:
133: /**
134: * Parameter name in event
135: *
136: * In observe method you can use $observer->getEvent()->getRule() in this case
137: *
138: * @var string
139: */
140: protected $_eventObject = 'rule';
141:
142: /**
143: * Contain sores labels
144: *
145: * @deprecated after 1.6.2.0
146: *
147: * @var array
148: */
149: protected $_labels = array();
150:
151: /**
152: * Rule's primary coupon
153: *
154: * @var Mage_SalesRule_Model_Coupon
155: */
156: protected $_primaryCoupon;
157:
158: /**
159: * Rule's subordinate coupons
160: *
161: * @var array of Mage_SalesRule_Model_Coupon
162: */
163: protected $_coupons;
164:
165: /**
166: * Coupon types cache for lazy getter
167: *
168: * @var array
169: */
170: protected $_couponTypes;
171:
172: /**
173: * Store already validated addresses and validation results
174: *
175: * @var array
176: */
177: protected $_validatedAddresses = array();
178:
179: /**
180: * Set resource model and Id field name
181: */
182: protected function _construct()
183: {
184: parent::_construct();
185: $this->_init('salesrule/rule');
186: $this->setIdFieldName('rule_id');
187: }
188:
189: /**
190: * Returns code mass generator instance for auto generated specific coupons
191: *
192: * @return Mage_SalesRule_Model_Coupon_MassgneratorInterface
193: */
194: public static function getCouponMassGenerator()
195: {
196: return Mage::getSingleton('salesrule/coupon_massgenerator');
197: }
198:
199: /**
200: * Set coupon code and uses per coupon
201: *
202: * @return Mage_SalesRule_Model_Rule
203: */
204: protected function _afterLoad()
205: {
206: $this->setCouponCode($this->getPrimaryCoupon()->getCode());
207: if ($this->getUsesPerCoupon() !== null && !$this->getUseAutoGeneration()) {
208: $this->setUsesPerCoupon($this->getPrimaryCoupon()->getUsageLimit());
209: }
210: return parent::_afterLoad();
211: }
212:
213: /**
214: * Save/delete coupon
215: *
216: * @return Mage_SalesRule_Model_Rule
217: */
218: protected function _afterSave()
219: {
220: $couponCode = trim($this->getCouponCode());
221: if (strlen($couponCode)
222: && $this->getCouponType() == self::COUPON_TYPE_SPECIFIC
223: && !$this->getUseAutoGeneration()
224: ) {
225: $this->getPrimaryCoupon()
226: ->setCode($couponCode)
227: ->setUsageLimit($this->getUsesPerCoupon() ? $this->getUsesPerCoupon() : null)
228: ->setUsagePerCustomer($this->getUsesPerCustomer() ? $this->getUsesPerCustomer() : null)
229: ->setExpirationDate($this->getToDate())
230: ->save();
231: } else {
232: $this->getPrimaryCoupon()->delete();
233: }
234:
235: parent::_afterSave();
236: return $this;
237: }
238:
239: /**
240: * Initialize rule model data from array.
241: * Set store labels if applicable.
242: *
243: * @param array $data
244: *
245: * @return Mage_SalesRule_Model_Rule
246: */
247: public function loadPost(array $data)
248: {
249: parent::loadPost($data);
250:
251: if (isset($data['store_labels'])) {
252: $this->setStoreLabels($data['store_labels']);
253: }
254:
255: return $this;
256: }
257:
258: /**
259: * Get rule condition combine model instance
260: *
261: * @return Mage_SalesRule_Model_Rule_Condition_Combine
262: */
263: public function getConditionsInstance()
264: {
265: return Mage::getModel('salesrule/rule_condition_combine');
266: }
267:
268: /**
269: * Get rule condition product combine model instance
270: *
271: * @return Mage_SalesRule_Model_Rule_Condition_Product_Combine
272: */
273: public function getActionsInstance()
274: {
275: return Mage::getModel('salesrule/rule_condition_product_combine');
276: }
277:
278: /**
279: * Returns code generator instance for auto generated coupons
280: *
281: * @return Mage_SalesRule_Model_Coupon_CodegeneratorInterface
282: */
283: public static function getCouponCodeGenerator()
284: {
285: if (!self::$_couponCodeGenerator) {
286: return Mage::getSingleton('salesrule/coupon_codegenerator', array('length' => 16));
287: }
288: return self::$_couponCodeGenerator;
289: }
290:
291: /**
292: * Set code generator instance for auto generated coupons
293: *
294: * @param Mage_SalesRule_Model_Coupon_CodegeneratorInterface
295: */
296: public static function setCouponCodeGenerator(Mage_SalesRule_Model_Coupon_CodegeneratorInterface $codeGenerator)
297: {
298: self::$_couponCodeGenerator = $codeGenerator;
299: }
300:
301: /**
302: * Retrieve rule's primary coupon
303: *
304: * @return Mage_SalesRule_Model_Coupon
305: */
306: public function getPrimaryCoupon()
307: {
308: if ($this->_primaryCoupon === null) {
309: $this->_primaryCoupon = Mage::getModel('salesrule/coupon');
310: $this->_primaryCoupon->loadPrimaryByRule($this->getId());
311: $this->_primaryCoupon->setRule($this)->setIsPrimary(true);
312: }
313: return $this->_primaryCoupon;
314: }
315:
316: /**
317: * Get sales rule customer group Ids
318: *
319: * @return array
320: */
321: public function getCustomerGroupIds()
322: {
323: if (!$this->hasCustomerGroupIds()) {
324: $customerGroupIds = $this->_getResource()->getCustomerGroupIds($this->getId());
325: $this->setData('customer_group_ids', (array)$customerGroupIds);
326: }
327: return $this->_getData('customer_group_ids');
328: }
329:
330: /**
331: * Get Rule label by specified store
332: *
333: * @param Mage_Core_Model_Store|int|bool|null $store
334: *
335: * @return string|bool
336: */
337: public function getStoreLabel($store = null)
338: {
339: $storeId = Mage::app()->getStore($store)->getId();
340: $labels = (array)$this->getStoreLabels();
341:
342: if (isset($labels[$storeId])) {
343: return $labels[$storeId];
344: } elseif (isset($labels[0]) && $labels[0]) {
345: return $labels[0];
346: }
347:
348: return false;
349: }
350:
351: /**
352: * Set if not yet and retrieve rule store labels
353: *
354: * @return array
355: */
356: public function getStoreLabels()
357: {
358: if (!$this->hasStoreLabels()) {
359: $labels = $this->_getResource()->getStoreLabels($this->getId());
360: $this->setStoreLabels($labels);
361: }
362:
363: return $this->_getData('store_labels');
364: }
365:
366: /**
367: * Retrieve subordinate coupons
368: *
369: * @return array of Mage_SalesRule_Model_Coupon
370: */
371: public function getCoupons()
372: {
373: if ($this->_coupons === null) {
374: $collection = Mage::getResourceModel('salesrule/coupon_collection');
375: /** @var Mage_SalesRule_Model_Resource_Coupon_Collection */
376: $collection->addRuleToFilter($this);
377: $this->_coupons = $collection->getItems();
378: }
379: return $this->_coupons;
380: }
381:
382: /**
383: * Retrieve coupon types
384: *
385: * @return array
386: */
387: public function getCouponTypes()
388: {
389: if ($this->_couponTypes === null) {
390: $this->_couponTypes = array(
391: Mage_SalesRule_Model_Rule::COUPON_TYPE_NO_COUPON => Mage::helper('salesrule')->__('No Coupon'),
392: Mage_SalesRule_Model_Rule::COUPON_TYPE_SPECIFIC => Mage::helper('salesrule')->__('Specific Coupon'),
393: );
394: $transport = new Varien_Object(array(
395: 'coupon_types' => $this->_couponTypes,
396: 'is_coupon_type_auto_visible' => false
397: ));
398: Mage::dispatchEvent('salesrule_rule_get_coupon_types', array('transport' => $transport));
399: $this->_couponTypes = $transport->getCouponTypes();
400: if ($transport->getIsCouponTypeAutoVisible()) {
401: $this->_couponTypes[Mage_SalesRule_Model_Rule::COUPON_TYPE_AUTO] = Mage::helper('salesrule')->__('Auto');
402: }
403: }
404: return $this->_couponTypes;
405: }
406:
407: /**
408: * Acquire coupon instance
409: *
410: * @param bool $saveNewlyCreated Whether or not to save newly created coupon
411: * @param int $saveAttemptCount Number of attempts to save newly created coupon
412: *
413: * @return Mage_SalesRule_Model_Coupon|null
414: */
415: public function acquireCoupon($saveNewlyCreated = true, $saveAttemptCount = 10)
416: {
417: if ($this->getCouponType() == self::COUPON_TYPE_NO_COUPON) {
418: return null;
419: }
420: if ($this->getCouponType() == self::COUPON_TYPE_SPECIFIC) {
421: return $this->getPrimaryCoupon();
422: }
423: /** @var Mage_SalesRule_Model_Coupon $coupon */
424: $coupon = Mage::getModel('salesrule/coupon');
425: $coupon->setRule($this)
426: ->setIsPrimary(false)
427: ->setUsageLimit($this->getUsesPerCoupon() ? $this->getUsesPerCoupon() : null)
428: ->setUsagePerCustomer($this->getUsesPerCustomer() ? $this->getUsesPerCustomer() : null)
429: ->setExpirationDate($this->getToDate());
430:
431: $couponCode = self::getCouponCodeGenerator()->generateCode();
432: $coupon->setCode($couponCode);
433:
434: $ok = false;
435: if (!$saveNewlyCreated) {
436: $ok = true;
437: } else if ($this->getId()) {
438: for ($attemptNum = 0; $attemptNum < $saveAttemptCount; $attemptNum++) {
439: try {
440: $coupon->save();
441: } catch (Exception $e) {
442: if ($e instanceof Mage_Core_Exception || $coupon->getId()) {
443: throw $e;
444: }
445: $coupon->setCode(
446: $couponCode .
447: self::getCouponCodeGenerator()->getDelimiter() .
448: sprintf('%04u', rand(0, 9999))
449: );
450: continue;
451: }
452: $ok = true;
453: break;
454: }
455: }
456: if (!$ok) {
457: Mage::throwException(Mage::helper('salesrule')->__('Can\'t acquire coupon.'));
458: }
459:
460: return $coupon;
461: }
462:
463: /**
464: * Check cached validation result for specific address
465: *
466: * @param Mage_Sales_Model_Quote_Address $address
467: * @return bool
468: */
469: public function hasIsValidForAddress($address)
470: {
471: $addressId = $this->_getAddressId($address);
472: return isset($this->_validatedAddresses[$addressId]) ? true : false;
473: }
474:
475: /**
476: * Set validation result for specific address to results cache
477: *
478: * @param Mage_Sales_Model_Quote_Address $address
479: * @param bool $validationResult
480: * @return Mage_SalesRule_Model_Rule
481: */
482: public function setIsValidForAddress($address, $validationResult)
483: {
484: $addressId = $this->_getAddressId($address);
485: $this->_validatedAddresses[$addressId] = $validationResult;
486: return $this;
487: }
488:
489: /**
490: * Get cached validation result for specific address
491: *
492: * @param Mage_Sales_Model_Quote_Address $address
493: * @return bool
494: */
495: public function getIsValidForAddress($address)
496: {
497: $addressId = $this->_getAddressId($address);
498: return isset($this->_validatedAddresses[$addressId]) ? $this->_validatedAddresses[$addressId] : false;
499: }
500:
501: /**
502: * Return id for address
503: *
504: * @param Mage_Sales_Model_Quote_Address $address
505: * @return string
506: */
507: private function _getAddressId($address) {
508: if($address instanceof Mage_Sales_Model_Quote_Address) {
509: return $address->getId();
510: }
511: return $address;
512: }
513:
514:
515:
516:
517:
518: /**
519: * Collect all product attributes used in serialized rule's action or condition
520: *
521: * @deprecated after 1.6.2.0 use Mage_SalesRule_Model_Resource_Rule::getProductAttributes() instead
522: *
523: * @param string $serializedString
524: *
525: * @return array
526: */
527: protected function _getUsedAttributes($serializedString)
528: {
529: return $this->_getResource()->getProductAttributes($serializedString);
530: }
531:
532: /**
533: * @deprecated after 1.6.2.0
534: *
535: * @param string $format
536: *
537: * @return string
538: */
539: public function toString($format='')
540: {
541: return '';
542: }
543:
544: /**
545: * Returns rule as an array for admin interface
546: *
547: * @deprecated after 1.6.2.0
548: *
549: * @param array $arrAttributes
550: *
551: * Output example:
552: * array(
553: * 'name'=>'Example rule',
554: * 'conditions'=>{condition_combine::toArray}
555: * 'actions'=>{action_collection::toArray}
556: * )
557: *
558: * @return array
559: */
560: public function toArray(array $arrAttributes = array())
561: {
562: return parent::toArray($arrAttributes);
563: }
564: }
565: