How can I access a custom policy that I add in a Commerce Engine pipeline block in the Storefront, and extend Sitecore.Commerce.XA.Foundation.Catalog.Models.ProductSummaryViewModel
with fields from this policy to display in my product search results?
I add a custom policy in an ExternalSellableItemSellPriceBlock
:
using Sitecore.Commerce.Core;
using System;
namespace Plugin.SCE.Policies
{
public class SaleitemUnitPolicy : Policy
{
public SaleitemUnitPolicy(string unit)
{
Unit = unit;
}
// PerHour, PerDay, PerMonth, PerItem
public String Unit { get; set; }
}
}
I use this policy in my pipeline block:
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Plugin.SCE.Policies;
using Sitecore.Commerce.Core;
using Sitecore.Commerce.Plugin.Catalog;
using Sitecore.Commerce.Plugin.Pricing;
using Sitecore.Framework.Pipelines;
namespace Plugin.SCE.Pipelines.Blocks
{
[PipelineDisplayName("Catalog.block.ExternalSellableItemSellPriceBlock")]
public class ExternalSellableItemSellPriceBlock : BaseCalculateSellPriceBlock<SellableItem, SellableItem>
{
private readonly CommerceCommander _commander;
public ExternalSellableItemSellPriceBlock(CommerceCommander commander) : base(commander)
{
_commander = commander;
_configuration = configuration;
}
public override async Task<SellableItem> RunAsync(SellableItem sellableProductItem, CommercePipelineExecutionContext context)
{
if (sellableProductItem == null)
{
return null;
}
if (sellableProductItem.HasComponent<BundleComponent>())
{
// default behavior
var block = new CalculateSellableItemSellPriceBlock(_commander);
var item = await block.RunAsync(sellableProductItem, context);
return item;
}
Money sellPrice;
string saleitemUnit;
(sellPrice, saleitemUnit) = await ExternalPricingUtil.ProductSellPrice(productId);
if (sellableProductItem.HasComponent<PriceSnapshotComponent>())
{
sellableProductItem.RemoveComponent(typeof(PriceSnapshotComponent));
}
if (sellableProductItem.HasPolicy<PriceCardPolicy>())
{
sellableProductItem.RemovePolicy(typeof(PriceCardPolicy));
}
sellableProductItem.SetPolicy((Policy)new PurchaseOptionMoneyPolicy() { SellPrice = sellPrice }); // replace if exists
sellableProductItem.AddPolicies(new Policy[] {
new SaleitemUnitPolicy(saleitemUnit)
});
return sellableProductItem;
}
}
}
I assume this data ends up somewhere in the Storefront pipeline, so I injected an ExtendViewModel
ProcessSearchItemsProcessor in the ProcessSearchItems pipeline:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<group groupName="experienceAccelerator">
<pipelines>
<processSearchItems>
<processor type="Feature.SCP.CommerceCatalog.Pipelines.ProcessSearchItems.ExtendViewModel, Feature.SCP.CommerceCatalog" patch:after="processor[@type='Sitecore.Commerce.XA.Feature.Catalog.Pipelines.Search.PrepareSearchItems, Sitecore.Commerce.XA.Feature.Catalog']" resolve="true"/>
</processSearchItems>
</pipelines>
</group>
</pipelines>
</sitecore>
</configuration>
The ExtendViewModel
processor has the following code:
using Sitecore.Commerce.XA.Feature.Catalog.Repositories;
using Sitecore.Commerce.XA.Foundation.Common.Context;
using Sitecore.Commerce.XA.Foundation.Common.Models;
using Sitecore.Commerce.XA.Foundation.Common.Providers;
using Sitecore.Framework.Conditions;
using Sitecore.XA.Feature.Search.Pipelines.ProcessSearchItems;
namespace Feature.SCP.CommerceCatalog.Pipelines.ProcessSearchItems
{
public class ExtendViewModel : ProcessSearchItemsProcessor
{
protected IStorefrontContext StorefrontContext
{
get;
}
protected IProductListRepository ProductListRepository
{
get;
}
protected IModelProvider ModelProvider
{
get;
}
protected IItemTypeProvider ItemTypeProvider
{
get;
}
public ExtendViewModel(IStorefrontContext storefrontContext, IProductListRepository productListRepository, IModelProvider modelProvider, IItemTypeProvider itemTypeProvider)
{
Condition.Requires(storefrontContext, "storefrontContext").IsNotNull();
Condition.Requires(productListRepository, "productListRepository").IsNotNull();
Condition.Requires(modelProvider, "modelProvider").IsNotNull();
Condition.Requires(itemTypeProvider, "itemTypeProvider").IsNotNull();
StorefrontContext = storefrontContext;
ProductListRepository = productListRepository;
ModelProvider = modelProvider;
ItemTypeProvider = itemTypeProvider;
}
public override void Process(ProcessSearchItemsArgs args)
{
if (StorefrontContext.CurrentStorefront != null && StorefrontContext.CurrentStorefront.AdditionalAjaxCall)
{
return;
}
foreach (var item in args.SearchItems)
{
// How do I get the policy of type SaleitemUnitPolicy containing field Unit?
//
// Update or extend the ProductSummaryViewModel with the data from policy.
//
// Model is created as follows:
// ProductSummaryViewModel model = ModelProvider.GetModel<ProductSummaryViewModel>();
// model.UseDamImages = useDamImages;
// model.Initialize(productEntity);
// item.Model = model;
//
// Would like to do something like:
// item.Model.SaleitemUnit = saleitemUnitPolicy.Unit;
}
}
}
}