Get campaign price for different variant inside custom price calculation

We currently use the PriceListItemService to get prices for variants. But this does not give us “current” prices, i.e. the prices that the current user (anonymous or not) would see after all campaigns are applied. It seems to just give list prices, as the name implies.

How do we get the same prices that the rest of Litium does? Should we use a campaign price service? Or is there some other way of getting prices?

Litium version: 7.6.2 & accelerator

I need to get the price in an API controller action, so it doesn’t look like I can use the ProductPriceModelBuilder.

I can see there is a CampaignPriceCalculator that can GetCampaignPrices, but it looks complicated to use.

Why don’t you use Litium.Web.Models.Products.ProductPriceModelBuilder.Build method?

Or is there a way to get that working?

Dependency cycle has been detected when trying to resolve component ‘Litium.Web.Models.Products.ProductPriceModelBuilder (231bd0c8-b3f8-4eb8-8c25-2eb62ff87615)’.
The resolution tree that resulted in the cycle is the following:
Component ‘Litium.Web.Models.Products.ProductPriceModelBuilder (231bd0c8-b3f8-4eb8-8c25-2eb62ff87615)’ resolved as dependency of
component ‘Litium.Accelerator.Services.ProductConfigurationService (50325535-9e93-445c-b675-5921e7f87515)’ resolved as dependency of
component ‘Litium.Products.PriceCalculator.IPriceCalculator (c416221c-5590-4300-95f0-cd4345c8dec9)’ resolved as dependency of
component ‘Litium.Web.Models.Products.ProductPriceModelBuilder (231bd0c8-b3f8-4eb8-8c25-2eb62ff87615)’ resolved as dependency of
component ‘Litium.Accelerator.Builders.Product.ProductItemViewModelBuilder (3f1cd84f-a40a-4042-9d10-32c5c89f0533)’ resolved as dependency of
component ‘Litium.Accelerator.Builders.Block.ProductBlockViewModelBuilder (424afdd9-2fde-4f34-b6c9-b7f46d0b467f)’ resolved as dependency of
component ‘system.web.mvc.icontroller(litium.accelerator.mvc.controllers.blocks.productblockcontroller)’ which is the root component being resolved.

ProductConfigurationService is our custom service.

Do you have a custom PriceCaclculator imlementation refering to ProductConfigurationService?

Yes, sorry, after actually reading the cyclomatic chain, I realize that our custom code is involved in this problem.

But, either way, are you saying the solution to getting the “current” price is to use the ProductPriceModelBuilder?

Yes or implement the logic of ProductPriceModelBuilder :slight_smile: It uses the price and campaign calculators to get the current price.

I’m having some trouble wrapping my head around this.

I can’t add a ProductPriceModelBuilder to my custom IPriceCalculator, since it creates a cyclic dependency.

Neither can I add an ICampaignPriceCalculator to my custom IPriceCalculator, for the same reason.

The problem is that my custom IPriceCalculator needs to know the price of a different product in order to do its calculation, and not just the list price.

Is there any way I could use a ProductPriceModelBuilder from my IPriceCalculator?

Or is there something else I can decorate (higher up the chain?) to alter the price calculation where I can use a ProductPriceModelBuilder?

Or if I implement a custom ProductPriceModelBuilder (if possible), would it automatically be used the same way an IPriceCalculator would?

It’s dependent on where you need to the prices to be visible.

The implementation of ICampaignPriceCalculator is using the IPriceCalculator to fetch the list price for the product when calculating the discounted price. ICampaignPriceCalculator cant be used in IPriceCalculator because of circular reference.

The implementation of ProductPriceModelBuilder is using both the ICampaignCalculator and IPriceCalculator to be able to calculate the correct price for the product for the visitor. The ProductPriceModelBuilder cant be used in the implementation of these services because of the circular reference.

ProductPriceModelBuilder is used in the Accelerator to build the price model, this including list price, tier prices and discounted price (campaign price).

We also have other items in the product that calculating the price, example the price agent feed that only using the ICampaignCalculator and IPriceCalculator.

If I understand correctly what you want to do is to calculate both the unit price and the discounted price, then you need to override both the IPriceCalculator to get the calculated unit price and ICampaignPriceCalculator if there is any special calculations that need to be done when the discounted price should be calculated.

I think you should do something like these in in a IPriceCalculator decorator implementation

        public IDictionary<Guid, PriceCalculatorResult> GetListPrices([NotNull] PriceCalculatorArgs calculatorArgs, [NotNull] params PriceCalculatorItemArgs[] itemArgs)
        {
            return itemArgs.ToDictionary(x => x.VariantSystemId, x =>
            {
                var variantsToFetchPricesFor = GetVariantsToUseForPriceLookup(x);

                var result = _parentResolver.GetListPrices(calculatorArgs, variantsToFetchPricesFor.ToArray());
                return new PriceCalculatorResult
                {
                    ListPrice = result.Sum(x => x.Value.ListPrice),
                    ListPriceWithVat = result.Sum(x => x.Value.ListPriceWithVat),
                    VatPercentage = result.Select(x => x.Value.VatPercentage).FirstOrDefault(),
                };
            });
        }

        IEnumerable<PriceCalculatorItemArgs> GetVariantsToUseForPriceLookup(PriceCalculatorItemArgs item)
        {
            // get all the other variants that should be included for price calculation and return PriceCalculatorItemArgs for them
            yield return new PriceCalculatorItemArgs
            {
                Quantity = item.Quantity,
                VariantSystemId = item.VariantSystemId
            };
        }
1 Like

Thank you for this detailed explanation. We’ll have to consider how best to approach this.

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.