We have been getting a bunch of exchange rate for order errors now.
An error occured whilst fetching the exchange rate for order {OrderId}
System.ArgumentNullException: Value cannot be null.
Parameter name: source
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at Vendr.Infrastructure.Services.ExchangeRatesApiCurrencyExchangeRateService.FetchExchangeRate(String fromCurrencyIsoCode, String toCurrencyIsoCode, DateTime date)
at Vendr.Infrastructure.Services.CurrencyExchangeRateServiceBase.GetExchangeRate(String fromCurrencyIsoCode, String toCurrencyIsoCode, DateTime date)
at Vendr.Core.Events.Domain.Handlers.Order.SetOrderBaseCurrencyExchangeRate.Handle(OrderFinalized evt)
I am really confused on what this is. And how I would go about resolving it. We are using multiple currencies but we aren't using a 3rd party exchange rates API. Would love some input on this
Thanks for raising this, it's just brough something to my attention that we are going to need to resolve.
Ultimately, Vendr OOTB connects to an exchange rate service (https://exchangeratesapi.io/) to calculate order exchange rates (it should only do this for orders not in a stores base currency). This is predominantly so that the analytics section / commerce dashboard are able to report sales figures in a single currency (the base currency defined on the store). Without this, stores handling multiple currencies couldn't show a single set of values.
The issue appears to be that this service previously didn't require any authentication to use the free tier however they now require an API key to be passed and so the exchange rate lookup are failing so it looks like we may need to source an alternative, or require folks to register and supply an API key.
We do have multiple implementations for different providers if you want to sign up to one of those in the meantime (Currency Layer has the same limits on the free tier)
ExchangeRatesApiCurrencyExchangeRateService
CurrencyLayerCurrencyExchangeRateService
FixerCurrencyExchangeRateService
These can be swapped out via the DI container
builder.Services.AddUnique<ICurrencyExchangeRateService>(f => new CurrencyLayerCurrencyExchangeRateService(apiKey));
Alternatively you can also implement the ICurrencyExchangeRateService if you have another service you wish to connect to.
Unfortunately there is just no way of doing these calculations without using a 3rd party service and so we tried to use the path of least resistance for most implementations, but it looks like even that may not be viable anymore.
Ok, looks like I've found another free alternative https://exchangerate.host/ if you want to try this. You'll need to define a new Exchange Rate Service like so
public class ExchangerateHostCurrencyExchangeRateService: CurrencyExchangeRateServiceBase
{
private const string API_BASE_URL = "https://api.exchangerate.host";
public override decimal FetchExchangeRate(string fromCurrencyIsoCode, string toCurrencyIsoCode, DateTime date)
{
return Get<ExchangerateHostSingleResponse>($"{API_BASE_URL}/{date:yyyy-MM-dd}?base={fromCurrencyIsoCode.ToUpper()}&symbols={toCurrencyIsoCode.ToUpper()}")
.Rates?.First().Value ?? 0;
}
public override Dictionary<string, Dictionary<string, decimal>> FetchExchangeRates(string fromCurrencyIsoCode, string[] toCurrencyIsoCodes, DateTime dateFrom, DateTime dateTo)
{
var results = new Dictionary<string, Dictionary<string, decimal>>();
LoopByMaxDateRange(dateFrom, dateTo, 365, (startDate, endDate) =>
{
var r = Get<ExchangerateHostTimeframeResponse>($"{API_BASE_URL}/timeseries?base={fromCurrencyIsoCode.ToUpper()}&symbols={string.Join(",", toCurrencyIsoCodes.Select(x => x.ToUpper()))}&start_date={startDate:yyyy-MM-dd}&end_date={endDate:yyyy-MM-dd}");
if (r?.Rates != null)
{
foreach (var rate in r.Rates)
{
results.Add(rate.Key, rate.Value);
}
}
});
return results;
}
}
internal class ExchangerateHostResponse
{
[JsonProperty(PropertyName = "base")]
public string Base { get; set; }
[JsonProperty(PropertyName = "date")]
public DateTime Date { get; set; }
}
internal class ExchangerateHostSingleResponse : ExchangerateHostResponse
{
[JsonProperty(PropertyName = "rates")]
public Dictionary<string, decimal> Rates { get; set; }
}
internal class ExchangerateHostTimeframeResponse : ExchangerateHostResponse
{
[JsonProperty(PropertyName = "rates")]
public Dictionary<string, Dictionary<string, decimal>> Rates { get; set; }
}
And then in your Startup / Composer you'll need to swap out the default implementation like so
I just implemented the new exchange rate service! Is there a way to double test if it works? Or is it just to leave it for a day and double check if any error has occurred?
there is nothing explicit to trigger it so it kind of is wait and see. This said, there is a background task that runs to try and re-populate exchange rates that failed so maybe look back at the orders that failed and see if the values have been populated.
Failing this, yea, just wait a few days and see if the error continues. It's not detrimental to order taking if you see those errors. As I say, it's mostly for the analytics section.
Exchange rate for order vendr
Hi!
We have been getting a bunch of exchange rate for order errors now.
I am really confused on what this is. And how I would go about resolving it. We are using multiple currencies but we aren't using a 3rd party exchange rates API. Would love some input on this
//Johannes
Hi Johannes,
Thanks for raising this, it's just brough something to my attention that we are going to need to resolve.
Ultimately, Vendr OOTB connects to an exchange rate service (https://exchangeratesapi.io/) to calculate order exchange rates (it should only do this for orders not in a stores base currency). This is predominantly so that the analytics section / commerce dashboard are able to report sales figures in a single currency (the base currency defined on the store). Without this, stores handling multiple currencies couldn't show a single set of values.
The issue appears to be that this service previously didn't require any authentication to use the free tier however they now require an API key to be passed and so the exchange rate lookup are failing so it looks like we may need to source an alternative, or require folks to register and supply an API key.
We do have multiple implementations for different providers if you want to sign up to one of those in the meantime (Currency Layer has the same limits on the free tier)
These can be swapped out via the DI container
Alternatively you can also implement the
ICurrencyExchangeRateService
if you have another service you wish to connect to.Unfortunately there is just no way of doing these calculations without using a 3rd party service and so we tried to use the path of least resistance for most implementations, but it looks like even that may not be viable anymore.
Hope this helps
// Matt
Ok, looks like I've found another free alternative https://exchangerate.host/ if you want to try this. You'll need to define a new Exchange Rate Service like so
And then in your Startup / Composer you'll need to swap out the default implementation like so
I'm going to change this to be the new default, but if you want on going stability, you might want to look at one of the paid / registered options.
Hope this helps
Matt
Hi Matt!
I just implemented the new exchange rate service! Is there a way to double test if it works? Or is it just to leave it for a day and double check if any error has occurred?
//Johannes
Hi Johannes,
there is nothing explicit to trigger it so it kind of is wait and see. This said, there is a background task that runs to try and re-populate exchange rates that failed so maybe look back at the orders that failed and see if the values have been populated.
Failing this, yea, just wait a few days and see if the error continues. It's not detrimental to order taking if you see those errors. As I say, it's mostly for the analytics section.
Hi Matt!
I have left it for a while now, and it works like a charm!
Thank you so much Matt! #H5YR
//Johannes
Fantastic!
I implemented as the default and pushed it out in the latest release so hopefully others won't have to face this issue.
Thanks again for reporting it, and actually coming back to tell me 👍
Matt
is working on a reply...