Magento Configurable Product Price Overriding Simple Product Price
When you create a configurable product it doesn't matter what's the price of simple products -- these prices are ignored completely. So if you want to sell a simple product A which has price $29.99 and a simple product B ($39.99) then you must create a configurable product, set its price to $29.99 and open Associated product tab. Add products you want to associate with this configurable product. After adding them a block named Super product attributes configuration appears which contains options and price differences. Leave product A price empty and put 10 (+$10) to product B price field and voila: different simple product have different price.
There's actually an extension that allows you to use simple product prices instead of price differences, but it's kind of tricky to set up. Since it's free extension, I hope nobody complains about me pasting its link here:
https://github.com/organicinternet/magento-configurable-simple
So, I use the code below in combination with an extension like organic internet simple configurable products.
The code below is meant for the cart/checkout process, essentially, it's an update to the configurable price model that passes price calculation to a simple product in the event the product has been added to the cart --- this solution DOES NOT display pricing on the product page itself (however there are many extensions that do that already).
Update app/code/core/Mage/Catalog/Model/Product/Type/Configurable/Price.php (ideally you use an extension or local override in app/code/local)
Update the method: getFinalPrice, change to
public function getFinalPrice($qty=null, $product)
{
//Start edit
$selectedAttributes = array();
if ($product->getCustomOption('attributes')) {
$selectedAttributes = unserialize($product->getCustomOption('attributes')->getValue());
}
//End edit
if (sizeof($selectedAttributes)) return $this->getSimpleProductPrice($qty, $product);
if (is_null($qty) && !is_null($product->getCalculatedFinalPrice())) {
return $product->getCalculatedFinalPrice();
}
$basePrice = $this->getBasePrice($product, $qty);
$finalPrice = $basePrice;
$product->setFinalPrice($finalPrice);
Mage::dispatchEvent('catalog_product_get_final_price', array('product' => $product, 'qty' => $qty));
$finalPrice = $product->getData('final_price');
$finalPrice += $this->getTotalConfigurableItemsPrice($product, $finalPrice);
$finalPrice += $this->_applyOptionsPrice($product, $qty, $basePrice) - $basePrice;
$finalPrice = max(0, $finalPrice);
$product->setFinalPrice($finalPrice);
return $finalPrice;
}
Then add this function right below getFinalPrice:
public function getSimpleProductPrice($qty=null, $product)
{
$cfgId = $product->getId();
$product->getTypeInstance(true)
->setStoreFilter($product->getStore(), $product);
$attributes = $product->getTypeInstance(true)
->getConfigurableAttributes($product);
$selectedAttributes = array();
if ($product->getCustomOption('attributes')) {
$selectedAttributes = unserialize($product->getCustomOption('attributes')->getValue());
}
$db = Mage::getSingleton('core/resource')->getConnection('core_read');
$dbMeta = Mage::getSingleton('core/resource');
$sql = <<<SQL
SELECT main_table.entity_id FROM {$dbMeta->getTableName('catalog/product')} `main_table` INNER JOIN
{$dbMeta->getTableName('catalog/product_super_link')} `sl` ON sl.parent_id = {$cfgId}
SQL;
foreach($selectedAttributes as $attributeId => $optionId) {
$alias = "a{$attributeId}";
$sql .= ' INNER JOIN ' . $dbMeta->getTableName('catalog/product') . "_int" . " $alias ON $alias.entity_id = main_table.entity_id AND $alias.attribute_id = $attributeId AND $alias.value = $optionId AND $alias.entity_id = sl.product_id";
}
$id = $db->fetchOne($sql);
return Mage::getModel("catalog/product")->load($id)->getFinalPrice($qty);
}
You can see, in the event the user has "customized" the product (IE, selected configurable options) we determine the associated simple product and pass control to its pricing model, otherwise if the product isn't "customized" (IE, we're browsing on the product page) we proceed as normal
Using Magento Version 1.9.2.2
May be slightly better solution, use 'Observer' approach instead of hacking the core or even overriding the default Model Price class i.e. app/code/core/Mage/Catalog/Model/Product/Type/Configurable/Price.php
All you have to do is to use Alan's code within your newly created Observer the only difference is instead of returning
Mage::getModel("catalog/product")->load($id)->getFinalPrice($qty);
Replace it with the following:
$fp = Mage::getModel("catalog/product")->load($id)->getFinalPrice($qty);
return $product->setFinalPrice($fp);
Follow this Observer.php
class YourFolderinLOCAL_YourModulename_Model_Observer
{
public function simpleProductPrice(Varien_Event_Observer $observer) {
$event = $observer->getEvent();
$product = $event->getProduct();
$qty = $event->getQty();
//Mage::log($observer, null, 'confPricing.log');
// process percentage discounts only for simple products
$selectedAttributes = array();
if ($product->getCustomOption('attributes')) {
Mage::log('yes-----', null, 'confPricing.log');
$selectedAttributes = unserialize($product->getCustomOption('attributes')->getValue());
}
if (sizeof($selectedAttributes)) return $this->getSimpleProductPrice($qty, $product);
}
public function getSimpleProductPrice($qty=null, $product)
{
$cfgId = $product->getId();
$product->getTypeInstance(true)
->setStoreFilter($product->getStore(), $product);
$attributes = $product->getTypeInstance(true)
->getConfigurableAttributes($product);
$selectedAttributes = array();
if ($product->getCustomOption('attributes')) {
$selectedAttributes = unserialize($product->getCustomOption('attributes')->getValue());
}
$db = Mage::getSingleton('core/resource')->getConnection('core_read');
$dbMeta = Mage::getSingleton('core/resource');
$sql = <<<SQL
SELECT main_table.entity_id FROM {$dbMeta->getTableName('catalog/product')} `main_table` INNER JOIN
{$dbMeta->getTableName('catalog/product_super_link')} `sl` ON sl.parent_id = {$cfgId}
SQL;
foreach($selectedAttributes as $attributeId => $optionId) {
$alias = "a{$attributeId}";
$sql .= ' INNER JOIN ' . $dbMeta->getTableName('catalog/product') . "_int" . " $alias ON $alias.entity_id = main_table.entity_id AND $alias.attribute_id = $attributeId AND $alias.value = $optionId AND $alias.entity_id = sl.product_id";
}
$id = $db->fetchOne($sql);
//Mage::log(Mage::getModel("catalog/product")->load($id)->getFinalPrice($qty), null, 'confPricing.log');
//return
$fp = Mage::getModel("catalog/product")->load($id)->getFinalPrice($qty);
return $product->setFinalPrice($fp);
}
}
Config.xml
<?xml version="1.0"?>
<config>
<modules>
<YourFolderinLOCAL_YourModulename>
<version>0.0.1</version>
</YourFolderinLOCAL_YourModulename>
</modules>
<global>
<models>
<YourFolderinLOCALYourModulename><!-- Al lovwercase in my case -->
<class>Your_Model</class><!-- not needed in my case -->
</YourFolderinLOCALYourModulename>
</models>
</global>
<frontend>
<events>
<catalog_product_get_final_price>
<observers>
<YourFolderinLOCAL_YourModulename_model_observer>
<type>singleton</type>
<class> YourFolderinLOCAL_YourModulename_Model_Observer</class>
<method>simpleProductPrice</method>
</YourFolderinLOCAL_YourModulenameg_model_observer>
</observers>
</catalog_product_get_final_price>
</events>
</frontend>
</config>
Hope it solves the problem.. :)