예제 #1
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);
        }
예제 #2
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);
        }
예제 #3
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));
            }
        }