00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 class Mage_SalesRule_Model_Validator extends Mage_Core_Model_Abstract
00038 {
00039
00040
00041
00042
00043
00044 protected $_rules;
00045
00046 protected function _construct()
00047 {
00048 parent::_construct();
00049 $this->_init('salesrule/validator');
00050 }
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 public function init($websiteId, $customerGroupId, $couponCode)
00061 {
00062 $this->setWebsiteId($websiteId)
00063 ->setCustomerGroupId($customerGroupId)
00064 ->setCouponCode($couponCode);
00065
00066 $this->_rules = Mage::getResourceModel('salesrule/rule_collection')
00067 ->setValidationFilter($websiteId, $customerGroupId, $couponCode)
00068 ->load();
00069
00070 return $this;
00071 }
00072
00073 public function process(Mage_Sales_Model_Quote_Item_Abstract $item)
00074 {
00075 $item->setFreeShipping(false);
00076 $item->setDiscountAmount(0);
00077 $item->setBaseDiscountAmount(0);
00078 $item->setDiscountPercent(0);
00079
00080 $quote = $item->getQuote();
00081 if ($item instanceof Mage_Sales_Model_Quote_Address_Item) {
00082 $address = $item->getAddress();
00083 } elseif ($quote->isVirtual()) {
00084 $address = $quote->getBillingAddress();
00085 } else {
00086 $address = $quote->getShippingAddress();
00087 }
00088
00089 $customerId = $quote->getCustomerId();
00090 $ruleCustomer = Mage::getModel('salesrule/rule_customer');
00091 $appliedRuleIds = array();
00092
00093 foreach ($this->_rules as $rule) {
00094
00095
00096
00097
00098 if ($rule->getIsValid() === false) {
00099 continue;
00100 }
00101
00102 if ($rule->getIsValid() !== true) {
00103
00104
00105
00106 if ($rule->getUsesPerCoupon() && ($rule->getTimesUsed() >= $rule->getUsesPerCoupon())) {
00107 $rule->setIsValid(false);
00108 continue;
00109 }
00110
00111
00112
00113 $ruleId = $rule->getId();
00114 if ($ruleId && $rule->getUsesPerCustomer()) {
00115 $ruleCustomer->loadByCustomerRule($customerId, $ruleId);
00116 if ($ruleCustomer->getId()) {
00117 if ($ruleCustomer->getTimesUsed() >= $rule->getUsesPerCustomer()) {
00118 continue;
00119 }
00120 }
00121 }
00122 $rule->afterLoad();
00123
00124
00125
00126 if (!$rule->validate($address)) {
00127 $rule->setIsValid(false);
00128 continue;
00129 }
00130
00131
00132
00133 $rule->setIsValid(true);
00134 }
00135
00136
00137
00138
00139 if (!$rule->getActions()->validate($item)) {
00140 continue;
00141 }
00142 $qty = $item->getQty();
00143 if ($item->getParentItem()) {
00144 $qty*= $item->getParentItem()->getQty();
00145 }
00146 $qty = $rule->getDiscountQty() ? min($qty, $rule->getDiscountQty()) : $qty;
00147 $rulePercent = min(100, $rule->getDiscountAmount());
00148 $discountAmount = 0;
00149 $baseDiscountAmount = 0;
00150 switch ($rule->getSimpleAction()) {
00151 case 'to_percent':
00152 $rulePercent = max(0, 100-$rule->getDiscountAmount());
00153
00154
00155 case 'by_percent':
00156 if ($step = $rule->getDiscountStep()) {
00157 $qty = floor($qty/$step)*$step;
00158 }
00159 $discountAmount = ($qty*$item->getCalculationPrice() - $item->getDiscountAmount()) * $rulePercent/100;
00160 $baseDiscountAmount= ($qty*$item->getBaseCalculationPrice() - $item->getBaseDiscountAmount()) * $rulePercent/100;
00161
00162 if (!$rule->getDiscountQty() || $rule->getDiscountQty()>$qty) {
00163 $discountPercent = min(100, $item->getDiscountPercent()+$rulePercent);
00164 $item->setDiscountPercent($discountPercent);
00165 }
00166 break;
00167
00168 case 'to_fixed':
00169 $quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount());
00170 $discountAmount = $qty*($item->getCalculationPrice()-$quoteAmount);
00171 $baseDiscountAmount= $qty*($item->getBaseCalculationPrice()-$rule->getDiscountAmount());
00172 break;
00173
00174 case 'by_fixed':
00175 if ($step = $rule->getDiscountStep()) {
00176 $qty = floor($qty/$step)*$step;
00177 }
00178 $quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount());
00179 $discountAmount = $qty*$quoteAmount;
00180 $baseDiscountAmount= $qty*$rule->getDiscountAmount();
00181 break;
00182
00183 case 'cart_fixed':
00184 $cartRules = $address->getCartFixedRules();
00185 if (!isset($cartRules[$rule->getId()])) {
00186 $cartRules[$rule->getId()] = $rule->getDiscountAmount();
00187 }
00188 if ($cartRules[$rule->getId()] > 0) {
00189 $quoteAmount = $quote->getStore()->convertPrice($cartRules[$rule->getId()]);
00190 $discountAmount = min($item->getRowTotal(), $quoteAmount);
00191 $baseDiscountAmount = min($item->getBaseRowTotal(), $cartRules[$rule->getId()]);
00192 $cartRules[$rule->getId()] -= $baseDiscountAmount;
00193 }
00194 $address->setCartFixedRules($cartRules);
00195 break;
00196
00197 case 'buy_x_get_y':
00198 $x = $rule->getDiscountStep();
00199 $y = $rule->getDiscountAmount();
00200 if (!$x || $y>=$x) {
00201 break;
00202 }
00203 $buy = 0; $free = 0;
00204 while ($buy+$free<$qty) {
00205 $buy += $x;
00206 if ($buy+$free>=$qty) {
00207 break;
00208 }
00209 $free += min($y, $qty-$buy-$free);
00210 if ($buy+$free>=$qty) {
00211 break;
00212 }
00213 }
00214 $discountAmount = $free*$item->getCalculationPrice();
00215 $baseDiscountAmount= $free*$item->getBaseCalculationPrice();
00216 break;
00217 }
00218
00219 $result = new Varien_Object(array(
00220 'discount_amount' => $discountAmount,
00221 'base_discount_amount' => $baseDiscountAmount,
00222 ));
00223 Mage::dispatchEvent('salesrule_validator_process', array(
00224 'rule' => $rule,
00225 'item' => $item,
00226 'address' => $address,
00227 'quote' => $quote,
00228 'qty' => $qty,
00229 'result' => $result,
00230 ));
00231
00232 $discountAmount = $result->getDiscountAmount();
00233 $baseDiscountAmount = $result->getBaseDiscountAmount();
00234
00235 $discountAmount = $quote->getStore()->roundPrice($discountAmount);
00236 $baseDiscountAmount = $quote->getStore()->roundPrice($baseDiscountAmount);
00237 $discountAmount = min($item->getDiscountAmount()+$discountAmount, $item->getRowTotal());
00238 $baseDiscountAmount = min($item->getBaseDiscountAmount()+$baseDiscountAmount, $item->getBaseRowTotal());
00239
00240 $item->setDiscountAmount($discountAmount);
00241 $item->setBaseDiscountAmount($baseDiscountAmount);
00242
00243 switch ($rule->getSimpleFreeShipping()) {
00244 case Mage_SalesRule_Model_Rule::FREE_SHIPPING_ITEM:
00245 $item->setFreeShipping($rule->getDiscountQty() ? $rule->getDiscountQty() : true);
00246 break;
00247
00248 case Mage_SalesRule_Model_Rule::FREE_SHIPPING_ADDRESS:
00249 $address->setFreeShipping(true);
00250 break;
00251 }
00252
00253 $appliedRuleIds[$rule->getRuleId()] = $rule->getRuleId();
00254
00255 if ($rule->getCouponCode() && ( strtolower($rule->getCouponCode()) == strtolower($this->getCouponCode()))) {
00256 $address->setCouponCode($this->getCouponCode());
00257 }
00258
00259 if ($rule->getStopRulesProcessing()) {
00260 break;
00261 }
00262 }
00263 $item->setAppliedRuleIds(join(',',$appliedRuleIds));
00264 $address->setAppliedRuleIds($this->mergeIds($address->getAppliedRuleIds(), $appliedRuleIds));
00265 $quote->setAppliedRuleIds($this->mergeIds($quote->getAppliedRuleIds(), $appliedRuleIds));
00266 return $this;
00267 }
00268
00269 public function mergeIds($a1, $a2, $asString=true)
00270 {
00271 if (!is_array($a1)) {
00272 $a1 = empty($a1) ? array() : explode(',', $a1);
00273 }
00274 if (!is_array($a2)) {
00275 $a2 = empty($a2) ? array() : explode(',', $a2);
00276 }
00277 $a = array_unique(array_merge($a1, $a2));
00278 if ($asString) {
00279 $a = implode(',', $a);
00280 }
00281 return $a;
00282 }
00283 }