Mini Tutorial: Creating Shopping Cart Rules Programatically

Shopping cart rules are probably the most common type of promotion used within Magento from applying discounts to specific products automatically or by coupons to running BOGO style promotions. Rules are extremely flexible and allow to specify conditions for triggering the rule and conditions to specify to which products the actions should apply.

There is one downside to the current implementation of the shopping cart rules, they have to be created manually. Magento doesn’t currently have support for mass rule creation or even duplicating an existing rule. This is highly inconvenient since some of our clients often require creating unique coupons some times in the thousands.

Fortunately we can easily create rules programatically using the following code:

public function generateRule($name = null, $coupon_code = null, $discount = 0, $sku)
{
  if ($name != null && $coupon_code != null)
  {
    $rule = Mage::getModel('salesrule/rule');
    $customer_groups = array(0, 1, 2, 3);
    $rule->setName($name)
      ->setDescription($name)
      ->setFromDate('')
      ->setCouponType(2)
      ->setCouponCode($coupon_code)
      ->setUsesPerCustomer(1)
      ->setCustomerGroupIds($customer_groups) //an array of customer grou pids
      ->setIsActive(1)
      ->setConditionsSerialized('')
      ->setActionsSerialized('')
      ->setStopRulesProcessing(0)
      ->setIsAdvanced(1)
      ->setProductIds('')
      ->setSortOrder(0)
      ->setSimpleAction('cart_fixed')
      ->setDiscountAmount($discount)
      ->setDiscountQty(null)
      ->setDiscountStep(0)
      ->setSimpleFreeShipping('0')
      ->setApplyToShipping('0')
      ->setIsRss(0)
      ->setWebsiteIds(array(1));

    $item_found = Mage::getModel('salesrule/rule_condition_product_found')
      ->setType('salesrule/rule_condition_product_found')
      ->setValue(1) // 1 == FOUND
      ->setAggregator('all'); // match ALL conditions
    $rule->getConditions()->addCondition($item_found);
    $conditions = Mage::getModel('salesrule/rule_condition_product')
      ->setType('salesrule/rule_condition_product')
      ->setAttribute('sku')
      ->setOperator('==')
      ->setValue($sku);
    $item_found->addCondition($conditions);

    $actions = Mage::getModel('salesrule/rule_condition_product')
      ->setType('salesrule/rule_condition_product')
      ->setAttribute('sku')
      ->setOperator('==')
      ->setValue($sku);
    $rule->getActions()->addCondition($actions);
    $rule->save();
  }
}

Let’s breakdown the code step by step. Although the function looks simple at first, since we are only instantiating a new *Magento_SalesRule_Model_Rule* object, setting all its properties and saving, there are a few woes and catch parts that are not as simple as they look.

Setting up the General information of the rule

 $rule->setName($name)
    ->setDescription($name)
    ->setFromDate('')
    ->setCouponType(2)
    ->setCouponCode($coupon_code)
    ->setUsesPerCustomer(1)
    ->setCustomerGroupIds($customer_groups) //an array of customer grou pids
    ->setIsActive(1)
    ->setConditionsSerialized('')
    ->setActionsSerialized('')
    ->setStopRulesProcessing(0)
    ->setIsAdvanced(1)
    ->setProductIds('')
    ->setSortOrder(0)
    ->setSimpleAction('cart_fixed')
    ->setDiscountAmount($discount)
    ->setDiscountQty(null)
    ->setDiscountStep(0)
    ->setSimpleFreeShipping('0')
    ->setApplyToShipping('0')
    ->setIsRss(0)
    ->setWebsiteIds(array(1));

At this point we are just setting up the general rule information, there are a few important properties that are being set:

// The value can be 1 or 2
// If the value is set to 1 the rule will apply without the need of a coupon
 ->setCouponType(2)

// There are 4 different actions by_percent, by_fixed, cart_fixed, buy_x_get_y
->setSimpleAction('cart_fixed')

Now for the interesting part we are going to set our rule conditions, I have seen some tutorials before that try to setup the rules conditions and actions as straight serialized values this is not going to work Magento. In order to set the conditions we need to:

The following code will read as: IF a product is FOUND with ALL these conditions

$item_found = Mage::getModel('salesrule/rule_condition_product_found')
   ->setType('salesrule/rule_condition_product_found')
   ->setValue(1) // 1 == FOUND
    ->setAggregator('all'); // match ALL conditions
 $rule->getConditions()->addCondition($item_found);

Now we set the conditions for our statement: WHERE sku is EQUAL to $sku

 $conditions = Mage::getModel('salesrule/rule_condition_product')
   ->setType('salesrule/rule_condition_product')
   ->setAttribute('sku')
   ->setOperator('==')
   ->setValue($sku);
 $item_found->addCondition($conditions);

And finally we specify which products should get the discount.

 $actions = Mage::getModel('salesrule/rule_condition_product')
    ->setType('salesrule/rule_condition_product')
    ->setAttribute('sku')
    ->setOperator('==')
    ->setValue($sku);
 $rule->getActions()->addCondition($actions);