3

If we applied coupon code and completed order.

Once we cancel the order, then coupon code should become applicable again, but it can't be used anymore. Please help me, it's strange default Magento behavior.

Please help me soon.

6

This is default Magento behaviour - if the payment fails / the order is canceled before it, then the coupon code will not be free to be reused.

There're few modules that change this behaviour. Quick googling gave me f/e:

http://magetechno.com/cancel-order-coupon-code-reuse.html

Here's description for the situation: http://magebase.com/magento-tutorials/quick-fix-coupon-codes-used-up-on-incomplete-transactions/

To avoid link being removed and for future reference I'm copy-pastying the contents of that post: (all credits go to MageBase.com for this solution, it's untested but from the looks of it - should do it's job):

app/code/local/Orchid/CouponFix/Model/Observer.php

<?php
class Orchid_CouponFix_Model_Observer
{
    public function cancel($observer)
    {
    $event = $observer->getEvent();
        $order = $event->getPayment()->getOrder();
        if ($order->canCancel()) {
        if ($code = $order->getCouponCode()) {
            $coupon = Mage::getModel('salesrule/rule')->load($code, 'coupon_code');
            $coupon->setTimesUsed($coupon->getTimesUsed()-1);
            $coupon->save();
            if($customerId = $order->getCustomerId()) {
                if ($customerCoupon = Mage::getModel('salesrule/rule_customer')->loadByCustomerRule($customerId, $coupon->getId())) {
                    $customerCoupon->setTimesUsed($customerCoupon->getTimesUsed()-1);
                    $customerCoupon->save();
                }
            }
        }
    }
}

app/code/local/Orchid/CouponFix/etc/config.xml

<config>
    <modules>
            <Orchid_CouponFix>
                    <version>0.1.0</version>
            </Orchid_CouponFix>
    </modules>
    <global>
        <models>
            <couponfix>
                <class>Orchid_CouponFix_Model</class>
            </couponfix>
    </models>
    <events>
        <sales_order_payment_cancel>
        <observers>
          <orchid_couponfix_observer>
            <type>singleton</type>
            <class>Orchid_CouponFix_Model_Observer</class>
            <method>cancel</method>
          </orchid_couponfix_observer>
        </observers>
        </sales_order_payment_cancel>     
    </events>
    </global>
</config>

app/etc/modules/Orchid_CouponFix.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Orchid_CouponFix>
            <active>true</active>
            <codePool>local</codePool>
        </Orchid_CouponFix>
    </modules>
</config> 
| improve this answer | |
  • thanks , i used Orchid module, when i try to cance lthe order i got theis error : SQLSTATE[42S22]: Column not found: 1054 Unknown column 'salesrule.coupon_code' in 'where clause', query was: SELECT salesrule.* FROM salesrule` WHERE (salesrule.coupon_code='123456')` please help me – Baby in Magento Jul 15 '16 at 9:24
  • also i downloaded this extension : magetechno.com/cancel-order-coupon-code-reuse.html but there is app/etc/module.xml file is not there, please help me – Baby in Magento Jul 15 '16 at 9:46
  • I hope it Magento 2.2.6 cancel functionality works as expected with coupon code reuse. How to develop it programatically – insoftservice Mar 6 '19 at 22:36
  • Could you let me know the actual path and function of this code which reverts coupon code so that it could be reuse tried to debug in magento/module-sales/controller/Adminhtml/order/cancel.php but was unable to get actual functionality which could be used in my customize cancel functionality – insoftservice Mar 6 '19 at 22:45
2

You could create an event observer for order_cancel_after. Then if the order was placed by a customer ($order->getCustomerId() > 0), you can update the salesrule_coupon_usage table and lower the value of times_used for this coupon.

  • Get the applied coupon codes for an order by checking the coupon_code attribute of an order and keep in mind that some extensions may accept more than one code and separate them by commas: $couponCodes = explode(',', $order->getCouponCode());
  • For finding the correct coupon_id, see Mage_SalesRule_Model_Coupon::loadByCode()
  • For decreasing times_used, you could check Mage_SalesRule_Model_Resource_Coupon_Usage::updateCustomerCouponTimesUsed(), which increases times_used
| improve this answer | |
2

The accepted answer doesn't work for me in Magento 1.9.3+ So i modified and added some code to the observer cancel function. This should do the trick:

public function cancel($observer)
{
    $event = $observer->getEvent();
    $order = $event->getPayment()->getOrder();

    if ($order->canCancel()) {
        $customerId = $order->getCustomerId();
        $code = $order->getCouponCode();

        if ($code) {
            $rule = Mage::getModel('salesrule/rule')->load($code, 'name');
            $rule->setTimesUsed($rule->getTimesUsed() - 1);
            $rule->save();

            $coupon = Mage::getModel('salesrule/coupon')->loadByCode($code);
            $coupon->setTimesUsed($coupon->getTimesUsed() - 1);
            $coupon->save();

            if ($customerId) {
                /* @var Mage_SalesRule_Model_Resource_Coupon_Usage $couponUsage */
                $couponUsage = Mage::getResourceModel('salesrule/coupon_usage');
                $couponUsage->getReadConnection()->delete($couponUsage->getMainTable(), [
                    'coupon_id = ?' => $coupon->getId(),
                    'customer_id = ?' => $customerId
                ]);

                $customerCoupon = Mage::getModel('salesrule/rule_customer')->loadByCustomerRule($customerId, $rule->getId());

                if ($customerCoupon) {
                    $customerCoupon->setTimesUsed($customerCoupon->getTimesUsed() - 1);
                    $customerCoupon->save();
                }
            }
        }
    }
}
| improve this answer | |
  • I confirm that the solution works on 1.9+ and take care of every tables that need to be edited. Great work – rou6e Jan 9 '19 at 15:07
  • @Jesse Visser if guest is going to apply coupon means ? where to do the changes – chris Jan 19 '19 at 10:51
1

I tried the above answer by @Jesse Visser in my Magento 1.9.0.1 but when I try to place an order it gives an error to try again later so I have updated the above code, any improvement on my below code would be great.

<?php
class Orchid_CouponFix_Model_Observer
{
    public function cancel($observer)
    {
    $resource = Mage::getSingleton('core/resource');
    $writeConnection = $resource->getConnection('core_write');
    $readConnection = $resource->getConnection('core_read');
    $event = $observer->getEvent();
        $order = $event->getPayment()->getOrder();
        if ($order->canCancel()) {
            if ($code = $order->getCouponCode()) {
                $coupon = Mage::getModel('salesrule/coupon')->load($code, 'code');
                $coupon_id = $coupon->getCouponId();
                $rule_id = $coupon->getRuleId();
                if($customerId = $order->getCustomerId()){
                    // Update or Delete record in salesrule_coupon_usage Table
                    $tableName = $resource->getTableName('salesrule_coupon_usage');
                    $query = "SELECT * FROM {$tableName} WHERE coupon_id={$coupon_id} AND customer_id={$customerId}";
                    $coupon_usage = $readConnection->fetchAll($query);
                    $coupon_usage = $coupon_usage[0]['times_used'];
                    if($coupon_usage==1){
                        $query = "DELETE FROM {$tableName} WHERE coupon_id={$coupon_id} AND customer_id={$customerId}";
                    }else{
                        $coupon_usage = $coupon_usage-1;
                        $query = "UPDATE {$tableName} SET times_used={$coupon_usage} WHERE coupon_id={$coupon_id} AND customer_id={$customerId}";
                    }
                    $writeConnection->query($query);

                    // Update or Delete record in salesrule_customer Table
                    $tableName = $resource->getTableName('salesrule_customer');
                    $query = "SELECT * FROM {$tableName} WHERE rule_id={$rule_id} AND customer_id={$customerId}";
                    $coupon_usage = $readConnection->fetchAll($query);
                    $coupon_usage = $coupon_usage[0]['times_used'];
                    if($coupon_usage==1){
                        $query = "DELETE FROM {$tableName} WHERE rule_id={$rule_id} AND customer_id={$customerId}";
                    }else{
                        $coupon_usage = $coupon_usage-1;
                        $query = "UPDATE {$tableName} SET times_used={$coupon_usage} WHERE rule_id={$rule_id} AND customer_id={$customerId}";
                    }
                    $writeConnection->query($query);
                }
            }
        }
    }
}

Cheers

| improve this answer | |
1

For CE 1.7.0.2 installations with all security patches installed (up to SUPEE10975), the salesrule_coupon table must also be updated, Obeserver.php updated:

<?php
class Orchid_CouponFix_Model_Observer
{
    public function cancel($observer)
    {
    $resource = Mage::getSingleton('core/resource');
    $writeConnection = $resource->getConnection('core_write');
    $readConnection = $resource->getConnection('core_read');
    $event = $observer->getEvent();
        $order = $event->getPayment()->getOrder();
        if ($order->canCancel()) {
            if ($code = $order->getCouponCode()) {
                $coupon = Mage::getModel('salesrule/coupon')->load($code, 'code');
                $coupon_id = $coupon->getCouponId();
                $rule_id = $coupon->getRuleId();
                if($customerId = $order->getCustomerId()){
                    // Update or Delete record in salesrule_coupon_usage Table
                    $tableName = $resource->getTableName('salesrule_coupon_usage');
                    $query = "SELECT * FROM {$tableName} WHERE coupon_id={$coupon_id} AND customer_id={$customerId}";
                    $coupon_usage = $readConnection->fetchAll($query);
                    $coupon_usage = $coupon_usage[0]['times_used'];
                    if($coupon_usage==1){
                        $query = "DELETE FROM {$tableName} WHERE coupon_id={$coupon_id} AND customer_id={$customerId}";
                    }else{
                        $coupon_usage = $coupon_usage-1;
                        $query = "UPDATE {$tableName} SET times_used={$coupon_usage} WHERE coupon_id={$coupon_id} AND customer_id={$customerId}";
                    }
                    $writeConnection->query($query);

                    // Update record in salesrule_coupon Table
                    $tableName = $resource->getTableName('salesrule_coupon');
                    $query = "SELECT * FROM {$tableName} WHERE coupon_id={$coupon_id}";
                    $coupon_usage = $readConnection->fetchAll($query);
                    $coupon_usage = $coupon_usage[0]['times_used'];
                    if($coupon_usage==1){
                        $coupon_usage = 0;
                        $query = "UPDATE {$tableName} SET times_used={$coupon_usage} WHERE coupon_id={$coupon_id}";
                    }else{
                        $coupon_usage = $coupon_usage-1;
                        $query = "UPDATE {$tableName} SET times_used={$coupon_usage} WHERE coupon_id={$coupon_id}";
                    }
                    $writeConnection->query($query);                    

                    // Update or Delete record in salesrule_customer Table
                    $tableName = $resource->getTableName('salesrule_customer');
                    $query = "SELECT * FROM {$tableName} WHERE rule_id={$rule_id} AND customer_id={$customerId}";
                    $coupon_usage = $readConnection->fetchAll($query);
                    $coupon_usage = $coupon_usage[0]['times_used'];
                    if($coupon_usage==1){
                        $query = "DELETE FROM {$tableName} WHERE rule_id={$rule_id} AND customer_id={$customerId}";
                    }else{
                        $coupon_usage = $coupon_usage-1;
                        $query = "UPDATE {$tableName} SET times_used={$coupon_usage} WHERE rule_id={$rule_id} AND customer_id={$customerId}";
                    }
                    $writeConnection->query($query);
                }
            }
        }
    }
}
| improve this answer | |
0

1.9

if ($code = $order->getCouponCode()) {
                    $resource = Mage::getSingleton('core/resource');
                    $writeConnection = $resource->getConnection('core_write');
                    $readConnection = $resource->getConnection('core_read');

                    $coupon = Mage::getModel('salesrule/coupon')->load($code, 'code');
                    $coupon_id = $coupon->getCouponId();
                    $rule_id = $coupon->getRuleId();

                    // Update record in salesrule_coupon Table
                    $tableName = 'salesrule_coupon';
                    $query = "SELECT * FROM {$tableName} WHERE coupon_id={$coupon_id}";
                    $coupon_usage = $readConnection->fetchAll($query);
                    $coupon_usage = $coupon_usage[0]['times_used'];
                    if($coupon_usage > 0){
                        $coupon_usage = $coupon_usage-1;
                        $query = "UPDATE {$tableName} SET times_used={$coupon_usage} WHERE coupon_id={$coupon_id}";
                    }
                    $writeConnection->query($query);

                    if($customerId = $order->getCustomerId()){
                        // Update or Delete record in salesrule_coupon_usage Table
                        $tableName = 'salesrule_coupon_usage';
                        $query = "SELECT * FROM {$tableName} WHERE coupon_id={$coupon_id} AND customer_id={$customerId}";
                        $coupon_usage = $readConnection->fetchAll($query);
                        $coupon_usage = $coupon_usage[0]['times_used'];
                        if($coupon_usage==1){
                            $query = "DELETE FROM {$tableName} WHERE coupon_id={$coupon_id} AND customer_id={$customerId}";
                        }else{
                            $coupon_usage = $coupon_usage-1;
                            $query = "UPDATE {$tableName} SET times_used={$coupon_usage} WHERE coupon_id={$coupon_id} AND customer_id={$customerId}";
                        }
                        $writeConnection->query($query);

                        // Update or Delete record in salesrule_customer Table
                        $tableName = 'salesrule_customer';
                        $query = "SELECT * FROM {$tableName} WHERE rule_id={$rule_id} AND customer_id={$customerId}";
                        $coupon_usage = $readConnection->fetchAll($query);
                        $coupon_usage = $coupon_usage[0]['times_used'];
                        if($coupon_usage==1){
                            $query = "DELETE FROM {$tableName} WHERE rule_id={$rule_id} AND customer_id={$customerId}";
                        }else{
                            $coupon_usage = $coupon_usage-1;
                            $query = "UPDATE {$tableName} SET times_used={$coupon_usage} WHERE rule_id={$rule_id} AND customer_id={$customerId}";
                        }
                        $writeConnection->query($query);
                    }
                }
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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