Example #1
0
        private decimal MapSummaryItemPrice(Product product, ref Product contextProduct, ProductSummaryModel.SummaryItem item, MapProductSummaryItemContext ctx)
        {
            // Returns the final price
            var finalPrice = decimal.Zero;
            var model      = ctx.Model;

            var priceModel = new ProductSummaryModel.PriceModel();

            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing && !ctx.BatchContext.ProductBundleItems.FullyLoaded)
            {
                ctx.BatchContext.ProductBundleItems.LoadAll();
            }

            if (product.ProductType == ProductType.GroupedProduct)
            {
                #region Grouped product

                if (ctx.GroupedProducts == null)
                {
                    // One-time batched retrieval of all associated products
                    var searchQuery = new CatalogSearchQuery()
                                      .PublishedOnly(true)
                                      .HasStoreId(ctx.Store.Id)
                                      .HasParentGroupedProduct(ctx.BatchContext.ProductIds.ToArray());

                    // Get all associated products for this batch grouped by ParentGroupedProductId
                    var allAssociatedProducts = _catalogSearchService.Search(searchQuery).Hits
                                                .OrderBy(x => x.ParentGroupedProductId)
                                                .ThenBy(x => x.DisplayOrder);

                    ctx.GroupedProducts = allAssociatedProducts.ToMultimap(x => x.ParentGroupedProductId, x => x);

                    if (ctx.GroupedProducts.Any())
                    {
                        ctx.BatchContext.AppliedDiscounts.Collect(allAssociatedProducts.Select(x => x.Id));
                    }
                }

                var associatedProducts = ctx.GroupedProducts[product.Id];

                priceModel.DisableBuyButton      = true;
                priceModel.DisableWishlistButton = true;
                priceModel.AvailableForPreOrder  = false;

                if (associatedProducts.Count > 0)
                {
                    contextProduct = associatedProducts.OrderBy(x => x.DisplayOrder).First();

                    _services.DisplayControl.Announce(contextProduct);

                    if (ctx.AllowPrices && _catalogSettings.PriceDisplayType != PriceDisplayType.Hide)
                    {
                        decimal?displayPrice       = null;
                        bool    displayFromMessage = false;

                        if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice)
                        {
                            displayPrice = _priceCalculationService.GetPreselectedPrice(contextProduct, ctx.Customer, ctx.BatchContext);
                        }
                        else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes)
                        {
                            displayPrice = _priceCalculationService.GetFinalPrice(contextProduct, null, ctx.Customer, decimal.Zero, false, 1, null, ctx.BatchContext);
                        }
                        else
                        {
                            displayFromMessage = true;
                            displayPrice       = _priceCalculationService.GetLowestPrice(product, ctx.Customer, ctx.BatchContext, associatedProducts, out contextProduct);
                        }

                        if (contextProduct != null && !contextProduct.CustomerEntersPrice)
                        {
                            if (contextProduct.CallForPrice)
                            {
                                priceModel.RegularPriceValue = null;
                                priceModel.PriceValue        = 0;
                                priceModel.RegularPrice      = null;
                                priceModel.Price             = ctx.Resources["Products.CallForPrice"];
                            }
                            else if (displayPrice.HasValue)
                            {
                                // Calculate prices
                                decimal taxRate        = decimal.Zero;
                                decimal oldPriceBase   = _taxService.GetProductPrice(contextProduct, contextProduct.OldPrice, out taxRate);
                                decimal finalPriceBase = _taxService.GetProductPrice(contextProduct, displayPrice.Value, out taxRate);
                                finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, ctx.Currency);

                                priceModel.RegularPriceValue = null;
                                priceModel.PriceValue        = finalPrice;
                                priceModel.RegularPrice      = null;

                                if (displayFromMessage)
                                {
                                    priceModel.Price = String.Format(ctx.Resources["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice));
                                }
                                else
                                {
                                    priceModel.Price = _priceFormatter.FormatPrice(finalPrice);
                                }

                                if (oldPriceBase > 0)
                                {
                                    priceModel.RegularPriceValue = _currencyService.ConvertFromPrimaryStoreCurrency(oldPriceBase, ctx.Currency);
                                }

                                priceModel.HasDiscount = (finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero);
                            }
                            else
                            {
                                // Actually it's not possible (we presume that displayPrice always has a value). We never should get here
                                Debug.WriteLine(string.Format("Cannot calculate displayPrice for product #{0}", product.Id));
                            }
                        }
                    }
                }

                #endregion
            }
            else
            {
                #region Simple product

                //add to cart button
                priceModel.DisableBuyButton = product.DisableBuyButton || !ctx.AllowShoppingCart || !ctx.AllowPrices;

                //add to wishlist button
                priceModel.DisableWishlistButton = product.DisableWishlistButton || !ctx.AllowWishlist || !ctx.AllowPrices;

                //pre-order
                priceModel.AvailableForPreOrder = product.AvailableForPreOrder;

                //prices
                if (ctx.AllowPrices && _catalogSettings.PriceDisplayType != PriceDisplayType.Hide && !product.CustomerEntersPrice)
                {
                    if (product.CallForPrice)
                    {
                        // call for price
                        priceModel.RegularPriceValue = null;
                        priceModel.PriceValue        = 0;
                        priceModel.RegularPrice      = null;
                        priceModel.Price             = ctx.Resources["Products.CallForPrice"];
                    }
                    else
                    {
                        //calculate prices
                        bool    displayFromMessage = false;
                        decimal displayPrice       = decimal.Zero;

                        if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice)
                        {
                            displayPrice = _priceCalculationService.GetPreselectedPrice(product, ctx.Customer, ctx.BatchContext);
                        }
                        else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes)
                        {
                            displayPrice = _priceCalculationService.GetFinalPrice(product, null, ctx.Customer, decimal.Zero, false, 1, null, ctx.BatchContext);
                        }
                        else
                        {
                            displayPrice = _priceCalculationService.GetLowestPrice(product, ctx.Customer, ctx.BatchContext, out displayFromMessage);
                        }

                        decimal taxRate        = decimal.Zero;
                        decimal oldPriceBase   = _taxService.GetProductPrice(product, product.OldPrice, out taxRate);
                        decimal finalPriceBase = _taxService.GetProductPrice(product, displayPrice, out taxRate);

                        decimal oldPrice = _currencyService.ConvertFromPrimaryStoreCurrency(oldPriceBase, ctx.Currency);
                        finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, ctx.Currency);

                        priceModel.HasDiscount = (finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero);

                        if (displayFromMessage)
                        {
                            priceModel.RegularPriceValue = null;
                            priceModel.RegularPrice      = null;
                            priceModel.Price             = String.Format(ctx.Resources["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice));
                        }
                        else
                        {
                            priceModel.PriceValue = finalPrice;
                            if (priceModel.HasDiscount)
                            {
                                priceModel.RegularPriceValue = oldPrice;
                                priceModel.RegularPrice      = _priceFormatter.FormatPrice(oldPrice);
                                priceModel.Price             = _priceFormatter.FormatPrice(finalPrice);
                            }
                            else
                            {
                                priceModel.RegularPriceValue = null;
                                priceModel.RegularPrice      = null;
                                priceModel.Price             = _priceFormatter.FormatPrice(finalPrice);
                            }
                        }
                    }
                }

                #endregion
            }

            var regularPriceValue = priceModel.RegularPriceValue.GetValueOrDefault();
            if (priceModel.HasDiscount && regularPriceValue > 0 && regularPriceValue > priceModel.PriceValue)
            {
                priceModel.SavingPercent = (float)((priceModel.RegularPriceValue - priceModel.PriceValue) / priceModel.RegularPriceValue) * 100;
                priceModel.SavingAmount  = _priceFormatter.FormatPrice(regularPriceValue - priceModel.PriceValue, true, false);

                if (model.ShowDiscountBadge)
                {
                    item.Badges.Add(new ProductSummaryModel.Badge
                    {
                        Label = T("Products.SavingBadgeLabel", priceModel.SavingPercent.ToString("N0")),
                        Style = BadgeStyle.Danger
                    });
                }
            }

            priceModel.CallForPrice = product.CallForPrice;

            item.Price = priceModel;

            return(finalPrice);
        }
        /// <param name="contextProduct">The product or the first associated product of a group.</param>
        /// <returns>The final price</returns>
        private async Task <(Money FinalPrice, Product ContextProduct)> MapSummaryItemPrice(Product product, ProductSummaryModel.SummaryItem item, MapProductSummaryItemContext ctx)
        {
            var options        = ctx.CalculationOptions;
            var batchContext   = ctx.BatchContext;
            var contextProduct = product;
            ICollection <Product> associatedProducts = null;

            var priceModel = new ProductSummaryModel.PriceModel();

            item.Price = priceModel;

            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing && !batchContext.ProductBundleItems.FullyLoaded)
            {
                await batchContext.ProductBundleItems.LoadAllAsync();
            }

            if (product.ProductType == ProductType.GroupedProduct)
            {
                priceModel.DisableBuyButton      = true;
                priceModel.DisableWishlistButton = true;
                priceModel.AvailableForPreOrder  = false;

                if (ctx.GroupedProducts == null)
                {
                    // One-time batched retrieval of all associated products.
                    var searchQuery = new CatalogSearchQuery()
                                      .PublishedOnly(true)
                                      .HasStoreId(options.Store.Id)
                                      .HasParentGroupedProduct(batchContext.ProductIds.ToArray());

                    // Get all associated products for this batch grouped by ParentGroupedProductId.
                    var searchResult = await _catalogSearchService.SearchAsync(searchQuery);

                    var allAssociatedProducts = (await searchResult.GetHitsAsync())
                                                .OrderBy(x => x.ParentGroupedProductId)
                                                .ThenBy(x => x.DisplayOrder);

                    ctx.GroupedProducts = allAssociatedProducts.ToMultimap(x => x.ParentGroupedProductId, x => x);
                    ctx.AssociatedProductBatchContext = _productService.CreateProductBatchContext(allAssociatedProducts, options.Store, options.Customer, false);

                    options.ChildProductsBatchContext = ctx.AssociatedProductBatchContext;
                }

                associatedProducts = ctx.GroupedProducts[product.Id];
                if (associatedProducts.Any())
                {
                    contextProduct = associatedProducts.OrderBy(x => x.DisplayOrder).First();
                    _services.DisplayControl.Announce(contextProduct);
                }
            }
            else
            {
                priceModel.DisableBuyButton      = product.DisableBuyButton || !ctx.AllowShoppingCart || !ctx.AllowPrices;
                priceModel.DisableWishlistButton = product.DisableWishlistButton || !ctx.AllowWishlist || !ctx.AllowPrices;
                priceModel.AvailableForPreOrder  = product.AvailableForPreOrder;
            }

            // Return if there's no pricing at all.
            if (contextProduct == null || contextProduct.CustomerEntersPrice || !ctx.AllowPrices || _catalogSettings.PriceDisplayType == PriceDisplayType.Hide)
            {
                return(new Money(options.TargetCurrency), contextProduct);
            }

            // Return if group has no associated products.
            if (product.ProductType == ProductType.GroupedProduct && !associatedProducts.Any())
            {
                return(new Money(options.TargetCurrency), contextProduct);
            }

            // Call for price.
            priceModel.CallForPrice = contextProduct.CallForPrice;
            if (contextProduct.CallForPrice)
            {
                var money = new Money(options.TargetCurrency).WithPostFormat(ctx.Resources["Products.CallForPrice"]);
                priceModel.Price = money;
                return(money, contextProduct);
            }

            var calculationContext = new PriceCalculationContext(product, options)
            {
                AssociatedProducts = associatedProducts
            };

            // -----> Perform calculation <-------
            var calculatedPrice = await _priceCalculationService.CalculatePriceAsync(calculationContext);

            var savings = calculatedPrice.PriceSaving;

            priceModel.Price       = calculatedPrice.FinalPrice;
            priceModel.HasDiscount = savings.HasSaving;

            if (savings.HasSaving)
            {
                priceModel.RegularPrice  = savings.SavingPrice;
                priceModel.SavingAmount  = savings.SavingAmount;
                priceModel.SavingPercent = savings.SavingPercent;

                if (ctx.Model.ShowDiscountBadge)
                {
                    item.Badges.Add(new ProductSummaryModel.Badge
                    {
                        Label = T("Products.SavingBadgeLabel", priceModel.SavingPercent.ToString("N0")),
                        Style = BadgeStyle.Danger
                    });
                }
            }

            return(calculatedPrice.FinalPrice, contextProduct);
        }
Example #3
0
        /// <param name="contextProduct">The product or the first associated product of a group.</param>
        /// <returns>The final price</returns>
        private decimal MapSummaryItemPrice(Product product, ref Product contextProduct, ProductSummaryModel.SummaryItem item, MapProductSummaryItemContext ctx)
        {
            var displayFromMessage = false;
            var taxRate            = decimal.Zero;
            var oldPriceBase       = decimal.Zero;
            var oldPrice           = decimal.Zero;
            var finalPriceBase     = decimal.Zero;
            var finalPrice         = decimal.Zero;
            var displayPrice       = decimal.Zero;
            ICollection <Product> associatedProducts = null;

            var priceModel = new ProductSummaryModel.PriceModel();

            item.Price = priceModel;

            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing && !ctx.BatchContext.ProductBundleItems.FullyLoaded)
            {
                ctx.BatchContext.ProductBundleItems.LoadAll();
            }

            if (product.ProductType == ProductType.GroupedProduct)
            {
                priceModel.DisableBuyButton      = true;
                priceModel.DisableWishlistButton = true;
                priceModel.AvailableForPreOrder  = false;

                if (ctx.GroupedProducts == null)
                {
                    // One-time batched retrieval of all associated products.
                    var searchQuery = new CatalogSearchQuery()
                                      .PublishedOnly(true)
                                      .HasStoreId(ctx.Store.Id)
                                      .HasParentGroupedProduct(ctx.BatchContext.ProductIds.ToArray());

                    // Get all associated products for this batch grouped by ParentGroupedProductId.
                    var allAssociatedProducts = _catalogSearchService.Search(searchQuery).Hits
                                                .OrderBy(x => x.ParentGroupedProductId)
                                                .ThenBy(x => x.DisplayOrder);

                    ctx.GroupedProducts = allAssociatedProducts.ToMultimap(x => x.ParentGroupedProductId, x => x);
                    ctx.AssociatedProductBatchContext = _dataExporter.Value.CreateProductExportContext(allAssociatedProducts, ctx.Customer, null, null, false);
                }

                associatedProducts = ctx.GroupedProducts[product.Id];
                if (associatedProducts.Any())
                {
                    contextProduct = associatedProducts.OrderBy(x => x.DisplayOrder).First();

                    _services.DisplayControl.Announce(contextProduct);
                }
            }
            else
            {
                priceModel.DisableBuyButton      = product.DisableBuyButton || !ctx.AllowShoppingCart || !ctx.AllowPrices;
                priceModel.DisableWishlistButton = product.DisableWishlistButton || !ctx.AllowWishlist || !ctx.AllowPrices;
                priceModel.AvailableForPreOrder  = product.AvailableForPreOrder;
            }

            // Return if there's no pricing at all.
            if (contextProduct == null || contextProduct.CustomerEntersPrice || !ctx.AllowPrices || _catalogSettings.PriceDisplayType == PriceDisplayType.Hide)
            {
                return(finalPrice);
            }
            // Return if group has no associated products.
            if (product.ProductType == ProductType.GroupedProduct && !associatedProducts.Any())
            {
                return(finalPrice);
            }

            // Call for price.
            priceModel.CallForPrice = contextProduct.CallForPrice;
            if (contextProduct.CallForPrice)
            {
                priceModel.Price = ctx.Resources["Products.CallForPrice"];
                return(finalPrice);
            }

            // Calculate prices.
            var batchContext = product.ProductType == ProductType.GroupedProduct ? ctx.AssociatedProductBatchContext : ctx.BatchContext;

            if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice)
            {
                displayPrice = _priceCalculationService.GetPreselectedPrice(contextProduct, ctx.Customer, ctx.Currency, batchContext);
            }
            else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes)
            {
                displayPrice = _priceCalculationService.GetFinalPrice(contextProduct, null, ctx.Customer, decimal.Zero, false, 1, null, batchContext);
            }
            else
            {
                // Display lowest price.
                if (product.ProductType == ProductType.GroupedProduct)
                {
                    displayFromMessage = true;
                    displayPrice       = _priceCalculationService.GetLowestPrice(product, ctx.Customer, batchContext, associatedProducts, out contextProduct) ?? decimal.Zero;
                }
                else
                {
                    displayPrice = _priceCalculationService.GetLowestPrice(product, ctx.Customer, batchContext, out displayFromMessage);
                }
            }

            oldPriceBase   = _taxService.GetProductPrice(contextProduct, contextProduct.OldPrice, out taxRate);
            finalPriceBase = _taxService.GetProductPrice(contextProduct, displayPrice, out taxRate);

            oldPrice   = _currencyService.ConvertFromPrimaryStoreCurrency(oldPriceBase, ctx.Currency);
            finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, ctx.Currency);

            priceModel.PriceValue = finalPrice;
            priceModel.Price      = displayFromMessage
                                ? string.Format(ctx.Resources["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice))
                                : _priceFormatter.FormatPrice(finalPrice);

            priceModel.HasDiscount = oldPriceBase > decimal.Zero && oldPriceBase > finalPriceBase;
            if (priceModel.HasDiscount)
            {
                priceModel.RegularPriceValue = oldPrice;
                priceModel.RegularPrice      = _priceFormatter.FormatPrice(oldPrice);
            }

            // Calculate saving.
            var finalPriceWithDiscount = _priceCalculationService.GetFinalPrice(contextProduct, null, ctx.Customer, decimal.Zero, true, 1, null, batchContext);

            finalPriceWithDiscount = _taxService.GetProductPrice(contextProduct, finalPriceWithDiscount, out taxRate);
            finalPriceWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceWithDiscount, ctx.Currency);

            var finalPriceWithoutDiscount = finalPrice;

            if (_catalogSettings.PriceDisplayType != PriceDisplayType.PriceWithoutDiscountsAndAttributes)
            {
                finalPriceWithoutDiscount = _priceCalculationService.GetFinalPrice(contextProduct, null, ctx.Customer, decimal.Zero, false, 1, null, batchContext);
                finalPriceWithoutDiscount = _taxService.GetProductPrice(contextProduct, finalPriceWithoutDiscount, out taxRate);
                finalPriceWithoutDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceWithoutDiscount, ctx.Currency);
            }

            // Discounted price has priority over the old price (avoids differing percentage discount in product lists and detail page).
            var regularPrice = finalPriceWithDiscount < finalPriceWithoutDiscount
                                ? finalPriceWithoutDiscount
                                : oldPrice;

            if (regularPrice > 0 && regularPrice > finalPriceWithDiscount)
            {
                priceModel.HasDiscount   = true;
                priceModel.SavingPercent = (float)((regularPrice - finalPriceWithDiscount) / regularPrice) * 100;
                priceModel.SavingAmount  = _priceFormatter.FormatPrice(regularPrice - finalPriceWithDiscount, true, false);

                if (!priceModel.RegularPriceValue.HasValue)
                {
                    priceModel.RegularPriceValue = regularPrice;
                    priceModel.RegularPrice      = _priceFormatter.FormatPrice(regularPrice);
                }

                if (ctx.Model.ShowDiscountBadge)
                {
                    item.Badges.Add(new ProductSummaryModel.Badge
                    {
                        Label = T("Products.SavingBadgeLabel", priceModel.SavingPercent.ToString("N0")),
                        Style = BadgeStyle.Danger
                    });
                }
            }

            return(finalPrice);
        }
Example #4
0
        /// <param name="contextProduct">The product or the first associated product of a group.</param>
        /// <returns>The final price</returns>
        private async Task <(Money FinalPrice, Product ContextProduct)> MapSummaryItemPrice(Product product, ProductSummaryModel.SummaryItem item, MapProductSummaryItemContext ctx)
        {
            //return (new Money(0, ctx.WorkingCurrency), product);
            var options            = ctx.CalculationOptions;
            var batchContext       = ctx.BatchContext;
            var contextProduct     = product;
            var displayFromMessage = false;
            var taxRate            = decimal.Zero;
            var oldPriceBase       = default(Money);
            var oldPrice           = default(Money);
            var finalPriceBase     = default(Money);
            var finalPrice         = new Money(ctx.PrimaryCurrency);
            var displayPrice       = (Money?)null;

            ICollection <Product> associatedProducts = null;

            var priceModel = new ProductSummaryModel.PriceModel();

            item.Price = priceModel;

            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing && !batchContext.ProductBundleItems.FullyLoaded)
            {
                await batchContext.ProductBundleItems.LoadAllAsync();
            }

            if (product.ProductType == ProductType.GroupedProduct)
            {
                priceModel.DisableBuyButton      = true;
                priceModel.DisableWishlistButton = true;
                priceModel.AvailableForPreOrder  = false;

                if (ctx.GroupedProducts == null)
                {
                    // One-time batched retrieval of all associated products.
                    var searchQuery = new CatalogSearchQuery()
                                      .PublishedOnly(true)
                                      .HasStoreId(options.Store.Id)
                                      .HasParentGroupedProduct(batchContext.ProductIds.ToArray());

                    // Get all associated products for this batch grouped by ParentGroupedProductId.
                    var searchResult = await _catalogSearchService.SearchAsync(searchQuery);

                    var allAssociatedProducts = (await searchResult.GetHitsAsync())
                                                .OrderBy(x => x.ParentGroupedProductId)
                                                .ThenBy(x => x.DisplayOrder);

                    ctx.GroupedProducts = allAssociatedProducts.ToMultimap(x => x.ParentGroupedProductId, x => x);
                    ctx.AssociatedProductBatchContext = _productService.CreateProductBatchContext(allAssociatedProducts, options.Store, options.Customer, false, null);

                    options.ChildProductsBatchContext = ctx.AssociatedProductBatchContext;
                }

                associatedProducts = ctx.GroupedProducts[product.Id];
                if (associatedProducts.Any())
                {
                    contextProduct = associatedProducts.OrderBy(x => x.DisplayOrder).First();
                    _services.DisplayControl.Announce(contextProduct);
                }
            }
            else
            {
                priceModel.DisableBuyButton      = product.DisableBuyButton || !ctx.AllowShoppingCart || !ctx.AllowPrices;
                priceModel.DisableWishlistButton = product.DisableWishlistButton || !ctx.AllowWishlist || !ctx.AllowPrices;
                priceModel.AvailableForPreOrder  = product.AvailableForPreOrder;
            }

            // Return if there's no pricing at all.
            if (contextProduct == null || contextProduct.CustomerEntersPrice || !ctx.AllowPrices || _catalogSettings.PriceDisplayType == PriceDisplayType.Hide)
            {
                return(new Money(options.TargetCurrency), contextProduct);
            }

            // Return if group has no associated products.
            if (product.ProductType == ProductType.GroupedProduct && !associatedProducts.Any())
            {
                return(new Money(options.TargetCurrency), contextProduct);
            }

            // Call for price.
            priceModel.CallForPrice = contextProduct.CallForPrice;
            if (contextProduct.CallForPrice)
            {
                return(new Money(options.TargetCurrency).WithPostFormat(ctx.Resources["Products.CallForPrice"]), contextProduct);
            }

            #region Test NEW

            var calculationContext = new PriceCalculationContext(product, options)
            {
                AssociatedProducts = associatedProducts
            };

            // -----> Perform calculation <-------
            var calculatedPrice = await _priceCalculationService.CalculatePriceAsync(calculationContext);

            priceModel.Price       = calculatedPrice.FinalPrice;
            priceModel.HasDiscount = calculatedPrice.HasDiscount;
            if (calculatedPrice.HasDiscount)
            {
                priceModel.RegularPrice  = calculatedPrice.RegularPrice;
                priceModel.SavingAmount  = calculatedPrice.SavingAmount;
                priceModel.SavingPercent = calculatedPrice.SavingPercent;
            }

            return(calculatedPrice.FinalPrice, contextProduct);

            #endregion

            // Calculate prices.
            batchContext = product.ProductType == ProductType.GroupedProduct ? ctx.AssociatedProductBatchContext : ctx.BatchContext;

            if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice)
            {
                displayPrice = await _priceCalculationService.GetPreselectedPriceAsync(contextProduct, options.Customer, batchContext);
            }
            else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes)
            {
                displayPrice = await _priceCalculationService.GetFinalPriceAsync(contextProduct, null, null, options.Customer, false, 1, null, batchContext);
            }
            else
            {
                // Display lowest price.
                if (product.ProductType == ProductType.GroupedProduct)
                {
                    displayFromMessage             = true;
                    (displayPrice, contextProduct) = await _priceCalculationService.GetLowestPriceAsync(product, options.Customer, batchContext, associatedProducts);
                }
                else
                {
                    (displayPrice, displayFromMessage) = await _priceCalculationService.GetLowestPriceAsync(product, options.Customer, batchContext);
                }
            }

            (oldPriceBase, taxRate) = await _taxService.GetProductPriceAsync(contextProduct, new Money(contextProduct.OldPrice, ctx.PrimaryCurrency));

            (finalPriceBase, taxRate) = await _taxService.GetProductPriceAsync(contextProduct, displayPrice ?? new Money(ctx.PrimaryCurrency));

            oldPrice   = ToWorkingCurrency(oldPriceBase, ctx);
            finalPrice = ToWorkingCurrency(finalPriceBase, ctx).WithPostFormat(options.TaxFormat);

            string finalPricePostFormat = finalPrice.PostFormat;
            if (displayFromMessage)
            {
                finalPricePostFormat = finalPricePostFormat == null
                    ? ctx.Resources["Products.PriceRangeFrom"]
                    : string.Format(ctx.Resources["Products.PriceRangeFrom"], finalPricePostFormat);
            }

            priceModel.Price = finalPrice.WithPostFormat(finalPricePostFormat);

            priceModel.HasDiscount = oldPriceBase > decimal.Zero && oldPriceBase > finalPriceBase;
            if (priceModel.HasDiscount)
            {
                priceModel.RegularPrice = oldPrice.WithPostFormat(options.TaxFormat);
            }

            // Calculate saving.
            var finalPriceWithDiscount = await _priceCalculationService.GetFinalPriceAsync(contextProduct, null, null, options.Customer, true, 1, null, batchContext);

            (finalPriceWithDiscount, taxRate) = await _taxService.GetProductPriceAsync(contextProduct, finalPriceWithDiscount);

            finalPriceWithDiscount = ToWorkingCurrency(finalPriceWithDiscount, ctx);

            var finalPriceWithoutDiscount = finalPrice;
            if (_catalogSettings.PriceDisplayType != PriceDisplayType.PriceWithoutDiscountsAndAttributes)
            {
                finalPriceWithoutDiscount = await _priceCalculationService.GetFinalPriceAsync(contextProduct, null, null, options.Customer, false, 1, null, batchContext);

                (finalPriceWithoutDiscount, taxRate) = await _taxService.GetProductPriceAsync(contextProduct, finalPriceWithoutDiscount);

                finalPriceWithoutDiscount = ToWorkingCurrency(finalPriceWithoutDiscount, ctx);
            }

            // Discounted price has priority over the old price (avoids differing percentage discount in product lists and detail page).
            var regularPrice = finalPriceWithDiscount < finalPriceWithoutDiscount
                ? finalPriceWithoutDiscount
                : oldPrice;

            if (regularPrice > 0 && regularPrice > finalPriceWithDiscount)
            {
                priceModel.HasDiscount   = true;
                priceModel.SavingPercent = (float)((regularPrice - finalPriceWithDiscount) / regularPrice) * 100;
                priceModel.SavingAmount  = (regularPrice - finalPriceWithDiscount).WithPostFormat(null);

                if (priceModel.RegularPrice == null)
                {
                    priceModel.RegularPrice = regularPrice.WithPostFormat(options.TaxFormat);
                }

                if (ctx.Model.ShowDiscountBadge)
                {
                    item.Badges.Add(new ProductSummaryModel.Badge
                    {
                        Label = T("Products.SavingBadgeLabel", priceModel.SavingPercent.ToString("N0")),
                        Style = BadgeStyle.Danger
                    });
                }
            }

            return(finalPrice, contextProduct);
        }