public virtual PriceCalculationOptions CreateDefaultOptions( bool forListing, Customer customer = null, Currency targetCurrency = null, ProductBatchContext batchContext = null) { customer ??= batchContext?.Customer ?? _workContext.CurrentCustomer; var store = batchContext?.Store ?? _storeContext.CurrentStore; var language = _workContext.WorkingLanguage; var priceDisplay = _catalogSettings.PriceDisplayType; var taxInclusive = _workContext.GetTaxDisplayTypeFor(customer, store.Id) == TaxDisplayType.IncludingTax; var determinePreselectedPrice = forListing && priceDisplay == PriceDisplayType.PreSelectedPrice; targetCurrency ??= _workContext.WorkingCurrency; batchContext ??= _productService.CreateProductBatchContext(null, store, customer, false); var options = new PriceCalculationOptions(batchContext, customer, store, language, targetCurrency) { IsGrossPrice = _taxSettings.PricesIncludeTax, TaxInclusive = taxInclusive, IgnorePercentageDiscountOnTierPrices = !_catalogSettings.ApplyPercentageDiscountOnTierPrice, IgnorePercentageTierPricesOnAttributePriceAdjustments = !_catalogSettings.ApplyTierPricePercentageToAttributePriceAdjustments, IgnoreDiscounts = forListing && priceDisplay == PriceDisplayType.PriceWithoutDiscountsAndAttributes, DetermineLowestPrice = forListing && priceDisplay == PriceDisplayType.LowestPrice, DeterminePreselectedPrice = determinePreselectedPrice, ApplyPreselectedAttributes = determinePreselectedPrice, TaxFormat = _currencyService.GetTaxFormat(null, taxInclusive, PricingTarget.Product, language), PriceRangeFormat = T("Products.PriceRangeFrom").Value, RoundingCurrency = targetCurrency == _primaryCurrency ? _workContext.WorkingCurrency : targetCurrency }; return(options); }
/// <summary> /// Creates a new context instance for given <paramref name="cartItem"/> and <paramref name="options"/>. /// </summary> /// <param name="cartItem">Shopping cart item.</param> /// <param name="options">The calculation options.</param> public PriceCalculationContext(OrganizedShoppingCartItem cartItem, PriceCalculationOptions options) : this(cartItem?.Item?.Product, cartItem?.Item?.Quantity ?? 1, options) { Guard.NotNull(cartItem, nameof(cartItem)); CartItem = cartItem; }
/// <summary> /// Creates a new context instance for given <paramref name="product"/>, <paramref name="quantity"/> and <paramref name="options"/>. /// </summary> /// <param name="product">The product to calculate price for.</param> /// <param name="quantity">The product quantity.</param> /// <param name="options">The calculation options.</param> public PriceCalculationContext(Product product, int quantity, PriceCalculationOptions options) { Guard.NotNull(options, nameof(options)); Product = product; Quantity = quantity; // Always work with a shallow copy of options Options = options.Clone(); }
/// <summary> /// Calculates the unit price for a given shopping cart item. /// </summary> /// <param name="priceCalculationService">Price calculation service.</param> /// <param name="cartItem">Shopping cart item.</param> /// <param name="ignoreDiscounts">A value indicating whether to ignore discounts.</param> /// <param name="targetCurrency">The target currency to use for money conversion. Obtained from <see cref="IWorkContext.WorkingCurrency"/> if <c>null</c>.</param> /// <returns>Calculated unit price.</returns> //public static async Task<CalculatedPrice> CalculateUnitPriceAsync( // this IPriceCalculationService2 priceCalculationService, // OrganizedShoppingCartItem cartItem, // bool ignoreDiscounts = false, // Currency targetCurrency = null) //{ // Guard.NotNull(priceCalculationService, nameof(priceCalculationService)); // Guard.NotNull(cartItem, nameof(cartItem)); // var options = priceCalculationService.CreateDefaultOptions(false, cartItem.Item.Customer, targetCurrency); // options.IgnoreDiscounts = ignoreDiscounts; // var context = new PriceCalculationContext(cartItem, options); // return await priceCalculationService.CalculatePriceAsync(context); //} /// <summary> /// Calculates both the unit price and the subtotal for a given shopping cart item. /// The subtotal is calculated by multiplying the unit price by <see cref="ShoppingCartItem.Quantity"/>. /// </summary> /// <param name="priceCalculationService">Price calculation service.</param> /// <param name="cartItem">Shopping cart item.</param> /// <param name="ignoreDiscounts">A value indicating whether to ignore discounts.</param> /// <param name="targetCurrency">The target currency to use for money conversion. Obtained from <see cref="IWorkContext.WorkingCurrency"/> if <c>null</c>.</param> /// <returns>Calculated subtotal.</returns> //public static async Task<(CalculatedPrice UnitPrice, CalculatedPrice Subtotal)> CalculateSubtotalAsync( // this IPriceCalculationService2 priceCalculationService, // OrganizedShoppingCartItem cartItem, // bool ignoreDiscounts = false, // Currency targetCurrency = null) //{ // Guard.NotNull(priceCalculationService, nameof(priceCalculationService)); // Guard.NotNull(cartItem, nameof(cartItem)); // var options = priceCalculationService.CreateDefaultOptions(false, cartItem.Item.Customer, targetCurrency); // options.IgnoreDiscounts = ignoreDiscounts; // var context = new PriceCalculationContext(cartItem, options); // return await priceCalculationService.CalculateSubtotalAsync(context); //} /// <summary> /// Calculates the price adjustments of product attributes, usually <see cref="ProductVariantAttributeValue.PriceAdjustment"/>. /// Typically used to display price adjustments of selected attributes on the cart page. /// The calculated adjustment is always a unit price. /// </summary> /// <param name="priceCalculationService">Price calculation service.</param> /// <param name="product">The product.</param> /// <param name="selection">Attribute selection.</param> /// <param name="quantity"> /// The product quantity. May have impact on the price, e.g. if tier prices are applied to price adjustments. /// Note that the calculated price is always the unit price. /// </param> /// <param name="options">Price calculation options. The default options are used if <c>null</c>.</param> /// <returns>Price adjustments of selected attributes. Key: <see cref="ProductVariantAttributeValue.Id"/>, value: attribute price adjustment.</returns> public static async Task <IDictionary <int, CalculatedPriceAdjustment> > CalculateAttributePriceAdjustmentsAsync( this IPriceCalculationService2 priceCalculationService, Product product, ProductVariantAttributeSelection selection, int quantity = 1, PriceCalculationOptions options = null) { Guard.NotNull(priceCalculationService, nameof(priceCalculationService)); Guard.NotNull(selection, nameof(selection)); options ??= priceCalculationService.CreateDefaultOptions(false); options.DeterminePriceAdjustments = true; var pricingContext = new PriceCalculationContext(product, quantity, options); pricingContext.AddSelectedAttributes(selection, product.Id); var price = await priceCalculationService.CalculatePriceAsync(pricingContext); return(price.AttributePriceAdjustments.ToDictionarySafe(x => x.AttributeValue.Id)); }
/// <summary> /// Gets the base price info for a product. /// </summary> /// <param name="priceCalculationService">Price calculation service.</param> /// <param name="product">The product to get the base price info for.</param> /// <param name="options">Price calculation options. The default options are used if <c>null</c>.</param> /// <returns>Base price info.</returns> public static async Task <string> GetBasePriceInfoAsync(this IPriceCalculationService priceCalculationService, Product product, PriceCalculationOptions options = null) { Guard.NotNull(priceCalculationService, nameof(priceCalculationService)); Guard.NotNull(product, nameof(product)); if (!product.BasePriceHasValue || product.BasePriceAmount == 0) { return(string.Empty); } options ??= priceCalculationService.CreateDefaultOptions(false); var context = new PriceCalculationContext(product, options); var price = await priceCalculationService.CalculatePriceAsync(context); return(priceCalculationService.GetBasePriceInfo(product, price.FinalPrice, options.TargetCurrency)); }
public virtual async Task <PriceCalculationContext> CreateCalculationContextAsync(OrganizedShoppingCartItem cartItem, PriceCalculationOptions options) { Guard.NotNull(cartItem, nameof(cartItem)); Guard.NotNull(options, nameof(options)); var product = cartItem.Item.Product; var context = new PriceCalculationContext(product, cartItem.Item.Quantity, options) { CartItem = cartItem }; // Include attributes selected for this cart item in price calculation. context.AddSelectedAttributes(cartItem); // Include bundle item data if the cart item is a bundle item. if (cartItem.Item.BundleItem != null) { context.BundleItem = cartItem.Item.BundleItem; } // Perf: we already have the bundle items of a bundled product. No need to load them again during calculation. if (cartItem.ChildItems?.Any() ?? false) { context.BundleItems = cartItem.ChildItems .Where(x => x.Item.BundleItem != null) .Select(x => x.Item.BundleItem) .ToList(); } if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing) { Guard.NotNull(cartItem.ChildItems, nameof(cartItem.ChildItems)); foreach (var bundleItem in cartItem.ChildItems) { await _productAttributeMaterializer.MergeWithCombinationAsync(bundleItem.Item.Product, bundleItem.Item.AttributeSelection); } } else { await _productAttributeMaterializer.MergeWithCombinationAsync(product, cartItem.Item.AttributeSelection); } return(context); }
/// <summary> /// Creates a new context instance for given <paramref name="product"/> and <paramref name="options"/>. /// </summary> /// <param name="product">The product to calculate price for.</param> /// <param name="options">The calculation options.</param> public PriceCalculationContext(Product product, PriceCalculationOptions options) : this(product, 1, options) { }