Programmatically Creating and Submitting Orders in Drupal

This post was written in 2010 for an old version of Drupal and is now outdated. For newer versions please take note of marinex’s comment.

Working for a new client the offers a product through a Drupal-driven webpage, I just finished developing a Drupal module that displays a form to let any user effortlessly download the trial product (Ubercart). The module had to capture basic user information, perform validations, create the order and a new user account, link them together, purchase the order using the free payment method, and redirect the user to his Purchased Files page – where he would now have all links associated with the given free trial product.

I searched a lot but didn’t find much information on how to do all that. I didn’t want to forge forms and call drupal_exec() – there had to be a cleaner way. Plus, I was just starting to learn my way around Drupal, so a little bit of digging helped me give bigger strides in my knowledge of the system.

The following code is what I came up with, I hope this is useful to someone!

  global $user;

  $trial_id = variable_get('ls_free_trial_product', NULL);
  $error_msg = FALSE;
  if (!$trial_id)
    $error_msg = 'The free trial product is not yet configured. Please contact an administrator.';

  $node = node_load($trial_id);
  $product = uc_product_load($node);
  if (!$product)
    $error_msg = 'There was an error finding the free trial product. Please contact an administrator.';
  $product->nid = $node->nid; //we need to do this in order for the file downloads to work
  $product->qty = 1;
  $product->title = $node->title;

  // Create the order and gather user information
  $order = uc_order_new($user->uid, 'completed');
  $order_id = $order->order_id;
  if (!$user->uid) {
    $names = split(' ', $form_state['values']['full_name']);
    $last_name = array_pop($names);
    $first_names = join(' ', $names);
    $email = $form_state['values']['email'];
    $company = $form_state['values']['company'];
  } else {
    $aid = _uc_addresses_get_default_address_id($user->uid);
    $address = _uc_addresses_db_get_address($user->uid, $aid);
    $first_names = $address->first_name;
    $last_name = $address->last_name;
    $email = $user->mail;
    $company = $address->company;
  }
  // Populate the order
  $order->products[] = $product;
  $order->payment_method = 'free_order';
  if (!isset($order->primary_email))
    $order->primary_email = $email;
  $order->billing_first_name = $first_names;
  $order->billing_last_name = $last_name;
  $order->billing_company = $company;
  if (!$user->uid)
    $order->data['new_user']['pass'] = $form_state['values']['password'];

  // Complete the sale
  uc_order_save($order);
  uc_cart_complete_sale($order, TRUE);

  // Submit the payment
  uc_payment_enter($order->order_id, 'free_order', 0, 0, NULL, t('Checkout completed for a free order.'));

  $order = uc_order_load($order_id);
  if ($order->order_status == 'payment_received') {
    $url = url('user/me/purchased-files');
    drupal_set_message(t("Your free purchase has been processed. Go to <a href="$url">My Downloads</a> to find the link to your product."));
    drupal_goto('user/me/purchased-files');
  }

Source and Download

You can see the whole source-code, fork it or download the zipped pluging at my public Github repository.

If this post was useful to you, please leave a comment and share it!

8 Comments Programmatically Creating and Submitting Orders in Drupal

  1. timani

    Good write actually. Its actually important to note line 46.
    uc_cart_complete_sale($order, TRUE);

    I see a lot of people ending at just uc_order_save($order) but the sale isnt actually complete, and stock is not adjusted without the uc_cart_complete_sale($order, TRUE) which is important if you have to keep track of an inventory.

    Reply
  2. psheiman

    Hi, what if I want this order to be processed by uc_recurring? Right now, if order is created programmatically, recurring fees isn’t added to order, bit if I “buy” prodcut using frontend, it is. Please advice.

    Reply
    1. gabrielsomoza

      Hi. Which version of Drupal are you using? This post was written for an older version (I may need to update it to reflect that). Best way to work around anything missing in the process is to take a look at the code that gets executed when you “buy” a product in the frontend. You should find the uc_recurring is used there (or an equivalent) and porting it to your script should be no problem. I can’t dig into this myself right now due to time limitations (sorry).

      Reply
  3. marinex

    Hi I looked at uc_payment_enter() in the documentation and this function call the uc_cart_complete_sale($order); so I think the uc_cart_complete_sale() is duplicate in your code.

    Reply
    1. gabrielsomoza

      Hi marinex – what version of Drupal are you using? Please note this post is 2 years old and is likely to be VERY outdated by now. I don’t even remember which version I wrote this for (should have mentioned it in the page).

      Reply

Leave a Reply