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