Creating Magento Orders Programmatically

Sometimes you just want to have the ability to create orders on the fly that get entered into Magento’s backend like any other normal order would if going through the normal checkout process.

In our scenario lets say we have a need to have products purchased with either real world currency, or a fictional site point based  currency (could be rewards, game points etc etc.) for virtual products or what ever. Lets also assume that we are going to be wanting to create this order for a product via XHR (aka: Ajax) and we have the product id we wish to be ordered at hand.. lets begin:

	require_once 'app/Mage.php';
	Mage::getSingleton('core/session', array('name' => 'frontend'));
	$_customer = Mage::getSingleton('customer/session')->getCustomer();
	if(!$_customer->isLoggedIn()){ die(); } //If someone is hitting this file and is not a logged in customer, kill the script (security level 1). You can remove this if you want, but WTF!

	$product_id = $_POST['id']; //id of product we want to purchase that was posted to this script

	//Shipping / Billing information gather
	$firstName = $_customer_data->getFirstname(); //get customers first name
	$lastName = $_customer_data->getLastname(); //get customers last name
	$customerAddressId = Mage::getSingleton('customer/session')->getCustomer()->getDefaultBilling(); //get default billing address from session

	//if we have a default billing addreess, try gathering its values into variables we need
	if ($customerAddressId){ 
       	$address = Mage::getModel('customer/address')->load($customerAddressId);
		$street = $address->getStreet();
		$city = $address->getCity();
		$postcode = $address->getPostcode();
		$phoneNumber = $address->getTelephone();
		$countryId = $address->getCountryId();
		$regionId = $address->getRegionId();
	// otherwise, setup some custom entry values so we don't have a bunch of confusing un-descriptive orders in the backend
		$address = 'No address';
		$street = 'No street';
		$city = 'No City';
		$postcode = 'No post code';
		$phoneNumber = 'No phone';
		$countryId = 'No country';
		$regionId = 'No region';		

	//Start a new order quote and assign current customer to it.
	$quote = Mage::getModel('sales/quote')->setStoreId(Mage::app('default')->getStore('default')->getId());

	//Low lets setup a shipping / billing array of current customer's session
	$addressData = array(
		'firstname' => $firstName,
		'lastname' => $lastName,
		'street' => $street,
		'city' => $city,
		'telephone' => $phoneNumber,
		'country_id' => $countryId,
		'region_id' => $regionId
	//Add address array to both billing AND shipping address objects.	
	$billingAddress = $quote->getBillingAddress()->addData($addressData);
	$shippingAddress = $quote->getShippingAddress()->addData($addressData);

 	//Set shipping objects rates to true to then gather any accrued shipping method costs a product main contain

	//Set quote object's payment method to check / money order to allow progromatic entries of orders 
	//(kind of hard to programmatically guess and enter a customer's credit/debit cart so only money orders are allowed to be entered via api) 
	$quote->getPayment()->importData(array('method' => 'checkmo'));

	//Save collected totals to quote object

	//Feed quote object into sales model
	$service = Mage::getModel('sales/service_quote', $quote);

	//submit all orders to MAGE

	//Setup order object and gather newly entered order
	$order = $service->getOrder();

	//Now set newly entered order's status to complete so customers can enjoy their goods. 
        //(optional of course, but most would like their orders created this way to be set to complete automagicly)

	//Finally we save our order after setting it's status to complete.

That will accept a single product id, and then create the order for it and set the order’s status to complete, DONE! However, what if we want to only allow the above script to create orders for items already in a customers cart?! Simple, we must inlcude a new snip directly under the portion we assign our customer to our quote object, like so:

$quote = Mage::getModel('sales/quote')->setStoreId(Mage::app('default')->getStore('default')->getId()); //please don't re-add this, its to show you where in the above script you would include this below cart check
$quote->assignCustomer($_customer); //please don't re-add this, its to show you where in the above script you would include this below cart check

	--------------------------Item already in chart check-------------------------------
//Now we get all items in the cart to make sure the purchase is legit
$session = Mage::getSingleton('checkout/session');
$items = $session->getQuote()->getAllVisibleItems();
$foundProducts = 'false'; //extra helper to exit the script if failed

//Now we must loop over all the found items in the cart and scrub each one against our incoming product id
foreach ($items as $item) {//<- plural to singular , becareful
	$item_to_product = Mage::getModel('catalog/product')->loadByAttribute('name',$item->getName());
	if($item_to_product->getId() == $product_id){
		$foundProduct = 'true';

//If foundProducts is still false, we break from the rest of the script	
if($foundProduct == 'false'){ die(); }

Cool! But hey, what if now after checking to make sure they indeed have the item in the cart before this script will work, how about removing the items from the cart after the script has created the order? Glad you asked. Add this to the very end of the script, and you will have the ordered product not only entred into the backed, but also removed from your cart.

//We must remove the product from the customers cart now so they can't re-order the same product (unless we want that at some point).
$cartHelper = Mage::helper('checkout/cart');
$session = Mage::getSingleton('checkout/session');
$items = $session->getQuote()->getAllVisibleItems();
foreach ($items as $item) {
	$item_to_product = Mage::getModel('catalog/product')->loadByAttribute('name',$item->getName());
	if($item_to_product->getId() == $product_id){
		$itemId = $item->getItemId();

AWESOME! And that’s about it, you can make some modifications if you need to maybe just order all things in the cart, order multiple product id’s via XHR.
Over and out.

Code was lifted from and modified me accordingly.

Thanks to   for getting the topic started and Vinai for damn near perfecting it.

Devin R. Olsen

Devin R. Olsen

Located in Portland Oregon. I like to teach, share and dabble deep into the digital dark arts of web and game development.

More Posts

Follow Me:TwitterFacebookGoogle Plus

3 Responses to “Creating Magento Orders Programmatically”

  1. Devin R. Olsen Rakesh says:

    I need to use existed controllers and functions for adding new order from my android native app, can you please provide me a whole code that I need!

  2. Devin R. Olsen sebastian says:

    thanks for your code. I believe its an error in:

    $firstName = $_customer_data->getFirstname(); //get customers first name
    $lastName = $_customer_data->getLastname(); //get customers last name

    $_customer_data its not a declared variable, instead i believe its $_customer.

    additionally i have one doubt. in Branko´s code he use it as a model declaration but in your code you use it directly in the controller. why you choose that path?. (just to learn) thank you.

  3. Devin R. Olsen Keith says:

    We’re trying to feed our intake form into magento for our phone repair company. We’ve used the code here to get most of the way there. Thank you so much for posting this.

    We have no use for people to be logged in, we simply want to match up their email address to an existing customer and attach the order to them. We would then follow up and get more information about the job at that point.

    This all works except for one glitch, when we edit the order using extended orders in magento and go to resave the edited order always says the email address for the customer is already assigned and creates a new user with no billing info in the customer table.

    If we go in the backend and create a new order for a client that way the problem doesn’t exist when we edit it. So on some level something isn’t really being connected.

    Any chance you could lend your thoughts?

Leave a Reply