Hey Magento Open Course fans,

As you all know, Magento uses a special filter called rule conditions to choose products or orders for promotions. In this lesson, we will examine types of rule conditions and how to create a module to use these rule conditions. Good luck with our Magento Tutorial.

Lesson 28 lasts for 3 hours with four sections:

  • Catalog price rules and shopping cart price rules
  • How to create database and model for custom rule conditions
  • Rule conditions edit form
  • How to validate rule conditions

However, we will divide this lesson into two parts. The first part will look at two sections:

  • Catalog price rules and shopping cart price rules
  • How to create database and model for custom rule conditions

1. Catalog price rules and shopping cart price rules

Magento supports two types of promotions, we can see them in Backend of Magento:

rule-condition-1

Catalog price rules: are applied to products before they are added to the shopping cart. They can be used to create sales and discounts that do not require customers to enter a discount code.

Shopping cart price rules: are applied when a customer reaches the shopping cart page. In addition, a coupon code can be associated with a shopping cart price rule to apply a discount when a set of conditions is met.

There are two conditions types corresponding to these conditions rules. Catalog Rule condition is used to create filter for products in Magento, Shopping Cart Rule condition is used to create filter for orders.

A Catalog Rule Conditions is as follows:

catalog-rule-condition

A Shopping Cart Rule conditions involves conditions when customers check out:

shopping-cart-rule

In addition, in Actions tab of Shopping Cart Rule there are conditions to identify items customers added to cart.

shopping-cart-rule-1

2. How to create database and model for custom rule conditions

In this lesson, I will instruct you how to create a module for Shopping Cart Rule Conditions. You should use module creator to create a module.

For example: I create module “Lesson28” and customize data for this module in file

appcodelocalMagestoreLesson28sqllesson28_setupmysql4-install-0.1.0.php:

CREATE TABLE {$this->getTable('lesson28')} (

`lesson28_id` int(11) unsigned NOT NULL auto_increment,
`name` VARCHAR(255) NULL,
`description` TEXT NULL,
`is_active` SMALLINT(6) NULL,
`website_ids` TEXT NULL,
`customer_group_ids` TEXT NULL,
`from_date` DATETIME NULL,
`to_date` DATETIME NULL,
`sort_order` INT(11) NULL,
`conditions_serialized` MEDIUMTEXT NULL,
`actions_serialized` MEDIUMTEXT NULL,
`custom_discount` DECIMAL(12,4) NULL,
PRIMARY KEY (`lesson28_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

To have data of conditions saved in this table, we need to pay attention to special fields of this table:

conditions_serialized: This field will save data of shopping cart conditions in serialized form.

actions_serialized: This field will save data of shopping cart item conditions in string serialized form.

Then, we need to customize in model in comparison with other models in lessons you wrote:

Model extends from Mage_Rule_Model_Rule class

Model writes methods: getConditionsInstance, getActionsInstance, loadPost…

Here is our model:

class Magestore_Lesson28_Model_Lesson28 extends Mage_Rule_Model_Rule

{
public function _construct()
{
parent::_construct();
$this->_init('lesson28/lesson28');
$this->setIdFieldName('lesson28_id');
}

public function getConditionsInstance()
{
return Mage::getModel('salesrule/rule_condition_combine');
}

public function getActionsInstance()
{
return Mage::getModel('salesrule/rule_condition_product_combine');
}

/**
* load Rule posted from web
*
* @param array $rule
* @return Magestore_RewardPointsRule_Model_Earning_Sales
*/
public function loadPost(array $rule)
{
$arr = $this->_convertFlatToRecursive($rule);
if (isset($arr['conditions'])) {
$this->getConditions()->setConditions(array())->loadArray($arr['conditions'][1]);
}
if (isset($arr['actions'])) {
$this->getActions()->setActions(array())->loadArray($arr['actions'][1], 'actions');
}
return $this;
}

protected function _beforeSave()
{
parent::_beforeSave();
if ($this->hasWebsiteIds()) {
$websiteIds = $this->getWebsiteIds();
if (is_array($websiteIds) && !empty($websiteIds)) {
$this->setWebsiteIds(implode(',', $websiteIds));
}
}
if ($this->hasCustomerGroupIds()) {
$groupIds = $this->getCustomerGroupIds();
if (is_array($groupIds) && !empty($groupIds)) {
$this->setCustomerGroupIds(implode(',', $groupIds));
}
}
return $this;
}
}

Method loadPost is used to add data to model and prepare for saving in database.

Bonus: Download a free guide that will show you 21-point Magento 2 Pre launch checklist.

3. Rule conditions edit form

After having model, we need to create admin pages in backend. You can look back to lessons from 7 to 10 for detail about Magento components in backend. Now, I will focus on special factors to work with rule conditions.

First, make conditions shown in edit form like shopping cart conditions in Magento.

Step 1: Use conditions template for tab conditions. I write it in _prepareForm method of file

app\code\local\Magestore\Lesson28\Block\Adminhtml\Lesson28\Edit\Tab\Conditions.php

$form = new Varien_Data_Form();

$form->setHtmlIdPrefix('rule_');

$renderer = Mage::getBlockSingleton('adminhtml/widget_form_renderer_fieldset')
->setTemplate('promo/fieldset.phtml')
->setNewChildUrl($this->getUrl('adminhtml/promo_quote/newConditionHtml/form/rule_conditions_fieldset'));

$fieldset = $form->addFieldset('conditions_fieldset', array('legend'=>Mage::helper('lesson28')->__('Apply the rule only if the following conditions are met (leave blank for all order)')))->setRenderer($renderer);

$fieldset->addField('conditions','text',array(
'name' => 'conditions',
'label' => Mage::helper('lesson28')->__('Conditions'),
'title' => Mage::helper('lesson28')->__('Conditions'),
'required' => true,
))->setRule($model)->setRenderer(Mage::getBlockSingleton('rule/conditions'));

Step 2: Add load JS to edit form from controllers

app\code\local\Magestore\Lesson28\controllers\Adminhtml\Lesson28Controller.php

We have the following method:

public function editAction()

{
$lesson28Id = $this->getRequest()->getParam('id');
$model = Mage::getModel('lesson28/lesson28')->load($lesson28Id);

if ($model->getId() || $lesson28Id == 0) {
$data = Mage::getSingleton('adminhtml/session')->getFormData(true);
if (!empty($data)) {
$model->setData($data);
}

$model->getConditions()->setJsFormObject('rule_conditions_fieldset');
$model->getActions()->setJsFormObject('rule_actions_fieldset');

Mage::register('lesson28_data', $model);

$this->loadLayout();
$this->_setActiveMenu('lesson28/lesson28');

$this->getLayout()->getBlock('head')
->setCanLoadExtJs(true)
->setCanLoadRulesJs(true);
$this->_addContent($this->getLayout()->createBlock('lesson28/adminhtml_lesson28_edit'))
->_addLeft($this->getLayout()->createBlock('lesson28/adminhtml_lesson28_edit_tabs'));

$this->renderLayout();
} else {
Mage::getSingleton('adminhtml/session')->addError(
Mage::helper('lesson28')->__('Item does not exist')
);
$this->_redirect('*/*/');
}
}

We need to notice function row:

$model->getConditions()->setJsFormObject('rule_conditions_fieldset');

$model->getActions()->setJsFormObject('rule_actions_fieldset');

And

$this->getLayout()->getBlock('head')

->setCanLoadExtJs(true)
->setCanLoadRulesJs(true);

Next, we add shopping cart items conditions to form by customizing in file

app\code\local\Magestore\Lesson28\Block\Adminhtml\Lesson28\Edit\Tab\Actions.php in method _prepareForm like conditions tab.

$form = new Varien_Data_Form();

$form->setHtmlIdPrefix('rule_');
$this->setForm($form);
$fieldset = $form->addFieldset('discount_action_fieldset', array('legend' => Mage::helper('lesson28')->__('Action')));

$fieldset->addField('custom_discount', 'text', array(
'label' => Mage::helper('lesson28')->__('Custom Discount'),
'title' => Mage::helper('lesson28')->__('Custom Discount'),
'name' => 'custom_discount',
'after_element_html' => '<strong>[' . Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE) . ']</strong>',
));

$renderer = Mage::getBlockSingleton('adminhtml/widget_form_renderer_fieldset')
->setTemplate('promo/fieldset.phtml')
->setNewChildUrl($this->getUrl('adminhtml/promo_quote/newActionHtml/form/rule_actions_fieldset'));

$fieldset = $form->addFieldset('actions_fieldset', array('legend' => Mage::helper('lesson28')->__('Apply the rule only to cart items matching the following conditions (leave blank for all items)')))->setRenderer($renderer);

$fieldset->addField('actions', 'text', array(
'label' => Mage::helper('lesson28')->__('Apply To'),
'title' => Mage::helper('lesson28')->__('Apply To'),
'name' => 'actions',
))->setRule($model)->setRenderer(Mage::getBlockSingleton('rule/actions'));

You can see previous lesson to know how to move content of these files to Magento tabs. Then, the result is an edit form for custom condition rule:

demo-rule

Finally, we need to write a code block to save action:

$model->loadPost($data)

->setData('from_date',$data['from_date'])
->setData('to_date',$data['to_date'])
->save();

We use function loadPost instead of setData to save data of conditions and actions.

4. How to validate rule conditions

After having information of rule saved in database, we use it to check actions for shopping cart.

For example: To discount items that meets requirements in shopping cart, I create a custom total (like lesson 23) but discount value is taken from table of this module.

Collect total function of model (Magestore_Lesson28_Model_Total_Quote_Discount)

public function collect(Mage_Sales_Model_Quote_Address $address)

{
$quote = $address->getQuote();
if (!$quote->isVirtual() && $address->getAddressType() == 'billing') {
return $this;
}

// Get Rules Discount
$rules = Mage::getResourceModel('lesson28/lesson28_collection')
->setAvailableFilter($quote->getCustomerGroupId(), Mage::app()->getWebsite()->getId());
foreach ($rules as $rule) {
if ($rule->validate($address)) {
$itemBaseDiscount = $rule->getCustomDiscount();
break;
}
}

$itemDiscount = Mage::app()->getStore()->convertPrice($itemBaseDiscount);
$totalDiscount = 0;
$baseTotalDiscount = 0;
foreach ($address->getAllItems() as $item) {
if ($item->getParentItemId()) continue;
if (!$rule->getActions()->validate($item)) {
continue;
}
if ($item->getHasChildren() && $item->isChildrenCalculated()) {
foreach ($item->getChildren() as $child) {
$totalDiscount += $itemDiscount;
$baseTotalDiscount += $itemBaseDiscount;

$child->setBaseCustomDiscount($itemBaseDiscount);
$child->setCustomDiscount($itemDiscount);
}
} else {
$totalDiscount += $itemDiscount;
$baseTotalDiscount += $itemBaseDiscount;

$item->setBaseCustomDiscount($itemBaseDiscount);
$item->setCustomDiscount($itemDiscount);
}
}

if ($totalDiscount > 0) {
$address->setCustomDiscount($totalDiscount);
$address->setBaseCustomDiscount($baseTotalDiscount);

$address->setGrandTotal($address->getGrandTotal() - $totalDiscount)
->setBaseGrandTotal($address->getBaseGrandTotal() - $baseTotalDiscount);
}

return $this;
}

Notice this function row:

$rule->validate($address)

This function row is used to check whether present shopping cart meet conditions of rule we created or not. This condition is taken from field conditions_serialized in database.

$rule->getActions()->validate($item)

This function row is used to check conditions for shopping cart items.The corresponding condition is taken from field actions_serialized in database.

You can access to frontend to check and create orders.

SUMMARY

In this lesson, we need to have background of rule conditions used in Magento and know how to use them in custom modules. You are recommended to see lesson 23 (Collect, Place and View Quote/Order) and 24 (Invoice and Refund) about Checkout Totals to update more for your custom modules.

Follow us in Magento Open Course for more Magento tutorials. Thank you.

Author

Why Magestore? We believe in building a meaningful & long-term relationship with you.

1 Comment

  1. Hello Jasmine Nguyen

    Great tutorial in this blog and i learn lot of things but if it is very generous if you could add option for tutorial download

Write A Comment