In the screenshot you can see my options.

Coupon configuration

I have created a coupon to have the free first shippings.

What i need is to have one unique code (Example: FREEFIRSTSHIPPING) that can be used only one time, but that every logged customers can use this same code one time.

The code works well, setting my Uses per Coupon value to 0, but i have noticed that i can use this code unlimited times, and this is wrong.

Is it a Magento 1.9 bug? Or am i doing something wrong?

PS: I have no coupons related extensions installed.

2 Answers 2


It's a known magento bug. Magento does not track coupons with empty discount (as in your case)

Correct settings are:

  • Use per coupon = 0 or empty,

  • Use per client = 1,

And modify the code in the Mage_SalesRule_Model_Observer (copy to local of course) from

    // use each rule (and apply to customer, if applicable)
    if ($order->getDiscountAmount() != 0) {

to, say

    if (true) {

Edit: You can just copy the file from

app\code\ **core** \Mage\SalesRule\Model\Observer.php 


app\code\ **local** \Mage\SalesRule\Model\Observer.php

and make all changes in the local version.

  • It works! Thanks! But i have only some problem to override this observer: i followed this guide (shepherdyuan.wordpress.com/2013/03/27/…) changing right data... but my override is not working, so i have edited the core file. I know it is a wrong thing to do :-( Can you help me with this override?
    – Simbus82
    Commented Aug 27, 2014 at 9:11
  • Have edited the answer
    – Amasty
    Commented Aug 27, 2014 at 11:48
  • Any idea on how to do the same thing in Magento 1.7? That observer does not have any check about the discount amount
    – Lorenzo S
    Commented May 18, 2015 at 10:52

I came across this today and was able to solve it thanks to @Amaty's comment.

Here are some more details:

The core module Mage_SalesRule registers a global observer to run after each sales order is placed.

This observer increments the times_used counter on coupon codes, this is used for enforcing limits.

The code to increment times_used is inside the following if statement:

if ($order->getDiscountAmount() != 0) {
    // snip

This means that if the order discount_amount is 0 no processing happens.

Source: https://github.com/OpenMage/magento-mirror/blob/magento-1.9/app/code/core/Mage/SalesRule/Model/Observer.php#L72-L133

Free Shipping coupons

Typically a Sales Rule set up to allow free shipping with no other discount will be set up as below:

enter image description here

One or many coupons are then created, a typical use case is multiple coupons valid for a single use per coupon.

Because of the logic around incrementing times_used when these coupons are used, if no other discounts apply, then the coupon will not be marked as used.

The Coupon Codes will however provide the correct "Free Shipping discount" and continue to work for later transactions. This means the merchant is discounting more than they intended with the free shipping coupon.

A Fix

I elected not to overwrite the existing core module's observer but rather create a new global observer of my own and use identical logic except for the following:

if ($order->getDiscountAmount() == 0) {
    // snip

This means the core observer will run and process all coupon_codes for orders with a DiscountAmount. The observer that I've put together will run for all others - this is so I can leave core untouched without double counting coupon usage.

I have published this as a module here: https://github.com/etailer/Etailer_CouponUsed/

I also wrote a Magento shell script that iterates through all orders with no discount_amount and a coupon_code present. It then increments their times_used. This is optional but I found it very useful to quickly void all the used coupons. It can also be extracted and used standalone if you've fixed the core issue some other way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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