Question

First question on stackoverflow...i am excited :)

Currently magento is using the special price if its lower than the applied catalog price rule. If the catalog price rule makes the product cheaper than the special price, then the catalog price rule defines the shop price.

I am looking for an elegant way to make catalog price rules be applied to the special price (additionally). Maybe there is some store config for it? Maybe there is some neat observer way?

Thank you so much!

Was it helpful?

Solution

Works up to current Magento 1.9.3.10. Just tested it in a project after update. Josef tried another approach which might work as well.


I am sad to say, I solved my first real stackoverflow question for my own:

  1. Goto Mage_CatalogRule_Model_Resource_Rule
  2. Goto method _getRuleProductsStmt
  3. Add this to the initial select of the method before the first original ->from:

    $select->from(null, array('default_price' => new Zend_Db_Expr("CASE WHEN pp_default_special.value THEN pp_default_special.value ELSE pp_default_normal.value END")));

  4. Add this after the first join() has happened

    $specialPriceAttr  = Mage::getSingleton('eav/config')
                        ->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'special_price');
    $specialPriceTable = $specialPriceAttr->getBackend()->getTable();
    $specialPriceAttributeId= $specialPriceAttr->getId();
    $joinCondition2 = '%1$s.entity_id=rp.product_id AND (%1$s.attribute_id=' . $specialPriceAttributeId . ') 
                                                    AND %1$s.store_id=%2$s';
    $select->join(
            array('pp_default_special'=>$specialPriceTable),
            sprintf($joinCondition2, 'pp_default_special', Mage_Core_Model_App::ADMIN_STORE_ID), null
    );
    

How it works:

When a catalog price rule is applied (via backend or cron) the db table catalogrule_product_price is populated. The above SQL magic joins the special_price (if exists) to the resultset as column default_value, if no special_price is found the regular price gets joined.

The result has been checked and is working.

Have fun! And dont hack the core!

OTHER TIPS

There seem to be some changes in newer Magento releases! For 1.9 i had to:

copy app/code/core/Mage/CatalogRule/Model/Action/Index/Refresh.php to app/code/local/Mage/CatalogRule/Model/Action/Index/Refresh.php Change _prepareTemporarySelect.

I post the function in full here. Joins for special_price are added and then the price added to the selection of the price field. It still prefers group prices, becuas I never use them, but that can be changed easily!

protected
function _prepareTemporarySelect(Mage_Core_Model_Website $website)
    {
    /** @var $catalogFlatHelper Mage_Catalog_Helper_Product_Flat */
    $catalogFlatHelper = $this->_factory->getHelper('catalog/product_flat');
    /** @var $eavConfig Mage_Eav_Model_Config */
    $eavConfig = $this->_factory->getSingleton('eav/config');
    $priceAttribute = $eavConfig->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'price');
    $specialPriceAttr = Mage::getSingleton('eav/config')->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'special_price');
    $specialPriceTable = $specialPriceAttr->getBackend()->getTable();
    $specialPriceAttributeId = $specialPriceAttr->getId();
    $select = $this->_connection->select()->from(array(
        'rp' => $this->_resource->getTable('catalogrule/rule_product')
    ) , array())->joinInner(array(
        'r' => $this->_resource->getTable('catalogrule/rule')
    ) , 'r.rule_id = rp.rule_id', array())->where('rp.website_id = ?', $website->getId())->order(array(
        'rp.product_id',
        'rp.customer_group_id',
        'rp.sort_order',
        'rp.rule_product_id'
    ))->joinLeft(array(
        'pg' => $this->_resource->getTable('catalog/product_attribute_group_price')
    ) , 'pg.entity_id = rp.product_id AND pg.customer_group_id = rp.customer_group_id' . ' AND pg.website_id = rp.website_id', array())->joinLeft(array(
        'pgd' => $this->_resource->getTable('catalog/product_attribute_group_price')
    ) , 'pgd.entity_id = rp.product_id AND pgd.customer_group_id = rp.customer_group_id' . ' AND pgd.website_id = 0', array());
    $storeId = $website->getDefaultStore()->getId();
    if ($catalogFlatHelper->isEnabled() && $storeId && $catalogFlatHelper->isBuilt($storeId))
        {
        $select->joinInner(array(
            'p' => $this->_resource->getTable('catalog/product_flat') . '_' . $storeId
        ) , 'p.entity_id = rp.product_id', array());
        $priceColumn = $this->_connection->getIfNullSql($this->_connection->getIfNullSql('pg.value', 'pgd.value') , $this->_connection->getIfNullSql('p.special_price', 'p.price'));
        }
      else
        {
        $select->joinInner(array(
            'pd' => $this->_resource->getTable(array(
                'catalog/product',
                $priceAttribute->getBackendType()
            ))
        ) , 'pd.entity_id = rp.product_id AND pd.store_id = 0 AND pd.attribute_id = ' . $priceAttribute->getId() , array())->joinLeft(array(
            'pspd' => $specialPriceTable
        ) , 'pspd.entity_id = rp.product_id AND (pspd.attribute_id=' . $specialPriceAttributeId . ')' . 'AND pspd.store_id = 0', array())->joinLeft(array(
            'p' => $this->_resource->getTable(array(
                'catalog/product',
                $priceAttribute->getBackendType()
            ))
        ) , 'p.entity_id = rp.product_id AND p.store_id = ' . $storeId . ' AND p.attribute_id = pd.attribute_id', array())->joinLeft(array(
            'psp' => $specialPriceTable
        ) , 'psp.entity_id = rp.product_id AND (psp.attribute_id=' . $specialPriceAttributeId . ')' . 'AND psp.store_id = ' . $storeId, array());
        $priceColumn = $this->_connection->getIfNullSql($this->_connection->getIfNullSql('pg.value', 'pgd.value') , $this->_connection->getIfNullSql('psp.value', $this->_connection->getIfNullSql('pspd.value', $this->_connection->getIfNullSql('p.value', 'pd.value'))));
        }

    $select->columns(array(
        'grouped_id' => $this->_connection->getConcatSql(array(
            'rp.product_id',
            'rp.customer_group_id'
        ) , '-') ,
        'product_id' => 'rp.product_id',
        'customer_group_id' => 'rp.customer_group_id',
        'from_date' => 'r.from_date',
        'to_date' => 'r.to_date',
        'action_amount' => 'rp.action_amount',
        'action_operator' => 'rp.action_operator',
        'action_stop' => 'rp.action_stop',
        'sort_order' => 'rp.sort_order',
        'price' => $priceColumn,
        'rule_product_id' => 'rp.rule_product_id',
        'from_time' => 'rp.from_time',
        'to_time' => 'rp.to_time'
    ));
    return $select;
    }

I fixed it in another way. It was just easy to put into the price field for example 100 and then into special price field 90 when there was 10% discount on product page but now I removed special price from product page and just created catalog price rule 10% discount to that product(s) and now other rules also work:)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top