/** * @param Mage_Sales_Model_Quote_Address $address * @param Mage_SalesRule_Model_Rule $rule * @param Mage_Sales_Model_Quote_Item_Abstract[] $allItems * @param Mage_Sales_Model_Quote_Item_Abstract[] $validItems * * @return bool */ public function handle(Mage_Sales_Model_Quote_Address $address, Mage_SalesRule_Model_Rule $rule, array $allItems, array $validItems) { if ($rule->getSimpleAction() !== Mage_SalesRule_Model_Rule::BUY_X_GET_Y_ACTION) { return false; } $helper = $this->getHelper(); // Get the X and Y values $x = max(floatval($rule->getDiscountStep()), 0.0); $y = max(floatval($rule->getDiscountAmount()), 0.0); if ($x <= 0.0 || $y <= 0.0) { return false; } // Get the discount step size $step = $x + $y; $applied = false; foreach ($validItems as $item) { // Get max quantity $qty = $helper->getItemRuleQty($item, $rule); // Apply discount step size limitation $qty = max($qty - ceil($qty / $step) * $x, 0.0); if ($qty <= 0.0) { continue; } $applied = true; // Get unit prices $itemPrice = $helper->getItemPrice($item); $itemBasePrice = $helper->getItemBasePrice($item); $itemOriginalPrice = $helper->getItemOriginalPrice($item); $itemBaseOriginalPrice = $helper->getItemBaseOriginalPrice($item); // Calculate discount amounts $discountAmount = $itemPrice * $qty; $originalDiscountAmount = $itemOriginalPrice * $qty; $baseDiscountAmount = $itemBasePrice * $qty; $baseOriginalDiscountAmount = $itemBaseOriginalPrice * $qty; // Round the discount amounts $discountAmount = $helper->round($discountAmount, $address->getQuote()->getQuoteCurrencyCode()); $baseDiscountAmount = $helper->round($baseDiscountAmount, $address->getQuote()->getBaseCurrencyCode()); $originalDiscountAmount = $helper->round($originalDiscountAmount, $address->getQuote()->getQuoteCurrencyCode()); $baseOriginalDiscountAmount = $helper->round($baseOriginalDiscountAmount, $address->getQuote()->getBaseCurrencyCode()); // Update the item discounts $item->setDiscountAmount($item->getDiscountAmount() + $discountAmount); $item->setBaseDiscountAmount($item->getBaseDiscountAmount() + $baseDiscountAmount); $item->setOriginalDiscountAmount($item->getOriginalDiscountAmount() + $originalDiscountAmount); $item->setBaseOriginalDiscountAmount($item->getBaseOriginalDiscountAmount() + $baseOriginalDiscountAmount); } return $applied; }
/** * @param Mage_Sales_Model_Quote_Address $address * @param Mage_SalesRule_Model_Rule $rule * @param Mage_Sales_Model_Quote_Item_Abstract[] $allItems * @param Mage_Sales_Model_Quote_Item_Abstract[] $validItems * * @return bool */ public function handle(Mage_Sales_Model_Quote_Address $address, Mage_SalesRule_Model_Rule $rule, array $allItems, array $validItems) { // Skip invalid rule actions if ($rule->getSimpleAction() !== Mage_SalesRule_Model_Rule::BY_FIXED_ACTION) { return false; } // Skip if there are no valid items and it's not applied to shipping if (!count($validItems) && !$rule->getApplyToShipping()) { return false; } // Define a few helpful variables $helper = $this->getHelper(); $quote = $address->getQuote(); $store = $quote->getStore(); // Discount amount $baseDiscountAmount = $helper->round($rule->getDiscountAmount(), $quote->getBaseCurrencyCode()); $discountAmount = $helper->round($store->convertPrice($baseDiscountAmount), $quote->getQuoteCurrencyCode()); // Skip zero discounts if ($discountAmount <= 0.0) { return false; } // Get the discount step size $step = max(floatval($rule->getDiscountStep()), 0.0); $applied = false; foreach ($validItems as $item) { // Get max quantity $qty = $helper->getItemRuleQty($item, $rule); // Apply discount step size limitation if ($step > 0.0) { $qty = floor($qty / $step) * $step; } // Skip zero quantities if ($qty <= 0.0) { continue; } $applied = true; // Calculate discount amounts $discountAmount = $discountAmount * $qty; $baseDiscountAmount = $baseDiscountAmount * $qty; $originalDiscountAmount = $discountAmount * $qty; $baseOriginalDiscountAmount = $baseDiscountAmount * $qty; // Round the discount amounts $discountAmount = $helper->round($discountAmount, $address->getQuote()->getQuoteCurrencyCode()); $baseDiscountAmount = $helper->round($baseDiscountAmount, $address->getQuote()->getBaseCurrencyCode()); $originalDiscountAmount = $helper->round($originalDiscountAmount, $address->getQuote()->getQuoteCurrencyCode()); $baseOriginalDiscountAmount = $helper->round($baseOriginalDiscountAmount, $address->getQuote()->getBaseCurrencyCode()); // Update the item discounts $item->setDiscountAmount($item->getDiscountAmount() + $discountAmount); $item->setBaseDiscountAmount($item->getBaseDiscountAmount() + $baseDiscountAmount); $item->setOriginalDiscountAmount($item->getOriginalDiscountAmount() + $originalDiscountAmount); $item->setBaseOriginalDiscountAmount($item->getBaseOriginalDiscountAmount() + $baseOriginalDiscountAmount); } if ($rule->getApplyToShipping()) { $shippingAmount = $address->getShippingAmountForDiscount(); $baseShippingAmount = $address->getBaseShippingAmountForDiscount(); if ($shippingAmount === null || $baseShippingAmount === null) { $shippingAmount = $address->getShippingAmount(); $baseShippingAmount = $address->getBaseShippingAmount(); } $shippingAmount -= $address->getShippingDiscountAmount(); $baseShippingAmount -= $address->getBaseShippingDiscountAmount(); $shippingDiscountAmount = min(max($discountAmount, 0.0), $shippingAmount); $shippingBaseDiscountAmount = min(max($baseDiscountAmount, 0.0), $baseShippingAmount); $address->setShippingDiscountAmount($address->getShippingDiscountAmount() + $shippingDiscountAmount); $address->setBaseShippingDiscountAmount($address->getBaseShippingDiscountAmount() + $shippingBaseDiscountAmount); $applied = true; } return $applied; }
/** * Get the items the need to be discounted based on the category ids or root category and escape bundle products from calculation * * @author Mohamed Meabed <*****@*****.**> * * @param Mage_SalesRule_Model_Rule $rule * @param Mage_Sales_Model_Quote_Address $address * @param Mage_Sales_Model_Quote_Address_Item $_addressItem * * @return array */ public function getItemsToDiscount($rule, $address, $_addressItem) { $conditions = $rule->getConditions()->getConditions(); $allowedCatIds = null; $parsedCats = array(); $condition = null; $_productCategories = array(); $cartCategories = array(); $catToProcess = array(); $isRootCategory = false; $validCondition = false; $rootCategoryId = Mage::app()->getStore()->getRootCategoryId(); $ignoreType = array('bundle'); /** @var Mage_SalesRule_Model_Rule_Condition_Address $c */ foreach ($conditions as $c) { if (!$allowedCatIds && !$condition && $c->getData('attribute')) { $condition = $c; $val = $c->getValueParsed(); if (is_string($val)) { $parsedCats = explode(',', $val); } if (is_array($val)) { $parsedCats = $val; } if ($parsedCats && is_array($parsedCats)) { if (in_array($rootCategoryId, $parsedCats)) { $isRootCategory = true; $_productCategories = array($rootCategoryId); } } } } $items = $address->getAllVisibleItems(); $discountStep = $rule->getDiscountStep(); $i = 0; /** @var Mage_Sales_Model_Quote_Item $item */ foreach ($items as $item) { // Escape bundles if (in_array($ignoreType, $item->getProductType())) { continue; } if (!$isRootCategory) { /** @var Mage_Catalog_Model_Product $_product */ $_product = Mage::getModel('catalog/product')->load($item->getProductId()); $_productCategories = $_product->getCategoryIds(); } $validCondition = $condition->validateAttribute($_productCategories); $cat = array_shift($_productCategories); if ($isRootCategory || $validCondition) { for ($x = 0; $x < $item->getQty(); $x++) { $cartCategories[$cat][$i]['itemId'] = $item->getId(); $cartCategories[$cat][$i]['qty'] = $item->getQty(); $cartCategories[$cat][$i]['price'] = $item->getPrice(); $cartCategories[$cat][$i]['item'] = $item; $i++; if (count($cartCategories[$cat]) >= $discountStep) { $catToProcess[$cat] = $cat; } } } } $x = $rule->getDiscountStep(); $y = $rule->getDiscountAmount(); $return = array(); foreach ($catToProcess as $cat) { $catItems = $cartCategories[$cat]; $this->aaSort($catItems, 'price'); $qtyTobeDiscounted = (int) ($i / $discountStep); $qtyTobeDiscounted *= $y; for ($j = 0; $j < $qtyTobeDiscounted; $j++) { $itemDisc = array_pop($catItems); /** @var Mage_Sales_Model_Quote_Address_Item $salesItem */ $salesItem = $itemDisc['item']; if ($salesItem && !isset($return[$salesItem->getId()])) { $return[$salesItem->getId()] = 0; } $return[$salesItem->getId()]++; } } return $return; }
/** * @param Mage_Sales_Model_Quote_Address $address * @param Mage_SalesRule_Model_Rule $rule * @param Mage_Sales_Model_Quote_Item_Abstract[] $allItems * @param Mage_Sales_Model_Quote_Item_Abstract[] $validItems * * @return bool */ public function handle(Mage_Sales_Model_Quote_Address $address, Mage_SalesRule_Model_Rule $rule, array $allItems, array $validItems) { // Skip invalid rule actions if ($rule->getSimpleAction() !== Mage_SalesRule_Model_Rule::BY_PERCENT_ACTION) { return false; } // Skip if there are no valid items and it's not applied to shipping if (!count($validItems) && !$rule->getApplyToShipping()) { return false; } // Define a few helpful variables $helper = $this->getHelper(); $quote = $address->getQuote(); $store = $quote->getStore(); // Get discount percent $discountPercent = max(min($rule->getDiscountAmount(), 100.0), 0.0); $discountMultiplier = $discountPercent / 100; // Skip zero discounts if ($discountPercent <= 0.0) { return false; } // Get the discount step size $step = max(floatval($rule->getDiscountStep()), 0.0); $applied = false; foreach ($validItems as $item) { // Get max quantity $qty = $helper->getItemRuleQty($item, $rule); // Apply discount step size limitation if ($step > 0.0) { $qty = floor($qty / $step) * $step; } // Skip zero quantities if ($qty <= 0.0) { continue; } $applied = true; // Get row prices $itemRowPrice = $helper->getItemPrice($item) * $qty; $itemBaseRowPrice = $helper->getItemBasePrice($item) * $qty; $itemOriginalRowPrice = $helper->getItemOriginalPrice($item) * $qty; $itemBaseOriginalRowPrice = $helper->getItemBaseOriginalPrice($item) * $qty; // Calculate discount amounts $discountAmount = ($itemRowPrice - $item->getDiscountAmount()) * $discountMultiplier; $baseDiscountAmount = ($itemBaseRowPrice - $item->getBaseDiscountAmount()) * $discountMultiplier; $originalDiscountAmount = ($itemOriginalRowPrice - $item->getOriginalDiscountAmount()) * $discountMultiplier; $baseOriginalDiscountAmount = ($itemBaseOriginalRowPrice - $item->getBaseOriginalDiscountAmount()) * $discountMultiplier; // Round the discount amounts $discountAmount = $helper->round($discountAmount, $address->getQuote()->getQuoteCurrencyCode()); $baseDiscountAmount = $helper->round($baseDiscountAmount, $address->getQuote()->getBaseCurrencyCode()); $originalDiscountAmount = $helper->round($originalDiscountAmount, $address->getQuote()->getQuoteCurrencyCode()); $baseOriginalDiscountAmount = $helper->round($baseOriginalDiscountAmount, $address->getQuote()->getBaseCurrencyCode()); // Update the item discounts $item->setDiscountAmount($item->getDiscountAmount() + $discountAmount); $item->setBaseDiscountAmount($item->getBaseDiscountAmount() + $baseDiscountAmount); $item->setOriginalDiscountAmount($item->getOriginalDiscountAmount() + $originalDiscountAmount); $item->setBaseOriginalDiscountAmount($item->getBaseOriginalDiscountAmount() + $baseOriginalDiscountAmount); // Update the item percent discount value $discountPercent = min(100, $item->getDiscountPercent() + $discountPercent); $item->setDiscountPercent($discountPercent); } if ($rule->getApplyToShipping()) { $shippingAmount = $address->getShippingAmountForDiscount(); $baseShippingAmount = $address->getBaseShippingAmountForDiscount(); if ($shippingAmount === null || $baseShippingAmount === null) { $shippingAmount = $address->getShippingAmount(); $baseShippingAmount = $address->getBaseShippingAmount(); } // Subtract existing discounts $shippingAmount -= $address->getShippingDiscountAmount(); $baseShippingAmount -= $address->getBaseShippingDiscountAmount(); // Calculate and round discounts $shippingDiscountAmount = $helper->round($shippingAmount * $discountMultiplier, $address->getQuote()->getQuoteCurrencyCode()); $shippingBaseDiscountAmount = $helper->round($baseShippingAmount * $discountMultiplier, $address->getQuote()->getBaseCurrencyCode()); // Make sure the discount isn't more that the remaining amount $shippingDiscountAmount = min(max($shippingDiscountAmount, 0.0), $shippingAmount); $shippingBaseDiscountAmount = min(max($shippingBaseDiscountAmount, 0.0), $baseShippingAmount); // Store discounts $address->setShippingDiscountAmount($address->getShippingDiscountAmount() + $shippingDiscountAmount); $address->setBaseShippingDiscountAmount($address->getBaseShippingDiscountAmount() + $shippingBaseDiscountAmount); $applied = true; } return $applied; }