Published on, Time to read
🕒 3 min read

Optimizely / Episerver: How to skip automatic validation of the cart?

Optimizely / Episerver: How to skip automatic validation of the cart?

Optimizely invokes its internal validators for the cart processing. But there's one catch. In Optimizely, cart validation may mutate the cart and its contents (line items).

So, when the back-office user wants to view carts, and validation fails, then the cart might be mutated, and the user will see the altered cart. It's a UX design flaw that violates CQRS and should not happen, as viewing the cart should not mutate it. There should be a separate action button for validation (and, thus, potential mutation) of the cart. The example scenario is that the variant does not have a max quantity setting, and the user added it to the cart. Entering the Commerce UI will remove the line item from the cart because of the validation. The message goes as follows:

The product XYZ has no valid max quantity setting and was removed from your cart.

Cart view
Image: Cart view

This article describes how to skip this default validation in scenarios where custom validation logic exists.

Under the hood

The class responsible for the cart validation is the EPiServer.Commerce.Order.OrderValidationService.

It has the following validation methods:

  • ValidateOrRemoveLineItems, checks if line item:
    • has not been removed
    • is active
    • has a valid market
    • has availability for a given date
    • is published
  • UpdatePlacedPriceOrRemoveLineItems, checks if line item:
    • has a valid price (> 0)
    • has price unchanged (in comparison to the price in the catalog)
  • UpdateInventoryOrRemoveLineItems, checks if line item:
    • has no inventory for a given quantity
    • has no inventory information
  • ApplyDiscounts:
    • does not validate anything, just applies discounts
  • UpdateInventoryOrRemoveLineItems:
    • runs again after applying discounts (some line items might be added after applying for promotions)

These are most of the validations listed. As we can see, the above methods might alter the cart and its contents, i.e., remove line items from the cart.

Also, these methods might be invoked explicitly in a custom cart validation scenario. You may use the original OrderValidationService or extension methods in IOrderGroupExtensions.

How to skip the validation?

In order to skip the validation, you may just substitute dependency by registering your implementation of IOrderValidationService in the IoC container (Mai, 2023).

services.AddTransient<OrderValidationService, CustomOrderValidationService>();

The next step would be to override the ValidateOrder method and use custom logic. Sometimes, you might need to skip the validation for a specific cart only. In this case, you might use orderGroup parameter of the above method and its cart name (e.g. "Wishlist") to determine if the validation should be skipped:

public override IDictionary<ILineItem, IList<ValidationIssue>> ValidateOrder(IOrderGroup orderGroup)
{
    if (orderGroup.Name.Equals("Wishlist", StringComparison.OrdinalIgnoreCase))
        return new Dictionary<ILineItem, IList<ValidationIssue>>();

    return base.ValidateOrder(orderGroup);
}

If you want to skip the validation only for the cart processing in the Commerce UI, then you might use the HttpContext to determine if the request is coming from the back-office:

var referer = _httpContextAccessor.HttpContext?.Request?.Headers["Referer"].FirstOrDefault() ??
    string.Empty;

if (referer.Contains("/episerver/commerce/ordermanagement", StringComparison.OrdinalIgnoreCase))
{
    return new Dictionary<ILineItem, IList<ValidationIssue>>();
}

return base.ValidateOrder(orderGroup);

Mai, Q. (2023). Skip validating carts. Quan Mai’s blog. https://vimvq1987.com/skip-validating-carts/