public function getDiscountAmount() { if (substr($this->getCouponCode(), 0, 6) == 'points') { $step = Mage::getStoreConfig('rewardpoints/default/points_money', Mage::app()->getStore()->getId()); return $this->getPointsAmt() / $step; } $test = new Mage_SalesRule_Model_Rule(); if (method_exists($test, 'getDiscountAmount')) { return parent::getDiscountAmount(); } if ($this->discount_amount) { return $this->discount_amount; } }
/** * @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; }
/** * Make sure that a gift is only added once, create a free item and add it to the cart. * * @param Mage_Sales_Model_Quote $quote * @param Mage_Sales_Model_Quote_Item $item * @param Mage_SalesRule_Model_Rule $rule */ protected static function _handleGift(Mage_Sales_Model_Quote $quote, Mage_Sales_Model_Quote_Item $item, Mage_SalesRule_Model_Rule $rule) { if ($rule->getIsApplied()) { return; } $qty = (int) $rule->getDiscountAmount(); if ($qty) { $freeItem = self::_getFreeQuoteItem($quote, $rule->getGiftSku(), $item->getStoreId(), $qty); self::_addAndApply($quote, $freeItem, $rule); } }
/** * @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::CART_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(); // Total available discount amounts $baseDiscountAmount = $helper->round($rule->getDiscountAmount(), $quote->getBaseCurrencyCode()); $discountAmount = $helper->round($store->convertPrice($baseDiscountAmount), $quote->getQuoteCurrencyCode()); // Skip zero discounts if ($discountAmount <= 0.0) { return false; } $applied = false; // Pre-calculate the totals for all valid items $ruleTotalItemsPrice = 0; $ruleTotalBaseItemsPrice = 0; $itemPrices = []; foreach ($validItems as $item) { // Get max quantity (min or rule max qty or item qty) $qty = $helper->getItemRuleQty($item, $rule); // Skip zero quantity if ($qty <= 0.0) { continue; } // Get unit price $itemPrice = $helper->getItemPrice($item); $itemBasePrice = $helper->getItemBasePrice($item); // Get row price $itemRowPrice = $itemPrice * $item->getTotalQty(); $itemBaseRowPrice = $itemBasePrice * $item->getTotalQty(); // Get discountable price $itemDiscountablePrice = $itemPrice * $qty; $itemBaseDiscountablePrice = $itemBasePrice * $qty; // Save price data for later $itemPrices[$item->getId()] = [$itemPrice, $itemBasePrice, $itemRowPrice, $itemBaseRowPrice, $itemDiscountablePrice, $itemBaseDiscountablePrice]; // Add row prices to running totals $ruleTotalItemsPrice += $itemDiscountablePrice; $ruleTotalBaseItemsPrice += $itemBaseDiscountablePrice; } $startDiscountAmount = $discountAmount; $startBaseDiscountAmount = $baseDiscountAmount; foreach ($validItems as $item) { // Skip the skipped items if (!isset($itemPrices[$item->getId()])) { continue; } // Flag indicating the rule was applied $applied = true; // Extract the pre-calculate price data list($itemPrice, $itemBasePrice, $itemRowPrice, $itemBaseRowPrice, $itemDiscountablePrice, $itemBaseDiscountablePrice) = $itemPrices[$item->getId()]; // Calculate remaining row amount $itemRemainingRowPrice = max($itemRowPrice - $item->getDiscountAmount(), 0); $itemRemainingBaseRowPrice = max($itemBaseRowPrice - $item->getBaseDiscountAmount(), 0); // Calculate price factor $priceFactor = $itemDiscountablePrice / $ruleTotalItemsPrice; $basePriceFactor = $itemBaseDiscountablePrice / $ruleTotalBaseItemsPrice; // Calculate (and round) the item discount amount $itemDiscountAmount = $helper->round($startDiscountAmount * $priceFactor, $quote->getQuoteCurrencyCode()); $itemBaseDiscountAmount = $helper->round($startBaseDiscountAmount * $basePriceFactor, $quote->getBaseCurrencyCode()); // Ensure discount does not exceed the remaining discount, max item discount, or remaining row price $itemDiscountAmount = max(min($itemDiscountAmount, $discountAmount, $itemDiscountablePrice, $itemRemainingRowPrice), 0.0); $itemBaseDiscountAmount = max(min($itemBaseDiscountAmount, $baseDiscountAmount, $itemBaseDiscountablePrice, $itemRemainingBaseRowPrice), 0.0); // Update the item discount $item->setDiscountAmount($item->getDiscountAmount() + $itemDiscountAmount); $item->setBaseDiscountAmount($item->getBaseDiscountAmount() + $itemBaseDiscountAmount); // This is a bit wonky, but needed for taxes $item->setOriginalDiscountAmount($item->getOriginalDiscountAmount() + $itemDiscountAmount); $item->setBaseOriginalDiscountAmount($item->getBaseOriginalDiscountAmount() + $itemBaseDiscountAmount); // Subtract from the total remaining discount amount $discountAmount -= $itemDiscountAmount; $baseDiscountAmount -= $itemBaseDiscountAmount; } 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 = max(min($discountAmount, $shippingAmount), 0.0); $shippingBaseDiscountAmount = max(min($baseDiscountAmount, $baseShippingAmount), 0.0); $address->setShippingDiscountAmount($address->getShippingDiscountAmount() + $shippingDiscountAmount); $address->setBaseShippingDiscountAmount($address->getBaseShippingDiscountAmount() + $shippingBaseDiscountAmount); // Subtract from the total discount amount $discountAmount -= $shippingDiscountAmount; $baseDiscountAmount -= $shippingBaseDiscountAmount; $applied = true; } // Do something with possible remaining discount amount if ($applied && $discountAmount > 0.0) { foreach ($validItems as $item) { // Skip the skipped items if (!isset($itemPrices[$item->getId()])) { continue; } // Extract the pre-calculate price data list($itemPrice, $itemBasePrice, $itemRowPrice, $itemBaseRowPrice, $itemDiscountablePrice, $itemBaseDiscountablePrice) = $itemPrices[$item->getId()]; // Calculate remaining row amount $itemRemainingRowPrice = max($itemRowPrice - $item->getDiscountAmount(), 0); $itemRemainingBaseRowPrice = max($itemBaseRowPrice - $item->getBaseDiscountAmount(), 0); // Apply the discount if ($itemRemainingRowPrice >= $discountAmount && $itemRemainingBaseRowPrice >= $baseDiscountAmount) { // Update the item discount $item->setDiscountAmount($item->getDiscountAmount() + $discountAmount); $item->setBaseDiscountAmount($item->getBaseDiscountAmount() + $baseDiscountAmount); // This is a bit wonky, but needed for taxes $item->setOriginalDiscountAmount($item->getOriginalDiscountAmount() + $discountAmount); $item->setBaseOriginalDiscountAmount($item->getBaseOriginalDiscountAmount() + $baseDiscountAmount); // Zero out remaining discount $discountAmount = 0.0; $baseDiscountAmount = 0.0; } // If we've used the discount, exit the loop early if ($discountAmount <= 0.0) { break; } } } 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; }