9

I have been working for 2 days for applying multiple coupon on cart I know there are modules which are available for that. But i don't want to use it. I want some custom code so that i can apply more than 1 coupon code in the single order.

Please help. i am very tired after working on the same stuff. enter image description here

  • 1
    Here you go stackoverflow.com/questions/15138237/… – Tim Hallman May 18 '15 at 16:24
  • Btw, your question is eerily similar to the one I just linked above, which is from 2013. – Tim Hallman May 18 '15 at 16:26
  • @Tim ~ I don't think that is the best method, since it involves adding columns directly to the sales tables bypassing Magento's conventional methods. I actually played around with this now, and with 2 rewrites and a few lines of code, this can easily be achieved. Also the answer in that link only allows for 2 codes to be added. Ill post an answer in a bit – Shaughn May 21 '15 at 8:41
  • @Shaughn pls post your code. – Zaheerabbas May 21 '15 at 9:56
  • could give me an example zip, or be more specific directories please thank's – alexmalara Sep 29 '15 at 22:42
14

In your custom module, add the following to config.xml:

<models>
    <salesrule>
        <rewrite>
            <quote_discount>Namespace_Module_Rewrite_SalesRule_Model_Quote_Discount</quote_discount>
        </rewrite>
    </salesrule>
</models>
<frontend>
    <routers>
        <checkout>
            <args>
                <modules>
                    <Namespace_Module before="Mage_Checkout">Namespace_Module_Checkout</Namespace_Module>
                </modules>
            </args>
        </checkout>
    </routers>
</frontend>

The first is a rewrite of Mage_SalesRule_Model_Quote_Discount to Namespace_Module_Rewrite_SalesRule_Model_Quote_Discount

The second is the overloaded controller Mage_Checkout_CartController

Next add the following file app/code/community/Namespace/Module/controllers/Checkout/CartController.php and insert the following code:

<?php

require_once 'Mage/Checkout/controllers/CartController.php';

class Namespace_Module_Checkout_CartController extends Mage_Checkout_CartController
{
    /**
     * Initialize coupon
     */
    public function couponPostAction()
    {
        /**
         * No reason continue with empty shopping cart
         */
        if (!$this->_getCart()->getQuote()->getItemsCount()) {
            $this->_goBack();
            return;
        }

        $couponCode = (string) $this->getRequest()->getParam('coupon_code');
        if ($this->getRequest()->getParam('remove') == 1) {
            $couponCode = '';
        }
        $oldCouponCode = $this->_getQuote()->getCouponCode();

        if (!strlen($couponCode) && !strlen($oldCouponCode)) {
            $this->_goBack();
            return;
        }

        try {
            $codeLength = strlen($couponCode);
            $isCodeLengthValid = $codeLength && $codeLength <= Mage_Checkout_Helper_Cart::COUPON_CODE_MAX_LENGTH;

            // Combine multiple coupons
            $couponFlag = true;

            if ($isCodeLengthValid) {
                $del = ',';

                if ($oldCouponCode) {

                    if ($oldCouponCode == $couponCode) {
                        $couponCode = $oldCouponCode;
                    } else {
                        $couponCode = $oldCouponCode . $del . $couponCode;
                    }
                }
            } else {
                $couponCode = '';
            }

            $this->_getQuote()->getShippingAddress()->setCollectShippingRates(true);
            $this->_getQuote()->setCouponCode($couponCode)
                ->collectTotals()
                ->save();

            if ($codeLength) {
                if ($isCodeLengthValid && $couponFlag) {
                    $this->_getSession()->addSuccess(
                        $this->__('Coupon code "%s" was applied.', Mage::helper('core')->escapeHtml($couponCode))
                    );
                } else {
                    $this->_getSession()->addError(
                        $this->__('Coupon code "%s" is not valid.', Mage::helper('core')->escapeHtml($couponCode))
                    );
                }
            } else {
                $this->_getSession()->addSuccess($this->__('Coupon code was canceled.'));
            }

        } catch (Mage_Core_Exception $e) {
            $this->_getSession()->addError($e->getMessage());
        } catch (Exception $e) {
            $this->_getSession()->addError($this->__('Cannot apply the coupon code.'));
            Mage::logException($e);
        }

        $this->_goBack();
    }
}

You will notice i added a section to combine coupon codes delimited by ",". This can obviously be more refined and you may want to add additional checking etc, but this code should work straight off the bat.

And finally we need to add the piece that does all the magic. Add the file app/code/community/Namespace/Module/Rewrite/SalesRule/Model/Quote/Discount.php

and add the content:

<?php

class Namespace_Module_Rewrite_SalesRule_Model_Quote_Discount extends Mage_SalesRule_Model_Quote_Discount
{
    /**
     * Collect address discount amount
     *
     * @param   Mage_Sales_Model_Quote_Address $address
     * @return  Mage_SalesRule_Model_Quote_Discount
     */
    public function collect(Mage_Sales_Model_Quote_Address $address)
    {
        Mage_Sales_Model_Quote_Address_Total_Abstract::collect($address);
        $quote = $address->getQuote();
        $store = Mage::app()->getStore($quote->getStoreId());
        $this->_calculator->reset($address);

        $items = $this->_getAddressItems($address);
        if (!count($items)) {
            return $this;
        }

        $couponCode = $quote->getCouponCode();
        $couponArray = explode(',',$couponCode);

        foreach ($couponArray as $couponCode) {
            $this->_calculator->init($store->getWebsiteId(), $quote->getCustomerGroupId(), $couponCode);
            $this->_calculator->initTotals($items, $address);

            $eventArgs = array(
                'website_id'        => $store->getWebsiteId(),
                'customer_group_id' => $quote->getCustomerGroupId(),
                'coupon_code'       => $couponCode,
            );

            $address->setDiscountDescription(array());
            $items = $this->_calculator->sortItemsByPriority($items);
            foreach ($items as $item) {
                if ($item->getNoDiscount()) {
                    $item->setDiscountAmount(0);
                    $item->setBaseDiscountAmount(0);
                }
                else {
                    /**
                     * Child item discount we calculate for parent
                     */
                    if ($item->getParentItemId()) {
                        continue;
                    }

                    $eventArgs['item'] = $item;
                    Mage::dispatchEvent('sales_quote_address_discount_item', $eventArgs);

                    if ($item->getHasChildren() && $item->isChildrenCalculated()) {
                        foreach ($item->getChildren() as $child) {
                            $this->_calculator->process($child);
                            $eventArgs['item'] = $child;
                            Mage::dispatchEvent('sales_quote_address_discount_item', $eventArgs);

                            $this->_aggregateItemDiscount($child);
                        }
                    } else {
                        $this->_calculator->process($item);
                        $this->_aggregateItemDiscount($item);
                    }
                }
            }

            /**
             * process weee amount
             */
            if (Mage::helper('weee')->isEnabled() && Mage::helper('weee')->isDiscounted($store)) {
                $this->_calculator->processWeeeAmount($address, $items);
            }

            /**
             * Process shipping amount discount
             */
            $address->setShippingDiscountAmount(0);
            $address->setBaseShippingDiscountAmount(0);
            if ($address->getShippingAmount()) {
                $this->_calculator->processShippingAmount($address);
                $this->_addAmount(-$address->getShippingDiscountAmount());
                $this->_addBaseAmount(-$address->getBaseShippingDiscountAmount());
            }

            $this->_calculator->prepareDescription($address);
        }

        return $this;
    }
}

Basically, what this does is breaks the coupon sting up, loops through each coupon code, calculates and updates the quote totals.

To test, i have setup 2 shopping cart rules:

  • test 1 - 10 % product price discount - Stop Further Rules Processing: No
  • test 2 - 10 % product price discount - Stop Further Rules Processing: No

No coupon: no coupon

Added coupon test 1: added coupon test 1

Added coupon test 2 added coupon test 1

I have tested with fixed amount discount and this works as expected as well.

And like i said, you may need to add additional checking, possibly for duplicates, but this is where you would start. For the frontend, you could add some logic split the codes however you prefer or leave as is.

  • Also forgot to mention, you would obviously need to replace Namespace/Module with your actual module name, etc. – Shaughn May 21 '15 at 11:22
  • after edit this answer now it's working like above screenshot.now how can i cancel specific coupon after applying multiple coupon. – Zaheerabbas May 28 '15 at 8:49
  • Thanks Shaughn for you answer, it worked for me on magento 1.9 but i couldn't get it to work on ver 1.8, it displays nothing in browser and throw memory size exhausted error in apache error.log (not magento error/system.log) – Haris Jun 30 '15 at 6:27
  • Hey Saddam, the memory issue is probably one of many issues, but what you could do is wrap the code in a try catch block and log any errors that crop up.Also check the max memory setting in php and make sure you have sufficient memory available. Just before the loop you could count the coupon codes and check how many there are as i suspect there are a few that is loaded into memory. – Shaughn Jul 1 '15 at 9:02
  • 1
    To easily prevent the multiple use of the same coupon codes you can just use array_unique $couponArray = array_unique(explode(',',$couponCode)); – Julian Jul 14 '16 at 12:33

protected by Community Jul 14 '16 at 13:33

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.