How to split Drupal Commerce orders at checkout

This week I needed to design a checkout workflow that, depending on the contents of a users shopping cart, would separate the current cart into two, and allow the user to check each out individually. Drupal Commerce comes with cart and checkout modules, to enable users to add products to a shopping cart, and then to checkout of your store. The commerce_cart module is really designed for a 1:1 user:cart ratio. That being said, it is possible to allow users to have more than one cart.

Commerce cart orders are standard orders with an order status that is recognized by the commerce_cart module as indicating that an order is in the shopping cart. All checkout pages provide an order status that is a cart status. For example the 'checkout', and 'review' checkout pages correspond to the checkout_checkout and checkout_review order statuses, which are recognized by commerce_cart as being cart orders. When selecting which order should be presented as the current shopping cart, commerce_cart looks for the first order, with a cart status, the greatest order_id. This is what is returned by commerce_cart_order_load().

In order to provide the required functionality I first provided a new checkout page and checkout pane, using hook_commerce_checkout_page_info() and hook_commerce_checkout_pane_info(). I placed the pane on the page and made the page the first in the commerce checkout workflow. I created a rule, using the Rules module, that would detect which types of items are in the cart, and depending on the business logic I was provided, would decide whether or not to show or hide the pane, and therefore the page as well. The rules were custom coded using some condition and action handlers that I created specifically for this project.

The checkout pane contains a simple form that allows the user to select which part of their order to checkout first. In the submit handler for the pane the line items that correspond with the order to be checked out first are removed from the current order, and added to a new cart order, created with comerce_cart_order_new(). Each order is then saved with the 'cart' status using commerce_order_status_update(), this is to make sure that some custom discount recalculation rules will fire for each order.

Finally I set the status of the new order to the original status of the current order (to reflect the current checkout page, and assign the new order object to $form_state['order'], this is so that the form will successfully redirect to the correct next checkout page for the new order. Once the customer completes the first order they are prompted, with an additional checkout pane on the 'complete' page of the checkout workflow, to begin the checkout process again with their remaining shopping cart.

I'm pretty happy with the current workflow and code, and am considering ways that it could be generalized and contributed back to the community.

Comments

Hey Everett, thanks for sharing your approach to a split order! This topic comes up about once a month, so I'm glad we have an article (and maybe some code : ) to point people to. Your DC posts have been great.

Hi there,

Nice write-up, I hope you enjoy Drupal Commerce :)

The commerce_cart module is really designed for a 1:1 user:cart ratio. That being said, it is possible to allow users to have more than one cart.

This is not actually true. Commerce is multi-cart from the start:

  • The Cart module allow each user to have multiple cart, but by default only shows one active cart at a time. The active cart is determined by the logic you mention (greatest order_id) that can be overridden by the hook_commerce_cart_order_id().
  • The Checkout module is also multi-cart from the start. The order ID is passed into every URLs, so each user can perform multiple stateful checkouts in parallel.

The only thing that is not really multi-cart friendly (yet) is the add to cart form. But the only thing you have to do to make it friendly is to override the submit function.

Once you have the products nicely separated into multiple carts (for example because you are working on a site that supports multiple vendors), the only thing you need to do is to display a page to the user with all his/her carts, and allowing it to checkout each. At the end of each checkout, redirect the user to this same page, to allow him/her to checkout the next one. This should be doable using Views alone.

Damien Tournoud

Hi Damien,

You are right, it is pretty easy to customize the cart / checkout process to support multiple carts per user / session. but that takes some custom development (not just Rules or UI settings. That being said, anyone implementing Drupal Commerce for anything more than a pretty standard checkout workflow is going to likely need to dig into these things anyway.

I've definitely enjoyed working with the Drupal Commerce API the past couple of weeks, and hope that more Commerce work comes my way so that I can explore it further.

Add new comment

Filtered HTML

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <h2> <h3> <h4> <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • To post pieces of code, surround them with <code>...</code> tags. For PHP code, you can use <?php ... ?>, which will also colour it based on syntax.

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.