"""Test exchange rate endpoint logic.""" import base64 import json import pytest from abacus_common_logic.test_utils.helpers import get_json_body from royalties.constants.constants import ( EXCHANGE_RATE_BULK_FIELD, STATEMENT_PERIOD_STATUSES, ) from royalties.constants.error import ( ERROR_CSV_EMPTY, ERROR_ENTITY_DOES_NOT_EXIST, ERROR_STATEMENT_PERIOD_NOT_ACCEPTING_FILES, ) from royalties.tests.utils.factories import StatementPeriodFactory BULK_ENDPOINT = '/exchange-rate/bulk-exchange-rates' @pytest.fixture def empty_csv_data(): """Return the equivalent of an empty csv.""" data = {} data['statement_period_id'] = 123 data[EXCHANGE_RATE_BULK_FIELD] = base64.b64encode('foo'.encode()).decode() return json.dumps(data) @pytest.fixture(scope='function') def invalid_currency_csv_data(): """Mock request data.""" statement_period = StatementPeriodFactory.create( closed_date=None, statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT ) statement_period_id = str(statement_period.statement_period_id) data = {} data['statement_period_id'] = statement_period.statement_period_id data[EXCHANGE_RATE_BULK_FIELD] = base64.b64encode( '\n'.join( [ '\t'.join(['period_id', 'from', 'ABC', 'DEF']), '\t'.join([statement_period_id, 'DEF', '0.50', '0.4444']), '\t'.join([statement_period_id, 'ABC', '0.4444', '0.50']), ] ).encode() ).decode() return json.dumps(data) @pytest.fixture(scope='function') def invalid_rate_csv_data(): """Mock request data.""" statement_period = StatementPeriodFactory.create( closed_date=None, statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT ) statement_period_id = str(statement_period.statement_period_id) data = {} data['statement_period_id'] = statement_period.statement_period_id data[EXCHANGE_RATE_BULK_FIELD] = base64.b64encode( '\n'.join( [ '\t'.join(['period_id', 'from', 'CAD', 'USD']), '\t'.join([statement_period_id, 'USD', 'abc', 'def']), '\t'.join([statement_period_id, 'CAD', '4teen', '5teen']), ] ).encode() ).decode() return json.dumps(data) def test_bulk_exchange_upload_no_data(fixture_client): """Tests hitting the upload endpoint without data.""" response = fixture_client.post(BULK_ENDPOINT, content_type='application/json') assert response.status_code == 400 def test_bulk_exchange_upload_with_data_no_period(fixture_client, empty_csv_data): """Tests hitting the upload endpoint with data but no open statement period.""" response = fixture_client.post( BULK_ENDPOINT, data=empty_csv_data, content_type='application/json' ) json_response = get_json_body(response) assert response.status_code == 400 assert json_response['message'] == ERROR_ENTITY_DOES_NOT_EXIST.format( object_type='StatementPeriod', object_id=123 ) def test_bulk_exchange_upload_with_period_and_no_data(fixture_client, empty_csv_data): """Tests passing empty data to the upload endpoint with an open statement period.""" StatementPeriodFactory.create( statement_period_id=123, closed_date=None, statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT, ) response = fixture_client.post( BULK_ENDPOINT, data=empty_csv_data, content_type='application/json' ) json_response = get_json_body(response) assert response.status_code == 400 assert json_response['message'] == {'errors': [ERROR_CSV_EMPTY], 'rows': []} def test_bulk_exchange_rate_upload_closed_period(fixture_client, empty_csv_data): """Tests uploading rates while the accounting period is CLOSED.""" StatementPeriodFactory.create( statement_period_id=123, closed_date='2020-01-01', statement_period_status=STATEMENT_PERIOD_STATUSES.CLOSED, ) response = fixture_client.post( BULK_ENDPOINT, data=empty_csv_data, content_type='application/json' ) assert response.status_code == 400 assert response.json['message'] == ERROR_STATEMENT_PERIOD_NOT_ACCEPTING_FILES def test_bulk_exchange_upload_not_accepting_files(fixture_client, empty_csv_data): """Tests uploading rates while the open period is not accepting files.""" StatementPeriodFactory.create( statement_period_id=123, statement_period_status=STATEMENT_PERIOD_STATUSES.OPEN, closed_date=None, ) response = fixture_client.post( BULK_ENDPOINT, data=empty_csv_data, content_type='application/json' ) json_response = get_json_body(response) assert response.status_code == 400 assert json_response['message'] == ERROR_STATEMENT_PERIOD_NOT_ACCEPTING_FILES def test_bulk_exchange_upload_invalid_currency( fixture_client, invalid_currency_csv_data ): """Tests passing an unknown currency code in data.""" response = fixture_client.post( BULK_ENDPOINT, data=invalid_currency_csv_data, content_type='application/json' ) json_response = get_json_body(response) expected_response = { 'errors': [ 'Line:2 Error: Currency code not recognized: DEF', 'Line:3 Error: Currency code not recognized: ABC', ], 'rows': [], } assert response.status_code == 400 assert json_response['message'] == expected_response def test_bulk_exchange_upload_invalid_rate(fixture_client, invalid_rate_csv_data): """Tests passing an invalid rate in the data.""" response = fixture_client.post( BULK_ENDPOINT, data=invalid_rate_csv_data, content_type='application/json' ) json_response = get_json_body(response) expected_response = { 'errors': ['Line:2 Error: Invalid rate.', 'Line:3 Error: Invalid rate.'], 'rows': [], } assert response.status_code == 400 assert json_response['message'] == expected_response @pytest.mark.db('mysql') def test_bulk_exchange_upload_valid_data_with_semicolons( fixture_client, standard_fx_data_with_semicolons, standard_fx_data_with_tabs ): """Tests passing valid data.""" StatementPeriodFactory.create( statement_period_id=123, statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT, closed_date=None, ) response = fixture_client.post( BULK_ENDPOINT, json=standard_fx_data_with_semicolons, content_type='application/json', ) assert response.status_code == 201 json_response = get_json_body(response) assert json_response == { 'errors': [], 'rows': [ { 'to_currency_code': 'AUD', 'rate': '0.3514000000000000000', 'statement_period_id': 123, 'from_currency_code': 'AED', }, { 'to_currency_code': 'USD', 'rate': '0.2722000000000000000', 'statement_period_id': 123, 'from_currency_code': 'AED', }, { 'to_currency_code': 'AUD', 'rate': '0.0019000000000000000', 'statement_period_id': 123, 'from_currency_code': 'AOA', }, { 'to_currency_code': 'USD', 'rate': '0.0015000000000000000', 'statement_period_id': 123, 'from_currency_code': 'AOA', }, { 'to_currency_code': 'AUD', 'rate': '0.0138000000000000000', 'statement_period_id': 123, 'from_currency_code': 'ARS', }, { 'to_currency_code': 'USD', 'rate': '0.0107200000000000000', 'statement_period_id': 123, 'from_currency_code': 'ARS', }, ], } @pytest.mark.db('mysql') def test_bulk_exchange_upload_valid_data_with_tabs( fixture_client, standard_fx_data_with_tabs ): """Tests passing valid data.""" StatementPeriodFactory.create( statement_period_id=123, statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT, closed_date=None, ) response_tabs = fixture_client.post( BULK_ENDPOINT, json=standard_fx_data_with_tabs, content_type='application/json' ) assert response_tabs.status_code == 201 json_response_tabs = get_json_body(response_tabs) assert json_response_tabs == { 'errors': [], 'rows': [ { 'to_currency_code': 'AUD', 'rate': '0.3514000000000000000', 'statement_period_id': 123, 'from_currency_code': 'AED', }, { 'to_currency_code': 'USD', 'rate': '0.2722000000000000000', 'statement_period_id': 123, 'from_currency_code': 'AED', }, { 'to_currency_code': 'AUD', 'rate': '0.0019000000000000000', 'statement_period_id': 123, 'from_currency_code': 'AOA', }, { 'to_currency_code': 'USD', 'rate': '0.0015000000000000000', 'statement_period_id': 123, 'from_currency_code': 'AOA', }, { 'to_currency_code': 'AUD', 'rate': '0.0138000000000000000', 'statement_period_id': 123, 'from_currency_code': 'ARS', }, { 'to_currency_code': 'USD', 'rate': '0.0107200000000000000', 'statement_period_id': 123, 'from_currency_code': 'ARS', }, ], }