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.
32 comments
i have not work this type of error please help me or mail abdulkarimkhorajiya@gmail.com
2018-04-17T05:21:18+00:00 ERR (3): User Error: Some transactions have not been committed or rolled back in C:\xampp\htdocs\magentoone\lib\Varien\Db\Adapter\Pdo\Mysql.php on line 4039
This is working fine in Magento Ver: 1.9.3.3 but only New Order email sent to the customer when invoice and shipment mail not sent to the customer automatically.
If you have any solution for direct sent invoice email and shipment email then please share here.
This is support in Magento Ver 1.9.3.3?
Nice. It’s still working in Magento 1.9.3.8. Thanks for sharing! 😀
Please share your some code here if possible.
Because for me 1.9.3.3 version not working right now that is why.
I tried a simplier solution by using a free extension: Auto Invoice https://www.magentocommerce.com/magento-connect/catalog/product/view/id/30599/s/auto-invoice-extension-1/ to get invoice automatically created and sent through email to customers right after purchasing process is finished.
Still find no bug with this one. It’s much easier for me without having to make any changes in code.
Thanks a lot for sharing the free and useful extension. I installed the extension and it worked well. But I have updated my website to Magento 2.1, so i am looking for an extension with the same function. I wonder if this one is suitable http://bsscommerce.com/magento-2-auto-invoice.html please give me an advice
I’m using a similar script.
Upgrading Magento from 1.7.0.2 to 1.9 a get a slow execution.
Before upgrading the script processed about 3 order per second, after the upgrade the script takes about 2/3seconds per order… so 6 times slower.
The slow line is
In particular the save() method takes 2 seconds.
I check for slow query in DB but no query is tracked.
Could you give me a suggestion to solve this isssue?
My script must process about 600 order and times are too longer.
Please help me
Thanks
Hello,
I tried it, but it doesn’t work.
First test i did it removed the invoice button and after that the shipment was not created also the invoice was not.
After the first test it doesn’t even do that.
I created the files in app/code/local/inchoo_invoicer
2 files observer.php and config.xml
How can i make it work?
Thanks in advance.
Btw i have magento 1.9.2
thank you for your code.
but it seems have a bug when use paypal express payment, because the state is “process” when place a new order by paypal express payment. so it will lead to the if statement if ($order->getState() == Mage_Sales_Model_Order::STATE_NEW) is become to invalid.
have some way to fix the bug?
thanks!
Is it possible create a “order shipped” status and use it through an automatic way on orders that already were shipped by the carrier (according to the tracking info) in Magento? This status is a “must have” status, and Magento does not have it by default. It’s very important to keep the orders updated for the sales team and would allow us to check with the carrier company if something wrong happened with the shipping, like because some thunderstorm, traffic, whatever… Most large ecommerce business has a “Order Shipped” status, it’s essential for sales management.
have any way to auto create shipment by status instead of state?
how to send invoice email to the customer ??? kindly reply
This was helpful. I am using mage CE 1.9
http://www.brainre.org/magento-automatically-send-invoice-email-after-invoice-is-created/
@rayan link you share is now 404 page.
can you please share same thing code or another link.
How to send email with invoice to customer and shop admin?
Great Post!
I use magento 1.5.1
I am trying to set the order status to “Complete” and do not want to notify the customer when the order is set to complete.
I used setState(‘complete’,true,”,false) method. The order status changed to “Complete”
But, in magento admin back-end, under “comment history”, I see the below text
Aug 20, 2013 9:05:54 AM | Complete | Customer Notified.
Since I used false (4th parameter in setState method), it is supposed to say “Customer not notified” right?
Any thoughts please?
Thanks
How to send email with invoice to customer and shop admin?
mmmh, thank you, but….how can i use this code? A noob explanation?
thanks a lot…
By(t)e
Thanks for the post, Branko
Recently I’ve used this for auto-shipping and faced an issue that order wasn’t changing to ‘Complete’ status, this is due to in second transaction order doesn’t have data changed, to force save it I had to do $shipment->getOrder()->setHasDataChanges(true)
Thanks,
for this great post…….. 🙂
$order->getState() is coming blank. Please help??
Great post BTW, it was really helpful!
I notice that it seems to be running through the function twice though, do you know why it would be doing this?
Just wanted to point out something missing from main post but that gregc corrected.
If you are wanting to filter by payment option you need to make sure there are double brackets after the getMethod
eg
if ($order->getPayment()->getMethod() == ‘checkmo’)
These are missing in the original post
Very helpful. Thanks for the tip Matthew! 🙂
Hi,
We have master/slave setup. It is working fine in UAT server. But the same is not working in LIVE. We are getting “Can not create invoice. Order is not found”.
Once i remove the master slave set up from local xml it is working fine.
So its like a bottle neck.
Its giving singleton/module/observer already exist error?? need help on that
Great tip!
Easily customized to auto-invoice Check/Money Order payments by changing the if statement in the observer code to
if (($order->getState() == Mage_Sales_Model_Order::STATE_NEW) &&
($order->getPayment()->getMethod() == ‘checkmo’)) {
It’s great to see simple, working examples of code.
Hi, I tried to build this module, but I get this error:
Mage registry key “_singleton / inchoo_invoicer_model / observer” already exists
click on the ‘Place Order’ and pay with PayPal, I think it does well with other methods of payment
We’re doing something similar but with EDI, how do you guys catch non-invoicable errors? We have this relatively ambiguous block of code,
if (!$order->canInvoice()) {
$this->_fault(‘data_invalid’, Mage::helper(‘sales’)->__(‘Cannot do invoice for order.’));
}
That really doesn’t tell you why it can invoice.
Thanks, nice code, exactly what I was looking for!
First of all, thanks a lot for such a wonderful article with the code details. Appreciate!
I have mainly 2 queries, which I’m writing it down. Please comment in details, if possible.
In the Observer class, what is the purpose of line – 50, and what will happen if I don’t provide this line:-
Also why is this only mentioned for the Shipment handle like this
and not something like
(just like the Invoice handle of line – 36)?
Thanks & Regards,
Anutosh