/// <summary>
            /// Adds or Removes the discount codes from the cart.
            /// </summary>
            /// <param name="shoppingCartId">The shopping cart identifier.</param>
            /// <param name="promotionCode">The promotion code.</param>
            /// <param name="isAdd">Indicates whether the operation is addition or removal of discount codes.</param>
            /// <returns>
            /// A shopping cart.
            /// </returns>
            /// <exception cref="System.ArgumentNullException">Thrown when shoppingCartId or promotionCode is null.</exception>
            /// <exception cref="Microsoft.Dynamics.Commerce.Runtime.DataValidationException">Shopping cart {0} was not found.</exception>
            public virtual async Task <Cart> AddOrRemovePromotionCode(string shoppingCartId, string promotionCode, bool isAdd)
            {
                if (string.IsNullOrWhiteSpace(shoppingCartId))
                {
                    throw new ArgumentNullException(nameof(shoppingCartId));
                }

                if (string.IsNullOrWhiteSpace(promotionCode))
                {
                    throw new ArgumentNullException(nameof(promotionCode));
                }

                ManagerFactory managerFactory = Utilities.GetManagerFactory(this.EcommerceContext);
                ICartManager   cartManager    = managerFactory.GetManager <ICartManager>();
                Cart           cart           = null;

                if (isAdd)
                {
                    cart = await cartManager.AddDiscountCode(shoppingCartId, promotionCode);
                }
                else
                {
                    cart = await cartManager.RemoveDiscountCodes(shoppingCartId, new Collection <string>() { promotionCode });
                }

                if (cart == null)
                {
                    RetailLogger.Log.OnlineStoreCartNotFound(shoppingCartId);
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotFound.ToString(), shoppingCartId);
                }

                cart = await DataAugmenter.GetAugmentedCart(this.EcommerceContext, cart);

                return(cart);
            }
            /// <summary>
            /// Removes the items.
            /// </summary>
            /// <param name="isCheckoutSession">If set to <c>true</c> [is checkout session].</param>
            /// <param name="lineIds">The line ids.</param>
            /// <returns>The updated cart.</returns>
            public async Task <Cart> RemoveItems(bool isCheckoutSession, IEnumerable <string> lineIds)
            {
                EcommerceContext      ecommerceContext      = ServiceUtilities.GetEcommerceContext(this.HttpContextBase);
                CartOperationsHandler cartOperationsHandler = new CartOperationsHandler(ecommerceContext);

                SessionType sessionType = ServiceUtilities.GetSessionType(this.HttpContextBase, isCheckoutSession);
                string      cartId      = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, sessionType);

                Cart cart = await cartOperationsHandler.RemoveItems(cartId, lineIds);

                // For checkout sessions, reflect the changes in shopping cart as well.
                if (sessionType == SessionType.AnonymousCheckout || sessionType == SessionType.SignedInCheckout)
                {
                    string shoppingCartId = null;
                    if (sessionType == SessionType.AnonymousCheckout)
                    {
                        shoppingCartId = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, SessionType.AnonymousShopping);
                    }
                    else if (sessionType == SessionType.SignedInCheckout)
                    {
                        shoppingCartId = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, SessionType.SignedInShopping);
                    }

                    await cartOperationsHandler.RemoveItems(shoppingCartId, lineIds);
                }

                cart = await DataAugmenter.GetAugmentedCart(ecommerceContext, cart);

                return(cart);
            }
            /// <summary>
            /// Adds the items.
            /// </summary>
            /// <param name="isCheckoutSession">If set to <c>true</c> [is checkout session].</param>
            /// <param name="cartLines">The cart lines.</param>
            /// <returns>The updated cart.</returns>
            public async Task <Cart> AddItems(bool isCheckoutSession, IEnumerable <CartLine> cartLines)
            {
                EcommerceContext      ecommerceContext      = ServiceUtilities.GetEcommerceContext(this.HttpContextBase);
                CartOperationsHandler cartOperationsHandler = new CartOperationsHandler(ecommerceContext);

                SessionType sessionType = ServiceUtilities.GetSessionType(this.HttpContextBase, isCheckoutSession);
                string      cartId      = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, sessionType);

                foreach (CartLine cartLine in cartLines)
                {
                    if (cartLine.Price != null && cartLine.Price != 0)
                    {
                        cartLine.IsPriceKeyedIn = true;
                    }
                }

                Cart cart = await cartOperationsHandler.AddItems(cartId, cartLines, sessionType);

                if (cart != null)
                {
                    ServiceUtilities.SetCartIdInResponseCookie(this.HttpContextBase, sessionType, cart.Id);
                }

                cart = await DataAugmenter.GetAugmentedCart(ecommerceContext, cart);

                return(cart);
            }
            /// <summary>
            /// Commences the checkout.
            /// </summary>
            /// <returns>Checkout cart.</returns>
            public async Task <Cart> CommenceCheckout()
            {
                EcommerceContext      ecommerceContext      = ServiceUtilities.GetEcommerceContext(this.HttpContextBase);
                CartOperationsHandler cartOperationsHandler = new CartOperationsHandler(ecommerceContext);

                string shoppingCartId;
                string previousCheckoutCartId;
                bool   isSignedIn = this.HttpContextBase.Request.IsAuthenticated;

                if (isSignedIn)
                {
                    shoppingCartId         = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, SessionType.SignedInShopping);
                    previousCheckoutCartId = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, SessionType.SignedInCheckout);
                }
                else
                {
                    shoppingCartId         = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, SessionType.AnonymousShopping);
                    previousCheckoutCartId = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, SessionType.AnonymousCheckout);
                }

                // Shopping cart would be null if the user lands on the checkout page immediately after signing in.
                // In this case we need to claim the anonymous shopping cart and assign it to the signed in user,
                // because there is no explicit GetShoppingCart call, which implicitly does the claiming, in the checkout page.
                if (string.IsNullOrWhiteSpace(shoppingCartId) && isSignedIn)
                {
                    Cart claimedShoppingCart = await this.GetCart(isCheckoutSession : true);

                    shoppingCartId = claimedShoppingCart.Id;
                    ServiceUtilities.SetCartIdInResponseCookie(this.HttpContextBase, SessionType.SignedInShopping, shoppingCartId);
                }

                Cart checkoutCart = await cartOperationsHandler.CommenceCheckout(shoppingCartId, previousCheckoutCartId);

                if (checkoutCart == null)
                {
                    string message = string.Format("Unable to create a checkout cart from shopping cart id: {0}", shoppingCartId);
                    throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotFound.ToString(), message);
                }

                // Update the checkout cart id cookie.
                SessionType sessionType = isSignedIn ? SessionType.SignedInCheckout : SessionType.AnonymousCheckout;

                ServiceUtilities.SetCartIdInResponseCookie(this.HttpContextBase, sessionType, checkoutCart.Id);

                checkoutCart = await DataAugmenter.GetAugmentedCart(ecommerceContext, checkoutCart);

                return(checkoutCart);
            }
            /// <summary>
            /// Commits the selected delivery options per line when the sales line in the order are being 'delivered' individually.
            /// </summary>
            /// <param name="shoppingCartId">The shopping cart identifier.</param>
            /// <param name="lineDeliverySpecifications">The line delivery options.</param>
            /// <returns>
            /// The updated shopping cart.
            /// </returns>
            /// <exception cref="System.ArgumentNullException">Thrown when the shoppingCartId or shippingOptions is null or empty.</exception>
            public virtual async Task <Cart> UpdateLineDeliverySpecifications(string shoppingCartId, IEnumerable <LineDeliverySpecification> lineDeliverySpecifications)
            {
                if (string.IsNullOrWhiteSpace(shoppingCartId))
                {
                    throw new ArgumentNullException(nameof(shoppingCartId));
                }

                if (lineDeliverySpecifications == null)
                {
                    throw new ArgumentNullException(nameof(lineDeliverySpecifications));
                }

                ManagerFactory managerFactory = Utilities.GetManagerFactory(this.EcommerceContext);
                ICartManager   cartManager    = managerFactory.GetManager <ICartManager>();
                Cart           cart           = await cartManager.UpdateLineDeliverySpecifications(shoppingCartId, lineDeliverySpecifications);

                cart = await DataAugmenter.GetAugmentedCart(this.EcommerceContext, cart);

                return(cart);
            }
            /// <summary>
            /// Updates the loyalty card id.
            /// </summary>
            /// <param name="shoppingCartId">The shopping cart id.</param>
            /// <param name="loyaltyCardId">The loyalty card id.</param>
            /// <returns>
            /// A shopping cart.
            /// </returns>
            /// <exception cref="System.ArgumentNullException">Thrown when shoppingCartId is null.</exception>
            /// <exception cref="Microsoft.Dynamics.Commerce.Runtime.DataValidationException">
            /// The loyalty card provided is blocked.
            /// or
            /// Invalid loyalty card number.
            /// or
            /// Shopping cart {0} of customer {1} was not found.
            /// </exception>
            public virtual async Task <Cart> UpdateLoyaltyCardId(string shoppingCartId, string loyaltyCardId)
            {
                if (string.IsNullOrWhiteSpace(shoppingCartId))
                {
                    throw new ArgumentNullException(nameof(shoppingCartId));
                }

                ManagerFactory managerFactory = Utilities.GetManagerFactory(this.EcommerceContext);
                ICartManager   cartManager    = managerFactory.GetManager <ICartManager>();

                Cart cart = new Cart()
                {
                    Id            = shoppingCartId,
                    LoyaltyCardId = loyaltyCardId
                };

                cart = await cartManager.Update(cart);

                cart = await DataAugmenter.GetAugmentedCart(this.EcommerceContext, cart);

                return(cart);
            }
            /// <summary>
            /// Gets the cart.
            /// </summary>
            /// <param name="isCheckoutSession">If set to <c>true</c> [is checkout session].</param>
            /// <returns>The cart object.</returns>
            public async Task <Cart> GetCart(bool isCheckoutSession)
            {
                EcommerceContext      ecommerceContext      = ServiceUtilities.GetEcommerceContext(this.HttpContextBase);
                CartOperationsHandler cartOperationsHandler = new CartOperationsHandler(ecommerceContext);

                SessionType sessionType = ServiceUtilities.GetSessionType(this.HttpContextBase, isCheckoutSession);
                string      cartId      = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, sessionType);

                Cart cart = null;

                if (sessionType == SessionType.AnonymousCheckout || sessionType == SessionType.SignedInCheckout)
                {
                    cart = await cartOperationsHandler.GetCart(cartId);
                }
                else
                {
                    if (sessionType == SessionType.AnonymousShopping)
                    {
                        if (!string.IsNullOrEmpty(cartId))
                        {
                            cart = await cartOperationsHandler.GetCart(cartId);
                        }
                    }
                    else if (sessionType == SessionType.SignedInShopping)
                    {
                        // Get the latest cart associated with the user.
                        Cart activeAuthenticatedShoppingCart = await cartOperationsHandler.GetActiveShoppingCart();

                        string anonymousShoppingCartId      = ServiceUtilities.GetCartIdFromRequestCookie(this.HttpContextBase, SessionType.AnonymousShopping);
                        bool   isAnonymousShoppingCartIdSet = !string.IsNullOrWhiteSpace(anonymousShoppingCartId);

                        if ((activeAuthenticatedShoppingCart == null) && isAnonymousShoppingCartIdSet)
                        {
                            // Claim the shopping cart id present in the cookie.
                            activeAuthenticatedShoppingCart = await cartOperationsHandler.ClaimAnonymousCart(anonymousShoppingCartId);
                        }
                        else if ((activeAuthenticatedShoppingCart != null) && isAnonymousShoppingCartIdSet)
                        {
                            // Move items from the anonymous shopping cart to the authenticated shopping cart.
                            activeAuthenticatedShoppingCart = await cartOperationsHandler.MoveItemsBetweenCarts(anonymousShoppingCartId, activeAuthenticatedShoppingCart.Id, sessionType);
                        }

                        // Clear anonymous shopping cart identifier.
                        ServiceUtilities.SetCartIdInResponseCookie(this.HttpContextBase, SessionType.AnonymousShopping, string.Empty);

                        cart = activeAuthenticatedShoppingCart;
                    }
                    else
                    {
                        string message = string.Format("Invalid session type encountered: {0}.", sessionType);
                        throw new NotSupportedException(message);
                    }

                    if (cart == null)
                    {
                        cart = await cartOperationsHandler.CreateEmptyCart();
                    }
                }

                ServiceUtilities.SetCartIdInResponseCookie(this.HttpContextBase, sessionType, cart.Id);

                cart = await DataAugmenter.GetAugmentedCart(ecommerceContext, cart);

                return(cart);
            }