I am programatically doing an invoice refund, and I want to set the order status to closed after the refund has happened.

The refund works, but changing the order status doesn't.

I was kind of hoping that the refund code would set the status to Closed for me, but it doesn't, the status just stays at Processing after the refund.

Here's the refund code:

$service = Mage::getModel('sales/service_order', $order);
$creditmemo = $service->prepareInvoiceCreditmemo($invoice);

I have read that the Complete and Closed statuses shouldn't be set manually, but I do need the order status changed to closed.

Here's what I've tried, none worked for me.


$order->addStatusHistoryComment("Refunded.", Mage_Sales_Model_Order::STATE_CLOSED);


$order->setData('state', Mage_Sales_Model_Order::STATE_CLOSED);



2 Answers 2


Order status/state Closed/closed is a "protected" status/state, which cannot be changed, along with Complete/complete. This means when you use the method setState, it will not work.

This is because in order to have a Closed order, you must have a fully invoiced and shipped order fully refunded. It looks like in your case you don't have a full shipment. If you have a full shipment and still not getting to Closed, something was done wrong.

In any case, you have two options.

  1. Do a full shipment (dummy if necessary). Refund fully and you should get to Closed automatically.

  2. Go around the restriction by using setData('state', Mage_Sales_Model_Order::STATE_CLOSED) instead of setState.

  • Thanks a lot that's a great explanation. Could you explain how to do a dummy shipment though?
    – Mex
    Commented Mar 20, 2015 at 11:41
  • Not to worry about the dummy shipment, I have managed to solve the issue. (I've posted my answer).
    – Mex
    Commented Mar 20, 2015 at 13:21

I have managed to get the order status to closed after a refund, by doing 2 things.

  1. Calling $order->save(); after the refund code.

  2. Preventing the sales_order_invoice_save_after event from firing twice by adding this to the top of my event method:

    // prevent this event from firing twice
        return $this; // this method has already been executed once in this request
    Mage::register('sales_order_invoice_save_after_event_triggered', true);
  • Believe me I tried, it says I have to wait until tomorrow.
    – Mex
    Commented Mar 20, 2015 at 15:42
  • When you can, I meant :)
    – laketuna
    Commented Mar 20, 2015 at 22:01

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.