diff --git a/README.md b/README.md index d2aeb82..bfeacf2 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The current release provides the following transformations: * `Split columns`: This transformation function allows you to divide values of one column into separate columns, using regular expressions. * `Lookup CloudBlue subscription data`: This transformation function allows you to get the Cloudblue subscription data by the subscription ID or parameter value. * `Lookup CloudBlue product item`: This transformation function allows you to get the CloudBlue product item data by the product item ID or MPN. -* `Convert currency`: This transformation function allows you to convert currency rates, using the https://apilayer.com/marketplace/exchangerates_data-api API. +* `Convert currency`: This transformation function allows you to convert currency rates, using the https://openexchangerates.org API. * `Formula`: This transformation function allows you to perform mathematical and logical operations on columns and context variables using the jq programming language. * `Delete rows by condition`: This transformation function allows you to delete rows that contain or do not contain a specific value(s). * `Lookup data from AirTable`: This transformation function allows you to populate data from AirTable by matching input column values with AirTable ones. @@ -19,7 +19,7 @@ The current release provides the following transformations: * `Get standard VAT Rate for EU Country`: This transformation function is performed, using the latest rates from the https://apilayer.com/marketplace/tax_data-api API. The input value must be either a two-letter country code defined in the ISO 3166-1 alpha-2 standard or country name. For example, ES or Spain. -For currency convert and VAT rate environment variable EXCHANGE_API_KEY is required. Visit https://apilayer.com to choose plan and obtain API Key. +To convert currency rates, the environment variable EXCHANGE_API_KEY is required. Visit https://openexchangerates.org to choose plan and obtain API Key. Overall, Connect Standard Transformations Library is a valuable extension of the CloudBlue Connect platform that provides users with a powerful set of tools for managing and manipulating data. By providing pre-built transformations that can be easily configured and executed, Connect Standard Transformations Library streamlines the data transformation process and makes it easier for users to work with their data. diff --git a/connect_transformations/currency_conversion/mixins.py b/connect_transformations/currency_conversion/mixins.py index bae79e7..4de3b35 100644 --- a/connect_transformations/currency_conversion/mixins.py +++ b/connect_transformations/currency_conversion/mixins.py @@ -50,7 +50,7 @@ def input_columns(self): name='Convert currency', description=( 'This transformation function allows you to convert currency rates, using the ' - '[Exchange rates API](https://apilayer.com/marketplace/exchangerates_data-api).' + '[Open Exchange Rates API](https://openexchangerates.org).' ), edit_dialog_ui='/static/transformations/currency_conversion.html', ) @@ -115,23 +115,23 @@ async def get_available_currencies( config: dict = Depends(get_config), ): try: - url = 'https://api.apilayer.com/exchangerates_data/symbols' + url = 'https://openexchangerates.org/api/currencies.json' async with httpx.AsyncClient( transport=httpx.AsyncHTTPTransport(retries=3), ) as client: response = await client.get( url, - headers={'apikey': config['EXCHANGE_API_KEY']}, + params={'app_id': config['EXCHANGE_API_KEY']}, ) data = response.json() - if response.status_code != 200 or not data['success']: + if response.status_code != 200: return [] currencies = [] - for key in data['symbols']: + for key in data: currencies.append( Currency( code=key, - description=data['symbols'][key], + description=data[key], ), ) return currencies diff --git a/connect_transformations/currency_conversion/utils.py b/connect_transformations/currency_conversion/utils.py index 40ee59f..91eb89d 100644 --- a/connect_transformations/currency_conversion/utils.py +++ b/connect_transformations/currency_conversion/utils.py @@ -77,7 +77,7 @@ def validate_currency_conversion(data): def load_currency_rate(currency_from, currency_to, api_key): try: - url = 'https://api.apilayer.com/exchangerates_data/latest' + url = 'https://openexchangerates.org/api/latest.json' params = { 'symbols': currency_to, 'base': currency_from, @@ -85,13 +85,12 @@ def load_currency_rate(currency_from, currency_to, api_key): response = requests.get( url, - params=params, - headers={'apikey': api_key}, + params={**params, 'app_id': api_key}, ) response.raise_for_status() data = response.json() - if not data['success']: + if not data.get('rates'): raise CurrencyConversionError( f'Unexpected response calling {url}' f' with params {params}', @@ -99,7 +98,8 @@ def load_currency_rate(currency_from, currency_to, api_key): return Decimal(data['rates'][currency_to]) except requests.RequestException as exc: + safe_exc = str(exc).split('?', 1)[0] raise CurrencyConversionError( f'An error occurred while requesting {url} with ' - f'params {params}: {exc}', + f'params {params}: {safe_exc}', ) diff --git a/connect_transformations/vat_rate/mixins.py b/connect_transformations/vat_rate/mixins.py index fb192a4..0099727 100644 --- a/connect_transformations/vat_rate/mixins.py +++ b/connect_transformations/vat_rate/mixins.py @@ -46,8 +46,8 @@ def preload_eu_vat_rates(self): @transformation( name='Get standard VAT rate for EU country', description=( - 'This transformation function is performed, using the latest rates from the ' - '[Exchange rates API](https://apilayer.com/marketplace/exchangerates_data-api). ' + 'This transformation function is performed, using the latest VAT rates from the ' + '[Tax Data API](https://apilayer.com/marketplace/tax_data-api). ' 'The input value must be either a two-letter country code defined' ' in the ISO 3166-1 alpha-2 standard or country name. ' 'For example, ES or Spain.' diff --git a/tests/transformations/test_currency_conversion.py b/tests/transformations/test_currency_conversion.py index 6e0acb2..acde520 100644 --- a/tests/transformations/test_currency_conversion.py +++ b/tests/transformations/test_currency_conversion.py @@ -16,18 +16,18 @@ def test_currency_conversion_first(mocker, responses): params = { 'symbols': 'EUR', 'base': 'USD', + 'app_id': '1a2b3c4d5e6f', } responses.add( 'GET', - 'https://api.apilayer.com/exchangerates_data/latest', + 'https://openexchangerates.org/api/latest.json', match=[matchers.query_param_matcher(params)], json={ - 'success': True, 'rates': {'EUR': 0.92343}, }, ) m = mocker.MagicMock() - app = StandardTransformationsApplication(m, m, config={'EXCHANGE_API_KEY': 'API Key'}) + app = StandardTransformationsApplication(m, m, config={'EXCHANGE_API_KEY': '1a2b3c4d5e6f'}) app.transformation_request = { 'transformation': { 'settings': [{ @@ -59,18 +59,18 @@ def test_currency_conversion_single_backward_compt(mocker, responses): params = { 'symbols': 'EUR', 'base': 'USD', + 'app_id': '1a2b3c4d5e6f', } responses.add( 'GET', - 'https://api.apilayer.com/exchangerates_data/latest', + 'https://openexchangerates.org/api/latest.json', match=[matchers.query_param_matcher(params)], json={ - 'success': True, 'rates': {'EUR': 0.92343}, }, ) m = mocker.MagicMock() - app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': 'API Key'}) + app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': '1a2b3c4d5e6f'}) app.transformation_request = { 'transformation': { 'settings': { @@ -102,10 +102,11 @@ def test_currency_conversion(mocker, responses): params = { 'symbols': 'EUR', 'base': 'USD', + 'app_id': '1a2b3c4d5e6f', } responses.add( 'GET', - 'https://api.apilayer.com/exchangerates_data/latest', + 'https://openexchangerates.org/api/latest.json', match=[matchers.query_param_matcher(params)], json={ 'success': True, @@ -113,7 +114,7 @@ def test_currency_conversion(mocker, responses): }, ) m = mocker.MagicMock() - app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': 'API Key'}) + app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': '1a2b3c4d5e6f'}) app.transformation_request = { 'transformation': { 'settings': [{ @@ -145,15 +146,16 @@ def test_currency_conversion_first_http_error(mocker, responses): params = { 'symbols': 'EUR', 'base': 'USD', + 'app_id': '1a2b3c4d5e6f', } responses.add( 'GET', - 'https://api.apilayer.com/exchangerates_data/latest', + 'https://openexchangerates.org/api/latest.json', match=[matchers.query_param_matcher(params)], status=500, ) m = mocker.MagicMock() - app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': 'API Key'}) + app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': '1a2b3c4d5e6f'}) app.transformation_request = { 'transformation': { 'settings': [{ @@ -170,9 +172,10 @@ def test_currency_conversion_first_http_error(mocker, responses): assert response.status == ResultType.FAIL assert ( 'An error occurred while requesting ' - 'https://api.apilayer.com/exchangerates_data/latest with params' + 'https://openexchangerates.org/api/latest.json with params' " {'symbols': 'EUR', 'base': 'USD'}" ) in response.output, response.output + assert 'app_id' not in response.output def test_currency_conversion_null_value(mocker): diff --git a/tests/webapp/test_currency_conversion.py b/tests/webapp/test_currency_conversion.py index e09bd93..6ca5bfe 100644 --- a/tests/webapp/test_currency_conversion.py +++ b/tests/webapp/test_currency_conversion.py @@ -149,19 +149,16 @@ def test_get_available_rates( ): httpx_mock.add_response( method='GET', - url='https://api.apilayer.com/exchangerates_data/symbols', + url='https://openexchangerates.org/api/currencies.json?app_id=1a2b3c4d5e6f', json={ - 'symbols': { - 'EUR': 'Euro', - 'USD': 'United States Dollar', - }, - 'success': True, + 'EUR': 'Euro', + 'USD': 'United States Dollar', }, ) client = test_client_factory(TransformationsWebApplication) response = client.get( '/api/currency_conversion/currencies', - config={'EXCHANGE_API_KEY': 'API Key'}, + config={'EXCHANGE_API_KEY': '1a2b3c4d5e6f'}, ) assert response.status_code == 200 @@ -184,16 +181,13 @@ def test_get_available_rates_invalid_response( ): httpx_mock.add_response( method='GET', - url='https://api.apilayer.com/exchangerates_data/symbols', - json={ - 'symbols': {}, - 'success': False, - }, + url='https://openexchangerates.org/api/currencies.json?app_id=1a2b3c4d5e6f', + json={}, ) client = test_client_factory(TransformationsWebApplication) response = client.get( '/api/currency_conversion/currencies', - config={'EXCHANGE_API_KEY': 'API Key'}, + config={'EXCHANGE_API_KEY': '1a2b3c4d5e6f'}, ) assert response.status_code == 200 @@ -207,13 +201,13 @@ def test_get_available_rates_invalid_status_code( ): httpx_mock.add_response( method='GET', - url='https://api.apilayer.com/exchangerates_data/symbols', + url='https://openexchangerates.org/api/currencies.json?app_id=1a2b3c4d5e6f', status_code=400, ) client = test_client_factory(TransformationsWebApplication) response = client.get( '/api/currency_conversion/currencies', - config={'EXCHANGE_API_KEY': 'API Key'}, + config={'EXCHANGE_API_KEY': '1a2b3c4d5e6f'}, ) assert response.status_code == 200