Handle missing exchange rate provider, allow fallback for missing rates #955

Merged
zachgoll merged 2 commits from zachgoll/currency-conversion-updates into main 2024-07-08 21:04:59 +08:00
zachgoll commented 2024-07-07 02:10:28 +08:00 (Migrated from github.com)

This PR reworks how we fetch exchange rates and provides a more explicit interface for dealing with missing rates.

Overview

Fallback exchange rates

Previously, the exchange_to method on Money would silently return a nil value. It now either raises a Money::ConversionError, or if provided a fallback rate to use, uses that for the conversion.

This makes it convenient to "zero out" a conversion or even provide a user-defined fallback exchange rate for specific currencies.

Simplification of exchange rate fixtures

Previously, many of the tests were dependent on the existence of exchange rates in the database to properly calculate family results. This made it challenging to know which tests needed these rates and which tests didn't.

As an ongoing, incremental effort to reduce the number of fixtures we're dealing with and decouple the test suite, I've explicitly defined exchange rates for the tests that need them.

Simplified exchange rate fetching

The ExchangeRate class has been reduced to 2 methods:

  • find_rate - fetch single rate from DB, and if not found, attempt to find it from configured exchange rate provider
  • find_rates - the "bulk" version of find_rate. Currently, it has similar functionality, but in the future, this will be replaced by a more efficient call to data providers (rather than looping through rates 1 by 1)

By providing cache: true to these methods, rates fetched from a data provider will be saved to the DB.

This PR reworks how we fetch exchange rates and provides a more explicit interface for dealing with missing rates. ## Overview ### Fallback exchange rates Previously, the `exchange_to` method on `Money` would silently return a `nil` value. It now either raises a `Money::ConversionError`, or if provided a fallback rate to use, uses that for the conversion. This makes it convenient to "zero out" a conversion or even provide a user-defined fallback exchange rate for specific currencies. ### Simplification of exchange rate fixtures Previously, many of the tests were dependent on the existence of exchange rates in the database to properly calculate family results. This made it challenging to know which tests needed these rates and which tests didn't. As an ongoing, incremental effort to reduce the number of fixtures we're dealing with and decouple the test suite, I've explicitly defined exchange rates for the tests that need them. ### Simplified exchange rate fetching The ExchangeRate class has been reduced to 2 methods: - `find_rate` - fetch single rate from DB, and if not found, attempt to find it from configured exchange rate provider - `find_rates` - the "bulk" version of `find_rate`. Currently, it has similar functionality, but in the future, this will be replaced by a more efficient call to data providers (rather than looping through rates 1 by 1) By providing `cache: true` to these methods, rates fetched from a data provider will be saved to the DB.
Sign in to join this conversation.