Try your search with a different keyword or use * as a wildcard.
using System.Globalization;
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Tax;
using Nop.Services.Directory;
using Nop.Services.Localization;
namespace Nop.Services.Catalog;
///
/// Price formatter
///
public partial class PriceFormatter : IPriceFormatter
{
#region Fields
protected readonly CurrencySettings _currencySettings;
protected readonly ICurrencyService _currencyService;
protected readonly ILocalizationService _localizationService;
protected readonly IMeasureService _measureService;
protected readonly IPriceCalculationService _priceCalculationService;
protected readonly IWorkContext _workContext;
protected readonly TaxSettings _taxSettings;
#endregion
#region Ctor
public PriceFormatter(CurrencySettings currencySettings,
ICurrencyService currencyService,
ILocalizationService localizationService,
IMeasureService measureService,
IPriceCalculationService priceCalculationService,
IWorkContext workContext,
TaxSettings taxSettings)
{
_currencySettings = currencySettings;
_currencyService = currencyService;
_localizationService = localizationService;
_measureService = measureService;
_priceCalculationService = priceCalculationService;
_workContext = workContext;
_taxSettings = taxSettings;
}
#endregion
#region Utilities
///
/// Gets currency string
///
/// Amount
/// A value indicating whether to show a currency
/// Target currency
/// Currency string without exchange rate
protected virtual string GetCurrencyString(decimal amount,
bool showCurrency, Currency targetCurrency)
{
ArgumentNullException.ThrowIfNull(targetCurrency);
string result;
if (!string.IsNullOrEmpty(targetCurrency.CustomFormatting))
//custom formatting specified by a store owner
result = amount.ToString(targetCurrency.CustomFormatting);
else
{
if (!string.IsNullOrEmpty(targetCurrency.DisplayLocale))
//default behavior
result = amount.ToString("C", new CultureInfo(targetCurrency.DisplayLocale));
else
{
//not possible because "DisplayLocale" should be always specified
//but anyway let's just handle this behavior
result = $"{amount:N} ({targetCurrency.CurrencyCode})";
return result;
}
}
//display currency code?
if (showCurrency && _currencySettings.DisplayCurrencyLabel)
result = $"{result} ({targetCurrency.CurrencyCode})";
return result;
}
///
/// Formats the shipping price
///
/// Price
/// A value indicating whether to show a currency
/// Target currency
/// Language
/// A value indicating whether price includes tax
/// A value indicating whether to show tax suffix
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
protected virtual async Task FormatShippingPriceAsync(decimal price, bool showCurrency,
Currency targetCurrency, int languageId, bool priceIncludesTax, bool showTax)
{
return await FormatPriceAsync(price, showCurrency, targetCurrency, languageId, priceIncludesTax, showTax);
}
///
/// Formats the payment method additional fee
///
/// Price
/// A value indicating whether to show a currency
/// Target currency
/// Language
/// A value indicating whether price includes tax
/// A value indicating whether to show tax suffix
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
protected virtual async Task FormatPaymentMethodAdditionalFeeAsync(decimal price, bool showCurrency,
Currency targetCurrency, int languageId, bool priceIncludesTax, bool showTax)
{
return await FormatPriceAsync(price, showCurrency, targetCurrency, languageId,
priceIncludesTax, showTax);
}
#endregion
#region Methods
///
/// Formats the price
///
/// Price
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPriceAsync(decimal price)
{
return await FormatPriceAsync(price, true, await _workContext.GetWorkingCurrencyAsync());
}
///
/// Formats the price
///
/// Price
/// A value indicating whether to show a currency
/// Target currency
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPriceAsync(decimal price, bool showCurrency, Currency targetCurrency)
{
var priceIncludesTax = await _workContext.GetTaxDisplayTypeAsync() == TaxDisplayType.IncludingTax;
return await FormatPriceAsync(price, showCurrency, targetCurrency, (await _workContext.GetWorkingLanguageAsync()).Id, priceIncludesTax);
}
///
/// Formats the price
///
/// Price
/// A value indicating whether to show a currency
/// A value indicating whether to show tax suffix
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPriceAsync(decimal price, bool showCurrency, bool showTax)
{
var priceIncludesTax = await _workContext.GetTaxDisplayTypeAsync() == TaxDisplayType.IncludingTax;
return await FormatPriceAsync(price, showCurrency, await _workContext.GetWorkingCurrencyAsync(), (await _workContext.GetWorkingLanguageAsync()).Id, priceIncludesTax, showTax);
}
///
/// Formats the price
///
/// Price
/// A value indicating whether to show a currency
/// Currency code
/// A value indicating whether to show tax suffix
/// Language
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPriceAsync(decimal price, bool showCurrency,
string currencyCode, bool showTax, int languageId)
{
var currency = await _currencyService.GetCurrencyByCodeAsync(currencyCode) ?? new Currency
{
CurrencyCode = currencyCode
};
var priceIncludesTax = await _workContext.GetTaxDisplayTypeAsync() == TaxDisplayType.IncludingTax;
return await FormatPriceAsync(price, showCurrency, currency, languageId, priceIncludesTax, showTax);
}
///
/// Formats the order price
///
/// Price
/// Currency rate
/// Customer currency code
/// A value indicating whether to display price on customer currency
/// Primary store currency
/// Language
/// A value indicating whether price includes tax
/// A value indicating whether to show tax suffix
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatOrderPriceAsync(decimal price,
decimal currencyRate, string customerCurrencyCode, bool displayCustomerCurrency,
Currency primaryStoreCurrency, int languageId, bool? priceIncludesTax = null, bool? showTax = null)
{
var needAddPriceOnCustomerCurrency = primaryStoreCurrency.CurrencyCode != customerCurrencyCode && displayCustomerCurrency;
var includesTax = priceIncludesTax ?? await _workContext.GetTaxDisplayTypeAsync() == TaxDisplayType.IncludingTax;
var priceText = await FormatPriceAsync(price, true, primaryStoreCurrency,
languageId, includesTax, showTax ?? _taxSettings.DisplayTaxSuffix);
if (!needAddPriceOnCustomerCurrency || await _currencyService.GetCurrencyByCodeAsync(customerCurrencyCode) is not Currency currency)
return priceText;
var customerPrice = _currencyService.ConvertCurrency(price, currencyRate);
var customerPriceText = await FormatPriceAsync(customerPrice, true, currency,
languageId, includesTax, showTax ?? _taxSettings.DisplayTaxSuffix);
priceText += $"
[{customerPriceText}]";
return priceText;
}
///
/// Formats the price
///
/// Price
/// A value indicating whether to show a currency
/// Currency code
/// Language
/// A value indicating whether price includes tax
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPriceAsync(decimal price, bool showCurrency,
string currencyCode, int languageId, bool priceIncludesTax)
{
var currency = await _currencyService.GetCurrencyByCodeAsync(currencyCode)
?? new Currency
{
CurrencyCode = currencyCode
};
return await FormatPriceAsync(price, showCurrency, currency, languageId, priceIncludesTax);
}
///
/// Formats the price
///
/// Price
/// A value indicating whether to show a currency
/// Target currency
/// Language
/// A value indicating whether price includes tax
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPriceAsync(decimal price, bool showCurrency,
Currency targetCurrency, int languageId, bool priceIncludesTax)
{
return await FormatPriceAsync(price, showCurrency, targetCurrency, languageId,
priceIncludesTax, _taxSettings.DisplayTaxSuffix);
}
///
/// Formats the price
///
/// Price
/// A value indicating whether to show a currency
/// Target currency
/// Language
/// A value indicating whether price includes tax
/// A value indicating whether to show tax suffix
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPriceAsync(decimal price, bool showCurrency,
Currency targetCurrency, int languageId, bool priceIncludesTax, bool showTax)
{
//we should round it no matter of "ShoppingCartSettings.RoundPricesDuringCalculation" setting
price = await _priceCalculationService.RoundPriceAsync(price, targetCurrency);
var currencyString = GetCurrencyString(price, showCurrency, targetCurrency);
if (!showTax)
return currencyString;
//show tax suffix
string formatStr;
if (priceIncludesTax)
{
formatStr = await _localizationService.GetResourceAsync("Products.InclTaxSuffix", languageId, false);
if (string.IsNullOrEmpty(formatStr))
formatStr = "{0} incl tax";
}
else
{
formatStr = await _localizationService.GetResourceAsync("Products.ExclTaxSuffix", languageId, false);
if (string.IsNullOrEmpty(formatStr))
formatStr = "{0} excl tax";
}
return string.Format(formatStr, currencyString);
}
///
/// Formats the price of rental product (with rental period)
///
/// Product
/// Price
///
/// A task that represents the asynchronous operation
/// The task result contains the rental product price with period
///
public virtual async Task FormatRentalProductPeriodAsync(Product product, string price)
{
ArgumentNullException.ThrowIfNull(product);
if (!product.IsRental)
return price;
if (string.IsNullOrWhiteSpace(price))
return price;
var result = product.RentalPricePeriod switch
{
RentalPricePeriod.Days => string.Format(await _localizationService.GetResourceAsync("Products.Price.Rental.Days"), price, product.RentalPriceLength),
RentalPricePeriod.Weeks => string.Format(await _localizationService.GetResourceAsync("Products.Price.Rental.Weeks"), price, product.RentalPriceLength),
RentalPricePeriod.Months => string.Format(await _localizationService.GetResourceAsync("Products.Price.Rental.Months"), price, product.RentalPriceLength),
RentalPricePeriod.Years => string.Format(await _localizationService.GetResourceAsync("Products.Price.Rental.Years"), price, product.RentalPriceLength),
_ => throw new NopException("Not supported rental period"),
};
return result;
}
///
/// Formats the shipping price
///
/// Price
/// A value indicating whether to show a currency
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatShippingPriceAsync(decimal price, bool showCurrency)
{
var priceIncludesTax = await _workContext.GetTaxDisplayTypeAsync() == TaxDisplayType.IncludingTax;
return await FormatShippingPriceAsync(price, showCurrency, await _workContext.GetWorkingCurrencyAsync(), (await _workContext.GetWorkingLanguageAsync()).Id, priceIncludesTax);
}
///
/// Formats the shipping price
///
/// Price
/// A value indicating whether to show a currency
/// Target currency
/// Language
/// A value indicating whether price includes tax
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatShippingPriceAsync(decimal price, bool showCurrency,
Currency targetCurrency, int languageId, bool priceIncludesTax)
{
var showTax = _taxSettings.ShippingIsTaxable && _taxSettings.DisplayTaxSuffix;
return await FormatShippingPriceAsync(price, showCurrency, targetCurrency, languageId, priceIncludesTax, showTax);
}
///
/// Formats the shipping price
///
/// Price
/// A value indicating whether to show a currency
/// Currency code
/// Language
/// A value indicating whether price includes tax
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatShippingPriceAsync(decimal price, bool showCurrency,
string currencyCode, int languageId, bool priceIncludesTax)
{
var currency = await _currencyService.GetCurrencyByCodeAsync(currencyCode)
?? new Currency
{
CurrencyCode = currencyCode
};
return await FormatShippingPriceAsync(price, showCurrency, currency, languageId, priceIncludesTax);
}
///
/// Formats the payment method additional fee
///
/// Price
/// A value indicating whether to show a currency
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPaymentMethodAdditionalFeeAsync(decimal price, bool showCurrency)
{
var priceIncludesTax = await _workContext.GetTaxDisplayTypeAsync() == TaxDisplayType.IncludingTax;
return await FormatPaymentMethodAdditionalFeeAsync(price, showCurrency, await _workContext.GetWorkingCurrencyAsync(),
(await _workContext.GetWorkingLanguageAsync()).Id, priceIncludesTax);
}
///
/// Formats the payment method additional fee
///
/// Price
/// A value indicating whether to show a currency
/// Target currency
/// Language
/// A value indicating whether price includes tax
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPaymentMethodAdditionalFeeAsync(decimal price, bool showCurrency,
Currency targetCurrency, int languageId, bool priceIncludesTax)
{
var showTax = _taxSettings.PaymentMethodAdditionalFeeIsTaxable && _taxSettings.DisplayTaxSuffix;
return await FormatPaymentMethodAdditionalFeeAsync(price, showCurrency, targetCurrency, languageId, priceIncludesTax, showTax);
}
///
/// Formats the payment method additional fee
///
/// Price
/// A value indicating whether to show a currency
/// Currency code
/// Language
/// A value indicating whether price includes tax
///
/// A task that represents the asynchronous operation
/// The task result contains the price
///
public virtual async Task FormatPaymentMethodAdditionalFeeAsync(decimal price, bool showCurrency,
string currencyCode, int languageId, bool priceIncludesTax)
{
var currency = await _currencyService.GetCurrencyByCodeAsync(currencyCode)
?? new Currency
{
CurrencyCode = currencyCode
};
return await FormatPaymentMethodAdditionalFeeAsync(price, showCurrency, currency,
languageId, priceIncludesTax);
}
///
/// Formats a tax rate
///
/// Tax rate
/// Formatted tax rate
public virtual string FormatTaxRate(decimal taxRate)
{
return taxRate.ToString("G29", CultureInfo.InvariantCulture);
}
///
/// Format base price (PAngV)
///
/// Product
/// Product price (in primary currency). Pass null if you want to use a default produce price
/// Total weight of product (with attribute weight adjustment). Pass null if you want to use a default produce weight
///
/// A task that represents the asynchronous operation
/// The task result contains the base price
///
public virtual async Task FormatBasePriceAsync(Product product, decimal? productPrice, decimal? totalWeight = null)
{
ArgumentNullException.ThrowIfNull(product);
if (!product.BasepriceEnabled)
return null;
var productAmount = totalWeight.HasValue && totalWeight.Value > decimal.Zero ? totalWeight.Value : product.BasepriceAmount;
//Amount in product cannot be 0
if (productAmount == 0)
return null;
var referenceAmount = product.BasepriceBaseAmount;
var productUnit = await _measureService.GetMeasureWeightByIdAsync(product.BasepriceUnitId);
//measure weight cannot be loaded
if (productUnit == null)
return null;
var referenceUnit = await _measureService.GetMeasureWeightByIdAsync(product.BasepriceBaseUnitId);
//measure weight cannot be loaded
if (referenceUnit == null)
return null;
productPrice ??= product.Price;
var basePrice = productPrice.Value /
//do not round. otherwise, it can cause issues
await _measureService.ConvertWeightAsync(productAmount, productUnit, referenceUnit, false) *
referenceAmount;
var basePriceInCurrentCurrency = await _currencyService.ConvertFromPrimaryStoreCurrencyAsync(basePrice, await _workContext.GetWorkingCurrencyAsync());
var basePriceStr = await FormatPriceAsync(basePriceInCurrentCurrency, true, false);
var result = string.Format(await _localizationService.GetResourceAsync("Products.BasePrice"),
basePriceStr, referenceAmount.ToString("G29"), referenceUnit.Name);
return result;
}
#endregion
}