Wednesday, January 17th, 2018
One of the most common requests we receive on e-commerce projects where Magento 1.9 is being used as a store is to add a percentage discount that works on the entire cart WITH a cap on the overall discount amount. This article will explain how to add this to your Magento installation. The same technique could be used to create any discount type with a cap.
On your Magento database, run the following SQL. This will create the field for maximum discount amount.
ALTER TABLE SalesRule ADD COLUMN discount_max DECIMAL(12,4);
This will allow the system to distinguish your per-cart-percentage rule from other types. Add:
const CART_PERCENT_ACTION = 'cart_percent';
after:
const CART_FIXED_ACTION = 'cart_fixed';
This is the code that actually processes this rule type for each item.
case Mage_SalesRule_Model_Rule::CART_PERCENT_ACTION:
if (empty($this->_rulesItemTotals[$rule->getId()])) {
Mage::throwException(Mage::helper('salesrule')->__('Item totals are not set for rule.'));
}
//Get the running cart total discount
$cartDiscountAmount = $this->_rulesItemTotals[$rule->getId()]['cart_total_discount'];
//percentage multiplier for maths
$_rulePct = $rulePercent/100;
// prevent applying whole cart discount for every shipping order, but only for first order
if ($quote->getIsMultiShipping()) {
$usedForAddressId = $this->getCartFixedRuleUsedForAddress($rule->getId());
if ($usedForAddressId && $usedForAddressId != $address->getId()) {
break;
} else {
$this->setCartFixedRuleUsedForAddress($rule->getId(), $address->getId());
}
}
$cartRules = $address->getCartFixedRules();
if (!isset($cartRules[$rule->getId()])) {
$cartRules[$rule->getId()] = $rule->getDiscountAmount();
}
//Have we exceeded the per-cart limit?
if ($cartDiscountAmount < $rule->getDiscountMax()) {
//If not, what's our maximum remaining
$maxAllowed = $rule->getDiscountMax()-$cartDiscountAmount;
//This item's discount is the smaller of the two
$discountAmount = $quote->getStore()->convertPrice(min($maxAllowed, (($baseItemPrice * $qty)*$_rulePct)));
$quoteAmount = $quote->getStore()->convertPrice($discountAmount);
$this->_rulesItemTotals[$rule->getId()]['cart_total_discount']+=$discountAmount;
$cartRules[$rule->getId()] = $discountAmount;
}
$address->setCartFixedRules($cartRules);
break;
We need to make sure that running totals are created for this new rule type, so change:
if (Mage_SalesRule_Model_Rule::CART_FIXED_ACTION == $rule->getSimpleAction()
to:
if ((Mage_SalesRule_Model_Rule::CART_FIXED_ACTION == $rule->getSimpleAction()||Mage_SalesRule_Model_Rule::CART_PERCENT_ACTION == $rule->getSimpleAction())
We’ll need to initialize our running total when the rule begins processing, so after:
$validItemsCount = 0;
add:
$cartDiscountTotalForThisRule = 0;
and after:
'items_price' => $ruleTotalItemsPrice,
add
'cart_total_discount' => $cartDiscountTotalForThisRule,
Next, we move on to updates for the management interface.(You did want to be able to edit this, right?)
First, we’ll need to add an option to the Discount Type dropdown on the SalesRule editor, so add:
Mage_SalesRule_Model_Rule::CART_PERCENT_ACTION => Mage::helper('salesrule')->__('Fixed percentage discount for whole cart'),
after:
Mage_SalesRule_Model_Rule::CART_FIXED_ACTION => Mage::helper('salesrule')->__('Fixed amount discount for whole cart'),
If you are working in code instead of /include, this is already done. If not, add:
const CART_PERCENT_ACTION = 'cart_percent';
after:
const CART_FIXED_ACTION = 'cart_fixed';
This will need to be added to prepareForm(), which is pretty straightforward. Add this:
$fieldset->addField('discount_max', 'text', array(
'name' => 'discount_max',
'label' => Mage::helper('salesrule')->__('Maximum Cart-wide Discount Amount'),
));
$model->setDiscountMax($model->getDiscountMax()*1);
after:
$model->setDiscountQty($model->getDiscountQty()*1);
And with that, you are done. Flush your cache, add your new SalesRule in the management interface, and enjoy!