In Magento, catalog rules apply to catalog and products to cut the product prices and promote sales. This is one special sharp tool for holidays promotion. Catalog price offers four ways to discount the price.
public function calcPriceRule ($actionOperator, $ruleAmount, $price)
{
$priceRule = 0;
switch ($actionOperator) {
case 'to_fixed':
$priceRule = $ruleAmount;
break;
case 'to_percent':
$priceRule= $price * $ruleAmount / 100;
break;
case 'by_fixed':
$priceRule = $price - $ruleAmount;
break;
case 'by_percent':
$priceRule = $price * (1 - $ruleAmount / 100);
break;
}
return $priceRule;
}
In addition, catalog rules use Magento event mechanism to finish the discount work. There are lots of event hooks defined in the config.xml.
<events>
<prepare_catalog_product_price_index_table>
<observers>
<catalogrule>
<class>catalogrule/observer</class>
<method>prepareCatalogProductPriceIndexTable</method>
</catalogrule>
</observers>
</prepare_catalog_product_price_index_table>
<catalog_product_type_configurable_price>
<observers>
<catalogrule>
<class>catalogrule/observer</class>
<method>catalogProductTypeConfigurablePrice</method>
</catalogrule>
</observers>
</catalog_product_type_configurable_price>
</events>
It is obvious that class Mage_CatalogRule_Model_Observer plays an important role in the catalog rule model. I will pick up some methods to explain the logic behind the scene.
public function prepareCatalogProductCollectionPrices(Varien_Event_Observer $observer)
{
/* @var $collection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */
$collection = $observer->getEvent()->getCollection();
$productIds = array();
/* @var $product Mage_Core_Model_Product */
foreach ($collection as $product) {
$key = implode('|', array($date, $websiteId, $groupId, $product->getId()));
if (!isset($this->_rulePrices[$key])) {
$productIds[] = $product->getId();
}
}
if ($productIds) {
$rulePrices = Mage::getResourceModel('catalogrule/rule')
->getRulePrices($date, $websiteId, $groupId, $productIds);
foreach ($productIds as $productId) {
$key = implode('|', array($date, $websiteId, $groupId, $productId));
$this->_rulePrices[$key] = isset($rulePrices[$productId]) ? $rulePrices[$productId] : false;
}
}
return $this;
}
When the production collection show in the front-end, the above code snippets will carry out and ensure the products to get their catalog rule prices.
After you apply the catalog rule in the admin back-end, the product price may be back to normal price after some time. It is a bit strange. However, the answer for this question is cron job. Catalog rule cron job must be enabled to avoid this problem.
<crontab>
<jobs>
<catalogrule_apply_all>
<schedule>
<cron_expr>0 1 * * *</cron_expr>
</schedule>
<run>
<model>catalogrule/observer::dailyCatalogUpdate</model>
</run>
</catalogrule_apply_all>
</jobs>
<events>
<catalog_product_get_final_price>
<observers>
<catalogrule>
<class>catalogrule/observer</class>
<method>processAdminFinalPrice</method>
</catalogrule>
</observers>
</catalog_product_get_final_price>
</events>
</crontab>
You may be still in doubt about the cron job's magic power. The follow code snippets from admin back-end tells us the truth.
public function applyRulesAction()
{
try {
Mage::getModel('catalogrule/rule')->applyAll();
Mage::app()->removeCache('catalog_rules_dirty');
Mage::getSingleton('adminhtml/session')->addSuccess(
Mage::helper('catalogrule')->__('The rules have been applied.')
);
} catch (Exception $e) {
Mage::getSingleton('adminhtml/session')->addError(
Mage::helper('catalogrule')->__('Unable to apply rules.')
);
throw $e;
}
$this->_redirect('*/*');
}
public function dailyCatalogUpdate($observer)
{
Mage::getResourceSingleton('catalogrule/rule')->applyAllRulesForDateRange();
return $this;
}