### promotion_dynamic_update Example Request (Get editable properties) Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example request for the promotion_dynamic_update tool to retrieve editable properties by providing only the promotion ID. ```json { "Id": "456" } ``` -------------------------------- ### Common OrderSearchOptions setup Source: https://docs.optimizely.com/commerce-connect-14/docs/searching-for-orders-using-ordercontext Defines common search options used by all following examples. Sets StartingRecord to 0, RecordsToRetrieve to 10000, and Namespace to "Mediachase.Commerce.Orders". ```csharp OrderSearchOptions searchOptions = new OrderSearchOptions(); searchOptions.StartingRecord = 0; searchOptions.RecordsToRetrieve = 10000; searchOptions.Namespace = "Mediachase.Commerce.Orders"; ``` -------------------------------- ### promotion_detail Example Request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example request for the promotion_detail tool, retrieving details for a promotion by its name or ContentReference ID. ```json { "Identifier": "20% Off Electronics", "IncludeAdditionalDetails": true } ``` -------------------------------- ### Install EPiServer.Commerce.Core NuGet package Source: https://docs.optimizely.com/commerce-connect-14/docs/authorizetokenex-installation-and-configuration Run this command in the Package Manager Console to install the EPiServer.Commerce.Core package, a prerequisite for building the AuthorizeTokenEx project. ```powershell Install-Package EPiServer.Commerce.Core ``` -------------------------------- ### promotion_create Example Request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example request for the promotion_create tool, creating a promotion within a campaign. Requires Name, Campaign, and PromotionType (full type name from promotion_types_list). Returns a confirmation dialog before creation. ```json { "Name": "Buy 2 Get 1 Free", "Campaign": "Summer Sale 2024", "PromotionType": "EPiServer.Commerce.Marketing.Promotions.BuyQuantityGetFreeItems", "Description": "Buy any 2 items, get 1 free" } ``` -------------------------------- ### Install Episerver CLI Tool globally Source: https://docs.optimizely.com/commerce-connect-14/docs/setting-up-your-development-environment Installs the EPiServer.Net.Cli tool globally from the Optimizely NuGet feed. Requires .NET 6. ```javascript dotnet tool install EPiServer.Net.Cli --global --add-source https://nuget.optimizely.com/feed/packages.svc/ ``` -------------------------------- ### Create new SKU using IContentRepository Source: https://docs.optimizely.com/commerce-connect-14/docs/catalog-content Shows how to create and publish a new SKU as IContent. Uses ServiceLocator to get IContentRepository, gets a default instance of CatalogContentTypeSample, sets required properties, and saves with SaveAction.Publish. ```csharp public ContentReference CreateNewSku(ContentReference linkToParentNode) { var contentRepository = ServiceLocator.Current.GetInstance(); //Create a new instance of CatalogContentTypeSample that will be a child to the specified parentNode. var newSku = contentRepository.GetDefault(linkToParentNode); //Set some required properties. newSku.Code = "MyNewCode"; newSku.SeoUri = "NewSku.aspx"; //Set the description newSku.Description = "This new SKU is great"; //Publish the new content and return its ContentReference. return contentRepository.Save(newSku, SaveAction.Publish, AccessLevel.NoAccess); } ``` -------------------------------- ### promotion_update Example Request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example request for the promotion_update tool, updating basic promotion properties such as name, active status, and priority. ```json { "Id": "456", "Name": "Buy 2 Get 1 Free - Extended", "IsActive": true, "Priority": 5 } ``` -------------------------------- ### Appsettings.json configuration example for Optimizely Commerce Connect Source: https://docs.optimizely.com/commerce-connect-14/docs/feature-specific-commerce-configurations Example configuration from the Optimizely Commerce 'Foundation' sample site. Shows the structure of the 'Commerce' section in Appsettings.json with options for handlers, plugins, meta objects, search, catalog, and other features. ```json { "Commerce": { "BusinessManagerOptions": { "Handlers": [ { "MetaClass": "Contact", "Method": "*", "TypeName": "Mediachase.Commerce.Customers.Handlers.ContactRequestHandler, Mediachase.Commerce" } ], "Plugins": [ { "MetaClass": "List", "Method": "CustomPage", "EventStage": "EventPipeLineStage.PostMainOperationInsideTranasaction", "TypeName": "Mediachase.Commerce.Customization.Plugins.CustomPageNormalizationPlugin, Mediachase.Commerce" } ] }, "MetaObjectOptions": { "MaxListObject": 1000, "UseCache": false, "CacheItemExpiration": 30, "UseSPOptimization": false, "SPItemExpiration": 10080, "Instances": [ { "MetaClass": "", "Type": "Mediachase.BusinessFoundation.Data.Meta.MetaObject, Mediachase.BusinessFoundation.Data" } ], "Types": [ { "Name": "Name", "Installer": "Mediachase.BusinessFoundation.Data.Meta.Management.DefaultMetaFieldInstaller, Mediachase.BusinessFoundation.Data", "Binder": "Mediachase.BusinessFoundation.Data.Meta.DefaultMetaObjectPropertyBinder, Mediachase.BusinessFoundation.Data" } ] }, "SearchOptions": { "DefaultSearchProvider": "LuceneSearchProvider", "MaxHitsForSearchResults": 1000, "IndexerBasePath": "[appDataPath]/Foundation/SearchIndex", "IndexerConnectionString": "", "SearchProviders": [ { "Name": "LuceneSearchProvider", "Type": "Mediachase.Search.Providers.Lucene.LuceneSearchProvider, Mediachase.Search.LuceneSearchProvider", "Parameters": { "queryBuilderType": "Mediachase.Search.Providers.Lucene.LuceneSearchQueryBuilder, Mediachase.Search.LuceneSearchProvider", "storage": "[appDataPath]/SearchIndex", "simulateFaceting": "true" } } ], "Indexers": [ { "Name": "catalog", "Type": "Mediachase.Search.Extensions.Indexers.CatalogIndexBuilder, Mediachase.Search.Extensions" } ] }, "CatalogOptions": { "AutoConfigure": true, "SalePriceTypes": [ { "Key": "Subscription", "Value": "3", "Description": "Subscription" }, { "Key": "MSRP", "Value": "4", "Description": "MSRP" } ], "ShowVariationListPrice": false, "CatalogImportBatchSize": 200, "CommandTimeout": -1, "CatalogEventLevel": 0, "DisableCatalogEventDrivenIndexing": false, "DisableQueueForIncrementalIndexing": false, "SkipCatalogContentModelCheck": false, "IgnorePropertyAndMetafieldMisMatch": false, "SimplifiedCatalogListingThreshold": 2000, "DraftMigrationBatchSize": 5000, "DraftMigrationTimeSpan": 1, "EnableFeatureGetReferencesInCatalog": false, "EnsurePublishedVersionInAllLanguages": true, "ArchivedThreshold": 30 }, "OptiGPTOptions": { "OptiAIKey": "", "OptiAISecret": "", "OptiAIUrl": "", "OptiAIDefaultModel": "" }, "ApplicationOptions": { "DefaultApplicationName": "ECApplication", "AdminHomePage": "Dashboard", "Cache": { "Enabled": true }, "AutoMigrate": true, "Features": { "DynamicPackageFeature": { "Feature": "DynamicPackageFeature", "State": 0, "Type": "Mediachase.Commerce.Core.Features.DynamicPackageFeature, Mediachase.Commerce" } } }, "CustomerOptions": { "AutoInstall": true, "DemoInstall": true }, "MarketingOptions": { "LinkableTypesEnabled": false }, "OrderOptions": { "NewOrderStatus": "InProgress", "SensitiveDataMode": 1, "AutoConfigure": true, "DisableOrderDataLocalization": false, "WishListCartNames": [ "WishList" ], "ExpiredCartsRemovalJobExcludedCartName": [ "" ], "ExpiredCartJobDays": 30, "CommandTimeout": 30 }, "PermissionOptions": { "Enable": false }, "DataOptions": { "DisableRetryPolicy": false, "LowFragmentationThreshold": 10, "HighFragmentationThreshold": 30, "DataBaseIndicesJobCommandTimeOut": -1, "LongQueryExecutionTimeOut": 10080, "UseBinaryFormatter": true }, "MetaDataOptions": { "DisableVersionSync": false } } } ``` -------------------------------- ### promotion_dynamic_update Example Request (Update properties) Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example request for the promotion_dynamic_update tool to update promotion properties using property paths with underscore notation for nested properties. ```json { "Id": "456", "Properties": { "Condition_RequiredQuantity": 3, "Discount_Percentage": 25.0, "IsActive": true } } ``` -------------------------------- ### campaign_create example request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example JSON request for the campaign_create tool, which creates a marketing campaign. The request requires Name, ValidFrom, and ValidUntil, with an optional Description. Note: this tool returns a confirmation dialog before creating the campaign. ```json { "Name": "Black Friday 2024", "Description": "Annual Black Friday sale event", "ValidFrom": "2024-11-29T00:00:00Z", "ValidUntil": "2024-12-02T23:59:59Z" } ``` -------------------------------- ### Install Optimizely templates with dotnet new Source: https://docs.optimizely.com/commerce-connect-14/docs/setting-up-your-development-environment Use this command to install the EPiServer.Templates package, which provides the necessary templates for creating Optimizely Customized Commerce projects. Requires .NET 6. ```javascript dotnet new -i EPiServer.Templates ``` -------------------------------- ### List promotions by sales response Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example response from the promotion_list_by_sales tool. Shows an items array with promotion details such as name, GUID, order count, discount type, and coupon code. ```json { "items": [ { "PromotionName": "20% Off Everything", "PromotionGuid": "abc123...", "OrderPlaced": 1250, "DiscountType": "Percentage", "CouponCode": "SAVE20" } ] } ``` -------------------------------- ### Get promotion properties response Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example response from the promotion_properties tool for the BuyQuantityGetItemDiscount promotion type. Shows a status code of 200, a message indicating 15 properties found, and a list of property objects with details such as name, property path, type, display name, description, required flag, and constraints. ```json { "StatusCode": 200, "Message": "Found 15 properties", "PromotionType": "BuyQuantityGetItemDiscount", "Properties": [ { "Name": "RequiredQuantity", "PropertyPath": "Condition_RequiredQuantity", "PropertyType": "Int32", "DisplayName": "Required Quantity", "Description": "Number of items required to trigger promotion", "IsRequired": true, "MinValue": 1, "DefaultValue": 1 }, { "Name": "Percentage", "PropertyPath": "Discount_Percentage", "PropertyType": "Decimal", "DisplayName": "Discount Percentage", "Description": "Percentage discount to apply", "IsRequired": true, "MinValue": 0, "MaxValue": 100 } ] } ``` -------------------------------- ### promotion_filter Example Request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example request for the promotion_filter tool, filtering promotions by name, active status, and target markets. ```json { "Name": "discount", "IsActive": true, "Markets": ["US"] } ``` -------------------------------- ### Get promotions and items for campaign Source: https://docs.optimizely.com/commerce-connect-14/docs/promotions-engine Gets a list of promotion items for a given campaign link. ```csharp IEnumerable promotionItemsList = ServiceLocator.Current.GetInstance().GetPromotionItemsForCampaign(campaignLink); ``` -------------------------------- ### Start webpack-dev-server for component development Source: https://docs.optimizely.com/commerce-connect-14/docs/extend-components Command to start the local development server for a component. The localhost runs on port 9090. ```shell yarn dev:server --config-name config-{folder name of the component} ``` -------------------------------- ### Install AuthorizeNet NuGet package Source: https://docs.optimizely.com/commerce-connect-14/docs/authorizetokenex-installation-and-configuration Run this command in the Package Manager Console to install the AuthorizeNet package version 1.9.4, a prerequisite for building the AuthorizeTokenEx project. ```powershell Install-Package AuthorizeNet -version 1.9.4 ``` -------------------------------- ### Get promotion details Source: https://docs.optimizely.com/commerce-connect-14/docs/common-workflows Gets promotion details using the promotion_detail tool, including additional details. ```json Tool: promotion_detail { "Identifier": "456", "IncludeAdditionalDetails": true } ``` -------------------------------- ### List all inventories Source: https://docs.optimizely.com/commerce-connect-14/docs/warehouses-and-inventories-examples Use IInventoryService.List() to list information for all inventories. The example returns an IEnumerable. ```text // List all inventory records. public IEnumerable ListAllInventories() { var inventoryService = ServiceLocator.Current.GetInstance(); return inventoryService.List(); } ``` -------------------------------- ### Get promotion prices for a collection of entries Source: https://docs.optimizely.com/commerce-connect-14/docs/promotions-engine Gets discounted entries for a collection of entry links using the promotion engine, current market, and default currency. ```csharp var promotionEngine = ServiceLocator.Current.GetInstance(); var currentMarket = ServiceLocator.Current.GetInstance(); var market = currentMarket.GetCurrentMarket(); IEnumerable discountedEntries = promotionEngine.GetDiscountPrices(entryLinks, market, market.DefaultCurrency); ``` -------------------------------- ### CSV asset file example Source: https://docs.optimizely.com/commerce-connect-14/docs/asset-importer Example CSV file with headers 'Variation Code' and 'Image ID', mapping product codes to asset file names. The first column is the Catalog Node/Entry code, and the second is the asset file name. Optional third column is sort order. ```text Variation Code,Image ID Jackets-Peacoats-Hooded,Jackets-Peacoats-Hooded.jpg Jackets-Peacoats-Ruffle,Jackets-Peacoats-Ruffle.jpg Jackets-Peacoats-Asymmetrical,Jackets-Peacoats-Asymmetrical.jpg 65990B,400x300.png 72008B,400x300.png 24215B,400x300.png Fashion,400x300.png,0 Fashion,980x150.png,2 Fashion,980x300.png,1 ``` -------------------------------- ### campaign_detail example request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example JSON request for the campaign_detail tool, which retrieves detailed information about a specific campaign. The request requires an Identifier and optionally includes additional details. ```json { "Identifier": "Summer Sale 2024", "IncludeAdditionalDetails": true } ``` -------------------------------- ### Configure services in Startup.cs Source: https://docs.optimizely.com/commerce-connect-14/docs/optimizely-graph-for-commerce-connect Adds the required services for Content Delivery API, Content Graph, and Commerce Graph in the ConfigureServices method. ```csharp services.AddContentDeliveryApi(); services.AddContentGraph(x => { x.IncludeInheritanceInContentType = true; x.PreventFieldCollision = true; }); services.AddCommerceGraph(); ``` -------------------------------- ### Get cache-skipping IInventoryService instance Source: https://docs.optimizely.com/commerce-connect-14/docs/warehouses-and-inventories-examples Use IInventoryService.GetCacheSkippingInstance(IEnumerable) to obtain an IInventoryService that skips the cache on reads. The example uses ServiceLocator to get the default instance and then calls GetCacheSkippingInstance. ```csharp // Gets an instance of IInventoryService that will skip the cache on reads. public IInventoryService GetCacheSkippingInstance() { var inventoryService= ServiceLocator.Current.GetInstance(); return inventoryService.GetCacheSkippingInstance(); } ``` -------------------------------- ### catalog_query example request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example JSON request for the catalog_query tool, filtering by ContentType, Name, IsAvailable, and Limit. The response includes Name, ContentType, ContentLink, ParentLink, type-specific fields, PricePerMarket data for variations, and Created, Changed, Language info. ```json { "ContentType": "ProductContent", "Name": "shirt", "IsAvailable": true, "Limit": 20 } ``` -------------------------------- ### Create a meta-field with MetaFieldBuilder Source: https://docs.optimizely.com/commerce-connect-14/docs/metafieldbuilder-class Example of using MetaFieldBuilder to create a meta-field. The Edit scope is automatically opened. The example creates a DateTime, Text, Guid, and Integer field, then calls SaveChanges(). ```text using (MetaFieldBuilder builder = new MetaFieldBuilder(metaClass)) { builder.CreateDateTime(CreatedFieldName, CreatedFriendlyName, false, true); builder.CreateText(CreatorFieldNameText, CreatorFriendlyName, false, 50, false); builder.CreateGuid(CreatorFieldNameGuid, CreatorFriendlyName, false); builder.CreateInteger(CreatorFieldNameInteger, CreatorFriendlyName, false, -1); builder.SaveChanges(); } ``` -------------------------------- ### Sample initialization module (C#) Source: https://docs.optimizely.com/commerce-connect-14/docs/initialization Use this module to register catalog content routes during initialization. It depends on EPiServer.Commerce.Initialization.InitializationModule and implements IInitializableModule. The Initialize method calls MapRoutes, which uses CatalogRouteHelper.MapDefaultHierarchialRouter. ```csharp using System.Web.Routing; using EPiServer.Framework; using EPiServer.Commerce.Routing; using EPiServer.Framework.Initialization; namespace CodeSamples.EPiServer.Commerce.Catalog { [ModuleDependency(typeof(global::EPiServer.Commerce.Initialization.InitializationModule))] public class RegisterRoutingModuleSample : IInitializableModule { public void Initialize(InitializationEngine context) { MapRoutes(RouteTable.Routes); } private static void MapRoutes(RouteCollection routes) { CatalogRouteHelper.MapDefaultHierarchialRouter(routes, true); } public void Uninitialize(InitializationEngine context) { /*uninitialize*/} public void Preload(string[] parameters) { } } } ``` -------------------------------- ### MarketImpl implementing ILowestPriceMarket Source: https://docs.optimizely.com/commerce-connect-14/docs/lowest-price-in-a-period-of-time Example of a market class implementing both IMarket and ILowestPriceMarket to use the feature. ```csharp public class MarketImpl : IMarket, ILowestPriceMarket { } ``` -------------------------------- ### Configure AI for product properties in Startup.cs Source: https://docs.optimizely.com/commerce-connect-14/docs/configure-ai-generated-product-descriptions Add this code to the ConfigureServices method in Startup.cs to enable AI generation for specified product model properties. Use UseOpalAIForProperties for multiple properties and UseOpalAIForProperty for a single property. Replace FashionProduct, FashionBundle, Description, and LongDescription with your own models and properties. ```csharp services.Configure(config => { config.UseOpalAIForProperties(x => x.Description, x => x.LongDescription); config.UseOpalAIForProperty(x => x.Description); }); ``` -------------------------------- ### Get a single inventory record Source: https://docs.optimizely.com/commerce-connect-14/docs/warehouses-and-inventories-examples Use IInventoryService.Get(string, string) to retrieve a single inventory record for a catalog entry and warehouse. The example calls Get() without arguments, which likely uses default parameters. ```csharp // Gets a single inventory record. public InventoryRecord GetAnInventory() { var inventoryService = ServiceLocator.Current.GetInstance(); return inventoryService.Get(); } ``` -------------------------------- ### Get validator properties request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example request body for the get_validator_properties tool. Requires PromotionType (campaign or promotion type name). Returns properties that have validation requirements. ```json { "PromotionType": "BuyQuantityGetFreeItems" } ``` -------------------------------- ### Get a warehouse by Code with IWarehouseRepository.Get(string) Source: https://docs.optimizely.com/commerce-connect-14/docs/warehouses-and-inventories-examples Use IWarehouseRepository.Get(string) to retrieve a single warehouse by its code. ```csharp // Get a specific Warehouse by Code public IWarehouse GetWarehouse(string warehouseCode) { var warehouseRepository = ServiceLocator.Current.GetInstance(); return warehouseRepository.Get(warehouseCode); } ``` -------------------------------- ### Get validator properties response Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example response from the get_validator_properties tool. Shows a status code of 200, a message indicating 3 properties with validators, and a list of property paths. ```json { "StatusCode": 200, "Message": "Found 3 properties with validators", "Properties": [ "Condition_RequiredQuantity", "Reward_NumberOfFreeItems", "Discount_Items" ] } ``` -------------------------------- ### Get a MetaClass collection and write names to trace Source: https://docs.optimizely.com/commerce-connect-14/docs/metaclass-class Retrieves the MetaClassManager from DataContext.Current.MetaModel and iterates over the MetaClasses collection, writing each meta-class name to the trace output. This example writes only user tables. ```csharp // Get MetaModel MetaClassManager metaModel = DataContext.Current.MetaModel; // Step 3. Enum meta-classes foreach (MetaClass mc in metaModel.MetaClasses) { Trace.WriteLine(mc.Name); } ``` -------------------------------- ### Create and update a warehouse with IWarehouseRepository.Save() Source: https://docs.optimizely.com/commerce-connect-14/docs/warehouses-and-inventories-examples Shows how to create a new warehouse and update an existing one. The IWarehouse object from Get/List is read-only; you must create a writable clone before updating. ```csharp public void CreateNewWarehouse() { var warehouseRepository = ServiceLocator.Current.GetInstance(); var warehouse = new Warehouse { Code = "NY", Name = "New York store", IsActive = true, IsPrimary = false, IsFulfillmentCenter = false, IsPickupLocation = true, IsDeliveryLocation = true, ContactInformation = new WarehouseContactInformation { FirstName = "First Name", LastName = "Last Name", Line1 = "Address Line 1", Line2 = "Address Line 2", City = "City", State = "State", CountryCode = "Country Code", PostalCode = "Postal Code", RegionCode = "Region Code", DaytimePhoneNumber = "Daytime Phone Number", EveningPhoneNumber = "Evening Phone Number", FaxNumber = "Fax Number", Email = "Email" } }; warehouseRepository.Save(warehouse); } public void UpdateWarehouse(string warehouseCode) { var warehouseRepository = ServiceLocator.Current.GetInstance(); var warehouse = warehouseRepository.Get(warehouseCode); // It's a read-only object var writableCloneWarehouse = new Warehouse(warehouse); // create writable clone before updating writableCloneWarehouse.IsPickupLocation = true; warehouseRepository.Service.Save(writableCloneWarehouse); } ``` -------------------------------- ### Define a product variant content type with CatalogContentType Source: https://docs.optimizely.com/commerce-connect-14/docs/commerce-rendering-templates Example of a simple content type for a product variant implementing IContent. It uses the CatalogContentType attribute with a GUID and MetaClassName, and inherits from VariationContent. ```csharp using System; using System.ComponentModel.DataAnnotations; using EPiServer.Commerce.Catalog.ContentTypes; using EPiServer.Commerce.Catalog.DataAnnotations; using EPiServer.Core; using EPiServer.DataAbstraction; using EPiServer.DataAnnotations; using EPiServer.SpecializedProperties; namespace MyCommerceSite.Models.Catalog { [CatalogContentType(GUID = "8d664789-3e96-409e-b418-baf807241f7c", MetaClassName = "My_Variation")] public class MyVariation : VariationContent { } } ``` -------------------------------- ### Install Optimizely.Commerce.Opal.Tools NuGet package Source: https://docs.optimizely.com/commerce-connect-14/docs/get-started-with-optimizely-agent-platform-tools Use this command to add the Optimizely.Commerce.Opal.Tools package to your project. Requires .NET 8.0 or later and EPiServer.Commerce.Core 14.x. ```bash dotnet add package Optimizely.Commerce.Opal.Tools ``` -------------------------------- ### Retrieving shipping method ID Source: https://docs.optimizely.com/commerce-connect-14/docs/shipping-gateways-and-providers Example code to retrieve the shipping method details using the methodId passed into GetRate. It looks up the shipping method and gets its name, handling the case where the row is not found. ```csharp // Look up payment method ShippingMethodDto methods = ShippingManager.GetShippingMethods(Thread.CurrentThread.CurrentCulture.Name); // the methodId was passed into the method as one of the method parameters ShippingMethodDto.ShippingMethodRow row = methods.ShippingMethod.FindByShippingMethodId(methodId); string name; if (row != null) { name = row.Name; } else { name = ""; } ``` -------------------------------- ### Create Optimizely Commerce project with dotnet CLI Source: https://docs.optimizely.com/commerce-connect-14/docs/creating-your-project Run these commands in order to create a new Optimizely Customized Commerce project, set up the CMS and commerce databases, and add an admin user. Replace ProjectName, username, password, and email with your own values. The -S and -E flags specify the SQL Server and use Windows authentication, and --reuse-cms-user reuses the CMS user for the commerce database. ```csharp dotnet new epi-commerce-empty --name ProjectName cd projectname dotnet-episerver create-cms-database ProjectName.csproj -S . -E dotnet-episerver create-commerce-database ProjectName.csproj -S . -E --reuse-cms-user dotnet-episerver add-admin-user ProjectName.csproj -u username -p password -e [email protected] -c EcfSqlConnection ``` -------------------------------- ### Get promotion properties request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example request body for the promotion_properties tool. Requires PromotionType (type name or full type name). Returns a response with status code, message, and a list of properties. ```json { "PromotionType": "BuyQuantityGetItemDiscount" } ``` -------------------------------- ### GetAssetUrl method example Source: https://docs.optimizely.com/commerce-connect-14/docs/asset-url-resolver Shows how to use AssetUrlResolver.GetAssetUrl to get the default asset for a variation. It creates a media file, adds it as a CommerceMedia to a variation, and returns the asset URL. Requires setting up the necessary services and content types. ```csharp using System.Globalization; using EPiServer; using EPiServer.Commerce.Catalog; using EPiServer.Commerce.Catalog.ContentTypes; using EPiServer.Commerce.SpecializedProperties; using EPiServer.Core; using EPiServer.DataAbstraction; using EPiServer.DataAccess; using EPiServer.Security; using EPiServer.Web; using Mediachase.Commerce.Catalog; public class UrlResolverSample { private AssetUrlResolver assetUrlResolver; private ReferenceConverter referenceConverter; private IContentLoader contentLoader; private AssetUrlConventions assetUrlConventions; private IContentRepository contentRepository; private ContentMediaResolver mediaDataResolver; private ContentTypeRepository contentTypeRepository; public string GetAssetUrl() { ContentReference rootCatalogLink; //Get a suitable MediaData type from extension var mediaType = mediaDataResolver.GetFirstMatching("jpg"); var contentType = contentTypeRepository.Load(mediaType); //Get a new empty file data var media = contentRepository.GetDefault(SiteDefinition.Current.GlobalAssetsRoot, contentType.ID); media.Name = "MyImages"; var contentLink = contentRepository.Save(media, SaveAction.Publish, AccessLevel.NoAccess); // Add variation var variation = contentRepository.GetDefault(rootCatalogLink, CultureInfo.GetCultureInfo("en-US")); variation.Name = "Variation name"; contentRepository.Save(variation, SaveAction.Save, AccessLevel.NoAccess); var commerceMedia = new CommerceMedia() {AssetLink = contentLink}; variation.CommerceMediaCollection.Add(commerceMedia); return assetUrlResolver.GetAssetUrl(variation); } } ``` -------------------------------- ### Retrieve package information for a shipping provider using ShippingMethodDto Source: https://docs.optimizely.com/commerce-connect-14/docs/shipping-gateways-and-providers This example shows how to retrieve package information for a shipping provider using ShippingMethodDto. It iterates through shipping options, gets associated packages, and retrieves individual package details. ```csharp Mediachase.Commerce.Orders.Dto.ShippingMethodDto shippingMethods = Mediachase.Commerce.Orders.Managers.ShippingManager.GetShippingMethods("en-us"); foreach(System.Data.DataRow row in shippingMethods.ShippingOption.Rows) { // A shipping option is a shipping provider Mediachase.Commerce.Orders.Dto.ShippingMethodDto.ShippingOptionRow shippingProviderRow = (Mediachase.Commerce.Orders.Dto.ShippingMethodDto.ShippingOptionRow)row; // now you have access to packages associated with the shipping provider Mediachase.Commerce.Orders.Dto.ShippingMethodDto.ShippingPackageRow[] packageRows = shippingProviderRow.GetShippingPackageRows(); //now you have access to the packages' names and id's //packageRows[0].ShippingPackageId //packageRows[0].PackageName //now you can retrieve the individual Package row with additional information Mediachase.Commerce.Orders.Dto.ShippingMethodDto method =Mediachase.Commerce.Orders.Managers.ShippingManager.GetShippingPackage(packageRows[0].PackageId); //the GetShippingPackage method just populates the Package table with the applicable shipping package if (method.Package.Rows.Count > 0) { Mediachase.Commerce.Orders.Dto.ShippingMethodDto.PackageRow packageRow = (Mediachase.Commerce.Orders.Dto.ShippingMethodDto.PackageRow)method.Package.Rows[0]; //here we can retrieve the package properties //packageRow.Length //packageRow.Height //packageRow.Width //packageRow.Description } } ``` -------------------------------- ### Retrieve and save catalog data using DTOs Source: https://docs.optimizely.com/commerce-connect-14/docs/low-level-apis Shows how to use CatalogContext.Current to get a CatalogDto, find an existing catalog ID, create a new catalog entry row, and save it. The example demonstrates the pattern of working with DTOs for saving catalog data. ```csharp ICatalogSystem target = CatalogContext.Current; CatalogDto catalogs = target.GetCatalogDto(); foreach (CatalogDto.CatalogRow catalog in catalogs.Catalog) { existingCatalogId = catalog.CatalogId; break; } CatalogEntryDto dto = target.GetCatalogEntriesDto(existingCatalogId, response); // Catalog entry create and set properties CatalogEntryDto.CatalogEntryRow catalogEntryRow = dto.CatalogEntry.NewCatalogEntryRow(); catalogEntryRow.ApplicationId = CatalogConfiguration.Instance.ApplicationId; dto.CatalogEntry.AddCatalogEntryRow(catalogEntryRow); target.SaveCatalogEntry(dto); ``` -------------------------------- ### Configure ODPJob through configuration file (Before 14.20.0) Source: https://docs.optimizely.com/commerce-connect-14/docs/commerce-connect-14-odp JSON configuration file sample for configuring the ODP integration before version 14.20.0. Uses MarketKeys with MarketId, AccessKey, and EndpointUrl. ```json { "EPiServer" : { "Commerce" : { "ODPJob": { "MarketKeys": [ { "MarketId": "US", "AccessKey": "key", "EndpointUrl": "https://api.zaius.com/" } ] } } } } ``` -------------------------------- ### Create a new record with CustomTableRow Source: https://docs.optimizely.com/commerce-connect-14/docs/working-with-sql-records Creates a new CustomTableRow object, sets column values using the index property, and calls Update to confirm the addition. Use PrimaryKeyId to get the primary key. BF supports Integer and Guid as primary keys. ```csharp // Create a new book CustomTableRow newBook = CustomTableRow(bookTable); newBook["Title"] = "Programming Windows Phone 7"; newBook.Update(); PrimaryKeyId newBookPk = newBook.PrimaryKeyId.Value; ``` -------------------------------- ### Render alternative and cross-sell recommendations in Package view Source: https://docs.optimizely.com/commerce-connect-14/docs/server-side-api-integration Add these sections to the Package view to render alternative products in RightMarginRecommendations and cross-sell products in BottomRecommendations. ```csharp @section RightMarginRecommendations { @{ Html.RenderAction("Index", "Recommendations", new { recommendations = Model.AlternativeProducts }); } } @section BottomRecommendations { @{ Html.RenderAction("Index", "Recommendations", new { recommendations = Model.CrossSellProducts }); } } ``` -------------------------------- ### commerce_list_market example request Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example JSON request for the commerce_list_market tool, filtering by IsEnabledOnly and Currency. ```json { "IsEnabledOnly": true, "Currency": "USD" } ``` -------------------------------- ### appsettings.json configuration for LowestPriceOptions Source: https://docs.optimizely.com/commerce-connect-14/docs/lowest-price-in-a-period-of-time JSON configuration to set the DaysAgo value for the lowest price tracking period. ```json "Commerce": { "LowestPriceOptions": { "DaysAgo": 30 }, } ``` -------------------------------- ### Register custom meta type installer and binder in appsettings.json (Commerce 14) Source: https://docs.optimizely.com/commerce-connect-14/docs/metatype-class For Commerce 14, register the custom meta-field installer and meta-object property binder in the 'Commerce' section of appsettings.json under 'MetaObjectTypeOptions'. Replace 'CustomType', 'Installer', and 'Binder' with your actual values. ```json "Commerce":{ "MetaObjectTypeOptions": { "Types": [ { "Name": "CustomType", "Installer": "", "Binder": "" } ] } } ``` -------------------------------- ### Apply Discounts to Cart with IPromotionEngine Source: https://docs.optimizely.com/commerce-connect-14/docs/order-processing Loads the default cart for the current contact and runs the promotion engine to apply discounts. Coupons must be added to the IOrderForm before calling ApplyDiscounts if required. The example shows both cart.ApplyDiscounts and promotionEngine.Run methods. ```csharp var orderRepository = ServiceLocator.Current.GetInstance(); var promotionEngine = ServiceLocator.Current.GetInstance(); var contactId = PrincipalInfo.CurrentPrincipal.GetContactId(); var cart = orderRepository.LoadCart(contactId, "Default"); //run apply discounts on the cart var rewardDescriptions = cart.ApplyDiscounts(promotionEngine, new PromotionEngineSettings()); //run apply discounts on the cart var rewardDescriptions = promotionEngine.Run(cart, new PromotionEngineSettings()); ``` -------------------------------- ### Promotion processor example in C# Source: https://docs.optimizely.com/commerce-connect-14/docs/custom-promotions This snippet shows a promotion processor with two methods. CanBeFulfilled checks if the promotion can be fulfilled by verifying a positive discount percentage and non-empty cart. GetRedemptions extracts affected entries and creates redemption descriptions. ```csharp /// Verify that the current promotion can potentially be fulfilled. /// /// /// This method is intended to be a very quick pre-check to avoid doing more expensive operations. /// In this case that a positive discount percentage has been set, and that the cart is not empty. /// /// The promotion to evaluate. /// The context for the promotion processor evaluation. /// /// true if the current promotion can potentially be fulfilled; otherwise, false. /// protected override bool CanBeFulfilled(PercentagePromotionSample promotionData, PromotionProcessorContext context) { if (promotionData.PercentageDiscount <= 0) { return false; } var lineItems = GetLineItems(context.OrderForm); if (!lineItems.Any()) { return false; } return true; } /// /// Gets all s affected by a given promotion. /// /// A collection of s to be checked against a promotion. /// The promotion used to evaluate the line items. /// A list of applicable s private IEnumerable GetRedemptions(IEnumerable applicableCodes, PercentagePromotionSample promotionData, PromotionProcessorContext context) { var redemptions = new List(); var requiredQuantity = promotionData.Condition.RequiredQuantity; var maxRedemptions = GetMaxRedemptions(promotionData.RedemptionLimits); for (int i = 0; i < maxRedemptions; i++) { var affectedEntries = context.EntryPrices.ExtractEntries(applicableCodes, requiredQuantity); if (affectedEntries == null) { break; } redemptions.Add(CreateRedemptionDescription(affectedEntries)); } return redemptions; } ``` -------------------------------- ### SqlBlobStream Constructor and Read Example Source: https://docs.optimizely.com/commerce-connect-14/docs/working-with-sql-records Example demonstrating how to create a SqlBlobStream object and read data from a BLOB column in chunks. ```APIDOC ## SqlBlobStream Constructor and Read Example ### Description Creates a SqlBlobStream object to read a BLOB column from a SQL table and reads data in chunks. ### Constructor `SqlBlobStream(string connectionString, string table, string blobColumn, SqlBlobAccess access, SqlParameter parameter)` ### Parameters - **connectionString** (string) - Required - The connection string to the database. - **table** (string) - Required - The name of the table containing the BLOB column. - **blobColumn** (string) - Required - The name of the BLOB column. - **access** (SqlBlobAccess) - Required - The access mode (e.g., SqlBlobAccess.Read). - **parameter** (SqlParameter) - Required - A SQL parameter to identify the row (e.g., @FileId). ### Example ```csharp strConnectionString = "Data source=(local);Initial catalog=TestDB;User Id=sa;Password="; string strSqlTable = "Files"; string strBLOBColumn = "Data"; try { using(SqlBlobStream stream = new SqlBlobStream(strConnectionString, strSqlTable, strBLOBColumn, SqlBlobAccess.Read, new SqlParameter("@FileId", 12345))) { byte[] tmpBuffer = new byte[1024]; int Length = 0; while ((Length = stream.Read(tmpBuffer, 0, 1024)) == 1024) { //Save tmpBuffer } } } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex); throw; } ``` ### Methods - **Read(byte[] buffer, int offset, int count)** - Reads a sequence of bytes from the current stream and advances the position. - **Seek(long offset, SeekOrigin origin)** - Sets the position within the current stream. ### Remarks - Supports synchronous and asynchronous read and write operations. - Supports random access using the Seek method. - Used to reduce memory usage when writing BLOB values by writing in chunks. ``` -------------------------------- ### Compare two meta-models and create synchronization script Source: https://docs.optimizely.com/commerce-connect-14/docs/exporting-and-importing-meta-models Loads an imported meta-model, extracts module manifests, loads the schema, loads the original meta-model, compares them with MetaModelSync.FindModifications, and saves the resulting sync commands to a file. The example includes a try-catch block that swallows exceptions. ```csharp try { // Load Imported Meta-Model List installedModules = new List(); XmlDocument xmlSrcMetaModel = new XmlDocument(); xmlSrcMetaModel.Load(srcMetaModelPath); // Load Modules From Source Meta-Model foreach (XmlNode xmlManifestNode in xmlSrcMetaModel.SelectNode("//mediachase.businessFoundation.data.meta/description/moduleManifests/moduleManifest")) { ModuleManifest manifest = McXmlSerializer.GetObject(xmlManifestNode.OuterXml); installedModules.Add(manifest); } // Load SchemaDocument SchemaDocument schema = new SchemaDocument(); schema.LoadDefault(installedModules.ToArray()); // Load Original Meta-model XmlDocument xmlDestMetaModel = new XmlDocument(); xmlDestMetaModel.Load(destMetaModelPath); // Compare two Meta-models SyncCommand\[] syncCommands = MetaModelSync.FindModifications(schema, xmlSrcMetaModel, xmlDestMetaModel); // Save sync commands to file McXmlSerializer.SaveObjectToFile(outputSyncFilePath, syncCommands); } catch (Exception ex) { } ``` -------------------------------- ### commerce_list_market example response Source: https://docs.optimizely.com/commerce-connect-14/docs/available-tools Example JSON response from the commerce_list_market tool, showing a successful status code and market details. ```json { "StatusCode": 200, "Message": "Found 3 markets", "Markets": [ { "MarketId": "US", "MarketName": "United States", "MarketDescription": "US Market", "DefaultCurrency": "USD", "DefaultLanguage": "en", "IsEnabled": true, "Countries": ["US"], "Languages": ["en", "es"] } ] } ``` -------------------------------- ### Listen for price and inventory changes with InitializationModule and SiteCatalogContentEventListener Source: https://docs.optimizely.com/commerce-connect-14/docs/indexing-variants-in-a-product-document Initialization module that sets PriceIndexing.IsIndexingIIndexedPrices to true and registers SiteCatalogContentClientConventions. Includes a custom event listener that overrides IndexContentsIfNeeded to index parent products instead of variants, with commented-out code for indexing variants if needed. ```csharp [InitializableModule] [ModuleDependency(typeof(FindCommerceInitializationModule))] public class InitializationModule : IConfigurableModule { public void Initialize(InitializationEngine context) { context.Locate.Advanced.GetInstance().IsIndexingIIndexedPrices = true; } public void Uninitialize(InitializationEngine context) { } public void ConfigureContainer(ServiceConfigurationContext context) { context.Services.AddSingleton(); } } public class SiteCatalogContentEventListener : CatalogContentEventListener { private ReferenceConverter _referenceConverter; private readonly IContentRepository _contentRepository; private readonly IRelationRepository _relationRepository; public SiteCatalogContentEventListener( ReferenceConverter referenceConverter, IContentRepository contentRepository, IClient client, CatalogEventIndexer indexer, CatalogContentClientConventions catalogContentClientConventions, PriceIndexing priceIndexing, IRelationRepository relationRepository) : base( referenceConverter, contentRepository, client, indexer, catalogContentClientConventions, priceIndexing) { _referenceConverter = referenceConverter; _contentRepository = contentRepository; _relationRepository = relationRepository; } protected override void IndexContentsIfNeeded(IEnumerable contentLinks, IDictionary cachedReindexContentOnEventForType, Func isReindexingContentOnUpdates) { // Update parent contents var contents = _contentRepository.GetItems(contentLinks, CultureInfo.InvariantCulture).ToList(); var parentContentLinks = new List(); foreach (var parents in contents.OfType().Select(content => _contentRepository.GetItems(content.GetParentProducts(_relationRepository), CultureInfo.InvariantCulture).Select(c => c.ContentLink).ToList())) { parentContentLinks.AddRange(parents); } // If index variants still needed, keep the line below // IndexContentsIfNeeded(contentLinks, GetIndexContentAction(), cachedReindexContentOnEventForType, isReindexingContentOnUpdates); IndexContentsIfNeeded(parentContentLinks, GetIndexContentAction(), cachedReindexContentOnEventForType, isReindexingContentOnUpdates); } } ``` -------------------------------- ### Get details of top-performing promotion Source: https://docs.optimizely.com/commerce-connect-14/docs/common-workflows Gets details of the top-performing promotion using the promotion_detail tool, including additional details. ```json Tool: promotion_detail { "Identifier": "top-promotion-id", "IncludeAdditionalDetails": true } ``` -------------------------------- ### Implement TrackProduct method Source: https://docs.optimizely.com/commerce-connect-14/docs/server-side-api-integration This method creates product tracking data, optionally skips recommendations, and sends the tracking request asynchronously. ```csharp public async Task TrackProduct(HttpContextBase httpContext, string productCode, bool skipRecommendations) { ... var trackingData = _trackingDataFactory.CreateProductTrackingData(productCode, httpContext); if (skipRecommendations) { trackingData.SkipRecommendations(); } return await _trackingService.TrackAsync(trackingData, httpContext, _contentRouteHelperAccessor().Content); } ``` -------------------------------- ### Register custom meta type installer and binder in application config (Version 10-13) Source: https://docs.optimizely.com/commerce-connect-14/docs/metatype-class For versions 10-13, register the custom meta-field installer and meta-object property binder in the 'mediachase.businessFoundation.data/metaObject/types' section of the application config file. Replace 'CustomType', 'installer', and 'binder' with your actual values. ```xml * ``` -------------------------------- ### Configure ODPJobOptions through code (Before 14.20.0) Source: https://docs.optimizely.com/commerce-connect-14/docs/commerce-connect-14-odp C# code sample for configuring the ODP integration through code before version 14.20.0. Uses MarketKey with MarketId, AccessKey, and EndpointUrl. ```csharp services.Configure < ODPJobOptions > (o => { o.MarketKeys = new List < MarketKey > { new() { MarketId = "US", AccessKey = "key", EndpointUrl = "" } }; }); ``` -------------------------------- ### Get promotion prices for a single entry Source: https://docs.optimizely.com/commerce-connect-14/docs/promotions-engine Gets discounted entries for a single entry link using the promotion engine and current market. ```csharp var promotionEngine = ServiceLocator.Current.GetInstance(); var currentMarket = ServiceLocator.Current.GetInstance(); IEnumerable discountedEntries = promotionEngine.GetDiscountPrices(entryLink, currentMarket); ```