示例#1
0
        public async Task HandleEventAsync(ValidatingCartEvent message)
        {
            // Order total validation.
            var roleMappings = _workContext.CurrentImpersonator?.CustomerRoleMappings ?? message.Customer.CustomerRoleMappings;
            var result       = await _orderProcessingService.ValidateOrderTotalAsync(message.Cart, roleMappings.Select(x => x.CustomerRole).ToArray());

            if (!result.IsAboveMinimum)
            {
                var convertedMin = _currencyService.ConvertFromPrimaryCurrency(result.OrderTotalMinimum, _workContext.WorkingCurrency);

                message.Warnings.Add(_localizationService.GetResource("Checkout.MinOrderSubtotalAmount").FormatInvariant(convertedMin.ToString(true)));
            }

            if (!result.IsBelowMaximum)
            {
                var convertedMax = _currencyService.ConvertFromPrimaryCurrency(result.OrderTotalMaximum, _workContext.WorkingCurrency);

                message.Warnings.Add(_localizationService.GetResource("Checkout.MaxOrderSubtotalAmount").FormatInvariant(convertedMax.ToString(true)));
            }
        }
        public async Task <IViewComponentResult> InvokeAsync(bool isEditable = false)
        {
            var orderTotalsEvent = new RenderingOrderTotalsEvent();
            await Services.EventPublisher.PublishAsync(orderTotalsEvent);

            var currency = Services.WorkContext.WorkingCurrency;
            var customer = orderTotalsEvent.Customer ?? Services.WorkContext.CurrentCustomer;
            var storeId  = orderTotalsEvent.StoreId ?? Services.StoreContext.CurrentStore.Id;

            var cart = await _shoppingCartService.GetCartItemsAsync(customer, ShoppingCartType.ShoppingCart, storeId);

            var model = new OrderTotalsModel
            {
                IsEditable = isEditable
            };

            if (!cart.Any())
            {
                return(View(model));
            }

            model.Weight = decimal.Zero;

            foreach (var cartItem in cart)
            {
                model.Weight += cartItem.Item.Product.Weight * cartItem.Item.Quantity;
            }

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

            if (measureWeight != null)
            {
                model.WeightMeasureUnitName = measureWeight.GetLocalized(x => x.Name);
            }

            // SubTotal
            var cartSubTotal = await _orderCalculationService.GetShoppingCartSubtotalAsync(cart);

            var subTotalConverted = _currencyService.ConvertFromPrimaryCurrency(cartSubTotal.SubtotalWithoutDiscount.Amount, currency);

            model.SubTotal = subTotalConverted;

            if (cartSubTotal.DiscountAmount > decimal.Zero)
            {
                var subTotalDiscountAmountConverted = _currencyService.ConvertFromPrimaryCurrency(cartSubTotal.DiscountAmount.Amount, currency);

                model.SubTotalDiscount = subTotalDiscountAmountConverted * -1;
                model.AllowRemovingSubTotalDiscount = cartSubTotal.AppliedDiscount != null &&
                                                      cartSubTotal.AppliedDiscount.RequiresCouponCode &&
                                                      cartSubTotal.AppliedDiscount.CouponCode.HasValue() &&
                                                      model.IsEditable;
            }

            // Shipping info
            // TODO: (ms) (core) Re-implement when any payment method has been implemented
            model.RequiresShipping = false;// cart.IsShippingRequired();
            if (model.RequiresShipping)
            {
                var shippingTotal = await _orderCalculationService.GetShoppingCartShippingTotalAsync(cart);

                if (shippingTotal.ShippingTotal.HasValue)
                {
                    var shippingTotalConverted = _currencyService.ConvertFromPrimaryCurrency(shippingTotal.ShippingTotal.Value.Amount, currency);
                    model.Shipping = shippingTotalConverted.ToString();

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

            // Payment method fee
            var paymentFee = await _orderCalculationService.GetShoppingCartPaymentFeeAsync(cart, customer.GenericAttributes.SelectedPaymentMethod);

            var paymentFeeTax = await _taxCalculator.CalculatePaymentFeeTaxAsync(paymentFee.Amount, customer : customer);

            if (paymentFeeTax.Price != 0m)
            {
                var convertedPaymentFeeTax = _currencyService.ConvertFromPrimaryCurrency(paymentFeeTax.Price, currency);
                model.PaymentMethodAdditionalFee = convertedPaymentFeeTax;
            }

            // Tax
            var displayTax      = true;
            var displayTaxRates = true;

            if (_taxSettings.HideTaxInOrderSummary && Services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax)
            {
                displayTax      = false;
                displayTaxRates = false;
            }
            else
            {
                (Money Price, TaxRatesDictionary TaxRates)cartTaxBase = (new Money(1.19m, currency), new TaxRatesDictionary()); //await _orderCalculationService.GetShoppingCartTaxTotalAsync(cart);
                var cartTax = _currencyService.ConvertFromPrimaryCurrency(cartTaxBase.Price.Amount, currency);

                if (cartTaxBase.Price == decimal.Zero && _taxSettings.HideZeroTax)
                {
                    displayTax      = false;
                    displayTaxRates = false;
                }
                else
                {
                    displayTaxRates = _taxSettings.DisplayTaxRates && cartTaxBase.TaxRates.Count > 0;
                    displayTax      = !displayTaxRates;
                    model.Tax       = cartTax.ToString(true);

                    foreach (var taxRate in cartTaxBase.TaxRates)
                    {
                        var rate     = _taxService.FormatTaxRate(taxRate.Key);
                        var labelKey = "ShoppingCart.Totals.TaxRateLine" + (Services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax ? "Incl" : "Excl");
                        model.TaxRates.Add(new OrderTotalsModel.TaxRate
                        {
                            Rate  = rate,
                            Value = _currencyService.ConvertFromPrimaryCurrency(taxRate.Value, currency),
                            Label = _localizationService.GetResource(labelKey).FormatCurrent(rate)
                        });
                    }
                }
            }

            model.DisplayTaxRates = displayTaxRates;
            model.DisplayTax      = displayTax;

            model.DisplayWeight             = _shoppingCartSettings.ShowWeight;
            model.ShowConfirmOrderLegalHint = _shoppingCartSettings.ShowConfirmOrderLegalHint;

            // Cart total
            // TODO: (ms) (core) Re-implement when any payment method has been implemented
            //var cartTotal = await _orderCalculationService.GetShoppingCartTotalAsync(cart);

            var cartTotal = new ShoppingCartTotal
            {
                Total                      = new(decimal.Zero, currency),
                ToNearestRounding          = new(decimal.Zero, currency),
                DiscountAmount             = new(15, currency),
                AppliedDiscount            = (await _db.Discounts.FirstOrDefaultAsync()) ?? new(),
                RedeemedRewardPoints       = 10,
                RedeemedRewardPointsAmount = new(10, currency),
                CreditBalance              = new(decimal.Zero, currency),
                AppliedGiftCards           = new() { new() { GiftCard = (await _db.GiftCards.Include(x => x.GiftCardUsageHistory).FirstOrDefaultAsync()) ?? new(), UsableAmount = new(50m, _currencyService.PrimaryCurrency) } },
                ConvertedAmount            = new ShoppingCartTotal.ConvertedAmounts
                {
                    Total             = new(decimal.Zero, currency),
                    ToNearestRounding = new(decimal.Zero, currency)
                }
            };

            if (cartTotal.ConvertedAmount.Total.HasValue)
            {
                model.OrderTotal = cartTotal.ConvertedAmount.Total.Value;
                if (cartTotal.ConvertedAmount.ToNearestRounding != decimal.Zero)
                {
                    model.OrderTotalRounding = cartTotal.ConvertedAmount.ToNearestRounding;
                }
            }

            // Discount
            if (cartTotal.DiscountAmount > decimal.Zero)
            {
                var orderTotalDiscountAmount = _currencyService.ConvertFromPrimaryCurrency(cartTotal.DiscountAmount.Amount, currency);
                model.OrderTotalDiscount = orderTotalDiscountAmount * -1;
                model.AllowRemovingOrderTotalDiscount = cartTotal.AppliedDiscount != null &&
                                                        cartTotal.AppliedDiscount.RequiresCouponCode &&
                                                        cartTotal.AppliedDiscount.CouponCode.HasValue() &&
                                                        model.IsEditable;
            }

            // Gift cards
            if (!cartTotal.AppliedGiftCards.IsNullOrEmpty())
            {
                foreach (var appliedGiftCard in cartTotal.AppliedGiftCards)
                {
                    if (appliedGiftCard?.GiftCard == null)
                    {
                        continue;
                    }

                    var gcModel = new OrderTotalsModel.GiftCard
                    {
                        Id         = appliedGiftCard.GiftCard.Id,
                        CouponCode = appliedGiftCard.GiftCard.GiftCardCouponCode,
                    };

                    var amountCanBeUsed = _currencyService.ConvertFromPrimaryCurrency(appliedGiftCard.UsableAmount.Amount, currency);
                    gcModel.Amount = amountCanBeUsed * -1;

                    var remainingAmountBase = _giftCardService.GetRemainingAmount(appliedGiftCard.GiftCard) - appliedGiftCard.UsableAmount;
                    var remainingAmount     = _currencyService.ConvertFromPrimaryCurrency(remainingAmountBase.Amount, currency);
                    gcModel.Remaining = remainingAmount;

                    model.GiftCards.Add(gcModel);
                }
            }

            // Reward points
            if (cartTotal.RedeemedRewardPointsAmount > decimal.Zero)
            {
                var redeemedRewardPointsAmountInCustomerCurrency = _currencyService.ConvertFromPrimaryCurrency(cartTotal.RedeemedRewardPointsAmount.Amount, currency);
                model.RedeemedRewardPoints       = cartTotal.RedeemedRewardPoints;
                model.RedeemedRewardPointsAmount = (redeemedRewardPointsAmountInCustomerCurrency * -1).ToString(true);
            }

            // Credit balance.
            if (cartTotal.CreditBalance > decimal.Zero)
            {
                var convertedCreditBalance = _currencyService.ConvertFromPrimaryCurrency(cartTotal.CreditBalance.Amount, currency);
                model.CreditBalance = (convertedCreditBalance * -1).ToString(true);
            }

            return(View(model));
        }
        private async Task <CalculatedPrice> CreateCalculatedPrice(CalculatorContext context, Product product = null, int subtotalQuantity = 1)
        {
            product ??= context.Product;

            var options = context.Options;

            // Calculate the subtotal price instead of the unit price.
            if (subtotalQuantity > 1 && context.FinalPrice > 0)
            {
                context.FinalPrice     = options.RoundingCurrency.RoundIfEnabledFor(context.FinalPrice) * subtotalQuantity;
                context.DiscountAmount = options.RoundingCurrency.RoundIfEnabledFor(context.DiscountAmount) * subtotalQuantity;
            }

            // Determine tax rate for product.
            var taxRate = await _taxService.GetTaxRateAsync(product, null, options.Customer);

            // Prepare result by converting price amounts.
            var result = new CalculatedPrice(context)
            {
                Product          = product,
                RegularPrice     = ConvertAmount(context.RegularPrice, context, taxRate, false, out _).Value,
                OfferPrice       = ConvertAmount(context.OfferPrice, context, taxRate, false, out _),
                PreselectedPrice = ConvertAmount(context.PreselectedPrice, context, taxRate, false, out _),
                LowestPrice      = ConvertAmount(context.LowestPrice, context, taxRate, false, out _),
                DiscountAmount   = ConvertAmount(context.DiscountAmount, context, taxRate, false, out _).Value,
                FinalPrice       = ConvertAmount(context.FinalPrice, context, taxRate, true, out var tax).Value,
                Tax = tax
            };

            if (tax.HasValue && _primaryCurrency != options.TargetCurrency)
            {
                // Exchange tax amounts.
                // TODO: (mg) (core) Check for rounding issues thoroughly!
                result.Tax = new Tax(
                    tax.Value.Rate,
                    // Amount
                    _currencyService.ConvertFromPrimaryCurrency(tax.Value.Amount, options.TargetCurrency).Amount,
                    // Price
                    result.FinalPrice.Amount,
                    tax.Value.IsGrossPrice,
                    tax.Value.Inclusive);
            }

            // Convert attribute price adjustments.
            context.AttributePriceAdjustments.Each(x => x.Price = ConvertAmount(x.RawPriceAdjustment, context, taxRate, false, out _).Value);

            // Calculate price saving.
            // The final price without discounts has priority over the old price.
            // This avoids differing percentage discount in product lists and detail page.
            var priceWithoutDiscount = result.FinalPrice + result.DiscountAmount;

            var savingPrice = result.FinalPrice < priceWithoutDiscount
                ? priceWithoutDiscount
                : ConvertAmount(product.OldPrice, context, taxRate, false, out _).Value;

            var hasSaving = savingPrice > 0 && result.FinalPrice < savingPrice;

            result.PriceSaving = new PriceSaving
            {
                HasSaving     = hasSaving,
                SavingPrice   = savingPrice,
                SavingPercent = hasSaving ? (float)((savingPrice - result.FinalPrice) / savingPrice) * 100 : 0f,
                SavingAmount  = hasSaving ? (savingPrice - result.FinalPrice).WithPostFormat(null) : null
            };

            return(result);
        }
示例#4
0
        private async Task <WishlistModel.ShoppingCartItemModel> PrepareWishlistCartItemModelAsync(OrganizedShoppingCartItem cartItem)
        {
            Guard.NotNull(cartItem, nameof(cartItem));

            var item     = cartItem.Item;
            var product  = item.Product;
            var customer = item.Customer;
            var currency = Services.WorkContext.WorkingCurrency;

            await _productAttributeMaterializer.MergeWithCombinationAsync(product, item.AttributeSelection);

            var productSeName = await SeoExtensions.GetActiveSlugAsync(product);

            var model = new WishlistModel.ShoppingCartItemModel
            {
                Id                  = item.Id,
                Sku                 = product.Sku,
                ProductId           = product.Id,
                ProductName         = product.GetLocalized(x => x.Name),
                ProductSeName       = productSeName,
                ProductUrl          = await _productUrlHelper.GetProductUrlAsync(productSeName, cartItem),
                EnteredQuantity     = item.Quantity,
                MinOrderAmount      = product.OrderMinimumQuantity,
                MaxOrderAmount      = product.OrderMaximumQuantity,
                QuantityStep        = product.QuantityStep > 0 ? product.QuantityStep : 1,
                ShortDesc           = product.GetLocalized(x => x.ShortDescription),
                ProductType         = product.ProductType,
                VisibleIndividually = product.Visibility != ProductVisibility.Hidden,
                CreatedOnUtc        = item.UpdatedOnUtc,
                DisableBuyButton    = product.DisableBuyButton,
            };

            if (item.BundleItem != null)
            {
                model.BundleItem.Id             = item.BundleItem.Id;
                model.BundleItem.DisplayOrder   = item.BundleItem.DisplayOrder;
                model.BundleItem.HideThumbnail  = item.BundleItem.HideThumbnail;
                model.BundlePerItemPricing      = item.BundleItem.BundleProduct.BundlePerItemPricing;
                model.BundlePerItemShoppingCart = item.BundleItem.BundleProduct.BundlePerItemShoppingCart;
                model.AttributeInfo             = await _productAttributeFormatter.FormatAttributesAsync(item.AttributeSelection, product, customer,
                                                                                                         includePrices : false, includeGiftCardAttributes : false, includeHyperlinks : false);

                var bundleItemName = item.BundleItem.GetLocalized(x => x.Name);
                if (bundleItemName.HasValue())
                {
                    model.ProductName = bundleItemName;
                }

                var bundleItemShortDescription = item.BundleItem.GetLocalized(x => x.ShortDescription);
                if (bundleItemShortDescription.HasValue())
                {
                    model.ShortDesc = bundleItemShortDescription;
                }

                if (model.BundlePerItemPricing && model.BundlePerItemShoppingCart)
                {
                    (var bundleItemPriceBase, var bundleItemTaxRate) = await _taxService.GetProductPriceAsync(product, await _priceCalculationService.GetSubTotalAsync(cartItem, true));

                    var bundleItemPrice = _currencyService.ConvertFromPrimaryCurrency(bundleItemPriceBase.Amount, currency);
                    model.BundleItem.PriceWithDiscount = bundleItemPrice.ToString();
                }
            }
            else
            {
                model.AttributeInfo = await _productAttributeFormatter.FormatAttributesAsync(item.AttributeSelection, product, customer);
            }

            var allowedQuantities = product.ParseAllowedQuantities();

            foreach (var qty in allowedQuantities)
            {
                model.AllowedQuantities.Add(new SelectListItem
                {
                    Text     = qty.ToString(),
                    Value    = qty.ToString(),
                    Selected = item.Quantity == qty
                });
            }

            var quantityUnit = await _db.QuantityUnits.FindByIdAsync(product.QuantityUnitId ?? 0);

            if (quantityUnit != null)
            {
                model.QuantityUnitName = quantityUnit.GetLocalized(x => x.Name);
            }

            if (product.IsRecurring)
            {
                model.RecurringInfo = string.Format(T("ShoppingCart.RecurringPeriod"),
                                                    product.RecurringCycleLength, product.RecurringCyclePeriod.GetLocalizedEnum());
            }

            if (product.CallForPrice)
            {
                model.UnitPrice = T("Products.CallForPrice");
            }
            else
            {
                var unitPriceWithDiscount = await _priceCalculationService.GetUnitPriceAsync(cartItem, true);

                var unitPriceBaseWithDiscount = await _taxService.GetProductPriceAsync(product, unitPriceWithDiscount);

                unitPriceWithDiscount = _currencyService.ConvertFromPrimaryCurrency(unitPriceBaseWithDiscount.Price.Amount, currency);

                model.UnitPrice = unitPriceWithDiscount.ToString();
            }

            // Subtotal and discount.
            if (product.CallForPrice)
            {
                model.SubTotal = T("Products.CallForPrice");
            }
            else
            {
                var cartItemSubTotalWithDiscount = await _priceCalculationService.GetSubTotalAsync(cartItem, true);

                var cartItemSubTotalWithDiscountBase = await _taxService.GetProductPriceAsync(product, cartItemSubTotalWithDiscount);

                cartItemSubTotalWithDiscount = _currencyService.ConvertFromPrimaryCurrency(cartItemSubTotalWithDiscountBase.Price.Amount, currency);

                model.SubTotal = cartItemSubTotalWithDiscount.ToString();

                // Display an applied discount amount.
                var cartItemSubTotalWithoutDiscount = await _priceCalculationService.GetSubTotalAsync(cartItem, false);

                var cartItemSubTotalWithoutDiscountBase = await _taxService.GetProductPriceAsync(product, cartItemSubTotalWithoutDiscount);

                var cartItemSubTotalDiscountBase = cartItemSubTotalWithoutDiscountBase.Price - cartItemSubTotalWithDiscountBase.Price;

                if (cartItemSubTotalDiscountBase > decimal.Zero)
                {
                    var shoppingCartItemDiscount = _currencyService.ConvertFromPrimaryCurrency(cartItemSubTotalDiscountBase.Amount, currency);
                    model.Discount = shoppingCartItemDiscount.ToString();
                }
            }

            if (item.BundleItem != null)
            {
                if (_shoppingCartSettings.ShowProductBundleImagesOnShoppingCart)
                {
                    model.Image = await PrepareCartItemPictureModelAsync(product, _mediaSettings.CartThumbBundleItemPictureSize, model.ProductName, item.AttributeSelection);
                }
            }
            else
            {
                if (_shoppingCartSettings.ShowProductImagesOnShoppingCart)
                {
                    model.Image = await PrepareCartItemPictureModelAsync(product, _mediaSettings.CartThumbPictureSize, model.ProductName, item.AttributeSelection);
                }
            }

            var itemWarnings = new List <string>();
            var itemIsValid  = await _shoppingCartValidator.ValidateCartAsync(new List <OrganizedShoppingCartItem> {
                cartItem
            }, itemWarnings);

            if (!itemIsValid)
            {
                model.Warnings.AddRange(itemWarnings);
            }

            if (cartItem.ChildItems != null)
            {
                foreach (var childItem in cartItem.ChildItems.Where(x => x.Item.Id != item.Id))
                {
                    var childModel = await PrepareWishlistCartItemModelAsync(childItem);

                    model.ChildItems.Add(childModel);
                }
            }

            return(model);
        }
示例#5
0
        private async Task <OrderDetailsModel.OrderItemModel> PrepareOrderItemModelAsync(
            Order order,
            OrderItem orderItem,
            CatalogSettings catalogSettings,
            ShoppingCartSettings shoppingCartSettings,
            MediaSettings mediaSettings,
            Currency customerCurrency)
        {
            var language = _services.WorkContext.WorkingLanguage;

            var attributeCombination = await _productAttributeMaterializer.FindAttributeCombinationAsync(orderItem.ProductId, orderItem.AttributeSelection);

            if (attributeCombination != null)
            {
                orderItem.Product.MergeWithCombination(attributeCombination);
            }

            var model = new OrderDetailsModel.OrderItemModel
            {
                Id            = orderItem.Id,
                Sku           = orderItem.Product.Sku,
                ProductId     = orderItem.Product.Id,
                ProductName   = orderItem.Product.GetLocalized(x => x.Name),
                ProductSeName = await orderItem.Product.GetActiveSlugAsync(),
                ProductType   = orderItem.Product.ProductType,
                Quantity      = orderItem.Quantity,
                AttributeInfo = orderItem.AttributeDescription
            };

            var quantityUnit = await _db.QuantityUnits.FindByIdAsync(orderItem.Product.QuantityUnitId ?? 0, false);

            model.QuantityUnit = quantityUnit == null ? string.Empty : quantityUnit.GetLocalized(x => x.Name);

            if (orderItem.Product.ProductType == ProductType.BundledProduct && orderItem.BundleData.HasValue())
            {
                var bundleData = orderItem.GetBundleData();

                var bundleProducts = await _db.ProductBundleItem
                                     .AsNoTracking()
                                     .Include(x => x.Product)
                                     .ApplyBundledProductsFilter(new int[] { orderItem.ProductId })
                                     .Select(x => new ProductBundleItemData(x))
                                     .ToListAsync();

                var bundleItems = shoppingCartSettings.ShowProductBundleImagesOnShoppingCart
                    ? bundleProducts.ToDictionarySafe(x => x.Item.ProductId)
                    : new Dictionary <int, ProductBundleItemData>();

                model.BundlePerItemPricing      = orderItem.Product.BundlePerItemPricing;
                model.BundlePerItemShoppingCart = bundleData.Any(x => x.PerItemShoppingCart);

                foreach (var bid in bundleData)
                {
                    var bundleItemModel = new OrderDetailsModel.BundleItemModel
                    {
                        Sku                 = bid.Sku,
                        ProductName         = bid.ProductName,
                        ProductSeName       = bid.ProductSeName,
                        VisibleIndividually = bid.VisibleIndividually,
                        Quantity            = bid.Quantity,
                        DisplayOrder        = bid.DisplayOrder,
                        AttributeInfo       = bid.AttributesInfo
                    };

                    bundleItemModel.ProductUrl = await _productUrlHelper.GetProductUrlAsync(bid.ProductId, bundleItemModel.ProductSeName, bid.AttributeSelection);

                    if (model.BundlePerItemShoppingCart)
                    {
                        var priceWithDiscount = _currencyService.ConvertFromPrimaryCurrency(bid.PriceWithDiscount, customerCurrency);
                        //bundleItemModel.PriceWithDiscount = _priceFormatter.FormatPrice(priceWithDiscount, true, order.CustomerCurrencyCode, language, false, false);
                        bundleItemModel.PriceWithDiscount = priceWithDiscount.ToString();
                    }

                    // Bundle item picture.
                    if (shoppingCartSettings.ShowProductBundleImagesOnShoppingCart && bundleItems.TryGetValue(bid.ProductId, out var bundleItem))
                    {
                        bundleItemModel.HideThumbnail = bundleItem.Item.HideThumbnail;

                        bundleItemModel.Image = await PrepareOrderItemImageModelAsync(
                            bundleItem.Item.Product,
                            mediaSettings.CartThumbBundleItemPictureSize,
                            bid.ProductName,
                            bid.AttributeSelection,
                            catalogSettings);
                    }

                    model.BundleItems.Add(bundleItemModel);
                }
            }

            // Unit price, subtotal.
            switch (order.CustomerTaxDisplayType)
            {
            case TaxDisplayType.ExcludingTax:
            {
                var unitPriceExclTaxInCustomerCurrency = _currencyService.ConvertFromPrimaryCurrency(orderItem.UnitPriceExclTax, customerCurrency);
                //model.UnitPrice = _priceFormatter.FormatPrice(unitPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, language, false, false);
                model.UnitPrice = unitPriceExclTaxInCustomerCurrency.ToString();

                var priceExclTaxInCustomerCurrency = _currencyService.ConvertFromPrimaryCurrency(orderItem.PriceExclTax, customerCurrency);
                //model.SubTotal = _priceFormatter.FormatPrice(priceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, language, false, false);
                model.SubTotal = priceExclTaxInCustomerCurrency.ToString();
            }
            break;

            case TaxDisplayType.IncludingTax:
            {
                var unitPriceInclTaxInCustomerCurrency = _currencyService.ConvertFromPrimaryCurrency(orderItem.UnitPriceInclTax, customerCurrency);
                //model.UnitPrice = _priceFormatter.FormatPrice(unitPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, language, true, false);
                model.UnitPrice = unitPriceInclTaxInCustomerCurrency.ToString();

                var priceInclTaxInCustomerCurrency = _currencyService.ConvertFromPrimaryCurrency(orderItem.PriceInclTax, customerCurrency);
                //model.SubTotal = _priceFormatter.FormatPrice(priceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, language, true, false);
                model.SubTotal = priceInclTaxInCustomerCurrency.ToString();
            }
            break;
            }

            model.ProductUrl = await _productUrlHelper.GetProductUrlAsync(orderItem.ProductId, model.ProductSeName, orderItem.AttributeSelection);

            if (shoppingCartSettings.ShowProductImagesOnShoppingCart)
            {
                model.Image = await PrepareOrderItemImageModelAsync(
                    orderItem.Product,
                    mediaSettings.CartThumbPictureSize,
                    model.ProductName,
                    orderItem.AttributeSelection,
                    catalogSettings);
            }

            return(model);
        }
示例#6
0
        public override async Task MapAsync(IEnumerable <OrganizedShoppingCartItem> from, MiniShoppingCartModel to, dynamic parameters = null)
        {
            Guard.NotNull(from, nameof(from));
            Guard.NotNull(to, nameof(to));

            var customer = _services.WorkContext.CurrentCustomer;

            to.ShowProductImages           = _shoppingCartSettings.ShowProductImagesInMiniShoppingCart;
            to.ThumbSize                   = _mediaSettings.MiniCartThumbPictureSize;
            to.CurrentCustomerIsGuest      = customer.IsGuest();
            to.AnonymousCheckoutAllowed    = _orderSettings.AnonymousCheckoutAllowed;
            to.DisplayMoveToWishlistButton = await _services.Permissions.AuthorizeAsync(Permissions.Cart.AccessWishlist);

            to.ShowBasePrice = _shoppingCartSettings.ShowBasePrice;
            to.TotalProducts = from.GetTotalQuantity();

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

            var taxFormat    = _currencyService.GetTaxFormat();
            var batchContext = _productService.CreateProductBatchContext(from.Select(x => x.Item.Product).ToArray(), null, customer, false);

            var subtotal = await _orderCalculationService.GetShoppingCartSubtotalAsync(from.ToList(), null, batchContext);

            var lineItems = subtotal.LineItems.ToDictionarySafe(x => x.Item.Item.Id);

            var currency = _services.WorkContext.WorkingCurrency;
            var subtotalWithoutDiscount = _currencyService.ConvertFromPrimaryCurrency(subtotal.SubtotalWithoutDiscount.Amount, currency);

            to.SubTotal = subtotalWithoutDiscount.WithPostFormat(taxFormat);

            // A customer should visit the shopping cart page before going to checkout if:
            //1. There is at least one checkout attribute that is reqired
            //2. Min order sub total is OK

            var checkoutAttributes = await _checkoutAttributeMaterializer.GetValidCheckoutAttributesAsync(from);

            to.DisplayCheckoutButton = !checkoutAttributes.Any(x => x.IsRequired);

            // Products sort descending (recently added products)
            foreach (var cartItem in from)
            {
                var item          = cartItem.Item;
                var product       = cartItem.Item.Product;
                var productSeName = await product.GetActiveSlugAsync();

                var cartItemModel = new MiniShoppingCartModel.ShoppingCartItemModel
                {
                    Id               = item.Id,
                    ProductId        = product.Id,
                    ProductName      = product.GetLocalized(x => x.Name),
                    ShortDesc        = product.GetLocalized(x => x.ShortDescription),
                    ProductSeName    = productSeName,
                    EnteredQuantity  = item.Quantity,
                    MaxOrderAmount   = product.OrderMaximumQuantity,
                    MinOrderAmount   = product.OrderMinimumQuantity,
                    QuantityStep     = product.QuantityStep > 0 ? product.QuantityStep : 1,
                    CreatedOnUtc     = item.UpdatedOnUtc,
                    ProductUrl       = await _productUrlHelper.GetProductUrlAsync(productSeName, cartItem),
                    QuantityUnitName = null,
                    AttributeInfo    = await _productAttributeFormatter.FormatAttributesAsync(
                        item.AttributeSelection,
                        product,
                        null,
                        ", ",
                        includePrices : false,
                        includeGiftCardAttributes : false,
                        includeHyperlinks : false,
                        batchContext : batchContext)
                };

                if (cartItem.ChildItems != null && _shoppingCartSettings.ShowProductBundleImagesOnShoppingCart)
                {
                    var bundleItems = cartItem.ChildItems.Where(x =>
                                                                x.Item.Id != item.Id &&
                                                                x.Item.BundleItem != null &&
                                                                !x.Item.BundleItem.HideThumbnail);

                    foreach (var bundleItem in bundleItems)
                    {
                        var bundleItemModel = new MiniShoppingCartModel.ShoppingCartItemBundleItem
                        {
                            ProductName   = bundleItem.Item.Product.GetLocalized(x => x.Name),
                            ProductSeName = await bundleItem.Item.Product.GetActiveSlugAsync(),
                        };

                        bundleItemModel.ProductUrl = await _productUrlHelper.GetProductUrlAsync(
                            bundleItem.Item.ProductId,
                            bundleItemModel.ProductSeName,
                            bundleItem.Item.AttributeSelection);

                        var file = await _db.ProductMediaFiles
                                   .AsNoTracking()
                                   .Include(x => x.MediaFile)
                                   .ApplyProductFilter(bundleItem.Item.ProductId)
                                   .FirstOrDefaultAsync();

                        if (file?.MediaFile != null)
                        {
                            var fileInfo = await _mediaService.GetFileByIdAsync(file.MediaFileId, MediaLoadFlags.AsNoTracking);

                            bundleItemModel.ImageModel = new ImageModel
                            {
                                File       = fileInfo,
                                ThumbSize  = MediaSettings.ThumbnailSizeXxs,
                                Title      = file.MediaFile.GetLocalized(x => x.Title)?.Value.NullEmpty() ?? T("Media.Manufacturer.ImageLinkTitleFormat", bundleItemModel.ProductName),
                                Alt        = file.MediaFile.GetLocalized(x => x.Alt)?.Value.NullEmpty() ?? T("Media.Manufacturer.ImageAlternateTextFormat", bundleItemModel.ProductName),
                                NoFallback = _catalogSettings.HideProductDefaultPictures,
                            };
                        }

                        cartItemModel.BundleItems.Add(bundleItemModel);
                    }
                }

                // Unit prices.
                if (product.CallForPrice)
                {
                    cartItemModel.UnitPrice = T("Products.CallForPrice");
                }
                else if (lineItems.TryGetValue(item.Id, out var lineItem))
                {
                    var unitPrice = _currencyService.ConvertFromPrimaryCurrency(lineItem.UnitPrice.FinalPrice.Amount, currency);
                    cartItemModel.UnitPrice = unitPrice.WithPostFormat(taxFormat).ToString(true);

                    if (unitPrice != 0 && to.ShowBasePrice)
                    {
                        cartItemModel.BasePriceInfo = _priceCalculationService.GetBasePriceInfo(item.Product, unitPrice, currency);
                    }
                }

                // Image.
                if (_shoppingCartSettings.ShowProductImagesInMiniShoppingCart)
                {
                    await cartItem.MapAsync(cartItemModel.Image, _mediaSettings.MiniCartThumbPictureSize, cartItemModel.ProductName);
                }

                to.Items.Add(cartItemModel);
            }
        }
示例#7
0
        public override async Task MapAsync(OrganizedShoppingCartItem from, TModel to, dynamic parameters = null)
        {
            Guard.NotNull(from, nameof(from));

            // TODO: (ms) (core) Be certain that product is null if it is removed from cart.
            if (from.Item.Product == null)
            {
                return;
            }

            var item             = from.Item;
            var product          = from.Item.Product;
            var customer         = item.Customer;
            var currency         = _services.WorkContext.WorkingCurrency;
            var shoppingCartType = item.ShoppingCartType;

            await _productAttributeMaterializer.MergeWithCombinationAsync(product, item.AttributeSelection);

            var productSeName = await product.GetActiveSlugAsync();

            // General model data
            to.Id            = item.Id;
            to.Sku           = product.Sku;
            to.ProductId     = product.Id;
            to.ProductName   = product.GetLocalized(x => x.Name);
            to.ProductSeName = productSeName;
            to.ProductUrl    = await _productUrlHelper.GetProductUrlAsync(productSeName, from);

            to.EnteredQuantity     = item.Quantity;
            to.MinOrderAmount      = product.OrderMinimumQuantity;
            to.MaxOrderAmount      = product.OrderMaximumQuantity;
            to.QuantityStep        = product.QuantityStep > 0 ? product.QuantityStep : 1;
            to.ShortDesc           = product.GetLocalized(x => x.ShortDescription);
            to.ProductType         = product.ProductType;
            to.VisibleIndividually = product.Visibility != ProductVisibility.Hidden;
            to.CreatedOnUtc        = item.UpdatedOnUtc;

            if (item.BundleItem != null)
            {
                to.BundleItem.Id             = item.BundleItem.Id;
                to.BundleItem.DisplayOrder   = item.BundleItem.DisplayOrder;
                to.BundleItem.HideThumbnail  = item.BundleItem.HideThumbnail;
                to.BundlePerItemPricing      = item.BundleItem.BundleProduct.BundlePerItemPricing;
                to.BundlePerItemShoppingCart = item.BundleItem.BundleProduct.BundlePerItemShoppingCart;
                to.AttributeInfo             = await _productAttributeFormatter.FormatAttributesAsync(
                    item.AttributeSelection,
                    product,
                    customer,
                    includePrices : false,
                    includeGiftCardAttributes : true,
                    includeHyperlinks : true);

                var bundleItemName = item.BundleItem.GetLocalized(x => x.Name);
                if (bundleItemName.Value.HasValue())
                {
                    to.ProductName = bundleItemName;
                }

                var bundleItemShortDescription = item.BundleItem.GetLocalized(x => x.ShortDescription);
                if (bundleItemShortDescription.Value.HasValue())
                {
                    to.ShortDesc = bundleItemShortDescription;
                }

                if (to.BundlePerItemPricing && to.BundlePerItemShoppingCart)
                {
                    var bundleItemSubTotalWithDiscountBase = await _taxService.GetProductPriceAsync(product, await _priceCalculationService.GetSubTotalAsync(from, true));

                    var bundleItemSubTotalWithDiscount = _currencyService.ConvertFromPrimaryCurrency(bundleItemSubTotalWithDiscountBase.Price.Amount, currency);
                    to.BundleItem.PriceWithDiscount = bundleItemSubTotalWithDiscount.ToString();
                }
            }
            else
            {
                to.AttributeInfo = await _productAttributeFormatter.FormatAttributesAsync(item.AttributeSelection, product, customer);
            }

            var allowedQuantities = product.ParseAllowedQuantities();

            foreach (var quantity in allowedQuantities)
            {
                to.AllowedQuantities.Add(new SelectListItem
                {
                    Text     = quantity.ToString(),
                    Value    = quantity.ToString(),
                    Selected = item.Quantity == quantity
                });
            }

            var quantityUnit = await _db.QuantityUnits.GetQuantityUnitByIdAsync(product.QuantityUnitId ?? 0, _catalogSettings.ShowDefaultQuantityUnit);

            if (quantityUnit != null)
            {
                to.QuantityUnitName = quantityUnit.GetLocalized(x => x.Name);
            }

            if (product.IsRecurring)
            {
                to.RecurringInfo = T("ShoppingCart.RecurringPeriod", product.RecurringCycleLength, product.RecurringCyclePeriod.GetLocalizedEnum());
            }

            if (product.CallForPrice)
            {
                to.UnitPrice = T("Products.CallForPrice");
            }
            else
            {
                var unitPriceWithDiscountBase = await _taxService.GetProductPriceAsync(product, await _priceCalculationService.GetUnitPriceAsync(from, true));

                var unitPriceWithDiscount = _currencyService.ConvertFromPrimaryCurrency(unitPriceWithDiscountBase.Price.Amount, currency);
                to.UnitPrice = unitPriceWithDiscount.ToString();
            }

            // Subtotal and discount.
            if (product.CallForPrice)
            {
                to.SubTotal = T("Products.CallForPrice");
            }
            else
            {
                var cartItemSubTotalWithDiscount = await _priceCalculationService.GetSubTotalAsync(from, true);

                var cartItemSubTotalWithDiscountBase = await _taxService.GetProductPriceAsync(product, cartItemSubTotalWithDiscount);

                cartItemSubTotalWithDiscount = _currencyService.ConvertFromPrimaryCurrency(cartItemSubTotalWithDiscountBase.Price.Amount, currency);

                to.SubTotal = cartItemSubTotalWithDiscount.ToString();

                // Display an applied discount amount.
                var cartItemSubTotalWithoutDiscount = await _priceCalculationService.GetSubTotalAsync(from, false);

                var cartItemSubTotalWithoutDiscountBase = await _taxService.GetProductPriceAsync(product, cartItemSubTotalWithoutDiscount);

                var cartItemSubTotalDiscountBase = cartItemSubTotalWithoutDiscountBase.Price - cartItemSubTotalWithDiscountBase.Price;

                if (cartItemSubTotalDiscountBase > decimal.Zero)
                {
                    var itemDiscount = _currencyService.ConvertFromPrimaryCurrency(cartItemSubTotalDiscountBase.Amount, currency);
                    to.Discount = itemDiscount.ToString();
                }
            }

            if (item.BundleItem != null)
            {
                if (_shoppingCartSettings.ShowProductBundleImagesOnShoppingCart)
                {
                    await from.MapAsync(to.Image, _mediaSettings.CartThumbBundleItemPictureSize, to.ProductName);
                }
            }
            else
            {
                if (_shoppingCartSettings.ShowProductImagesOnShoppingCart)
                {
                    await from.MapAsync(to.Image, _mediaSettings.CartThumbPictureSize, to.ProductName);
                }
            }

            var itemWarnings = new List <string>();
            var isItemValid  = await _shoppingCartValidator.ValidateCartItemsAsync(new[] { from }, itemWarnings);

            if (!isItemValid)
            {
                itemWarnings.Each(x => to.Warnings.Add(x));
            }
        }
        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;
        }