Integrating Merchello with an EPOS System. Part 2

This blog post was actually written a couple of years ago and was never published. It seemed a shame for it to be lost, so today we are publishing it anyway :)


This is the second article in a series of two covering the two phases in which we implemented the e-commerce functionality and the integration of Merchello with their own EPOS system. In the first article we explained how we managed to upload and sync the products in the store with the website. In this one, we will talk about the second phase of development, focusing on the download of online orders to their store system.

Part of this article is based on the previous one, so if you still didn't read it or are curious about it, please go ahead and click on the link:

Integrating Merchello with EPOS System

Integration

As explained in the previous article, the integration was done through a specific module added to Encore, the software by their EPOS provider. This module is prepared to call and receive orders data at predefined intervals of time and add these orders to the store database. We had to write the specific code to call our site and pull the right data. Our API, then, has to collect the online orders, prepare them and send them in the response. The methods in charge of this in our API are:

  • Login
  • Download orders
  • Update Order Status
  • Logout

The login/logout methods, the security around the process and the environments implementation follow the same logic as for the upload process.

Orders in Merchello

The checkout process on the site is handled entirely by Merchello, that offers a neat helpful resource to achieve everything involved in it. Of course, the actual payment will need to be done through a payment provider, and it will need to be integrated somehow in the workflow. In Merchello website, you can find a list of useful plugins that include integration with different payment providers. These are free plugins developed and managed by the community. You can also find other plugins out there created by Umbraco developers for other major providers like PayPal. In case you are using a provider for which you cannot find a plugin, it might be worth asking the community, or you can develop your own based on any one of the available plugins.

In our case, we were working with WorldPay and there was no option to change it since it is also the provider used in the store. We had to develop our custom payment provider, but that will fall out of the scope of this article and will probably deserve a post on its own. If you are interested in knowing the details of our WorldPay plugin, please drop us a line.

Merchello is capable of dealing with orders, invoices and shipments and it offers a pretty easy interface in the back office. Although shipments and fulfilling of orders are processed at the store we still make use of most of the functionalities Merchello has to offer.

After an order has been completed and paid online, we save it as part of a specific collection so we will know exactly where we need to look for them. In Merchello you can create orders collections, in the same way as with products, to help you organize them. There are several collections by default that let you view the orders and invoices grouped by status. To add an order to a specific collection from the code, we use this method:

/// <summary>
/// The add to Encore collection.
/// </summary>
private void AddToEncoreCollection(IPaymentResult attempt)
{
    var collectionService = this.Context.Services.EntityCollectionService;

    var encorePendingCollection =
        collectionService.GetRootLevelEntityCollections(EntityType.Invoice)
            .FirstOrDefault(
                x =>
                    string.Equals(x.Name.Trim(), CustomEntityCollections.EncoreOrders, StringComparison.CurrentCultureIgnoreCase));

    if (encorePendingCollection != null)
    {
        attempt.Invoice.AddToCollection(encorePendingCollection);
    }
}

Download

The EPOS system does its scheduled task to download the online orders and make a request to the site. Since the orders that are ready to be downloaded and integrated are part of a specific collection, it is pretty simple to get them. We only need to serialize them according to the environment we are using (this was explained in the previous article).

/// <summary>
/// Gets the web invoices for downloading to be passed to Encore.
/// </summary>
/// <returns>
/// The <see cref="IEnumerable{WebOrder}"/>.
/// </returns>
public IEnumerable<WebOrder> GetWebPendingOrders()
{
    if (this.environment == null)
    {
        throw new WebApiEnvironmentException("There is no environment available to parse the orders for this call.");
    }

    var invoiceService = MerchelloContext.Current.Services.InvoiceService;
    var collectionService = MerchelloContext.Current.Services.EntityCollectionService;

    var encorePendingCollection =
        collectionService.GetRootLevelEntityCollections(EntityType.Invoice)
            .FirstOrDefault(
                x =>
                    string.Equals(x.Name.Trim(), CustomEntityCollections.EncoreOrders, StringComparison.CurrentCultureIgnoreCase));

    if (encorePendingCollection == null)
    {
        throw new WebInvoiceException($"{CustomEntityCollections.EncoreOrders} invoice collection not found");
    }

    var invoices = invoiceService.GetFromCollection(encorePendingCollection.Key, 1, 10000, "createDate");

    return this.environment.Serializer.ToWebOrders(invoices.Items);
}

Update order status

Encore then will receive the orders and will store them in the store database. The plan here was to send a new request to the site to update the order status once the process has been successfully completed. We found, though, that internally Encore did not return anything back to the module we are using, so it is not a functionality that we can use without trying to hack the code or writing overcomplicated workarounds. Given the number of online orders expected, it was not a problem to do this update manually from within the back office. Also, Encore is smart enough to not process orders that have been downloaded already, so this update was kind of a secondary issue.

For those interested, here is the code that would be in charge of the update. It basically moves the processed orders to a new collection in Merchello.

/// <summary>
/// Updates an order status as passed by Encore
/// </summary>
/// <param name="jsonOrderUpdate">
/// The order update JSON object.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool UpdateOrderStatus(JToken jsonOrderUpdate)
{
    if (this.environment == null)
    {
        throw new WebApiEnvironmentException("There is no environment available to update the order.");
    }

    var orderUpdate = this.environment.Serializer.ToOrderUpdate(jsonOrderUpdate);
    var invoiceService = MerchelloContext.Current.Services.InvoiceService;
    var collectionService = MerchelloContext.Current.Services.EntityCollectionService;

    var encorePendingCollection =
        collectionService.GetRootLevelEntityCollections(EntityType.Invoice)
            .FirstOrDefault(
                x =>
                    string.Equals(x.Name.Trim(), CustomEntityCollections.EncoreOrders, StringComparison.CurrentCultureIgnoreCase));
    var encoreDownloadedCollection =
        collectionService.GetRootLevelEntityCollections(EntityType.Invoice)
            .FirstOrDefault(
                x =>
                    string.Equals(x.Name.Trim(), CustomEntityCollections.EncoreDownloaded, StringComparison.CurrentCultureIgnoreCase));

    var invoice = invoiceService.GetByInvoiceNumber(orderUpdate.OrderId);
    invoice.RemoveFromCollection(encorePendingCollection);
    invoice.AddToCollection(encoreDownloadedCollection);

    return true;
}

Addendum: track errors

While working on this project, we realized how sensitive the data integration between two platforms is, especially when they work in such different ways. The process can fail for many unexpected reasons. To keep track of possible errors on Encore side during the upload and download processes we decided to implement a little special trick. On the Encore side, we surrounded all requests to the site with try/catch blocks that, when they catch an exception, make a new call to the site with the exception message and stack trace. On our side, then, we save the message in the Umbraco logs so we can review them whenever an exception occurs. This has proven especially useful during testing on the staging environment, as well as on the live site. It allows us to track down the error relatively quickly and find a solution. Most of the times we could fix the problem directly in the code, while other times we were able to spot some misconfiguration on their store settings without the client having to contact their EPOS support team.

Conclusions

As for all e-commerce sites, the shopping workflow needs to be very smooth. Also, due to the sensitive nature of the data, any integration with other platforms needs to be robust and fail proof. I am proud to say that we met all these requirements. The client has also shown great interest in the integration process and is very happy with the final product and our ongoing support.

This was really an extraordinary project to work on and, no doubt, a challenge.


Author

Miguel Lopez

Miguel Lopez

Miguel is a web developer and Umbraco Master. He enjoys both technology and a good old fashioned book. He moved to the UK from Spain in 2015 and has been fully committed to Vizioz since.


comments powered by Disqus