Magento has an awesome feature for setting different tiered pricing for different quantity and also for different customer group. But sometimes you may feel this is problematic since you have to set a fixed price for tier items.
So, Lets make our hands dirty to extend this feature so that we can set a percentage which % amount will be deducted from the item price.
Step1
Magento keeps productโs tier pricing information in product_entity_tier_price table. Fist lets create a new column โtier_typeโ to keep track which type(Fixed / percentage) of tier pricing to be applied.
File:/app/etc/modules/Mypackage_Tierpricing.xml
<?xml version="1.0"?>
<config>
<modules>
<Mypackage_Tierpricing>
<active>true</active>
<codePool>local</codePool>
</Mypackage_Tierpricing>
</modules>
</config>
File:/app/code/local/Mypackage/Tierpricing/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<Mypackage_Tierpricing>
<version>0.1.0</version>
</Mypackage_Tierpricing>
</modules>
<global>
<resources>
<tierpricing_setup>
<setup>
<module>Mypackage_Tierpricing</module>
</setup>
<connection>
<use>core_setup</use>
</connection>
</tierpricing_setup>
<tierpricing_write>
<connection>
<use>core_write</use>
</connection>
</tierpricing_write>
<tierpricing_read>
<connection>
<use>core_read</use>
</connection>
</tierpricing_read>
</resources>
</global>
</config>
File: /app/code/local/Mypackage/Tierpricing/sql/tierpricing_setup/mysql4-install-0.1.0.php
<?php
$installer = $this;
$installer->startSetup();
$installer->run(
"ALTER TABLE {$this->getTable('catalog_product_entity_tier_price')} ADD tier_type INT NOT NULL AFTER qty ; ");
$installer->endSetup();
Step2
Lets change the product admin panel to save/update tier type (Fixed/percentage). We override the block Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Backend_Tierprice so that it fetches the “tier_type”
from db.
File:-app/code/local/Mypackage/Catalog/Model/Product/Attribute/Backend/Tierprice.php
<?php
class Mypackage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Backend_Tierprice extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Backend_Tierprice
{
public function loadProductPrices($product, $attribute)
{
//add new column name to the sql
$select = $this->_getReadAdapter()->select()
->from($this>getMainTable(), array(
'website_id', 'all_groups', 'cust_group' => 'customer_group_id',
'price_qty' => 'qty', 'price' => 'value', 'tier_type',
))
->where('entity_id=?', $product->getId())
->order('qty');
if ($attribute->isScopeGlobal()) {
$select->where('website_id=?', 0);
}
else {
if ($storeId = $product->getStoreId()) {
$select->where('website_id IN (?)', array(0, Mage::app()->getStore($storeId)->getWebsiteId()));
}
}
return $this->_getReadAdapter()->fetchAll($select);
}
}
?>
To save tier_type we to override the backend model Mage_Catalog_Model_Product_Attribute_Backend_Tierprice.
File:-app/code/local/Mypackage/Catalog/Model/Resource/Eav/Mysql4/Product/Attribute/Backend/Tierprice.php
<?php
class Mypackage_Catalog_Model_Product_Attribute_Backend_Tierprice extends Mage_Catalog_Model_Product_Attribute_Backend_Tierprice
{
public function afterSave($object)
{
$this->_getResource()->deleteProductPrices($object, $this->getAttribute());
$tierPrices = $object->getData($this->getAttribute()->getName());
if (!is_array($tierPrices)) {
return $this;
}
$prices = array();
foreach ($tierPrices as $tierPrice) {
if (empty($tierPrice['price_qty']) || !isset($tierPrice['price']) || !empty($tierPrice['delete'])) {
continue;
}
$useForAllGroups = $tierPrice['cust_group'] == Mage_Customer_Model_Group::CUST_GROUP_ALL;
$customerGroupId = !$useForAllGroups ? $tierPrice['cust_group'] : 0;
$priceKey = join('-', array(
$tierPrice['website_id'],
intval($useForAllGroups),
$customerGroupId,
$tierPrice['price_qty']
));
//Add new column "tier_type"
$prices[$priceKey] = array(
'website_id' => $tierPrice['website_id'],
'all_groups' => intval($useForAllGroups),
'customer_group_id' => $customerGroupId,
'qty' => $tierPrice['price_qty'],
'value' => $tierPrice['price'],
'tier_type' => $tierPrice['tier_type'],
);
}
if ($this->getAttribute()->getIsGlobal() == Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_WEBSITE) {
if ($storeId = $object->getStoreId()) {
$websites = array(Mage::app()->getStore($storeId)->getWebsite());
}
else {
$websites = Mage::app()->getWebsites();
}
$baseCurrency = Mage::app()->getBaseCurrencyCode();
$rates = $this->_getWebsiteRates();
foreach ($websites as $website) {
/* @var $website Mage_Core_Model_Website */
if (!is_array($object->getWebsiteIds()) || !in_array($website->getId(), $object->getWebsiteIds())) {
continue;
}
if ($rates[$website->getId()]['code'] != $baseCurrency) {
foreach ($prices as $data) {
$priceKey = join('-', array(
$website->getId(),
$data['all_groups'],
$data['customer_group_id'],
$data['qty']
));
if (!isset($prices[$priceKey])) {
$prices[$priceKey] = $data;
$prices[$priceKey]['website_id'] = $website->getId();
$prices[$priceKey]['value'] = $data['value'] * $rates[$website->getId()]['rate'];
}
}
}
}
}
foreach ($prices as $data) {
$this->_getResource()->insertProductPrice($object, $data);
}
return $this;
}
}
Change the admin phtml for tier pricing.
File:-/app/design/adminhtml/default/default/template/catalog/product/edit/price/tier.phtml
<?php
<?php $_htmlId = $this->getElement()->getHtmlId() ?>
<?php $_htmlClass = $this->getElement()->getClass() ?>
<?php $_htmlName = $this->getElement()->getName() ?>
<?php $_readonly = $this->getElement()->getReadonly() ?>
<?php $_multiWebsite= $this->isMultiWebsites(); ?>
<tr>
<td class="label"><?php echo $this->getElement()->getLabel() ?></td>
</tr>
<tr>
<td colspan="10" class="grid tier">
<table cellspacing="0" class="data border" id="tiers_table">
<?php if ($_multiWebsite): ?>
<col width="135" />
<?php endif; ?>
<col width="120" />
<col width="60" />
<col width="140"/>
<col width="60" />
<thead>
<tr class="headings">
<th <?php if (!$_multiWebsite): ?>style="display:none"<?php endif; ?>><?php echo Mage::helper('sales')->__('Website') ?></th>
<th><?php echo Mage::helper('catalog')->__('Customer Group') ?></th>
<th><?php echo Mage::helper('catalog')->__('Qty') ?></th>
<!-- Added -->
<th><?php echo Mage::helper('catalog')->__('Type') ?></th>
<!-- -/- -->
<th><?php echo $this->getPriceColumnHeader(Mage::helper('catalog')->__('Price')) ?></th>
<th class="last"><?php echo Mage::helper('catalog')->__('Action') ?></th>
</tr>
<tr id="<?php echo $_htmlId ?>_add_template" class="template no-display">
<!-- Website list -->
<td <?php if (!$_multiWebsite): ?>style="display:none"<?php endif; ?>>
<select disabled="no-template" class="<?php echo $_htmlClass ?> required-entry" name="<?php echo $_htmlName ?>[__index__][website_id]" id="tier_price_row___index___website">
<?php foreach ($this->getWebsites() as $_websiteId => $_info): ?>
<option value="<?php echo $_websiteId ?>"><?php echo $_info['name'] ?><?php if (!empty($_info['currency'])): ?> [<?php echo $_info['currency'] ?>]<?php endif; ?></option>
<?php endforeach ?>
</select>
</td>
<!-- -/- -->
<!-- Customer Group -->
<td>
<select disabled="no-template" class="<?php echo $_htmlClass ?> custgroup required-entry" name="<?php echo $_htmlName ?>[__index__][cust_group]" id="tier_price_row___index___cust_group">
<?php foreach ($this->getCustomerGroups() as $_groupId=>$_groupName): ?>
<option value="<?php echo $_groupId ?>"><?php echo htmlspecialchars($_groupName) ?></option>
<?php endforeach ?>
</select>
</td>
<!-- -/- -->
<!-- Qty -->
<td class="nobr">
<input disabled="no-template" class="<?php echo $_htmlClass ?> qty required-entry validate-greater-than-zero" type="text" name="<?php echo $_htmlName ?>[__index__][price_qty]" value="'#{qty}'" /> <small class="nobr"><?php echo Mage::helper('catalog')->__('and above')?></small>
</td>
<!-- -/- -->
<!-- Added type-->
<td class="nobr">
<select disabled="no-template" class="<?php echo $_htmlClass ?> tiertype required-entry" name="<?php echo $_htmlName ?>[__index__][tier_type]" id="tier_price_row___index___tier_type" >
<option value="0">Fixed</option>
<option value="1">% Off</option>
</select>
</td>
<!-- -/- -->
<!-- Price -->
<td>
<input disabled="no-template" class="<?php echo $_htmlClass ?> required-entry validate-greater-than-zero" type="text" name="<?php echo $_htmlName ?>[__index__][price]" value="'#{price}'" />
</td>
<!-- -/- -->
<!-- Button -->
<td class="last"><input type="hidden" name="<?php echo $_htmlName ?>[__index__][delete]" class="delete" disabled="no-template" value="" /><button title="Delete Tier" class="scalable delete icon-btn delete-product-option" onclick="tierPriceControl.deleteItem(event);return false"><span>Delete</span></button></td>
<!-- -/- -->
</tr>
</thead>
<tfoot>
<tr>
<td <?php if (!$_multiWebsite): ?>style="display:none"<?php endif; ?>></td>
<td colspan="5" class="a-right"><?php echo $this->getAddButtonHtml() ?></td>
</tr>
</tfoot>
<tbody id="<?php echo $_htmlId ?>_container">
</tbody>
</table>
<script type="text/javascript">
//<![CDATA[
var tierPriceControl = {
template : new Template('<tr>' + $('<?php echo $_htmlId ?>_add_template').innerHTML.replace(/__index__/g, '#{index}').replace(/ disabled="?no-template"?/g, '').replace(/ disabled/g, '').replace(/="'([^']*)'"/g, '="$1"') + '</tr>'),
itemsCount : 0,
deleteButton: false,
addItem : function () {
<?php if ($_readonly): ?>
if (arguments.length < 4) {
return;
}
<?php endif; ?>
var data = {};
data.website_id = 0;
data.group = '<?php echo $this->getDefaultCustomerGroup() ?>';
data.qty = '';
data.price = '';
data.index = this.itemsCount++;
if(arguments.length == 5) {
data.website_id = arguments[0];
data.group = arguments[1];
data.qty = arguments[2];
data.price = arguments[3];
data.tier_type = arguments[4];
}
Element.insert($('<?php echo $_htmlId ?>_container'), {'bottom':this.template.evaluate(data)});
$('tier_price_row_'+data.index+'_cust_group').value = data.group;
$('tier_price_row_'+data.index+'_website').value = data.website_id;
$('tier_price_row_'+data.index+'_tier_type').value = data.tier_type;
<?php if ($_readonly): ?>
$('<?php echo $_htmlId ?>_container').select('input', 'select')
.each(this.disableElement);
$('<?php echo $_htmlId ?>_container').up('table').select('button')
.each(this.disableElement);
<?php endif; ?>
},
disableElement: function(elem) {
elem.disabled = true
elem.addClassName('disabled');
},
deleteItem : function(event) {
var tr = Event.findElement(event, 'tr');
if (tr) {
Element.select(tr, '.delete').each(function(elem){elem.value='1'});
Element.select(tr, ['input', 'select']).each(function(elem){elem.hide()});
Element.hide(tr);
Element.addClassName(tr, 'no-display template');
}
}
}
<?php foreach ($this->getValues() as $_item): ?>
tierPriceControl.addItem('<?php echo $_item['website_id'] ?>', '<?php echo $_item['cust_group'] ?>', '<?php echo $_item['price_qty']*1 ?>','<?php echo sprintf('%.2f', $_item['price']) ?>','<?php echo $_item['tier_type'] ?>');
<?php endforeach; ?>
<?php if ($_readonly): ?>
$('<?php echo $_htmlId ?>_container').up('table').select('button')
.each(tierPriceControl.disableElement);
<?php endif; ?>
//]]>
</script>
</td>
</tr>
Step 3
To change tier pricing we override the Mage_Catalog_Model_Product_Type_Price model’s getTierPrice method.
File:-/app/code/local/Mypackage/Catalog/Model/Product/Type/Price.php
<?php
class Mypackage_Catalog_Model_Product_Type_Price extends Mage_Catalog_Model_Product_Type_Price
{
public function getTierPrice($qty=null, $product)
{
$allGroups = Mage_Customer_Model_Group::CUST_GROUP_ALL;
$prices = $product->getData('tier_price');
if (is_null($prices)) {
if ($attribute = $product->getResource()->getAttribute('tier_price')) {
$attribute->getBackend()->afterLoad($product);
$prices = $product->getData('tier_price');
}
}
if (is_null($prices) || !is_array($prices)) {
if (!is_null($qty)) {
return $product->getPrice();
}
return array(array(
'price' => $product->getPrice(),
'website_price' => $product->getPrice(),
'price_qty' => 1,
'cust_group' => $allGroups,
));
}
$custGroup = $this->_getCustomerGroupId($product);
if ($qty) {
$prevQty = 1;
$prevPrice = $product->getPrice();
$prevGroup = $allGroups;
foreach ($prices as $price) {
if ($price['cust_group']!=$custGroup && $price['cust_group']!=$allGroups) {
// tier not for current customer group nor is for all groups
continue;
}
if ($qty < $price['price_qty']) {
// tier is higher than product qty
continue;
}
if ($price['price_qty'] < $prevQty) {
// higher tier qty already found
continue;
}
if ($price['price_qty'] == $prevQty && $prevGroup != $allGroups && $price['cust_group'] == $allGroups) {
// found tier qty is same as current tier qty but current tier group is ALL_GROUPS
continue;
}
$prevPrice = $price['website_price'];
$prevQty = $price['price_qty'];
if($price['tier_type'] == 1 && $price['price_qty'] <= 100){
$off = ($price['website_price'] * $product->getPrice())/100;
$prevPrice = $product->getPrice() - $off;
}
$prevGroup = $price['cust_group'];
}
return $prevPrice;
} else {
foreach ($prices as $i=>$price) {
if ($price['cust_group']!=$custGroup && $price['cust_group']!=$allGroups) {
unset($prices[$i]);
}
}
}
return ($prices) ? $prices : array();
}
}
?>
At last register all these override into config.xml.
File:-/app/code/local/Mypackage/Catalog/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<Mypackage_Catalog>
<version>0.1.0</version>
</Mypackage_Catalog>
</modules>
<global>
<models>
<catalog>
<rewrite>
<product_type_price>Mypackage_Catalog_Model_Product_Type_Price</product_type_price>
<product_attribute_backend_tierprice>Mypackage_Catalog_Model_Product_Attribute_Backend_Tierprice</product_attribute_backend_tierprice>
</rewrite>
</catalog>
<catalog_resource_eav_mysql4>
<rewrite>
<product_attribute_backend_tierprice>Mypackage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Backend_Tierprice</product_attribute_backend_tierprice>
</rewrite>
</catalog_resource_eav_mysql4>
</models>
</global>
</config>
Register this local catalog module in etc.
File:/app/etc/modules/Mypackage_Catalog.xml
<?xml version="1.0"?>
<config>
<modules>
<Mypackage_Catalog>
<active>true</active>
<codePool>local</codePool>
</Mypackage_Catalog>
</modules>
</config>