There might be a situation when you don’t have any price defined on a sellable item and you still want the ability to Add To Cart. If you are not well across how pricing works in Sitecore Experience Commerce(SXC), please have a look at this article from Andrew Sutherland.
In a nutshell, the pricing calculation works from Price Book to List Price. If there are price cards defined on a sellable item, that price is used but if there is no price card, ListPrice defined on a sellable item is used.
If your eCommerce website has the option of Contact To Purchase, you might end up having no prices defined(nor price cards neither list price). In such scenarios, you will get this error while trying to add to cart
Item ‘item name’ is not purchasable.
At this stage, you have two options either ask your Content Author to add List Price as $0.00 which doesn’t reflect the actual state of the system or extend Sitecore Commerce with the ability to AddToCart without any price.
If you trace down the origin of the above error you will find ValidateCartLinePrice inside a pipeline in catalog plugin
If you see the logic inside this block, it will look for money policy that gets added to a sellable item if there is a price card or list price present on the item.
So to enable AddToCart with no price, I started looking into the pipeline which deals with List price. I found ICalculateSellableItemListPricePipeline which calls a block CalculateSellableItemListPriceBlock.
This block would leave the list price as null if it is not defined on a sellable item. And I ended up adding a custom block after this block to be able to set List Price to 0.00 inside the cart.
ConfigureSitecore.cs to configure the block
.ConfigurePipeline<ICalculateSellableItemListPricePipeline>(configure => configure .Add<CalculateMissingListPriceBlock>().After<CalculateSellableItemListPriceBlock>())
CalculateMissingListPriceBlock.cs looks like
public class CalculateMissingListPriceBlock : PipelineBlock<SellableItem, SellableItem, CommercePipelineExecutionContext> { public override Task<SellableItem> Run(SellableItem arg, CommercePipelineExecutionContext context) { return Task.Run(() => { CalculateMissingPrice(arg, context); return arg; }); } private void CalculateMissingPrice(SellableItem item, CommercePipelineExecutionContext context) { if (item.ListPrice == null) { context.Logger.LogInformation($"{nameof(CalculateMissingListPriceBlock)} {item.FriendlyId} list price is null, zero price will be used"); item.ListPrice = new Money(context.CommerceContext.CurrentCurrency(), 0); } } }