public virtual async Task <Money> GetUnitPriceAsync(OrganizedShoppingCartItem shoppingCartItem, bool includeDiscounts)
        {
            Guard.NotNull(shoppingCartItem, nameof(shoppingCartItem));

            var currency = _workContext.WorkingCurrency;
            var cartItem = shoppingCartItem.Item;
            var customer = cartItem.Customer;
            var product  = cartItem.Product;

            if (product != null)
            {
                if (product.CustomerEntersPrice)
                {
                    return(currency.AsMoney(cartItem.CustomerEnteredPrice));
                }
                else if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)
                {
                    if (shoppingCartItem.ChildItems != null)
                    {
                        foreach (var bundleItem in shoppingCartItem.ChildItems)
                        {
                            await _productAttributeMaterializer.MergeWithCombinationAsync(bundleItem.Item.Product, bundleItem.Item.AttributeSelection);
                        }

                        var bundleItems = shoppingCartItem.ChildItems
                                          .Where(x => x.BundleItemData?.Item != null)
                                          .Select(x => x.BundleItemData);

                        var finalPrice = await GetFinalPriceAsync(product, bundleItems, null, customer, includeDiscounts, cartItem.Quantity);

                        return(currency.AsMoney(finalPrice.Amount));
                    }
                }
                else
                {
                    await _productAttributeMaterializer.MergeWithCombinationAsync(product, cartItem.AttributeSelection);

                    var pvaValues = await _productAttributeMaterializer.MaterializeProductVariantAttributeValuesAsync(cartItem.AttributeSelection);

                    var attributesTotalPrice = new Money(currency);

                    foreach (var pvaValue in pvaValues)
                    {
                        attributesTotalPrice += await GetProductVariantAttributeValuePriceAdjustmentAsync(pvaValue, product, customer, null, cartItem.Quantity);
                    }

                    var finalPrice = await GetFinalPriceAsync(product, attributesTotalPrice, customer, includeDiscounts, cartItem.Quantity, shoppingCartItem.BundleItemData);

                    return(currency.AsMoney(finalPrice.Amount));
                }
            }

            return(new Money(currency));
        }
예제 #2
0
        public virtual async Task <decimal> GetUnitPriceAsync(OrganizedShoppingCartItem shoppingCartItem, bool includeDiscounts)
        {
            Guard.NotNull(shoppingCartItem, nameof(shoppingCartItem));

            var finalPrice = decimal.Zero;
            var customer   = shoppingCartItem.Item.Customer;
            var product    = shoppingCartItem.Item.Product;

            if (product != null)
            {
                if (product.CustomerEntersPrice)
                {
                    finalPrice = shoppingCartItem.Item.CustomerEnteredPrice;
                }
                else if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)
                {
                    if (shoppingCartItem.ChildItems != null)
                    {
                        foreach (var bundleItem in shoppingCartItem.ChildItems)
                        {
                            await _productAttributeMaterializer.MergeWithCombinationAsync(bundleItem.Item.Product, bundleItem.Item.AttributeSelection);
                        }

                        var bundleItems = shoppingCartItem.ChildItems
                                          .Where(x => x.BundleItemData?.Item != null)
                                          .Select(x => x.BundleItemData)
                                          .ToList();

                        finalPrice = await GetFinalPriceAsync(product, bundleItems, customer, decimal.Zero, includeDiscounts, shoppingCartItem.Item.Quantity);
                    }
                }
                else
                {
                    await _productAttributeMaterializer.MergeWithCombinationAsync(product, shoppingCartItem.Item.AttributeSelection);

                    var attributesTotalPrice = decimal.Zero;
                    var pvaValues            = await _productAttributeMaterializer.MaterializeProductVariantAttributeValuesAsync(shoppingCartItem.Item.AttributeSelection);

                    foreach (var pvaValue in pvaValues)
                    {
                        attributesTotalPrice += await GetProductVariantAttributeValuePriceAdjustmentAsync(pvaValue, product, customer, null, shoppingCartItem.Item.Quantity);
                    }

                    finalPrice = await GetFinalPriceAsync(product, customer, attributesTotalPrice, includeDiscounts, shoppingCartItem.Item.Quantity, shoppingCartItem.BundleItemData);
                }
            }

            finalPrice = _workContext.WorkingCurrency.RoundIfEnabledFor(finalPrice);
            return(finalPrice);
        }
        public virtual async Task <PriceCalculationContext> CreateCalculationContextAsync(OrganizedShoppingCartItem cartItem, PriceCalculationOptions options)
        {
            Guard.NotNull(cartItem, nameof(cartItem));
            Guard.NotNull(options, nameof(options));

            var product = cartItem.Item.Product;
            var context = new PriceCalculationContext(product, cartItem.Item.Quantity, options)
            {
                CartItem = cartItem
            };

            // Include attributes selected for this cart item in price calculation.
            context.AddSelectedAttributes(cartItem);

            // Include bundle item data if the cart item is a bundle item.
            if (cartItem.Item.BundleItem != null)
            {
                context.BundleItem = cartItem.Item.BundleItem;
            }

            // Perf: we already have the bundle items of a bundled product. No need to load them again during calculation.
            if (cartItem.ChildItems?.Any() ?? false)
            {
                context.BundleItems = cartItem.ChildItems
                                      .Where(x => x.Item.BundleItem != null)
                                      .Select(x => x.Item.BundleItem)
                                      .ToList();
            }

            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)
            {
                Guard.NotNull(cartItem.ChildItems, nameof(cartItem.ChildItems));

                foreach (var bundleItem in cartItem.ChildItems)
                {
                    await _productAttributeMaterializer.MergeWithCombinationAsync(bundleItem.Item.Product, bundleItem.Item.AttributeSelection);
                }
            }
            else
            {
                await _productAttributeMaterializer.MergeWithCombinationAsync(product, cartItem.Item.AttributeSelection);
            }

            return(context);
        }
예제 #4
0
        protected virtual async Task <IList <OrganizedShoppingCartItem> > OrganizeCartItemsAsync(ICollection <ShoppingCartItem> cart)
        {
            var result = new List <OrganizedShoppingCartItem>();

            if (cart.IsNullOrEmpty())
            {
                return(result);
            }

            var parents = cart.Where(x => x.ParentItemId is null);

            // TODO: (ms) (core) to reduce db roundtrips -> load and filter children by parents (id and so on) into lists and try to get from db as batch request

            foreach (var parent in parents)
            {
                var parentItem = new OrganizedShoppingCartItem(parent);

                var children = cart.Where(x => x.ParentItemId != null &&
                                          x.ParentItemId == parent.Id &&
                                          x.Id != parent.Id &&
                                          x.ShoppingCartTypeId == parent.ShoppingCartTypeId &&
                                          x.Product.CanBeBundleItem());

                // TODO: (ms) (core) Reduce database roundtrips in OrganizeCartItemsAsync
                foreach (var child in children)
                {
                    var childItem = new OrganizedShoppingCartItem(child);

                    if (child.RawAttributes.HasValue() &&
                        (parent.Product?.BundlePerItemPricing ?? false) &&
                        child.BundleItem != null)
                    {
                        var selection = new ProductVariantAttributeSelection(child.RawAttributes);

                        await _productAttributeMaterializer.MergeWithCombinationAsync(child.Product, selection);

                        var attributeValues = await _productAttributeMaterializer
                                              .MaterializeProductVariantAttributeValuesAsync(selection);

                        if (!attributeValues.IsNullOrEmpty())
                        {
                            childItem.BundleItemData.AdditionalCharge += attributeValues.Sum(x => x.PriceAdjustment);
                        }
                    }

                    parentItem.ChildItems.Add(childItem);
                }

                result.Add(parentItem);
            }

            return(result);
        }
예제 #5
0
        public override async Task MapAsync(OrganizedShoppingCartItem from, TModel to, dynamic parameters = null)
        {
            Guard.NotNull(from, nameof(from));
            Guard.NotNull(to, nameof(to));

            var item             = from.Item;
            var product          = from.Item.Product;
            var customer         = item.Customer;
            var currency         = _services.WorkContext.WorkingCurrency;
            var shoppingCartType = item.ShoppingCartType;
            var productSeName    = await product.GetActiveSlugAsync();

            var taxFormat    = parameters?.TaxFormat as string;
            var batchContext = parameters?.BatchContext as ProductBatchContext;

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

            // 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,
                    batchContext : batchContext);

                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;
                }

                var calculationOptions = _priceCalculationService.CreateDefaultOptions(false, customer, null, batchContext);
                var calculationContext = await _priceCalculationService.CreateCalculationContextAsync(from, calculationOptions);

                var(bundleItemUnitPrice, bundleItemSubtotal) = await _priceCalculationService.CalculateSubtotalAsync(calculationContext);

                if (to.BundlePerItemPricing && to.BundlePerItemShoppingCart)
                {
                    to.BundleItem.PriceWithDiscount = bundleItemSubtotal.FinalPrice.ToString();
                }

                to.BasePrice = _priceCalculationService.GetBasePriceInfo(product, bundleItemUnitPrice.FinalPrice);
            }
            else
            {
                to.AttributeInfo = await ProductAttributeFormatter.FormatAttributesAsync(item.AttributeSelection, product, customer, batchContext : batchContext);
            }

            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 = to.UnitPrice.WithPostFormat(T("Products.CallForPrice"));
                to.SubTotal  = to.UnitPrice;
            }
            else if (item.BundleItem == null)
            {
                if (shoppingCartType == ShoppingCartType.ShoppingCart)
                {
                    var subtotal = parameters?.CartSubtotal as ShoppingCartSubtotal;
                    var lineItem = subtotal.LineItems.FirstOrDefault(x => x.Item.Item.Id == item.Id);

                    var unitPrice = CurrencyService.ConvertFromPrimaryCurrency(lineItem.UnitPrice.FinalPrice.Amount, currency);
                    to.UnitPrice = unitPrice.WithPostFormat(taxFormat);

                    var itemSubtotal = CurrencyService.ConvertFromPrimaryCurrency(lineItem.Subtotal.FinalPrice.Amount, currency);
                    to.SubTotal = itemSubtotal.WithPostFormat(taxFormat);

                    if (lineItem.Subtotal.DiscountAmount > 0)
                    {
                        var itemDiscount = CurrencyService.ConvertFromPrimaryCurrency(lineItem.Subtotal.DiscountAmount.Amount, currency);
                        to.Discount = itemDiscount.WithPostFormat(taxFormat);
                    }

                    to.BasePrice = _priceCalculationService.GetBasePriceInfo(product, unitPrice);
                }
                else
                {
                    var calculationOptions = _priceCalculationService.CreateDefaultOptions(false, customer, null, batchContext);
                    var calculationContext = await _priceCalculationService.CreateCalculationContextAsync(from, calculationOptions);

                    var(unitPrice, itemSubtotal) = await _priceCalculationService.CalculateSubtotalAsync(calculationContext);

                    to.UnitPrice = unitPrice.FinalPrice;
                    to.SubTotal  = itemSubtotal.FinalPrice;

                    if (itemSubtotal.DiscountAmount > 0)
                    {
                        to.Discount = itemSubtotal.DiscountAmount;
                    }
                }
            }

            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 isValid      = await ShoppingCartValidator.ValidateCartItemsAsync(new[] { from }, itemWarnings);

            if (!isValid)
            {
                to.Warnings.AddRange(itemWarnings);
            }

            var cart = await ShoppingCartService.GetCartItemsAsync(customer, shoppingCartType, _services.StoreContext.CurrentStore.Id);

            var attrWarnings = new List <string>();

            isValid = await ShoppingCartValidator.ValidateProductAttributesAsync(item, cart, attrWarnings);

            if (!isValid)
            {
                to.Warnings.AddRange(attrWarnings);
            }
        }
예제 #6
0
        public virtual async Task <ShoppingCartSubTotal> GetShoppingCartSubTotalAsync(IList <OrganizedShoppingCartItem> cart, bool?includeTax = null)
        {
            Guard.NotNull(cart, nameof(cart));

            var includingTax = includeTax ?? (_workContext.TaxDisplayType == TaxDisplayType.IncludingTax);
            var result       = new ShoppingCartSubTotal();

            if (!(cart?.Any() ?? false))
            {
                return(result);
            }

            var customer = cart.GetCustomer();
            var subTotalExclTaxWithoutDiscount = new Money(_primaryCurrency);
            var subTotalInclTaxWithoutDiscount = new Money(_primaryCurrency);

            foreach (var cartItem in cart)
            {
                if (cartItem.Item.Product == null)
                {
                    continue;
                }

                var     item = cartItem.Item;
                decimal taxRate = decimal.Zero;
                Money   itemExclTax, itemInclTax;

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

                if (_primaryCurrency.RoundOrderItemsEnabled)
                {
                    // Gross > Net RoundFix.
                    var unitPrice = await _priceCalculationService.GetUnitPriceAsync(cartItem, true);

                    // Adaption to eliminate rounding issues.
                    (itemExclTax, taxRate) = await _taxService.GetProductPriceAsync(item.Product, unitPrice, false, customer : customer);

                    itemExclTax            = _primaryCurrency.AsMoney(itemExclTax.Amount * item.Quantity);
                    (itemInclTax, taxRate) = await _taxService.GetProductPriceAsync(item.Product, unitPrice, true, customer : customer);

                    itemInclTax = _primaryCurrency.AsMoney(itemInclTax.Amount * item.Quantity);
                }
                else
                {
                    var itemSubTotal = await _priceCalculationService.GetSubTotalAsync(cartItem, true);

                    (itemExclTax, taxRate) = await _taxService.GetProductPriceAsync(item.Product, itemSubTotal, false, customer : customer);

                    (itemInclTax, taxRate) = await _taxService.GetProductPriceAsync(item.Product, itemSubTotal, true, customer : customer);
                }

                subTotalExclTaxWithoutDiscount += itemExclTax;
                subTotalInclTaxWithoutDiscount += itemInclTax;

                result.TaxRates.Add(taxRate, itemInclTax.Amount - itemExclTax.Amount);
            }

            // Checkout attributes.
            if (customer != null)
            {
                var values = await _checkoutAttributeMaterializer.MaterializeCheckoutAttributeValuesAsync(customer.GenericAttributes.CheckoutAttributes);

                foreach (var value in values)
                {
                    var(attributePriceExclTax, _) = await _taxService.GetCheckoutAttributePriceAsync(value, false, customer);

                    var(attributePriceInclTax, taxRate) = await _taxService.GetCheckoutAttributePriceAsync(value, true, customer);

                    subTotalExclTaxWithoutDiscount += attributePriceExclTax.Amount;
                    subTotalInclTaxWithoutDiscount += attributePriceInclTax.Amount;

                    result.TaxRates.Add(taxRate, attributePriceInclTax.Amount - attributePriceExclTax.Amount);
                }
            }


            // Subtotal without discount.
            result.SubTotalWithoutDiscount = _primaryCurrency.AsMoney(includingTax ? subTotalInclTaxWithoutDiscount.Amount : subTotalExclTaxWithoutDiscount.Amount, true, true);

            // We calculate discount amount on order subtotal excl tax (discount first).
            var(discountAmountExclTax, appliedDiscount) = await this.GetOrderSubtotalDiscountAsync(subTotalExclTaxWithoutDiscount, customer);

            result.AppliedDiscount = appliedDiscount;

            if (subTotalExclTaxWithoutDiscount < discountAmountExclTax)
            {
                discountAmountExclTax = subTotalExclTaxWithoutDiscount;
            }

            var discountAmountInclTax = discountAmountExclTax;

            // Subtotal with discount (excl tax).
            var subTotalExclTaxWithDiscount = subTotalExclTaxWithoutDiscount - discountAmountExclTax;
            var subTotalInclTaxWithDiscount = subTotalExclTaxWithDiscount;

            // Add tax for shopping items & checkout attributes.
            var tempTaxRates = new Dictionary <decimal, decimal>(result.TaxRates);

            foreach (var kvp in tempTaxRates)
            {
                var taxRate   = kvp.Key;
                var taxAmount = kvp.Value;

                if (taxAmount != decimal.Zero)
                {
                    // Discount the tax amount that applies to subtotal items.
                    if (subTotalExclTaxWithoutDiscount > decimal.Zero)
                    {
                        var discountTax = result.TaxRates[taxRate] * (discountAmountExclTax.Amount / subTotalExclTaxWithoutDiscount.Amount);
                        discountAmountInclTax   += discountTax;
                        taxAmount                = _primaryCurrency.RoundIfEnabledFor(result.TaxRates[taxRate] - discountTax);
                        result.TaxRates[taxRate] = taxAmount;
                    }

                    // Subtotal with discount (incl tax).
                    subTotalInclTaxWithDiscount += taxAmount;
                }
            }

            discountAmountInclTax = _primaryCurrency.AsMoney(discountAmountInclTax.Amount);

            result.DiscountAmount       = _primaryCurrency.AsMoney(includingTax ? discountAmountInclTax.Amount : discountAmountExclTax.Amount, false);
            result.SubTotalWithDiscount = _primaryCurrency.AsMoney(includingTax ? subTotalInclTaxWithDiscount.Amount : subTotalExclTaxWithDiscount.Amount, true, true);

            return(result);
        }
예제 #7
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);
        }
예제 #8
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));
            }
        }