Sitecore Experience Commerce: Debugging the Commerce Engine from Visual Studio in XC 10

In this article, we will review how to attach a running Commerce Engine instance to the Visual Studio Debugger for local debugging.

Introduction

In Sitecore Experience Commerce 9.X.Y, the Commerce Engine was built on .NET Core 2.2 or lower, which either only supported the out-of-process hosting or is the default configuration. This meant that IIS was essentially being used as a proxy to forward requests to the Commerce Engine application, which is why you are probably familiar with attaching the debugger to a process named Sitecore.Commerce.Engine.exe. By hovering over the process, the source Commerce Engine could easily be identified when attaching the process to Visual Studio.

Sitecore Experience Commerce 10 now leverages .Net Core 3.1, which uses in-process hosting, meaning the Commerce Engine instance run in the same process as its IIS worker process. Overall, the in-process hosting provides improved performanced as requests aren't being proxied over the loopback adapter.

Now that we have a better understanding of the switch from out-of-process to in-process hosting in XC 10, it should be apparent as to why we need to amend how we attach the Commerce Engine to Visual Studio's debugger.

Attaching the Commerce Engine instance to the Visual Studio Debugger

First thing we will need to do is to retrieve the process Id to verfiy that we are attaching the correct process in Visual Studio. To do this, open IIS and navigate to the Worker Processes view.

In the Worker Processes view, look for the application pool name containing the name of the application pool configured for the Commerce Engine instance and note the Process Id.

If the application pool does not show the Commerce Engine instance, it has likely not started, or shut down due to inactivity. Execute a request to the Commerce Engine instance and refresh the Worker Processes view in IIS.

Over in Visual Studio, open the Attach to Process dialog, select the Show processes from all users as you will likely be running the Commerce Engine under a dedicated user profile, and locate the ID that we identified from the Worker Proccesses view in IIS. The 'w3wp' can also be applied to the process filters to more easily locate the process.

References

Microsoft: Host ASP.Net Core on Windows with IIS > Hosting models

Sitecore Experience Commerce: Promotion Evaluation and Application Logic in XC 10

In this article, we will review the breaking changes to promotions that have been introduced in XC 10, considerations for upgrading from a XC 9.X solution, and the updated business logic that the Commerce Engine utilises to evaluate and apply promotions.

Note: References to date will indicate both date and time throughout this article.

Introduction

Previously in Sitecore Experience Commerce: Promotion Evaluation and Application Logic, we had identified that promotions calculations were broken down into cart line level and cart level promotions, of which cart line level promotions were calculated and applied prior to cart level promotions.

In Sitecore Commerce 10, there are 3 key changes that are important to understand, especially when upgrading solutions to XC 10, as the changes to rules for promotion application means that cart line and cart subtotal and total calculations may differ.

  1. Exclusive promotions are now exclusive across the cart line level and cart level promotions.
  2. Promotion Priority indexes have been introduced, allowing business users to specify a priority level that will take precedence in the initial ordering of promotions during evaluation. The lower the promotion priority value, the higher the promotion is evaluated (let it sink in for a minute).
    1. For exclusive promotion application, automatic promotions are addressed prior to coupon promotions, then Promotion Priority is the decider for determining the exclusive promotion within the group regardless of whether it's a cart line level or cart level promotion.
    2. For applying multiple non-exclusive promotions, cart line level promotions, still take precedence over cart level promotions, while the Promotion Priority is a secondary factor.
 
Sitecore.Commerce.Plugin.Carts
ICalculateCartPipeline (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Carts.ClearCartBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Carts.CalculateCartSubTotalsBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Fulfillment.CalculateCartLinesFulfillmentBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Fulfillment.CalculateCartFulfillmentBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Promotions.CalculateCartPromotionsBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Promotions.RemoveUnwatedFreeGiftsFromCartBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Tax.CalculateCartLinesTaxBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Tax.CalculateCartTaxBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Carts.CalculateCartTotalsBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Payments.CalculateCartPaymentsBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)
     ------------------------------------------------------------
     Plugin.Carts.WriteCartTotalsToContextBlock (Sitecore.Commerce.Plugin.Carts.Cart => Sitecore.Commerce.Plugin.Carts.Cart)

Promotion Evaluating Logic

The following diagram shows the pipelines and pipeline blocks that are called during the process of evaluating the applicable promotions and additional filtering for exclusive promotion evaluation.

Figure 1. Promotion qualification evaluation pipeline logic

The following steps make up the evaluation process:

  1. Pre-Evaluate Promotions: Removes any previous selected free gift cart lines from the cart and adds them as a unique object by type to the commerce context. This is too ensure that these cart lines are not utilised when evaluating applicable promotions.
  2. Search For Promotions: Performs a search on the promotions index and retrieves the promotion entities from the commerce database:
    • Index Search Filters:
      1. By Promotion Entity Type: Filters down to the promotion entity type, i.e. excludes promotion book indexes.
      2. By Valid Date: Filters out promotions that do not fall within the Valid From/To dates based on effective date.
      3. By Catalogs: Filters out promotions where the associated catalog does not match any of the catalogs that are associated to any of the cart line items.
    • Post-Search Filters on Entity List:
      1. Filter Not Approved Promotions: Removes promotions that are not approved and, if the promotion is disabled, where the effective date is prior to the updated date (the date the promotion was disabled). The latter rule is to allow the promotion to be active when reviewed the storefront at a previous point in time.
  3. Filter Promotions By Items: Removes promotions where the cart contains no sellable items marked as included in the ItemsCollection qualification or where the cart contains any of the sellable items marked as excluded in the ItemsCollection qualification.
  4. Filter Promotions By Coupon: Removes promotions that require a coupon that has not been applied to the cart.
  5. Evaluate Promotions: Filters out promotions where promotion qualification and benefit rules are not applicable to the current cart.
  6. Filter Promotions With Coupons By Exclusivity: If exclusive coupon promotions are present in the promotions list, the list will be filtered down to a single exclusive coupon promotion. The exclusive promotion will be determined with the lowest Promotion Priority value, followed by the Added date that their corresponding coupons were applied to the cart, in the event of a tie breaker.
  7. Filter Promotions By Exclusivity: If exclusive automatic promotions are present in the promotions list, the list will be filtered down to a single exclusive automatic promotion. The promotion will be determined by the lowest Promotion Priority value, followed by the earliest (oldest) Valid From date, and in the event of multiple promotions sharing the same lowest Promotion Priority value and earliest Valid From date the promotion that was created earliest will take win.
  8. Post-Evaluate Promotions: Adds the previously selected free gift cart lines back to the cart; retrieved from the commerce context.

Promotion Priorisation Rules

While the previous section covered how promotions are evaluated, and also provided some insight into promotion priorisation, we will now cover the prioritisation rules.

The following diagram shows the logic used to determine which promotion(s) to apply to the cart.

Figure 2. Flow chart of promotion application logic

The blue boxes represent logic for maintaining free gift selections and don't impact the application of the promotions, however this shows where this logic is handled.

There are essentially 3 steps that make up the promotion application process:

  1. Apply a single exclusive automatic promotion.
    • The promotion will be determined by the lowest Promotion Priority value, which will fallback to the earliest (oldest) Valid From date, and then the earliest Created date the promotion that was created, in the result of tied values.
    • If a promotion is applied here, no further promotions are applied.
  2. Apply a single exclusive coupon promotion.
    • The promotion will be determined by the lowest Promotion Priority value, with the Added date that their corresponding coupons were applied to the cart as a fallback to manage tied values.
    • If a promotion is applied here, no further promotions are applied.
  3. Apply all non-exclusive promotions.
    • The promotion order will be determined by cart line level promotions being applied first and cart level promotions applied second, both ordered by ascending Promotion Priority value. Where Promotion Priority values are equal, promotions are furthered ordered as follows:
      1. Automatic promotions, ordered by earliest (oldest) Valid From date, and in the event of multiple promotions sharing the same earliest Valid From date the promotion that was created earliest will win.
      2. Coupon promotions, ordered by earliest Added date that their corresponding coupons were applied to the cart.

Can Promotions Be Configured to XC 9.X Logic?

If Promotion Priorities are not utilised, the promotion logic remains largely the same as cart line level promotions are still applied before cart level promotions. The key difference is the promotion logic now ensures a sole exclusive promotion, which cannot be reverted by configuration and will require customisation.

References

Sitecore Experience Commerce: Creating a Commerce Engine Plugin in XC 10

In this article, we will look at the steps in creating a custom plugin project for the Commerce Engine solution using the current developer experience in XC 10.

Introduction

With XC 10, creating a Sitecore Commerce plugin project is currently not available as a Visual Studio extension project template and has been migrated to the .Net Core CLI as a static project template.

As per previous versions of the the Sitecore Commerce plugin project, this is intended as a reference project representing a loose end-to-end implementation with sample classes. It is also commonly utilised as the starting template for your project, where you will remove the sample classes and utilise the csproj file and the project's folder structure as the skeleton for your plugins.

Installing the Sitecore.Commerce.Plugin.Template

The plugin project template is no longer distributed via the Commerce Engine SDK and is now available via the Sitecore Commerce Official NuGet Feed. To download the project template, search for Sitecore.Commerce.Plugin.Template and navigate to the package details page.

On the package details page, scroll down and download the package from right panel under the Info section.

The plugin project template can now be installed via the .Net Core CLI. Open PowerShell and run the following command, dotnet new -i <full path to Sitecore.Commerce.Plugin.Template.*.*.*.nupkg>.

dotnet new -i C:\Projects\Sitecore.Commerce.Plugin.Template.6.0.4.nupkg

Now if we run the dotnet new command in PowerShell, we can see the installed plugin project template.

Creating a new Sitecore Commerce Plugin Project

Now with the plugin project tempate installed, we can create a new project using the template.

Using you Commerce Engine solution's root directory, the following command will create the plugin project in the desired directory, dotnet new pluginsample -o <relative path to project directory>/<project name>.

dotnet new pluginsample -o src/Foundation/MyPlugin/Engine/Foundation.MyPlugin.Engine

Note: The project name has not been configured at this time, so we will perform some post project creation steps to resolve this.

After creating the project, navigate to the folder where the project was created and rename Sitecore.Commerce.Plugin.Sample.csproj to your project name, e.g. Foundation.MyPlugin.Engine.csproj

To resolve namespaces within the project, you can use a tool, such as Notepad++, to replace all references of 'Sitecore.Commerce.Plugin.Sample' to <your project name>, e.g. Foundation.MyPlugin.Engine.

Adding the Plugin to the Commerce Engine Solution

With our new project created, we can add it the Commerce Engine solution by right-clicking a solution folder, selecting the Add Existing Project command, and adding the project from its location.

Finally add the project to the Commerce Engine by adding the project reference to the Sitecore.Commerce.Engine project.