Sitecore Experience Commerce: Preparing a Clean Install of XC 9.1

In this article, we will look at preparing for the installation Sitecore Experience Commerce, by making the minimal amount of necessary changes for a baseline installation and avoiding the pitfalls with the default configuration. From this point, modifying the configurations for project-specific should be simpler.

This article is intended to supplement the Sitecore XC 9.1 Installation Guide for the download package version Sitecore.Commerce.2019.04-3.0.163.zip.

Pre-Installation

Before running the deployment script, we will correct the configuration and apply some workarounds in order to successfully install Sitecore Commerce.

Workarounds

  1. The <Identity Server web root>\Config\production\Sitecore.IdentityServer.Host.xml needs to be updated to include the new commerce site bindings from the $SiteHostHeaderName. ("sxa.storefront.com" from the deployment script).
    <Clients>
      <DefaultClient>
        <AllowedCorsOrigins>
      	  <AllowedCorsOriginsGroup1>http://SC911.sc</AllowedCorsOriginsGroup1>
      	  <AllowedCorsOriginsGroup2>http://sxa.storefront.com</AllowedCorsOriginsGroup2>
      	  <AllowedCorsOriginsGroup3>https://sxa.storefront.com</AllowedCorsOriginsGroup3>
        </AllowedCorsOrigins>
      </DefaultClient>
      ...
    </Clients>
    
  2. Follow Installing Sitecore Experience Commerce 9.1 with Default Storefront Tenant and Site.

Configuration

For the installation step, we assume that Sitecore XP 9.1.1 has been installed already from XP Single packages (XP0). The only change to the configuration that is made is to reset the password $SitecoreAdminPassword to "b".

Now, we need to reset the Deploy-Sitecore-Commerce.ps1 configurations to reasonable defaults.

To simplify the installation process, I place the Sitecore PowerShell Extensions zip file, Sitecore Experience Accelerator zip file, and Microsoft.Web.XmlTransform.dll file directly in the deployment folder.

The following parameters are reset back to XP 9.1.1 Single packages (XP0) configuration:

  • $Sitename
  • $SqlDbPrefix
  • $IdentityServerSiteName
param(
	[string]$SiteName = "XP0",
	[string]$SiteHostHeaderName = "sxa.storefront.com",
	[string]$SqlDbPrefix = "$SiteName",
	[string]$CommerceSearchProvider = "SOLR",
	[string]$IdentityServerSiteName = "$SiteName.IdentityServer"
)

The following parameters are reset back to XP 9.1.1 Single packages (XP0) configuration:

  • SiteName
  • InstallDir
  • XConnectInstallDir

The following parameters are updated so that the evaluations return a single (and correct) string response, as opposed to an array of strings:

  • SitecoreCommerceEnginePath
  • SitecoreBizFxServicesContentPath

The following parameters are configured to point back to the deployment directory:

  • PowerShellExtensionsModuleFullPath
  • SXAModuleFullPath
  • MergeToolFullPath

The following parameters are modified to point to the correct release zip files, provided in the Commerce package:

  • SXACommerceModuleFullPath
  • SXAStorefrontModuleFullPath
$params = @{
		Path                                        = Resolve-Path '.\Configuration\Commerce\Master_SingleServer.json'
		BaseConfigurationFolder                     = Resolve-Path '.\Configuration'
		SiteName                                    = "$SiteName.sc"
		SiteHostHeaderName                          = $SiteHostHeaderName
		InstallDir                                  = "c:\inetpub\wwwroot\$SiteName.sc"
		XConnectInstallDir                          = "c:\inetpub\wwwroot\$SiteName.xconnect"
		CommerceInstallRoot                         = "c:\inetpub\wwwroot\"        
		CommerceServicesDbServer                    = $($Env:COMPUTERNAME)    #OR "SQLServerName\SQLInstanceName"
		CommerceServicesDbName                      = "SitecoreCommerce9_SharedEnvironments"
		CommerceServicesGlobalDbName                = "SitecoreCommerce9_Global"
		SitecoreDbServer                            = $($Env:COMPUTERNAME)            #OR "SQLServerName\SQLInstanceName"
		SitecoreCoreDbName                          = "$($SqlDbPrefix)_Core"
		SitecoreUsername                            = "sitecore\admin"
		SitecoreUserPassword                        = "b"
		CommerceSearchProvider                      = $CommerceSearchProvider
		SolrUrl                                     = "https://solr:8992/solr"
		SolrRoot                                    = "c:\\solr-7.2.1"
		SolrService                                 = "solr-7.2.1"
		SolrSchemas                                 = ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "SolrSchemas" )
		CommerceServicesPostfix                     = "Sc9"
		CommerceServicesHostPostfix                 = "Sc9.qa"
		SearchIndexPrefix                           = "sitecore"
		EnvironmentsPrefix                          = "Habitat"
		Environments                                = @('AdventureWorksAuthoring', 'HabitatAuthoring')
		AzureSearchServiceName                      = ""
		AzureSearchAdminKey                         = ""
		AzureSearchQueryKey                         = ""
		CommerceEngineDacPac                        = Resolve-Path -Path "..\Sitecore.Commerce.Engine.SDK.*\Sitecore.Commerce.Engine.DB.dacpac"
		CommerceOpsServicesPort                     = "5015"
		CommerceShopsServicesPort                   = "5005"
		CommerceAuthoringServicesPort               = "5000"
		CommerceMinionsServicesPort                 = "5010"
		SitecoreBizFxPort                           = "4200"
		SitecoreCommerceEnginePath                  = Resolve-Path -Path "..\Sitecore.Commerce.Engine.3.0.163.zip"
		SitecoreBizFxServicesContentPath            = Resolve-Path -Path "..\Sitecore.BizFX.2.0.3"
		CommerceEngineCertificateName               = "storefront.engine"
		SiteUtilitiesSrc                            = ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "SiteUtilityPages" )
		HabitatImagesModuleFullPath                 = Resolve-Path -Path "..\Sitecore.Commerce.Habitat.Images-*.zip"
		AdvImagesModuleFullPath                     = Resolve-Path -Path "..\Adventure Works Images.zip"
		CommerceConnectModuleFullPath               = Resolve-Path -Path "..\Sitecore Commerce Connect*.zip"
		CommercexProfilesModuleFullPath             = Resolve-Path -Path "..\Sitecore Commerce ExperienceProfile Core *.zip"
		CommercexAnalyticsModuleFullPath            = Resolve-Path -Path "..\Sitecore Commerce ExperienceAnalytics Core *.zip"
		CommerceMAModuleFullPath                    = Resolve-Path -Path "..\Sitecore Commerce Marketing Automation Core *.zip"
		CommerceMAForAutomationEngineModuleFullPath = Resolve-Path -Path "..\Sitecore Commerce Marketing Automation for AutomationEngine *.zip"
		CEConnectModuleFullPath                     = Resolve-Path -Path "..\Sitecore Commerce Engine Connect*.zip"
		PowerShellExtensionsModuleFullPath          = Resolve-Path -Path "..\Sitecore PowerShell Extensions*.zip"
		SXAModuleFullPath                           = Resolve-Path -Path "..\Sitecore Experience Accelerator*.zip"
		SXACommerceModuleFullPath                   = Resolve-Path -Path "..\Sitecore Commerce Experience Accelerator 2.*.zip"
		SXAStorefrontModuleFullPath                 = Resolve-Path -Path "..\Sitecore Commerce Experience Accelerator Storefront 2.*.zip"
		SXAStorefrontThemeModuleFullPath            = Resolve-Path -Path "..\Sitecore Commerce Experience Accelerator Storefront Themes*.zip"
		SXAStorefrontCatalogModuleFullPath          = Resolve-Path -Path "..\Sitecore Commerce Experience Accelerator Habitat Catalog*.zip"
		MergeToolFullPath                           = Resolve-Path -Path "..\Microsoft.Web.XmlTransform.dll"
		UserDomain                                  = $Env:COMPUTERNAME
		UserName                                    = 'CSFndRuntimeUser'
		UserPassword                                = 'Pu8azaCr'                          

		BraintreeAccount                            = @{
			MerchantId = ''
			PublicKey = ''
			PrivateKey = ''
		}
		SitecoreBizFxServerName                     = "SitecoreBizFx"
		SitecoreIdentityServerApplicationName       = $IdentityServerSiteName
		SitecoreIdentityServerHostName              = $IdentityServerSiteName
	}

Post Installation

  • During the installation the original bindings for the Sitecore website, e.g. 'XP0.sc', are removed. Add these bindings back in IIS.
  • If you add the Postman collections/environments to Postman, the
    SitecoreIdServerHost will need to be updated to point to 'XP0.identityserver'.

Installing Sitecore Experience Commerce 9.1 with Default Storefront Tenant and Site

In this article, we will look at applying a workaround in order to install the default storefront tenant and site during the Sitecore Commerce 9.1 installation as unfortunately there's a bug that prevents these from being created during the installation.

Workaround Steps

Note: This has been tested and verified against the On Premise packages.

 

  1. Following on from the installation guide's step, 2.2. Download the Sitecore XC release package and prerequisites, navigate and extract the file named xml from Sitecore Commerce Experience Accelerator Storefront 2.0.181.zip\package.zip\items\master\sitecore\system\Modules\PowerShell\Script Library\CXA - Internal\Web API\CreateDefaultStorefrontTenantAndSite\{6FEC77C8-00DC-4B7B-9597-82588616A1F2}\en\1.
  2. Open the file and add the following snippet before Function CreateCXATenant.
    #Override Write-Progress to avoid errors which happen because of impossibility to write-progress in non-interactive sessions
    Function Write-Progress {
        [CmdletBinding()]
        param(
            [Parameter(Mandatory = $false)]
            $Activity,
            [Parameter(Mandatory = $false)]
            $CurrentOperation,
            [Parameter(Mandatory = $false)]
            $Status,
            [Parameter(Mandatory = $false)]
            $PercentComplete,
            [Parameter(Mandatory = $false)]
            [switch]$Completed
        )
        process {
            # do nothing
        }
    }
    
  3. Replace the file in the archive with the updated file.
  4. Continue to follow the installation guide.

When the deployment script run in step 3.2. Run the deployment script, the default tenant and site will now be created.

Sitecore Experience Commerce: Pricing Calculation Logic – Part 2

In this article, we highlight the expected pricing outcomes through decision tables.

For a high-level look at the important aspects of the business logic that determine list and sell prices, see Pricing Calculation Logic - Part 1.

Pricing Transparency (Advanced)

The following decision tables can be utilised to help understand and troubleshoot pricing outcomes.

Important notes:

  • The business logic applies to the OOTB Sitecore Commerce solution.
  • Price cards are resolved by the price book associated to the catalog.
  • These findings do not take into consideration promotions, specifically those that affect sellable item/variant sell price.

Sellable Item Price Calculation

These messages will be applied to the MessagesComponent of a  SellableItem entity.

In simplying the table, I took a few shortcuts to note:

  • 'Valid snapshot' conditions assume a price card has been resolved by name or tag. Refer to the previous flow diagrams in Pricing Calculation Logic - Part 1 to understand the more complex conditions.
  • For 'Has variants?', 'Calculate item list price in depth?', and 'Has list price for currency?' conditions, the Rules that state a group 'N'. However, I actually mean that some, but not all, of these conditions can be true.

Variant Price Calculation

These messages will be applied to the MessagesComponent of a  ItemVariationComponent within the SellableItem entity.

In simplying the table, I took a few shortcuts to note:

  • 'Valid snapshot' conditions assume a price card has been resolved by name or tag. Refer to the previous flow diagrams in Pricing Calculation Logic - Part 1 to understand the more complex conditions.

Cart Item Calculation (Sellable Item)

These messages will be applied to the MessagesComponent of a sellable item CartLineComponent.

Messages will be applied in the following order:

  1. Sellable Item Price Calculation
  2. Cart Item Calculation (Sellable Item)

Cart Item Calculation (Variant)

These messages will be applied to the MessagesComponent of a variant CartLineComponent.

Messages will be applied in the following order:

  1. Sellable Item Price Calculation
  2. Variant Price Calculation
  3. Cart Item Calculation (Variant)

References

Sitecore Experience Commerce: Pricing Calculation Logic – Part 1

In this multi-part article, we will review the Sellable Item/Variant price calculation processes that determines and differentiates the list pricing from the sell pricing.

As this is one of the more complex areas of Sitecore Commerce, Part 1 will cover the business logic used to apply the pricing, while Pricing Calculation Logic - Part 2 will highlight the expected pricing outcomes through decision tables.

This article is intended to suplement the official Pricing transparency documentation.

Introduction

The  MessagesComponent on the SellableItem entity, ItemVariationComponent, and CartProductComponent provides the audit trail for how the sellable item/variant pricing was calculated. The '<=' in the Text property is not a logic operator, but instead represents the assignment of the source to the price type.

{
	"@odata.type": "#Sitecore.Commerce.Core.MessagesComponent",
	"Id": "47edb873fe754c89ae4bc41d7c309811",
	"Name": "",
	"Comments": "",
	"Policies": [],
	"Messages": [
		{
			"Code": "Pricing",
			"Text": "SellPrice<=PriceCard.Snapshot: Price=$10.00|Qty=1.0|PriceCard=Habitat_PriceCard"
		},
		{
			"Code": "Pricing",
			"Text": "ListPrice<=PricingPolicy: Price=$1,919.69"
		}
	],
	"ChildComponents": []
}
{
	"@odata.type": "#Sitecore.Commerce.Core.MessagesComponent",
	"Id": "ed77a9de5db941ffbfcf0b217e3affda",
	"Name": "",
	"Comments": "",
	"Policies": [],
	"Messages": [
		{
			"Code": "Pricing",
			"Text": "Variation.SellPrice<=Variation.PriceCard.Snapshot: Price=$9.00|Qty=1.0|Variation=56042567|PriceCard=Habitat_VariantsPriceCard"
		},
		{
			"Code": "Pricing",
			"Text": "Variation.ListPrice<=Variation.PricePolicy: Variation=56042567|Price=$2,429.99"
		}
	],
	"ChildComponents": []
}
{
	"@odata.type": "#Sitecore.Commerce.Core.MessagesComponent",
	"Id": "7e6bc27965ef4f3a954e6fcdadb96fa5",
	"Name": "",
	"Comments": "",
	"Policies": [],
	"Messages": [
		{
			"Code": "Pricing",
			"Text": "SellPrice<=PriceCard.Snapshot: Price=$10.00|Qty=1.0|PriceCard=Habitat_PriceCard"
		},
		{
			"Code": "Pricing",
			"Text": "ListPrice<=PricingPolicy: Price=$1,919.69"
		},
		{
			"Code": "Pricing",
			"Text": "Variation.SellPrice<=Variation.PriceCard.Snapshot: Price=$9.00|Qty=1.0|Variation=56042567|PriceCard=Habitat_VariantsPriceCard"
		},
		{
			"Code": "Pricing",
			"Text": "Variation.ListPrice<=Variation.PricePolicy: Variation=56042567|Price=$2,429.99"
		},
		{
			"Code": "Pricing",
			"Text": "CartItem.SellPrice<=PriceCard.ActiveSnapshot: Price=$6.00|Qty=5.0"
		},
		{
			"Code": "Pricing",
			"Text": "CartItem.ListPrice<=SellableItem.Variation.ListPrice: Price=$2,429.99"
		}
	],
	"ChildComponents": []
}

The 2 primary pricing scenarios we see in Sitecore Commerce are:

  • The pricing of a sellable item/variant as is (per single unit)
  • The pricing of a sellable item/variant once added to the cart. Pricing calculations here may also affected by quantity, via price tiers of associated price cards, and specific promotions that affect the sell price.

Sellable Item/Variant Pricing Calculations

The first scenario, where we are retrieving a sellable item/variant, to display on the Product Listing or Product Details pages for example, calculates the pricing through the following steps:

  1. Calculate Sellable Item Sell Price
  2. Calculate Variations Sell Price
  3. Calculate Sellable Item List Price
  4. Calculate Variations List Price
  5. Reconcile Sellable Item Prices

Important notes:

  • The business logic applies to the OOTB Sitecore Commerce solution.
  • Price cards are resolved by the price book associated to the catalog.
  • These findings do not take into consideration promotions, specifically those that affect sellable item/variant sell price.

Calculate Sellable Item Sell Price

The CalculateSellableItemSellPriceBlock will attempt to determine the sell price for the sellable item, adding it to the PurchaseOptionMoneyPolicy.

Notable flow aspects

  • Only the first attempt at resolving a price card will be utilised. i.e. if the price card name associated to the sellable item cannot be resolved to a price card or valid snapshot, the price card by tags logic is not used as a fall back.

Calculate Variations Sell Price

The CalculateVariationsSellPriceBlock will attempt to determine the sell price for each variant of the sellable item.

Notable flow aspects

  • The flow diagram represents a single variant. The pipeline block will utilise this flow for each variant.
  • Only the first attempt at resolving a price card will be utilised.
  • If the price card is resolved from the sellable item, the message will not reflect that the price card was retrieved from the sellable item.

Calculate Sellable Item List Price

The CalculateSellableItemListPriceBlock will attempt to determine the list price for sellable item.

Notable flow aspects

  • The GlobalPricingPolicy's CalculateItemListPriceInDepth property is set to false by default.
  • When iterating over variants for a valid ListPricingPolicy, the first variant to have a valid ListPricingPolicy will be used. The logic does not look for the lowest or highest price amongst all variants.

Calculate Variations List Price

The CalculateVariationsListPriceBlock will attempt to determine the list price for each variant of the sellable item.

Reconcile Sellable Item Prices

The ReconcileSellableItemPricesBlock will attempt to resolve missing List Prices and Sell Prices from the sellable item and variants. A flow diagram has been created for the Sellable Item and Variants separately.

Notable flow aspects

  • Setting the list price to 0 will ensure a price has been assigned.

Notable flow aspects

  • Setting the list price to 0 will ensure a price has been assigned.

Cart Line Calculations

The second scenario mentioned was that where the pricing calculation of sellable items/variants that have been added to the cart. The following step is performed after the standard pricing calculations to take into consideration the price tiers from price cards:

  1. Calculate Cart Line Price

Calculate Cart Line Price

The CalculateCartLinePricesBlock will determine and apply the appropriate list and sell prices for each cart line.

Notable flow aspects

  • There is an expectation that the list price and sell prices would have been resolved in Reconcile Sellable Item Prices.
  • Where a snapshot exists on a sellable item/variant the cart line's quantity value will determine the price tier that will be utilised to retrieve the sell price from.
  • The messages from the Sellable Item and, if applicable, Variant are copied into the cart line MessagesComponent to document the pricing stacks, which assist in auditing pricing overrides in determining the final pricing.

Glossary

Navigating the pricing logic can be time-consuming due to similar and varied terms being used for similar or varying components, so here is a short glossary for better clarification.

  • Sellable Item/Variant List Pricing (Policy): The list pricing policy represents an array of prices (only one price per currency) that are associated to a sellable item/variant is specified under the Pricing entity view of the sellable item/variant in the Merchanding manager.
  • Price Card (Name): The price card or price card name associated to the sellable item/variant is specified under the Pricing entity view of the sellable item/variant in the Merchanding manager.
  • Sellable Item/Variant list price: This is the ListPrice property of a Sellable Item/Variant, not to be confused with the ListPricingPolicy.
    "Policies": [
    	{
    		"@odata.type": "#Sitecore.Commerce.Plugin.Pricing.ListPricingPolicy",
    		"PolicyId": "0d4cee51dffd44aa8a019394dd5ad1b1",
    		"Prices": [
    			{
    				"CurrencyCode": "USD",
    				"Amount": 1919.69
    			},
    			{
    				"CurrencyCode": "CAD",
    				"Amount": 2078.26
    			}
    		]
    	}
    ],
    "ListPrice": {
    	"CurrencyCode": "USD",
    	"Amount": 1919.69
    }
    
  • Sell Price: The sell price is associated to a Sellable Item/Variant or Cart Line via the PurchaseOptionMoneyPolicy.
    "Policies": [
    	{
    		"@odata.type": "#Sitecore.Commerce.Plugin.Pricing.PurchaseOptionMoneyPolicy",
    		"PolicyId": "12b963fe3b2b47618555c8783c877002",
    		"Models": [],
    		"Expires": "2019-04-22T12:30:46.5380974Z",
    		"SellPrice": {
    			"CurrencyCode": "USD",
    			"Amount": 10
    		},
    		"FixedSellPrice": false
    	}
    ]
    
  • (Cart Line) Unit List Price: This is the determined list price of the cart line.
    "Policies": [
    	{
    		"@odata.type": "#Sitecore.Commerce.Plugin.Pricing.PurchaseOptionMoneyPolicy",
    		"PolicyId": "5e6c1f42c7c94bc4b79696e716b6cda5",
    		"Models": [],
    		"Expires": "2019-04-22T13:13:18.8117816Z",
    		"SellPrice": {
    			"CurrencyCode": "USD",
    			"Amount": 6
    		},
    		"FixedSellPrice": false
    	}
    ],
    "UnitListPrice": {
    	"CurrencyCode": "USD",
    	"Amount": 2429.99
    }
    

References

Sitecore Experience Commerce: Managing Catalog Images

In this article, we will look at how to manage catalog images that are associated to sellable items in the Business Tools' Merchandising Manager.

With the Habitat Master catalog and SXA Storefront site that is setup during the installation of Sitecore Experience Commerce, we have a great reference point for implementing custom sites. However, one of the not so obvious configurations is how to configure catalog images for new catalogs.

Commerce Media Items OData API Key

In Sitecore's Core database (pre XC 9.1) or Master database (from XC 9.1), the Commerce Media Items OData API Key contains the Search Filter property, which is responsible for applying the filter of media items that are restricted in the search results.

(Fields/any(f: (f/Name eq 'Extension' and (f/Value eq 'png' or f/Value eq 'jpg'))) and Language eq 'en' and (contains(Path, '/images/adventure') or contains(Path, '/images/habitat')))

The Search Filter value itself is performing 3 levels of filtering:-

  1. Extension Type: The supported media extension types.
  2. Language: The language is utilised to prevent duplicate media items from being returned, i.e. per language version.
  3. Location: The media library folder where the catalog images are stored.

Note: This is a global configuration that will apply to all media search controls in Sitecore Commerce. This means that although we can segregate catalog images to different Media Library folders in Sitecore, the Image search results in the Business Tools will return results for all configured catalog image folder locations and extension types.  This makes sense considering sellable items can be associated across catalogs.

Configuring Image Extension Types

The default configured image types include jpg and png formats. To modify the extension types, we look at the extension part of the filter where we can add or remove the Value comparisons as desired.

(f: (f/Name eq 'Extension' and (f/Value eq 'png' or f/Value eq 'jpg')))

Configure the Value comparison in the format f/Value eq '<extension type>'. Don't modify the wrapping logic. When specifying multiple extensions use the 'or' clause as per the initial configuration.

Adding Extension Type Example

In this example, I will add the gif extension type and sample image to validate the change.

Configure the Extension Type

In the Sitecore Content Editor using the Core database (pre XC 9.1) or Master database (from XC 9.1) :-

  1. Go to /sitecore/system/Settings/Services/API Keys/CommerceMediaItemsODataAPIKey
  2. Update the extension part of the Search Filter value to include the 'gif' comparison.
(f: (f/Name eq 'Extension' and (f/Value eq 'png' or f/Value eq 'jpg' or f/Value eq 'gif')))

Add Images of the New Extension Type

In the Sitecore Content Editor using the Master database:-

  1. Go to /sitecore/media library/Images/<catalog image folder>
  2. Upload the media file to the folder.

    e.g. sunglasses.gif
  3. Publish the item.
  4. Re-index the master/web databases.

Add the Image to a Sellable Item

In the Business Tools' Merchandising Manager:-

  1. Navigation to the desired Sellable Item or create a new Sellable Item.
    1. Ensure the Sellable Item's Entity Version has not been published, otherwise a new version will need to be created.
  2. Under the Images section, click the Add an Image button.
  3. Search for the image name.
  4. Select the image name and click the tick (accept) button.
  5. Promote the sellable item through the workflow states until it's published.

View the Image on the Sellable Item in the Storefront

In the Storefront's website:-

  1. Either navigate to the Category or Search Results Page, containing the product, navigate to any page that contains any component that displays the Sellable Item, e.g. Promoted Products component, or navigate directly to the Product Details Page.

Configuring Image Source Location

For media image location, we need to configure the location part of the filter where we can add or remove the Path comparisons as desired.

By default, we see that the locations have been configured for the folders that have been utilised for the Adventure Works and Habitat catalogs.

(contains(Path, '/images/adventure') or contains(Path, '/images/habitat'))

Configure the Path to the location of the catalog images folder in the format contains(Path, '/<catalog image folder location>')  where <catalog image folder location> is under the Media Library Sitecore item tree. When using multiple folder locations (usually one folder per catalog), use the 'or' clause as per the initial configuration.

Update: I found that the contains function had some issues with parsing the Path value where spaces are used in the item names, hence '/images/adventure' rather than '/images/adventure works'. Another issue I found was that using the contains function also meant that any folder structure, outside the Media Library item, in the Sitecore tree that matched the path would also be included for the media search results causing undesired entries.

To resolve this, I found a more performant an accurate solution using the startswith function, which appears to resolve the Path value relative to the Media Library item and accepts spaces in the item names.

(startswith(Path, '/images/adventure works/')

Please note that I haven't updated the remainder of this article with this change, but keep it in mind when making updating the filter yourself.

Adding Catalog Image Folder Example

In this example, I will add the HelloWorld catalog image folder type and sample image to validate the change.

Configure the Location Folders

In the Sitecore Content Editor using the Core database (pre XC 9.1) or Master database (from XC 9.1) :-

  1. Go to /sitecore/system/Settings/Services/API Keys/CommerceMediaItemsODataAPIKey
  2. Update the location part of the Search Filter value to include the 'helloworld' comparison.
(contains(Path, '/images/adventure') or contains(Path, '/images/habitat') or contains(Path, '/images/helloworld'))

Add Images of the Catalog Image Folder

In the Sitecore Content Editor using the Master database:-

  1. Go to /sitecore/media library/Images/HelloWorld
  2. Upload the media file to the folder.

    e.g. sunglasses.jpg
  3. Publish the item.
  4. Re-index the master/web databases.

Search for the Image in the Merchandising Manager

In the Business Tools' Merchandising Manager:-

  1. Navigation to the desired Sellable Item or create a new Sellable Item.
    1. Ensure the Sellable Item's Entity Version has not been published, otherwise a new version will need to be created.
  2. Under the Images section, click the Add an Image button.
  3. Search for the image name.
  4. Ensure the image shows in the search results

Summary

We learnt that the configurations of image folder location and filtered media extension types for catalog images are set in the Search Filter field of the Commerce Media Items OData API Key Sitecore item in the Core database (pre XC 9.1) or Master database (from XC 9.1) . We also learnt that the configurations are global and will apply to all media search controls in the Business Tools.