Exemplo n.º 1
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);
            }
        }
Exemplo n.º 2
0
        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;
        }