Magento E-commerce Platform Q/ A

How to Add a Discount to the Total in Magento?

Quite frequently there is a requirement by the shop owners to add a discount to the checkout totals. You should add a custom total to existing (default) totals collection. The first step is to add this code to the config.xml file:

<global>
<sales>
            <quote>
                <totals>
                    <discount>
                        <class>Ikantam_BasicLoyalty_Model_ Discount</class>
                        <after>subtotal</after>
                    </ discount >
                </totals>
            </quote>
			
            <order_invoice>
                <totals>
                    <discount >
                        <class>Ikantam_BasicLoyalty_Model_ Invoice </class>
                        <after>subtotal</after>
                    </discount >
                </totals>
            </order_invoice>
			
            <order_creditmemo>
                <totals>
                    <discount >
                        <class>Ikantam_BasicLoyalty_Model_Creditmemo</class>
                        <after>subtotal</after>
                    </discount >
                </totals>
            </order_creditmemo>
        </sales>
</global>

 

This code will allow you to add a custom value to: quote, order invoice and order credit memo controllers. Also with the help of tags: <after> and <before> it is possible to define the discount calculation procedure here. It needs to be done in order to define the value (subtotal, total etc) to calculate discount. In the example below the discount of subtotal meaning is calculated.

The next step is to create classes specified in config.xml file which will calculate the discount. Let's start with Ikantam_BasicLoyalty_Model_Discount.

class Ikantam_BasicLoyalty_Model_Discount extends Mage_Sales_Model_Quote_Address_Total_Abstract {

    public function collect(Mage_Sales_Model_Quote_Address $address) {
            if ($address->getData('address_type') == 'billing')
                return $this;

$discount = 15; //your discount percent
                
                $grandTotal = $address->getGrandTotal();
                $baseGrandTotal = $address->getBaseGrandTotal();

                $totals = array_sum($address->getAllTotalAmounts());
                $baseTotals = array_sum($address->getAllBaseTotalAmounts());

                $address->setFeeAmount(-$totals * $discount / 100);
                $address->setBaseFeeAmount(-$baseTotals * $discount / 100);

                $address->setGrandTotal($grandTotal + $address->getFeeAmount());
                $address->setBaseGrandTotal($baseGrandTotal + $address->getBaseFeeAmount());
        return $this;
    }

    public function fetch(Mage_Sales_Model_Quote_Address $address) {
        
            if ($address->getData('address_type') == 'billing')
                return $this;

            $amt = $address->getDiscountAmount();
            if ($amt != 0) {
                
                
                $address->addTotal(array(
                    'code' => 'Discount',
                    'title' => 'Discount',
                    'value' => $amt
                ));
            }
        
        return $address;
    }

}

 

Note: Total value is calculated for all addresess (could be billing and shipping, or multiple shipping addresses, etc.) indicated in quote, that's why it is essential to calculate the discount only for the shipping address, in other cases the discount will appear twice. To avoid this situation, run the address verification first and only after the verification, perform discount calculations and pass the results to Total collection. The method: fetch() is responsible for displaying the discount. Thus, if all done well, the discount should appear on Checkout and Cart pages:

228

229

 

The next steps: implement the classes Ikantam_BasicLoyalty_Model_Invoice and Ikantam_BasicLoyalty_Model_Creditmemo which are similar to each other and do not require further explanation.

class Ikantam_BasicLoyalty_Model_Invoice extends Mage_Sales_Model_Order_Invoice_Total_Abstract
{
    public function collect(Mage_Sales_Model_Order_Invoice $invoice)
    {
        $invoice->setGrandTotal($invoice->getGrandTotal() + $invoice->getFeeAmount());
        $invoice->setBaseGrandTotal($invoice->getBaseGrandTotal() + $invoice->getBaseFeeAmount());

        return $this;
    }
}
class Ikantam_BasicLoyalty_Model_Creditmemo extends Mage_Sales_Model_Order_Creditmemo_Total_Abstract
{
    public function collect(Mage_Sales_Model_Order_Creditmemo $creditmemo)
    {
        $creditmemo->setGrandTotal($creditmemo->getGrandTotal() + $creditmemo->getFeeAmount());
        $creditmemo->setBaseGrandTotal($creditmemo->getBaseGrandTotal() + $creditmemo->getBaseFeeAmount());

        return $this;
    }
}

 

Add the following code to config.ini file to display the discount:

<blocks>
            <basicloyalty>
                <class>Ikantam_BasicLoyalty_Block</class>
            </basicloyalty>

            <adminhtml>
                <rewrite>
                    <sales_order_totals>Ikantam_BasicLoyalty_Block_Adminhtml_Sales_Order</sales_order_totals>   <sales_order_invoice_totals>Ikantam_BasicLoyalty_Block_Adminhtml_Sales_Invoice</sales_order_invoice_totals>     <sales_order_creditmemo_totals>Ikantam_BasicLoyalty_Block_Adminhtml_Sales_Creditmemo</sales_order_creditmemo_totals>
                </rewrite>
            </adminhtml>
                
            <sales>
                <rewrite>
                    <order_totals>Ikantam_BasicLoyalty_Block_Sales_Order</order_totals>
                    <order_invoice_totals>Ikantam_BasicLoyalty_Block_Sales_Invoice</order_invoice_totals>
<order_creditmemo_totals>Ikantam_BasicLoyalty_Block_Sales_Creditmemo</order_creditmemo_totals>
                </rewrite>
            </sales>
                
        </blocks>

 

And create the corresponding classes. As you can see these classes have almost the same code:

class Ikantam_BasicLoyalty_Block_Sales_Creditmemo extends Mage_Sales_Block_Order_Creditmemo_Totals {

    protected function _initTotals() {
        parent::_initTotals();
        $amt = $this->getSource()->getFeeAmount();
        $baseAmt = $this->getSource()->getBaseFeeAmount();
        if ($amt != 0) {

            $this->addTotal(new Varien_Object(array(
                        'code' => 'Discount',
                        'value' => $amt,
                        'base_value' => $baseAmt,
                        'label' => 'Discount',
                    )), 'discount');
        }
        return $this;
    }
}
class Ikantam_BasicLoyalty_Block_Adminhtml_Sales_Invoice extends Mage_Sales_Block_Order_Invoice_Totals {

    protected function _initTotals() {
        parent::_initTotals();
        $amt = $this->getSource()->getFeeAmount();
        $baseAmt = $this->getSource()->getBaseFeeAmount();
        if ($amt != 0) {
            $this->addTotal(new Varien_Object(array(
                        'code' => 'Discount',
                        'value' => $amt,
                        'base_value' => $baseAmt,
                        'label' => 'Discount',
                    )), 'discount');
        }
        return $this;
    }

}
class Ikantam_BasicLoyalty_Block_Sales_Order extends Mage_Sales_Block_Order_Totals {

    protected function _initTotals() {
        parent::_initTotals();
        $amt = $this->getSource()->getFeeAmount();
        $baseAmt = $this->getSource()->getBaseFeeAmount();
        if ($amt != 0) {
            $this->addTotal(new Varien_Object(array(
                        'code' => 'Fee',
                        'value' => $amt,
                        'base_value' => $baseAmt,
                        'label' => 'Discount',
                    )), 'discount');
        }
        return $this;
    }

}

234

233

 

That's it. The discount was succesfully added to all necessary areas of the store.