What's the best way to create orders and line items programmatically? I've looked for some API functions to call to accomplish this, but haven't seen any. Perhaps it's just a matter of creating the proper database entities using the database API? Or is ther a more appropriate way? I intend to do this through the Services module, so there won't be any UI involved.

I will likely also want to add service calls to define products in this way later on, in case this is something to factor in.

-JM

Comments

TheWizz’s picture

Hmm, answering my own question here, I guess. I now found the commerce_order_new and commerce_line_item_new functions, which I seem to have missed for some reason earlier. Presumably those would do what I want... After some spelunking, I also found the method to add fields to Orders. At first, I expected to find it under "Content types", but eventually found it under Store Configuration, Order Settings, Manage Fields. Somewhat confusing at first, but I guess there's a good reason for keeping this "content type" off to the side in the Store menu.

-JM

pcambra’s picture

Version: 7.x-1.0-beta2 » 7.x-1.x-dev

You should take a look to the tests (commerce_base.test) creates orders and products for testing purposes.

redben’s picture

Status: Active » Closed (fixed)

Or the commerce_cart_product_add() on commerce cart module
http://drupalcode.org/project/commerce.git/blob/HEAD:/modules/cart/comme...

TheWizz’s picture

Thanks for your suggestions. I got things partially working. I first create the order using

	$order = commerce_order_new($user->uid, 'complete');

The goal of all this is to consolidate orders collected through another system, hence I set the order to already be "complete" to begin with. BTW, should that be "complete" or "completed"? I'm somwhat confused by the wording used in the array returned by commerce_order_commerce_order_state_info(), which I assume is what defines the valid states.

I then move on to creating the line items, as follows:

		$line_item = entity_create('commerce_line_item', array(
		    'type' => 'product',
		    'line_item_label' => $name,
		    'quantity' => $qty,
		));

I need to create line items based on what's received from the other system, hence I'm not creating them based on commerce product entities, but need to provide all details verbatim. I set the name and quantity as shown above, then do the following to add the price to the line item:

		// Wrap the line item and product to easily set field information.
		$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);

		// Set the unit price on the line item object.
		$basePrice = commerce_price_field_data_auto_creation();
		$basePrice['amount'] = $amount;
  		$line_item_wrapper->commerce_unit_price = $basePrice;

		// Save the line item now so we get its ID.
    	    	$line_item = commerce_line_item_save($line_item);
    	
    	    	// Add it to the order's line item reference value.
		$order_wrapper->commerce_line_items[] = $line_item;

Finally I save the complete order using commerce_order_save($order). This basically seems to work. However, when subsequently viewing the order in Commerce, each line item's name is enclosed in parenthesis, and there's no total calculated. I suspect there's some action involved in calculating totals which doesn't happen due to the way I add the line items. Please let me know if there's a better way to accomplish the above, which also performs the Total calculations, and other details that I may be overlooking. For instance, calling commerce_price_field_data_auto_creation() directly feels wrong. I'm sure there's a more "kosher" method for creating a price field that I'm supposed to use here, but I'm quite new to Drupal and haven't fully understood all the new "fields" stuff yet. Any pointers are most welcome!

-JM

TheWizz’s picture

Status: Closed (fixed) » Active
redben’s picture

First, if you don't use commerce product for the imported orders you should not be using line items of type product, since these need to reference product on the database. So you might need to create a line item type that does not reference a "commerce product".
For the price calculation, i have no clue !

TheWizz’s picture

Thanks, redben. Do I need to somehow declare another type of line item, or can I just give it a different name in the 'type' => 'product' entry? Any name? And I think I've figured out why the price calculation doesnät work. I have only the line item's total price specified – I think I need to fill it with its constituent "price components" as well (base price, VAT, etc), which serve as the basis of the order total price calculation, as far as I can tell.

pcambra’s picture

Some notes:

  • About the complete/completed thing, see #1080764: Rules do not update order state
  • You've got also commerce_line_item_new for creating line items as the same as orders.
  • See also commerce_cart_order_refresh() for reference.
TheWizz’s picture

Thanks, pcambra and redben. I've made some progress, and seem to have most things working now, except for the price components. I need to build these from scratch for the line item (since it's not directly based on a commerce product). I've been struggling here for a couple of days. It's a rather complex multi-level structure. What's the best way for adding this info to the line item, given a known base price amount and tax amount?

-JM

PS: Also, any thought on my question #7 above?

redben’s picture

If the question you refer to is how to create line item types, I suggest you have a look at product_reference module and see how it defines product line item type.

TheWizz’s picture

Status: Active » Fixed

Thanks for the hint, redben. I believe I managed to add a line item type of my own. I also eventually got the, somewhat complex, price component stuff working, including the various kinds of VAT we have to deal with here.

-JM

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

tahiticlic’s picture

@TheWizz : can you provide your module code please? I've to do the same thing and just looking at product_reference module I don't succeed... Thanks!

TheWizz’s picture

Here's my code. It essentially imports orders with line items from another system. The trickiest part was getting the elaborate price structure, with its various components, to work. Perhaps there's a more elegant way, or an API function, that can perform this, rather than hard-coding the logic down to a fairly low level? If anyone knows a better way, please let me know.

-JM


	$line_item = commerce_line_item_new('myLineItemType', $order->order_id);

	$line_item->quantity = $orderItem['quantity'];
	$line_item->line_item_label = $name;

	// Wrap the line item and product to easily set field information.
	$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);

	$line_item_wrapper->commerce_total->amount = 0;	// Just establish field

	$price = $orderItem['price'] / 100;	// Qty 1 price inc VAT
	$vatRatio = $orderItem['tax'];
	$vatAmount = $price * (1 - (1 / (1 + $vatRatio)));
	$line_item_wrapper->commerce_unit_price->amount = $price;
	$currCode = $order->commerce_order_total[LANGUAGE_NONE][0]['currency_code'];

	$line_item_wrapper->commerce_unit_price->data = commerce_price_component_add(
		$line_item_wrapper->commerce_unit_price->value(),
		'base_price',
		array(
			'amount' => $price - $vatAmount,
			'currency_code' => $currCode,
			'data' => array(),
		),
		TRUE
	);

	// Determine price component name matching tax rate
	$rateCompName = "vat";	// Default name, of not found below
	$rates = commerce_tax_rates();
	foreach ($rates as $rate) {
		if ($vatRatio == $rate['rate']) {
			$rateCompName = $rate['price_component'];
			break;
		}
	}

	$line_item_wrapper->commerce_unit_price->data = commerce_price_component_add(
		$line_item_wrapper->commerce_unit_price->value(),
		$rateCompName,
		array(
			'amount' => $vatAmount,
			'currency_code' => $currCode,
			'data' => array(),
		),
	  TRUE
	);

	// Save the line item now so we get its ID.
	$line_item = commerce_line_item_save($line_item);

	// Add it to the order's line item reference value.
	$order_wrapper->commerce_line_items[] = $line_item;
tahiticlic’s picture

Thanks, I've done quite the same.

hoZt’s picture

I have been working with the code in #14 and still can not get it to create my items to come in correctly. None of my field tables like field_data_commerce_line are getting populated so when I view the order it is blank. @TheWizz do you think that you can post the remaining couple of lines before and after this to make your example work?

I have looked hard and can not find any example how to do this. commerce_base.test looks like it creates a cart and uses that for the order. I need to be able to modify the price as you are doing.

It would be good if this could be made a recipe as I am sure others are going to want to do something similar.

Thanks!

TheWizz’s picture

Perhaps you're not declaring your line item type (i.e., "myLineItemType" in the snippet above)?

hoZt’s picture

I did have the correct line type (product) in my case, but still could not get it to work.

With the new RC1 release the cart object has changed so you can now modify the price. Here is a simple example that is working. I just needed to have control of the price when adding items to an order so my case is not as complicated as your VAT example. I am open to suggestions on how to do this better.

// These are my test values.  
$product_id = "22015";
$quantity = 2;
$uid = 1;
$price = 5.50;

// Create a new shopping cart order by adding the products to it.
// This will be a loop adding all the products on the order.
if ($product = commerce_product_load($product_id)) {
  // Now change the price
  $product->commerce_price[LANGUAGE_NONE][0]['amount'] = strval($price * 100);
  $product->field_cost[LANGUAGE_NONE][0]['amount'] = strval($price * 100);
  $line_item = commerce_product_line_item_new($product, $quantity);
  $line_item = commerce_cart_product_add($uid, $line_item);
}

$order = commerce_cart_order_load($uid);
$order = commerce_order_status_update($order, "completed", TRUE);
commerce_order_save($order);
aneek’s picture

Hello hoZt,

I followed this code snippet and started to work on a custom Module that extends the APIs of DC. Now, the problem I am facing is I have a product of price $10.
I am modifying its price as you mentioned

function commerce_canvas_cart_form_submit($form, &$form_state) {
	global $user;
	/**
	 * Only a basic product is added to cart. Just to test
	 * @todo
	 * The product id will be sent via the commerce product form
	 * May change how this section behaves. May Implement the jQuery
	 */
	$product_id = 1;
	
	$quantity = 2;
	$uid = $user->uid;
	$price =100;
	
	$product = commerce_product_load($product_id);
	$product->commerce_price[LANGUAGE_NONE][0]['amount'] = strval($price * 100);
	$product->field_cost[LANGUAGE_NONE][0]['amount'] = strval($price * 100);
	$line_item = commerce_product_line_item_new($product, $quantity);
	$line_item = commerce_cart_product_add($uid, $line_item);
	$order = commerce_cart_order_load($uid);
	commerce_order_save($order);
	
	
	//commerce_cart_product_add_by_id($product_id);
	//drupal_goto('cart');
}

Now in the cart I am getting the item added as $10. How can I change this one to $100 ? But it changes the quantity. Not the price.
Note that this is a custom module that uses hooks and APIs from DC.
Any help.?

kenorb’s picture

Title: Creating Order and Line Items programmatcally? » Creating Order and Line Items programmatically?
Issue summary: View changes
mogtofu33’s picture

I found this subject usefull, code by TheWizz is a good start, but commerce_line_item_save return a value, so to save an new line_item you need to simply save line item:

// Save the line item now so we get its ID.
commerce_line_item_save($line_item);

And you need to set a corresponding line item type from admin/commerce/config/line-items (product, fee, order_discount if module enabled...)

raul_drupal_dev’s picture

Well I think this way is pretty cool! ^^

  commerce_line_item_save($line_item);
  
  $taxRates = commerce_tax_rates();
  
  if (isset($taxRates["iva_espanyol"])) { //in this case I use "iva_español" becouse is my tax name. Make sure to change to your own tax rate!
    commerce_tax_rate_apply($taxRates["iva_espanyol"], $line_item);
    commerce_line_item_save($line_item);
  }

reference

sumit-k’s picture

Thanks , #22 worked for apply tax on newly created line item.