### Install Optimizely Templates Source: https://docs.developers.optimizely.com/commerce-connect/docs/setting-up-your-development-environment Installs the necessary project templates for Optimizely Customized Commerce development. Ensure you have the .NET 6 SDK installed. ```bash dotnet new -i EPiServer.Templates ``` -------------------------------- ### Install EPiServer.Commerce.Core NuGet Package Source: https://docs.developers.optimizely.com/commerce-connect/docs/authorizetokenex-installation-and-configuration Use this command in the Package Manager Console to install the EPiServer.Commerce.Core NuGet package. This is required for Commerce Connect integration. ```powershell Install-Package EPiServer.Commerce.Core ``` -------------------------------- ### Install Episerver CLI Tool Source: https://docs.developers.optimizely.com/commerce-connect/docs/setting-up-your-development-environment Installs the global Episerver command-line interface tool. This tool is required for managing Optimizely projects and requires .NET 6. ```bash dotnet tool install EPiServer.Net.Cli --global --add-source https://nuget.optimizely.com/feed/packages.svc/ ``` -------------------------------- ### Market Listing Response Example Source: https://docs.developers.optimizely.com/commerce-connect/docs/available-tools Example of a successful response when listing markets, showing market details like ID, name, currency, language, and availability. ```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"] } ] } ``` -------------------------------- ### Example ICouponUsage Implementation Source: https://docs.developers.optimizely.com/commerce-connect/docs/coupons An example implementation of the ICouponUsage interface. The Report method can be used to store information about the coupon codes that were used when a purchase is made. ```csharp public class CustomCouponUsage : ICouponUsage { public void Report(IEnumerable appliedPromotions) { // Store any information needed about the coupon codes that were used. } } ``` -------------------------------- ### Example Configuration for Scopes and Channels Source: https://docs.developers.optimizely.com/commerce-connect/docs/multiple-scopes This XML configuration demonstrates setting up scopes, channels, and different types of settings (required and optional) with their respective values. ```xml ``` -------------------------------- ### Install Optimizely Opal Tools NuGet Package Source: https://docs.developers.optimizely.com/commerce-connect/docs/get-started-with-opal-tools Add the Optimizely.Commerce.Opal.Tools NuGet package to your project using the .NET CLI. ```bash dotnet add package Optimizely.Commerce.Opal.Tools ``` -------------------------------- ### Example ICouponFilter Implementation Source: https://docs.developers.optimizely.com/commerce-connect/docs/coupons An example filter that verifies against a single coupon code. It checks if provided coupon codes match promotion coupon codes and excludes promotions if a required coupon is missing. ```csharp public virtual PromotionFilterContext Filter(PromotionFilterContext filterContext, IEnumerable couponCodes) { foreach (var promotion in filterContext.IncludedPromotions) { var couponCode = promotion.Coupon.Code; if (String.IsNullOrEmpty(couponCode)) { continue; } if (couponCodes.Contains(couponCode, StringComparer.OrdinalIgnoreCase)) { filterContext.AddCouponCode(promotion.ContentGuid, couponCode); } else { filterContext.ExcludePromotion( promotion, FulfillmentStatus.CouponCodeRequired, filterContext.RequestedStatuses.HasFlag(RequestFulfillmentStatus.NotFulfilled))); } } return filterContext; } ``` -------------------------------- ### Create Recommendations View Source: https://docs.developers.optimizely.com/commerce-connect/docs/server-side-api-integration Create a partial view to render recommendation data. This example iterates through recommended products and renders a partial view for each product tile. ```cshtml @model EPiServer.Reference.Commerce.Site.Features.Recommendations.ViewModels.RecommendationsViewModel @foreach (var product in Model.Products) {
@Html.Partial("_Product", product.TileViewModel)
} ``` -------------------------------- ### Install AuthorizeNet NuGet Package Source: https://docs.developers.optimizely.com/commerce-connect/docs/authorizetokenex-installation-and-configuration Use this command in the Package Manager Console to install the AuthorizeNet NuGet package. Ensure you are using version 1.9.4. ```powershell Install-Package AuthorizeNet -version 1.9.4 ``` -------------------------------- ### Create Orders with IOrderRepository Source: https://docs.developers.optimizely.com/commerce-connect/docs/order-manipulation Demonstrates creating different order types such as carts, purchase orders, and payment plans using the `IOrderRepository`. Ensure you have the necessary service locator setup. ```csharp var orderRepository = ServiceLocator.Current.GetInstance(); var contactId = PrincipalInfo.CurrentPrincipal.GetContactId(); //Create cart var cart = orderRepository.Create(contactId, "Default"); //Create purchase order var purchaseOrder = orderRepository.Create(contactId, "Default"); //Create payment plan var paymentPlan = orderRepository.Create(contactId, "Default"); ``` -------------------------------- ### Configure Brand and Color Facets Source: https://docs.developers.optimizely.com/commerce-connect/docs/configuring-facets-and-filters Example configuration for brand and color facets using SimpleValue type. Includes localized descriptions for different locales. ```xml Brand Märke Brand 0 Märke 0 Brand 1 Märke 1 Brand 2 Märke 2 Brand 3 Märke 3 Color Färg Black Svart White Vit Red ``` -------------------------------- ### Initialize SqlContext and Get Database Object Source: https://docs.developers.optimizely.com/commerce-connect/docs/sql-meta-model Initializes the SqlContext and retrieves the Database object. The using statement ensures SqlContext.Dispose is called automatically. ```csharp // Step 0. Connection String string connectionString = "Data Source=(local);Initial Catalog=TestDatabase;User ID=sa;Password=;"; // Step 1. Initialize Sql Meta Model using (SqlContext.Current = new SqlContext(connectionString)) { // Step 2. Get Database Database database = SqlContext.Current.Database; } ``` -------------------------------- ### Get Promotions and Items for a Campaign Source: https://docs.developers.optimizely.com/commerce-connect/docs/promotions-engine Retrieve a list of promotions and associated items for a specific campaign using the promotion engine. The EPiServer.Commerce.Marketing namespace is required. ```csharp IEnumerable promotionItemsList = ServiceLocator.Current.GetInstance().GetPromotionItemsForCampaign(campaignLink); ``` -------------------------------- ### Get Promotion Prices for Multiple Entries Source: https://docs.developers.optimizely.com/commerce-connect/docs/promotions-engine Obtain discounted prices for a collection of entries, specifying the market and currency. Ensure the EPiServer.Commerce.Marketing namespace is included. ```csharp var promotionEngine = ServiceLocator.Current.GetInstance(); var currentMarket = ServiceLocator.Current.GetInstance(); var market = currentMarket.GetCurrentMarket(); IEnumerable discountedEntries = promotionEngine.GetDiscountPrices(entryLinks, market, market.DefaultCurrency); ``` -------------------------------- ### Get Promotion Properties Source: https://docs.developers.optimizely.com/commerce-connect/docs/available-tools Retrieve all available properties for a given promotion type, including metadata like Name, PropertyPath, and Description. This is useful for understanding the structure and requirements of a promotion. ```json { "PromotionType": "BuyQuantityGetItemDiscount" } ``` -------------------------------- ### Get Single Inventory Record Source: https://docs.developers.optimizely.com/commerce-connect/docs/warehouses-and-inventories-examples Retrieve a specific inventory record for a given catalog entry and warehouse. The method signature in the example appears incomplete. ```csharp // Gets a single inventory record. public InventoryRecord GetAnInventory() { var inventoryService = ServiceLocator.Current.GetInstance(); return inventoryService.Get(); } ``` -------------------------------- ### Percentage Promotion Processor Example Source: https://docs.developers.optimizely.com/commerce-connect/docs/custom-promotions Implement a custom promotion processor for percentage-based discounts. This class evaluates promotions against order forms, determines applicable items, and calculates the reward description. ```csharp using EPiServer.Commerce.Extensions; using EPiServer.Commerce.Marketing; using EPiServer.Framework.Localization; using EPiServer.ServiceLocation; using System.Collections.Generic; using System.Linq; namespace CodeSamples.EPiServer.Commerce.Marketing { #region PercentagePromotionProcessorSample /// /// Sample of a promotion processor for . /// [ServiceConfiguration(Lifecycle = ServiceInstanceScope.Singleton)] public class PercentagePromotionProcessorSample : EntryPromotionProcessorBase { private readonly CollectionTargetEvaluator _targetEvaluator; private readonly FulfillmentEvaluator _fulfillmentEvaluator; private readonly LocalizationService _localizationService; /// /// Creates a new instance of a . /// /// The service that is used to evaluate an order against a promotion's target properties. /// The service that is used to evaluate the fulfillment status of the promotion. /// The service that is used to get localized strings. public PercentagePromotionProcessorSample( CollectionTargetEvaluator targetEvaluator, FulfillmentEvaluator fulfillmentEvaluator, LocalizationService localizationService) { _targetEvaluator = targetEvaluator; _fulfillmentEvaluator = fulfillmentEvaluator; _localizationService = localizationService; } /// /// Evaluates a promotion against an order form. /// /// The promotion to evaluate. /// The promotion processor context. /// /// A telling whether the promotion was fulfilled, /// which items the promotion was applied to and to which discount percentage. /// protected override RewardDescription Evaluate(PercentagePromotionSample promotionData, PromotionProcessorContext context) { var lineItems = GetLineItems(context.OrderForm); var condition = promotionData.Condition; var applicableCodes = _targetEvaluator.GetApplicableCodes(lineItems, condition.Items, condition.MatchRecursive); var fulfillmentStatus = _fulfillmentEvaluator.GetStatusForBuyQuantityPromotion( applicableCodes, lineItems, condition.RequiredQuantity, condition.PartiallyFulfilledThreshold); var affectedEntries = context.EntryPrices.ExtractEntries(applicableCodes, condition.RequiredQuantity); return RewardDescription.CreatePercentageReward( fulfillmentStatus, GetRedemptions(applicableCodes, promotionData, context), promotionData, promotionData.PercentageDiscount, fulfillmentStatus.GetRewardDescriptionText(_localizationService)); } /// /// Gets the items related to a promotion. /// /// The promotion data to get items for. /// /// The promotion condition and reward items. /// protected override PromotionItems GetPromotionItems(PercentagePromotionSample promotionData) { var specificItems = new CatalogItemSelection( promotionData.Condition.Items, CatalogItemSelectionType.Specific, promotionData.Condition.MatchRecursive); return new PromotionItems(promotionData, specificItems, specificItems); } /// /// 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. ``` -------------------------------- ### Configure Opal AI for Product Properties Source: https://docs.developers.optimizely.com/commerce-connect/docs/set-up-opal-ai Add this code to your `Startup.cs` file's `ConfigureServices` method to specify which product model properties should use AI generation. Replace `FashionProduct`, `FashionBundle`, `Description`, and `LongDescription` with your actual product models and properties. ```csharp services.Configure(config => { config.UseOpalAIForProperties(x => x.Description, x => x.LongDescription); config.UseOpalAIForProperty(x => x.Description); }); ``` -------------------------------- ### Initialize Custom Campaign Routes Source: https://docs.developers.optimizely.com/commerce-connect/docs/marketing Sets up custom routing for campaign content by implementing 'IConfigurableModule'. This module registers a specific route for campaign management, allowing for custom URL structures. Ensure EPiServer.Commerce.Initialization.InitializationModule is a dependency. ```csharp using EPiServer.Core; using EPiServer.DataAbstraction; using EPiServer.Framework; using EPiServer.Framework.Initialization; using EPiServer.ServiceLocation; using EPiServer.Web.Routing; using EPiServer.Web.Routing.Segments; using System.Linq; using System.Web.Routing; namespace EPiServer.Commerce.Sample.Business.Initialization { /// /// Initialization module to handle the initialization of Commerce. /// [ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))] [InitializableModule] public class CampaignInitalization : IConfigurableModule { /// /// Initializes Commerce using the specified context. /// /// The context. public void Initialize(InitializationEngine context) { EPiServer.Global.RoutesRegistered += Global_RoutesRegistered; } private void Global_RoutesRegistered(object sender, RouteRegistrationEventArgs e) { RegisterRoutes(RouteTable.Routes); } private static void RegisterRoutes(RouteCollection routes) { // Route for editing commerce content (which has a root not connected to the global root) MapCampaignRoute(routes, name: "campaignroot", url: "Campaigns/{language}/{nodeedit}/{partial}/{action}", defaults: new { action = "index" }); } private static void MapCampaignRoute(RouteCollection routes, string name, string url, object defaults, object constraints = null) { var contentRootService = ServiceLocator.Current.GetInstance(); var root = ServiceLocator.Current.GetInstance() .GetItems(contentRootService.List(), new LoaderOptions()) .SingleOrDefault(x => x.Name.Equals("SysCampaignRoot")); var segmentRouter = ServiceLocator.Current.GetInstance(); segmentRouter.RootResolver = (sd) => root.ContentLink; var parameters = new MapContentRouteParameters { UrlSegmentRouter = segmentRouter, BasePathResolver = null,//Use Cms default Direction = SupportedDirection.Both, Constraints = constraints }; routes.MapContentRoute( name, url, defaults, parameters); } public void Uninitialize(InitializationEngine context) { // Uninitialize catalog content version } public void ConfigureContainer(ServiceConfigurationContext context) { } } } ``` -------------------------------- ### Get Cache Skipping Inventory Service Instance Source: https://docs.developers.optimizely.com/commerce-connect/docs/warehouses-and-inventories-examples Retrieves an instance of `IInventoryService` that bypasses the cache for read operations. This is useful for ensuring you get the most up-to-date inventory data. ```APIDOC ## GetCacheSkippingInstance ### Description Gets an instance of `IInventoryService` that will skip the cache on reads. ### Method Signature `public IInventoryService GetCacheSkippingInstance()` ### Example Usage ```csharp // Gets an instance of IInventoryService that will skip the cache on reads. public IInventoryService GetCacheSkippingInstance() { var inventoryService= ServiceLocator.Current.GetInstance(); return inventoryService.GetCacheSkippingInstance(); } ``` ``` -------------------------------- ### Update an Existing Warehouse Source: https://docs.developers.optimizely.com/commerce-connect/docs/warehouses-and-inventories-examples To update a warehouse, first retrieve it using `Get`, create a writable clone, modify its properties, and then save the clone. The `IWarehouse` object returned by `Get` is read-only. ```csharp 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); } ``` ```csharp public void UpdateWarehouse(string warehouseCode) { var warehouseRepository = ServiceLocator.Current.GetInstance(); var warehouse = warehouseRepository.Get(warehouseCode); // It's a read-only object var writableCloneWarehouse = warehouse.CreateWritableClone(); writableCloneWarehouse.IsPickupLocation = true; warehouseRepository.Service.Save(writableCloneWarehouse); } ``` -------------------------------- ### Implement Custom Price Optimizer Source: https://docs.developers.optimizely.com/commerce-connect/docs/pricing Implement the IPriceOptimizer interface to customize how prices are optimized. This example groups prices by common attributes and selects the one with the highest unit price amount. ```csharp public class CustomPriceOptimizer : IPriceOptimizer { public IEnumerable OptimizePrices(IEnumerable prices) { return prices.GroupBy(p => new { p.CatalogKey, p.MinQuantity, p.MarketId, p.ValidFrom, p.CustomerPricing, p.UnitPrice.Currency }) .Select(g => g.OrderByDescending(c => c.UnitPrice.Amount).First()).Select(p => new OptimizedPriceValue(p, null)); } } ``` -------------------------------- ### Start Local Development Server for React Components Source: https://docs.developers.optimizely.com/commerce-connect/docs/extend-components Use `yarn dev:server` with a specific config name to start the webpack-dev-server for local development of your React components. The server typically runs on port 9090. ```shell yarn dev:server --config-name config-{folder name of the component} ``` -------------------------------- ### Implement Custom Entry Information Source: https://docs.developers.optimizely.com/commerce-connect/docs/extend-search-result-display Implement IEntryInformation to customize displayed properties and product URLs. Inject the default implementation to leverage existing logic. ```csharp public class CustomEntryInformation : IEntryInformation { IRelationRepository _relationRepository = ServiceLocation.ServiceLocator.Current.GetInstance(); IUrlResolver _urlResolver = ServiceLocation.ServiceLocator.Current.GetInstance(); IEntryInformation _defaultImplementation; public CustomEntryInformation(IEntryInformation defaultImplementation) { _defaultImplementation = defaultImplementation; } public IDictionary GetCustomProperties(EntryContentBase entry) { var myVariant = entry as MyVariant; if (myVariant == null) { return _defaultImplementation.GetCustomProperties(entry); } return new Dictionary() { { nameof(myVariant.Size), myVariant.Size.ToString() }, { nameof(myVariant.Color), myVariant.Color } }; } public string GetProductUrl(EntryContentBase entry) { var productLink = entry is VariationContent ? entry.GetParentProducts(_relationRepository).FirstOrDefault() : entry.ContentLink; if (productLink == null) { return string.Empty; } var urlBuilder = new UrlBuilder(_urlResolver.GetUrl(productLink)); if (entry.Code != null) { urlBuilder.QueryCollection.Add("variationCode", entry.Code); } return urlBuilder.ToString(); } } public class MyVariant : VariationContent { public virtual int Size { get; set; } public virtual string Color { get; set; } public virtual int IntegrationCode { get; set; } } ``` -------------------------------- ### Create a New Guid MetaField Source: https://docs.developers.optimizely.com/commerce-connect/docs/metafield-class This method creates a new Guid meta-field for a meta-class. It handles null checks for name and friendly name, and sets a default value based on whether the field is nullable. Requires an initialized MetaClass object. ```csharp public MetaField CreateGuid(string name, string friendlyName, bool isNullable) { if (name == null) throw new ArgumentNullException("name"); if (friendlyName == null) throw new ArgumentNullException("friendlyName"); AttributeCollection attr = new AttributeCollection(); string defaultValue = isNullable ? string.Empty : "newid()"; MetaField retVal = this.MetaClass.CreateMetaField(name, friendlyName, MetaFieldType.Guid, isNullable, defaultValue, attr); return retVal; } ``` -------------------------------- ### CSV Asset File Structure Example Source: https://docs.developers.optimizely.com/commerce-connect/docs/asset-importer Example of a CSV file mapping catalog items to assets. The first column is typically the Catalog Node/Entry code, and the second is the asset file name. An optional third column specifies the 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 ``` -------------------------------- ### Enable Event-Driven Order Reporting in Startup.cs Source: https://docs.developers.optimizely.com/commerce-connect/docs/collect-data-for-reports Configure event-driven order reporting to be enabled by setting EnableEventDrivenOrderReporting to true within the ConfigureServices method of Startup.cs. ```csharp //Startup.cs public void ConfigureServices(IServiceCollection services) { services.Configure(o => { o.EnableEventDrivenOrderReporting = true; }); } ``` -------------------------------- ### promotion_detail Source: https://docs.developers.optimizely.com/commerce-connect/docs/available-tools Get comprehensive details about a specific promotion using its identifier. ```APIDOC ## promotion_detail ### Description Get comprehensive details about a specific promotion. ### Method POST ### Endpoint /promotion_detail ### Parameters #### Request Body - **Identifier** (string) - Required - Promotion name or ContentReference ID. - **IncludeAdditionalDetails** (boolean) - Optional - Includes all properties and audit info. ### Request Example ```json { "Identifier": "20% Off Electronics", "IncludeAdditionalDetails": true } ``` ### Response #### Success Response (200) - **StatusCode** (integer) - The status code of the response. - **Message** (string) - A message indicating the result of the operation. - **Promotion** (object) - Details of the promotion. - **Id** (string) - The unique identifier of the promotion. - **Name** (string) - The name of the promotion. - **Description** (string) - The description of the promotion. - **IsActive** (boolean) - Indicates if the promotion is currently active. - **PromotionType** (string) - The type of the promotion. - **FullTypeName** (string) - The full internal name of the promotion type. - **CampaignId** (string) - The ID of the campaign the promotion belongs to. - **Priority** (integer) - The priority of the promotion. - **CouponCode** (string) - The coupon code associated with the promotion, if any. - **DiscountType** (string) - The type of discount applied (e.g., Percentage, Amount). - **ValidFrom** (string) - The start date and time when the promotion is valid (ISO 8601). - **ValidUntil** (string) - The end date and time when the promotion is valid (ISO 8601). - **EditLinkUrl** (string) - URL to edit the promotion in the CMS. - **Properties** (array) - A list of properties associated with the promotion. - **Name** (string) - The name of the property. - **Value** (any) - The value of the property. - **PropertyType** (string) - The data type of the property. ### Response Example ```json { "StatusCode": 200, "Message": "Promotion found", "Promotion": { "Id": "456", "Name": "20% Off Electronics", "Description": "20% discount on all electronics", "IsActive": true, "PromotionType": "BuyQuantityGetItemDiscount", "FullTypeName": "EPiServer.Commerce.Marketing.Promotions.BuyQuantityGetItemDiscount", "CampaignId": "123", "Priority": 10, "CouponCode": "ELEC20", "DiscountType": "Percentage", "ValidFrom": "2024-06-01T00:00:00Z", "ValidUntil": "2024-08-31T23:59:59Z", "EditLinkUrl": "/episerver/cms/...", "Properties": [ { "Name": "Condition_RequiredQuantity", "Value": 1, "PropertyType": "Int32" }, { "Name": "Discount_Percentage", "Value": 20.0, "PropertyType": "Decimal" } ] } } ``` ``` -------------------------------- ### Configure Product Recommendations environment Source: https://docs.developers.optimizely.com/commerce-connect/docs/installing-and-configuring-the-native-integration-package Configure settings for your Product Recommendations environment using `appsettings.json` and the `PersonalizationOptions` class. This includes API URLs, tokens, site information, and scope-specific settings. ```json { "EPiServer": { "Personalization": { "PersonalizationOptions": { "BaseApiUrl": "https://defaultbaseurl.com", "Site": "defaultsite", "ClientToken": "defaultclienttoken", "AdminToken": "defaultadmin", "Channel": "test", "RequestTimeout": 30, "TrackingMode": "ClientSide", "SkipUserHostTracking": true, "UsePseudonymousUserId": true, "FeedCatalogName": "Test", "FeedSkipProductLevel": true, "Scopes": [ { "AdminToken": "scopeadmin", "BaseApiUrl": "https://scopebaseurl.com", "ClientToken": "scopeclienttoken", "Site": "scopesite", "Channel": "scopetest", "FeedCatalogName": "ScopeTest", "FeedSkipProductLevel": false, "ScopeId": "scopeid", "Name": "Scope Test" } ] } } } } ``` -------------------------------- ### Get Warehouse by Code Source: https://docs.developers.optimizely.com/commerce-connect/docs/warehouses-and-inventories-examples Use `IWarehouseRepository.Get()` with a string code to retrieve a specific warehouse. ```csharp // Get a specific Warehouse by Code public IWarehouse GetWarehouse(string warehouseCode) { var warehouseRepository = ServiceLocator.Current.GetInstance(); return warehouseRepository.Get(warehouseCode); } ``` -------------------------------- ### Get Warehouse by ID Source: https://docs.developers.optimizely.com/commerce-connect/docs/warehouses-and-inventories-examples Use `IWarehouseRepository.Get()` with an integer ID to retrieve a specific warehouse. ```csharp // Get a specific Warehouse by ID public IWarehouse GetWarehouse(int warehouseId) { var warehouseRepository = ServiceLocator.Current.GetInstance(); return warehouseRepository.Get(warehouseId); } ``` -------------------------------- ### Configure Entry Filters for Promotions Source: https://docs.developers.optimizely.com/commerce-connect/docs/exclude-products-from-promotions Implement IEntryFilter by configuring EntryFilterSettings during site initialization to exclude specific catalog items from all promotions. This example shows how to add filters based on content type, interface implementation, meta fields, and product codes. ```csharp namespace EPiServer.Reference.Commerce.Site.Infrastructure { [ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))] public class SiteInitialization : IConfigurableModule { public void Initialize(InitializationEngine context) { SetupExcludedPromotionEntries(context); } public void ConfigureContainer(ServiceConfigurationContext context) { } public void Uninitialize(InitializationEngine context) { } private void SetupExcludedPromotionEntries(InitializationEngine context) { var filterSettings = context.Locate.Advanced.GetInstance(); filterSettings.ClearFilters(); //Add filter predicates for a whole content type. filterSettings.AddFilter(x => false); //Add filter predicates based on any property of the content type, including implemented interfaces. filterSettings.AddFilter(x => !x.ShouldBeExcluded); //Add filter predicates based on meta fields that are not part of the content type models, e.g. if the field is dynamically added to entries in an import or integration. filterSettings.AddFilter(x => !(bool)(x["ShouldBeExcludedPromotionMetaField"] ?? false)); //Add filter predicates base on codes like below. var ExcludingCodes = new string[] { "SKU-36127195", "SKU-39850363", "SKU-39101253" }; filterSettings.AddFilter(x => !ExcludingCodes.Contains(x.Code)); } } } ``` -------------------------------- ### Configure Optimizely Graph Services Source: https://docs.developers.optimizely.com/commerce-connect/docs/optimizely-graph-for-commerce-connect Add these services in the ConfigureServices method of Startup.cs to enable Content Delivery API and Content Graph integration. ```csharp services.AddContentDeliveryApi(); services.AddContentGraph(x => { x.IncludeInheritanceInContentType = true; x.PreventFieldCollision = true; }); services.AddCommerceGraph(); ``` -------------------------------- ### Get Promotion Items for Campaign Source: https://docs.developers.optimizely.com/commerce-connect/docs/promotions-engine Retrieves promotion items associated with a specific campaign. ```APIDOC ## Get Promotion Items for Campaign ### Description Retrieves promotion items for a given campaign. ### Method ```csharp IEnumerable GetPromotionItemsForCampaign(int campaignLink) ``` ### Parameters - **campaignLink** (int) - The link to the campaign. ``` -------------------------------- ### Get Current Market Source: https://docs.developers.optimizely.com/commerce-connect/docs/multi-market-examples Retrieves the currently active market. Requires an instance of ICurrentMarket from the ServiceLocator. ```csharp public IMarket GetCurrentMarket() { var currentMarketService = ServiceLocator.Current.GetInstance(); // Get current markets. return currentMarketService.GetCurrentMarket(); } ``` -------------------------------- ### Initialize OrderSearchOptions Source: https://docs.developers.optimizely.com/commerce-connect/docs/searching-for-orders-using-ordercontext Initializes the OrderSearchOptions with default values for starting record, records to retrieve, and namespace. ```csharp OrderSearchOptions searchOptions = new OrderSearchOptions(); searchOptions.StartingRecord = 0; searchOptions.RecordsToRetrieve = 10000; searchOptions.Namespace = "Mediachase.Commerce.Orders"; ``` -------------------------------- ### Create a new cart Source: https://docs.developers.optimizely.com/commerce-connect/docs/shopping-carts Use the `.Create()` method on `IOrderRepository` to initialize a new cart. This method is suitable when a cart does not already exist. ```csharp var cart = orderRepository.Create(customerId, "Default"); ``` -------------------------------- ### Create an Empty Commerce Project Source: https://docs.developers.optimizely.com/commerce-connect/docs/creating-your-project Use this command to create a new, empty Optimizely Customized Commerce project. Replace 'ProjectName' with your desired project name. ```csharp dotnet new epi-commerce-empty --name ProjectName ``` ```csharp cd projectname ``` ```csharp dotnet-episerver create-cms-database ProjectName.csproj -S . -E ``` ```csharp dotnet-episerver create-commerce-database ProjectName.csproj -S . -E --reuse-cms-user ``` ```csharp dotnet-episerver add-admin-user ProjectName.csproj -u username -p password -e user@email.com -c EcfSqlConnection ``` -------------------------------- ### Get Parent Product by Variant Source: https://docs.developers.optimizely.com/commerce-connect/docs/product-variants Retrieves the parent products for a given variant. Requires an instance of IRelationRepository. ```csharp public IEnumerable GetProductByVariant(ContentReference variation) { var relationRepository = ServiceLocator.Current.GetInstance(); var products = relationRepository.GetParents(variation); return products; } ``` -------------------------------- ### Create New SKU as IContent Source: https://docs.developers.optimizely.com/commerce-connect/docs/catalog-content Use IContentRepository to create a new catalog entry (SKU) as an IContent object. Ensure required properties like Code, SeoUri, and Description are set before publishing. ```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); } ``` -------------------------------- ### Get All Available Markets Source: https://docs.developers.optimizely.com/commerce-connect/docs/multi-market-examples Retrieves all markets available in the system. Ensure the IMarketService is accessible via ServiceLocator. ```csharp public IEnumerable GetAvailableMarkets() { var marketService = ServiceLocator.Current.GetInstance(); // Get all available markets. return marketService.GetAllMarkets(); } ``` -------------------------------- ### Apply Discounts to Cart in C# Source: https://docs.developers.optimizely.com/commerce-connect/docs/order-processing This snippet demonstrates how to apply discounts to a cart by running the promotion engine. If coupons are required for discounts, add them to the IOrderForm beforehand. ```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()); ``` -------------------------------- ### Get Cache-Skipping IInventoryService Instance Source: https://docs.developers.optimizely.com/commerce-connect/docs/warehouses-and-inventories-examples Obtain an instance of IInventoryService that bypasses the cache for read operations. Ensure ServiceLocator is configured. ```csharp // Gets an instance of IInventoryService that will skip the cache on reads. public IInventoryService GetCacheSkippingInstance() { var inventoryService= ServiceLocator.Current.GetInstance(); return inventoryService.GetCacheSkippingInstance(); } ``` -------------------------------- ### Configure Bolt Options in Startup File Source: https://docs.developers.optimizely.com/commerce-connect/docs/bolt-installation Configure Bolt payment provider options programmatically in the startup file using dependency injection. Ensure Optimizely Customized Commerce is version 14.9.0 or higher. ```csharp services.Configure(x => { x.EnvironmentType = EnvironmentType.Sandbox; x.PublishableKey = "Key"; x.ApiKey = "Api Key"; x.DivisionPublicId = "Public Id"; x.SigningSecret = "signing secret"; x.AutoCapture = true; }); ``` -------------------------------- ### Get Promotion Prices for Multiple Entries Source: https://docs.developers.optimizely.com/commerce-connect/docs/promotions-engine Retrieves promotion prices for a collection of entries within a specified market and currency. ```APIDOC ## Get Promotion Prices for Multiple Entries ### Description Retrieves promotion prices for a collection of entries. ### Method ```csharp IEnumerable GetDiscountPrices(int[] entryLinks, IMarket market, string currency) ``` ### Parameters - **entryLinks** (int[]) - An array of entry links for which to get promotion prices. - **market** (IMarket) - The market context. - **currency** (string) - The currency for which to get promotion prices. ``` -------------------------------- ### Run PromotionEngine with Unit Exclusion Source: https://docs.developers.optimizely.com/commerce-connect/docs/promotion-exclusions Call the PromotionEngine directly and set the `ExclusionLevel` to `Unit` to manage item-level promotion exclusions. ```csharp var cart = ServiceLocator.Current.GetInstance().LoadOrCreateCart(PrincipalInfo.CurrentPrincipal.GetContactId(), Cart.DefaultName); ServiceLocator.Current.GetInstance().Run(cart, new PromotionEngineSettings() { ExclusionLevel = ExclusionLevel.Unit })); ``` -------------------------------- ### Get Promotion Prices for a Single Entry Source: https://docs.developers.optimizely.com/commerce-connect/docs/promotions-engine Retrieves promotion prices for a specific entry within the current market context. ```APIDOC ## Get Promotion Prices for a Single Entry ### Description Retrieves promotion prices for a single entry. ### Method ```csharp IEnumerable GetDiscountPrices(int entryLink, IMarket currentMarket) ``` ### Parameters - **entryLink** (int) - The link to the entry for which to get promotion prices. - **currentMarket** (IMarket) - The current market context. ``` -------------------------------- ### Initialize Sql Metamodel and Transaction Source: https://docs.developers.optimizely.com/commerce-connect/docs/working-with-sql-records This snippet demonstrates how to initialize the SqlContext, begin a transaction, create a new record, and commit the transaction. Ensure the connection string is valid and the 'Book' table exists. ```csharp using (SqlContext.Current = new SqlContext(connectionString)) { using (SqlTransactionScope tran = SqlContext.Current.BeginTransaction()) { // Step 1. Get Book table Table bookTable = SqlContext.Current.Database.Tables["Book"]; // Step 2. Create a new book CustomTableRow newBook = new CustomTableRow(bookTable); newBook["Title"] = "Programming Windows Phone 7"; newBook.Update(); PrimaryKeyId newBookPk = newBook.PrimaryKeyId.Value; // Step N. Call Commit to commit transaction tran.Commit(); } } ``` -------------------------------- ### Update StringDictionary Metafield Source: https://docs.developers.optimizely.com/commerce-connect/docs/catalog-content Update a StringDictionary metafield by treating the property as a normal dictionary. Example shows initializing with key-value pairs. ```csharp content.StringDict = new Dictionary() {{ "abc", "xyz" }, {"hello", "world"}}; ``` -------------------------------- ### Create a New Warehouse Source: https://docs.developers.optimizely.com/commerce-connect/docs/warehouses-and-inventories-examples Use `IWarehouseRepository.Save` to add a new warehouse. Ensure all required properties are set. ```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); } ``` -------------------------------- ### Retrieve All Registered Order Statuses Source: https://docs.developers.optimizely.com/commerce-connect/docs/extending-order-status Access the OrderStatus.RegisteredStatuses property to get a collection of all available order statuses, including built-in ones. ```csharp var statuses = OrderStatus.RegisteredStatuses; ``` -------------------------------- ### Enable tracking using appsettings.json Source: https://docs.developers.optimizely.com/commerce-connect/docs/installing-and-configuring-the-native-integration-package Use the `TrackingOptions` class to enable tracking via the `appsettings.json` file. This is a basic configuration for enabling tracking. ```json { "EPiServer": { "Tracking": { "TrackingOptions": { "TrackingEnabled": true } } } } ``` -------------------------------- ### Get Subtotal of Return Order Source: https://docs.developers.optimizely.com/commerce-connect/docs/calculating-orders-return-purchase-order-calculator Calculates the subtotal for all return order forms within a purchase order. Requires an IPurchaseOrder and IReturnPurchaseOrderCalculator. ```csharp public void GetSubTotal(IPurchaseOrder purchaseOrder, IReturnPurchaseOrderCalculator returnPurchaseOrderCalculator) { var subTotal = returnPurchaseOrderCalculator.GetSubTotal(purchaseOrder); Debug.WriteLine("Subtotal for return order '{0}': {1}", purchaseOrder.OrderLink.OrderGroupId, subTotal); } ``` -------------------------------- ### Start Purchase Order Processing Source: https://docs.developers.optimizely.com/commerce-connect/docs/order-processing Initiates the processing of a purchase order using the IPurchaseOrderProcessor. Requires the order repository and processor to be set up. ```csharp IOrderRepository orderRepository; IPurchaseOrderProcessor purchaseOrderProcessor; (…) var orderGroupId = 123; var purchaseOrder = orderRepository.Load(orderGroupId); purchaseOrderProcessor.ProcessOrder(purchaseOrder); ``` -------------------------------- ### List Available Promotion Types Source: https://docs.developers.optimizely.com/commerce-connect/docs/common-workflows Use this tool to list the available promotion types for creating new promotions. ```json Tool: promotion_types_list ``` -------------------------------- ### Create Interval Filter Source: https://docs.developers.optimizely.com/commerce-connect/docs/filtering-and-sorting Use IntervalFilterElement to filter elements based on a date range. Specify the start and end dates for the interval. ```csharp FilterElement filter = new IntervalFilterElement("StartDate", from, to); ``` -------------------------------- ### Delete Order Using IOrderRepository Source: https://docs.developers.optimizely.com/commerce-connect/docs/order-manipulation Provides an example of deleting an order using the `Delete` method of the `IOrderRepository`. This operation requires a valid `orderReference`. ```csharp var orderRepository = ServiceLocator.Current.GetInstance(); orderRespository.Delete(orderReference); ``` -------------------------------- ### Initialize Price and Inventory Indexing Source: https://docs.developers.optimizely.com/commerce-connect/docs/indexing-variants-in-a-product-document This module initializes the `PriceIndexing` service to enable indexing of prices. It also registers custom `CatalogContentClientConventions` for handling product and variation content. ```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(); } } ``` -------------------------------- ### Get Collection of Columns Source: https://docs.developers.optimizely.com/commerce-connect/docs/sql-meta-model Iterates through the columns of a table and writes their names to trace output. Ensure a table object is initialized before accessing its columns. ```csharp foreach (Column column in newTable.Columns) { System.Diagnostics.Trace.WriteLine(column.Name); } ``` -------------------------------- ### Configure ODP Integration via Configuration File (Before 14.20.0) Source: https://docs.developers.optimizely.com/commerce-connect/docs/commerce-connect-14-odp Configure ODP integration settings in the configuration file before version 14.20.0. Ensure MarketId, AccessKey, and EndpointUrl are correctly set. ```json { "EPiServer" : { "Commerce" : { "ODPJob": { "MarketKeys": [ { "MarketId": "US", "AccessKey": "key", "EndpointUrl": "https://api.zaius.com/" } ] } } } } ``` -------------------------------- ### List All Warehouses Source: https://docs.developers.optimizely.com/commerce-connect/docs/warehouses-and-inventories-examples Use `IWarehouseRepository.List()` to retrieve information for all available warehouses. ```csharp // Get list Warehouse public IEnumerable ListAllWarehouses() { var warehouseRepository = ServiceLocator.Current.GetInstance(); return warehouseRepository.List(); } ``` -------------------------------- ### Configure Promotion Properties Source: https://docs.developers.optimizely.com/commerce-connect/docs/common-workflows Use this tool to dynamically update properties of an existing promotion, such as setting spend amount conditions or discount percentages. Ensure the 'Id' corresponds to the promotion you wish to update. ```json Tool: promotion_dynamic_update { "Id": "456", "Properties": { "Condition_SpendAmount": 50.00, "Discount_Percentage": 25.0 } } ``` -------------------------------- ### Get Promotion Prices for a Single Entry Source: https://docs.developers.optimizely.com/commerce-connect/docs/promotions-engine Retrieve discounted prices for a single entry by evaluating active promotions. Requires the EPiServer.Commerce.Marketing namespace. ```csharp var promotionEngine = ServiceLocator.Current.GetInstance(); var currentMarket = ServiceLocator.Current.GetInstance(); IEnumerable discountedEntries = promotionEngine.GetDiscountPrices(entryLink, currentMarket); ``` -------------------------------- ### Import Meta-Model by Executing Synchronization Commands Source: https://docs.developers.optimizely.com/commerce-connect/docs/exporting-and-importing-meta-models Execute synchronization commands to import a meta-model. This process requires loading the synchronization commands from a file and then applying them using MetaModelSync.Execute within a transaction scope. Ensure the DataContext is properly initialized. ```csharp try { // Open DataContext DataContext.Current = new DataContext(connectionString); // Load Sync Commands SchemaDocument schema = new SchemaDocument(); schema.LoadDefault(); // Load Sync Commands SyncCommand\[] syncCommands = McXmlSerializer.GetObjectFromFile(filePath); // Apply Sync Command using (TransactionScope tran = DataContext.Current.BeginTransaction()) { MetaModelSync.Execute(schema, syncCommands); tran.Commit(); } } catch (Exception ex) { } ```