Exemplo n.º 1
0
 /**
  * @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;
 }
Exemplo n.º 2
0
 /**
  * @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;
 }
Exemplo n.º 3
0
 /**
  * @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;
 }
Exemplo n.º 4
0
 /**
  * Fire an event to process this 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
  */
 protected function fireRuleEvent(Mage_Sales_Model_Quote_Address $address, Mage_SalesRule_Model_Rule $rule, array $allItems, array $validItems)
 {
     $result = new Varien_Object(['applied' => false]);
     Mage::dispatchEvent('sales_quote_address_discount_apply_rule_' . str_replace(' ', '', strtolower(trim($rule->getSimpleAction()))), ['address' => $address, 'rule' => $rule, 'all_items' => $allItems, 'valid_items' => $validItems, 'result' => $result]);
     return (bool) $result->getData('applied');
 }
Exemplo n.º 5
0
 /**
  * @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;
 }