Sanjay Kumar
Feb 1, 2021
  2007
(6 votes)

Multilingual cart validation message

The purpose of this blog to display the cart validation messages market's language specific and make it user-friendly to the customer for the better understanding. 

About the Market in Episerver Commerce?
Market is a central of Episerver Commerce. A single site can have multiple markets, each with its own product catalog, language, currency, and promotions. Classes in this topic are available in the Mediachase.Commerce or Mediachase.Commerce.Markets namespaces.

Problem:
In one of my site, I have implemented multi-market functionality and managed the content accordingly but there is no feature to display the cart validation message in readable format to the customer for market language specific.

e.g.

  • United State (en) : Display the cart validation message in English language.
  • France (fr) : Display the cart validation message in French language.

Solution:

Episerver provides a class method OrderValidationService.ValidateOrder(cart) to validate your cart before to save, using IOrderRepository.Save(cart) method. With the help of this method we make sure the cart has enough quantity, prices are correct and up-to-date, and any promotions are applied correctly.

The ValidateOrder(cart) method returns IDictionary<ILineItem, IList<ValidationIssue>> validation issue per ILineItem but  ValidationIssue is an enum type that returns validation message in below formats which are not user-friendly and market language specific.

  • CannotProcessDueToMissingOrderStatus
  • RemovedDueToCodeMissing
  • RemovedDueToNotAvailableInMarket
  • RemovedDueToUnavailableCatalog
  • ...

So let’s make cart validation message user-friendly in the simple way.

Step 1: Create an XML file language specific and place the all possible cart validation message like below and placed into the lang folder under the site root.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<languages>
  <language name="English" id="en">
    <cart>
      <validation>
        <CannotProcessDueToMissingOrderStatus>Cannot process due to missing order status.</CannotProcessDueToMissingOrderStatus>
        <RemovedDueToCodeMissing>The catalog entry code that maps to the line item has been removed or changed.</RemovedDueToCodeMissing>
        <RemovedDueToNotAvailableInMarket>Item has been removed from the cart because it is not available in your market.</RemovedDueToNotAvailableInMarket>
        <RemovedDueToUnavailableCatalog>Item has been removed from the cart because the catalog of this entry is not available.</RemovedDueToUnavailableCatalog>
        <RemovedDueToUnavailableItem>Item has been removed from the cart because it is not available at this time.</RemovedDueToUnavailableItem>
        <RemovedDueToInsufficientQuantityInInventory>Item has been removed from the cart because there is not enough available quantity.</RemovedDueToInsufficientQuantityInInventory>
        <RemovedDueToInactiveWarehouse>Item has been removed from the cart because the selected warehouse is inactive.</RemovedDueToInactiveWarehouse>
        <RemovedDueToMissingInventoryInformation>Item has been removed due to missing inventory information.</RemovedDueToMissingInventoryInformation>
        <RemovedDueToInvalidPrice>Item has been removed due to an invalid price.</RemovedDueToInvalidPrice>
        <RemovedDueToInvalidMaxQuantitySetting>Item has been removed due to an invalid setting for maximum quantity.</RemovedDueToInvalidMaxQuantitySetting>
        <AdjustedQuantityByMinQuantity>Item quantity has been adjusted due to the minimum quantity threshold.</AdjustedQuantityByMinQuantity>
        <AdjustedQuantityByMaxQuantity>Item quantity has been adjusted due to the maximum quantity threshold.</AdjustedQuantityByMaxQuantity>
        <AdjustedQuantityByBackorderQuantity>Item quantity has been adjusted due to backorder quantity threshold.</AdjustedQuantityByBackorderQuantity>
        <AdjustedQuantityByPreorderQuantity>Item quantity has been adjusted due to the preorder quantity threshold.</AdjustedQuantityByPreorderQuantity>
        <AdjustedQuantityByAvailableQuantity>Item quantity has been adjusted due to the available quantity threshold.</AdjustedQuantityByAvailableQuantity>
        <PlacedPricedChanged>This item's price has changed since it was added to your cart.</PlacedPricedChanged>
        <RemovedGiftDueToInsufficientQuantityInInventory>Gift item has been removed from the cart because there is not enough available quantity.</RemovedGiftDueToInsufficientQuantityInInventory>
        <RejectedInventoryRequestDueToInsufficientQuantity>The inventory request for item has been rejected because there is not enough available quantity.</RejectedInventoryRequestDueToInsufficientQuantity>
      </validation>
    </cart>
  </language>
  <language name="French" id="fr">
    <cart>
      <validation>
        <CannotProcessDueToMissingOrderStatus>Il ne peut pas être traité en raison d'un statut de commande manquant.</CannotProcessDueToMissingOrderStatus>
        <RemovedDueToCodeMissing>Le code d'entrée de catalogue qui correspond à l'élément de campagne a été supprimé ou modifié.</RemovedDueToCodeMissing>
        <RemovedDueToNotAvailableInMarket>L'article a été retiré du panier car il n'est pas disponible sur votre marché.</RemovedDueToNotAvailableInMarket>
        <RemovedDueToUnavailableCatalog>L'article a été retiré du panier car le catalogue de cette entrée n'est pas disponible.</RemovedDueToUnavailableCatalog>
        <RemovedDueToUnavailableItem>L'article a été retiré du panier car il n'est pas disponible pour le moment.</RemovedDueToUnavailableItem>
        <RemovedDueToInsufficientQuantityInInventory>L'article a été retiré du panier car la quantité disponible est insuffisante.</RemovedDueToInsufficientQuantityInInventory>
        <RemovedDueToInactiveWarehouse>L'article a été retiré du panier car l'entrepôt sélectionné est inactif.</RemovedDueToInactiveWarehouse>
        <RemovedDueToMissingInventoryInformation>L'article a été supprimé en raison d'informations d'inventaire manquantes.</RemovedDueToMissingInventoryInformation>
        <RemovedDueToInvalidPrice>L'article a été supprimé en raison d'un prix non valide.</RemovedDueToInvalidPrice>
        <RemovedDueToInvalidMaxQuantitySetting>L'article a été supprimé en raison d'un paramètre non valide pour la quantité maximale.</RemovedDueToInvalidMaxQuantitySetting>
        <AdjustedQuantityByMinQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité minimale.</AdjustedQuantityByMinQuantity>
        <AdjustedQuantityByMaxQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité maximale.</AdjustedQuantityByMaxQuantity>
        <AdjustedQuantityByBackorderQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité de commandes en souffrance.</AdjustedQuantityByBackorderQuantity>
        <AdjustedQuantityByPreorderQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité de précommande.</AdjustedQuantityByPreorderQuantity>
        <AdjustedQuantityByAvailableQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité disponible.</AdjustedQuantityByAvailableQuantity>
        <PlacedPricedChanged>Le prix de cet article a changé depuis qu'il a été ajouté à vos favoris.</PlacedPricedChanged>
        <RemovedGiftDueToInsufficientQuantityInInventory>L'article cadeau a été retiré du panier car la quantité disponible est insuffisante.</RemovedGiftDueToInsufficientQuantityInInventory>
        <RejectedInventoryRequestDueToInsufficientQuantity>La demande d'inventaire pour l'article a été rejetée car la quantité disponible n'est pas suffisante.</RejectedInventoryRequestDueToInsufficientQuantity>
      </validation>
    </cart>
  </language>
</languages>

Step 2: Create a model class that will hold the error message and variant code.

public class CartValidationIssue
{
        public string Message { get; set; }
 
        public string Code{ get; set; }

        public bool IsBlank => string.IsNullOrWhiteSpace(this.Message);
       
        public static CartValidationIssue Make(string message, string code)
        {
            return new CartValidationIssue
            {
                Message = message,
                Code = code,
            };
        }
 }

Step 3: Create described methods where you are validating your cart and returns the validation messages in the list format after reading from XML file and show on the cart page or mini-cart area.

  1. Use ICurrentMarket interface and get the current market culture
  2. Make sure you have selected correct default language for the current market in commerce manager for e.g. France choose default language francais

 

public List<CartValidationIssue> ValidateCart(ICart cart)
{

            var validationResult = _orderValidationService.ValidateOrder(cart);

            var errors =
                validationResult
                    ?.Select(lineItemIssueEntry => new
                    {
                        LineItemIssues =
                            lineItemIssueEntry.Value
                                .Select(validationIssue => new
                                {
                                    ValidationIssueMessage = this.GetCartValidationMessage(validationIssue),
                                    LineItemCode = lineItemIssueEntry.Key.Code,
                                })
                                .ToList(),
                    })
                    .SelectMany(lineItemIssueGroup => lineItemIssueGroup.LineItemIssues)
                    .Select(x => CartValidationIssue.Make(x.ValidationIssueMessage, x.LineItemCode))
                    .Where(x => !x.IsBlank)
                    .ToList() ?? new List<CartValidationIssue>();

            return errors;
 }
 private string GetCartValidationMessage(ValidationIssue issue)
 {
            var market = _currentMarket.GetCurrentMarket();
            var cultureInfo = market.DefaultLanguage;

            switch (issue)
            {
                default:
                case ValidationIssue.None:
                    return null;

                case ValidationIssue.CannotProcessDueToMissingOrderStatus:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/CannotProcessDueToMissingOrderStatus", "It cannot process due to missing order status.", cultureInfo);

                case ValidationIssue.RemovedDueToCodeMissing:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToCodeMissing", "The catalog entry code that maps to the line item has been removed or changed.", cultureInfo);

                case ValidationIssue.RemovedDueToNotAvailableInMarket:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToNotAvailableInMarket", "The catalog entry code that maps to the line item has been removed or changed.", cultureInfo);

                case ValidationIssue.RemovedDueToUnavailableCatalog:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToUnavailableCatalog", "The catalog entry code that maps to the line item has been removed or changed.", cultureInfo);

                case ValidationIssue.RemovedDueToUnavailableItem:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToUnavailableItem", "Item has been removed from the cart because it is not available at this time.", cultureInfo);

                case ValidationIssue.RemovedDueToInsufficientQuantityInInventory:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToInsufficientQuantityInInventory", "Item has been removed from the cart because there is not enough available quantity.", cultureInfo);

                case ValidationIssue.RemovedDueToInactiveWarehouse:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToInactiveWarehouse", "Item has been removed from the cart because the selected warehouse is inactive.", cultureInfo);

                case ValidationIssue.RemovedDueToMissingInventoryInformation:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToMissingInventoryInformation", "Item has been removed due to missing inventory information.", cultureInfo);

                case ValidationIssue.RemovedDueToInvalidPrice:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToInvalidPrice", "Item has been removed due to an invalid price.", cultureInfo);

                case ValidationIssue.RemovedDueToInvalidMaxQuantitySetting:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToInvalidMaxQuantitySetting", "Item has been removed due to an invalid setting for maximum quantity.", cultureInfo);

                case ValidationIssue.AdjustedQuantityByMinQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByMinQuantity", "Item quantity has been adjusted due to the minimum quantity threshold", cultureInfo);

                case ValidationIssue.AdjustedQuantityByMaxQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByMaxQuantity", "Item quantity has been adjusted due to the maximum quantity threshold.", cultureInfo);

                case ValidationIssue.AdjustedQuantityByBackorderQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByBackorderQuantity", "Item quantity has been adjusted due to backorder quantity threshold.", cultureInfo);

                case ValidationIssue.AdjustedQuantityByPreorderQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByPreorderQuantity", "Item quantity has been adjusted due to the preorder quantity threshold.", cultureInfo);

                case ValidationIssue.AdjustedQuantityByAvailableQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByAvailableQuantity", "Item quantity has been adjusted due to the available quantity threshold.", cultureInfo);

                case ValidationIssue.PlacedPricedChanged:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/PlacedPricedChanged", "This item's price has changed since it was added to your favorites.", cultureInfo);

                case ValidationIssue.RemovedGiftDueToInsufficientQuantityInInventory:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedGiftDueToInsufficientQuantityInInventory", "Gift item has been removed from the cart because there is not enough available quantity.", cultureInfo);

                case ValidationIssue.RejectedInventoryRequestDueToInsufficientQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RejectedInventoryRequestDueToInsufficientQuantity", "The inventory request for item has been rejected because there is not enough available quantity.", cultureInfo);
            }
 }

Result:

e.g. The validation message display for France(fr) market in the French language.

Enjoy the coding and share your thoughts 😊

Thanks for your visit!

Feb 01, 2021

Comments

Please login to comment.
Latest blogs
Integrating Optimizely DAM with Your Website

This article is the second in a series about integrating Optimizely DAM with websites. It discusses how to install the necessary package and code t...

Andrew Markham | Sep 28, 2024 | Syndicated blog

Opticon 2024 - highlights

I went to Opticon in Stockholm and here are my brief highlights based on the demos, presentations and roadmaps  Optimizely CMS SaaS will start to...

Daniel Ovaska | Sep 27, 2024

Required fields support in Optimizely Graph

It's been possible to have "required" properties (value must be entered) in the CMS for a long time. The required metadata haven't been reflected i...

Jonas Bergqvist | Sep 25, 2024

How to write a bespoke notification management system

Websites can be the perfect vehicle for notifying customers of important information quickly, whether it’s the latest offer, an operational message...

Nicole Drath | Sep 25, 2024

Optimizely DAM – An Introduction

I presented a talk about the Optimizely DAM at the OMVP summit during Opticon 2024 in Sweden. I have now converted that talk into two blog posts....

Andrew Markham | Sep 25, 2024 | Syndicated blog

Simple and Effective Personalization with Optimizely Data Platform (ODP)

As we dive into the amazing capabilities of Optimizely One, let’s shine a spotlight on the Optimizely Data Platform (ODP). This simple tool unifies...

Alex Harris - Perficient | Sep 24, 2024 | Syndicated blog