using System.Globalization; using System.Xml; using Nop.Core; using Nop.Core.Http; using Nop.Services.Configuration; using Nop.Services.Directory; using Nop.Services.Localization; using Nop.Services.Logging; using Nop.Services.Plugins; namespace Nop.Plugin.ExchangeRate.EcbExchange; public class EcbExchangeRateProvider : BasePlugin, IExchangeRateProvider { #region Fields protected readonly EcbExchangeRateSettings _ecbExchangeRateSettings; protected readonly IHttpClientFactory _httpClientFactory; protected readonly ILocalizationService _localizationService; protected readonly ILogger _logger; protected readonly ISettingService _settingService; #endregion #region Ctor public EcbExchangeRateProvider(EcbExchangeRateSettings ecbExchangeRateSettings, IHttpClientFactory httpClientFactory, ILocalizationService localizationService, ILogger logger, ISettingService settingService) { _ecbExchangeRateSettings = ecbExchangeRateSettings; _httpClientFactory = httpClientFactory; _localizationService = localizationService; _logger = logger; _settingService = settingService; } #endregion #region Methods /// /// Gets currency live rates /// /// Exchange rate currency code /// /// A task that represents the asynchronous operation /// The task result contains the exchange rates /// public async Task> GetCurrencyLiveRatesAsync(string exchangeRateCurrencyCode) { ArgumentNullException.ThrowIfNull(exchangeRateCurrencyCode); //add euro with rate 1 var ratesToEuro = new List { new() { CurrencyCode = "EUR", Rate = 1, UpdatedOn = DateTime.UtcNow } }; //get exchange rates to euro from European Central Bank try { var httpClient = _httpClientFactory.CreateClient(NopHttpDefaults.DefaultHttpClient); var stream = await httpClient.GetStreamAsync(_ecbExchangeRateSettings.EcbLink); //load XML document var document = new XmlDocument(); document.Load(stream); //add namespaces var namespaces = new XmlNamespaceManager(document.NameTable); namespaces.AddNamespace("ns", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref"); namespaces.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01"); //get daily rates var dailyRates = document.SelectSingleNode("gesmes:Envelope/ns:Cube/ns:Cube", namespaces); if (!DateTime.TryParseExact(dailyRates.Attributes["time"].Value, "yyyy-MM-dd", null, DateTimeStyles.None, out var updateDate)) updateDate = DateTime.UtcNow; foreach (XmlNode currency in dailyRates.ChildNodes) { //get rate if (!decimal.TryParse(currency.Attributes["rate"].Value, NumberStyles.Currency, CultureInfo.InvariantCulture, out var currencyRate)) continue; ratesToEuro.Add(new Core.Domain.Directory.ExchangeRate() { CurrencyCode = currency.Attributes["currency"].Value, Rate = currencyRate, UpdatedOn = updateDate }); } } catch (Exception ex) { await _logger.ErrorAsync("ECB exchange rate provider", ex); } //return result for the euro if (exchangeRateCurrencyCode.Equals("eur", StringComparison.InvariantCultureIgnoreCase)) return ratesToEuro; //use only currencies that are supported by ECB var exchangeRateCurrency = ratesToEuro.FirstOrDefault(rate => rate.CurrencyCode.Equals(exchangeRateCurrencyCode, StringComparison.InvariantCultureIgnoreCase)) ?? throw new NopException(await _localizationService.GetResourceAsync("Plugins.ExchangeRate.EcbExchange.Error")); //return result for the selected (not euro) currency return ratesToEuro.Select(rate => new Core.Domain.Directory.ExchangeRate { CurrencyCode = rate.CurrencyCode, Rate = Math.Round(rate.Rate / exchangeRateCurrency.Rate, 4), UpdatedOn = rate.UpdatedOn }).ToList(); } /// /// Install the plugin /// /// A task that represents the asynchronous operation public override async Task InstallAsync() { //settings var defaultSettings = new EcbExchangeRateSettings { EcbLink = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" }; await _settingService.SaveSettingAsync(defaultSettings); //locales await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.ExchangeRate.EcbExchange.Error", "You can use ECB (European central bank) exchange rate provider only when the primary exchange rate currency is supported by ECB"); await base.InstallAsync(); } /// /// Uninstall the plugin /// /// A task that represents the asynchronous operation public override async Task UninstallAsync() { //settings await _settingService.DeleteSettingAsync(); //locales await _localizationService.DeleteLocaleResourceAsync("Plugins.ExchangeRate.EcbExchange.Error"); await base.UninstallAsync(); } #endregion }