示例#1
0
        protected virtual void PrepareShippingCartModel(ShoppingCartModel model,
                                                        IList <ShoppingCartItem> cart,
                                                        IList <ShippingCart> shippingCarts,
                                                        IList <ShippingCartItem> shippingCartItems,
                                                        bool isEditable = true,
                                                        bool validateCheckoutAttributes       = false,
                                                        bool prepareEstimateShippingIfEnabled = true, bool setEstimateShippingDefaultAddress = true,
                                                        bool prepareAndDisplayOrderReviewData = false)
        {
            if (cart == null)
            {
                throw new ArgumentNullException("cart");
            }

            if (model == null)
            {
                throw new ArgumentNullException("model");
            }

            model.OnePageCheckoutEnabled = _orderSettings.OnePageCheckoutEnabled;

            if (cart.Count == 0)
            {
                return;
            }

            #region Simple properties

            model.IsEditable        = isEditable;
            model.ShowProductImages = _shoppingCartSettings.ShowProductImagesOnShoppingCart;
            model.ShowSku           = _catalogSettings.ShowProductSku;
            var checkoutAttributesXml = _workContext.CurrentCustomer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id);
            model.CheckoutAttributeInfo = _checkoutAttributeFormatter.FormatAttributes(checkoutAttributesXml, _workContext.CurrentCustomer);
            bool minOrderSubtotalAmountOk = _orderProcessingService.ValidateMinOrderSubtotalAmount(cart);
            if (!minOrderSubtotalAmountOk)
            {
                decimal minOrderSubtotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderSubtotalAmount, _workContext.WorkingCurrency);
                model.MinOrderSubtotalWarning = string.Format(_localizationService.GetResource("Checkout.MinOrderSubtotalAmount"), _priceFormatter.FormatPrice(minOrderSubtotalAmount, true, false));
            }
            model.TermsOfServiceOnShoppingCartPage = _orderSettings.TermsOfServiceOnShoppingCartPage;
            model.TermsOfServiceOnOrderConfirmPage = _orderSettings.TermsOfServiceOnOrderConfirmPage;

            //gift card and gift card boxes
            model.DiscountBox.Display = _shoppingCartSettings.ShowDiscountBox;
            var discountCouponCode = _workContext.CurrentCustomer.GetAttribute <string>(SystemCustomerAttributeNames.DiscountCouponCode);
            var discount           = _discountService.GetDiscountByCouponCode(discountCouponCode);
            if (discount != null &&
                discount.RequiresCouponCode &&
                _discountService.IsDiscountValid(discount, _workContext.CurrentCustomer))
            {
                model.DiscountBox.CurrentCode = discount.CouponCode;
            }
            model.GiftCardBox.Display = _shoppingCartSettings.ShowGiftCardBox;

            //cart warnings
            var cartWarnings = _shoppingCartService.GetShoppingCartWarnings(cart, checkoutAttributesXml, validateCheckoutAttributes);
            foreach (var warning in cartWarnings)
            {
                model.Warnings.Add(warning);
            }

            #endregion

            #region Checkout attributes

            var checkoutAttributes = _checkoutAttributeService.GetAllCheckoutAttributes(_storeContext.CurrentStore.Id, !cart.RequiresShipping());
            foreach (var attribute in checkoutAttributes)
            {
                var attributeModel = new ShoppingCartModel.CheckoutAttributeModel
                {
                    Id                   = attribute.Id,
                    Name                 = attribute.GetLocalized(x => x.Name),
                    TextPrompt           = attribute.GetLocalized(x => x.TextPrompt),
                    IsRequired           = attribute.IsRequired,
                    AttributeControlType = attribute.AttributeControlType,
                    DefaultValue         = attribute.DefaultValue
                };
                if (!String.IsNullOrEmpty(attribute.ValidationFileAllowedExtensions))
                {
                    attributeModel.AllowedFileExtensions = attribute.ValidationFileAllowedExtensions
                                                           .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                                           .ToList();
                }

                if (attribute.ShouldHaveValues())
                {
                    //values
                    var attributeValues = _checkoutAttributeService.GetCheckoutAttributeValues(attribute.Id);
                    foreach (var attributeValue in attributeValues)
                    {
                        var attributeValueModel = new ShoppingCartModel.CheckoutAttributeValueModel
                        {
                            Id              = attributeValue.Id,
                            Name            = attributeValue.GetLocalized(x => x.Name),
                            ColorSquaresRgb = attributeValue.ColorSquaresRgb,
                            IsPreSelected   = attributeValue.IsPreSelected,
                        };
                        attributeModel.Values.Add(attributeValueModel);

                        //display price if allowed
                        if (_permissionService.Authorize(StandardPermissionProvider.DisplayPrices))
                        {
                            decimal priceAdjustmentBase = _taxService.GetCheckoutAttributePrice(attributeValue);
                            decimal priceAdjustment     = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency);
                            if (priceAdjustmentBase > decimal.Zero)
                            {
                                attributeValueModel.PriceAdjustment = "+" + _priceFormatter.FormatPrice(priceAdjustment);
                            }
                            else if (priceAdjustmentBase < decimal.Zero)
                            {
                                attributeValueModel.PriceAdjustment = "-" + _priceFormatter.FormatPrice(-priceAdjustment);
                            }
                        }
                    }
                }



                //set already selected attributes
                var selectedCheckoutAttributes = _workContext.CurrentCustomer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id);
                switch (attribute.AttributeControlType)
                {
                case AttributeControlType.DropdownList:
                case AttributeControlType.RadioList:
                case AttributeControlType.Checkboxes:
                case AttributeControlType.ColorSquares:
                {
                    if (!String.IsNullOrEmpty(selectedCheckoutAttributes))
                    {
                        //clear default selection
                        foreach (var item in attributeModel.Values)
                        {
                            item.IsPreSelected = false;
                        }

                        //select new values
                        var selectedValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(selectedCheckoutAttributes);
                        foreach (var attributeValue in selectedValues)
                        {
                            foreach (var item in attributeModel.Values)
                            {
                                if (attributeValue.Id == item.Id)
                                {
                                    item.IsPreSelected = true;
                                }
                            }
                        }
                    }
                }
                break;

                case AttributeControlType.ReadonlyCheckboxes:
                {
                    //do nothing
                    //values are already pre-set
                }
                break;

                case AttributeControlType.TextBox:
                case AttributeControlType.MultilineTextbox:
                {
                    if (!String.IsNullOrEmpty(selectedCheckoutAttributes))
                    {
                        var enteredText = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id);
                        if (enteredText.Count > 0)
                        {
                            attributeModel.DefaultValue = enteredText[0];
                        }
                    }
                }
                break;

                case AttributeControlType.Datepicker:
                {
                    //keep in mind my that the code below works only in the current culture
                    var selectedDateStr = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id);
                    if (selectedDateStr.Count > 0)
                    {
                        DateTime selectedDate;
                        if (DateTime.TryParseExact(selectedDateStr[0], "D", CultureInfo.CurrentCulture,
                                                   DateTimeStyles.None, out selectedDate))
                        {
                            //successfully parsed
                            attributeModel.SelectedDay   = selectedDate.Day;
                            attributeModel.SelectedMonth = selectedDate.Month;
                            attributeModel.SelectedYear  = selectedDate.Year;
                        }
                    }
                }
                break;

                default:
                    break;
                }

                model.CheckoutAttributes.Add(attributeModel);
            }

            #endregion

            #region Cart items
            foreach (var sci in cart)
            {
                var cartItemModel = new ShoppingCartModel.ShoppingCartItemModel
                {
                    Id            = sci.Id,
                    Sku           = sci.Product.FormatSku(sci.AttributesXml, _productAttributeParser),
                    ProductId     = sci.Product.Id,
                    ProductName   = sci.Product.GetLocalized(x => x.Name),
                    ProductSeName = sci.Product.GetSeName(),
                    Quantity      = sci.Quantity,
                    AttributeInfo = _productAttributeFormatter.FormatAttributes(sci.Product, sci.AttributesXml),
                };

                //allow editing?
                //1. setting enabled?
                //2. simple product?
                //3. has attribute or gift card?
                //4. visible individually?
                cartItemModel.AllowItemEditing = _shoppingCartSettings.AllowCartItemEditing &&
                                                 sci.Product.ProductType == ProductType.SimpleProduct &&
                                                 (!String.IsNullOrEmpty(cartItemModel.AttributeInfo) || sci.Product.IsGiftCard) &&
                                                 sci.Product.VisibleIndividually;

                //allowed quantities
                var allowedQuantities = sci.Product.ParseAllowedQuantities();
                foreach (var qty in allowedQuantities)
                {
                    cartItemModel.AllowedQuantities.Add(new SelectListItem
                    {
                        Text     = qty.ToString(),
                        Value    = qty.ToString(),
                        Selected = sci.Quantity == qty
                    });
                }

                //recurring info
                if (sci.Product.IsRecurring)
                {
                    cartItemModel.RecurringInfo = string.Format(_localizationService.GetResource("ShoppingCart.RecurringPeriod"), sci.Product.RecurringCycleLength, sci.Product.RecurringCyclePeriod.GetLocalizedEnum(_localizationService, _workContext));
                }

                //rental info
                if (sci.Product.IsRental)
                {
                    var rentalStartDate = sci.RentalStartDateUtc.HasValue ? sci.Product.FormatRentalDate(sci.RentalStartDateUtc.Value) : "";
                    var rentalEndDate   = sci.RentalEndDateUtc.HasValue ? sci.Product.FormatRentalDate(sci.RentalEndDateUtc.Value) : "";
                    cartItemModel.RentalInfo = string.Format(_localizationService.GetResource("ShoppingCart.Rental.FormattedDate"),
                                                             rentalStartDate, rentalEndDate);
                }

                //unit prices
                if (sci.Product.CallForPrice)
                {
                    cartItemModel.UnitPrice = _localizationService.GetResource("Products.CallForPrice");
                }
                else
                {
                    decimal taxRate;
                    decimal shoppingCartUnitPriceWithDiscountBase = _taxService.GetProductPrice(sci.Product, _priceCalculationService.GetUnitPrice(sci), out taxRate);
                    decimal shoppingCartUnitPriceWithDiscount     = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartUnitPriceWithDiscountBase, _workContext.WorkingCurrency);
                    cartItemModel.UnitPrice = _priceFormatter.FormatPrice(shoppingCartUnitPriceWithDiscount);
                }
                //subtotal, discount
                if (sci.Product.CallForPrice)
                {
                    cartItemModel.SubTotal = _localizationService.GetResource("Products.CallForPrice");
                }
                else
                {
                    //sub total
                    Discount scDiscount;
                    decimal  shoppingCartItemDiscountBase;
                    decimal  taxRate;
                    decimal  shoppingCartItemSubTotalWithDiscountBase = _taxService.GetProductPrice(sci.Product, _priceCalculationService.GetSubTotal(sci, true, out shoppingCartItemDiscountBase, out scDiscount), out taxRate);
                    decimal  shoppingCartItemSubTotalWithDiscount     = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemSubTotalWithDiscountBase, _workContext.WorkingCurrency);
                    cartItemModel.SubTotal = _priceFormatter.FormatPrice(shoppingCartItemSubTotalWithDiscount);

                    //display an applied discount amount
                    if (scDiscount != null)
                    {
                        shoppingCartItemDiscountBase = _taxService.GetProductPrice(sci.Product, shoppingCartItemDiscountBase, out taxRate);
                        if (shoppingCartItemDiscountBase > decimal.Zero)
                        {
                            decimal shoppingCartItemDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemDiscountBase, _workContext.WorkingCurrency);
                            cartItemModel.Discount = _priceFormatter.FormatPrice(shoppingCartItemDiscount);
                        }
                    }
                }

                //picture
                if (_shoppingCartSettings.ShowProductImagesOnShoppingCart)
                {
                    cartItemModel.Picture = PrepareCartItemPictureModel(sci,
                                                                        _mediaSettings.CartThumbPictureSize, true, cartItemModel.ProductName);
                }

                //item warnings
                var itemWarnings = _shoppingCartService.GetShoppingCartItemWarnings(
                    _workContext.CurrentCustomer,
                    sci.ShoppingCartType,
                    sci.Product,
                    sci.StoreId,
                    sci.AttributesXml,
                    sci.CustomerEnteredPrice,
                    sci.RentalStartDateUtc,
                    sci.RentalEndDateUtc,
                    sci.Quantity,
                    false);
                foreach (var warning in itemWarnings)
                {
                    cartItemModel.Warnings.Add(warning);
                }

                //shipping item
                var existsShippingItems = shippingCartItems.Where(c => c.ShoppingCartItemId == sci.Id).ToList();
                for (int i = 0; i < sci.Quantity; i++)
                {
                    var existsShippingItem    = existsShippingItems.FirstOrDefault(c => c.ShippingCartPosition == i);
                    var shippingCartItemModel = new ShoppingCartModel.ShippingCartItemModel
                    {
                        RecipientName        = existsShippingItem != null ? existsShippingItem.ShippingCart.RecipientName : string.Empty,
                        ShippingCartPosition = i
                    };
                    cartItemModel.ShippingCartItems.Add(shippingCartItemModel);
                }

                model.Items.Add(cartItemModel);
            }

            #endregion

            #region ShippingCartItems
            model.RecipientNames = shippingCarts.Select(c => c.RecipientName).ToList();
            if (model.RecipientNames.Contains(MySelf) && model.RecipientNames.IndexOf(MySelf) != 0)
            {
                model.RecipientNames.Remove(MySelf);
            }
            if (!model.RecipientNames.Contains(MySelf))
            {
                model.RecipientNames.Insert(0, MySelf);
            }

            #endregion

            #region Button payment methods

            var paymentMethods = _paymentService
                                 .LoadActivePaymentMethods(_workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id)
                                 .Where(pm => pm.PaymentMethodType == PaymentMethodType.Button)
                                 .Where(pm => !pm.HidePaymentMethod(cart))
                                 .ToList();
            foreach (var pm in paymentMethods)
            {
                if (cart.IsRecurring() && pm.RecurringPaymentType == RecurringPaymentType.NotSupported)
                {
                    continue;
                }

                string actionName;
                string controllerName;
                RouteValueDictionary routeValues;
                pm.GetPaymentInfoRoute(out actionName, out controllerName, out routeValues);

                model.ButtonPaymentMethodActionNames.Add(actionName);
                model.ButtonPaymentMethodControllerNames.Add(controllerName);
                model.ButtonPaymentMethodRouteValues.Add(routeValues);
            }

            #endregion

            #region Order review data

            if (prepareAndDisplayOrderReviewData)
            {
                model.OrderReviewData.Display = true;

                //billing info
                var billingAddress = _workContext.CurrentCustomer.BillingAddress;
                if (billingAddress != null)
                {
                    model.OrderReviewData.BillingAddress.PrepareModel(
                        address: billingAddress,
                        excludeProperties: false,
                        addressSettings: _addressSettings,
                        addressAttributeFormatter: _addressAttributeFormatter);
                }

                //shipping info
                if (cart.RequiresShipping())
                {
                    model.OrderReviewData.IsShippable = true;

                    if (_shippingSettings.AllowPickUpInStore)
                    {
                        model.OrderReviewData.SelectedPickUpInStore = _workContext.CurrentCustomer.GetAttribute <bool>(SystemCustomerAttributeNames.SelectedPickUpInStore, _storeContext.CurrentStore.Id);
                    }

                    if (!model.OrderReviewData.SelectedPickUpInStore)
                    {
                        var shippingAddress = _workContext.CurrentCustomer.ShippingAddress;
                        if (shippingAddress != null)
                        {
                            model.OrderReviewData.ShippingAddress.PrepareModel(
                                address: shippingAddress,
                                excludeProperties: false,
                                addressSettings: _addressSettings,
                                addressAttributeFormatter: _addressAttributeFormatter);
                        }
                    }


                    //selected shipping method
                    var shippingOption = _workContext.CurrentCustomer.GetAttribute <ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _storeContext.CurrentStore.Id);
                    if (shippingOption != null)
                    {
                        model.OrderReviewData.ShippingMethod = shippingOption.Name;
                    }
                }
                //payment info
                var selectedPaymentMethodSystemName = _workContext.CurrentCustomer.GetAttribute <string>(
                    SystemCustomerAttributeNames.SelectedPaymentMethod, _storeContext.CurrentStore.Id);
                var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(selectedPaymentMethodSystemName);
                model.OrderReviewData.PaymentMethod = paymentMethod != null?paymentMethod.GetLocalizedFriendlyName(_localizationService, _workContext.WorkingLanguage.Id) : "";

                //custom values
                var processPaymentRequest = _httpContext.Session["OrderPaymentInfo"] as ProcessPaymentRequest;
                if (processPaymentRequest != null)
                {
                    model.OrderReviewData.CustomValues = processPaymentRequest.CustomValues;
                }
            }
            #endregion
        }
        private async Task PrepareCheckoutAttributes(ShoppingCartModel model, GetShoppingCart request)
        {
            #region Checkout attributes

            var checkoutAttributes = await _checkoutAttributeService.GetAllCheckoutAttributes(request.Store.Id, !request.Cart.RequiresShipping());

            foreach (var attribute in checkoutAttributes)
            {
                var attributeModel = new ShoppingCartModel.CheckoutAttributeModel {
                    Id                   = attribute.Id,
                    Name                 = attribute.GetLocalized(x => x.Name, request.Language.Id),
                    TextPrompt           = attribute.GetLocalized(x => x.TextPrompt, request.Language.Id),
                    IsRequired           = attribute.IsRequired,
                    AttributeControlType = attribute.AttributeControlType,
                    DefaultValue         = attribute.DefaultValue
                };
                if (!String.IsNullOrEmpty(attribute.ValidationFileAllowedExtensions))
                {
                    attributeModel.AllowedFileExtensions = attribute.ValidationFileAllowedExtensions
                                                           .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                                           .ToList();
                }

                if (attribute.ShouldHaveValues())
                {
                    //values
                    var attributeValues = attribute.CheckoutAttributeValues;
                    foreach (var attributeValue in attributeValues)
                    {
                        var attributeValueModel = new ShoppingCartModel.CheckoutAttributeValueModel {
                            Id              = attributeValue.Id,
                            Name            = attributeValue.GetLocalized(x => x.Name, request.Language.Id),
                            ColorSquaresRgb = attributeValue.ColorSquaresRgb,
                            IsPreSelected   = attributeValue.IsPreSelected,
                        };
                        attributeModel.Values.Add(attributeValueModel);

                        //display price if allowed
                        if (await _permissionService.Authorize(StandardPermissionProvider.DisplayPrices))
                        {
                            decimal priceAdjustmentBase = (await _taxService.GetCheckoutAttributePrice(attribute, attributeValue)).checkoutPrice;
                            decimal priceAdjustment     = await _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, request.Currency);

                            if (priceAdjustmentBase > decimal.Zero)
                            {
                                attributeValueModel.PriceAdjustment = "+" + _priceFormatter.FormatPrice(priceAdjustment);
                            }
                            else if (priceAdjustmentBase < decimal.Zero)
                            {
                                attributeValueModel.PriceAdjustment = "-" + _priceFormatter.FormatPrice(-priceAdjustment);
                            }
                        }
                    }
                }
                //set already selected attributes
                var selectedCheckoutAttributes = request.Customer.GetAttributeFromEntity <string>(SystemCustomerAttributeNames.CheckoutAttributes, request.Store.Id);
                switch (attribute.AttributeControlType)
                {
                case AttributeControlType.DropdownList:
                case AttributeControlType.RadioList:
                case AttributeControlType.Checkboxes:
                case AttributeControlType.ColorSquares:
                case AttributeControlType.ImageSquares:
                {
                    if (!String.IsNullOrEmpty(selectedCheckoutAttributes))
                    {
                        //clear default selection
                        foreach (var item in attributeModel.Values)
                        {
                            item.IsPreSelected = false;
                        }

                        //select new values
                        var selectedValues = await _checkoutAttributeParser.ParseCheckoutAttributeValues(selectedCheckoutAttributes);

                        foreach (var attributeValue in selectedValues)
                        {
                            if (attributeModel.Id == attributeValue.CheckoutAttributeId)
                            {
                                foreach (var item in attributeModel.Values)
                                {
                                    if (attributeValue.Id == item.Id)
                                    {
                                        item.IsPreSelected = true;
                                    }
                                }
                            }
                        }
                    }
                }
                break;

                case AttributeControlType.ReadonlyCheckboxes:
                {
                    //do nothing
                    //values are already pre-set
                }
                break;

                case AttributeControlType.TextBox:
                case AttributeControlType.MultilineTextbox:
                {
                    if (!String.IsNullOrEmpty(selectedCheckoutAttributes))
                    {
                        var enteredText = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id);
                        if (enteredText.Any())
                        {
                            attributeModel.DefaultValue = enteredText[0];
                        }
                    }
                }
                break;

                case AttributeControlType.Datepicker:
                {
                    //keep in mind my that the code below works only in the current culture
                    var selectedDateStr = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id);
                    if (selectedDateStr.Any())
                    {
                        DateTime selectedDate;
                        if (DateTime.TryParseExact(selectedDateStr[0], "D", CultureInfo.CurrentCulture,
                                                   DateTimeStyles.None, out selectedDate))
                        {
                            //successfully parsed
                            attributeModel.SelectedDay   = selectedDate.Day;
                            attributeModel.SelectedMonth = selectedDate.Month;
                            attributeModel.SelectedYear  = selectedDate.Year;
                        }
                    }
                }
                break;

                case AttributeControlType.FileUpload:
                {
                    if (!String.IsNullOrEmpty(selectedCheckoutAttributes))
                    {
                        var  downloadGuidStr = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id).FirstOrDefault();
                        Guid downloadGuid;
                        Guid.TryParse(downloadGuidStr, out downloadGuid);
                        var download = await _downloadService.GetDownloadByGuid(downloadGuid);

                        if (download != null)
                        {
                            attributeModel.DefaultValue = download.DownloadGuid.ToString();
                        }
                    }
                }
                break;

                default:
                    break;
                }

                model.CheckoutAttributes.Add(attributeModel);
            }
            #endregion
        }
        public override async Task MapAsync(IEnumerable <OrganizedShoppingCartItem> from, ShoppingCartModel to, dynamic parameters = null)
        {
            Guard.NotNull(from, nameof(from));
            Guard.NotNull(to, nameof(to));

            if (!from.Any())
            {
                return;
            }

            await base.MapAsync(from, to, null);

            var store    = _services.StoreContext.CurrentStore;
            var customer = _services.WorkContext.CurrentCustomer;
            var currency = _services.WorkContext.WorkingCurrency;

            var isEditable = parameters?.IsEditable == true;
            var validateCheckoutAttributes        = parameters?.ValidateCheckoutAttributes == true;
            var prepareEstimateShippingIfEnabled  = parameters?.PrepareEstimateShippingIfEnabled == true;
            var setEstimateShippingDefaultAddress = parameters?.SetEstimateShippingDefaultAddress == true;
            var prepareAndDisplayOrderReviewData  = parameters?.PrepareAndDisplayOrderReviewData == true;

            #region Simple properties

            to.MediaDimensions             = _mediaSettings.CartThumbPictureSize;
            to.DeliveryTimesPresentation   = _shoppingCartSettings.DeliveryTimesInShoppingCart;
            to.DisplayBasePrice            = _shoppingCartSettings.ShowBasePrice;
            to.DisplayWeight               = _shoppingCartSettings.ShowWeight;
            to.DisplayMoveToWishlistButton = await _services.Permissions.AuthorizeAsync(Permissions.Cart.AccessWishlist);

            to.TermsOfServiceEnabled         = _orderSettings.TermsOfServiceEnabled;
            to.DisplayCommentBox             = _shoppingCartSettings.ShowCommentBox;
            to.DisplayEsdRevocationWaiverBox = _shoppingCartSettings.ShowEsdRevocationWaiverBox;
            to.IsEditable = isEditable;

            var measure = await _db.MeasureWeights.FindByIdAsync(_measureSettings.BaseWeightId, false);

            if (measure != null)
            {
                to.MeasureUnitName = measure.GetLocalized(x => x.Name);
            }

            to.CheckoutAttributeInfo = HtmlUtils.ConvertPlainTextToTable(
                HtmlUtils.ConvertHtmlToPlainText(
                    await _checkoutAttributeFormatter.FormatAttributesAsync(customer.GenericAttributes.CheckoutAttributes, customer)));

            // Gift card and gift card boxes.
            to.DiscountBox.Display = _shoppingCartSettings.ShowDiscountBox;
            var discountCouponCode = customer.GenericAttributes.DiscountCouponCode;
            var discount           = await _db.Discounts
                                     .AsNoTracking()
                                     .Where(x => x.CouponCode == discountCouponCode)
                                     .FirstOrDefaultAsync();

            if (discount != null &&
                discount.RequiresCouponCode &&
                await _discountService.IsDiscountValidAsync(discount, customer))
            {
                to.DiscountBox.CurrentCode = discount.CouponCode;
            }

            to.GiftCardBox.Display = _shoppingCartSettings.ShowGiftCardBox;

            // Reward points.
            if (_rewardPointsSettings.Enabled && !from.IncludesMatchingItems(x => x.IsRecurring) && !customer.IsGuest())
            {
                var rewardPointsBalance    = customer.GetRewardPointsBalance();
                var rewardPointsAmountBase = _orderCalculationService.ConvertRewardPointsToAmount(rewardPointsBalance);
                var rewardPointsAmount     = _currencyService.ConvertFromPrimaryCurrency(rewardPointsAmountBase.Amount, currency);

                if (rewardPointsAmount > decimal.Zero)
                {
                    to.RewardPoints.DisplayRewardPoints = true;
                    to.RewardPoints.RewardPointsAmount  = rewardPointsAmount.ToString(true);
                    to.RewardPoints.RewardPointsBalance = rewardPointsBalance;
                    to.RewardPoints.UseRewardPoints     = customer.GenericAttributes.UseRewardPointsDuringCheckout;
                }
            }

            // Cart warnings.
            var warnings    = new List <string>();
            var cartIsValid = await _shoppingCartValidator.ValidateCartItemsAsync(from, warnings, validateCheckoutAttributes, customer.GenericAttributes.CheckoutAttributes);

            if (!cartIsValid)
            {
                to.Warnings.AddRange(warnings);
            }

            #endregion

            #region Checkout attributes

            var checkoutAttributes = await _checkoutAttributeMaterializer.GetValidCheckoutAttributesAsync(from);

            foreach (var attribute in checkoutAttributes)
            {
                var caModel = new ShoppingCartModel.CheckoutAttributeModel
                {
                    Id                   = attribute.Id,
                    Name                 = attribute.GetLocalized(x => x.Name),
                    TextPrompt           = attribute.GetLocalized(x => x.TextPrompt),
                    IsRequired           = attribute.IsRequired,
                    AttributeControlType = attribute.AttributeControlType
                };

                if (attribute.IsListTypeAttribute)
                {
                    var taxFormat = _currencyService.GetTaxFormat(null, null, PricingTarget.Product);
                    var caValues  = await _db.CheckoutAttributeValues
                                    .AsNoTracking()
                                    .Where(x => x.CheckoutAttributeId == attribute.Id)
                                    .ToListAsync();

                    // Prepare each attribute with image and price
                    foreach (var caValue in caValues)
                    {
                        var pvaValueModel = new ShoppingCartModel.CheckoutAttributeValueModel
                        {
                            Id            = caValue.Id,
                            Name          = caValue.GetLocalized(x => x.Name),
                            IsPreSelected = caValue.IsPreSelected,
                            Color         = caValue.Color
                        };

                        if (caValue.MediaFileId.HasValue && caValue.MediaFile != null)
                        {
                            pvaValueModel.ImageUrl = _mediaService.GetUrl(caValue.MediaFile, _mediaSettings.VariantValueThumbPictureSize, null, false);
                        }

                        caModel.Values.Add(pvaValueModel);

                        // Display price if allowed.
                        if (await _services.Permissions.AuthorizeAsync(Permissions.Catalog.DisplayPrice))
                        {
                            var priceAdjustmentBase = await _taxCalculator.CalculateCheckoutAttributeTaxAsync(caValue);

                            var priceAdjustment = _currencyService.ConvertFromPrimaryCurrency(priceAdjustmentBase.Price, currency);

                            if (priceAdjustment > 0)
                            {
                                pvaValueModel.PriceAdjustment = "+" + priceAdjustment.WithPostFormat(taxFormat).ToString();
                            }
                            else if (priceAdjustment < 0)
                            {
                                pvaValueModel.PriceAdjustment = "-" + (priceAdjustment * -1).WithPostFormat(taxFormat).ToString();
                            }
                        }
                    }
                }

                // Set already selected attributes.
                var selectedCheckoutAttributes = customer.GenericAttributes.CheckoutAttributes;
                switch (attribute.AttributeControlType)
                {
                case AttributeControlType.DropdownList:
                case AttributeControlType.RadioList:
                case AttributeControlType.Boxes:
                case AttributeControlType.Checkboxes:
                    if (selectedCheckoutAttributes.AttributesMap.Any())
                    {
                        // Clear default selection.
                        foreach (var item in caModel.Values)
                        {
                            item.IsPreSelected = false;
                        }

                        // Select new values.
                        var selectedCaValues = await _checkoutAttributeMaterializer.MaterializeCheckoutAttributeValuesAsync(selectedCheckoutAttributes);

                        foreach (var caValue in selectedCaValues)
                        {
                            foreach (var item in caModel.Values)
                            {
                                if (caValue.Id == item.Id)
                                {
                                    item.IsPreSelected = true;
                                }
                            }
                        }
                    }
                    break;

                case AttributeControlType.TextBox:
                case AttributeControlType.MultilineTextbox:
                    if (selectedCheckoutAttributes.AttributesMap.Any())
                    {
                        var enteredText = selectedCheckoutAttributes.GetAttributeValues(attribute.Id)?
                                          .Select(x => x.ToString())
                                          .FirstOrDefault();

                        if (enteredText.HasValue())
                        {
                            caModel.TextValue = enteredText;
                        }
                    }
                    break;

                case AttributeControlType.Datepicker:
                {
                    // Keep in mind my that the code below works only in the current culture.
                    var enteredDate = selectedCheckoutAttributes.AttributesMap
                                      .Where(x => x.Key == attribute.Id)
                                      .SelectMany(x => x.Value)
                                      .FirstOrDefault()
                                      .ToString();

                    if (enteredDate.HasValue() &&
                        DateTime.TryParseExact(enteredDate, "D", CultureInfo.CurrentCulture, DateTimeStyles.None, out var selectedDate))
                    {
                        caModel.SelectedDay   = selectedDate.Day;
                        caModel.SelectedMonth = selectedDate.Month;
                        caModel.SelectedYear  = selectedDate.Year;
                    }
                }
                break;

                case AttributeControlType.FileUpload:
                    if (selectedCheckoutAttributes.AttributesMap.Any())
                    {
                        var FileValue = selectedCheckoutAttributes.AttributesMap
                                        .Where(x => x.Key == attribute.Id)
                                        .Select(x => x.Value.ToString())
                                        .FirstOrDefault();

                        if (FileValue.HasValue() && caModel.UploadedFileGuid.HasValue() && Guid.TryParse(caModel.UploadedFileGuid, out var guid))
                        {
                            var download = await _db.Downloads
                                           .Include(x => x.MediaFile)
                                           .FirstOrDefaultAsync(x => x.DownloadGuid == guid);

                            if (download != null && !download.UseDownloadUrl && download.MediaFile != null)
                            {
                                caModel.UploadedFileName = download.MediaFile.Name;
                            }
                        }
                    }
                    break;

                default:
                    break;
                }

                to.CheckoutAttributes.Add(caModel);
            }

            #endregion

            #region Estimate shipping

            if (prepareEstimateShippingIfEnabled)
            {
                to.EstimateShipping.Enabled = _shippingSettings.EstimateShippingEnabled &&
                                              from.Any() &&
                                              from.IncludesMatchingItems(x => x.IsShippingEnabled);

                if (to.EstimateShipping.Enabled)
                {
                    // Countries.
                    var defaultEstimateCountryId = setEstimateShippingDefaultAddress && customer.ShippingAddress != null
                        ? customer.ShippingAddress.CountryId
                        : to.EstimateShipping.CountryId;

                    var countriesForShipping = await _db.Countries
                                               .AsNoTracking()
                                               .ApplyStoreFilter(store.Id)
                                               .Where(x => x.AllowsShipping)
                                               .ToListAsync();

                    foreach (var countries in countriesForShipping)
                    {
                        to.EstimateShipping.AvailableCountries.Add(new SelectListItem
                        {
                            Text     = countries.GetLocalized(x => x.Name),
                            Value    = countries.Id.ToString(),
                            Selected = countries.Id == defaultEstimateCountryId
                        });
                    }

                    // States.
                    var states = defaultEstimateCountryId.HasValue
                        ? await _db.StateProvinces.AsNoTracking().ApplyCountryFilter(defaultEstimateCountryId.Value).ToListAsync()
                        : new();

                    if (states.Any())
                    {
                        var defaultEstimateStateId = setEstimateShippingDefaultAddress && customer.ShippingAddress != null
                            ? customer.ShippingAddress.StateProvinceId
                            : to.EstimateShipping.StateProvinceId;

                        foreach (var s in states)
                        {
                            to.EstimateShipping.AvailableStates.Add(new SelectListItem
                            {
                                Text     = s.GetLocalized(x => x.Name),
                                Value    = s.Id.ToString(),
                                Selected = s.Id == defaultEstimateStateId
                            });
                        }
                    }
                    else
                    {
                        to.EstimateShipping.AvailableStates.Add(new SelectListItem {
                            Text = T("Address.OtherNonUS"), Value = "0"
                        });
                    }

                    if (setEstimateShippingDefaultAddress && customer.ShippingAddress != null)
                    {
                        to.EstimateShipping.ZipPostalCode = customer.ShippingAddress.ZipPostalCode;
                    }
                }
            }

            #endregion

            #region Cart items

            var allProducts = from
                              .Select(x => x.Item.Product)
                              .Union(from.Select(x => x.ChildItems).SelectMany(child => child.Select(x => x.Item.Product)))
                              .ToArray();

            var batchContext = _productService.CreateProductBatchContext(allProducts, null, customer, false);
            var subtotal     = await _orderCalculationService.GetShoppingCartSubtotalAsync(from.ToList(), null, batchContext);

            dynamic itemParameters = new ExpandoObject();
            itemParameters.TaxFormat    = _currencyService.GetTaxFormat();
            itemParameters.BatchContext = batchContext;
            itemParameters.CartSubtotal = subtotal;

            foreach (var cartItem in from)
            {
                var model = new ShoppingCartModel.ShoppingCartItemModel();

                await cartItem.MapAsync(model, (object)itemParameters);

                to.AddItems(model);
            }

            #endregion

            #region Order review data

            if (prepareAndDisplayOrderReviewData)
            {
                var checkoutState = _httpContextAccessor.HttpContext?.GetCheckoutState();

                to.OrderReviewData.Display = true;

                // Billing info.
                var billingAddress = customer.BillingAddress;
                if (billingAddress != null)
                {
                    await MapperFactory.MapAsync(billingAddress, to.OrderReviewData.BillingAddress);
                }

                // Shipping info.
                if (from.IsShippingRequired())
                {
                    to.OrderReviewData.IsShippable = true;

                    var shippingAddress = customer.ShippingAddress;
                    if (shippingAddress != null)
                    {
                        await MapperFactory.MapAsync(shippingAddress, to.OrderReviewData.ShippingAddress);
                    }

                    // Selected shipping method.
                    var shippingOption = customer.GenericAttributes.SelectedShippingOption;
                    if (shippingOption != null)
                    {
                        to.OrderReviewData.ShippingMethod = shippingOption.Name;
                    }

                    if (checkoutState != null && checkoutState.CustomProperties.ContainsKey("HasOnlyOneActiveShippingMethod"))
                    {
                        to.OrderReviewData.DisplayShippingMethodChangeOption = !(bool)checkoutState.CustomProperties.Get("HasOnlyOneActiveShippingMethod");
                    }
                }

                if (checkoutState != null && checkoutState.CustomProperties.ContainsKey("HasOnlyOneActivePaymentMethod"))
                {
                    to.OrderReviewData.DisplayPaymentMethodChangeOption = !(bool)checkoutState.CustomProperties.Get("HasOnlyOneActivePaymentMethod");
                }

                var selectedPaymentMethodSystemName = customer.GenericAttributes.SelectedPaymentMethod;
                var paymentMethod = await _paymentService.LoadPaymentMethodBySystemNameAsync(selectedPaymentMethodSystemName);

                // TODO: (ms) (core) Wait for PluginMediator.GetLocalizedFriendlyName implementation
                //model.OrderReviewData.PaymentMethod = paymentMethod != null ? _pluginMediator.GetLocalizedFriendlyName(paymentMethod.Metadata) : "";
                to.OrderReviewData.PaymentSummary            = checkoutState.PaymentSummary;
                to.OrderReviewData.IsPaymentSelectionSkipped = checkoutState.IsPaymentSelectionSkipped;
            }

            #endregion

            var paymentTypes        = new PaymentMethodType[] { PaymentMethodType.Button, PaymentMethodType.StandardAndButton };
            var boundPaymentMethods = await _paymentService.LoadActivePaymentMethodsAsync(
                customer,
                from.ToList(),
                store.Id,
                paymentTypes,
                false);

            var bpmModel = new ButtonPaymentMethodModel();

            foreach (var boundPaymentMethod in boundPaymentMethods)
            {
                if (from.IncludesMatchingItems(x => x.IsRecurring) && boundPaymentMethod.Value.RecurringPaymentType == RecurringPaymentType.NotSupported)
                {
                    continue;
                }

                var widgetInvoker = boundPaymentMethod.Value.GetPaymentInfoWidget();
                bpmModel.Items.Add(widgetInvoker);
            }

            to.ButtonPaymentMethods = bpmModel;
        }