Esempio n. 1
0
        /// <summary>
        /// Formats the price
        /// </summary>
        /// <param name="price">Price</param>
        /// <param name="showCurrency">A value indicating whether to show a currency</param>
        /// <param name="targetCurrency">Target currency</param>
        /// <param name="language">Language</param>
        /// <param name="priceIncludesTax">A value indicating whether price includes tax</param>
        /// <param name="showTax">A value indicating whether to show tax suffix</param>
        /// <returns>Price</returns>
        public string FormatPrice(decimal price, bool showCurrency,
                                  Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax)
        {
            //round before rendering
            //should we use RoundingHelper.RoundPrice here?
            price = RoundingHelper.RoundPrice(price, targetCurrency);

            string currencyString = GetCurrencyString(price, showCurrency, targetCurrency);

            if (showTax)
            {
                //show tax suffix
                string formatStr;
                if (priceIncludesTax)
                {
                    formatStr = _localizationService.GetResource("Products.InclTaxSuffix", language.Id, false);
                    if (String.IsNullOrEmpty(formatStr))
                    {
                        formatStr = "{0} incl tax";
                    }
                }
                else
                {
                    formatStr = _localizationService.GetResource("Products.ExclTaxSuffix", language.Id, false);
                    if (String.IsNullOrEmpty(formatStr))
                    {
                        formatStr = "{0} excl tax";
                    }
                }
                return(string.Format(formatStr, currencyString));
            }

            return(currencyString);
        }
        /// <summary>
        /// Gets the shopping cart unit price (one item)
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="quantity">Quantity</param>
        /// <param name="attributesXml">Product atrributes (XML format)</param>
        /// <param name="customerEnteredPrice">Customer entered price (if specified)</param>
        /// <param name="rentalStartDate">Rental start date (null for not rental products)</param>
        /// <param name="rentalEndDate">Rental end date (null for not rental products)</param>
        /// <param name="includeDiscounts">A value indicating whether include discounts or not for price computation</param>
        /// <param name="discountAmount">Applied discount amount</param>
        /// <param name="appliedDiscount">Applied discount</param>
        /// <returns>Shopping cart unit price (one item)</returns>
        public virtual async Task <(decimal unitprice, decimal discountAmount, List <AppliedDiscount> appliedDiscounts)> GetUnitPrice(Product product,
                                                                                                                                      Customer customer,
                                                                                                                                      ShoppingCartType shoppingCartType,
                                                                                                                                      int quantity,
                                                                                                                                      string attributesXml,
                                                                                                                                      decimal customerEnteredPrice,
                                                                                                                                      DateTime?rentalStartDate, DateTime?rentalEndDate,
                                                                                                                                      bool includeDiscounts)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

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

            var discountAmount   = decimal.Zero;
            var appliedDiscounts = new List <AppliedDiscount>();

            decimal?finalPrice = null;

            if (shoppingCartType == ShoppingCartType.Auctions && product.ProductType == ProductType.Auction)
            {
                finalPrice = customerEnteredPrice;
            }

            if (!finalPrice.HasValue)
            {
                var combination = _productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    if (combination.OverriddenPrice.HasValue)
                    {
                        finalPrice = combination.OverriddenPrice.Value;
                    }
                    if (combination.TierPrices.Any())
                    {
                        var storeId          = _storeContext.CurrentStore.Id;
                        var actualTierPrices = combination.TierPrices.Where(x => string.IsNullOrEmpty(x.StoreId) || x.StoreId == storeId)
                                               .Where(x => string.IsNullOrEmpty(x.CustomerRoleId) ||
                                                      customer.CustomerRoles.Where(role => role.Active).Select(role => role.Id).Contains(x.CustomerRoleId)).ToList();
                        var tierPrice = actualTierPrices.LastOrDefault(price => quantity >= price.Quantity);
                        if (tierPrice != null)
                        {
                            finalPrice = tierPrice.Price;
                        }
                    }
                }
            }
            if (!finalPrice.HasValue)
            {
                //summarize price of all attributes
                decimal attributesTotalPrice = decimal.Zero;
                var     attributeValues      = _productAttributeParser.ParseProductAttributeValues(product, attributesXml);
                if (attributeValues != null)
                {
                    foreach (var attributeValue in attributeValues)
                    {
                        attributesTotalPrice += await GetProductAttributeValuePriceAdjustment(attributeValue);
                    }
                }

                //get price of a product (with previously calculated price of all attributes)
                if (product.CustomerEntersPrice)
                {
                    finalPrice = customerEnteredPrice;
                }
                else
                {
                    int qty;
                    if (_shoppingCartSettings.GroupTierPricesForDistinctShoppingCartItems)
                    {
                        //the same products with distinct product attributes could be stored as distinct "ShoppingCartItem" records
                        //so let's find how many of the current products are in the cart
                        qty = customer.ShoppingCartItems
                              .Where(x => x.ProductId == product.Id)
                              .Where(x => x.ShoppingCartType == shoppingCartType)
                              .Sum(x => x.Quantity);
                        if (qty == 0)
                        {
                            qty = quantity;
                        }
                    }
                    else
                    {
                        qty = quantity;
                    }
                    var getfinalPrice = await GetFinalPrice(product,
                                                            customer,
                                                            attributesTotalPrice,
                                                            includeDiscounts,
                                                            qty,
                                                            product.ProductType == ProductType.Reservation?rentalStartDate : null,
                                                            product.ProductType == ProductType.Reservation?rentalEndDate : null);

                    finalPrice       = getfinalPrice.finalPrice;
                    discountAmount   = getfinalPrice.discountAmount;
                    appliedDiscounts = getfinalPrice.appliedDiscounts;
                }
            }

            if (!finalPrice.HasValue)
            {
                finalPrice = 0;
            }

            //rounding
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                var primaryCurrency = await _currencyService.GetPrimaryExchangeRateCurrency();

                finalPrice = RoundingHelper.RoundPrice(finalPrice.Value, primaryCurrency);
            }
            return(finalPrice.Value, discountAmount, appliedDiscounts);
        }
Esempio n. 3
0
        /// <summary>
        /// Gets the final price
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">The customer</param>
        /// <param name="additionalCharge">Additional charge</param>
        /// <param name="includeDiscounts">A value indicating whether include discounts or not for final price computation</param>
        /// <param name="quantity">Shopping cart item quantity</param>
        /// <param name="rentalStartDate">Rental period start date (for rental products)</param>
        /// <param name="rentalEndDate">Rental period end date (for rental products)</param>
        /// <param name="discountAmount">Applied discount amount</param>
        /// <param name="appliedDiscount">Applied discount</param>
        /// <returns>Final price</returns>
        public virtual decimal GetFinalPrice(Product product,
                                             Customer customer,
                                             decimal additionalCharge,
                                             bool includeDiscounts,
                                             int quantity,
                                             DateTime?rentalStartDate,
                                             DateTime?rentalEndDate,
                                             out decimal discountAmount,
                                             out List <AppliedDiscount> appliedDiscounts)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            discountAmount   = decimal.Zero;
            appliedDiscounts = new List <AppliedDiscount>();

            var cacheKey = string.Format(PriceCacheEventConsumer.PRODUCT_PRICE_MODEL_KEY,
                                         product.Id,
                                         additionalCharge.ToString(CultureInfo.InvariantCulture),
                                         includeDiscounts,
                                         quantity,
                                         string.Join(",", customer.GetCustomerRoleIds()),
                                         _storeContext.CurrentStore.Id);
            var cacheTime = _catalogSettings.CacheProductPrices ? 60 : 0;

            //we do not cache price for reservation products
            //otherwise, it can cause memory leaks (to store all possible date period combinations)
            if (product.ProductType == ProductType.Reservation)
            {
                cacheTime = 0;
            }

            ProductPriceForCaching PrepareModel()
            {
                var result = new ProductPriceForCaching();

                //initial price
                decimal price = product.Price;

                //customer product price
                var customerPrice = _customerService.GetPriceByCustomerProduct(customer.Id, product.Id);

                if (customerPrice.HasValue && customerPrice.Value < price)
                {
                    price = customerPrice.Value;
                }

                //tier prices
                var tierPrice = product.GetPreferredTierPrice(customer, _storeContext.CurrentStore.Id, quantity);

                if (tierPrice != null)
                {
                    price = tierPrice.Price;
                }

                //additional charge
                price = price + additionalCharge;

                //reservations
                if (product.ProductType == ProductType.Reservation)
                {
                    if (rentalStartDate.HasValue && rentalEndDate.HasValue)
                    {
                        decimal d = 0;
                        if (product.IncBothDate)
                        {
                            decimal.TryParse(((rentalEndDate - rentalStartDate).Value.TotalDays + 1).ToString(), out d);
                        }
                        else
                        {
                            decimal.TryParse((rentalEndDate - rentalStartDate).Value.TotalDays.ToString(), out d);
                        }
                        price = price * d;
                    }
                }

                if (includeDiscounts)
                {
                    //discount
                    List <AppliedDiscount> tmpAppliedDiscounts;
                    decimal tmpDiscountAmount = GetDiscountAmount(product, customer, price, out tmpAppliedDiscounts);
                    price = price - tmpDiscountAmount;

                    if (tmpAppliedDiscounts != null)
                    {
                        result.AppliedDiscountIds    = tmpAppliedDiscounts.Select(x => x.DiscountId).ToList();
                        result.AppliedDiscountAmount = tmpDiscountAmount;
                    }
                }

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

                //rounding
                if (_shoppingCartSettings.RoundPricesDuringCalculation)
                {
                    var primaryCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryExchangeRateCurrencyId);
                    result.Price = RoundingHelper.RoundPrice(price, primaryCurrency);
                }
                else
                {
                    result.Price = price;
                }

                return(result);
            }

            var cachedPrice = cacheTime > 0 ? _cacheManager.Get(cacheKey, cacheTime, () => { return(PrepareModel()); }) : PrepareModel();

            if (includeDiscounts)
            {
                foreach (var appliedDiscountId in cachedPrice.AppliedDiscountIds)
                {
                    var appliedDiscount = _discountService.GetDiscountById(appliedDiscountId);
                    if (appliedDiscount != null)
                    {
                        appliedDiscounts.Add(new AppliedDiscount()
                        {
                            DiscountId = appliedDiscount.Id, IsCumulative = appliedDiscount.IsCumulative
                        });
                    }
                }
                if (appliedDiscounts.Any())
                {
                    discountAmount = cachedPrice.AppliedDiscountAmount;
                }
            }

            return(cachedPrice.Price);
        }
        /// <summary>
        /// Gets the final price
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">The customer</param>
        /// <param name="additionalCharge">Additional charge</param>
        /// <param name="includeDiscounts">A value indicating whether include discounts or not for final price computation</param>
        /// <param name="quantity">Shopping cart item quantity</param>
        /// <param name="rentalStartDate">Rental period start date (for rental products)</param>
        /// <param name="rentalEndDate">Rental period end date (for rental products)</param>
        /// <param name="discountAmount">Applied discount amount</param>
        /// <param name="appliedDiscount">Applied discount</param>
        /// <returns>Final price</returns>
        public virtual async Task <(decimal finalPrice, decimal discountAmount, List <AppliedDiscount> appliedDiscounts, TierPrice preferredTierPrice)> GetFinalPrice(Product product,
                                                                                                                                                                      Customer customer,
                                                                                                                                                                      decimal additionalCharge,
                                                                                                                                                                      bool includeDiscounts,
                                                                                                                                                                      int quantity,
                                                                                                                                                                      DateTime?rentalStartDate,
                                                                                                                                                                      DateTime?rentalEndDate)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            var discountAmount   = decimal.Zero;
            var appliedDiscounts = new List <AppliedDiscount>();

            async Task <ProductPriceForCaching> PrepareModel()
            {
                var result = new ProductPriceForCaching();

                //initial price
                decimal price = product.Price;

                //tier prices
                var tierPrice = product.GetPreferredTierPrice(customer, _storeContext.CurrentStore.Id, quantity);

                if (tierPrice != null)
                {
                    price = tierPrice.Price;
                    result.PreferredTierPrice = tierPrice;
                }

                //customer product price
                if (_catalogSettings.CustomerProductPrice)
                {
                    var customerPrice = await _customerProductService.GetPriceByCustomerProduct(customer.Id, product.Id);

                    if (customerPrice.HasValue && customerPrice.Value < price)
                    {
                        price = customerPrice.Value;
                    }
                }

                //additional charge
                price = price + additionalCharge;

                //reservations
                if (product.ProductType == ProductType.Reservation)
                {
                    if (rentalStartDate.HasValue && rentalEndDate.HasValue)
                    {
                        decimal d = 0;
                        if (product.IncBothDate)
                        {
                            decimal.TryParse(((rentalEndDate - rentalStartDate).Value.TotalDays + 1).ToString(), out d);
                        }
                        else
                        {
                            decimal.TryParse((rentalEndDate - rentalStartDate).Value.TotalDays.ToString(), out d);
                        }
                        price = price * d;
                    }
                }

                if (includeDiscounts)
                {
                    //discount
                    var discountamount = await GetDiscountAmount(product, customer, price);

                    decimal tmpDiscountAmount = discountamount.discountAmount;
                    List <AppliedDiscount> tmpAppliedDiscounts = discountamount.appliedDiscounts;
                    price = price - tmpDiscountAmount;

                    if (tmpAppliedDiscounts != null)
                    {
                        result.AppliedDiscounts      = tmpAppliedDiscounts.ToList();
                        result.AppliedDiscountAmount = tmpDiscountAmount;
                    }
                }

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

                //rounding
                if (_shoppingCartSettings.RoundPricesDuringCalculation)
                {
                    var primaryCurrency = await _currencyService.GetPrimaryExchangeRateCurrency();

                    result.Price = RoundingHelper.RoundPrice(price, primaryCurrency);
                }
                else
                {
                    result.Price = price;
                }

                return(result);
            }

            var modelprice = await PrepareModel();

            if (includeDiscounts)
            {
                appliedDiscounts = modelprice.AppliedDiscounts.ToList();
                if (appliedDiscounts.Any())
                {
                    discountAmount = modelprice.AppliedDiscountAmount;
                }
            }

            return(modelprice.Price, discountAmount, appliedDiscounts, modelprice.PreferredTierPrice);
        }
        /// <summary>
        /// Gets the shopping cart unit price (one item)
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="quantity">Quantity</param>
        /// <param name="attributesXml">Product atrributes (XML format)</param>
        /// <param name="customerEnteredPrice">Customer entered price (if specified)</param>
        /// <param name="rentalStartDate">Rental start date (null for not rental products)</param>
        /// <param name="rentalEndDate">Rental end date (null for not rental products)</param>
        /// <param name="includeDiscounts">A value indicating whether include discounts or not for price computation</param>
        /// <param name="discountAmount">Applied discount amount</param>
        /// <param name="appliedDiscount">Applied discount</param>
        /// <returns>Shopping cart unit price (one item)</returns>
        public virtual decimal GetUnitPrice(Product product,
                                            Customer customer,
                                            ShoppingCartType shoppingCartType,
                                            int quantity,
                                            string attributesXml,
                                            decimal customerEnteredPrice,
                                            DateTime?rentalStartDate, DateTime?rentalEndDate,
                                            bool includeDiscounts,
                                            out decimal discountAmount,
                                            out List <Discount> appliedDiscounts)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

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

            discountAmount   = decimal.Zero;
            appliedDiscounts = new List <Discount>();

            decimal finalPrice;

            var combination = _productAttributeParser.FindProductAttributeCombination(product, attributesXml);

            if (combination != null && combination.OverriddenPrice.HasValue)
            {
                finalPrice = combination.OverriddenPrice.Value;
            }
            else
            {
                //summarize price of all attributes
                decimal attributesTotalPrice = decimal.Zero;
                var     attributeValues      = _productAttributeParser.ParseProductAttributeValues(product, attributesXml);
                if (attributeValues != null)
                {
                    foreach (var attributeValue in attributeValues)
                    {
                        attributesTotalPrice += GetProductAttributeValuePriceAdjustment(attributeValue);
                    }
                }

                //get price of a product (with previously calculated price of all attributes)
                if (product.CustomerEntersPrice)
                {
                    finalPrice = customerEnteredPrice;
                }
                else
                {
                    int qty;
                    if (_shoppingCartSettings.GroupTierPricesForDistinctShoppingCartItems)
                    {
                        //the same products with distinct product attributes could be stored as distinct "ShoppingCartItem" records
                        //so let's find how many of the current products are in the cart
                        qty = customer.ShoppingCartItems
                              .Where(x => x.ProductId == product.Id)
                              .Where(x => x.ShoppingCartType == shoppingCartType)
                              .Sum(x => x.Quantity);
                        if (qty == 0)
                        {
                            qty = quantity;
                        }
                    }
                    else
                    {
                        qty = quantity;
                    }
                    finalPrice = GetFinalPrice(product,
                                               customer,
                                               attributesTotalPrice,
                                               includeDiscounts,
                                               qty,
                                               product.IsRental ? rentalStartDate : null,
                                               product.IsRental ? rentalEndDate : null,
                                               out discountAmount, out appliedDiscounts);
                }
            }

            //rounding
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                finalPrice = RoundingHelper.RoundPrice(finalPrice);
            }

            return(finalPrice);
        }