Custom campaign action

Hi. I’m trying to build a custom campaign (action).

The purpose for the campaign is to calculate a campaign price depending on a percentage value stored on the users connected organization and if the selected quantity is greater than one it goes out to an API to fetch the stacked price and uses it as the campaign price.

The condition for the campaign is a Assortment Condition.

I got this working (kind of). I have a couple of questions.

  1. What is the difference between ActionArgs.OrderContainer.OrderRows and ActionArgs.FilteredOrderRows?

  2. When I load my product list each variant hits the campaign and is available in the FilteredOrderRows. That’s great.

But when I’ve added products to my cart they are “persisted” to the FilteredOrderRows for each next call to the campaign action. Is this a correct behavior? I’m only interested in the current variant, not the ones already added to cart. Can I distinguish the current variant in any way?

Litium version: 7.3.1

When building a campaign action or condition is that it will be executed many times per view. Say that you have a list of 48 products that is displayed you will have 48 different calculations so it is important that all the checks we are doing here are as fast as possible. Also if possible that we don’t do the same calculations for the same variant in the same request.

Not sure if you should implement this as a campaign and instead implement your logic in the IPriceCalculator to be able to use campaign prices up on the result that not will be possible otherwise; in a simple way. I assume that the customer have some type of percentage of the list price and this is the customers price and not a campaign price for the customer.

The FilteredOrderRows is the order row that is filtered when all the conditions is applied. It is this data that you should use to calculate the prices.

When you adding the variant to the cart the variant will be included in all additional calls but the quantity is changed. Example if you have variant with quantity 1 in the cart and the request will make a check for the price it will change the quantity to 2 instead; or the next value depend on decimals for the unit of measurement. The reason is that the prices can be different depend on the quantity and also other products that exists in the cart, for example if you by product X you will get discount on product Y.

Thanks Patric. Yeah, it might seem as a campaign action is not the way to go in this case then.

I wan’t to display the list price alongside with the calculated price. How can I make that happen if I return my customer price from my IPriceCalculator?

If you return an own class as the result, then you can provide multiple values.

As an example how it can be implemented (untested) where the price that is returned from the IPriceCalculator can be casted to MyPriceResult and you will then have access to the original price.

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

namespace Litium.Accelerator.Services
{
    [ServiceDecorator(typeof(IPriceCalculator))]
    public class MySpecialPriceCalculator : IPriceCalculator
    {
        private readonly IPriceCalculator _parent;
        private readonly PersonStorage _personStorage;

        public MySpecialPriceCalculator(
            IPriceCalculator parent,
            PersonStorage personStorage)
        {
            _parent = parent;
            _personStorage = personStorage;
        }

        public IDictionary<Guid, PriceCalculatorResult> GetListPrices(PriceCalculatorArgs calculatorArgs, params PriceCalculatorItemArgs[] itemArgs)
        {
            var prices = _parent.GetListPrices(calculatorArgs, itemArgs);

            if (prices.Count == 0)
            {
                return prices;
            }

            var organization = _personStorage.CurrentSelectedOrganization;
            var discountPercentage = organization?.Fields.GetValue<decimal?>("DiscountPercentage");
            if (discountPercentage is null)
            {
                return prices;
            }

            return prices
                .AsEnumerable()
                .ToDictionary(x => x.Key, x => (PriceCalculatorResult)new MyPriceResult(x.Value, discountPercentage.Value));
        }

        public ICollection<PriceList> GetPriceLists(PriceCalculatorArgs calculatorArgs)
        {
            return _parent.GetPriceLists(calculatorArgs);
        }
    }

    public class MyPriceResult : PriceCalculatorResult
    {
        public MyPriceResult(PriceCalculatorResult result, decimal discountPercentage)
        {
            OriginalPrice = result.ListPrice;
            OriginalPriceWithVat = result.ListPriceWithVat;
            VatPercentage = result.VatPercentage;

            ListPrice = result.ListPrice - (result.ListPrice * discountPercentage);
            ListPriceWithVat = result.ListPriceWithVat - (result.ListPriceWithVat * discountPercentage); // maybe better to recalculate the value depend on the vat percentage
        }

        public decimal OriginalPrice { get; }
        public decimal OriginalPriceWithVat { get; }
    }
}

Thanks! Yeah, this is a much cleaner solution.

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