Example #1
0
        /// <summary>
        /// Creates a new context instance for given <paramref name="cartItem"/> and <paramref name="options"/>.
        /// </summary>
        /// <param name="cartItem">Shopping cart item.</param>
        /// <param name="options">The calculation options.</param>
        public PriceCalculationContext(OrganizedShoppingCartItem cartItem, PriceCalculationOptions options)
            : this(cartItem?.Item?.Product, cartItem?.Item?.Quantity ?? 1, options)
        {
            Guard.NotNull(cartItem, nameof(cartItem));

            CartItem = cartItem;
        }
Example #2
0
        /// <summary>
        /// Gets discount amount
        /// </summary>
        /// <param name="shoppingCartItem">The shopping cart item</param>
        /// <param name="appliedDiscount">Applied discount</param>
        /// <returns>Discount amount</returns>
        public virtual decimal GetDiscountAmount(OrganizedShoppingCartItem shoppingCartItem, out Discount appliedDiscount)
        {
            appliedDiscount = null;

            var customer            = shoppingCartItem.Item.Customer;
            var totalDiscountAmount = decimal.Zero;
            var product             = shoppingCartItem.Item.Product;
            var quantity            = shoppingCartItem.Item.Quantity;

            if (product != null)
            {
                var attributesTotalPrice = decimal.Zero;
                var pvaValues            = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml).ToList();

                foreach (var pvaValue in pvaValues)
                {
                    attributesTotalPrice += GetProductVariantAttributeValuePriceAdjustment(pvaValue, product, customer, null, quantity);
                }

                var productDiscountAmount = GetDiscountAmount(product, customer, attributesTotalPrice, quantity, out appliedDiscount);
                totalDiscountAmount = productDiscountAmount * quantity;
            }

            totalDiscountAmount = totalDiscountAmount.RoundIfEnabledFor(_services.WorkContext.WorkingCurrency);
            return(totalDiscountAmount);
        }
        public void Can_get_shopping_cart_item_subTotal()
        {
            //customer
            var customer = new Customer();

            //shopping cart
            var product1 = new Product
            {
                Id    = 1,
                Name  = "Product name 1",
                Price = 12.34M,
                CustomerEntersPrice = false,
                Published           = true,
            };
            var sci1 = new ShoppingCartItem()
            {
                Customer   = customer,
                CustomerId = customer.Id,
                Product    = product1,
                ProductId  = product1.Id,
                Quantity   = 2,
            };

            var item = new OrganizedShoppingCartItem(sci1);

            _priceCalcService.GetSubTotal(item, false).ShouldEqual(24.68);
        }
        /// <summary>
        /// Gets discount amount
        /// </summary>
        /// <param name="shoppingCartItem">The shopping cart item</param>
        /// <param name="appliedDiscount">Applied discount</param>
        /// <returns>Discount amount</returns>
        public virtual decimal GetDiscountAmount(OrganizedShoppingCartItem shoppingCartItem, out Discount appliedDiscount)
        {
            var customer = shoppingCartItem.Item.Customer;

            appliedDiscount = null;
            decimal totalDiscountAmount = decimal.Zero;
            var     product             = shoppingCartItem.Item.Product;

            if (product != null)
            {
                decimal attributesTotalPrice = decimal.Zero;

                var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml).ToList();
                foreach (var pvaValue in pvaValues)
                {
                    attributesTotalPrice += GetProductVariantAttributeValuePriceAdjustment(pvaValue);
                }

                decimal productDiscountAmount = GetDiscountAmount(product, customer, attributesTotalPrice, shoppingCartItem.Item.Quantity, out appliedDiscount);
                totalDiscountAmount = productDiscountAmount * shoppingCartItem.Item.Quantity;
            }

            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                totalDiscountAmount = Math.Round(totalDiscountAmount, 2);
            }
            return(totalDiscountAmount);
        }
Example #5
0
        /// <summary>
        /// Gets the shopping cart unit price (one item)
        /// </summary>
        /// <param name="shoppingCartItem">The shopping cart item</param>
        /// <param name="includeDiscounts">A value indicating whether include discounts or not for price computation</param>
        /// <returns>Shopping cart unit price (one item)</returns>
        public virtual decimal GetUnitPrice(OrganizedShoppingCartItem shoppingCartItem, bool includeDiscounts)
        {
            decimal 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)
                        {
                            bundleItem.Item.Product.MergeWithCombination(bundleItem.Item.AttributesXml, _productAttributeParser);
                        }

                        var bundleItems = shoppingCartItem.ChildItems.Where(x => x.BundleItemData.IsValid()).Select(x => x.BundleItemData).ToList();

                        finalPrice = GetFinalPrice(product, bundleItems, customer, decimal.Zero, includeDiscounts, shoppingCartItem.Item.Quantity);
                    }
                }
                else
                {
                    product.MergeWithCombination(shoppingCartItem.Item.AttributesXml, _productAttributeParser);

                    var attributesTotalPrice = decimal.Zero;

                    var pvaValuesEnum = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml);

                    if (pvaValuesEnum != null)
                    {
                        var pvaValues = pvaValuesEnum.ToList();

                        foreach (var pvaValue in pvaValues)
                        {
                            attributesTotalPrice += GetProductVariantAttributeValuePriceAdjustment(pvaValue);
                        }
                    }

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

            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                finalPrice = Math.Round(finalPrice, 2);
            }

            return(finalPrice);
        }
        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));
        }
Example #7
0
        /// <summary>
        /// Gets shopping cart item total weight
        /// </summary>
        /// <param name="shoppingCartItem">Shopping cart item</param>
        /// <returns>Shopping cart item weight</returns>
        public virtual decimal GetShoppingCartItemTotalWeight(OrganizedShoppingCartItem shoppingCartItem)
        {
            if (shoppingCartItem == null)
            {
                throw new ArgumentNullException("shoppingCartItem");
            }

            decimal totalWeight = GetShoppingCartItemWeight(shoppingCartItem) * shoppingCartItem.Item.Quantity;

            return(totalWeight);
        }
Example #8
0
        public override async Task MapAsync(OrganizedShoppingCartItem from, ShoppingCartModel.ShoppingCartItemModel to, dynamic parameters = null)
        {
            Guard.NotNull(from, nameof(from));
            Guard.NotNull(to, nameof(to));

            var item    = from.Item;
            var product = item.Product;

            await base.MapAsync(from, to, (object)parameters);

            to.Weight                = product.Weight;
            to.IsShipEnabled         = product.IsShippingEnabled;
            to.IsDownload            = product.IsDownload;
            to.HasUserAgreement      = product.HasUserAgreement;
            to.IsEsd                 = product.IsEsd;
            to.DisableWishlistButton = product.DisableWishlistButton;

            if (product.DisplayDeliveryTimeAccordingToStock(_catalogSettings))
            {
                var deliveryTime = await _deliveryTimeService.GetDeliveryTimeAsync(product.GetDeliveryTimeIdAccordingToStock(_catalogSettings));

                if (deliveryTime != null)
                {
                    to.DeliveryTimeName     = deliveryTime.GetLocalized(x => x.Name);
                    to.DeliveryTimeHexValue = deliveryTime.ColorHexValue;

                    if (_shoppingCartSettings.DeliveryTimesInShoppingCart is DeliveryTimesPresentation.DateOnly
                        or DeliveryTimesPresentation.LabelAndDate)
                    {
                        to.DeliveryTimeDate = _deliveryTimeService.GetFormattedDeliveryDate(deliveryTime);
                    }
                }
            }

            if (from.Item.BundleItem == null)
            {
                var selectedValues = await _productAttributeMaterializer.MaterializeProductVariantAttributeValuesAsync(item.AttributeSelection);

                selectedValues.Each(x => to.Weight += x.WeightAdjustment);
            }

            if (from.ChildItems != null)
            {
                foreach (var childItem in from.ChildItems.Where(x => x.Item.Id != item.Id))
                {
                    var model = new ShoppingCartModel.ShoppingCartItemModel();

                    await childItem.MapAsync(model, (object)parameters);

                    to.AddChildItems(model);
                }
            }
        }
Example #9
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 static async Task MapAsync(this OrganizedShoppingCartItem entity, ImageModel model, int pictureSize, string productName)
        {
            Guard.NotNull(entity, nameof(entity));
            Guard.NotNull(model, nameof(model));

            var product = entity.Item.Product;

            dynamic parameters = new ExpandoObject();
            parameters.Selection = entity.Item.AttributeSelection;
            parameters.Product = product;
            parameters.ProductName = productName.HasValue() ? productName : product.GetLocalized(x => x.Name);
            parameters.PictureSize = pictureSize;

            await MapperFactory.MapAsync(entity, model, parameters);
        }
Example #11
0
        public static IList <OrganizedShoppingCartItem> Organize(this IList <ShoppingCartItem> cart)
        {
            var result = new List <OrganizedShoppingCartItem>();
            var productAttributeParser = EngineContext.Current.Resolve <IProductAttributeParser>();

            if (cart == null || cart.Count <= 0)
            {
                return(result);
            }

            foreach (var parent in cart.Where(x => x.ParentItemId == null))
            {
                var parentItem = new OrganizedShoppingCartItem(parent);

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

                foreach (var child in childs)
                {
                    var childItem = new OrganizedShoppingCartItem(child);

                    if (parent.Product != null && parent.Product.BundlePerItemPricing && child.AttributesXml != null && child.BundleItem != null)
                    {
                        var combination = productAttributeParser.FindProductVariantAttributeCombination(child.Product, child.AttributesXml);

                        if (combination != null && combination.Price.HasValue)
                        {
                            childItem.BundleItemData.PriceOverride = combination.Price.Value;
                        }
                        else
                        {
                            var attributeValues = productAttributeParser.ParseProductVariantAttributeValues(child.AttributesXml);
                            if (attributeValues != null)
                            {
                                childItem.BundleItemData.AdditionalCharge = decimal.Zero;
                                attributeValues.Each(x => childItem.BundleItemData.AdditionalCharge += x.PriceAdjustment);
                            }
                        }
                    }

                    parentItem.ChildItems.Add(childItem);
                }

                result.Add(parentItem);
            }

            return(result);
        }
        /// <summary>
        /// Calculates the unit price for a given shopping cart item.
        /// </summary>
        /// <param name="priceCalculationService">Price calculation service.</param>
        /// <param name="cartItem">Shopping cart item.</param>
        /// <param name="ignoreDiscounts">A value indicating whether to ignore discounts.</param>
        /// <param name="targetCurrency">The target currency to use for money conversion. Obtained from <see cref="IWorkContext.WorkingCurrency"/> if <c>null</c>.</param>
        /// <returns>Calculated unit price.</returns>
        public static async Task <CalculatedPrice> CalculateUnitPriceAsync(
            this IPriceCalculationService2 priceCalculationService,
            OrganizedShoppingCartItem cartItem,
            bool ignoreDiscounts    = false,
            Currency targetCurrency = null)
        {
            Guard.NotNull(priceCalculationService, nameof(priceCalculationService));
            Guard.NotNull(cartItem, nameof(cartItem));

            var options = priceCalculationService.CreateDefaultOptions(false, cartItem.Item.Customer, targetCurrency);

            options.IgnoreDiscounts = ignoreDiscounts;
            var context = new PriceCalculationContext(cartItem, options);

            return(await priceCalculationService.CalculatePriceAsync(context));
        }
        public virtual async Task <decimal> GetCartItemWeightAsync(OrganizedShoppingCartItem cartItem, bool multipliedByQuantity = true)
        {
            Guard.NotNull(cartItem, nameof(cartItem));

            if (cartItem.Item.Product is null)
            {
                return(decimal.Zero);
            }

            var attributesWeight = cartItem.Item.RawAttributes.HasValue()
                ? await GetCartItemsAttributesWeightAsync(new List <OrganizedShoppingCartItem> {
                cartItem
            }, false)
                : decimal.Zero;

            return(multipliedByQuantity
                ? (cartItem.Item.Product.Weight + attributesWeight) * cartItem.Item.Quantity
                : cartItem.Item.Product.Weight + attributesWeight);
        }
        public void Can_get_shoppingCartItem_totalWeight_without_attributes()
        {
            var sci = new ShoppingCartItem()
            {
                AttributesXml = "",
                Quantity      = 3,
                Product       = new Product()
                {
                    Weight = 1.5M,
                    Height = 2.5M,
                    Length = 3.5M,
                    Width  = 4.5M
                }
            };

            var item = new OrganizedShoppingCartItem(sci);

            _shippingService.GetShoppingCartItemTotalWeight(item).ShouldEqual(4.5M);
        }
Example #15
0
        public override async Task MapAsync(OrganizedShoppingCartItem from, WishlistModel.WishlistItemModel to, dynamic parameters = null)
        {
            Guard.NotNull(from, nameof(from));
            Guard.NotNull(to, nameof(to));

            await base.MapAsync(from, to);

            if (from.ChildItems != null)
            {
                foreach (var childItem in from.ChildItems.Where(x => x.Item.Id != from.Item.Id))
                {
                    var model = new WishlistModel.WishlistItemModel
                    {
                        DisableBuyButton = childItem.Item.Product.DisableBuyButton
                    };

                    await childItem.MapAsync(model);

                    to.AddChildItems(model);
                }
            }
        }
Example #16
0
        /// <summary>
        /// Gets shopping cart item weight (of one item)
        /// </summary>
        /// <param name="shoppingCartItem">Shopping cart item</param>
        /// <returns>Shopping cart item weight</returns>
        public virtual decimal GetShoppingCartItemWeight(OrganizedShoppingCartItem shoppingCartItem)
        {
            if (shoppingCartItem == null)
            {
                throw new ArgumentNullException("shoppingCartItem");
            }

            decimal weight = decimal.Zero;

            if (shoppingCartItem.Item.Product != null)
            {
                decimal attributesTotalWeight = decimal.Zero;

                if (!String.IsNullOrEmpty(shoppingCartItem.Item.AttributesXml))
                {
                    var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml);

                    foreach (var pvaValue in pvaValues)
                    {
                        if (pvaValue.ValueType == ProductVariantAttributeValueType.ProductLinkage)
                        {
                            var linkedProduct = _productService.GetProductById(pvaValue.LinkedProductId);
                            if (linkedProduct != null && linkedProduct.IsShipEnabled)
                            {
                                attributesTotalWeight += (linkedProduct.Weight * pvaValue.Quantity);
                            }
                        }
                        else
                        {
                            attributesTotalWeight += pvaValue.WeightAdjustment;
                        }
                    }
                }

                weight = shoppingCartItem.Item.Product.Weight + attributesTotalWeight;
            }
            return(weight);
        }
        public virtual AdjustInventoryResult AdjustInventory(OrganizedShoppingCartItem sci, bool decrease)
        {
            if (sci == null)
            {
                throw new ArgumentNullException("cartItem");
            }

            if (sci.Item.Product.ProductType == ProductType.BundledProduct && sci.Item.Product.BundlePerItemShoppingCart)
            {
                if (sci.ChildItems != null)
                {
                    foreach (var child in sci.ChildItems.Where(x => x.Item.Id != sci.Item.Id))
                    {
                        AdjustInventory(child.Item.Product, decrease, sci.Item.Quantity * child.Item.Quantity, child.Item.AttributesXml);
                    }
                }
                return(new AdjustInventoryResult());
            }
            else
            {
                return(AdjustInventory(sci.Item.Product, decrease, sci.Item.Quantity, sci.Item.AttributesXml));
            }
        }
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="helper">Product URL helper</param>
        /// <param name="productSeName">Product SEO name</param>
        /// <param name="cartItem">Organized shopping cart item</param>
        /// <returns>Product URL</returns>
        public static string GetProductUrl(
            this ProductUrlHelper helper,
            string productSeName,
            OrganizedShoppingCartItem cartItem)
        {
            Guard.NotNull(cartItem, nameof(cartItem));

            var query   = new ProductVariantQuery();
            var product = cartItem.Item.Product;

            if (product.ProductType != ProductType.BundledProduct)
            {
                helper.DeserializeQuery(query, product.Id, cartItem.Item.AttributesXml);
            }
            else if (cartItem.ChildItems != null && product.BundlePerItemPricing)
            {
                foreach (var childItem in cartItem.ChildItems.Where(x => x.Item.Id != cartItem.Item.Id))
                {
                    helper.DeserializeQuery(query, childItem.Item.ProductId, childItem.Item.AttributesXml, childItem.BundleItemData.Item.Id);
                }
            }

            return(helper.GetProductUrl(query, productSeName));
        }
Example #19
0
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="helper">Product URL helper.</param>
        /// <param name="productSlug">Product URL slug.</param>
        /// <param name="cartItem">Organized shopping cart item.</param>
        /// <returns>Product URL.</returns>
        public static async Task <string> GetProductUrlAsync(this ProductUrlHelper helper, string productSlug, OrganizedShoppingCartItem cartItem)
        {
            Guard.NotNull(helper, nameof(helper));
            Guard.NotNull(cartItem, nameof(cartItem));

            var query   = new ProductVariantQuery();
            var product = cartItem.Item.Product;

            if (product.ProductType != ProductType.BundledProduct)
            {
                await helper.AddAttributesToQueryAsync(query, cartItem.Item.AttributeSelection, product.Id);
            }
            else if (cartItem.ChildItems != null && product.BundlePerItemPricing)
            {
                foreach (var childItem in cartItem.ChildItems.Where(x => x.Item.Id != cartItem.Item.Id))
                {
                    await helper.AddAttributesToQueryAsync(query, childItem.Item.AttributeSelection, childItem.Item.ProductId, childItem.Item.BundleItem.Id);
                }
            }

            return(helper.GetProductUrl(productSlug, query));
        }
        /// <summary>
        /// Gets discount amount
        /// </summary>
        /// <param name="shoppingCartItem">The shopping cart item</param>
        /// <returns>Discount amount</returns>
        public virtual decimal GetDiscountAmount(OrganizedShoppingCartItem shoppingCartItem)
        {
            Discount appliedDiscount;

            return(GetDiscountAmount(shoppingCartItem, out appliedDiscount));
        }
 /// <summary>
 /// Gets the shopping cart item sub total
 /// </summary>
 /// <param name="shoppingCartItem">The shopping cart item</param>
 /// <param name="includeDiscounts">A value indicating whether include discounts or not for price computation</param>
 /// <returns>Shopping cart item sub total</returns>
 public virtual decimal GetSubTotal(OrganizedShoppingCartItem shoppingCartItem, bool includeDiscounts)
 {
     return(GetUnitPrice(shoppingCartItem, includeDiscounts) * shoppingCartItem.Item.Quantity);
 }
Example #22
0
        /// <summary>
        /// Adjusts product inventory. The caller is responsible for database commit.
        /// </summary>
        /// <param name="productService">Product service.</param>
        /// <param name="item">Shopping cart item.</param>
        /// <param name="decrease">A value indicating whether to increase or descrease product stock quantity.</param>
        /// <returns>Adjust inventory result.</returns>
        public static async Task <AdjustInventoryResult> AdjustInventoryAsync(this IProductService productService, OrganizedShoppingCartItem item, bool decrease)
        {
            Guard.NotNull(productService, nameof(productService));
            Guard.NotNull(item, nameof(item));

            if (item.Item.Product.ProductType == ProductType.BundledProduct && item.Item.Product.BundlePerItemShoppingCart)
            {
                if (item.ChildItems != null)
                {
                    foreach (var child in item.ChildItems.Where(x => x.Item.Id != item.Item.Id))
                    {
                        await productService.AdjustInventoryAsync(
                            child.Item.Product,
                            child.Item.AttributeSelection,
                            decrease,
                            item.Item.Quantity *child.Item.Quantity);
                    }
                }

                return(new AdjustInventoryResult());
            }
            else
            {
                return(await productService.AdjustInventoryAsync(
                           item.Item.Product,
                           item.Item.AttributeSelection,
                           decrease,
                           item.Item.Quantity));
            }
        }
 public virtual async Task <Money> GetSubTotalAsync(OrganizedShoppingCartItem shoppingCartItem, bool includeDiscounts)
 {
     return(_primaryCurrency.AsMoney(await GetUnitPriceAmountAsync(shoppingCartItem, includeDiscounts) * shoppingCartItem.Item.Quantity));
 }
        public virtual async Task <(Money Amount, Discount AppliedDiscount)> GetDiscountAmountAsync(OrganizedShoppingCartItem shoppingCartItem)
        {
            Guard.NotNull(shoppingCartItem, nameof(shoppingCartItem));

            var customer = shoppingCartItem.Item.Customer;
            var product  = shoppingCartItem.Item.Product;
            var quantity = shoppingCartItem.Item.Quantity;

            if (product == null)
            {
                return(new(_primaryCurrency), null);
            }

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

            foreach (var pvaValue in pvaValues)
            {
                attributesTotalPrice += await GetVariantPriceAdjustmentAsync(pvaValue, product, customer, null, quantity);
            }

            var(discountAmount, appliedDiscount) = await GetDiscountAmountAsync(product, attributesTotalPrice, customer, quantity);

            return(_primaryCurrency.AsMoney(discountAmount * quantity), appliedDiscount);
        }
Example #25
0
 protected override void Map(OrganizedShoppingCartItem from, WishlistModel.WishlistItemModel to, dynamic parameters = null)
 => throw new NotImplementedException();
Example #26
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);
        }
Example #27
0
 public static async Task MapAsync(this OrganizedShoppingCartItem entity, WishlistModel.WishlistItemModel model)
 {
     await MapperFactory.MapAsync(entity, model, null);
 }
        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);
        }
        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);
            }
        }
        /// <summary>
        /// Adds selected product attributes of a shopping cart item to be taken into account in the price calculation.
        /// For example required for price adjustments of attributes selected by the customer.
        /// Also adds selected attributes of bundle items if <see cref="Product.BundlePerItemPricing"/> is activated.
        /// </summary>
        /// <param name="context">The target product calculation context.</param>
        /// <param name="item">Shopping cart item.</param>
        public static void AddSelectedAttributes(this PriceCalculationContext context, OrganizedShoppingCartItem cartItem)
        {
            Guard.NotNull(context, nameof(context));

            if (cartItem != null)
            {
                var item = cartItem.Item;

                context.AddSelectedAttributes(item);

                if (item.Product.ProductType == ProductType.BundledProduct && item.Product.BundlePerItemPricing)
                {
                    cartItem.ChildItems.Each(x => context.AddSelectedAttributes(x.Item));
                }
            }
        }