atwix

Magento auto invoice and set custom order status upon checkout

Many developers are wondering how to customize Magento behavior once an order has been placed. In particular, sometimes a company would like to change the order status to “Pending” and send an invoice to the customer automatically after checkout. The following article offers a simple solution for this.Let’s assume that we need to have the order status set to “Processing” instead of “Pending” for orders paid with the “Credit Card Save” payment method and have the standard invoice sent automatically at the same time.

A custom Magento module will be required for this task. Let’s name it Atwix_Orderhook.
Step 1

First, create a module initializer in /app/etc/modules/Atwix_Orderhook.xml with the following content:

<?xml version="1.0"?>
<config>
    <modules>
        <Atwix_Orderhook>
            <active>true</active>
            <codePool>community</codePool>
        </Atwix_Orderhook>
    </modules>
</config>

Step 2

Create a module configuration file config.xml in /app/code/community/NAMESPACE/MODULENAME/etc/
(replace NAMESPACE and MODULENAME with your own values). In our case the path will be /app/code/community/Atwix/Orderhook/etc/.

config.xml content:

<?xml version="1.0"?>
<config>
    <modules>
        <Atwix_Orderhook>
            <version>1.0</version>
        </Atwix_Orderhook>
    </modules>

    <global>

        <models>            
            <orderhook>
                <class>Atwix_Orderhook_Model</class>
            </orderhook>
        </models>

        <events>
            <sales_order_place_after>
                <observers>
                    <auto_invoice_order>
                        <type>singleton</type>
                        <class>orderhook/observer</class>
                        <method>implementOrderStatus</method>
                    </auto_invoice_order>
                </observers>
            </sales_order_place_after>
        </events>

    </global>
</config>

As you can see, we have described observer in the events section. Observers allow you to execute some operations after a desired event took place. We need to observe the sales_order_place_after event in our extension. This event takes place after an order has been placed. Also, do not forget to init your Model path in the models section, like the example above.
<class> … </class> section contains a path to the file with observer class. In our case the file is app/code/community/Atwix/Orderhook/Observer.php, which we will create later.
Section <method> … </method> contains the method’s name, which will be called on in the sales_order_place_after event.

Step 3

Create observer file app/code/community/Atwix/Orderhook/Model/Observer.php with the following content:

<?php

class Atwix_Orderhook_Model_Observer 
{
    public function implementOrderStatus($event)
    {
        $order = $event->getOrder();

        if ($this->_getPaymentMethod($order) == 'ccsave') {
            if ($order->canInvoice())
                $this->_processOrderStatus($order);
        }
        return $this;
    }

    private function _getPaymentMethod($order)
    {
        return $order->getPayment()->getMethodInstance()->getCode();
    }

    private function _processOrderStatus($order)
    {
        $invoice = $order->prepareInvoice();

        $invoice->register();
        Mage::getModel('core/resource_transaction')
           ->addObject($invoice)
           ->addObject($invoice->getOrder())
           ->save();

        $invoice->sendEmail(true, '');
        $this->_changeOrderStatus($order);
        return true;
    }

    private function _changeOrderStatus($order)
    {
        $statusMessage = '';
        $order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true);        
	$order->save();
    }
}

implementOrderStatus($event) {…} function will be called upon completion of the order’s placement. As you can see, there are some conditions inside that are responsible for the payment method name verification. As we have described above – order status will be changed only if “Credit Card Save” payment method has been used with the order. If you don’t need these conditions – just remove the verification.
_processOrderStatus Method creates an invoice for the order and sends it to the customer.
_changeOrderStatus Method changes the order status to STATE_PROCESSING.

That’s it. You can easily write your own handlers with any functionality from this observer. For example, you can send an additional email or shut down the server after an order has been placed :)

P.S. Here is a list of the order statuses that you can apply to the order object:

/**
 * change order status to 'Completed'
 */
$order->setState(Mage_Sales_Model_Order::STATE_COMPLETE, true)->save();
Similarly, you can change the order status to pending, processing, canceled, closed, held, etc.

/**
 * change order status to "Pending"
 */
$order->setState(Mage_Sales_Model_Order::STATE_NEW, true)->save();
 
/**
 * change order status to "Pending Paypal"
 */
$order->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT, true)->save();
 
/**
 * change order status to "Processing"
 */
$order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true)->save();
 
/**
 * change order status to "Completed"
 */
$order->setState(Mage_Sales_Model_Order::STATE_COMPLETE, true)->save();
 
/**
 * change order status to "Closed"
 */
$order->setState(Mage_Sales_Model_Order::STATE_CLOSED, true)->save();
 
/**
 * change order status to "Canceled"
 */
$order->setState(Mage_Sales_Model_Order::STATE_CANCELED, true)->save();
 
/**
 * change order status to "Held"
 */
$order->setState(Mage_Sales_Model_Order::STATE_HOLDED, true)->save();



Enjoyed this post? us on Facebook and on Twitter to stay tuned.

  • Pingback: Make emails for custom events | Atwix

  • Larry Sainte-Marie

    Thanks. this was helpful – however some edits need to be made to make it work.

    in the observer.php – change the class to Atwix_Orderhook_Model_Observer
    in the config.xml – change orderhook/observer to Atwix_Orderhook_Model_Observer

    I think if you rolled this up as a free or commercial extension it would be very helpful, since it is fairly easy to figure out how to change states and statuses.

    thanks again

    • Enarc

      Thanks for your hint, Larry. Class name was wrong. As for config file: you can use ‘classname’ or ‘path’ syntax in magento xml structures.
      It can be
      orderhook/observer = [module_directory_name]/[filename_in_models_directory]
      or
      Atwix_Orderhook_Model_Observer = [classname]

      • Darkpagan

        Unfortunately when I place this on to STATE_COMPLETE I get an error stating”
        The Order State “complete” must not be set manually”. Any ideas as in how to get around this… Basically I am wanting the orders to be set immediately to complete within Magento

  • Minh Nghi Trần Phan

    This article is the solution for the problem I got. I followed exactly these instructions above, but I couldn’t get it work. Here’re what I did:

    - Created: /app/etc/modules/Atwix_Orderhook.xml
    - Created: /app/code/community/Atwix/Orderhook/etc/config.xml
    - Created: app/code/community/Atwix/Orderhook/Model/Observer.php

    Is there any step that I missed? My Magento version is 1.6.0.0. Please help me. Thanks

    • Enarc

      Hello Minh Nghi Trần Phan.
      First of all you should clean your cache. Go to Admin->System->Cache Management and push “Flush Magento Cache”.
      Then go to the Admin->System->Configuration->Advanced.
      You should see your module in the listing.

      • Minh Nghi Trần Phan

        Hi Enarc,
        Thanks for your quick reply, I cleaned the cache and saw the Atwix_orderhook module listing in the backend, but every new order I created still set to “Pending” and no invoice was created. :(

        • Enarc

          Also, as was noticed before, in our example auto status works only with Credit Card (Saved) method.
          If you want to apply auto status to all payment methods your function will be like this:

          public function implementOrderStatus($event)
          {
          $order = $event->getOrder();
          if ($order->canInvoice())
          $this->_processOrderStatus($order);

          return $this;
          }

  • Andrew

    Followed all the steps – and have now checked them again. All that happens is that the checkout page refreshes and takes me back through the shopping cart process again in a loop that I can’t get past.

  • sam

    been trying this for two days now but cant get it to work

  • vasa

    how can save the order in the custom payment.
    Is this correct?Order is not stored and i used the code in my response function.

    $order = Mage::getModel(‘sales/order’);
    $order_id = Mage::getSingleton(‘checkout/session’)->getLastRealOrderId();
    $order->loadByIncrementId($order_id);
    $order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true, ‘Gateway has authorized the

    payment.’);
    $order->sendNewOrderEmail();
    $order->setEmailSent(true);
    :( please give me solun

    Thnx
    vasa