Episerver has quite nice mechanism on validating cart, line item, shipment , , promotion and inventory. I was looking into customizing the line item validtion, to inject some business logic. To do this:

  1. First create new class and inherit from ILineItemValidator
   public class CustomLineItemValidator : ILineItemValidator
    {
        private readonly ILineItemValidator defaultImplementation;
        private readonly IOrderRepository orderRepository;

        public CustomLineItemValidator(ILineItemValidator defaultImplementation,
            IOrderRepository orderRepository)
        {
            this.defaultImplementation = defaultImplementation;
            this.orderRepository = orderRepository;
        }

        [Obsolete]
        public bool Validate(ILineItem lineItem, IMarket market, Action<ILineItem, ValidationIssue> onValidationError)
        {
            if (AlreadyPurchased(lineItem))
            {
                onValidationError(lineItem, ValidationIssue.RemovedDueToUnavailableItem);

                return false;
            }

            return defaultImplementation.Validate(lineItem, market, onValidationError);
        }

        public bool Validate(ILineItem lineItem, MarketId marketId, Action<ILineItem, ValidationIssue> onValidationError)
        {
            if (AlreadyPurchased(lineItem))
            {
                onValidationError(lineItem, ValidationIssue.RemovedDueToUnavailableItem);

                return false;
            }

            return defaultImplementation.Validate(lineItem, marketId, onValidationError);
        }

        private bool AlreadyPurchased(ILineItem lineItem)
        {
            var alreadyPurchased = false;
            var customerId = lineItem?.ParentOrderGroup?.CustomerId;

            if (customerId != null)
            {
                var orders = orderRepository.Load<IPurchaseOrder>(customerId.Value);

                if (orders != null)
                {

                    alreadyPurchased = orders.Any(a => a.GetAllLineItems()
                                                            .Any(l => string.Equals(l.Code,
                                                                                    lineItem.Code,
                                                                                    StringComparison.InvariantCultureIgnoreCase)));

                }
            }

            return alreadyPurchased;
        }
    }

In our example above, we are checking to make sure if the user already purchased the item before and if that is a case we return false as a result of validation. It may be weird but our customer has this requirement and it is meaningful in their context. As you can see we are re-using existing line item validator as well.

2. Next step is to inject our new validator to the DI:

    [InitializableModule]
    public class DependencyResolverInitialization : IConfigurableModule
    {
        private static readonly ILogger logger = LogManager.GetLogger();

        public void ConfigureContainer(ServiceConfigurationContext context)
        {
            var services = context.Services;

            services.Intercept<ILineItemValidator>(
                (locator, defaultImplementation) =>
                    new CustomLineItemValidator(defaultImplementation,
                                locator.GetInstance<IOrderRepository>()));
        }
    }

As you can see on DependencyResolverInitialization class, I added a new section to intercept the ILineItemValidator. If you are not sure what I’m speaking of you can read more about it here.

If you are having ‘Commerce Manager’ make sure you do same thing in both CommerceManager and Shopfront projects!

Leave a Reply

Your email address will not be published. Required fields are marked *