an abstract image of a grid adhering to waves with various spotlights of teal and purple

Sitecore E-Commerce Services 2.2 with Custom On-Site Hosted Payment Forms

Toby Gutierrez
Toby Gutierrez

Sitecore E-Commerce Services is a great way to setup an online web shop for your business in a snap. In this post I will address how to quickly setup Sitecore SES 2.2.

Sitecore SES 2.2 is a breeze to get setup and get configured with your current installation of Sitecore. In my experience Sitecore SES is geared towards clients with these types of business attributes:

  • Online web shop or brick and mortar retailer with online web shop to supplement in-store sales 
  • Many products (tangible) 
  • Many product categories 
  • Many product images 
  • Performs shipping & handling 
  • Has an order process (new, in process and closed) for orders 
  • Client is alright with off-site payment processing with a payment provider such as 

If those basic attributes of the business are in place then Sitecore SES will be a snap. Otherwise, you may be looking at customizing Sitecore SES to fit the business. The good news is that it can be done. However, depending on the level of skill of the developer you will be looking at a tiny bit of ramp up time. Sitecore SES is developed using dependency injection with unity.

First, if you are not familiar with this pattern and practice then I recommend you take a look at this tutorial Developer’s Guide to Dependency Injection Using Unity. Once you have some basic knowledge of dependency injection with unity you will be able to understand the architecture of what is going on under the hood in Sitecore SES.

Next, if you are going to customize Sitecore SES, I recommend getting a tool such as .NET reflector so that you can decompile the Sitecore SES .dll’s. Download your free .NET reflector trial here. This also will allow you to see what’s going on under the hood and will allow you to grab code for reuse in creating extended custom implementations.

In a recent implementation my task was to break away from the out-of-the-box functionality of Sitecore SES, which uses off-site payment provider forms, and create a custom on-site hosted payment form using as the payment provider. Below I will give some direction on necessary steps I took in order to do that:

First, I used the example cart that is provided with Sitecore SES and followed the same basic structure as seen below for my shopping cart process:

Sitecore SES Content Structure

Let’s begin to focus on the payment page, which we will build a form to take in the customers’ data and payment information. Once our form is built we can start building in the logic behind what the user submits and where the fun begins:

On-Site Hosted Payment Form

Above is an image snippet of a simple form to take in the data that we need from the customer (keep in mind this is all test data being sent to in test mode).

Next, we will create a custom order manager class that will be used to create the order when the user clicks on the “submit order” button. This way we have a bit more control over the order creation process and how the data is stored within the Sitecore e-commerce tables.

Typically you would call the create order method like so to create an order using that original implementation: 

IOrderManager orderManager = Sitecore.Ecommerce.Context.Entity.Resolve>(new ResolverOverride[0]);
Order order = orderManager.CreateOrder(Cart);

However, I ran into an issue with the order manager create order (cart) method returning an exception. The order manager would be instantiated but the create order would error out giving me a “target of an invocation” error. Because the error was occurring in the e-commerce .dlls I couldn’t debug and step through. So I created a custom order manager using the transient order manager as a template. I also decompiled the class using .NET reflector, extracted the code and created a new class called custom order manager as such:

public class CustomOrderManager : IOrderManager, IUserAware
// Code left out here for verbose reasons
// Get code from TransientOrderManager class in Sitecore.Ecommerce.Visitor.OrderManagement.Transient namespace

Since SES uses unity inversion of control containers and the dependency injection pattern, once I created the class I had to make some modifications to the unity.config. I added the following alias to the order management section:

[alias alias="CustomOrderManager" type="SS.ECommerce.Helpers.CustomOrderManager, SS.ECommerce" /]

Then, I modified the map to value to reflect my new custom order manager verse the old order manager in the products section:

[register type="IOrderManager" mapTo="CustomOrderManager"]
[lifetime type="hierarchical" /]

Once my new custom order manager was registered, I can resolve my new custom order manager and be able to debug through it to find out what is going on and make any further customizations that I want. I made the same call but just changed my variable name to custom order manager:

IOrderManager customOrderManager = Sitecore.Ecommerce.Context.Entity.Resolve>(new ResolverOverride[0]);
Order order = customOrderManager.CreateOrder(Cart);

When this was complete I received the same “target of an invocation” error, however now I could debug. When I debugged I found the error was happening as the destination process status method was being called. For this implementation I didn’t need to process the status for this particular project because our payment gateway is doing a lot of the work for us (i.e. sending emails, etc.) so I commented it out. Then the order was then being created and was able to be seen in the order manager.

With all the above tasks complete, in order to customize the create order method you will need to create a custom interface as well to implement for custom order manager. The code can also be extracted using .NET reflector to accomplish this.

I wanted to have more control over how the data was being stored in the data tables during the create order process so I created the custom order manager interface to have a create order method. This method would take on a company ID, comments and a list of product IDs to store in the data tables along with the normal data that SES will store:

public interface ICustomOrderManager where TOrder : Order
// Methods
TOrder CreateOrder(TShoppingCart shoppingCart) where TShoppingCart : ShoppingCart;
TOrder CreateOrder(TShoppingCart shoppingCart, int companyId, string comments, List productIds = null) where TShoppingCart : ShoppingCart;
string GenerateOrderNumber();
TOrder GetOrder(string orderNumber);
IEnumerable GetOrders(TQuery query);
IEnumerable GetOrders(TQuery query, int pageIndex, int pageSize);
int GetOrdersCount(TQuery query);
void SaveOrder(TOrder order);

I then modified the alias to reflect my new custom order manager interface in the unity configuration:

<alias alias="ICustomOrderManager" type="SS.ECommerce.Helpers.ICustomOrderManager`1, SS.ECommerce" />

Then I mapped my interface to my custom order manager like I did before with order manager:

<register type="ICustomOrderManager" mapTo="CustomOrderManager">
<lifetime type="hierarchical" />

Now, I can pass parameters I choose and manipulate the data in the create order method.

Being able to manipulate how the data is stored in the tables was a bit ambiguous to me at first until I started really looking into the data relationships in the orders database. The key for me was to convert the order to Sitecore.e-commerce.OrderManagement.Orders.Order from the legacy order (Sitecore.E-commerce, DomainModel.Orders.Order). At that point I could tap into the correct properties to store the data as such:

Sitecore.Ecommerce.OrderManagement.Orders.Order newOrder = this.Convert(legacyOrder);
newOrder.Note = comments;

That is all you generally you need to know to you create an on-site hosted payment form using Sitecore SES 2.2. Once you get the feel for dependency injection, the Sitecore SES 2.2 module and the data relationships in the orders database, you will be well on your way to creating a more customized solution for your clients.

Let's Get Started

We'd love to hear from you. We probably have a lot in common. I mean, you like chatting about data-binding, UX patterns, and javascript functions, right?


Cookies help us improve your website experience. By using our website, you agree to our use of cookies and our privacy policy.