This time I would like to demonstrate how easy it is to extend Sitecore XC Business Tools. When I am talking about Sitecore XC, I often tell the people, that one of the benefits of Business Tools is, that they are completely date driven. This weekend I really found out how powerful this benefit is in daily life work.
Within this blog post I will guide you through the process, of how to implement such an application in Business Tools with the example of my Carts application. The idea for that application came up, when I had a requirements workshop with some clients. There the wish came up to be able to see all active carts in the backend system to be able as customer service employee to help customers, who have problems with there carts. Because Sitecore XC does not provide such an application OOTB, I started playing around with that to create one.
A great starting point for me was to have a look at some example plugin implementation provided here
This github repo contains a lot of great examples, of how thing can be done in Sitecore XC. As you can see in the screen below I migrated the code to Sitecore XC 9.1, integrated that into my demo solution and had a deeper look at the implementation
In addition to these demo applications, you can also see the mentioned new Carts application. But now maybe the question comes up
How can you create new Business Tools applications?
This is much easier than you might think now. Let me first show you all the pipelines you should know to also know when to use which one
IBizFxNavigationPipeline: This pipeline is the starting point of the whole Business Tools application. Once you open Business Tools, in the end the application grabs all applications to show, based on the results given by this pipeline. If you know want to add a new application to Business Tools, you just have to create a new block and hook in into this pipeline.
As you can see in the screen below, the block has EntityView as in- and output parameter. The only condition, which has to be add is, that this block should only react if the current view is ToolsNavigation view. That’s our start screen.
Once we enter that screen, we just create a new view and add that view to the given entity view as a child view. The result after compiling that code is in deed already the screen above with the new application Carts showing up in Business Tools start screen. We just provided the data to display and the Business Tools application did all the rendering job for us.
IGetEntityViewPipeline: Now things are getting more and more interesting. What we now would like to do, is to click on that new application to show some kind of overview or details screen. The IGetEntityViewPipeline is always called, once any kind of entity view should be shown. It does not matter for which application or if the view is a master view, details view or dialog view (forms). Because of that the content of this pipeline is also quiet big, because in the end every single view to display is added there as a block. The differentiation, which view should be applied when is done by view name and action (if it is an action or not). This you will also see later on in more detail.
Let us first add a block, which renders our overview of our new Carts application. To achieve that, we just create a new view called DevOpsCartsDashboard as you can see below in more detail.
You can again see the same structure for entity views as before. The first statement is a check, if we are on the correct entity view. In our case the name of the entity view was outsourced into the policy to avoid redundancy. The name of the view is the view name of the carts application we added earlier as child view. Once we click on the icon, we open the entity view with that name. And because we want to render new information / child views in that application, we check for that specific entity view name. Once we are in that view, we add more child views by using a special command for that, the ChildViewActiveCarts command. The benefit of using a command to render child views is, that in this way code becomes cleaner and more reusable.
As you can see in the screen above, we just use the given entity view, the Carts application view and add new child views to that. Each child view will be in the end displayed as new single accordion elements. In our case, we create a new Active Carts child view to display all active carts know by the commerce engine. Of course after adding that child view to the entity view we have to also add some properties to display.
We first grab all carts from the engine for the current commerce context. Then we iterate through all the carts. For each cart we create a dedicated cart view with some properties of the cart to show. In the end we just add every single cart view to our previously added active carts view. This way we generate a new accordion Active Carts with various single entries, each representing a single cart. The screen below shows, how this overview page in the end looks like after compiling that code.
You can see, that in my example I had two active carts, one created via Postman and one created via Storefront. And both carts appeared in the overview page. What you also might see is some small but powerful detail. The name of the carts are in addition links and they are linked to the detail pages of the corresponding cart entities. So when you click on the click e.g. of Cart01 you will be redirected to the Entity View of Carts for the specific cart Cart01. You achieve that by simply doing 2 little things in your code.
- On the name property of the cart you just have to specify the UiType and set it to EntityLink
- In the Cart view set the property ItemId to the entity ID of the cart you would like to link to
Now let’s come to the entity view of a cart. If we have not done anything, the whole view would just consist of some really basic information like seen below in the Summary tab.
Of course these information are basically nice, and of course it is really nice, that we are able to display our entity in that easy way. But I guess, we would like to see more details of our current cart in that view. To display more and more information, we just again have to create a new block hook in into the IGetEntityViewPipeline pipeline and implement the new child views. Below you can see the beginning of the new class EntityViewCart.
You can see, that I just check if an entity is applied to the entity view, which is in deed the case, if we render an entity detail view like carts, orders, customers etc. In addition I try to grab a cart and check if the cart is a valid one. In my case, just checked if create date and update date are the same. In case we are on a valid cart entity view, these values will defer, because the cart already was created earlier and had interactions afterwards. In case we are on a other entity view e.g. customer, the GetCartCommand would return a newly created cart. (and yes not null ^^ ) But this cart would have date created and date updated the same date, so I would skip these views. I guess there are smarter ways of grabbing and checking the cart entity view. But for my experiment this was sufficient enough to cover all possible cases, also that this view should not be applied on other entities. As you can see from the code I do some pre-processing before really adding some new content.
Because such an entity view contains a lot of information I decided to split the adding into smaller pieces and show you each piece step by step. Each piece is structured always the same way.
- Grabbing necessary information
- Creating a child view
- Adding that child view to the overall entity view
- Adding properties to the child view
One of the easier child views was the Totals view, where I just wanted to show information about all the totals values on a cart.
A little bit more difficult was the display of all applied adjustments. In this view, we had to ensure, that we display not just a single view with some properties, but a list of views each with some properties. The procedure is the same, than we had in the Carts application overview page by showing a list of active carts in a single view
Now next information to show are the line items added on the cart. And not only the line items, but also some more detailed information about each added line.
Above you can see the whole code for Line Item and product component child views. I decided to split line items and product components to be able to to give customer service even more information about all added lines to cart. The line items with, holds just basic information like prices, quantities and totals.
The product component child view below holds even more information about the product behind the line item of the cart. As you can directly see in that component, this is again linked with the corresponding entity behind.
So if you click on the name in the cart product component you will directly be redirect to the sellable item detail page of the product added to cart to see even more detail information.
Next view is again some easier view, the voucher view. Within that view, we just grab the cart coupon component from cart and extract basic information about added coupon codes.
If a coupon code is added, you are also able to click on the promotion entity target to see the promotion behind the coupon code. Same procedure, like you saw earlier with the cart product component. You see, that you all the time, when displaying other entities, you are also able to directly link them to your view to allow easy navigation between them.
Ne important child view is the physical fulfillment view, which just shows information about applied physical fulfillment method. Of course you can also add a view for digital fulfillment or even other ones. But for demonstration reason, that specific view is enough to demonstrate the possibilities.
Last but not least I also wanted to display one payment view. Because for testing I always use GiftCard payment, I decided to show you that example here. Again, you are totally free to display also other payment methods or types depending on your own custom business needs.
So by now you saw, how to step by step create your new entity view and fill it with custom data. But just displaying information is most likely not enough. We of course also want to edit some stuff. To be able to do that, the two missing pipelines are taking action.
IFormatEntityViewPipeline: This pipeline is now responsible for adding all kind of actions to our views. In our case we just have one single class for adding all kind of actions to all of our views. Of course depending on your preferences you can also split that up or arrange differently. What this class we have now does is in the end quiet simple. Depending on the fact if we are on our target view, like cart entity view, we just iterate through all the child views (all the once we created earlier) to grab the ones, we would like to add actions to. Then if we found the view we just have to access the action policy of that view and simply add a new action to that list. The new object is of type EntityActionView. An example of that can be seen below.
In this example you can see, that based on the entity view (Carts entity view) we just grab the child view of name Line Items. Once we found that, we add all our action we would like to add e.g. Add Line Item, Edit Line Item, Remove Line item. If we would like to add more actions like for gift cards, vouchers or other child views, we would just have to do the same for all other child views.
Once we have done that and open the cart entity view again, we can see all kind of new buttons beside our child views.
If we would click them now, just an empty or nearly empty dialog would open with an accept and reject button, nothing more.
Note: The dialog you can see above will be displayed, once you set the property of EntityActionView RequiresConfirmation = true.
Now let’s do the next step. The next step is to fill the dialog with some new fields. This is much easier, than you might think. Let’s stay at the example of line items child view with add, edit and remove functionality and have a look how to add fields to the view to be able to add some custom information. IF we e.g. want to add a new line item to our cart we have to provide some basic information like, catalog, productId, variantId and quantity. Below you can see an example implementation of the add view
Now let’s see, what code is responsible for rendering that view. Because these dialogs are nothing more than entity views, the process of adding such a view is exactly the same, than before with views. We just have to create a new block and hook in into IGetEntityViewPipeline. The whole implementation of the dialog above can be seen below.
In the beginning we just have to check, if we are in the right view, like in all other views. If it is this case, we in the end just add all our properties to the given entity view. For each property we can individually decide, if the property is hidden, if it is a mandatory field to add and it’s default value.
So what’s next now? If we would now use the dialog, like seen above, unfortunately nothing would happen. To make something happen, we finally have to implement a custom action, which should be triggered, once we trigger the action in the dialog. To do that, the last pipeline is now used.
IDoActionPipeline: In this pipeline we add all kind of blocks, which are responsible for doing actions. In our case we added a class DoActionAddLineItem, which should take over the responsibility of really adding now a line item to the given entity view cart. Once we click the “accept” button in the dialog the IDoActionPipeline is triggered with each block within. So what we first have to do, like always is, to determine, if the current action is the one we would like to react on. If that is the case, we simply grab all the previously added view properties and in the end just trigger the AddCartLineCommand to really add the cart line to the current cart. The code below shows the whole implementation of that action.
If we now after doing all that, enter our cart entity view, click on Add Line in our Lines view, fill in some existing product with its data and click “accept” the line item is immediately added to the cart, and the cart entity view reloads and directly shows the new line item in the Cart Lines view.
In the same way, we can also implement functionality like edit or remove.
One special behavior of edit is, that we are able to choose a line item within our Line Items view and click on Edit Line Item. The application automatically knows which specific line item was selected, so we are able to use the given data to pre fill the input fields. An example of such an implementation can be seen below.
The first special thing in the form view, is that based on the selected line item, we extract the current quantity as default value.
In the DoAction class of edit line item now, we just have to extract the quantity field and again grab the selected line item from the entity view. Based on these information we were now able to differentiate between RemoveCartLineCommand and UpdateCartLineCommand. Below is the rendering of the previously seen code.
The same way like seen above, I also implemented all the other actions and dialogs you can see in the following screens. These implementation contain
- Remove Line Item
- Add Voucher
- Remove Voucher
- Add physical fulfillment
- Add GiftCard
- Remove GiftCard
And of course like always. These implementations are just demonstrations of what you are able to do in commerce engine.
Physical Fulfillment Actions
Gift Card Actions
The code of all these implementations and the whole Carts application can be found in my github account under the following url
Within this blog post I hope you saw, how easy it is to add new applications to the Sitecore Commerce Business Tools and how easy it is to extend these views with new custom information. To do that, we as backend developer just have to hook in into some specific pipelines and provide the data, which should be displayed. The Business Tools application then reacts on these data and renders, whatever is given. There is no need to touch the frontend application or even know how it is implemented.
And that’s what I think, is the real meaning of Data Driven UI.