A lot of organisations have requirements to integrate more than just a product and orders feed. A common ask from some customers is to integrate with their bespoke pricing API. In this post I’ll take you through just how easy it is with Sitecore Experience Commerce 9.
The Product Setup
We setup a normal sellable-item with the bare minimum required. Notice there is no pricing configured for the sellable-item, there’s no list price configured and no sell price configured (price card).
The External API
For this example I’ll be using CMYKhub’s publicly available test API – https://github.com/CMYKhub/. Using postman we can really easily simulate a pricing call for the product we’ve configured.
The Plugin
Now it’s time to create a Sitecore Commerce plugin to make the external pricing request. Here is the working example: https://github.com/kazimnami/Sitecore.Commerce.ExternalPricing
The bulk of the work is done in a single pipeline block
namespace Feature.Pricing.Engine { [PipelineDisplayName(Constants.Pipelines.Blocks.CalculateCartLinesPrice)] public class CalculateCartLinesPriceBlock : PipelineBlock { private readonly CommerceCommander _commerceCommander; public CalculateCartLinesPriceBlock(CommerceCommander commerceCommander) : base(null) { _commerceCommander = commerceCommander; } public override async Task Run(Cart arg, CommercePipelineExecutionContext context) { Condition.Requires(arg).IsNotNull($"{Name}: Cart cannot be null."); Condition.Requires(arg.Lines).IsNotNull($"{Name}: The cart's lines cannot be null"); if (!arg.Lines.Any()) return arg; // Valid cart items var validCartLines = arg.Lines .Where(line => line != null && line.HasComponent() && !string.IsNullOrEmpty(line.ItemId) && line.ItemId.Split('|').Length >= 2); // Iterate valid cart items foreach (var line in validCartLines) { // Get sellable items (products) SellableItem sellableItem = await _commerceCommander.Command().Process(context.CommerceContext, line.ItemId, false); if (sellableItem == null) { context.Logger.LogError($"{Name}-SellableItemNotFound for Cart Line: ItemId={line.ItemId}|CartId={arg.Id}|LineId={line.Id}"); return arg; } // Set list & sell pricing line.UnitListPrice = sellableItem.ListPrice; if (sellableItem.Manufacturer.Equals("CMYKhub", StringComparison.OrdinalIgnoreCase)) { var request = new { ProductId = sellableItem.FriendlyId, Quantity = (int)line.Quantity, Kinds = 1 }; var cmykHubPrice = await CreatePriceAsync(request); if (cmykHubPrice != null) { var optionMoneyPolicy = new PurchaseOptionMoneyPolicy { SellPrice = new Sitecore.Commerce.Core.Money("USD", cmykHubPrice.Price.IncTax) // new Sitecore.Commerce.Core.Money(cmykHubPrice.Price.Currency.Code, cmykHubPrice.Price.IncTax); }; line.Policies.Remove(line.Policies.OfType().FirstOrDefault()); line.SetPolicy(optionMoneyPolicy); // Add to pricing messaging var lineMessages = line.GetComponent(); lineMessages.AddMessage(context.GetPolicy().Pricing, $"CartItem.SellPrice<=CMYKhub.Pricing: Price={optionMoneyPolicy.SellPrice.AsCurrency()}"); } }; } return arg; } } }
The Result
From the product detail page (PDP) we can see the sellable item has no price.
When we add to cart, the cart line calculation block will trigger and make a call to CMYKhub’s pricing API and return a price for the product.