OrderRepository.SaveAsPurchaseOrder(cart) returns null when trying to create a purchase order

Vote:
 

Hello, 

We got an error on a customer site where OrderRepository.SaveAsPurchaseOrder(cart) returns null when trying to create a purchase order. It doesn't throw an exception with an descriptive error message, but only returns null, so we don't know why it fails (we get null-ref exc when we try to use the purchaseOrder). How do we figure out why it gives us null, is something missing on the cart or is this a bug?

We're running Epi-commerce 13.14.1

#221289
Edited, Apr 16, 2020 7:56
Vote:
 

Hi Oscar, Please validate the cart using ICartValidationService before saving as purchase order.

Please try the below code.

1. Create an error view model.

public class ErrorViewModel
{
    public string Message { get; set; }

    public string LineItemCode { get; set; }

    public static ErrorViewModel Make(string error, string code)
    {
        return new ErrorViewModel
        {
            Message = error,
            LineItemCode = code
        };
    }
}
  

2. Create an interface with ICartValidationService 

public interface ICartValidationService
{
   IEnumerable<ErrorViewModel> ValidateCart(ICart cart);
}

3.  Finally, create a cart validation service.

public class CartValidationService : ICartValidationService
    {
        private readonly IInventoryProcessor _inventoryProcessor;
        private readonly ILineItemValidator _lineItemValidator;
        private readonly IPlacedPriceProcessor _placedPriceProcessor;
        private readonly IPromotionEngine _promotionEngine;

        public CartValidationService(
            IInventoryProcessor inventoryProcessor,
            ILineItemValidator lineItemValidator,
            IPlacedPriceProcessor placedPriceProcessor,
            IPromotionEngine promotionEngine)
        {
            _inventoryProcessor = inventoryProcessor ?? throw new ArgumentNullException(nameof(inventoryProcessor));
            _lineItemValidator = lineItemValidator ?? throw new ArgumentNullException(nameof(lineItemValidator));
            _placedPriceProcessor =
                placedPriceProcessor ?? throw new ArgumentNullException(nameof(placedPriceProcessor));
            _promotionEngine = promotionEngine ?? throw new ArgumentNullException(nameof(promotionEngine));
        }

        public IEnumerable<ErrorViewModel> ValidateCart(ICart cart)
        {
            var errors =
                this.Validate(cart)
                    ?.Select(lineItemEntry => new
                    {
                        LineItemIssues =
                            lineItemEntry.Value
                                .Select(validationIssue => new
                                {
                                    ValidationIssueMessage = this?.GetCartValidationMessage(validationIssue),
                                    LineItemCode = lineItemEntry.Key.Code,
                                })
                                .ToList(),
                    })
                    .SelectMany(lineItemIssueGroup => lineItemIssueGroup.LineItemIssues)
                    .Select(x => ErrorViewModel.Make(x.ValidationIssueMessage, x.LineItemCode))
                    .ToList() ?? new List<ErrorViewModel>();

            return errors;
        }

        private Dictionary<ILineItem, List<ValidationIssue>> Validate(ICart cart)
        {
            if (cart == null)
                return null;

            if (string.Equals(cart.Name, OrderNames.WishList, StringComparison.InvariantCultureIgnoreCase))
                return new Dictionary<ILineItem, List<ValidationIssue>>();

            var validationIssues = new Dictionary<ILineItem, List<ValidationIssue>>();

            cart.ValidateOrRemoveLineItems(
                (item, issue) => this.AddValidationIssues(validationIssues, item, issue),
                _lineItemValidator);

            cart.UpdatePlacedPriceOrRemoveLineItems(
                CustomerContext.Current.GetContactById(cart.CustomerId),
                (item, issue) => this.AddValidationIssues(validationIssues, item, issue),
                _placedPriceProcessor);

            cart.UpdateInventoryOrRemoveLineItems(
                (item, issue) => this.AddValidationIssues(validationIssues, item, issue),
                _inventoryProcessor);

            cart.ApplyDiscounts(_promotionEngine, new PromotionEngineSettings());

            cart.UpdateInventoryOrRemoveLineItems(
                (item, issue) => { },
                _inventoryProcessor);

            return validationIssues;
        }

        private void AddValidationIssues(
            Dictionary<ILineItem, List<ValidationIssue>> validationIssues,
            ILineItem item,
            ValidationIssue issue)
        {
            if (validationIssues == null)
                return;

            if (!validationIssues.ContainsKey(item))
            {
                validationIssues.Add(item, new List<ValidationIssue>());
            }

            var issues = validationIssues[item];

            if (issues.Any(x => x == issue))
                return;

            issues.Add(issue);

            validationIssues[item] = issues;
        }

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

                case ValidationIssue.CannotProcessDueToMissingOrderStatus:
                    return "Message...";

                case ValidationIssue.RemovedDueToCodeMissing:
                    return "Message...";

                case ValidationIssue.RemovedDueToNotAvailableInMarket:
                    return "Message...";

                case ValidationIssue.RemovedDueToUnavailableCatalog:
                    return "Message...";

                case ValidationIssue.RemovedDueToUnavailableItem:
                    return "Message...";

                case ValidationIssue.RemovedDueToInsufficientQuantityInInventory:
                    return "Message...";

                case ValidationIssue.RemovedDueToInactiveWarehouse:
                    return "Message...";

                case ValidationIssue.RemovedDueToMissingInventoryInformation:
                    return "Message...";

                case ValidationIssue.RemovedDueToInvalidPrice:
                    return "Message...";

                case ValidationIssue.RemovedDueToInvalidMaxQuantitySetting:
                    return "Message...";

                case ValidationIssue.AdjustedQuantityByMinQuantity:
                    return "Message...";

                case ValidationIssue.AdjustedQuantityByMaxQuantity:
                    return "Message...";

                case ValidationIssue.AdjustedQuantityByBackorderQuantity:
                    return "Message...";

                case ValidationIssue.AdjustedQuantityByPreorderQuantity:
                    return "Message...";

                case ValidationIssue.AdjustedQuantityByAvailableQuantity:
                    return "Message...";

                case ValidationIssue.PlacedPricedChanged:
                    return "Message...";

                case ValidationIssue.RemovedGiftDueToInsufficientQuantityInInventory:
                    return "Message...";

                case ValidationIssue.RejectedInventoryRequestDueToInsufficientQuantity:
                    return "Message...";
            }
        }
    }
#221317
Edited, Apr 16, 2020 10:42
Vote:
 

Thank you, we'll do that!

Where can I find the ICartValidationService ? Because it doesn't seem to exist in Commerce 13.14.1?

#221320
Edited, Apr 16, 2020 10:15
Sanjay Kumar - Apr 16, 2020 10:45
Hi Oscar, I have updated my previous comment so, please try.
Validate a cart Episerver help url: https://world.episerver.com/documentation/developer-guides/commerce/orders/shopping-carts
Vote:
 

Ah, thanks alot for sharing that :). 

#221329
Apr 16, 2020 10:48
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.