Custom PriceCalculator implementation?

Is it possible to implement a custom PriceCalculator that fetches prices from an external resource (e.g. an ERP system) in specific cases, e.g. when rendering a product view, but uses the default implementation and the local pricelists in Litium when rendering product listings?

Litium version: 5.6.0

I think it should be possible but never done it myself :slight_smile:

Set the PriceCalculatorArgs.SourceId to a value that is identifier your view and use that to see what logic the price calculator should use.

That seems doable :slight_smile: Where would we set it?

Is it correct that the PriceCalculator.GetListPrices() method always is called once for each product/variant? If one call was made for a batch of products we could probably make a call to the ERP system but not for each one.

You need to set it in the calling code :slight_smile:

And in most cases the PriceCalculator.GetListPrices is executed for each product but it depend on the implementation. The method will take an array of arguments so multiple prices can be executed at once. The calling code need to be changed to do that instead.

Digging through the code trying to figure out how this works… Do we need to implement the ProductPriceModelBuilder which seems to be what’s creating the price?

And of course it depends on the implementation, in this case it’s a pretty much vanilla Accelerator implementation so maybe you have better insight in how to do this :slight_smile:

@patric.forsgard Do you think the best way in our case is to implement the ProductPriceModelBuilder?

Instead of overriding everything you can probably do an decorator that using an AsyncLocal static variable that is changing the arguments that is sent into the price agent, then in example the controller you can set this to the value you want and it will be used during the request.

See the following code snippet that will set the organization system ids on the same way.

using JetBrains.Annotations;
using Litium.Accelerator.Utilities;
using Litium.Products;
using Litium.Products.PriceCalculator;
using Litium.Runtime.DependencyInjection;
using System;
using System.Collections.Generic;

namespace Litium.Accelerator.Mvc.Routing
{
    [ServiceDecorator(typeof(IPriceCalculator))]
    internal class PriceCalculatorDecorator : IPriceCalculator
    {
        private readonly IPriceCalculator _parentResolver;

        public PriceCalculatorDecorator(IPriceCalculator parentResolver)
        {
            _parentResolver = parentResolver;
        }

        public IDictionary<Guid, PriceCalculatorResult> GetListPrices([NotNull] PriceCalculatorArgs calculatorArgs, [NotNull] params PriceCalculatorItemArgs[] itemArgs)
        {
            SetOrangizationSystemIds(calculatorArgs);
            return _parentResolver.GetListPrices(calculatorArgs, itemArgs);
        }

        public ICollection<PriceList> GetPriceLists([NotNull]PriceCalculatorArgs calculatorArgs)
        {
            SetOrangizationSystemIds(calculatorArgs);
            return _parentResolver.GetPriceLists(calculatorArgs);
        }

        private void SetOrangizationSystemIds([NotNull] PriceCalculatorArgs calculatorArgs)
        {
            var selectedOrganization = PersonStorage.CurrentSelectedOrganization;
            if (selectedOrganization != null)
            {
                calculatorArgs.OrganizationSystemIds = new List<Guid>() { selectedOrganization.SystemId };
            }
        }
    }
}