Introduction

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.

1. Add a column for discount_max to salesrule:

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);

2. Add a new simple_action to Mage_SalesRule_Model_Rule_Model_Abstract (/app/code/core/Mage/SalesRule/Model/Rule.php)

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';

3. Add a case to the switch in Mage_Sales_Model_Quote_Item_Abstract->process() (/app/code/core/Mage/SalesRule/Model/Validator.php)

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;

4. Update Mage_Sales_Model_Quote_Address->initTotals for the new simple_action (/app/code/core/Mage/SalesRule/Model/Validator.php)

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?)

1. In Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_Actions (/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Actions.php)

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'),

2. Add new simple_action to Mage_SalesRule_Model_Rule (already done if working in /code instead of /include)

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';

3. Add Discount_Max to Management interface tab in Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_Actions (/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Actions.php)

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!

Introduction

While building the front page for this site, I found myself stuck on the title graphic.

I had the following requirements:

Initially, I looked at trianglify – but I was already using that for the site backdrop.  After some further searching, I settled on geopattern. There is a demo page here.

Usage

Usage is simple – just include the script and either use the GeoPattern global, or the jQuery plugin.


// Use the global...
var pattern = GeoPattern.generate('GitHub');
$('#geopattern').css('background-image', pattern.toDataUrl());

// ...or the plugin
$('#geopattern').geopattern('GitHub');

There are options for the pattern seed, color, basecolor, and pattern generator:


//Generate yellow octagons
GeoPattern.generate("seed string",{color: '#997700',baseColor:'#997722', generator: "ocatagons"});
//Generate green chevrons
GeoPattern.generate("seed string2",{color: '#22FF44',baseColor:'#000000', generator: "chevrons"});

Applying the resulting image to an object in your DOM is simple with jQuery:


 $('#objectid').css('background-image', pattern.toDataUrl());

Gotchas

This was one of the simplest pieces I’ve worked with yet – it’s really just plug and play. As long as you don’t MUNG the script somehow, you’re good. I didn’t bother with using npm or bower to include it – I just dropped it in my page and started working.

Example

This canvas is patterned with a random seed. Refresh to see a new pattern.