Skip to content

Commit 6bbbcb5

Browse files
authored
Merge pull request #98 from cloudblue/cloudblue/fix/LITE-30685-fix-currency-converter
Fix currency converter by changing data provider
2 parents 2903239 + cee2bf6 commit 6bbbcb5

6 files changed

Lines changed: 38 additions & 41 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ The current release provides the following transformations:
1111
* `Split columns`: This transformation function allows you to divide values of one column into separate columns, using regular expressions.
1212
* `Lookup CloudBlue subscription data`: This transformation function allows you to get the Cloudblue subscription data by the subscription ID or parameter value.
1313
* `Lookup CloudBlue product item`: This transformation function allows you to get the CloudBlue product item data by the product item ID or MPN.
14-
* `Convert currency`: This transformation function allows you to convert currency rates, using the https://apilayer.com/marketplace/exchangerates_data-api API.
14+
* `Convert currency`: This transformation function allows you to convert currency rates, using the https://openexchangerates.org API.
1515
* `Formula`: This transformation function allows you to perform mathematical and logical operations on columns and context variables using the jq programming language.
1616
* `Delete rows by condition`: This transformation function allows you to delete rows that contain or do not contain a specific value(s).
1717
* `Lookup data from AirTable`: This transformation function allows you to populate data from AirTable by matching input column values with AirTable ones.
1818
* `Lookup data from Excel file attached to stream`: This transformation function allows you to populate data from the attached Excel file by matching input column values with the attached table values.
1919
* `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.
2020

2121

22-
For currency convert and VAT rate environment variable EXCHANGE_API_KEY is required. Visit https://apilayer.com to choose plan and obtain API Key.
22+
To convert currency rates, the environment variable EXCHANGE_API_KEY is required. Visit https://openexchangerates.org to choose plan and obtain API Key.
2323

2424
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.
2525

connect_transformations/currency_conversion/mixins.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def input_columns(self):
5050
name='Convert currency',
5151
description=(
5252
'This transformation function allows you to convert currency rates, using the '
53-
'[Exchange rates API](https://apilayer.com/marketplace/exchangerates_data-api).'
53+
'[Open Exchange Rates API](https://openexchangerates.org).'
5454
),
5555
edit_dialog_ui='/static/transformations/currency_conversion.html',
5656
)
@@ -115,23 +115,23 @@ async def get_available_currencies(
115115
config: dict = Depends(get_config),
116116
):
117117
try:
118-
url = 'https://api.apilayer.com/exchangerates_data/symbols'
118+
url = 'https://openexchangerates.org/api/currencies.json'
119119
async with httpx.AsyncClient(
120120
transport=httpx.AsyncHTTPTransport(retries=3),
121121
) as client:
122122
response = await client.get(
123123
url,
124-
headers={'apikey': config['EXCHANGE_API_KEY']},
124+
params={'app_id': config['EXCHANGE_API_KEY']},
125125
)
126126
data = response.json()
127-
if response.status_code != 200 or not data['success']:
127+
if response.status_code != 200:
128128
return []
129129
currencies = []
130-
for key in data['symbols']:
130+
for key in data:
131131
currencies.append(
132132
Currency(
133133
code=key,
134-
description=data['symbols'][key],
134+
description=data[key],
135135
),
136136
)
137137
return currencies

connect_transformations/currency_conversion/utils.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,29 +77,29 @@ def validate_currency_conversion(data):
7777

7878
def load_currency_rate(currency_from, currency_to, api_key):
7979
try:
80-
url = 'https://api.apilayer.com/exchangerates_data/latest'
80+
url = 'https://openexchangerates.org/api/latest.json'
8181
params = {
8282
'symbols': currency_to,
8383
'base': currency_from,
8484
}
8585

8686
response = requests.get(
8787
url,
88-
params=params,
89-
headers={'apikey': api_key},
88+
params={**params, 'app_id': api_key},
9089
)
9190
response.raise_for_status()
9291
data = response.json()
9392

94-
if not data['success']:
93+
if not data.get('rates'):
9594
raise CurrencyConversionError(
9695
f'Unexpected response calling {url}'
9796
f' with params {params}',
9897
)
9998

10099
return Decimal(data['rates'][currency_to])
101100
except requests.RequestException as exc:
101+
safe_exc = str(exc).split('?', 1)[0]
102102
raise CurrencyConversionError(
103103
f'An error occurred while requesting {url} with '
104-
f'params {params}: {exc}',
104+
f'params {params}: {safe_exc}',
105105
)

connect_transformations/vat_rate/mixins.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ def preload_eu_vat_rates(self):
4646
@transformation(
4747
name='Get standard VAT rate for EU country',
4848
description=(
49-
'This transformation function is performed, using the latest rates from the '
50-
'[Exchange rates API](https://apilayer.com/marketplace/exchangerates_data-api). '
49+
'This transformation function is performed, using the latest VAT rates from the '
50+
'[Tax Data API](https://apilayer.com/marketplace/tax_data-api). '
5151
'The input value must be either a two-letter country code defined'
5252
' in the ISO 3166-1 alpha-2 standard or country name. '
5353
'For example, ES or Spain.'

tests/transformations/test_currency_conversion.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ def test_currency_conversion_first(mocker, responses):
1616
params = {
1717
'symbols': 'EUR',
1818
'base': 'USD',
19+
'app_id': '1a2b3c4d5e6f',
1920
}
2021
responses.add(
2122
'GET',
22-
'https://api.apilayer.com/exchangerates_data/latest',
23+
'https://openexchangerates.org/api/latest.json',
2324
match=[matchers.query_param_matcher(params)],
2425
json={
25-
'success': True,
2626
'rates': {'EUR': 0.92343},
2727
},
2828
)
2929
m = mocker.MagicMock()
30-
app = StandardTransformationsApplication(m, m, config={'EXCHANGE_API_KEY': 'API Key'})
30+
app = StandardTransformationsApplication(m, m, config={'EXCHANGE_API_KEY': '1a2b3c4d5e6f'})
3131
app.transformation_request = {
3232
'transformation': {
3333
'settings': [{
@@ -59,18 +59,18 @@ def test_currency_conversion_single_backward_compt(mocker, responses):
5959
params = {
6060
'symbols': 'EUR',
6161
'base': 'USD',
62+
'app_id': '1a2b3c4d5e6f',
6263
}
6364
responses.add(
6465
'GET',
65-
'https://api.apilayer.com/exchangerates_data/latest',
66+
'https://openexchangerates.org/api/latest.json',
6667
match=[matchers.query_param_matcher(params)],
6768
json={
68-
'success': True,
6969
'rates': {'EUR': 0.92343},
7070
},
7171
)
7272
m = mocker.MagicMock()
73-
app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': 'API Key'})
73+
app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': '1a2b3c4d5e6f'})
7474
app.transformation_request = {
7575
'transformation': {
7676
'settings': {
@@ -102,18 +102,19 @@ def test_currency_conversion(mocker, responses):
102102
params = {
103103
'symbols': 'EUR',
104104
'base': 'USD',
105+
'app_id': '1a2b3c4d5e6f',
105106
}
106107
responses.add(
107108
'GET',
108-
'https://api.apilayer.com/exchangerates_data/latest',
109+
'https://openexchangerates.org/api/latest.json',
109110
match=[matchers.query_param_matcher(params)],
110111
json={
111112
'success': True,
112113
'rates': {'EUR': 0.92343},
113114
},
114115
)
115116
m = mocker.MagicMock()
116-
app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': 'API Key'})
117+
app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': '1a2b3c4d5e6f'})
117118
app.transformation_request = {
118119
'transformation': {
119120
'settings': [{
@@ -145,15 +146,16 @@ def test_currency_conversion_first_http_error(mocker, responses):
145146
params = {
146147
'symbols': 'EUR',
147148
'base': 'USD',
149+
'app_id': '1a2b3c4d5e6f',
148150
}
149151
responses.add(
150152
'GET',
151-
'https://api.apilayer.com/exchangerates_data/latest',
153+
'https://openexchangerates.org/api/latest.json',
152154
match=[matchers.query_param_matcher(params)],
153155
status=500,
154156
)
155157
m = mocker.MagicMock()
156-
app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': 'API Key'})
158+
app = StandardTransformationsApplication(m, m, {'EXCHANGE_API_KEY': '1a2b3c4d5e6f'})
157159
app.transformation_request = {
158160
'transformation': {
159161
'settings': [{
@@ -170,9 +172,10 @@ def test_currency_conversion_first_http_error(mocker, responses):
170172
assert response.status == ResultType.FAIL
171173
assert (
172174
'An error occurred while requesting '
173-
'https://api.apilayer.com/exchangerates_data/latest with params'
175+
'https://openexchangerates.org/api/latest.json with params'
174176
" {'symbols': 'EUR', 'base': 'USD'}"
175177
) in response.output, response.output
178+
assert 'app_id' not in response.output
176179

177180

178181
def test_currency_conversion_null_value(mocker):

tests/webapp/test_currency_conversion.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,19 +149,16 @@ def test_get_available_rates(
149149
):
150150
httpx_mock.add_response(
151151
method='GET',
152-
url='https://api.apilayer.com/exchangerates_data/symbols',
152+
url='https://openexchangerates.org/api/currencies.json?app_id=1a2b3c4d5e6f',
153153
json={
154-
'symbols': {
155-
'EUR': 'Euro',
156-
'USD': 'United States Dollar',
157-
},
158-
'success': True,
154+
'EUR': 'Euro',
155+
'USD': 'United States Dollar',
159156
},
160157
)
161158
client = test_client_factory(TransformationsWebApplication)
162159
response = client.get(
163160
'/api/currency_conversion/currencies',
164-
config={'EXCHANGE_API_KEY': 'API Key'},
161+
config={'EXCHANGE_API_KEY': '1a2b3c4d5e6f'},
165162
)
166163

167164
assert response.status_code == 200
@@ -184,16 +181,13 @@ def test_get_available_rates_invalid_response(
184181
):
185182
httpx_mock.add_response(
186183
method='GET',
187-
url='https://api.apilayer.com/exchangerates_data/symbols',
188-
json={
189-
'symbols': {},
190-
'success': False,
191-
},
184+
url='https://openexchangerates.org/api/currencies.json?app_id=1a2b3c4d5e6f',
185+
json={},
192186
)
193187
client = test_client_factory(TransformationsWebApplication)
194188
response = client.get(
195189
'/api/currency_conversion/currencies',
196-
config={'EXCHANGE_API_KEY': 'API Key'},
190+
config={'EXCHANGE_API_KEY': '1a2b3c4d5e6f'},
197191
)
198192

199193
assert response.status_code == 200
@@ -207,13 +201,13 @@ def test_get_available_rates_invalid_status_code(
207201
):
208202
httpx_mock.add_response(
209203
method='GET',
210-
url='https://api.apilayer.com/exchangerates_data/symbols',
204+
url='https://openexchangerates.org/api/currencies.json?app_id=1a2b3c4d5e6f',
211205
status_code=400,
212206
)
213207
client = test_client_factory(TransformationsWebApplication)
214208
response = client.get(
215209
'/api/currency_conversion/currencies',
216-
config={'EXCHANGE_API_KEY': 'API Key'},
210+
config={'EXCHANGE_API_KEY': '1a2b3c4d5e6f'},
217211
)
218212

219213
assert response.status_code == 200

0 commit comments

Comments
 (0)