"""Tests for validation.""" from random import choice from types import SimpleNamespace from unittest.mock import MagicMock from unittest.mock import patch from abacus_common_data.country import Country from marshmallow import ValidationError import pytest from abacus_account.blueprints.account_tax_info import validate_record_owner from abacus_account.constants import error from abacus_account.constants.constants import EMPLOYEE_ALL_VENDORS_MARK from abacus_account.constants.constants import ORCHARD_PAYEE_ROLE from abacus_account.constants.constants import ORCHARD_ROLES from abacus_account.constants.constants import VENDOR_RESOURCE_NAME from abacus_account.models import AccountPaymentTerm from abacus_account.utils.validations import validate_country_code from abacus_account.utils.validations import validate_payload from abacus_account.utils.validations import validate_payment_type from abacus_account.utils.validations import validate_payoneer_program from tests.utils.factories import AccountFactory from tests.utils.factories import AccountPayeeFactory account_id = 2 vendor_id = 3 profile_id_header = 1234 profile_type_header = 'DocumentsProfile' def test_validate_country_code_success(): """Test success validation of country code.""" country_code = choice(Country.get_list()).alpha3 assert validate_country_code(country_code) is None def test_validate_country_code_fail(): """Test failed validation of country code.""" country_code = 'Test' expected_error_message = error.ERROR_UNKNOWN_COUNTRY.format( code=country_code ) with pytest.raises(ValidationError, match=expected_error_message): validate_country_code(country_code) def test_validate_payment_type_success(fresh_db, reference_payment_entity_fixture): """Test success validation of country code.""" account = AccountFactory.create( account_id=11 ) payment_term_obj = AccountPaymentTerm.create( account_id=account.account_id, currency_code='USD', payment_entity_id=5, payment_minimum='350', payment_schedule='30_days_after_month_end', ) assert validate_payment_type(payment_term_obj, { 'payment_entity_id': 5, 'agreement_type_id': 12 }) is None def test_validate_payment_type_success_knr_not_modifies_agreement( fresh_db, reference_payment_entity_fixture ): """Test success validation of knr not modifies agreement type.""" account = AccountFactory.create( account_id=12 ) payment_term_obj = AccountPaymentTerm.create( account_id=account.account_id, currency_code='USD', payment_entity_id=4, payment_minimum='350', payment_schedule='30_days_after_month_end', ) assert validate_payment_type(payment_term_obj, { 'payment_entity_id': 4, }) is None def test_validate_payment_type_fail(fresh_db, reference_payment_entity_fixture): """Test failed validation of country code.""" account = AccountFactory.create( account_id=13 ) payment_term_obj = AccountPaymentTerm.create( account_id=account.account_id, currency_code='USD', payment_entity_id=4, payment_minimum='350', payment_schedule='30_days_after_month_end', ) expected_error_message = error.ERROR_KNR_ACCOUNT_CANT_MODIFY_AGREEMENT_TYPE.format( payment_term_id=payment_term_obj.account_payment_term_id ) with pytest.raises(ValidationError, match=expected_error_message): validate_payment_type(payment_term_obj, { 'payment_entity_id': 4, 'agreement_type_id': 3 }) def test_validate_record_owner_error_on_profile_headers(mocker): """ Test request owner validation of the request and account tax info record. Error on getting Orchard headers. """ mocker.patch('abacus_account.utils.validations.flask_request' '.get_profile_headers', return_value=('DocumentsProfile', None)) result = validate_record_owner({}, account_id) assert not result def test_validate_record_owner_ok_on_missing_type_headers(mocker): """ Test request owner validation of the request and account tax info record. Ok on getting empty profile type within Orchard headers. """ mocker.patch('abacus_account.utils.validations.flask_request' '.get_profile_headers', return_value=(None, None)) result = validate_record_owner({}, account_id) assert result def test_validate_record_owner_error_on_profile_id_header(mocker): """ Test request owner validation of the request and account tax info record. Error on getting Orchard-Profile-Id header. """ mocker.patch('abacus_account.utils.validations.flask_request.' 'get_profile_headers', return_value=(profile_type_header, None)) result = validate_record_owner({}, account_id) assert not result def test_validate_record_owner_error_on_ows_abacus_account_error(mocker): """ Test request owner validation of the request and account tax info record. Error on ows-abacus-account request. """ mocker.patch('abacus_account.utils.validations.flask_request.' 'get_profile_headers', return_value=('DocumentsProfile', 1234)) ows_abacus_response_mock = MagicMock(json_data={}, status_code=403) mocker.patch('abacus_account.utils.validations.ows_client.get', return_value=ows_abacus_response_mock) mock_headers = MagicMock(return_value={'headers': { ORCHARD_ROLES: ORCHARD_PAYEE_ROLE }}) result = validate_record_owner(mock_headers, account_id) assert not result def test_validate_record_owner_error_on_ows_permissions_error(mocker): """ Test request owner validation of the request and account tax info record. Error on ows-permissions request. """ mocker.patch('abacus_account.utils.validations.flask_request.' 'get_profile_headers', return_value=('DocumentsProfile', 1234)) ows_permissions_response_mock = MagicMock(json={}, status_code=404) mocker.patch('abacus_account.utils.validations.ows_client.get', side_effect=[ows_permissions_response_mock]) mock_headers = MagicMock(return_value={'headers': { ORCHARD_ROLES: ORCHARD_PAYEE_ROLE }}) result = validate_record_owner(mock_headers, account_id) assert not result def test_validate_record_owner_success(mocker): """ Test request owner validation of the request and account tax info record. Success validation. """ mocker.patch('abacus_account.utils.validations.flask_request.' 'get_profile_headers', return_value=('DocumentsProfile', 1234)) mock_perm_resp = mocker.Mock() mock_perm_resp.return_value = { 'items': [{'type': VENDOR_RESOURCE_NAME, 'vendorId': account_id}] } ows_permissions_response_mock = MagicMock( json=mock_perm_resp, status_code=200 ) mocker.patch('abacus_account.utils.validations.ows_client.get', side_effect=[ows_permissions_response_mock]) mock_headers = MagicMock(return_value={'headers': { ORCHARD_ROLES: ORCHARD_PAYEE_ROLE }}) result = validate_record_owner(mock_headers, account_id) assert result def test_validate_record_owner_success_on_employee_request(mocker): """ Test request owner validation of the request and account tax info record. Success validation on employee request. """ mocker.patch('abacus_account.utils.validations.flask_request.' 'get_profile_headers', return_value=('DocumentsProfile', 1234)) mock_perm_resp = mocker.Mock() mock_perm_resp.return_value = { 'items': [{ 'type': VENDOR_RESOURCE_NAME, 'vendorId': EMPLOYEE_ALL_VENDORS_MARK }] } ows_permissions_response_mock = MagicMock( json=mock_perm_resp, status_code=200 ) mocker.patch('abacus_account.utils.validations.ows_client.get', side_effect=[ows_permissions_response_mock]) mock_headers = MagicMock(return_value={'headers': { ORCHARD_ROLES: ORCHARD_PAYEE_ROLE }}) result = validate_record_owner(mock_headers, account_id) assert result @patch('abacus_account.utils.validations.models') @patch('abacus_account.utils.validations.logic') def test_validate_payoneer_program( mock_logic, mock_models, fresh_db, reference_payment_entity_fixture ): """Test validate_payoneer_program.""" account = AccountFactory.create( account_id=13 ) account_payee = AccountPayeeFactory.create(account=account) payment_term_obj = AccountPaymentTerm.create( account_id=account.account_id, currency_code='USD', payment_entity_id=5, payment_minimum='350', payment_schedule='30_days_after_month_end' ) params = {'payoneer_program_id': 12345} mock_logic.get_payoneer_program.return_value = SimpleNamespace( status=200, message=dict(payoneer_program_id=12345) ) mock_models.AccountPaymentTerm.query.filter_by.return_value \ .first.return_value = payment_term_obj result = validate_payoneer_program(account_payee, **params) assert result is None mock_logic.get_payoneer_program.assert_called_once_with( currency_code=payment_term_obj.currency_code, agreement_type_id=payment_term_obj.agreement_type_id, payment_entity_id=payment_term_obj.payment_entity_id, reference_payment_type_id=None ) @patch('abacus_account.utils.validations.models') @patch('abacus_account.utils.validations.logic') def test_validate_payoneer_program_with_reference_payment_type_id( mock_logic, mock_models, fresh_db, reference_payment_entity_fixture ): """Test validate_payoneer_program passes reference_payment_type_id when provided.""" account = AccountFactory.create( account_id=14 ) account_payee = AccountPayeeFactory.create(account=account) payment_term_obj = AccountPaymentTerm.create( account_id=account.account_id, currency_code='USD', payment_entity_id=5, payment_minimum='350', payment_schedule='30_days_after_month_end' ) reference_payment_type_id = 99 params = { 'payoneer_program_id': 12345, 'reference_payment_type_id': reference_payment_type_id } mock_logic.get_payoneer_program.return_value = SimpleNamespace( status=200, message=dict(payoneer_program_id=12345) ) mock_models.AccountPaymentTerm.query.filter_by.return_value \ .first.return_value = payment_term_obj result = validate_payoneer_program(account_payee, **params) assert result is None mock_logic.get_payoneer_program.assert_called_once_with( currency_code=payment_term_obj.currency_code, agreement_type_id=payment_term_obj.agreement_type_id, payment_entity_id=payment_term_obj.payment_entity_id, reference_payment_type_id=reference_payment_type_id ) def test_validate_payload_success(): """Test validate_payload success case.""" schema_mock = MagicMock() schema_instance = schema_mock.return_value schema_instance.load.return_value = {'key': 'value'} payload = {'key': 'value'} result = validate_payload(payload, schema_mock) assert result == {'key': 'value'} schema_instance.load.assert_called_once_with(payload) @patch('abacus_account.utils.validations.abort') def test_validate_payload_validation_error(abort_mock): """Test validate_payload with ValidationError.""" schema_mock = MagicMock() schema_instance = schema_mock.return_value schema_instance.load.side_effect = ValidationError({'field': ['error']}) payload = {'field': 'bad_value'} validate_payload(payload, schema_mock) abort_mock.assert_called_once_with(description={'field': ['error']}, code=400)