Tuesday, March 13, 2018

Sitecore Experience Commerce - Error: catalog name X is already in use

During testing of a Sitecore Experience Commerce minion which manipulated catalog and sellable item entities, the following error occurred when attempting to run the ICreateCatalogPipeline pipeline.
ERROR PipelineAbort:Catalog name MyCatalog is already in use.
In between minion runs I had been running the following DevOps calls in postman to ensure a fresh start:

  1.  {{OpsApiHost}}/{{OpsApi}}/CleanEnvironment() - Cleans the environment of all entities
  2. {{OpsApiHost}}/{{OpsApi}}/Bootstrap() - Bootstraps commerce, if this is not run you may not be able to add categories
  3. {{OpsApiHost}}/{{OpsApi}}/InitializeEnvironment(environment='MyEnvironment') - as above
However the error was still appearing, even though the catalog no longer existed. To solve this error one of the following will usually work:
  1. Restart IIS to clear any caches
  2. Run the cache clear using the devops postman call {{ServiceHost}}/{{OpsApi}}/ClearCacheStore()
Doing these, stopped the error and my catalog would successfully be created again.

Sitecore Experience Commerce - Error: PopulateItemAvailabilityBlock.AllocationNull

When creating a minion that handled data sync into Sitecore Experience Commerce, the following error occurred when using the IAssociateSellableItemToCatalog pipeline to associate a sellable item with a given category (inside a catalog).
ERROR PopulateItemAvailabilityBlock.AllocationNull.CatalogName|ProductId|
From what I could see, the cause of this error was attempting to add a sellable item to a catalog when no pricing/inventory information is available for it. Doing one of the following to/for the product before attempting to associate with a catalog should fix the error:

  1. Tag the sellable item and a price card with the same tag - worked for me
  2. Add a list price to the sellable item
Let me know in the comments down below, if either of these don't solve your issue. Also ensure that the entity has been updated correctly after making changes (IPersistEntityPipeline pipeline can help with this).

Sitecore Experience Commerce - Error: PipelineAbort:Invalid currency

During minion development in Sitecore Experience Commerce, the following error occurred when running the IAddPriceCardPipeline pipeline.
2 00:10:13 ERROR Pipeline completed with error
System.Exception: Error processing block: Management.block.GetCurrencySetById ---> System.ArgumentNullException: Management.block.GetCurrencySetById: The currency set Id cannot be null or empty.
42 00:10:13 WARN CtxMsg.ValidationError.InvalidCurrency: Text=Invalid currency 'NZD'. Valid currencies are ''.|Shopper=[None]|Shop=|Correlation=d68174cf-9976-410d-b15b-0ee1de8ba39c
42 00:10:13 ERROR PipelineAbort:Invalid currency 'NZD'. Valid currencies are ''.
This error traces back to the fact that I was incorrectly passing in the PriceBook parameter. There is no pipeline to get you a price book by name, however the following example will get you a PriceBook entity by name (if it exists). This makes use of the IFindEntitiesInListPipeline pipeline.
var books = (await _findEntitiesPipeline.Run(new FindEntitiesInListArgument(typeof(PriceBook), string.Format(context.GetPolicy<KnownPricingViewsPolicy>().PriceBooks, "BookName"), 0, int.MaxValue), context)).List;
var book = (PriceBook)books.Items.FirstOrDefault();
Hopefully this snippet is able to save someone some time!

Friday, March 9, 2018

Sitecore Experience Commerce - Adding a new empty environment

For a detailed explanation of Commerce roles and how they tie in with environments, please see my dedicated post. This gives an overview of environments and I recommend reading before continuing with this post.

This example shows how to add a new environement with empty data, if you want to initialize it with data (like the Habitat example) then see my post: Adding a new environment initialized with data.

Define the environment

The first piece of the puzzle is a JSON configuration file where the environment/plugin is defined. These files are placed it src\Sitecore.Commerce.Engine\wwwroot\data\Environments, and in my case I duplicated the PlugIn.Habitat.CommerceShops-1.0.0.json example. It's too big to post here, but the areas I changed were:
  • ArtifactStoreId - to a new GUID - this would be the same for a given set of environments (authoring, shops and minions)
  • Id - to a new ID (the efe49ff743d34b649fffcof293615cd9one)
  • Id - to a new name (the Entity-CommerceEnvironment-HabitatShops one)
  • Name - a new environment name
  • InitialArtifactSets - as follows
InitialArtifactSets for environment

Add the environment to global

To have the environment appear in the business tools, open up the Global.json file that comes inside the bootstrap folder of the Sitecore.Commerce.Engine project. There will be a GlobalEnvironment section which contains the values of the environments to appear in business tools. Here you can add the new environment name. 

Sitecore Experience Commerce - Environment for business tools

Initialize the environment

Now I just publish the Sitecore.Commerce.Engine project to the four commerce sites (ensuring thumbprints for certificates are setup correctly). Of course don't forget that each of these needs their environment set in the config file.

Inside postman, create a new environment to match the one you just created:

New postman environment
The run the following service calls from Postman:
  1. GetToken - under authentication
  2. Bootstrap Sitecore Commerce - under SitecoreCommerce_DevOps
  3. Initialize Environment - under SitecoreCommerce_DevOps
If any of these calls failed (due to 500 error), you will need to take a look in the Commerce Ops log files. If all went smoothly then your new environment is available in the Commerce Business Tools interface!

new environment in Experience Commerce
For me, the only error I got was around some dodgy JSON in the environment/plugin configuration. I had changed the currency elements to NZD and had missed a single USD instance. 

Sitecore Experience Commerce - Commerce roles and how they tie in with environments

As part of the installation of Sitecore Experience Commerce, 4 commerce websites are added to the IIS manager, each of which performs a unique engine role. Note that in some cases users will scale this down to a single instance locally for development and the full 4 in production. These 4 roles are:
  1. Authoring - handles traffic from the commerce business tools.
  2. Shops - serves traffic from a storefront.
  3. Minions - runs independently and runs your minion(s).
  4. DevOps - internal and will have higher permissions to handle environment bootstrapping etc.
Sitecore Experience Commerce roles
These 4 engine roles actually have the same code deployed - via the Sitecore.Commerce.Engine project which contains references to any plugins you create as well as defined environments. 

Where they differ is in which commerce environment is defined against a given role. To quote the Sitecore documentation:
Each deployed role can have different policies and behaviors, which can be specified using a specific Commerce Environment for that role. When a call is made to the Commerce Engine, the call’s header specifies an environment. This environment is used by the engine to control policies and behavior for that call. Specifying a particular environment allows explicit independent control (per role) of functions, such as caching, data storage, integration connections, and so on. 
Using environment policies, engine roles can either share a common persistent store, or use separate dedicated storage. All roles share the same storage in the out-of-box implementation. This allows artifacts to be visible to each role without a publishing process. For example, this makes orders immediately available to the Authoring role, and makes approved promotions and pricing changes immediately available to the Shops role. 
Each role can have independent caching policies. For example, reduced caching can be configured on the Authoring role so that changes are seen right away, and heavier caching can be configured on the Shops role to increase performance.
So what exactly is an environment, again lets take a look at the documentation:
Commerce environments provide the ability to have separately configurable pools of data and service functionality that run together in a single-service instance. Environments can share the same persistent store as other environments or be separated into their own exclusive persistent store.
Basically an environment can be used to group configurations for a given function and can share as much as needed with other related/unrelated environments.

To give a better illustration, lets take a look at what comes out of the box with Experience Commerce and Habitat. Inside the default Sitecore.Commerce.Engine project (comes as part of the SDK and is what is deployed to these roles) is an Environments folder which contains a number of JSON configuration files. The files that are relevant for this discussions are:
  1. PlugIn.Habitat.CommerceAuthoring-1.0.0.json - Name: HabitatAuthoring
  2. PlugIn.Habitat.CommerceMinions-1.0.0.json - Name: HabitatMinions
  3. PlugIn.Habitat.CommerceShops-1.0.0.json  - Name: HabitatShops
Take note of the name of each of these environment (as defined in the JSON itself). Looking into the contents of these files you may notice that shops and authoring are quite similar and the main differences are a couple of extra policies and plugins on the authoring environment. They actually share the same store/context so this makes sense as we don't want customer migration processing to happen on the instance accessed by the storefront. The minions environment definition is quite different and of course has a heap of minions defined. 

Now if we go into each of the commerce role websites (mentioned at the start of this post) they each will contain a config.json file in the wwwroot folder. The EnvironmentName setting in these configuration files is the only difference at deployment time (remember the same project gets deployed to all 4). 
  1. Authoring - HabitatAuthoring
  2. Shops - HabitatShops
  3. Minions - HabitatMinions
  4. DevOps - AdventureWorksOpsApi
As you may have noticed, these 4 roles each refer back to one of the habitat environments defined above. This is how each role knows what it's purpose is and it ties back to the environment. In this out of the box implemtation they all work together: All roles share the same storage in the out-of-box implementation.

Note: the AdventureWorksOpsApi environment does not appear to have been defined or shipped with the version of the SDK that I used. In this case it's fine to also set the role of this to the HabitatAuthoring or to remove this and point to the Authoring role.

There are two final pieces to this puzzle:

How does an environment appear in Experience Commerce Business Toosl?
Inside the Sitecore.Commerce.Engine project is a Global.Json file, this contains a GlobalEnvironment section which is where the values of environments you wish to appear in the business tools will be listed. Generally this would just be the authoring and shops environments (as is out of the box).

How do we define which environment is used inside Sitecore itself?
The full answer is available in my post: Sitecore Experience Commerce - Catalogs in the Sitecore Content Editor. The short answer is that the Sitecore.Commerce.Engine.Connect.config configuration file has a defaultEnvironment setting where we name the environment.

Hopefully this blog post has provided some clarity about what the commerce roles are in Experience Commerce and how they relate back to environments.