Contact us on: +44 (0)1432 617 006

The Site Doctor Blog

Footprints in the snow of a warped mind

< Back to Blog

Speed up your uCommerce checkout pipeline

Speed is key when it comes to e-commerce. Regardless of which platform you use to sell online it has to be fast and no-where is this truer than the checkout processes.

uCommerce is a great platform and it's Pipeline feature makes uCommerce hugely extensible however with great power comes great responsibility and you have to think about your users.

Out of the box uCommerce emails the customers their order confirmation email as part of the Checkout Pipeline. This is fine, however we have found that generating this email and sending it to the customer is often slow. This can result in the customer clicking the "Pay" button more than once or just being generally frustrating -at a point in their journey that should just be thanking them. By slow we're only talking about a few seconds but that's a lifetime in e-commerce.

Thanks to uCommerce's order status structure, the solution is pretty simple. By default the order flow is as follows:

image

 

By simply adding an extra order status you can move all the slow logic (sending emails, sending the order via an API etc) into another pipeline that is executed outside the customer's checkout process and so take as long as you need.

The order's new flow would then look something like this:

image

In uCommerce v7+:

  1. Run the SQL (below)
  2. Create a new folder in the uCommerce App's folder i.e. "OrderProcessing"
  3. Create a file "custom.config" from below

In uCommerce v6 and earlier:

  1. Run the SQL (below)
  2. Edit Baskets.Checkout.config and comment out <value>${Checkout.SendConfirmationEmail}</value>
  3. Create a new config "ToOrderProcessing.config"
  4. Copy the contents of the custom.config xml from below and remove the partial-component section

 

Create uCommerce Order Status via SQL

BEGIN TRAN

INSERT INTO uCommerce_OrderStatus (OrderStatusId, Name, Sort, RenderChildren, RenderInMenu, NextOrderStatusId, IncludeInAuditTrail, AllowUpdate, AlwaysAvailable, Pipeline, AllowOrderEdit)
VALUES (1000,'Order Processing', 3, 0, 1, 3, 1, 1, 0, 'ToOrderProcessing', 1);

-- Optional: Update the various order statuses
UPDATE uCommerce_OrderStatus SET [Sort]=1 WHERE OrderStatusId=1 -- Basket
UPDATE uCommerce_OrderStatus SET [Sort]=2 WHERE OrderStatusId=2 -- New order
UPDATE uCommerce_OrderStatus SET [Sort]=4 WHERE OrderStatusId=1000003 -- Dispatched
UPDATE uCommerce_OrderStatus SET [Sort]=5 WHERE OrderStatusId=1000000 -- Requires attention
UPDATE uCommerce_OrderStatus SET [Sort]=6 WHERE OrderStatusId=3 -- Completed order
UPDATE uCommerce_OrderStatus SET [Sort]=7 WHERE OrderStatusId=5 -- Invoiced
UPDATE uCommerce_OrderStatus SET [Sort]=8 WHERE OrderStatusId=6 -- Paid
UPDATE uCommerce_OrderStatus SET [Sort]=9 WHERE OrderStatusId=7 -- Cancelled
UPDATE uCommerce_OrderStatus SET [Sort]=10 WHERE OrderStatusId=1000001 -- Manually cancelled
UPDATE uCommerce_OrderStatus SET [Sort]=11 WHERE OrderStatusId=1000002 -- Processing

ROLLBACK TRAN
-- Comment this out when you're happy it's working
--COMMIT TRAN

ToOrderProcessing.config / custom.config

<configuration>
    <components>
        <partial-component id="Checkout">
            <parameters>
                <tasks>
                    <array>
                        <value remove="${Checkout.SendConfirmationEmail}" />
                    </array>
                </tasks>
            </parameters>
        </partial-component>

        <!-- s/o Order Processing -->
        <component id="ToOrderProcessing" 
                      type="UCommerce.Pipelines.Transactions.Orders.OrderProcessingPipeline, UCommerce.Pipelines" 
                      service="UCommerce.Pipelines.IPipeline`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce">
            <parameters>
                <tasks>
                    <array>
                        <value>${OrderProcessing.SendConfirmationEmail}</value>
                    </array>
                </tasks>
            </parameters>
        </component>

        <component id="OrderProcessing.SendConfirmationEmail" 
                      type="UCommerce.Pipelines.Common.SendEmailTask, UCommerce.Pipelines" 
                      service="UCommerce.Pipelines.IPipelineTask`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce">
            <parameters>
                <emailtypename>OrderConfirmation</emailtypename>
            </parameters>
        </component>

        <!-- Add any other order complete tasks here -->

        <!-- e/o Order Processing -->
    </components>
</configuration>

 

We also recommend doing this when sending orders from uCommerce to Xero (blog post to come soon) or uploading order data to TrendSeam as it doesn't matter if the remote servers are slow. Also, if for any reason the pipeline fails i.e. and error with the SMTP it will re-try until the email is sent.

You can also automate it easily by creating an MVC action that moves and order from one uCommerce status to another and then hit that every 5 minutes (see periodically visit a url with windows scheduler for how to automate it). The action would look something like this:

 

public ActionResult ChangeOrderStatus(int currentStatus, int newStatus)
{
    var orderService = ObjectFactory.Instance.Resolve();

    if (orderService == null)
    {
        return Content("0 Orders Processed. Unable to locate OrderService from DI.");
    }

    var current = OrderStatus.FirstOrDefault(w => w.OrderStatusId == currentStatus); 
    var proposed = OrderStatus.FirstOrDefault(w => w.OrderStatusId == newStatus); 
    if (current == null)
    {
        return Content("0 Orders Processed. currentStatus is invalid.");
    }
    if (proposed == null)
    {
        return Content("0 Orders Processed. newStatus is invalid.");
    }
    
    var orders = PurchaseOrder.Find(w => w.OrderStatus == current).ToList();
    if (!orders.Any())
    {
        return Content("0 Orders Processed. No orders found for that status id.");
    }

    foreach (var order in orders)
    {
          orderService.ChangeOrderStatus(order, proposed);
    }

    return Content($"{orders.Count} Orders Processed.");
}

Happy order processing

Author: Tim on

Liked this post? Got a suggestion? Leave a comment