Пример #1
0
        public virtual decimal GetFinalPrice(
            Product product,
            IEnumerable <ProductBundleItemData> bundleItems,
            Customer customer,
            decimal additionalCharge,
            bool includeDiscounts,
            int quantity,
            ProductBundleItemData bundleItem = null,
            PriceCalculationContext context  = null)
        {
            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)
            {
                var result = decimal.Zero;
                var items  = bundleItems;

                if (items == null)
                {
                    items = context == null
                        ? _productService.GetBundleItems(product.Id)
                        : context.ProductBundleItems.GetOrLoad(product.Id).Select(x => new ProductBundleItemData(x)).ToList();
                }

                foreach (var itemData in items.Where(x => x != null && x.Item != null))
                {
                    var itemPrice = GetFinalPrice(itemData.Item.Product, customer, itemData.AdditionalCharge, includeDiscounts, 1, itemData, context);

                    result += decimal.Multiply(itemPrice, itemData.Item.Quantity);
                }

                return(result < decimal.Zero ? decimal.Zero : result);
            }

            return(GetFinalPrice(product, customer, additionalCharge, includeDiscounts, quantity, bundleItem, context));
        }
Пример #2
0
		/// <summary>
		/// Get the initial price including preselected attributes
		/// </summary>
		/// <param name="product">Product</param>
		/// <param name="context">Object with cargo data for better performance</param>
		/// <returns>Preselected price</returns>
		public virtual decimal GetPreselectedPrice(Product product, PriceCalculationContext context)
		{
			if (product == null)
				throw new ArgumentNullException("product");

			var result = decimal.Zero;

			if (context == null)
				context = CreatePriceCalculationContext();

			if (product.ProductType == ProductType.BundledProduct)
			{
				var bundleItems = _productService.GetBundleItems(product.Id);

				var productIds = bundleItems.Select(x => x.Item.ProductId).ToList();
				productIds.Add(product.Id);

				context.Collect(productIds);

				foreach (var bundleItem in bundleItems.Where(x => x.Item.Product.CanBeBundleItem()))
				{
					// fetch bundleItems.AdditionalCharge for all bundle items
					var unused = GetPreselectedPrice(bundleItem.Item.Product, context, bundleItem, bundleItems);
				}

				result = GetPreselectedPrice(product, context, null, bundleItems);
			}
			else
			{
				result = GetPreselectedPrice(product, context, null, null);
			}

			return result;
		}
        public virtual decimal GetFinalPrice(
            Product product,
            IEnumerable <ProductBundleItemData> bundleItems,
            Customer customer,
            decimal additionalCharge,
            bool includeDiscounts,
            int quantity,
            ProductBundleItemData bundleItem = null,
            PriceCalculationContext context  = null)
        {
            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)
            {
                decimal result = decimal.Zero;
                var     items  = bundleItems ?? _productService.GetBundleItems(product.Id);

                foreach (var itemData in items.Where(x => x.IsValid()))
                {
                    decimal itemPrice = GetFinalPrice(itemData.Item.Product, customer, itemData.AdditionalCharge, includeDiscounts, 1, itemData, context);

                    result = result + decimal.Multiply(itemPrice, itemData.Item.Quantity);
                }

                return(result < decimal.Zero ? decimal.Zero : result);
            }
            return(GetFinalPrice(product, customer, additionalCharge, includeDiscounts, quantity, bundleItem, context));
        }
Пример #4
0
        public virtual PriceCalculationContext CreatePriceCalculationContext(
            IEnumerable <Product> products = null,
            Customer customer = null,
            int?storeId       = null)
        {
            if (customer == null)
            {
                customer = _services.WorkContext.CurrentCustomer;
            }

            if (!storeId.HasValue)
            {
                storeId = _services.StoreContext.CurrentStore.Id;
            }

            var context = new PriceCalculationContext(products,
                                                      x => _productAttributeService.GetProductVariantAttributesByProductIds(x, null),
                                                      x => _productAttributeService.GetProductVariantAttributeCombinations(x),
                                                      x => _productService.GetTierPricesByProductIds(x, customer, storeId.Value),
                                                      x => _categoryService.GetProductCategoriesByProductIds(x, true),
                                                      x => _manufacturerService.GetProductManufacturersByProductIds(x),
                                                      x => _productService.GetAppliedDiscountsByProductIds(x),
                                                      x => _productService.GetBundleItemsByProductIds(x, true)
                                                      );

            return(context);
        }
Пример #5
0
        public virtual decimal GetFinalPrice(
            Product product,
            Customer customer,
            decimal additionalCharge,
            bool includeDiscounts,
            int quantity,
            ProductBundleItemData bundleItem = null,
            PriceCalculationContext context  = null,
            bool isTierPrice = false)
        {
            // Initial price.
            decimal result = product.Price;

            // Special price.
            var specialPrice = GetSpecialPrice(product);

            if (specialPrice.HasValue)
            {
                result = specialPrice.Value;
            }

            if (isTierPrice)
            {
                includeDiscounts = true;
            }

            // Tier prices.
            if (product.HasTierPrices && includeDiscounts && !(bundleItem != null && bundleItem.Item != null))
            {
                var tierPrice           = GetMinimumTierPrice(product, customer, quantity, context);
                var discountAmountTest  = GetDiscountAmount(product, customer, additionalCharge, quantity, out var appliedDiscountTest, bundleItem);
                var discountProductTest = result - discountAmountTest;

                //decimal? tierPrice = GetMinimumTierPrice(product, customer, quantity);
                if (tierPrice.HasValue && tierPrice < discountProductTest)
                {
                    includeDiscounts = false;
                    result           = Math.Min(result, tierPrice.Value);
                }
            }

            // Discount + additional charge.
            if (includeDiscounts)
            {
                var discountAmount = GetDiscountAmount(product, customer, additionalCharge, quantity, out var appliedDiscount, bundleItem, context);
                result = result + additionalCharge - discountAmount;
            }
            else
            {
                result = result + additionalCharge;
            }

            if (result < decimal.Zero)
            {
                result = decimal.Zero;
            }

            return(result);
        }
        public virtual PriceCalculationContext CreatePriceCalculationContext(IEnumerable<Product> products = null)
        {
            var context = new PriceCalculationContext(products,
                x => _productAttributeService.GetProductVariantAttributesByProductIds(x, null),
                x => _productAttributeService.GetProductVariantAttributeCombinations(x),
                x => _productService.GetTierPrices(x, _services.WorkContext.CurrentCustomer, _services.StoreContext.CurrentStore.Id),
                x => _categoryService.GetProductCategoriesByProductIds(x, true)
            );

            return context;
        }
        public virtual decimal GetDiscountAmount(
            Product product,
            Customer customer,
            decimal additionalCharge,
            int quantity,
            out Discount appliedDiscount,
            ProductBundleItemData bundleItem = null,
            PriceCalculationContext context  = null)
        {
            appliedDiscount = null;
            decimal appliedDiscountAmount     = decimal.Zero;
            decimal finalPriceWithoutDiscount = decimal.Zero;

            if (bundleItem.IsValid())
            {
                if (bundleItem.Item.Discount.HasValue && bundleItem.Item.BundleProduct.BundlePerItemPricing)
                {
                    appliedDiscount = new Discount
                    {
                        UsePercentage      = bundleItem.Item.DiscountPercentage,
                        DiscountPercentage = bundleItem.Item.Discount.Value,
                        DiscountAmount     = bundleItem.Item.Discount.Value
                    };

                    finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem, context);
                    appliedDiscountAmount     = appliedDiscount.GetDiscountAmount(finalPriceWithoutDiscount);
                }
            }
            else
            {
                // dont't apply when customer entered price or discounts should be ignored completely
                if (product.CustomerEntersPrice || _catalogSettings.IgnoreDiscounts)
                {
                    return(appliedDiscountAmount);
                }

                var allowedDiscounts = GetAllowedDiscounts(product, customer, context);
                if (allowedDiscounts.Count == 0)
                {
                    return(appliedDiscountAmount);
                }

                finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem, context);
                appliedDiscount           = allowedDiscounts.GetPreferredDiscount(finalPriceWithoutDiscount);

                if (appliedDiscount != null)
                {
                    appliedDiscountAmount = appliedDiscount.GetDiscountAmount(finalPriceWithoutDiscount);
                }
            }

            return(appliedDiscountAmount);
        }
        public virtual PriceCalculationContext CreatePriceCalculationContext(IEnumerable <Product> products = null)
        {
            var context = new PriceCalculationContext(products,
                                                      x => _productAttributeService.GetProductVariantAttributesByProductIds(x, null),
                                                      x => _productAttributeService.GetProductVariantAttributeCombinations(x),
                                                      x => _productService.GetTierPricesByProductIds(x, _services.WorkContext.CurrentCustomer, _services.StoreContext.CurrentStore.Id),
                                                      x => _categoryService.GetProductCategoriesByProductIds(x, true),
                                                      x => _productService.GetAppliedDiscountsByProductIds(x)
                                                      );

            return(context);
        }
Пример #9
0
        public virtual decimal?GetLowestPrice(
            Product product,
            Customer customer,
            PriceCalculationContext context,
            IEnumerable <Product> associatedProducts,
            out Product lowestPriceProduct)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            if (associatedProducts == null)
            {
                throw new ArgumentNullException("associatedProducts");
            }

            if (product.ProductType != ProductType.GroupedProduct)
            {
                throw Error.InvalidOperation("Choose the other override for products not of type grouped product.");
            }

            lowestPriceProduct = null;
            decimal?lowestPrice = null;

            if (context == null)
            {
                context = CreatePriceCalculationContext(customer: customer);
            }

            foreach (var associatedProduct in associatedProducts)
            {
                var tmpPrice = GetFinalPrice(associatedProduct, customer, decimal.Zero, true, int.MaxValue, null, context);

                if (associatedProduct.LowestAttributeCombinationPrice.HasValue && associatedProduct.LowestAttributeCombinationPrice.Value < tmpPrice)
                {
                    tmpPrice = associatedProduct.LowestAttributeCombinationPrice.Value;
                }

                if (!lowestPrice.HasValue || tmpPrice < lowestPrice.Value)
                {
                    lowestPrice        = tmpPrice;
                    lowestPriceProduct = associatedProduct;
                }
            }

            if (lowestPriceProduct == null)
            {
                lowestPriceProduct = associatedProducts.FirstOrDefault();
            }

            return(lowestPrice);
        }
        /// <summary>
        /// Get the lowest possible price for a product.
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="context">Object with cargo data for better performance</param>
        /// <param name="displayFromMessage">Whether to display the from message.</param>
        /// <returns>The lowest price.</returns>
        public virtual decimal GetLowestPrice(Product product, PriceCalculationContext context, out bool displayFromMessage)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            if (product.ProductType == ProductType.GroupedProduct)
            {
                throw Error.InvalidOperation("Choose the other override for products of type grouped product.");
            }

            // note: attribute price adjustments were never regarded here cause of many reasons

            if (context == null)
            {
                context = CreatePriceCalculationContext();
            }

            bool isBundlePerItemPricing = (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing);

            displayFromMessage = isBundlePerItemPricing;

            var lowestPrice = GetFinalPrice(product, null, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue, null, context);

            if (product.LowestAttributeCombinationPrice.HasValue && product.LowestAttributeCombinationPrice.Value < lowestPrice)
            {
                lowestPrice        = product.LowestAttributeCombinationPrice.Value;
                displayFromMessage = true;
            }

            if (lowestPrice == decimal.Zero && product.Price == decimal.Zero)
            {
                lowestPrice = product.LowestAttributeCombinationPrice ?? decimal.Zero;
            }

            if (!displayFromMessage && product.ProductType != ProductType.BundledProduct)
            {
                var attributes = context.Attributes.Load(product.Id);
                displayFromMessage = attributes.Any(x => x.ProductVariantAttributeValues.Any(y => y.PriceAdjustment != decimal.Zero));
            }

            if (!displayFromMessage && product.HasTierPrices && !isBundlePerItemPricing)
            {
                var tierPrices = context.TierPrices.Load(product.Id)
                                 .RemoveDuplicatedQuantities();

                displayFromMessage = (tierPrices.Count > 0 && !(tierPrices.Count == 1 && tierPrices.First().Quantity <= 1));
            }

            return(lowestPrice);
        }
Пример #11
0
        public virtual decimal GetLowestPrice(Product product, Customer customer, PriceCalculationContext context, out bool displayFromMessage)
        {
            Guard.NotNull(product, nameof(product));

            if (product.ProductType == ProductType.GroupedProduct)
            {
                throw Error.InvalidOperation("Choose the other override for products of type grouped product.");
            }

            // Note, attribute price adjustments will not be taken into account here.
            if (context == null)
            {
                context = CreatePriceCalculationContext(customer: customer);
            }

            var isBundlePerItemPricing = product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing;
            var lowestPrice            = GetFinalPrice(product, null, customer, decimal.Zero, true, int.MaxValue, null, context);

            displayFromMessage = isBundlePerItemPricing;

            if (product.LowestAttributeCombinationPrice.HasValue)
            {
                if (product.LowestAttributeCombinationPrice.Value < lowestPrice)
                {
                    lowestPrice = product.LowestAttributeCombinationPrice.Value;
                }
                displayFromMessage = true;
            }

            if (lowestPrice == decimal.Zero && product.Price == decimal.Zero)
            {
                lowestPrice = product.LowestAttributeCombinationPrice ?? decimal.Zero;
            }

            if (!displayFromMessage && product.ProductType != ProductType.BundledProduct)
            {
                var attributes = context.Attributes.GetOrLoad(product.Id);
                displayFromMessage = attributes.Any(x => x.ProductVariantAttributeValues.Any(y => y.PriceAdjustment != decimal.Zero));
            }

            if (!displayFromMessage && product.HasTierPrices && !isBundlePerItemPricing)
            {
                var tierPrices = context.TierPrices.GetOrLoad(product.Id)
                                 .RemoveDuplicatedQuantities();

                displayFromMessage = tierPrices.Count > 0 && !(tierPrices.Count == 1 && tierPrices.First().Quantity <= 1);
            }

            return(lowestPrice);
        }
        public virtual decimal GetFinalPrice(
            Product product,
            Customer customer,
            decimal additionalCharge,
            bool includeDiscounts,
            int quantity,
            ProductBundleItemData bundleItem = null,
            PriceCalculationContext context  = null)
        {
            //initial price
            decimal result = product.Price;

            //special price
            var specialPrice = GetSpecialPrice(product);

            if (specialPrice.HasValue)
            {
                result = specialPrice.Value;
            }

            //tier prices
            if (product.HasTierPrices && !bundleItem.IsValid())
            {
                decimal?tierPrice = GetMinimumTierPrice(product, customer, quantity, context);
                if (tierPrice.HasValue)
                {
                    result = Math.Min(result, tierPrice.Value);
                }
            }

            //discount + additional charge
            if (includeDiscounts)
            {
                Discount appliedDiscount = null;
                decimal  discountAmount  = GetDiscountAmount(product, customer, additionalCharge, quantity, out appliedDiscount, bundleItem, context);
                result = result + additionalCharge - discountAmount;
            }
            else
            {
                result = result + additionalCharge;
            }

            if (result < decimal.Zero)
            {
                result = decimal.Zero;
            }

            return(result);
        }
Пример #13
0
        /// <summary>
        /// Gets allowed discounts
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <returns>Discounts</returns>
        protected virtual IList <Discount> GetAllowedDiscounts(Product product, Customer customer, PriceCalculationContext context = null)
        {
            var result = new List <Discount>();

            if (_catalogSettings.IgnoreDiscounts)
            {
                return(result);
            }

            // check discounts assigned to the product
            if (product.HasDiscountsApplied)
            {
                // We use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls
                IEnumerable <Discount> appliedDiscounts = null;

                if (context == null)
                {
                    appliedDiscounts = product.AppliedDiscounts;
                }
                else
                {
                    if (!context.AppliedDiscounts.FullyLoaded)
                    {
                        context.AppliedDiscounts.LoadAll();
                    }
                    appliedDiscounts = context.AppliedDiscounts.GetOrLoad(product.Id);
                }

                if (appliedDiscounts != null)
                {
                    foreach (var discount in appliedDiscounts)
                    {
                        if (discount.DiscountType == DiscountType.AssignedToSkus && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer))
                        {
                            result.Add(discount);
                        }
                    }
                }
            }

            // check discounts assigned to categories
            if (_discountService.GetAllDiscounts(DiscountType.AssignedToCategories).Any())
            {
                IEnumerable <ProductCategory> productCategories = null;

                if (context == null)
                {
                    productCategories = _categoryService.GetProductCategoriesByProductId(product.Id);
                }
                else
                {
                    productCategories = context.ProductCategories.GetOrLoad(product.Id);
                }

                if (productCategories != null)
                {
                    foreach (var productCategory in productCategories)
                    {
                        var category = productCategory.Category;
                        if (category.HasDiscountsApplied)
                        {
                            //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls
                            var categoryDiscounts = category.AppliedDiscounts;

                            foreach (var discount in categoryDiscounts)
                            {
                                if (discount.DiscountType == DiscountType.AssignedToCategories && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer))
                                {
                                    result.Add(discount);
                                }
                            }
                        }
                    }
                }
            }

            // check discounts assigned to manufacturers
            if (_discountService.GetAllDiscounts(DiscountType.AssignedToManufacturers).Any())
            {
                IEnumerable <ProductManufacturer> productManufacturers = null;

                if (context == null)
                {
                    productManufacturers = _manufacturerService.GetProductManufacturersByProductId(product.Id);
                }
                else
                {
                    productManufacturers = context.ProductManufacturers.GetOrLoad(product.Id);
                }

                if (productManufacturers != null)
                {
                    foreach (var productManufacturer in productManufacturers)
                    {
                        var manu = productManufacturer.Manufacturer;
                        if (manu.HasDiscountsApplied)
                        {
                            var manuDiscounts = manu.AppliedDiscounts;

                            foreach (var discount in manuDiscounts)
                            {
                                if (discount.DiscountType == DiscountType.AssignedToManufacturers && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer))
                                {
                                    result.Add(discount);
                                }
                            }
                        }
                    }
                }
            }

            return(result);
        }
Пример #14
0
        /// <summary>
        /// Get the initial price including preselected attributes
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="context">Object with cargo data for better performance</param>
        /// <returns>Preselected price</returns>
        public virtual decimal GetPreselectedPrice(Product product, PriceCalculationContext context)
        {
            if (product == null)
                throw new ArgumentNullException("product");

            var result = decimal.Zero;

            if (context == null)
                context = CreatePriceCalculationContext();

            if (product.ProductType == ProductType.BundledProduct)
            {
                var bundleItems = _productService.GetBundleItems(product.Id);

                var productIds = bundleItems.Select(x => x.Item.ProductId).ToList();
                productIds.Add(product.Id);

                context.Collect(productIds);

                foreach (var bundleItem in bundleItems.Where(x => x.Item.Product.CanBeBundleItem()))
                {
                    // fetch bundleItems.AdditionalCharge for all bundle items
                    var unused = GetPreselectedPrice(bundleItem.Item.Product, context, bundleItem, bundleItems);
                }

                result = GetPreselectedPrice(product, context, null, bundleItems);
            }
            else
            {
                result = GetPreselectedPrice(product, context, null, null);
            }

            return result;
        }
        /// <summary>
        /// Gets a tier price
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <param name="quantity">Quantity</param>
        /// <returns>Price</returns>
        protected virtual decimal?GetMinimumTierPrice(Product product, Customer customer, int quantity, PriceCalculationContext context = null)
        {
            if (!product.HasTierPrices)
            {
                return(decimal.Zero);
            }

            IEnumerable <TierPrice> tierPrices = null;

            if (context == null)
            {
                tierPrices = product.TierPrices
                             .OrderBy(tp => tp.Quantity)
                             .FilterByStore(_services.StoreContext.CurrentStore.Id)
                             .FilterForCustomer(customer)
                             .ToList()
                             .RemoveDuplicatedQuantities();
            }
            else
            {
                tierPrices = context.TierPrices.Load(product.Id)
                             .RemoveDuplicatedQuantities();
            }

            if (tierPrices == null)
            {
                return(decimal.Zero);
            }

            int     previousQty   = 1;
            decimal?previousPrice = null;

            foreach (var tierPrice in tierPrices)
            {
                //check quantity
                if (quantity < tierPrice.Quantity)
                {
                    continue;
                }
                if (tierPrice.Quantity < previousQty)
                {
                    continue;
                }

                //save new price
                previousPrice = tierPrice.Price;
                previousQty   = tierPrice.Quantity;
            }

            return(previousPrice);
        }
        protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationContext context, ProductBundleItemData bundleItem, IEnumerable <ProductBundleItemData> bundleItems)
        {
            var taxRate = decimal.Zero;
            var attributesTotalPriceBase       = decimal.Zero;
            var preSelectedPriceAdjustmentBase = decimal.Zero;
            var isBundle            = (product.ProductType == ProductType.BundledProduct);
            var isBundleItemPricing = (bundleItem != null && bundleItem.Item.BundleProduct.BundlePerItemPricing);
            var isBundlePricing     = (bundleItem != null && !bundleItem.Item.BundleProduct.BundlePerItemPricing);
            var bundleItemId        = (bundleItem == null ? 0 : bundleItem.Item.Id);

            var selectedAttributes      = new NameValueCollection();
            var selectedAttributeValues = new List <ProductVariantAttributeValue>();
            var attributes = context.Attributes.Load(product.Id);

            // 1. fill selectedAttributes with initially selected attributes
            foreach (var attribute in attributes.Where(x => x.ProductVariantAttributeValues.Count > 0 && x.ShouldHaveValues()))
            {
                int preSelectedValueId = 0;
                ProductVariantAttributeValue defaultValue = null;
                var selectedValueIds = new List <int>();
                var pvaValues        = attribute.ProductVariantAttributeValues;

                foreach (var pvaValue in pvaValues)
                {
                    ProductBundleItemAttributeFilter attributeFilter = null;

                    if (bundleItem.FilterOut(pvaValue, out attributeFilter))
                    {
                        continue;
                    }

                    if (preSelectedValueId == 0 && attributeFilter != null && attributeFilter.IsPreSelected)
                    {
                        preSelectedValueId = attributeFilter.AttributeValueId;
                    }

                    if (!isBundlePricing && pvaValue.IsPreSelected)
                    {
                        decimal attributeValuePriceAdjustment = GetProductVariantAttributeValuePriceAdjustment(pvaValue);
                        decimal priceAdjustmentBase           = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, out taxRate);

                        preSelectedPriceAdjustmentBase = decimal.Add(preSelectedPriceAdjustmentBase, priceAdjustmentBase);
                    }
                }

                // value pre-selected by a bundle item filter discards the default pre-selection
                if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null)
                {
                    //defaultValue.IsPreSelected = true;
                    selectedAttributeValues.Add(defaultValue);
                    selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId);
                }
                else
                {
                    foreach (var value in pvaValues.Where(x => x.IsPreSelected))
                    {
                        selectedAttributeValues.Add(value);
                        selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, value.Id, product.Id, bundleItemId);
                    }
                }
            }

            // 2. find attribute combination for selected attributes and merge it
            if (!isBundle && selectedAttributes.Count > 0)
            {
                var attributeXml = selectedAttributes.CreateSelectedAttributesXml(product.Id, attributes, _productAttributeParser, _services.Localization,
                                                                                  _downloadService, _catalogSettings, _httpRequestBase, new List <string>(), true, bundleItemId);

                var combinations = context.AttributeCombinations.Load(product.Id);

                var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml));

                if (selectedCombination != null && selectedCombination.IsActive && selectedCombination.Price.HasValue)
                {
                    product.MergedDataValues = new Dictionary <string, object> {
                        { "Price", selectedCombination.Price.Value }
                    };
                }
            }

            if (_catalogSettings.EnableDynamicPriceUpdate && !isBundlePricing)
            {
                if (selectedAttributeValues.Count > 0)
                {
                    selectedAttributeValues.Each(x => attributesTotalPriceBase += GetProductVariantAttributeValuePriceAdjustment(x));
                }
                else
                {
                    attributesTotalPriceBase = preSelectedPriceAdjustmentBase;
                }
            }

            if (bundleItem != null)
            {
                bundleItem.AdditionalCharge = attributesTotalPriceBase;
            }

            var result = GetFinalPrice(product, bundleItems, _services.WorkContext.CurrentCustomer, attributesTotalPriceBase, true, 1, bundleItem, context);

            return(result);
        }
Пример #17
0
        protected virtual decimal GetTierPriceAttributeAdjustment(Product product, Customer customer, int quantity, PriceCalculationContext context = null, decimal adjustment = 0)
        {
            if (!product.HasTierPrices)
            {
                return(decimal.Zero);
            }

            IEnumerable <TierPrice> tierPrices = null;

            if (context == null)
            {
                tierPrices = product.TierPrices
                             .OrderBy(tp => tp.Quantity)
                             .FilterByStore(_services.StoreContext.CurrentStore.Id)
                             .FilterForCustomer(customer)
                             .ToList()
                             .RemoveDuplicatedQuantities();
            }
            else
            {
                tierPrices = context.TierPrices.GetOrLoad(product.Id)
                             .RemoveDuplicatedQuantities();
            }

            if (tierPrices == null)
            {
                return(decimal.Zero);
            }

            int     previousQty   = 1;
            decimal previousPrice = 0;

            foreach (var tierPrice in tierPrices)
            {
                //check quantity
                if (quantity < tierPrice.Quantity)
                {
                    continue;
                }
                if (tierPrice.Quantity < previousQty)
                {
                    continue;
                }

                //save new price
                if (tierPrice.CalculationMethod == TierPriceCalculationMethod.Percental && _catalogSettings.ApplyTierPricePercentageToAttributePriceAdjustments)
                {
                    previousPrice = adjustment - (adjustment / 100 * tierPrice.Price);
                }

                previousQty = tierPrice.Quantity;
            }

            return(previousPrice);
        }
Пример #18
0
        protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationContext context, ProductBundleItemData bundleItem, IEnumerable<ProductBundleItemData> bundleItems)
        {
            var taxRate = decimal.Zero;
            var attributesTotalPriceBase = decimal.Zero;
            var preSelectedPriceAdjustmentBase = decimal.Zero;
            var isBundle = (product.ProductType == ProductType.BundledProduct);
            var isBundleItemPricing = (bundleItem != null && bundleItem.Item.BundleProduct.BundlePerItemPricing);
            var isBundlePricing = (bundleItem != null && !bundleItem.Item.BundleProduct.BundlePerItemPricing);
            var bundleItemId = (bundleItem == null ? 0 : bundleItem.Item.Id);

            var selectedAttributes = new NameValueCollection();
            var selectedAttributeValues = new List<ProductVariantAttributeValue>();
            var attributes = context.Attributes.Load(product.Id);

            // 1. fill selectedAttributes with initially selected attributes
            foreach (var attribute in attributes.Where(x => x.ProductVariantAttributeValues.Count > 0 && x.ShouldHaveValues()))
            {
                int preSelectedValueId = 0;
                ProductVariantAttributeValue defaultValue = null;
                var selectedValueIds = new List<int>();
                var pvaValues = attribute.ProductVariantAttributeValues;

                foreach (var pvaValue in pvaValues)
                {
                    ProductBundleItemAttributeFilter attributeFilter = null;

                    if (bundleItem.FilterOut(pvaValue, out attributeFilter))
                        continue;

                    if (preSelectedValueId == 0 && attributeFilter != null && attributeFilter.IsPreSelected)
                        preSelectedValueId = attributeFilter.AttributeValueId;

                    if (!isBundlePricing && pvaValue.IsPreSelected)
                    {
                        decimal attributeValuePriceAdjustment = GetProductVariantAttributeValuePriceAdjustment(pvaValue);
                        decimal priceAdjustmentBase = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, out taxRate);

                        preSelectedPriceAdjustmentBase = decimal.Add(preSelectedPriceAdjustmentBase, priceAdjustmentBase);
                    }
                }

                // value pre-selected by a bundle item filter discards the default pre-selection
                if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null)
                {
                    //defaultValue.IsPreSelected = true;
                    selectedAttributeValues.Add(defaultValue);
                    selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId);
                }
                else
                {
                    foreach (var value in pvaValues.Where(x => x.IsPreSelected))
                    {
                        selectedAttributeValues.Add(value);
                        selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, value.Id, product.Id, bundleItemId);
                    }
                }
            }

            // 2. find attribute combination for selected attributes and merge it
            if (!isBundle && selectedAttributes.Count > 0)
            {
                string attributeXml = selectedAttributes.CreateSelectedAttributesXml(product.Id, attributes, _productAttributeParser, _services.Localization,
                    _downloadService, _catalogSettings, _httpRequestBase, new List<string>(), true, bundleItemId);

                var combinations = context.AttributeCombinations.Load(product.Id);

                var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml, attributes));

                if (selectedCombination != null && selectedCombination.IsActive && selectedCombination.Price.HasValue)
                {
                    product.MergedDataValues = new Dictionary<string, object> { { "Price", selectedCombination.Price.Value } };
                }
            }

            if (_catalogSettings.EnableDynamicPriceUpdate && !isBundlePricing)
            {
                if (selectedAttributeValues.Count > 0)
                {
                    selectedAttributeValues.Each(x => attributesTotalPriceBase += GetProductVariantAttributeValuePriceAdjustment(x));
                }
                else
                {
                    attributesTotalPriceBase = preSelectedPriceAdjustmentBase;
                }
            }

            if (bundleItem != null)
            {
                bundleItem.AdditionalCharge = attributesTotalPriceBase;
            }

            var result = GetFinalPrice(product, bundleItems, _services.WorkContext.CurrentCustomer, attributesTotalPriceBase, true, 1, bundleItem, context);
            return result;
        }
        /// <summary>
        /// Gets allowed discounts
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <returns>Discounts</returns>
        protected virtual IList <Discount> GetAllowedDiscounts(Product product, Customer customer, PriceCalculationContext context = null)
        {
            var result = new List <Discount>();

            if (_catalogSettings.IgnoreDiscounts)
            {
                return(result);
            }

            if (product.HasDiscountsApplied)
            {
                //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls
                IEnumerable <Discount> appliedDiscounts = null;

                if (context == null)
                {
                    appliedDiscounts = product.AppliedDiscounts;
                }
                else
                {
                    appliedDiscounts = context.AppliedDiscounts.Load(product.Id);
                }

                if (appliedDiscounts != null)
                {
                    foreach (var discount in appliedDiscounts)
                    {
                        if (discount.DiscountType == DiscountType.AssignedToSkus && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer))
                        {
                            result.Add(discount);
                        }
                    }
                }
            }

            //performance optimization. load all category discounts just to ensure that we have at least one
            if (_discountService.GetAllDiscounts(DiscountType.AssignedToCategories).Any())
            {
                IEnumerable <ProductCategory> productCategories = null;

                if (context == null)
                {
                    productCategories = _categoryService.GetProductCategoriesByProductId(product.Id);
                }
                else
                {
                    productCategories = context.ProductCategories.Load(product.Id);
                }

                if (productCategories != null)
                {
                    foreach (var productCategory in productCategories)
                    {
                        var category = productCategory.Category;

                        if (category.HasDiscountsApplied)
                        {
                            //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls
                            var categoryDiscounts = category.AppliedDiscounts;

                            foreach (var discount in categoryDiscounts)
                            {
                                if (discount.DiscountType == DiscountType.AssignedToCategories && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer))
                                {
                                    result.Add(discount);
                                }
                            }
                        }
                    }
                }
            }

            return(result);
        }
Пример #20
0
        public virtual decimal GetDiscountAmount(
			Product product,
            Customer customer,
            decimal additionalCharge,
            int quantity,
            out Discount appliedDiscount,
			ProductBundleItemData bundleItem = null,
			PriceCalculationContext context = null)
        {
            appliedDiscount = null;
            decimal appliedDiscountAmount = decimal.Zero;
            decimal finalPriceWithoutDiscount = decimal.Zero;

            if (bundleItem.IsValid())
            {
                if (bundleItem.Item.Discount.HasValue && bundleItem.Item.BundleProduct.BundlePerItemPricing)
                {
                    appliedDiscount = new Discount
                    {
                        UsePercentage = bundleItem.Item.DiscountPercentage,
                        DiscountPercentage = bundleItem.Item.Discount.Value,
                        DiscountAmount = bundleItem.Item.Discount.Value
                    };

                    finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem, context);
                    appliedDiscountAmount = appliedDiscount.GetDiscountAmount(finalPriceWithoutDiscount);
                }
            }
            else
            {
                // dont't apply when customer entered price or discounts should be ignored completely
                if (product.CustomerEntersPrice || _catalogSettings.IgnoreDiscounts)
                {
                    return appliedDiscountAmount;
                }

                var allowedDiscounts = GetAllowedDiscounts(product, customer, context);
                if (allowedDiscounts.Count == 0)
                {
                    return appliedDiscountAmount;
                }

                finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem, context);
                appliedDiscount = allowedDiscounts.GetPreferredDiscount(finalPriceWithoutDiscount);

                if (appliedDiscount != null)
                {
                    appliedDiscountAmount = appliedDiscount.GetDiscountAmount(finalPriceWithoutDiscount);
                }
            }

            return appliedDiscountAmount;
        }
Пример #21
0
        /// <summary>
        /// Gets the price adjustment of a variant attribute value
        /// </summary>
        /// <param name="attributeValue">Product variant attribute value</param>
        /// <returns>Price adjustment of a variant attribute value</returns>
        public virtual decimal GetProductVariantAttributeValuePriceAdjustment(ProductVariantAttributeValue attributeValue,
                                                                              Product product, Customer customer, PriceCalculationContext context, int productQuantity = 1)
        {
            Guard.NotNull(attributeValue, nameof(attributeValue));

            if (attributeValue.ValueType == ProductVariantAttributeValueType.Simple)
            {
                if (productQuantity > 1 && attributeValue.PriceAdjustment > 0)
                {
                    var tierPriceAttributeAdjustment = GetTierPriceAttributeAdjustment(product, customer, productQuantity, context, attributeValue.PriceAdjustment);
                    if (tierPriceAttributeAdjustment != 0)
                    {
                        return(tierPriceAttributeAdjustment);
                    }
                }

                return(attributeValue.PriceAdjustment);
            }

            if (attributeValue.ValueType == ProductVariantAttributeValueType.ProductLinkage)
            {
                var linkedProduct = _productService.GetProductById(attributeValue.LinkedProductId);

                if (linkedProduct != null)
                {
                    var productPrice = GetFinalPrice(linkedProduct, true) * attributeValue.Quantity;
                    return(productPrice);
                }
            }

            return(decimal.Zero);
        }
Пример #22
0
        public virtual decimal? GetLowestPrice(Product product, PriceCalculationContext context, IEnumerable<Product> associatedProducts, out Product lowestPriceProduct)
        {
            if (product == null)
                throw new ArgumentNullException("product");

            if (associatedProducts == null)
                throw new ArgumentNullException("associatedProducts");

            if (product.ProductType != ProductType.GroupedProduct)
                throw Error.InvalidOperation("Choose the other override for products not of type grouped product.");

            lowestPriceProduct = null;
            decimal? lowestPrice = null;
            var customer = _services.WorkContext.CurrentCustomer;

            if (context == null)
                context = CreatePriceCalculationContext();

            foreach (var associatedProduct in associatedProducts)
            {
                var tmpPrice = GetFinalPrice(associatedProduct, customer, decimal.Zero, true, int.MaxValue, null, context);

                if (associatedProduct.LowestAttributeCombinationPrice.HasValue && associatedProduct.LowestAttributeCombinationPrice.Value < tmpPrice)
                {
                    tmpPrice = associatedProduct.LowestAttributeCombinationPrice.Value;
                }

                if (!lowestPrice.HasValue || tmpPrice < lowestPrice.Value)
                {
                    lowestPrice = tmpPrice;
                    lowestPriceProduct = associatedProduct;
                }
            }

            if (lowestPriceProduct == null)
                lowestPriceProduct = associatedProducts.FirstOrDefault();

            return lowestPrice;
        }
Пример #23
0
        protected virtual decimal GetPreselectedPrice(
            Product product,
            Customer customer,
            Currency currency,
            PriceCalculationContext context,
            ProductBundleItemData bundleItem,
            IEnumerable <ProductBundleItemData> bundleItems)
        {
            var taxRate = decimal.Zero;
            var attributesTotalPriceBase       = decimal.Zero;
            var preSelectedPriceAdjustmentBase = decimal.Zero;
            var isBundle            = product.ProductType == ProductType.BundledProduct;
            var isBundleItemPricing = bundleItem != null && bundleItem.Item.BundleProduct.BundlePerItemPricing;
            var isBundlePricing     = bundleItem != null && !bundleItem.Item.BundleProduct.BundlePerItemPricing;
            var bundleItemId        = bundleItem == null ? 0 : bundleItem.Item.Id;

            var query = new ProductVariantQuery();
            var selectedAttributeValues = new List <ProductVariantAttributeValue>();
            var attributes = context.Attributes.GetOrLoad(product.Id);

            // 1. Fill query with initially selected attributes.
            foreach (var attribute in attributes.Where(x => x.ProductVariantAttributeValues.Any() && x.ShouldHaveValues()))
            {
                int preSelectedValueId = 0;
                ProductVariantAttributeValue defaultValue = null;
                var selectedValueIds = new List <int>();
                var pvaValues        = attribute.ProductVariantAttributeValues;

                foreach (var pvaValue in pvaValues)
                {
                    ProductBundleItemAttributeFilter attributeFilter = null;

                    if (bundleItem?.Item?.FilterOut(pvaValue, out attributeFilter) ?? false)
                    {
                        continue;
                    }

                    if (preSelectedValueId == 0 && attributeFilter != null && attributeFilter.IsPreSelected)
                    {
                        preSelectedValueId = attributeFilter.AttributeValueId;
                    }

                    if (!isBundlePricing && pvaValue.IsPreSelected)
                    {
                        var includingTax = _services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax;
                        var attributeValuePriceAdjustment = GetProductVariantAttributeValuePriceAdjustment(pvaValue, product, customer, context, 1);
                        var priceAdjustmentBase           = _taxService.GetProductPrice(product, product.TaxCategoryId, attributeValuePriceAdjustment,
                                                                                        includingTax, customer, currency, _taxSettings.PricesIncludeTax, out taxRate);

                        preSelectedPriceAdjustmentBase = decimal.Add(preSelectedPriceAdjustmentBase, priceAdjustmentBase);
                    }
                }

                // Value pre-selected by a bundle item filter discards the default pre-selection.
                if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null)
                {
                    //defaultValue.IsPreSelected = true;
                    selectedAttributeValues.Add(defaultValue);
                    query.AddVariant(new ProductVariantQueryItem(defaultValue.Id.ToString())
                    {
                        ProductId          = product.Id,
                        BundleItemId       = bundleItemId,
                        AttributeId        = attribute.ProductAttributeId,
                        VariantAttributeId = attribute.Id,
                        Alias      = attribute.ProductAttribute.Alias,
                        ValueAlias = defaultValue.Alias
                    });
                }
                else
                {
                    foreach (var value in pvaValues.Where(x => x.IsPreSelected))
                    {
                        selectedAttributeValues.Add(value);
                        query.AddVariant(new ProductVariantQueryItem(value.Id.ToString())
                        {
                            ProductId          = product.Id,
                            BundleItemId       = bundleItemId,
                            AttributeId        = attribute.ProductAttributeId,
                            VariantAttributeId = attribute.Id,
                            Alias      = attribute.ProductAttribute.Alias,
                            ValueAlias = value.Alias
                        });
                    }
                }
            }

            // 2. Find attribute combination for selected attributes and merge it.
            if (!isBundle && query.Variants.Any())
            {
                var attributeXml = query.CreateSelectedAttributesXml(product.Id, bundleItemId, attributes, _productAttributeParser, _services.Localization,
                                                                     _downloadService, _catalogSettings, _httpRequestBase, new List <string>());

                var combinations = context.AttributeCombinations.GetOrLoad(product.Id);

                var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml));

                if (selectedCombination != null && selectedCombination.IsActive && selectedCombination.Price.HasValue)
                {
                    product.MergedDataValues = new Dictionary <string, object> {
                        { "Price", selectedCombination.Price.Value }
                    };

                    if (selectedCombination.BasePriceAmount.HasValue)
                    {
                        product.MergedDataValues.Add("BasePriceAmount", selectedCombination.BasePriceAmount.Value);
                    }

                    if (selectedCombination.BasePriceBaseAmount.HasValue)
                    {
                        product.MergedDataValues.Add("BasePriceBaseAmount", selectedCombination.BasePriceBaseAmount.Value);
                    }
                }
            }

            if (_catalogSettings.EnableDynamicPriceUpdate && !isBundlePricing)
            {
                if (selectedAttributeValues.Count > 0)
                {
                    selectedAttributeValues.Each(x => attributesTotalPriceBase += GetProductVariantAttributeValuePriceAdjustment(x, product, customer, context, 1));
                }
                else
                {
                    attributesTotalPriceBase = preSelectedPriceAdjustmentBase;
                }
            }

            if (bundleItem != null)
            {
                bundleItem.AdditionalCharge = attributesTotalPriceBase;
            }

            var result = GetFinalPrice(product, bundleItems, customer, attributesTotalPriceBase, true, 1, bundleItem, context);

            return(result);
        }
Пример #24
0
        public virtual decimal GetFinalPrice(
			Product product, 
			IEnumerable<ProductBundleItemData> bundleItems,
			Customer customer, 
			decimal additionalCharge, 
			bool includeDiscounts, 
			int quantity, 
			ProductBundleItemData bundleItem = null,
			PriceCalculationContext context = null)
        {
            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)
            {
                decimal result = decimal.Zero;
                var items = bundleItems ?? _productService.GetBundleItems(product.Id);

                foreach (var itemData in items.Where(x => x.IsValid()))
                {
                    decimal itemPrice = GetFinalPrice(itemData.Item.Product, customer, itemData.AdditionalCharge, includeDiscounts, 1, itemData, context);

                    result = result + decimal.Multiply(itemPrice, itemData.Item.Quantity);
                }

                return (result < decimal.Zero ? decimal.Zero : result);
            }
            return GetFinalPrice(product, customer, additionalCharge, includeDiscounts, quantity, bundleItem, context);
        }
Пример #25
0
        public virtual decimal GetFinalPrice(
			Product product, 
            Customer customer,
            decimal additionalCharge, 
            bool includeDiscounts, 
            int quantity,
			ProductBundleItemData bundleItem = null,
			PriceCalculationContext context = null)
        {
            //initial price
            decimal result = product.Price;

            //special price
            var specialPrice = GetSpecialPrice(product);
            if (specialPrice.HasValue)
                result = specialPrice.Value;

            //tier prices
            if (product.HasTierPrices && !bundleItem.IsValid())
            {
                decimal? tierPrice = GetMinimumTierPrice(product, customer, quantity, context);
                if (tierPrice.HasValue)
                    result = Math.Min(result, tierPrice.Value);
            }

            //discount + additional charge
            if (includeDiscounts)
            {
                Discount appliedDiscount = null;
                decimal discountAmount = GetDiscountAmount(product, customer, additionalCharge, quantity, out appliedDiscount, bundleItem, context);
                result = result + additionalCharge - discountAmount;
            }
            else
            {
                result = result + additionalCharge;
            }

            if (result < decimal.Zero)
                result = decimal.Zero;

            return result;
        }
Пример #26
0
        /// <summary>
        /// Gets allowed discounts
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <returns>Discounts</returns>
        protected virtual IList<Discount> GetAllowedDiscounts(Product product, Customer customer, PriceCalculationContext context = null)
        {
            var result = new List<Discount>();
            if (_catalogSettings.IgnoreDiscounts)
                return result;

            if (product.HasDiscountsApplied)
            {
                //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls
                foreach (var discount in product.AppliedDiscounts)
                {
                    if (discount.DiscountType == DiscountType.AssignedToSkus && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer))
                    {
                        result.Add(discount);
                    }
                }
            }

            //performance optimization. load all category discounts just to ensure that we have at least one
            if (_discountService.GetAllDiscounts(DiscountType.AssignedToCategories).Any())
            {
                IEnumerable<ProductCategory> productCategories = null;

                if (context == null)
                    productCategories = _categoryService.GetProductCategoriesByProductId(product.Id);
                else
                    productCategories = context.ProductCategories.Load(product.Id);

                if (productCategories != null)
                {
                    foreach (var productCategory in productCategories)
                    {
                        var category = productCategory.Category;

                        if (category.HasDiscountsApplied)
                        {
                            //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls
                            var categoryDiscounts = category.AppliedDiscounts;

                            foreach (var discount in categoryDiscounts)
                            {
                                if (discount.DiscountType == DiscountType.AssignedToCategories && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer))
                                {
                                    result.Add(discount);
                                }
                            }
                        }
                    }
                }
            }

            return result;
        }
Пример #27
0
        /// <summary>
        /// Gets a tier price
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <param name="quantity">Quantity</param>
        /// <returns>Price</returns>
        protected virtual decimal? GetMinimumTierPrice(Product product, Customer customer, int quantity, PriceCalculationContext context = null)
        {
            if (!product.HasTierPrices)
                return decimal.Zero;

            IEnumerable<TierPrice> tierPrices = null;

            if (context == null)
            {
                tierPrices = product.TierPrices
                    .OrderBy(tp => tp.Quantity)
                    .FilterByStore(_services.StoreContext.CurrentStore.Id)
                    .FilterForCustomer(customer)
                    .ToList()
                    .RemoveDuplicatedQuantities();
            }
            else
            {
                tierPrices = context.TierPrices.Load(product.Id);
            }

            if (tierPrices == null)
                return decimal.Zero;

            int previousQty = 1;
            decimal? previousPrice = null;

            foreach (var tierPrice in tierPrices)
            {
                //check quantity
                if (quantity < tierPrice.Quantity)
                    continue;
                if (tierPrice.Quantity < previousQty)
                    continue;

                //save new price
                previousPrice = tierPrice.Price;
                previousQty = tierPrice.Quantity;
            }

            return previousPrice;
        }
Пример #28
0
        /// <summary>
        /// Get the lowest possible price for a product.
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="context">Object with cargo data for better performance</param>
        /// <param name="displayFromMessage">Whether to display the from message.</param>
        /// <returns>The lowest price.</returns>
        public virtual decimal GetLowestPrice(Product product, PriceCalculationContext context, out bool displayFromMessage)
        {
            if (product == null)
                throw new ArgumentNullException("product");

            if (product.ProductType == ProductType.GroupedProduct)
                throw Error.InvalidOperation("Choose the other override for products of type grouped product.");

            // note: attribute price adjustments were never regarded here cause of many reasons

            if (context == null)
                context = CreatePriceCalculationContext();

            bool isBundlePerItemPricing = (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing);

            displayFromMessage = isBundlePerItemPricing;

            var lowestPrice = GetFinalPrice(product, null, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue, null, context);

            if (product.LowestAttributeCombinationPrice.HasValue && product.LowestAttributeCombinationPrice.Value < lowestPrice)
            {
                lowestPrice = product.LowestAttributeCombinationPrice.Value;
                displayFromMessage = true;
            }

            if (lowestPrice == decimal.Zero && product.Price == decimal.Zero)
            {
                lowestPrice = product.LowestAttributeCombinationPrice ?? decimal.Zero;
            }

            if (!displayFromMessage && product.ProductType != ProductType.BundledProduct)
            {
                var attributes = context.Attributes.Load(product.Id);
                displayFromMessage = attributes.Any(x => x.ProductVariantAttributeValues.Any(y => y.PriceAdjustment != decimal.Zero));
            }

            if (!displayFromMessage && product.HasTierPrices && !isBundlePerItemPricing)
            {
                var tierPrices = context.TierPrices.Load(product.Id);

                displayFromMessage = (tierPrices.Count > 0 && !(tierPrices.Count == 1 && tierPrices.First().Quantity <= 1));
            }

            return lowestPrice;
        }
Пример #29
0
        public virtual decimal GetPreselectedPrice(Product product, Customer customer, Currency currency, PriceCalculationContext context)
        {
            Guard.NotNull(product, nameof(product));

            var result = decimal.Zero;

            if (context == null)
            {
                context = CreatePriceCalculationContext(customer: customer);
            }

            if (product.ProductType == ProductType.BundledProduct)
            {
                var bundleItems = context.ProductBundleItems
                                  .GetOrLoad(product.Id)
                                  .Select(x => new ProductBundleItemData(x))
                                  .ToList();

                var productIds = bundleItems.Select(x => x.Item.ProductId).ToList();
                productIds.Add(product.Id);
                context.Collect(productIds);

                // Fetch bundleItems.AdditionalCharge for all bundle items.
                foreach (var bundleItem in bundleItems.Where(x => x.Item.Product.CanBeBundleItem()))
                {
                    var unused = GetPreselectedPrice(bundleItem.Item.Product, customer, currency, context, bundleItem, bundleItems);
                }

                result = GetPreselectedPrice(product, customer, currency, context, null, bundleItems);
            }
            else
            {
                result = GetPreselectedPrice(product, customer, currency, context, null, null);
            }

            return(result);
        }