Order Object Workflow through Checkout

I was having this discussion in IRC with DamZ, neclimdul, and one other person about how to handle the creation, update, and saving of the order object through checkout. In Ubercart, the workflow was as follows:

  1. View the checkout page, nothing is there. Any code that needed an order object would construct it on the fly using the cart contents.
  2. Submit the checkout page and an order was created with the ID stuffed into the session. The order status was "In Checkout" and it had an order ID and would be used for displaying the review page or setting default values on the checkout form if the customer went back.
  3. Complete the sale and the order status would get updated at least to Pending and maybe further depending on Conditional Actions.

The method it sounded like neclimdul implemented for e-Commerce 3.x and DamZ had implemented through a modified UC Advanced Checkout module was to create a cached order object at the beginning of checkout. It would have as many default values as possible, including a default address from the address book. As the customer went through checkout, it would be filled in, until upon checkout completion it would be saved. This served the advantage of not messing up the sequence of order IDs with data from people who bail on the checkout process. However, I pointed out the advantage of keeping the data around for the purposes of following up with potential customers to make sales.

As we discussed, this can be easily implemented as a contributed module working through the process neclimdul / DamZ were describing. I think it best to go this route and am interested in feedback. I'll be porting the Advanced Checkout module as a starting point for the Drupal Commerce checkout system, as it already tackles the definition of checkout panes and placement of panes onto checkout pages (single or multiple) with an optional review step.

  1. The shopping cart object extends the order object and supplies default values on load for the products in the cart. This happens on the fly at pageload, though I suppose we can even cache this cart object in the session or at least for logged in users.
  2. When the user comes into checkout, we instantiate an order that then is further filled out through the checkout process.
  3. Upon checkout completion, the order object is saved. If checkout is canceled or the cached order object is deleted, provide a hook for modules to capture the data for later use.

This is obviously very rough and needs to be fleshed out further, so all feedback is welcome.

Ryan Szrama
Posted: Feb 7, 2010


neclimdul on February 9, 2010

I wonder about shopping cart extending the order as there may be properties/methods on order that really don't make sense for a cart object. It might make more sense as an interface. This is something to flesh out in the final implementation but just some possible gotcha's we should watch out for.

Damien Tournoud on February 9, 2010

I'm considering making the order permanent as soon as you add the first product to the cart. This would have several advantages:

* The order is completely available (including in the database), so each process can see a consistent state (for example, we can make rules act on that "order" before and during checkout)
* We can easily support one click scenarios and cart-less scenarios

The only disadvantage is that the sequence of order_ids will not be consistent. But (1) we can easily implement a "store order ID" in addition to the internal order_id that will be generated when the checkout completes (the same way we have a SKU and a product_id), (2) most store owners have very specific requirements for order IDs, and we need a custom logic to build that anyway.

redben on February 9, 2010

I brought this up on the thread about SKUs. I really see order_id and order_number as too different keys. The primary key is the technical key (order_id) and the business key, order_number (or store order id as you call it damien) would be a unique key . The latter is the only one the users see/know. It might be an extra column but i think it makes things clearer.
Just like products have product_id and sku

jpstrikesback (not verified) on February 10, 2010

Am I right to think Storing the order object in the DB right away is more scalable on a high traffic site?

Ryan Ryan Szrama on February 10, 2010

Not sure... all we've ever stored before was the cart products and we built the cart on the fly. If we store the cart products in the same table as the order products table, it's going to grow very quickly and could make things worse. I'm also not sure it will make other things faster, like auto-populating addresses and such... it will all still require additional database requests since addresses will be Fields.

Matt Winters (not verified) on February 11, 2010

My cents on this so far is more of a question: do any of the scenarios discussed in the write-up and comments have significant implications for "non-traditional" products? And I'm not thinking so much about downloadable products as service, access, content posting, and other types of uses that don't really center around products per se. There are many interesting implementations of "non-traditional" eCommerce, but I also see this as expanding in type, number, and creativity in the future.

Ryan Ryan Szrama on March 1, 2010

I think a strong Rules integration here will make these sort of non-traditional things much simpler than they were in the past. The product features system of Ubercart never really matured, but that's because it was mostly just an unhelpful usability layer between product nodes and the Conditional Actions system.

With Drupal Commerce, I'd like to see these things handled through Rules with custom actions and integration with other contributed modules. I'd love to still see some UI simplification for usability, but even just having a single way to accommodate new business models instead of a hybrid system will be a huge advantage.

redben on March 2, 2010

One thing that seems to be important to me to make things flexible is to have the cart and order independent from product. They should have some kind of api that just says "give me something with a reference, description a price and qty", whether it is the product module or another one. This would let us keep the product module focused on the 80% classical use cases and let other modules implement any other non classical "order-able" things.
Or maybe the product module *could* be that API, having a default implementation wich covers the regular "order-able" products...
I don't know