1

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?

Product extended with custom property

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; 
            }
        }
    }
}
1

Created custom ProductSummaryViewModel class with inheriting XA.Feature.Catalog.Models.ProductSummaryViewModel and add new all new fields required in custom ProductSummaryViewModel class. Patch out of box ProductSummaryViewModel attribute with custom ProductSummaryViewModel class. Then populated custom fields inside Initialize functions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.