Accelerate the power of Sitecore XC policies – Custom plugin to let content authors change settings in BizFx tools on runtime

Accelerate the power of Sitecore XC policies – Custom plugin to let content authors change settings in BizFx tools on runtime

For some time now, while working with Sitecore XC, I am struggling with the concept of policies. In general I really like that concept, how new policies are added to an environment and how things work. But more more I got requirements from customers, who wanted to be able to change those policies on their own. And of course you all now, that this is not possible. Policies are added, edited and maintained purely by developers. So either way you would have to exactly do that. Just change the setting all the time the customer wishes, or provide a smarter solution for that. And exactly that I tried to fulfill. Within this blog post I will first describe shortly the mechanism of policies and how they are maintained, will come back to he customer requirements, which are appearing more and more in all my projects and what that really means for us developers, till I finally present some extension for Sitecore XC OOTB logic to generically fulfill such requirements in an easy way.

Introduction to policies

If you are not familiar with the terms environments, policies and roles I strongly recommend you to read first one of my previous articles, which can be found here. But let me also try to sum up the essence of that article here a bit.

As you all might now, the normal way of storing any kind of configuration for Sitecore XC, is, to store it in a custom policy. A policy is nothing more than a piece of json file like seen below.

2020-03-18 20_07_55-esrvath02 - Remotedesktopverbindung

As you can see such a policy consists of 1 to n different properties, which can be set and maintained within that specific json file. These values are then mapped to custom .cs policy file to be then used ion runtime

2020-03-18 20_09_50-esrvath02 - Remotedesktopverbindung

Multiple of such policies are then combined together to one big environment Sitecore XC uses to execute pipelines, blocks commands and more for specific storefronts.

So in the end to speak in Sitecore XP terminology these polices are very similar to .config files or patches under the App Config/Include folder. As good as that works the trouble starts now in the way, of how such configs are maintained and deployed to other environments.

Process of how to bring changes of policies live

Boths types of configurations .config files and .json policies have the same weakness or better restrictions. They can normally not be maintained by content authors. The normal process of changing a value there and bringing it e.g. to production is in simple words the following

  • Change the value locally 
  • Commit and push these changes
  • Deploy this to the target environment 
  • Bootstrap environment so that json values are stored in DB to be used on runtime

So you can already imagine, that this is nothing an editor can do, and nothing, which can be done very quick. Because of that normally, in Sitecore XP you create global setting items, which can be maintained on runtime by content authors. Unfortunately nothing similar is existing in Sitecore XC – till now. ^^

Custom Settings plugin

So because I recognized, that there is definitely a lack in OOTB implementations, which make the life of content editors and developers more difficult, I thought, it makes sense to provide some new plugin to fill that gab.

What does it do?

With the newly created settings plugin you are now able to set previously defined policies values within a new BizFx application on runtime.

How does it look like?

In the screenshot below you can see the new application after integrating the setting plugin into a customer solution.

2020-03-16 10_05_19-esrvath02 - Remotedesktopverbindung

If you click on the settings application an overview of all existing settings is displayed. If no setting exists a default one is created automatically, which can be used.2020-03-16 10_06_14-esrvath02 - Remotedesktopverbindung

In the standard implementation of settings plugin you have 4 actions available to interact with settings, which can also be seen in the screenshot below

  • Add
  • Remove
  • Activate
  • Deactivate

Add: On click a new forms opens, where you can enter a Name and Display Name to create a new setting entity.

Remove: Removes the currently selected settings entity

Activate: Activates the currently selected settings entity. In addition it iterates through all other existing setting entities to disable them automatically, so there can be only one setting be active.

Deactivate: Deactivates currently selected settings entity

2020-03-16 10_06_39-esrvath02 - Remotedesktopverbindung

If you now click e.g. on the Default Setting entity, the corresponding entity view opens. After initially integrating the plugin, the settings entity will just have one single property is Active, like you can see below.

2020-03-18 20_27_51-esrvath02 - Remotedesktopverbindung

From this point on, you can now start filling the settings entity with all kind of policies you would like to edit on runtime.

How to integrate it into custom plugins?

So let’s start of how to integrate a custom plugin policy into the settings functionality.

Basically you need 4 different blocks to be able to display information in an accordion in an entity view, to provide an editor action on that accordion, to display a form to be able to edit properties and to be able to apply these changes to the current entity.

  • EntityViewXXX (Used to display data in accordion view)
  • FormEditXXX (Used in dialog to edit properties)
  • DoActionXXX (Used to apply edited properties from FormEdit to entity)
  • EnsureActionXXX (Used to provide edit button on new accordion view)

For all of you, who already extended entity views with new accordion views, know, that this needs some time to be fully implemented. Therefore the first thing I did for the settings plugin was, to make that process much easier for developer.

Base blocks

The settings plugin provides you with 3 different base blocks, which can also be seen below.

2020-03-16 10_11_28-esrvath02 - Remotedesktopverbindung

What you now just have to do to integrate your plugin into settings is, to create 4 different blocks and do the following steps

  • Inherit from the corresponding base blocks of settings plugin
  • Execute Base.Run method and provide policy as generic parameter and view  or action name in function parameter
  • Add all the new blocks to the specific pipelines in ConfigureSitecore.cs

2020-03-16 10_12_55-esrvath02 - Remotedesktopverbindung

Now let’s have a look at the whole code of the 4 blocks, where we use inheritance to use some basic functionality.

2020-03-16 10_13_05-esrvath02 - Remotedesktopverbindung2020-03-16 10_13_13-esrvath02 - Remotedesktopverbindung2020-03-16 10_13_21-esrvath02 - Remotedesktopverbindung2020-03-18 21_03_46-esrvath02 - Remotedesktopverbindung

As you can see, the whole implementation of all these 4 blocks consists of just one single line of code, where you just have to tell the function, which policy and which view name (Entity View) or which action name (DoAction and Form Edit) to use.

Last but not least add all the 4 blocks now to corresponding pipelines, like seen below

2020-03-18 20_52_50-esrvath02 - Remotedesktopverbindung

Policy Property Attribute

In addition to the base blocks, which can be used in custom plugin, you now just have to use the newly provided EditorSetting attribute on already existing plugin policies. In the screenshot below you can see an example, where I added the new attribute to all properties of the PimImporterPolicy you already know from the beginning.

2020-03-16 10_08_18-esrvath02 - Remotedesktopverbindung

After you added these attributes to the policy and reload the settings entity again, you will now see, that a new accordion has been loaded with all the properties you previously added via setting the editor setting attribute.

2020-03-16 10_07_14-esrvath02 - Remotedesktopverbindung

And of course also the edit functionality is directly fully working like seen below.

2020-03-16 10_12_02-esrvath02 - Remotedesktopverbindung

And lastly, of course if you confirm changes, the piece of code is also already working, which applies these changes automatically to the current settings entity.

Note: As you might see, there are of course currently some limitations, like list handling, which will be covered in more detail as improvement in the future. Right now you can also edit lists, which are treated as pipe separated strings.

In case you do not want to use every property of the policy, you can easily remove all the attributes from the properties you would like to exclude from settings functionality.

2020-03-17 09_47_41-esrvath02 - Remotedesktopverbindung2020-03-17 09_50_21-esrvath02 - Remotedesktopverbindung

In this example I removed the setting for start hour, end hour, pim endpoint because I do not want editors to edit such properties ^^. But in the end it is completely up to you, what you would like to be editable in settings entity.

Extensions

Now, after we added our policy to the settings entity, we also want to use it in our code. To do that, I also created some piece of code to do that. The same way you retrieve policy from commerce context, you can now also retrieve settings policy.

  • context.GetPolicy<T>() -> Grab policy from environment
  • context.GetSettingPolicy<T>(CommerceCommander commander) -> Grab policy from active setting entity with fallback logic to grab policy from environment

Below you can the whole and simple implementation of GetSettingPolicy with integrated fallback logic.

2020-03-16 10_10_50-esrvath02 - Remotedesktopverbindung

If we now think of possibilities how we could use the new settings in custom code.

Different ways to use setting policies together with OOTB environment policies

  • Overwrite whole policy
    • In such case just use the new extension method context.GetSettingPolicy<T>(…) and continue working with the returning policy
  • Overwrite just specific properties
    • Use Standard context.GetPolicy<T>() AND context.GetSettingPolicy<T>(…) to retrieve environment and setting policy to decide later on, which property to be used when and which fallback logic shall be applied
  • Completely standalone setting
    • Note that such policies are not stored in environment and cannot be retrieved via OOTB context.GetPolicy<T>() call
    • Use context.GetSettingPolicy<T>(…) to retrieve the setting policy

Because in our example, we removed some of the properties from the possibility to be edited in settings, we would have to apply approach number 2 from above. To do that, we first grab settings policy, beside with environment policy.

2020-03-16 10_09_36-esrvath02 - Remotedesktopverbindung

And then we can easily and individually apply our custom fallback logic for each property, like seen for mailsubject below.

2020-03-18 21_29_40-esrvath02 - Remotedesktopverbindung

Conclusion

Within this blog post I presented a newly created plugin called Plugin.Sample.Settings, with which you are now able to edit policy properties not only in json on development time, but also within BizFx tools in a new application on runtime.

This way it is much easier to edit specific settings per environment as developer or editor.

The whole code can be found in the following github repository

And as always, the code is not production ready and is not extensively tested. Therefore use this code as a starting point for your own implementation.

Sitecore XC – Everything you have to know to work with media items

This time I would like to share some insights on the topic, of how to use Stecore XP media library items within commerce engine entities. Maybe most of you, who already used Sitecore XC, have already seen the Images component of sellable items and variants.2020-01-18 20_49_56-Alnatura - Microsoft Visual Studio (Administrator)

Of course I already played around with that and used images of example habitat and adventure works. But recently I was faced the customer requirement, that customer wanted to map own images from Sitecore XP media library to previously imported products. And here the story begins…

As mentioned above I already around a bit with images on demo products. Below you can see the steps to map an image to a sellable item in demo environment

2020-01-18 20_53_33-Alnatura - Microsoft Visual Studio (Administrator)

2020-01-18 20_54_16-Studio X Over-the-Ear Wireless Headphones

As you can see, you can just use some kind of search to find the proper image, chose it and easily set it.

So my first step was to go into a custom product, within a custom environment and just try to add my images from media library there, as I did with habitat or adventure works products.

2020-01-18 21_09_31-Winterschokolade

One thing I realized very quick was, that I in deed find images, but not my ones.

2020-01-18 21_13_31-Winterschokolade

As you can see above, on my sellable item within my own environment, I just saw e.g. backpack stuff instead of all my food images I wanted to see.

2020-01-18 21_15_16-Winterschokolade

And once I entered the exact media item name I was searching for, I just got “No results” screen.  But I know my image was added correctly to the media item

2020-01-18 21_14_55-Desktop

What I did on XP side, was, that I just added a folder common, beside the folder adventure works and habitat and added all the product images I wanted to use later on there.

2020-01-18 20_51_19-Desktop

But obviously that was not enough. For some reasons my own new images were not found. So let’s start looking, what really happens on search call to understand, where the problem my be.

2020-01-18 21_17_03-Winterschokolade

As you can see, I started to have a look at the call, which was executed on search click. You can see, that a DoUIAction() call is triggered with some special parameters. One parameter is exactly, what we were looking for, the “Action: SearchMediaItems”. So we know now, that there must be some action called SearchMediaItems within commerce engine call.

So next step was a familiar one. I used dot peek to have a look at commerce engine dlls to find that function. To be sure I really find something, I just added all commerce engine dlls to dot peek and just searched for SearchMediaItems.

2020-01-18 21_22_09-JetBrains dotPeek

The results can be seen above. Very successful I would say. After looking into some of these classes, I finally found the interesting one, SearchMediaItemsBlock.cs. In the end this class is being used for searching media items in XP from XC side.2020-01-18 21_23_48-JetBrains dotPeek

The decompiled code of that class now tells us even more. Sitecore uses some basic SitecoreConnectionManager class to handle all kind of search and retrieving functionality for items from XP. And within that manager class we have also a function called SearchMediaItemsAsync, which is in the end used.2020-01-18 21_25_06-JetBrains dotPeek

Having a look now into that class into our function, we finally get the information we needed. Sitecore uses predefined item API call with some parameters to access XP. To do that, it also uses an API Key ODataItemServiceApiKey, which is stored within a policy. So let’s have a look into that policy. 2020-01-18 21_31_06-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

Of course now we can have a look into our environments to maybe find that property. And et voilà there really is a setting as you can see above. You can see some ItemID there. Now next step was to use that ItemID to find the corresponding item.

2020-01-18 21_33_15-Desktop

 And there was a Item. Within Sitecore XP in /system/settings/services/API keys there is an item which handles basic settings for searching. It tells e.g. which database should be used and defines some basic filters.

AND FINALLY the highlighted area shows us, why we did not retrieve any of our own images. There is a filter, that limits image retrieval to “images/habitat” and “images/adventure works”.2020-01-18 21_34_24-Desktop

So now we also know the steps how to fix it. And of course I don’t want to fix it with manipulating OOTB Items from Sitecore. So I just created a new API Key Item with some custom Search Filter setting. As highlighted above I just want to include the folder “images/common”. Everything else is more or less the same for now.2020-01-18 21_36_43-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

Next step after creating the new Api Key item, we also have to add it to our environment file. Above you can see, the comparisons of the OOTB and my custom environment. The nice thing about that approach of adding a new api key for my new environment is, that both environments now can search for media items completely decoupled from each others.2020-01-18 22_33_18-Winterschokolade.png

So, if we now execute the search again from the beginning, we finally also get the result, we wanted to have.

Of course it is nice, that we can now link our own images to our own products, but the initial requirement is not really fulfilled. The customer does not want to manually link all the images after an image import. So there has to be some kind of automatism.

I decided to integrate image linking to my standard product importer pipeline, which you already know from earlier blog posts. I hust added a new function called EditImageData.

2020-01-18 21_42_50-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

The code for that small function can be seen above. We just use the information we got from dot peek and use the SitecoreConnectionManager also within our code. One special thing on our images is, that the image name is exactly the so called ean (gtin).

Once we got the proper image, we just retrieve the standard ImagesComponent and add the Image Sitecore ID to the Images list. And that’s it. After doing that and re importing all our products, all our products finally now got an image fully automatically.

Sitecore XC – Finally price card snapshots also have an end date

Sitecore XC – Finally price card snapshots also have an end date

In this blog post I would like to present you an implementation for an issue we all might have suffered from. But let us start in the beginning and shortly discuss how pricing works in Sitecore XC in general.

How does pricing work in Sitecore XC?

The most basic way to set a price in Sitecore XC is, that we just set a price on the sellable item directly as List Price. This price can be of course set per currency like seen in the example below.

2019-11-13 07_54_17-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Because such a price setting is quiet inflexible Sitecore has build some piece of logic on top of that. The core principle of that mechanism is so define a price based on currency, date, and quantity, which is far more flexible, than just set one single price per sellable item.

This can be edited by an editor under the Pricing Application in the Business Tools of Sitecore XC.

2019-11-13 09_41_17-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

Once you entered this application you are able to define a so called Pricebook.

2019-11-13 07_55_15-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Such a Pricebook can be linked to one or more catalogs and is itself just a container for more specific price settings, the so called Pricecards.

2019-11-13 09_05_38-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Such a Pricecard then be directly applied on a sellable item to a sellable item via the Pricing field.

2019-11-13 10_18_36-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Now the interesting part starts, where real price settings come into play. Pricecards themselves are again just containers for so called Snapshots.

2019-11-13 09_09_08-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

A snapshot itself then contains the information of a start date, when this specific snapshot should be applied, a tiered price per currency, which means you can define how much one single sellable item costs, in case a customer has X items in cart. And last but not least, you are able to tag the snapshot to define to which sellable items this specific snapshot should be applied.

2019-11-13 09_09_44-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Therefore you see, that this pricing mechanism is far more flexible and powerful, than just adding a simple list price to a sellable item directly.

2019-11-13 09_10_05-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Known limitations of snapshots

This overall pricing mechanism is really great and powerful. But when talking to clients and collecting all their wishes and requirements, one feature was wished very often, which is currently not possible to fulfill with the OOTB capabilities. The client always asks exactly the following question

How can I set an end date for the snapshots?

Right now the behavior of snapshots is very rough described like this:

  • Once a Pricecard is linked correctly to a product, Sitecore grabs all the snapshots and checks if the start dates of the snapshots are greater than the current date time.
  • Then Sitecore sorts all the snapshots descending
  • Finally Sitecore just grabs the first element from that list and evaluates its pricing information

This means, than if the start date of multiple snapshots have been reached and therefore multiple snapshots would be valid, Sitecore takes the latest one to ensure, that at a specific time just one single snapshot is valid.

So for a content author this means, he has to create a snapshot to determine a specific pricing. Once he wants to change that pricing for a specific period of time, e.g. to offer a special price on a special day or a special time span, he would have to create a new snapshot with the new pricing information and and the proper start date. So now the issue starts. Because the author cannot set a specific end date, this price would be valid “forever”. And because we do not want to have that price forever, the author now has to create another snapshot with the old pricing again and the proper start date. This start date has then to be the date, when the special pricing should end. So instead of just creating two snapshots with proper start and end date, the author has to workaround that and create a third helper snapshot to restore old pricing again.

Of course this works, but to be honest is quiet unwieldy. We also asked Sitecore about the possiblity to set an end date on snapshots. The answer was, that they know about that missing feature, and that they are working on implementing that for a later version. But when exactly that feature is implemented by Sitecore themselves is not officially known.

The recommendation of Sitecore then was to implement such a feature on our own.

tenor

How to get rid of this limitation?

The solution is as simple as it might sound. We just implement the possibility to set and end date on snapshots, save that properly and then extend the snapshot evaluation while retrieving pricing information. Sounds easy, right? And yes it is, if you know where to hook in. Let’s have a rough overview of all todos:

  1. Extend the form to enter an end date in addition to the start date
  2. Extend the snapshot to also hold information about end date
  3. Extend the action, which saves the start date to the snapshot to also save the end date to the snapshot
  4. Extend the view to display also the end date in addition to the start date
  5. Extend sellable item and variation sell price calculation to respect the new end date field

Let us start with the task to extend to input form, where an editor can specify the Begin Date. Of course now we would like the user also to be able to specify an End Date the same way.

How do we achieve that?

Quiet simple! I knew this piece of code I need should be in the Pricing Plugin provided by Sitecore. Therefore I simply reflectored that dll to find something close to edit / show snapshot details. After searching a while, I also found the right class GetPriceSnapshotDetailsViewBlock, which you can see below.

2019-11-14 09_43_34-JetBrains dotPeek

So I just took that piece of code and added the new field End Date in the same way Start Date was added. You will see, that I slightly modified the OOTB code a bit also for the standard fields. The reasons for that were, that I wanted to change the date time format a bit when displaying the fields and that I wanted to include another field just in edit mode. But more details later on.

After adding all the stuff properly the new output of the dialog was the following.

2019-11-13 07_40_57-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

So next step is of course, that once an editor sets a proper End Date, we also want this date to be stored somehow on the Snapshot.

To do this, we have to implement a custom DoAction block, which is responsible for taking the properties entered in edit mode and saving them to the entities or components. Again I crawled in the dll and found the proper class DoActionAddPriceSnapshotBlock.

2019-11-14 09_56_12-JetBrains dotPeek.png

So again, I created my own version of that class and added piece of logic to also extract the End Date. The only problem, which now came up was, the issue, how the values were stored on the price card snapshot. Sitecore used a custom command for that. Unfortunately the parameter of that command did not really fit to the new situation of having now also an end date. As you can see, it just accepted a begin date. Of course there were also other overloads of that call, but more or less, they did not fit as well or would lead to a long rat tail I would have to handle. Therefore I decided to just create my own command, based on the given one, and extend also this piece of code to handle End Date properly. The basic implementation can be seen below.

2019-11-14 10_00_09-JetBrains dotPeek.png

My custom implementation is really nothing more, than a command with another endpoint also accepting the parameter End Date and a piece of logic to include the End Date into the snapshot.

2019-11-14 10_02_03-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

Because we are in a an environment, where we prefer composition over inheritance, I had to create a new component, which in the end holds the End Date property.

2019-11-14 10_08_46-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

If Sitecore implements that feature on their own, I am pretty sure, they will just add another property directly in the Snapshot component, like it was done with Start Date. But in the end it does not matter if the End Date property is located directly in the Snapshot component or in another child component. You just have to know where it is for later usage. But that’s already all the magic to set the End Date Property from the point the editor enters it to the point it is part of the Snapshot. Below you can now the the result, after saving.

Note: Here you can already see, that I changed the output date format also a bit to also display time and not only date, which makes it much easier for editors to set Start and End Date minute-by-minute.

2019-11-13 07_43_46-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Now let’s come to the more interesting part of the implementation. After we have successfully set the End Date we of course also have to evaluate it properly. To do that, I had to find out, where the Snapshots are evaluated at all to also hook in there.

After some time crawling through the dll, I found exactly, what I needed. CalculateSellableItemSellPriceBlock for sellable items sell price calculation and CalculateVariationsSellPriceBlock for variants of sellable items sell price calculation. Within these classes you can see, that the calculation included functions like ResolveSnapshotByCard and ResolveSnapshotByTags, which in the end use functions like FilterPriceSnapshotsByDate and FilterPriceSnapshotsByTags.

2019-11-14 10_16_22-JetBrains dotPeek

2019-11-14 10_16_41-JetBrains dotPeek

In the screenshots above I highlighted exact the location in code, where the snapshot is evaluated. The only thing now we have to do is, that we have to also include the new End Date in that calculation. For demonstration reason I chose the approach to create new classes, one for sellable item sell price calculation and one for variations, the inherited from the existing once and just overwrite the virtual functions to include our new evaluation.

In the End the functions in the new class look like this.

2019-11-14 10_20_56-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

2019-11-14 10_22_41-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Just a simple evaluation if the End Date has not been reached.

Note: You can see here already an extension I made for End Date evaluation, which I describe in the end in more Detail

Now let’s see all that in action. I created a Pricecard called Demo and attached it to my demo product.

2019-11-13 11_16_20-Rechner

Then I created two snapshots on it. One snapshot should be valid from now to some date far in the future (or has no End Date). And one snapshot should only be valid for just a small time span, in this case just a few minutes. After that, the price of the snapshot before, should automatically take over again, without the need to create a third snapshot. The two snapshots can be seen below.

2019-11-13 11_21_48-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

2019-11-13 11_25_07-Rechner

2019-11-13 11_25_13-Rechner

Now let’s put that sellable item into the cart and see what happens over the time.

We start with a time after the start date of the “normal” price and before the start date of the “special” price.

2019-11-13 11_24_26-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

The result is exactly, what we wanted to have. Because the first snapshot is valid and the second not, Sitecore uses the price from the first snapshot to calculate sell price.

Now let’s call the cart a bit later. The time now falls into the start date of the first AND the second snapshot and also is located within the first and second snapshot end date. From Sitecore OOTB logic, it now should take the snapshot, which start date is closer to the current date time.

2019-11-13 11_41_34-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

And this is also the case, like seen in the screen above. Sitecore uses now our special price instead of the normal price, when we call the cart again.

Last but not least we now want to test the really interesting case. What happens now if we call the cart at a time, where both snapshot start dates are matching, but the end date has expired. We would expect now, that because the end date of the special price snapshot has expired, Sitecore automatically chooses the normal price snapshot again according to the new implementation.

2019-11-13 12_05_58-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

I know the sceeen above looks a bit wild, but displays exactly what happens. When we call the cart again at a time after the end time of the special price, Sitecore really takes the normal price again. As you can see the start and end date of the normal price match. And the start date of the special price matches. But because the end date, displayed in red, does not match, Sitecore does not use that snapshot, like it would do in standard implementation, but uses the first snapshot and uses its price as a valid sell price.

Note: Of course we could come into the situation, where no snapshot is valid, because all the end dates would be reached. But that is also no problem. In such scenarios, Sitecore’s own fallback takes over and uses as fallback to the price card logic simply the list price directly set on sellable item. But of course, if this price would not exist you are screwed and the sellable item would not be sellable anymore and would lead to an error, if trying to add to cart.

Now let me finally show you one little extension I already made, while implementing End Date handling. I believe, that there are scenarios, where some basic price really should have just a start date and no end date. Because the OOTB Date Time field always needs a value to be set, I worked around that and created in addition a small checkbox to let the editor decide, whether the really wants to set an end date. In case he want, he just checks the checkbox and everything is like described above.

2019-11-13 12_16_15-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

In case he does not check the checkbox, the DoAction block I created just ignores, what was transmitted in End Date field and simply writes DatetimeOffset.MinValue into the End Date property. This then can later on be checked and treated e.g. like an non existing value in display, like seen below.

2019-11-13 12_16_59-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

And as seen before in the sell price calculation we can also react on that specific value to avoid End Date evaluation. This way, in case you do not set an End Date for a snapshot it acts exactly as it did OOTB before.

Conclusion

Within this blog post I showed you easy it can be in general to implemented some missing feature in Sitecore XC. I showed how to start, where to look any how to hook in correctly at the specific locations, which need to be changed.

Within this special change we created a feature, which allows the editor to set additionally to the start date also an end date for price card snapshots to be even more flexible in creating complex pricing scenarios.

As always the full demo code can be found in a repository on my github and as always this code is not production ready and should be used used as an entry point or for demonstration reason.

https://github.com/Chris1415/Plugin.Sample.Pricing.Pricecards

Sitecore XC – Usage of Composer Templates vs. Entity Components

Sitecore XC – Usage of Composer Templates vs. Entity Components

This time I would like to share some thoughts on the topic of how to extend your commerce entites.

If you are already working with Sitecore XC you will most probably know, that commerce entities in general are extended via components. So if e.g. your sellable item entity needs more properties, like nutrients or allergies for food products you would just create a new component and “attach” it to the sellable item.

From version 9 on Sitecore introduced a new application Composer, with which it should be very easy to extend all kind of OOTB commerce entities. If you would like to know more about Composer in general, I would recommend you to read one of my articles about Composer. In general with this Composer application you can create new custom views with all kind of custom properties. You can then link that new view to any of OOTB entities like sellable item, customer, catalog, category etc. And if you now e.g. use Merchandise tool to see the sellable item and edit it, you will directly also recognize all the new custom views and properties created via Composer and linked to that entity. So without writing a single line of code you are able to completely customize and individualize all you entities and maintain them directly.

So the question at this point would be:

Why should you not use that fancy feature?

The answer of course is not so easy. Let us have a closer look at Composer and how to really work with it in a real world scenario.

Composer in real world

In one of my Sitecore XC projects, we were faced the task to extend standard sellable item with quiet a lot new properties. The version we started was at this time was 9.1.  And because of that, the first approach which came into my mind was to use Composer. I already knew about one disadvantage of using Composer, which I directly wanted to work around. If you create a new composer template within e.g. your local instance, it might work perfectly fine. But the trouble already starts, when you try, to bring that newly created composer template to other DEV instances, testing or production. There is currently no OOTB way of deploying such templates to other environments. You can just create these templates and link them to other entities. This would later on lead to massively different instances, which is not track- or maintainable anymore. Because of that, the community already thought about some workarounds to overcome that issue, so that compser templates are deployable again.

For my solution I was building, I decided to use Code First Approach. Once you created a new template, you would, as usual, check in this file into your repository, where it is getting versioned and shared among other DEVs instances and later on in release management also on other environments like TEST or PROD fully automated.

And at first everything went well so far. I was able to programmatically create all of my new custom views and link them correctly to my sellable item entities. I was also able see and edit these new views and properties in entity view. OK, to be 100% honest, I was able to create and maintain all of my custom views for sellable item entity. But what about variants of sellable items? You might now, that variants of sellable items are no entities. Variants themselves are handled as components, which extend standard sellable items. If your now try to extend properties of sellable item variants, instead of sellable item, you will quickly find out, that this is right now not possible at all. At the moment, you just can link your composer templates to entities.

2019-09-08 14_20_33-Test.png

This means, that you cannot use composer to extend sellable item variants. To extend sellable item variants, you have to use plain, “old” components and do it on your own.

Next step was now to import product data from some web service to Sitecore. And here the odyssey started. I struggled a lot with adding data to composer generated custom views, but because if some reasons. For some of my issues I also created Sitecore support ticket. And one of the ticket also pointed out to be a bug in the system. But let me explain in detail, so you don’t have to go through all of that on your own.

It all started with the question of, how to access programmatically composer generated custom views. Of course Sitecore XC offers calls for creating, editing and retrieving sellable items in general. Now, based on the assumption, we correctly created or retrieved our sellable item entity, where do we find our custom views, so we can edit them? unfortunately the answer is not that easy, so I just provide you some code, which I wrote for my case, which does the job.

2019-09-07 19_36_14-_new 5 - Notepad++

  1. Grab the sellable item
  2. Use GetEntityViewCommand to grab sellable items entity view
  3. Find the view you would like to edit
  4. Grab the EditView of that specific view
  5. Iterate through all the properties you want to edit and edit them
  6. Use DoActionCommand to save all the changes

As you can already see, such an approach is more complicated than you would usually edit a sellable item with components. In addition with more and more custom views you edit, the performance of the overall import process is getting worse and worse. And not only that. I encountered the strange behavior, that from time to time the properties were not correctly added or edited for the custom views. Some times it worked and some times it just did nothing.  But OK. For now I accepted that, and created a support ticket to be sure, it is not a bug or something like that.

And after implementing the basic code for importing everything, I started testing various scenarios like, edit existing item, create item and add data, delete the item and recreate it, and also delete composer template and recreate that, to be sure, that all these scenarios work in other environments without any problems. But while testing around, I encountered another strange behavior. The situation was, that I created a sellable item with custom views. I added some data to that item and filled the custom view. Now I wanted to delete the composer template, recreate it and import the data again to the sellable item. The problem now was, even after deleting the composer template, the filled custom views were still present on the sellable item. And even worse, after recreating the composer template again, the custom view was present on the sellable item twice. One time filled from earlier test and one time new fresh empty one. I was not able to remove the custom view, until I completely deleted the current sellable item and recreate it. After doing that, it again just had all the custom views just one time. Because that really was a strange issue, I also created a support ticket for that behavior.

Support Tickets with topic Compser

  • Out of support scope – Properly fill composer properties programmatically
  • 278078 – Sitecore XC: Composer generated views are displayed multiple times on sellable items

2019-07-21 16_40_32-.png

 

To be completely honest, I created some more support tickets, than these two. But all the other tickets had some other issues while implementing an importer. And of course in future blog post I will keep you informed about newly found and registered bugs. For now we just have a look at these two tickets about composer. The first one, was unfortunately out of scope as part of Sitecore support. The problem was, that basically the code works, but just did not add values from time to time. To resolve that issue, I was asked to directly contact  regional Sitecore representative to get help from the Professional Services team.

Let’s have a look in the meantime at the other issue. After some discussions the issue was registered as bug under the reference number 278078. So right now, you might get trouble when you use composer templates on your entities, fill them, delete the templates and recreate them. And right now there is no easy way of overcoming that issue, other than rewriting some really basic composer code.

So while struggling with all these kinds of issues, I was able to talk also with an architect from Sitecore. You remember, that this was the advice of Sitecore support I followed now. After a short discussion it pointed out, that composer might not be the best choice considering the current situation and how I use it.

And I have to admit, that I fully share that opinion after I really tried to integrate that new feature into the development workflow. It is still a quiet new feature with a few weaknesses, which have to be overcome first to unleash it’s full potential. But if we do not use Composer to extend all our sellable items, the question now is:

What can we use instead of using Composer?

Back to the roots – Why not using just components directly?

You really don’t have to use Composer to extend any kind of commerce entity. Before Composer was introduced, there was a pretty standard way, of how you can extend all kind of commerce entities on your own. You just created a new component, with all your properties you wanted the entity to have.

2019-09-08 14_27_39-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

Sitecore also has some helper functionality OOTB, with which you can easily get, create and set custom components on entities to maintain your custom components.

2019-09-08 14_28_38-Alnatura.Experience.Commerce - Microsoft Visual Studio  (Administrator).png

2019-09-08 14_29_40-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

In the end, after getting the component and setting your properties, you just have to persist the entity again to the database, and that’s it.

2019-09-08 14_30_20-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

So for an importer process, it’s also nothing more, than this. Instead of finding custom, edit views, adding properties there and calling a magic DoActionCommand in the background for each view you changed, you just grab the sellable item, grab the component with the OOTB helper, set the properties and in the end, as usual, persist entity. And I guess this might be the plainest, easiest and most performant way of editing custom properties of your entities.

I already tested this approach with 8 custom components with more than 80 custom properties, which extended the standard sellable item entity, and the importer was definitely not that slowly, than it was, when using the composer based approach.

2019-09-08 13_12_51-Support.pptx - PowerPoint.png

2019-09-08 14_39_30-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

But I would say, we have one big disadvantage of using this approach. When using Composer to create templates, these templates and respective the custom views, which can be seen in the screenshot above, are directly visible and editable on the linked entities. This benefit, we do not have, when creating and adding components directly to our entities. To see and edit the new properties of our entities, we have to implement some further logic, which extends the standard entity view, in our case the sellable item entity view, with all our new components. And with exact this way we also can extend our sellable item variants. If you would like to know more, about how to extend Business Tools, and in this case entity views to see and edit custom properties, I would strongly recommend you, to read this article of me, where I describe in detail the process with the example of creating and extending the cart entity view.

So of course this produces a bit more work to get everything working, but I guess at the moment, for this scenario, I was faced to, it is still the better approach, because in the end, if something does not work as expected, you can completely customize or work around everything.

You might now remember the code from the beginning, where I showed, how to edit custom view of sellable item. I will now show you, how the code changed now in importer.

2019-09-08 14_33_34-Alnatura.Experience.Commerce - Microsoft Visual Studio  (Administrator).png

So you see, that this piece of code definitely became much easier, than before. Instead of duzend of lines of code for preparation and retrieval it is more or less just one line of code for retrieval and X lines for X properties to change.

Conclusion

Within this article you learned, that there are various ways of extending Sitecore XC entities with custom properties. You saw, that the newly introduced Composer application might look cool and in general has a lot of potential to make the life of authors and developers much easier. But right at the moment you clearly have to weigh well, if Composer is the right tool for your business needs and requirements. If not, don’t be afraid of using plain, old components directly. It might lead to more work in the beginning, but in the end it might safe you a lot more time.

Extend Sitecore XC Business Tools – The real meaning of data driven UI

Extend Sitecore XC Business Tools – The real meaning of data driven UI

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

2019-05-26 20_20_32-logs

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
  • IGetEntityViewPipeline
  • IFormatEntityViewPipeline
  • IDoActionPipeline

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.

2019-05-27 21_21_27-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

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.

2019-05-27 21_17_46-Customer.Sample.Solution - Microsoft Visual Studio  (Administrator).png

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.

2019-05-27 21_30_15-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

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.

2019-05-27 21_40_05-Customer.Sample.Solution - Microsoft Visual Studio  (Administrator).png

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.

2019-05-26 20_26_38-Custom Dev Ops

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.

2019-05-26 20_26_52-Summary

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.

2019-05-27 22_09_19-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

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.

2019-05-27 22_11_53-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

2019-05-26 20_27_02-Summary

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

2019-05-27 22_13_39-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

2019-05-26 20_27_10-Summary

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.

2019-05-27 22_17_30-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)2019-05-27 22_18_04-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

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.

2019-05-26 20_27_19-SummaryThe 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.

2019-05-26 20_28_00-SummarySo 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.

2019-05-27 22_23_39-Customer.Sample.Solution - Microsoft Visual Studio  (Administrator).png

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.

2019-05-27 22_27_44-Customer.Sample.Solution - Microsoft Visual Studio  (Administrator).png

2019-05-26 20_28_07-Summary

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.

2019-05-27 22_29_44-Customer.Sample.Solution - Microsoft Visual Studio  (Administrator).png

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.

2019-05-27 22_33_14-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

2019-05-26 20_28_24-Summary

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.

2019-05-27 22_34_50-Customer.Sample.Solution - Microsoft Visual Studio  (Administrator).png

2019-05-26 20_29_18-Summary

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.

2019-05-26 20_27_19-SummaryIf we would click them now, just an empty or nearly empty dialog would open with an accept and reject button, nothing more.

2019-05-28 19_26_46-Summary

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

2019-05-26 20_27_27-Summary

2019-05-26 20_27_45-Summary

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.

2019-05-28 19_35_33-Customer.Sample.Solution - Microsoft Visual Studio  (Administrator).png

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.

2019-05-28 19_45_17-Customer.Sample.Solution - Microsoft Visual Studio  (Administrator).png

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.

2019-05-28 19_50_56-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

The first special thing in the form view, is that based on the selected line item, we extract the current quantity as default value.2019-05-28 19_51_15-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

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.

2019-05-26 20_27_34-Summary

2019-05-26 20_27_52-Summary

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.

Voucher Actions

This slideshow requires JavaScript.

Physical Fulfillment Actions

This slideshow requires JavaScript.

Gift Card Actions

This slideshow requires JavaScript.

The code of all these implementations and the whole Carts application can be found in my github account under the following url

Conclusion

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.

Bring your Sitecore XC deployments from the Stone Age to the future – How to deploy server specific environments fully automated

This time I would like to share some thoughts on a topic every developer will be faced, at least if the topic CI and CD comes up and you would like to completely automate that process for your Sitecore XC instance as hopefully most of you are already doing with your Sitecore XP implementations. For that I would like to describe first of all the general process of how to deploy an instance of commerce engine. After that, I will point out the limitations of that OOTB process and what problems now come up. In the end will will describe the newly introduced approach of solving that problem and show the results of that implementation.

How to deploy a commerce engine

Let’s first have a look at the topic of how the commerce engine is deployed in general, to understand later on, what we have to change in that process to realize server specific automated deployments.

From what we learned from the Sitecore documentation is, that in general there are 3 different ways to deploy commerce engine

  1. Visual Studio Publish
  2. Command Line Tool
  3. Inside a build environment

Visual Studio Publish: To deploy your commerce engine via VS publish, just open the commerce engine solution. Then right click on the Sitecore.Commerce.Engine and click Publish (Veröffentlichen). In the new screen you can now switch various kinds of publish methods.

2019-05-05 21_18_48-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

If you open that screen with the OOTB commerce engine SDK the filesystem publish method is already setup initially.

2019-05-05 21_19_16-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)2019-05-05 21_19_11-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

Just double check if the target path of the publishment is correctly and fits for your engine. After you finished that, just save the settings and execute the publishment.

Command Line Tool: The second way of how to publish a commerce engine is, via command line tool e.g. cmd tool. To do that, just navigate to the root of your commerce engine solution and execute dotnet publish command there with proper parameters.

2019-05-07 18_35_30-Administrator_ Eingabeaufforderung

dotnet publish {SOLUTION NAME} -f {FRAMEWORK} -c {BUILD CONFIGURATION} -o {PATH TO PUBLISH} -r {RUNTIME}

If you do not set the proper parameters for your environment the result of the publish might work, but if you try to use that engine and work with that, you will most likely get some IIS server error telling you the engine started but stopped again.

You can also either way choose the output path as any folder and copy the output manually to the proper location, or directly give the right path of your engine.

Note: To publish commerce engine to your IIS instance, make sure the current engine is not in use by either way reset or stop IIS for the time of the publish or copy process.

Inside a build environment: This way I will not describe in detail, cause it is highly dependent on your specific build environment. Depending on the environment you will most probably have different board tools of how to deploy a .NET Core application properly.

What are the problems now?

If we are working locally and just want to publish our instance for development reasons to our local IIS everything is totally fine so far and everything is working as expected. But of course we do not only want to deploy our code to the development engine locally, but also to some other servers like testing or productive environment.

And at that point we know already from our Sitecore XP solution, that there are various settings or configs, which are dependent to the specific environment. Examples for such files are connectionstrings.config, datafolder.config, transformations of the web.config and so on. Of course also Sitecore XC has configuration files. These files are called environments. If you want to learn more about environments, I recommend to first read that blog post of me, where I described environments in detail, what they are, how they are structured and how to adapt them.

Of course also in Sitecore XC we will also reach the point, where we need server specific settings, like in Sitecore XP. Scenarios of such settings could be endpoints of interfaces, which differ from local, to testing, to productive servers or just credentials or accounts to database.

In various projects I was able to see, how others deal with that kind problem. The overall result was, that some developer all the time deploys commerce engine manually by doing for example the steps described below

  • opening Visual Studio
  • building the solution
  • removing all the configs (for now)
  • zipping the output package
  • copying that package to the target server
  • unzipping that package
  • replacing all the files with the output package
  • manually go into each environment compare that environment with the one of the deployment package and edit that file piece by piece

You see, that such a deployment consists of many manual, time consuming and error-prone single steps. If you just do one little mistake in one of these steps, deployment will most probably fail. Results could lead from harsh server errors to hidden errors in implementations, which are found by chance. afterwards.

The aim of course should be to completely automate such a process to rule out human errors and minimize deployment time. In the next chapter I will introduce an approach of how to overcome all these issues by having easy maintainable server specific environment json files with .NET Core.

Approach of solving that problem

Of course I can imagine there are various ways, of how to overcome such problems within Sitecore Commerce Engine. In this article I just concentrqte on an a very generic and plugin like approach. The approach I will describe in detail now consists of various small changes and adaptions made in the solution at various places

  • Creation of new ASPNETCORE_ENVIRONMENT specific environment files
  • Creation of new plugin to handle the new environments on bootstrap command
  • Transformations of web.config to set ASPNETCORE_ENVIRONMENT

Together all these changes now make it able to use your own CI / CD systems to deploy the commerce engine fully automated.

Creation of new environment files

Let’s start with the creation of new environment files under “\wwwroot\data\Environments”. For demonstration reason I used PlugIn.AdventureWorks.CommerceAuthoring-1.0.0.json and created a new file called PlugIn.AdventureWorks.CommerceAuthoring-1.0.0.UAT-CM.json. You see the that the new file just has an extension shortly before the end. In VS the files look like this

2019-05-07 19_39_34-Customer.Sample.Solution - Microsoft Visual Studio  (Administrator).png

You can see, that VS directly and automatically recognizes the new file as “sub file” of the original one. This mechanism behind that relies on standard .NET Core environment handling. The extension “UAT-CM” is just a new .NET CORE environment I created for later usage. Maybe you already know such files with namings like

  • Development
  • Stating
  • Production

These mechanism are also already used by the commerce engine for example when dealing with config.json and the development variant of that file. This file is handled by OOTB .NET Core mechanisms like mentioned above.

From what I saw there, I got inspired to also use such an approach for our Sitecore XC environment json files. There this standard .NET Core behavior is not applied, cause these files are loaded and evaluated not by .NET Core, but by a dedicated plugin within commerce engine. This plugin just loads all the json files within /wwwroot/data/environments/ and processes them, with no differentiation of .NET Core environments. But that should not stop me ^^. Within the next sub chapters you will see the changes made to the plugin, so that all these pieces of functionalities work for our environment files.

Of course the naming of the .NET Core environments is completely up to you. I decided for now to use the following notations for historical and Sitecore reasons, where you have a local development machine a scaled Sitecore environment for testing called UAT (User Acceptance Testing) and a scaled Sitecore environment for production called PROD.

  • Development (Local deployment)
  • UAT-CM (Content Management commerce service of UAT)
  • UAT-CD (Content Delivery commerce service of UAT)
  • UAT-MINION (Minions commerce service of UAT)
  • PROD-CM (Content Management commerce service of PROD)
  • PROD-CD (Content Delivery commerce service of PROD)
  • PROD-MINION (Minions commerce service of PROD)

Now that we know, how we create and name our new environments, so that they are applied later on correctly, we will have a look at the content of these files.

I decided to offer two different ways of how the content can be added to these files

  • as full replacement
  • as merge / overwrite

Full replacement Mode: To create a new environment, which uses that mode, you just have to create the new environment file based on the original environment file, with all the given settings. Within the new file you now just have to change all the settings, which you would like to change for the specific environment. The rest stays as it is. The way Sitecore later on bootstraps the new environment is now, that it just, based on the given .NET CORE environment loads the new environment specific environment file, instead of the original one. Therefore the new environment specific files always need ALL the settings like the original one, nevertheless they are the same or not. For that file I guess you don’t need an example, cause it completely looks the same, except that the values are different at some places.

Overwrite / Merge Mode: To create a new environment, which uses that mode, you just have to create the new environment file with only the entries, which have been changed. This means, the file consists only the json structure of the entries, which should be overwritten or for arrays merged. Let’s have a look at an example of that file in comparison to the original one.

2019-05-01 11_22_10-C__Code_SXC910Playground_src_Sitecore.Commerce.Engine_wwwroot_data_Environments_.png

Above you can the the complete content of the new PlugIn.AdventureWorks.CommerceAuthoring-1.0.0.UAT-CM.json file. You can directly see, that it is much shorter than the original one. In this

Note: The only important thing you have to obey is, that the structure of the json file should be the same, from the element to change to the root element of the json.

For this demonstration I decided to just change the following settings

  • Sitecore.Commerce.Plugin.Tax.GlobalTaxPolicy,
    • DefaultCartTaxRate from 0.1 to 0.5
    • DefaultItemTaxRate from 0.1 to 0.5
  • Sitecore.Commerce.Plugin.Orders.GlobalCheckoutPolicy
    • EnableQuickCheckout from true to false
  • Sitecore.Commerce.Plugin.Catalog.VariationPropertyPolicy
    • Values from [Color, Size] to [Brand]
  • Sitecore.Commerce.Plugin.Orders.KnownOrderListsPolicy
    • Key Orders from list_style_bullets to list_style_bulletsTEST
    • ProblemOrders from ProblemOrders to TESTProblemOrders
  • Sitecore.Commerce.Plugin.Fulfillment.GlobalPhysicalFulfillmentPolicy
    • Fee for Ground from 15 USD to 150 USD

In the following screenshots you can see, the specific settings of the origin file

2019-05-01 11_23_10-C__Code_SXC910Playground_src_Sitecore.Commerce.Engine_wwwroot_data_Environments_

2019-05-01 11_23_53-C__Code_SXC910Playground_src_Sitecore.Commerce.Engine_wwwroot_data_Environments_

2019-05-01 11_24_14-C__Code_SXC910Playground_src_Sitecore.Commerce.Engine_wwwroot_data_Environments_

Creation of new plugin

Now let’s have a closer look into the newly created plugin to process the environments correctly. I started by investigating where the bootstrap commands ends up in commerce engine and found the following IBootstrapPipeline

2019-05-07 20_36_53-NodeConfiguration_Deployment01_965adef45dbb48458e2cc80329e6859f.log - Editor

Next I used dotPeek to investigate the BootStrapImportJsonBlock to see how Sitecore’s OOTB implementation imports all the environment files.

2019-05-07 20_41_34-JetBrains dotPeek.png

The most interesting part of that block can be seen above. You can see that it just does the following steps to import jsons

  • Grab all files under wwwroot\data\Environments
  • Iterate through all files
  • Make some validation checks if the current file is a valid environment / policy set
  • Based on the information if the current file is an environment or policy set
    • Call import environment command
    • Call import policy set command

My idea now, when I saw that code, was, that I should be able to use that code and modify it in a way, it would be able to also differentiate between .NET Core environment specific json environments. In the following screenshots.

2019-05-07 21_03_15-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

The first change I made in the standard code is highlighted above. I just implemented a piece of logic, which is responsible for loading the environment specific json files in parallel to the original one. The parameter environmentName is based on the current .NET Core variable ASPNETCORE_ENVIRONMENT and reflects exactly the naming used for our environment files. In addition you can see some boolean value ReplaceWithEnvironmentSpecificFile. This is right now some class level property which switches between the above mentioned modes replace and merge. In case of replacement it really just loads the environment specific file instead of the original one. In case it should merge the files you see the behavior below in the next screenshot.2019-05-07 21_04_26-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

That piece of logic just checks again the flag and if a server specific environment exists. If so, the new logic takes action. On high level the idea is very simple. The idea is just to take the both json files and use newtonsoft board tools to merge these two json files loaded as JObjects. Unfortunately this approach is not as easy as it might sound. If you try to merge the two jsons as whole, the result will not be, what we expect it to be. The board tools are not able to correctly merge the two environment jsons, so the result is a file where some of the policies were just added two times or other elements, which definitely do not belong together were merged together. So the solution was, not to use the whole file to merge the jsons, but to break down the jsons in multiple objects and merge these objects individually, some kind of divide & conquer approach. I decided to use all elements, which start with a type property, cause these elements are complex elements. In addition I only choose first level elements with a type property. In the screen below, you can see an example of how the environment file is spitted by the algorithm in smaller elements, which are then merged with corresponding element the original file.

2019-05-07 21_18_46-C__Code_SXC910Playground_src_Sitecore.Commerce.Engine_wwwroot_data_Environments_.png

To always iterate correctly through the environment specific file, find the elements to merge in the original file, I also created two helper functions, which achieve exactly this.2019-05-07 21_05_15-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)2019-05-07 21_05_27-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

These pieces of logic just iterate through the json. At first it skips the root level type property. After that it iterates till it reaches other type properties. Once it reached that point, it starts finding that type property in the original file. Once we reached one object with a type property, we stop iterating deeper into that object and just go on with the sibling objects to avoid merging sub objects with type property, which are already merged earlier. And cause we are just grabbing all the first level objects with type property we always grab objects ob type policy, which are unique in the environment specific and origin file, so it can easily be found.

Once we merged every object we found, we just come back and produce the json string of that merged file again, so it can be used afterwards in following processes.

Transformations of web.config

Now after we created the new environment files and the new plugin to process these files, we finally have to deal with the problem of how to set the ASPNETCORE_ENVIRONMENT correctly for the server. From what I already read in various posts, there are many ways of achieving that goal. You can

  • start the engine with the environment parameter
  • set it IIS wide
  • set it machine wide
  • set it on the website
  • set it in VS publish process
  • and so on

For now I decided to set the parameter on website level, furthermore within the web.config file. An example of the web.config can be seen below.

2019-05-07 21_36_15-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

In addition to that entry I created various web.config transformation files, which react on given build configuration parameter. Below you can see web.config transformations in the naming convention, we already know from earlier.

2019-05-07 21_36_43-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

Each of these files at the moment just overwrite the ASPNETCORE_ENVIRONMENT parameter with the correct value. So for example web.UAT-CM.config sets ASPNETCORE_ENVIRONMENT variable to UAT-CM and so on.2019-05-07 21_36_55-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

To trigger these build configurations I finally created them also in VS als build configurations, like seen below

2019-05-07 21_41_59-Customer.Sample.Solution - Microsoft Visual Studio (Administrator)

Results

So what is now the result of everything?

Now with all the changes we can use the dotnet publish command in the following way, very similar to the one you saw in the beginning, but slightly different in the configuration parameter

2019-05-07 21_45_34-Administrator_ Eingabeaufforderung

The outcome of that command is a fully working deployment package, where the web.config has the patched entry, we will use later on in bootstrap command

2019-05-07 21_48_24-Deploy.png

If we now deploy that engine to the right place the new ASPNETCORE_ENVIRONMENT parameter will take place on startup for that specific website

Note:  We could also deploy that directly to the right location or use some smarter powershell script to do that job like seen below. For local deployment I just created a small powershell script, which takes over all the manual steps I would have to do

  • takes some parameters
  • publishes the application,
  • stops IIS,
  • copies the deployment package to the destination,
  • starts IIS again,
  • grabs token from Identity server
  • and finally calls bootstrap

2019-05-07 21_59_43-_C__Code_CommerceEngineDeploymentScript.ps1 - Notepad++2019-05-07 22_01_05-_C__Code_CommerceEngineDeploymentScript.ps1 - Notepad++.png

Now it is getting more and more interesting. After we successfully deployed all the latest changes and called bootstrap we can now see the results. For better visualization I just saved the merged file together with the original one and used Notepad++ compare tool to compare these two files to see all changes.

2019-04-28 19_03_35-C__PlugIn.AdventureWorks.CommerceAuthoring-1.0.0_Orignial.json - Notepad++2019-04-28 19_04_29-C__PlugIn.AdventureWorks.CommerceAuthoring-1.0.0_Orignial.json - Notepad++2019-04-28 19_05_38-C__PlugIn.AdventureWorks.CommerceAuthoring-1.0.0_Orignial.json - Notepad++2019-04-28 19_06_08-C__PlugIn.AdventureWorks.CommerceAuthoring-1.0.0_Orignial.json - Notepad++

What are the results?

The results are exactly what we except them to be! All the settings we initially patched in the server specific environment are correctly taken over in the merged file. If we additionally have a look how commerce engine deals with the new environment json file, I just had a look at the outcome of the ImportEnvironmentCommand, which takes our json as string, saves that to DB and returns an environment objects. The screens below show the values of the properties we wanted to be changed cause of merging.

2019-04-28 19_20_33-Customer.Sample.Solution (Debugging) - Microsoft Visual Studio (Administrator)2019-04-28 19_20_52-Customer.Sample.Solution (Debugging) - Microsoft Visual Studio (Administrator)2019-04-28 19_20_11-Customer.Sample.Solution (Debugging) - Microsoft Visual Studio (Administrator)2019-04-28 19_21_17-Customer.Sample.Solution (Debugging) - Microsoft Visual Studio (Administrator)

Also here you can see, that Sitecore accepted the merged Json file add was able to create a usable environment file with the merged values of the parameters.

The whole plugin can be found under https://github.com/Chris1415/Custom.Sample.Plugin.CI

Conclusion

Within the today’s blog bost you learned about problems, which might occur when deploying your commerce engine to some other servers than local development. You saw the challenges and how deployments are done nowadays at some places. But in the end you also saw an approach of dealing with that problem to be able to fully automatically deploy your commerce engine based on the target environment.

And as always the code you saw here is just for demonstration reason and not deeply and fully tested. This should be just an entry point for you to get into that topic and get an idea of how to solve the given problem.

Sitecore XC 9.0.3 – Extension of NodeConfiguration log to detect recursive Calls from additional Pipelines and Command

Today I would like to introduce a newly created plugin, which helps developers to better understand what is happening behind the scenes of commands, pipelines and blocks.

Everyone who is working with Sitecore XC already knows, that one of the core principles of commerce engine is the usage of pipelines. Once you have to run a bigger or longer running task, you easily trigger a pipeline via corresponding command, which then let various blocks do the work.

For better maintenance of that construct of pipelines and blocks, Sitecore itself provides us with the ability to have a look, which pipelines are existing in the engine and which blocks are inside. This overview is really, really great and helpful and already saved a lot of time, while debugging and creating new functionality. But lately I encountered problems, where this OOTB information were not sufficient enough. So what I did now, was to extend that the given information to solve my problems.

But for all of you, who do not know that standard mechanism of monitoring your pipelines, I will shortly recap that for you, before I explain the extensions made to that.

NodeConfiguration

The standard mechanism of debugging your pipeline is, that on startup of the commerce engine a custom log file, the so called NodeConfiguration log file is created. That file holds on the one hand some standard and basic information about the current state of the engine. But on the other hand it also has information about ALL configured pipelines with all blocks included in the pipelines. Also all input and output parameters are given in that file. Below is an example of the output of that file.

bild6.png

Scenarios, where I already used that file very often were for example, when I had to create new functionality for special parts of commerce engine. In such cases, I used that file, to see, which pipelines with which blocks are already existing and where I could hook in with custom block. But this file was also very helpful in debugging given code to see in which pipeline the given block is called, what other blocks are called in that pipeline, to get a better overview of the overall context of the code I had to debug.

Recognized limitations

But now let’s come to the point, where I took all information of the given file, but still had a lack of information I had to cover with lot’s of manual work. All of you, who read my last block post, already know about a problem a recently encountered. The main problem was, that the code I had to investigate produced some inconsistent results to the entities, but was spread not only over various blocks within one pipeline, but also over various blocks over various pipelines, which were extensively nested inside each others.

At this point I encountered a big limitation of the given NodeConfiguration file. Of course it was helpful to determine the correct pipeline of the given blocks. But I had no idea, what the blocks did behind the scenes. What I did then, was to create a new text file. At the beginning I added the pipeline I knew with all the blocks. Then I had a look at each block individually, custom code AND Sitecore code to see, what is happening inside. The aim of that was, to see, if any of these blocks itself again call a pipeline and therefore create a new level of nesting. After I finished that I had a text file with nested levels of pipelines, blocks command and so on, like you can see below.

2019-03-25 13_50_37-D__Logs von UAT_Mit holen einer neuen Order in Payback_PipelineOverviewRefund.tx

With that manually created file I know was able to see, at which pipeline the processing started, which blocks were inside and which pipelines, commands or other code was called from within these blocks to discover extensive nesting. The aim of that specific file, was to find out, where entities are grabbed from DB, from context or from args of pipelines and when these entities are saved back to DB. The issue was described in detail in my last blog post.

But because creating that file took a lot of time, I thought about a possibility to automatically create such a file in that way to determine nested pipelines / blocks / commands. The result of these considerations is now the newly created PipelineMonitoring plugin.

Custom Pipeline Monitoring

Of course now you will ask yourself:

  • What does the new plugin do?
  • What are the benefits of using that plugin?

Let us start here with the first question, what the new plugin does. In the end, I just created a new block similar to the block, who is responsible for creating the NodeConfiguration log file and hooked in, into the same pipeline after that block. This block now creates on startup of commerce engine a new log file currently named PipelineMonitoringXXXXXX.log The information visible in that file are nearly the same, than in NodeConfiguration log file. But it has 2 major improvements, which make it more valuable than the standard log file.

The first improvement is, that you can not only see all pipelines with corresponding blocks, but also nested pipelines and commands.

The second smaller improvement is a small declaration in the beginning of the pipelines, blocks and commands. The new plugin is able, with some additional information, to determine what pipelines, blocks and commands are OOTB and which are coming from custom code. With that annotation you can directly and clearly see and differentiate Sitecore code from custom code, which also helps developers to debug pipelines and blocks.

An example of the output of the file can be seen below.

2019-03-25 13_59_17-192.168.101.10 - Remotedesktopverbindung

You can directly see, that the basic formatting is the same than in the standard NodeConfiguration log file. In our example, we see a new pipeline created in commerce engine. This pipeline consists of three blocks. Now the extended information take place. Below the two blocks CheckTicketBlock, ActivateTicketBlock and PersistEntityBlock, we now can see, which pipelines or commands are called from there. In our example we can now directly see, that the ActivateTicketBlock itself consists of two further commands, the FindEntityCommand and PersistEntityCommand. Behind these two new commands, we can also see in that files, which new pipelines are executed and used. And if we reach the level, that we again see, that a new pipeline is used, the nesting stops, because at this place you are able to see whats behind that pipeline, because that pipeline is described already in detail within that file. So you just have to search for that pipeline in the file and have a look there, what’s exactly behind that.

From our scenario now, when we start examining the given pipeline, we can directly see one new information, which would be not visible in standard log. We have an ActivateTicketBlock, which not only grabs but also persists the entity and in addition we have a special block which also takes the entity and persists it in the end. So you could say the persisting is done redundantly. Of course you should check, what exactly is grabbed and saved back to DB. But in our example it was exactly the same entity. So as an improvement you are now able to go into the ActivateTicketBlock and remove the PersistEntityCommand, because the last block of the pipeline is already doing that.

In addition with the output <CUSTOM> in front of the pipelines, blocks and commands you can directly see on the first look, whats standard Sitecore code and whats custom code, which again makes it much easier to find problems or modifications to the standard behavior of Sitecore XC. To use that specific feature of the plugin you just have to do one small thing within your plugins. To be able to differentiate between OOTB code and custom we in this phase of the plugin I use a special attribute set on the assembly info of the project. While grabbing the pipelines, blocks and commands, the system knows from which assembly this code is coming.

[assembly: CustomAssembly()]

2019-03-27 15_41_52-192.168.101.10 - Remotedesktopverbindung.png

Now let’s come to an additional feature of the plugin. This feature is about how you can use these new information within your solution. Of course it is useful to get that new log file with all the new information. But it still stays a simple .txt file, where you are really limited in outputting all the new data in a nice way.

Because of that I also created an OData compliant API call for retrieving all the new information as JSON to output them on your own with all the fanciness you want.

The call which can be used is quiet simple

{{ServiceHost}}/api/GetStackedPipelines()?$expand=Components( $expand=ChildComponents( $expand=ChildComponents( $expand=ChildComponents)))

As a result you get a data structure which is quiet similar to the output of the standard pipeline configuration output except all the new information.

Note: You might already saw one I would say strange thing with the call. It is about the $expand operator, which is in this case used to grab child components recursively. And here is already the problem.In theory the data structure could be continued with all the child’s and child’s of children endless. When we just call the API without any parameter, we would just retrieve the first level of entities. With the $expand operator, we tell OData to also include special property into the output . In our case all components of our first level pipeline entity. But then the problem starts. How do we extend all the block entities with child components, which are themselves again block entities.

From what I tested and read, this is OOTB not possible right now in our version with OData to give for example a parameter which tells $expand with a parameter like

{{ServiceHost}}/api/GetStackedPipelines()?$expand=Components($expand=ChildComponents($level=5))

https://databoom.wordpress.com/2015/06/05/odata-rest-api-and-recursive-queries/

Therefore as a workaround I duplicated the expand operator some times, which also produced a sufficient result for cases I needed. The following image shows an example of a custom pipeline, with all blocks, and recursively called commands and pipelines presented as JSON.

screencapture-jsonprettyprint-json-pretty-printer-php-2019-03-27-16_04_06.png

Last but not least I will also tell you, where you can find the new plugin, so you could have a look, download it, use it and of course if you want also modify it for your custom business needs. As always this implementation is not production ready and just an example of how the given problem, the lack of information, can be solved.

https://github.com/Chris1415/Sitecore.Commerce.Plugin.PipelineMonitoring

Practical experiences with Sitecore XC – Some useful best practices

Every Sitecore developer and enthusiast should by now have already heard about Sitecore Commerce or better Sitecore XC. This product is already existing for about 2 years now and has run through big transformations. From the old days, where Sitecore Commerce meant using a Microsoft Commerce Server connected to Sitecore via Commerce Connect; through the beginning of the transformation where Sitecore introduced the revolutionary Commerce Engine, which was initially introduced and worked in some kind of hybrid mode with the old Microsoft Commerce Server; till nowadays, where Sitecore Commerce is called Sitecore XC and only consists of the new Commerce Engine without any need to have the Microsoft Commerce Server.

Within this little article I would like to tell a story about this journey, from a developers perspective, which means, how were the developers confronted with the new technology, what were various pitfalls and how you were able to overcome these pitfalls. Of course the focus will be on the experiences with the very latest version of Sitecore XC (9.0 Update 3). The aim is, to give all of you an idea, what it means to get confronted with the task to implement a Sitecore XC solution and hopefully to give you some ideas, how to avoid pitfalls to make your life easier with some personal best practices in the end.

From what I heard, at least from the German community, and maybe also other communities from all over the world,  Sitecore XC is still some kind of magic, which terrifies even self-confessed Sitecore developers. But kidding aside, Sitecore XC is quiet a huge topic with various new architectural concepts, frameworks and ways how to implement a solution. Hopefully with this article I can calm some of you down and show that Sitecore XC is magic, which can be unboxed and mastered.

2019-01-08 15_52_08-präsentation1 - powerpoint

The daily business situation

Let’s assume you are now a Sitecore developer and some of your customers ask you, if they should use Sitecore XC for there next commerce project. What can you do now to advise the customer professionally and convince him to use Sitecoere XC. And a even better question, how can you, as a developer, get quickly into this black box topic Sitecore XC .

I myself was facing exactly this problem some time ago and to be honest I am still learning today and most probably will never stop learning and experiencing new aspects of Sitecore XC. So my first advice is: Never stop learning. Even if you think, you know everything, I can promise you, there will be customer requirements or situations, where you have to dig even deeper into the system and learn new aspects of Sitecore XC.

Where to start

The next question is, where to start learning, if you never have been confronted with  Sitecore XC. In the very beginning of Sitecore Commerce 8.2.1 there very nearly no documentations available, except of the official Siteocore documentation. My approach then to learn more about Sitecore Commerce was

  1. Read the Release Notes / Sitecore Documentation
  2. Install the Demo Storefront
  3. Play around with the OOTB features to get a rough overview

After doing these three steps I had a good overview, what Sitecore Commerce means, where the strength are and how to use it. Of course you can use the same approach for every new topic and newer versions of Sitecore XC. What I personally always do, when a new Sitecore XC release was published, I do all the three steps again. I read the release notes to get informed about the newest features, I install the newest demo storefront and play around with the new features.

Note: Nowadays you are in a even better situation, than all of us 2 years ago. Nowadays Sitecore made enormous progress in the product itself as well as the whole  documentation. In addition we have a great community, which helps with answers and blogposts, Sitecore itself provided really cool training (100, 200, 300) to get into the topic commerce, slack, stackexchange and much more. You can see a great list of everything here.

How to go on

The next question is, how could be go on from that point? To read a lot of documentation and play around with the demo storefront is nice, but you will not get practical experiences in working with the product, in this case Sitecore XC. But in my opinion, that’s exactly what you need. In the documentation and demo storefront you will always see the system from it’s best side, so the best case scenario, where everything works perfectly fine. But what happens, if we go on from that point? What happens, if be implement our first functionality? How will the system react on real business scenarios? Will it be stable? Can it handle that? All these questions should come into your mind at this point. And the only way, how we can find answers to all of these questions is: Try it out! Start implementing your custom logic. Think of common use cases or scenarios and implement them to see what happens. I can promise you, you will come to the point, where something breaks, or does not work the way you expect it to work.

What I did e.g. was to think of the use case to use Sitecore XC for a German customer. After having a look at the features, I quickly found out, that the OOTB functionality for calculating taxes was build the way, that you can set one specific tax rate environment wide. Unfortunately in Germany and other countries, we have the situation, where we need multiple tax rate per environment, which vary from product to product. So this was the best point to start, writing a custom plugin to see, if I can overcome that lack of functionality with a custom tax plugin.

How to implement functionalities in Commerce Engine?

But here we run into another issue. If you start working with Sitecore XC you will see, that you will not only get a new module or new feature for Sitecore XP, like with the installation of WFFM (Yes I know it’s dead, but a good example 😀 – RIP WFFM), but a whole new architectural concept, with an independent solution based on .NET Core and how to implement pieces of logic for Sitecore. In Sitecore XP e.g. you build pages and modules most likely following the Helix principles. You will always have something like controllers, which use services to do something and get view models to be displayed on views. If you need some kind of settings, you most likely use setting configs under app_config or settings items, spoken very rough on high level.

But if you start on Sitecore XC you will quickly find out, that most of these things are not working this way. And because of that, I think it makes the learning curve even harder. To understand the fundamentals of Commerce Engine implementation takes a lot of time. Most likely you cannot just open the solution and start coding. Most probably then your results won’t be what you want to implement. For me personally it was a real changeover to get into these new architecture of Commerce Engine. After some time, training, reading and testing it became better and nowadays we also have a strong community, which shares also knowledge about how to implement stuff in commerce engine.

From all these sources, daily work and experiences you could derive some Best Practices or DOs and DON’Ts for working with commerce engine and implementing plugins, which might help working with Sitecore XC. Why I just picked this list is because I’ve already come across all these things in my day-to-day work.

Some Best Practices

A Plugin in Commerce Engine is not a Feature in Helix architecture

When you previously worked with Sitecore XP and standard module implementation, like implementing a new image-text module, a stage, or some fancy list, slider or map, you will always have the same approach of doing that. And if you follow some basic architectural guideline, like Helix, you have even more a standard approach of doing such work. When you now start working on Sitecore XC and implement your first feature or better plugin in commerce engine, it happens quickly, that you apply the same architectural guidelines also in commerce engine. When you read the documentation and some blog post, you know about, how a plugin project is structured, and what components belong to a standard commerce engine plugin. The issue, I observed now in some implementations is, that developer handled commerce engine plugins as some kind of feature layer projects within Helix architecture. What does that? It means, that, when you for example have plugin A, which consists of some new Pipelines and Components to extend e.g. your cart and you have Plugin B, which uses the components from Plugin A, the approach was to take out these components from Plugin A, create a new Plugin C, which holds these and many more components from many more Plugins and let reference Plugin A and B to that Plugin C. This approach is quiet familiar in Sitecore XP, where you have two feature layer projects and create a foundation layer project, which both features are allowed to reference. You can see some diagram, which illustrates that below.2019-01-12 19_33_15-präsentation1 - powerpointWhy is that a bad approach? It is, because it tears the plugin apart completely. Your plugin is then spread over two or even more different plugins, which at least violates the basic principle of Opt-In-Complexity. You cannot just include the stuff / plugins you really need and want into your solution anymore, because it is spread all over your solution over various dlls. Removing all of these plugins from your solution, would cause also other plugins to not work properly anymore, which means all the plugins have to stay active, even if you don’t need them. And if you e.g. need just one component in that magic Plugin C from before within your new Plugin, you are obligated to reference the Plugin to get the component, but most likely get even more garbage you don’t really want. So if you have such a scenario with Plugin A and B, just let Plugin B reference Plugin A and let it use the component from there. Some basic principle could be, that a plugin should contain ALL pieces of logic, which belong to the Plugin and should not be spitted up among various VS projects. A small illustration is added below.2019-01-12 19_34_18-präsentation1 - powerpointThis is also a standard approach in OOTB provided plugins by Sitecore itself, see the diagram below. You see, that Orders plugin for example just references the Carts plugin to use components, Pipelines and more from Carts to provide special Orders functionality.

bild1

CommandsController / Minions / CommerceCommands should contain as less code as possible

If you implement a new functionality in commerce engine within you plugin you should take care, that the CommandsController.cs, the Minions and the CommerceCommands should not do all the work. What I mean is, that e.g. if you have a minion, which grabs some information from external systems, which should be used for all of your orders, you should better implement a custom pipeline with blocks, which do the actual work. One benefit of using a pipeline is, that is is completely adaptable by other plugins by adding or removing various blocks to the pipeline. Another great benefit of using pipelines is, that the actual work is placed at one single location, which then can be used by different pieces of code. So for example you can then execute your pipeline from a Minion in regular intervals, from web requests via CommandsController or by custom CommerceCommand, used by service proxy, without unnecessarily duplicating the logic.

Use Service Proxy if possible instead of implementing web requests on your own

Most of you already know different ways to interact with commerce engine from within Sitecore XP instance. You know, you can call the commerce engine directly or use Commerce Connect API. The benefit of using Commerce Connect API basically is, that Commerce Connect includes various analytics functionalities, which are triggered and collected OOTB.

But, what if you have to extend or individualize the commerce engine. If you do that, most likely Commerce Connect is not usable anymore. In such cases you will have to implement a direct communication with commerce engine. Also this can be done at least in two ways.  You can implement web requests and execute them on your own. An example of that can be seen below.

2019-01-12 20_01_36-alnatura - microsoft visual studio (administrator)

In such an approach you have to take care of the URL to call, all headers, parameters and also deserialize the result on your own.

Another quiet nice approach of interacting directly with the commerce engine is to use a service proxy. Because commerce engine uses OData it exposes all its functionality in a way, that clients like Sitecore XP can easily generate a powerful service proxy. Sitecore also provided us with a VS solution to do that. With such a service proxy, you can easily access the whole commerce engine in a common and easy way. Examples how to do that, you can see in the implementation of Commerce Connect API seen below.

Always evaluate policies on runtime, when you need them

If you implement a custom plugin and need some settings, commerce engine allows you to do that, with the usage of policies. From one of my previous blog posts you already know, what a policy is.

A policy is a named, versionable and variable set of data that can be used as facts within behaviors to influence behavioral outcomes. This provides an auditable mechanism for viewing, simulating, and changing core decision criteria that might be used by business processes or other policy-driven behavior. Various plugins have specialized policies to add additional facts to existing policies and/or new policies, or to implement new concepts, such as dynamic pricing.

So, what I now saw, was the approach to use a block in the IStartNodePipeline, which just grabs the policy by context and saves that to a static instance. Every future usage of policies now grabs the policy values from that static instance, instead of always getting the polices by context on runtime.

But what is wrong with that approach?

The problem with that approach is, that the IStartNodePipeline is called with a special environment. And of course the policy values of that environment are grabbed and stored within the static instance. When we now call some functionality of our plugin from another environment, than the IStartNodePipeline was called, we will get the wrong policy values from the static instance. So at this point, we are not able to properly have multiple environments within our commerce engine, just because we used the standard mechanism of policies incorrectly.

So, if you use policies within your plugin, always use the current context to grab the right policy values on runtime.

Do not change the status of an order “manually” within your plugin

How do you change the status of commerce engine orders? What I already saw was a simple approach of doing that. The situation was, that some external system gave feedback on the order status based on the fact, if the order was shipped or not, or if something went wrong etc. The engine now gets the feedback within a defined minion. The minion determined based on the feedback, the next status of the order, grabbed the order and directly changed the status. The problem with that approach is, that commerce engine has it’s own way of changing the stati of orders. Within commerce engine there exist special minions like, PendingOrdersMinionWaitingForAvailabilityOrdersMinion and some more, which in the end scan dedicated lists of order, like all pending orders, grab them and execute a corresponding pipeline, like PendingOrdersMinionPipeline. Within these pipeline some blocks check various conditions if and how an order should be proceeded and set to a new status. But that’s not all. These blocks also manage commerce entity lists, to remove this order from the previous list and put it correctly into the next one, take care of indexing and more.

So if you want to set the status of an order, just add the information for that on the order, implement your custom block in the right pipeline and let the Minions do the job. Also if you plan to create new order stati, just follow the standard approach of creating a dedicated minion for that, commerce entity list to hold all the orders of your status, extend the existing pipelines with blocks, which put the orders into your status and create your own pipeline, which handles orders in your status.

Do not hard code storefront or project specific stuff within your plugins

Imagine the situation, that you implement a new plugin, which should be able to react differently if called from different storefronts. What you now should not do is something like seen in the screen below.

2019-01-12 19_42_14-customer.sample.solution - microsoft visual studio (administrator)

But why should you not implement stuff like this within a plugin?

If you implement such statements within your plugin, it would be closely coupled to your Sitecore XP instance, which uses that plugin. Such a plugin with hard coded storefronts, or other hard coded properties, cannot be used in other instances anymore. But this is a core architectural idea of plugins. Plugins should be implemented in a way, that they can be shared among a various number of instances e.g. like a Nuget package, without changing a single line of code. And yes, it is possible. At least, if you are faced with the given problem.

What you should do, if you want to implement different behavior when used by different storefronts, is add for every storefront a custom environment. Use policies to implement individual settings for your plugin. Based on the storefront the corresponding environment with custom set of policies can be grabbed on runtime. Now you can implement some kind of generic logic, which uses your policy to decide, which way to go. Such an approach is then dependent on the environment, which can vary from instance to instance. But the code can stay always the same.

Let Commerce Engine calculate all the pricing of carts, orders and so on

This point might be obvious. But I already came across pieces of code, where commerce specific functionality was implemented within Sitecore XP. Image you have the requirement, that an order can only be created, when the cart has reached a minimum order value. What you could do now, is to grab the cart from commerce engine and within your Sitecore XP cart feature just check the value of the cart against a predefined threshold, which is stored in some settings item. Based on the check, you could allow the user to proceed the checkout or not.

Of course this approach works well. But from my point of you it is not optimal. Some kind of minimum order value is a very commerce specific feature. Such commerce specific feature should then also be handled by commerce engine on its own. What you should get from the commerce engine is the information for your current cart, if the minimum order value has been reached and maybe also what the minimum order value is. Depending on the specific use case, the determination, if that value has been reached can be quiet complicated, because you maybe not only want to check against Subtotal or Grandtotal, but against Grandtotal – FulfillmentFee to exclude shipping costs from that value. And at least if we reach the point, where complex calculations are necessary, these should stay in commerce engine as single source of truth. And image the case, where you have multiple endpoints, which interact with the commerce engine, like Sitecore, a mobile app, Postman and more. And you implement such kind of minimum order value in Sitecore directly, all the other endpoints would have to implement the same logic, so the behavior is consistent. Otherwise it would be possible e.g. that Sitecore can only create orders with a minimum order value of 50 Euro, but the mobile app or Postman can already create orders with any value, which might violate business requirements.

What you could do is to create a new plugin. Within this plugin you create a new pipeline block, which hooks in into e.g. GetCartPipeline at the very end. Within your new block you now do your check and calculation. The threshold can be saved in a dedicated policy, so it also can be different per environment. After the calculation you could enrich the cart with a new threshold component, which holds the information if the threshold has been reached or not and maybe also the value of the threshold to display that in frontend. In addition you could also add a new block in CreateOrderPipeline, which just checks the new flag, if the threshold has been reached, and if not just forbid the order creation. This way the responsibility of calculation of commerce specific features stays in commerce engine at on single location, where it belongs to. And from that point on it does not matter anymore, from where you try to proceed with the checkout, cause every endpoint will get the same results from commerce engine and can just react on that, instead of doing all the calculations.

If you want to expose functionalities in Commerce Engine, use Pipelines instead of Services, Repositories, Factories and so on

In standard Sitecore XP implementations, where you follow a micro-services approach, in implementation of new features, you most likely create services, which can be consumed by others. An illustrative example of that approach can be seen in the implementation of new SxA modules, like described in the following article.

This approach works well in Sitecore XP. But if you start implementing features / plugins in Sitecore XC this approach is less optimal for the given architecture of Sitecore XC. A core principle of Commerce Engine is the concept of pipelines. Benefits of such kind of approach are

  • Pipelines can be adapted the way business requirements require it
  • You can individually add, remove, replace blocks within pipelines
  • You can create complete new pipelines, which then can also be adapted by other plugins
  • You can remove pipelines / plugins completely for opt-in complexity
  • There is a special log file NodeConfiguration, which holds information about all existing pipeline and containing blocks to easily work with them
  • and many more

If you would now just create a service within your plugin, it would be much harder for other plugin to find and use that service, others than with pipelines. And it would be even impossible to adapt that existing service to fit on individual business needs.  Therefore we would violate and lose some important core principles of commerce engine by extensively using services over pipelines.

If possible, use commerce entity lists for performance reasons

Image the requirement, that you have implemented a Minion, which has to check e.g. if Orders are in a specific state, and if so, do something with these orders. What you could do now, is to use FindEntityPipeline for every single order to grab the order and afterwards check the status and only keep orders, which are in the right state.

But what you also could do is, to use OOTB feature of commerce engine; so called entity lists. Sitecore provides us already with some predefined entity list, especially for order handling. Sitecore holds e.g. a list of all pending, on hold, problem and many more orders. If you now want to check the status of an order, you just have to read the corresponding list and check if your order is in.  If so, you can afterwards grab the order from the system and do your stuff. This way we won’t grab any order unnecessarily, which is in a wrong state.

Such entity lists can also be created and maintained on your own for your custom business needs. Depending on your use case, you just have to add your commerce entity to a new list by adding a special TransientListMembershipsComponent to the entity and add the name of the commerce list, like seen below.

2019-01-13 09_35_28-customer.sample.solution - microsoft visual studio (administrator)

This way commerc engine will create a new entity list, if not existing, and puts this entity in there. After that, you are able e.g. with a minion to grab all entities of that new list again. If you want to remove your entities again from the entity lists, you just have to use RemoveListEntitiesPipeline, like seen below.

2019-01-13 09_39_34-customer.sample.solution - microsoft visual studio (administrator)

Add new Pipelines in the standard way of using SitecorePipelinesConfigBuilder

In general, if you you want to create a new pipeline, you just have to create that pipeline and add it within the SitecorePipelinesConfigBuilder within your ConfigureSitecore.cs class.

  • config
    .ConfigurePipeline<IPipelineName>(c => 
    c.Add<BLOCK>())

But I have already seen another approach of creating a pipeline. In that approach, you have a static manager class, which holds in the end a list of pipeline definitions. If you now want to add a new pipeline, you just have to access that static manager class and add your pipeline by definition. This definition can implemented as an enum. So these pipelines would only exist within that manager class virtually and is not accessible from outside

  • PipelineDefinitionManager
    .Instance
    .GetDefinition(ENUM.SOMEPROPERTY)
    .Add<BLOCK>()

Of course this approach works and in the end we get our pipelines and all of these pipelines are usable via the manager class. But it also has some drawbacks

  • You can only add pipelines of dedicated input and output parameter, based on your manager class
  • These pipelines do not appear in the NodeConfiguration log file, so you have no chance of having a look, which pipelines are configured and how
  • If you try to adapt some pipeline, which was created this way, you have to reflector the existing code to see, which pipeline exist and how they are configured, which is nearly impossible

So my recommendation at this point is, not to over engineer stuff or reinvent the wheel and lose all of the advantages, if you could use a standard approach.

Use standard functionalities as often as you can, instead of reinventing the wheel

If you are working with Commerce Engine you will come to the point, that you have to extend standard functionalities with new ones. One use case, which I have already seen, I would like to show case to you. The task was to implement a new fulfillment method. The approach of doing that was to create a new interface in commerce engine to add that fulfillment method, a new component, which just inherited from standard Component and a piece of logic, which grabbed the current cart to add that new component.

But what are possible problems with such an approach?

With such an approach you would in the end implement a workaround of using OOTB existing fulfillment functionality. Sitecore already has  powerful fulfillment capabilities with Commerce Connect integration, dedicated components and pieces of logic to handle order creation and other stuff afterwards. If you now just use your own component and treat it like your fulfillment component, you would break all the functionalities, which are already existing and you have to implement all of them again on your own. In addition some related features like pricing or promotions would also not work the way you expect anymore. Assume, that you have added your custom fulfillment component with a fulfillment fee and you would like to use a promotion, which removes the fulfillment fee from your cart as benefit. This promotion would not work anymore and you would also have to implement something new on your own.

A better approach of implementing e.g. a new fulfillment option is to use all the OOTB components. First you would just add that new method as Commerce Connect fulfillment Item in Sitecore XP. You would also add that method within standard fulfillment policy. If you need a new component with new special properties for your new fulfillment option, just create a new component and inherit from standard fulfillment component and use that component on your cart. This way Sitecore also recoginzes OOTB your new component e.g. as standard fulfillment component. And all the related functionalities work again as expected. Therefore, if possible, try to use standard components and extend these functionalities with custom business needs, instead of reinventing the wheel.

Use Roles for scalability in Sitecore XC

Lets have a look at a standard setup in Sitecore XP and, how we could integrate Commerce Engine into that environment. A very simple approach would be the following one.

2019-01-13 11_24_34-Workshop.pptx - PowerPoint.png

We have one CM and on CD Sitecore XP web server and just one single Commerce Services instance, which serves the traffic from all the Sitecore instances. Of course even in small setups, this approach would be insufficient. Cause just having just one single instance, which serves traffic from authors from CM system, shoppers from storefronts and executing scheduled tasks in the form of minions in the background is most likely not enough.

A simple approach of handling that is to just increase the number of Commerce Services conected with a load balancer to handle more traffic. A diagram of how this could look like can be seen below.

2019-01-13 11_24_03-workshop.pptx - powerpoint

Of course, instead of using dedicated servers connected via load balances, you could also place the commerce services closer to the web servers, if you want.

But this is not the final approach of how scalability is done for Sitecore XC. Sitecoere XC uses the concept of Roles to realize scalability. From one of my previous blog posts, you should already know, what a Role is. Here is a part of the definition again to bring it back to your mind.

Role: “The Sitecore XC solution implements the concept of Commerce Engine roles to support scalability. In a production environment, traffic is usually split up among multiple installed instances of the Commerce Engine, which are usually physically located close to their traffic sources… “

So in the end we have multiple Commerce Services, which are located close to the web servers. The special thing now is, that each commerce service has a different logical roles, based on its location in the environment. Physically all the Commerce Services are identical, but each has its own set of policies depending on the traffic, which should be served. OOTB Commerce Services can have the following roles

  • Authoring – Close to CM
  • Shops – Close to CD
  • Minion – Decoupled
  • DevOps – Close to CM

A diagram, of how this architecture could look like, can be seen below.

2019-01-13 11_24_16-Workshop.pptx - PowerPoint.png

With such an approach, all the single Commerce Services only have to serve very specific traffic and only have to do very specific work. And every single instance can be configured in an optimal way to do that.

If you adapt existing or implement new Pipelines, use NodeConfiguration logfile to see the current state of your changes

If you follow the core principle of commerce engine and work with pipelines you will most probably adapt existing pipelines or create complete new ones.

The question now, when you want to adapt existing pipelines is, which pipelines exist in commerce engine and how are they currently configured?

The answer to that question is simple. Sitecore provides us with a new type of configuration file. under /wwwroot/logs/. There you find configs which start with NodeConfiguration, like seen in the screen below.

Bild5.png

This logfile holds information about all the currently configured pipelines with used blocks. This file lists all the existing pipelines, with input and output parameters. In addition it lists all the blocks, which are used by the pipeline, each also with the information about input and output parameters. All that can be seen below with the example of IAddCartLinePipeline. These information are essential for every developer, who tries to inject custom blocks into such a pipeline.

bild6

 If you add a new block, you of course have to take, that the input parameter of your block matches the output parameter of the previous block and your output parameter matches the input parameter of the next block. And of course within such a log file you are able to see, if your custom block or whole custom pipeline is added to the commerce engine or not.

If you find bugs in the system, don’t hesitate to create Sitecore Support tickets

Only if we report bugs and misbehavior of the system to Sitecore, they are able to fix such stuff and make the product more stable. When I started working on Sitecore Commerce 8.2.1, it really felt like a Beta test for me. I tried out as many features as possible and played around with the product. While doing that, I experienced a lot of issue, which I thought might be bugs. So for every issue I created a single Sitecore support ticket. You can see an extract of the support portal below.

Bild2.png

In the end it turned out, that most of the issues really were bugs in the new commerce engine. One version later, most of the reported bugs were bugs by Sitecore itself. So by reporting misbehavior back to Sitecore, they were able to make the product more stable, which is, in my opinion, worth it to invest some time in ticket creation and reporting.

Conclusion

Within this article you got insight in some of my experiences from the last 2 years while working with Sitecore Commerce 8.2.1 up to working with Sitecore XC (9.0.3). I saw, how everything started with the introduction of new commerce engine, evolved and what we got till now. It is true, that starting with the big topic Sitecore XC as developer is not easy. But hopefully with this article, you see, that not everything is such magic, as it seems to be in the beginning and you got some personal best practices, which might help in the future.

Sitecore XC 9.0.2 – How to avoid misbehavior when using CreateCategoryCommand

This time I would like to show you some interesting behavior of a special command within Sitecore Commerce Engine. This command is the CreateCategoryCommand and was initially used within my previously mentioned custom Importer plugin. Within that plugin I created a CategoryImport, which was responsible for creating or updating category based on given information.

Now the problem started…

My approach of doing that, was quiet simple.

  1. Use CreateCategoryCommand to try to create a category
  2. If it returns NULL, the category could not be created, because most likely it already exists
  3. Use GetCategoryComand to retrieve the existing category
  4. Use EditCategoryCommand to manipulate the category itself
  5. Use some Associate to parent command to handle associations
  6. Use Delete Relationship command to handle disassociation

2018-09-18 08_41_46-Customer.Sample.Solution - Microsoft Visual Studio.png

In general this approach would also work well. But it didn’t !!!

After a lot of investigation and exchange with Sitecore Support, I found the root cause, why this approach did not work for me.

The behavior was, that at first everything went well, the category was created, adapted, some associations were made correctly. But on the second call, nothing worked anymore. Even if changes should be made on the category or the associations, they were not applied after running the code snipped. Even stranger was, that while debugging the code, everything went well, without any error. Also the local classes e.g. Category class was edited correctly. But in the end nothing were changed in the Database, so the PersistEntityBlock did not work properly.

After some investigation I found out that the root cause was the CreateCategoryCommand and further more, the fact, that when this command fails, every other command, which follows later on, in the end fails in the described behavior. This also explains the behavior, that the first call produces successful results, but the second one not.

Sitecore was able to reproduce that behavior after my investigation and explanation and registered this as bug with the public reference number 41466.

2018-09-18 08_40_22-Customer.Sample.Solution - Microsoft Visual Studio.png

For me a simple rearrangement of the code already solved the problem. Instead of trying to create a category at first and retrieving it later, I switched these statements and now I am trying to get a category at first, and if that fails, I know it does not exist and then call the CreateCategoryCommand, which then should not fail anymore. This works perfectly fine for me, and shows, that the general approach to let a command fail to react on that, is a proper way and that only the CreateCategoryCommand has some internal issue.

I hope this little bug description with working workaround can save some of your time and you can concentrate on the rally important stuff of your business logic, instead of hunting some mysterious bugs. 😀

 

Sitecore XC 9.0.2 – Workaround of getting all parent entities for a given category

Sitecore XC 9.0.2 – Workaround of getting all parent entities for a given category

This article is a small update of the previous one, where I talked about a custom importer. In the end there were still a few topics left open, which had to be implemented afterwards, cause of open Sitecore tickets. One of these topics was about the disassociation of parents from a given category or sellable item while updating their data. The main problem was:

How do we get a list of all parent entities of my given category or sellable item?

When we would be able to get such a list, we could use the parameter ParentNames from the importer call, which holds all entities, which should be associated as parents and this list of already associated parents to determine the delta and then disassociate all of these entities.

The only information the entity itself holds is a list of Catalog and Category ids. But these IDs are Sitecore item ids and not commerce engine entity ids. Therefore these ids were completely useless.  After a short exchange with Sitecore support, it pointed out, that relationships are not stored on the entity itself, but in  special list within commerce engine. Such lists are e.g. catalogtocategorycategorytocategory or categorytosellableitem.  These lists are structured, that we can query an specific entity and get all the children of that entity back.

That’s definitely a step into the right direction, but unfortunately not what we need in our use case. Sitecore also thinks this way, so that a new feature request has been added with public reference number 41453, where it should be possible to get all the associated parent entities of a given category or sellable item.

For now I created a small service as workaround, which uses the existing lists to achieve a GetAllParentEntities() functionality.

2018-09-16 15_31_00-Customer.Sample.Solution - Microsoft Visual Studio.png

2018-09-16 14_56_47-Customer.Sample.Solution - Microsoft Visual Studio.png

https://github.com/Chris1415/Plugin.Sample.Importer/blob/master/Services/Implementation/AssociatedItemRetrievalService.cs

At first use the FindEntitiesInListCommand() on catalog root level to get all first level categories.

Note: The parameter FindEntitiesInListCommand differs a bit, when its called on catalog or category level.

Then iterate through all first level categories. For each entity check if one of these categories matches the origin entity. If so, add the parent entity (At this point the catalog) to the result list. If not, use the child entity to iterate recursively through all of its children and do the same, than before on catalog level. Below you can see the implemented recursion. 2018-09-16 15_03_17-Customer.Sample.Solution - Microsoft Visual Studio

https://github.com/Chris1415/Plugin.Sample.Importer/blob/master/Services/Implementation/AssociatedItemRetrievalService.cs

Note: Now you can see, that the FindEntitiesInListCommand is a bit different on category level, than on catalog level. In the end combine all the matching entities and return all of them.

Note2: The same way we get here association between catalog – category and category – category, we can easily extend that approach of handling also catalog – sellableitem and category – sellableitem exactly in the same way. We only have to adjust the return type and the association type.

With such a helper, we can now go back to our importer, where we need all the parent entities

2018-09-16 15_05_11-Customer.Sample.Solution - Microsoft Visual Studio.png

https://github.com/Chris1415/Plugin.Sample.Importer/blob/master/Services/Implementation/CategoryImporter.cs

Within our importer now first get a list of all parent entities with the custom AssociatedItemRetrievalService.GetAllParentEntities() call. Next iterate through all entities.  For each entity check if the given ParentNames contain one of the entities. If so, do nothing, because the association, which was previously made, is correct. Otherwise we have to remove the existing association. For that, we first build up the correct parameter set (The parameters differ, depending on whether a catalog or category has to be disassociated) Then we can easily call the DeleteRelationshipCommand for each relationship.

The whole implementation can be found within the import plugin available under https://github.com/Chris1415/Plugin.Sample.Importer.

Of course this whole approach is not very performant, but I think for now it will solve our problem, till Sitecore provides us with a dedicated OOTB list for child to parent associations for a highly performant access.