Automatically invoice/ship/complete order in Magento

Various merchants, various demands. Imagine you have a private on site sale or something like that, where your checkout requirements are pretty simply: create invoice / ship and complete the order all at once. For example, you are doing the checkout for bunch of people standing in front of you, paying you money right on the spot. In such scenario overload of manually creating an invoice and shipment can be too much.

Thus, having your Magento automatically invoice/ship/complete orders can be a logical request. So how do we do that?

Easy! All you need to do is to observe the sales_order_save_after event or observe the controller_action_predispatch event and target the Mage_Checkout_OnepageController::successAction() catching the Mage::getSingleton(‘checkout/session’)->getLastOrderId(). In this example I decided to demonstrate the possible (not ideal, or not even the best) “sales_order_save_after event” approach.

If we where to code everything in form of a module/extension, then all we need are two files. Here is the content of config.xml of our module:

<config>
<modules>
<Inchoo_Invoicer>
<version>1.0.0.0</version>
</Inchoo_Invoicer>
</modules>
<global>
<models>
<inchoo_invoicer>
<class>Inchoo_Invoicer_Model</class>
</inchoo_invoicer>
</models>
<events>
<sales_order_save_after>
<observers>
<inchoo_invoicer_automatically_complete_order>
<class>inchoo_invoicer/observer</class>
<method>automaticallyInvoiceShipCompleteOrder</method>
</inchoo_invoicer_automatically_complete_order>
</observers>
</sales_order_save_after>
</events>
</global>
</config>

And here is the code for our observer model.

class Inchoo_Invoicer_Model_Observer
{
/**
* Mage::dispatchEvent($this->_eventPrefix.'_save_after', $this->_getEventData());
* protected $_eventPrefix = 'sales_order';
* protected $_eventObject = 'order';
* event: sales_order_save_after
*/
public function automaticallyInvoiceShipCompleteOrder($observer)
{
$order = $observer->getEvent()->getOrder();
 
$orders = Mage::getModel('sales/order_invoice')->getCollection()
->addAttributeToFilter('order_id', array('eq'=>$order->getId()));
$orders->getSelect()->limit(1);
 
if ((int)$orders->count() !== 0) {
return $this;
}
 
if ($order->getState() == Mage_Sales_Model_Order::STATE_NEW) {
 
try {
if(!$order->canInvoice()) {
$order->addStatusHistoryComment('Inchoo_Invoicer: Order cannot be invoiced.', false);
$order->save();
}
 
//START Handle Invoice
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice();
 
$invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_OFFLINE);
$invoice->register();
 
$invoice->getOrder()->setCustomerNoteNotify(false);
$invoice->getOrder()->setIsInProcess(true);
$order->addStatusHistoryComment('Automatically INVOICED by Inchoo_Invoicer.', false);
 
$transactionSave = Mage::getModel('core/resource_transaction')
->addObject($invoice)
->addObject($invoice->getOrder());
 
$transactionSave->save();
//END Handle Invoice
 
//START Handle Shipment
$shipment = $order->prepareShipment();
$shipment->register();
 
$order->setIsInProcess(true);
$order->addStatusHistoryComment('Automatically SHIPPED by Inchoo_Invoicer.', false);
 
$transactionSave = Mage::getModel('core/resource_transaction')
->addObject($shipment)
->addObject($shipment->getOrder())
->save();
//END Handle Shipment
} catch (Exception $e) {
$order->addStatusHistoryComment('Inchoo_Invoicer: Exception occurred during automaticallyInvoiceShipCompleteOrder action. Exception message: '.$e->getMessage(), false);
$order->save();
}
}
 
return $this;
}
}

Before I go any further, I must emphasize that there is a certain known buggy code within automaticallyInvoiceShipCompleteOrder method :). This is to keep the example simple. Meaning this code should be written with more detailed checks if it where to go on live site. As you can see, the first thing I’m doing above is looking into the sales/order_invoice collection to check if there are any existing invoices created for the particular order. If there are none, then I proceed with creating both invoice and shipment.

Next in line is the simple check for order state, IF “new” (which means created right now) then do the entire process of invoicing and shipment. This IF condition is a good place if you wish ti limit this code to orders created by specific Payment gateway, for example Check/Money which has the “checkmo” code, in which case all you need to do is call if ($order->getPayment()->getMethod == ‘checkmo’), etc. The above code was tested on Magento 1.6.2.0. If you plan using it on some live site, please test it thoroughly before and adjust it to your specific needs.

Cheers.