"""Tests for Account Payee logic.""" import datetime from unittest.mock import Mock, patch from abacus_common_logic.utils.dates import parse_date from abacus_account.constants import error from abacus_account.logic import account_payee as logic from abacus_account.schemas.account_payee import AccountPayeeDetailSchema from tests.utils.factories import AccountFactory from tests.utils.factories import AccountPayeeFactory from tests.utils.factories import AccountPaymentTermFactory from tests.utils.factories import PaymentEntityPayoneerProgramFactory from tests.utils.factories import ReferencePaymentTypeFactory from tests.utils.factories import ReferencePayoneerProgramFactory @patch('abacus_account.logic.account_payee._validate_account_id_unique') @patch('abacus_account.logic.account_payee.models') def test_create_account_payee_success( mock_models, mock__validate_account_id_unique ): """Test create_account_payee method.""" mock_response = { 'account_id': 1, 'account_payee_id': 1, 'payoneer_program_id': None, 'payoneer_payee_id': 1, 'payoneer_payee_name': 'Captain Payoneer', 'payoneer_iframe_url': 'payoneer.com/iframe', 'payoneer_iframe_url_date': datetime.date(2022, 3, 3), 'payoneer_session_id': '2000', 'reference_payment_type_id': None, } account = AccountFactory.create() mock_models.Account.get_by_id_or_error.return_value = account mock__validate_account_id_unique.return_value = None mock_models.AccountPayee.create.return_value = mock_response res = logic.create_account_payee( account_id=1, payoneer_payee_id=1, payoneer_payee_name='Captain Payoneer', payoneer_iframe_url='payoneer.com/iframe', payoneer_iframe_url_date=datetime.date(2022, 3, 3), payoneer_session_id='2000' ) assert res.status == 201 assert res.message['account_id'] == mock_response['account_id'] assert res.message['account_payee_id'] == mock_response['account_payee_id'] assert res.message['payoneer_payee_id'] == mock_response['payoneer_payee_id'] assert res.message['payoneer_payee_name'] == mock_response['payoneer_payee_name'] assert res.message['payoneer_iframe_url'] == mock_response['payoneer_iframe_url'] assert parse_date(res.message['payoneer_iframe_url_date']) == \ mock_response['payoneer_iframe_url_date'] assert res.message['payoneer_session_id'] == mock_response['payoneer_session_id'] assert (res.message['reference_payment_type_id'] == mock_response['reference_payment_type_id']) mock_models.AccountPayee.create.assert_called_once_with( account_id=1, payoneer_payee_id=1, payoneer_payee_name='Captain Payoneer', payoneer_iframe_url='payoneer.com/iframe', payoneer_iframe_url_date=datetime.date(2022, 3, 3), payoneer_session_id='2000' ) @patch('abacus_account.logic.account_payee._validate_account_id_unique') @patch('abacus_account.logic.account_payee.models') def test_create_account_payee_payoneer_program_payment_type_mismatch_from_payee( mock_models, mock__validate_account_id_unique, reference_payment_entity_fixture ): """Test create_account_payee uses payoneer program from account payment term.""" mock_response = { 'account_id': 1, 'account_payee_id': 1, 'payoneer_program_id': 7777, 'payoneer_payee_id': 1, 'payoneer_payee_name': 'Captain Payoneer', 'payoneer_iframe_url': 'payoneer.com/iframe', 'payoneer_iframe_url_date': datetime.date(2022, 3, 3), 'payoneer_session_id': '2000', 'reference_payment_type_id': 7, } ReferencePayoneerProgramFactory.create( payoneer_program_id=7777, reference_payment_type_id=7 ) payment_entity_payoneer_program = PaymentEntityPayoneerProgramFactory.create( reference_payment_entity_id=5, payoneer_program_id=7777, ) account = AccountFactory.create() account_payment_term = AccountPaymentTermFactory.create( account=account ) mock_models.Account.get_by_id_or_error.return_value = account mock__validate_account_id_unique.return_value = None mock_models.AccountPayee.create.return_value = mock_response mock_models.PaymentEntityPayoneerProgram.get_by_criteria.return_value = payment_entity_payoneer_program # noqa: E501 res = logic.create_account_payee( account_id=1, payoneer_payee_id=1, payoneer_payee_name='Captain Payoneer', payoneer_iframe_url='payoneer.com/iframe', payoneer_iframe_url_date=datetime.date(2022, 3, 3), payoneer_session_id='2000' ) assert res.status == 400 assert res.errors == { 'code': 'error', 'message': 'Reference payment type and payoneer program mismatch', } mock_models.AccountPayee.create.assert_not_called() mock_models.PaymentEntityPayoneerProgram.get_by_criteria.\ assert_called_once_with( payment_entity_id=account_payment_term.payment_entity_id, payment_currency='USD', agreement_type_id=1 ) @patch('abacus_account.logic.account_payee._validate_account_id_unique') @patch('abacus_account.logic.account_payee.models') def test_create_account_payee_payoneer_program_payment_type_mismatch_from_params( mock_models: Mock, mock__validate_account_id_unique: Mock, ): """Test create_account_payee uses payoneer program from params fail mismatch.""" ReferencePayoneerProgramFactory.create( payoneer_program_id=7777, reference_payment_type_id=7 ) account = AccountFactory.create() mock_models.Account.get_by_id_or_error.return_value = account mock__validate_account_id_unique.return_value = None res = logic.create_account_payee( account_id=1, payoneer_payee_id=1, payoneer_payee_name='Captain Payoneer', payoneer_iframe_url='payoneer.com/iframe', payoneer_iframe_url_date=datetime.date(2022, 3, 3), payoneer_session_id='2000', payoneer_program_id=7777, reference_payment_type_id=2, ) assert res.status == 400 assert res.errors == { 'code': 'error', 'message': 'Reference payment type and payoneer program mismatch', } mock_models.AccountPayee.create.assert_not_called() mock_models.PaymentEntityPayoneerProgram.get_by_criteria.assert_not_called() @patch('abacus_account.logic.account_payee._validate_account_id_unique') @patch('abacus_account.logic.account_payee.models') def test_create_account_payee_does_not_set_missing_payoneer_program( mock_models, mock__validate_account_id_unique, reference_payment_entity_fixture ): """Test create_account_payee leaves payoneer program empty if no match found.""" mock_response = { 'account_id': 1, 'account_payee_id': 1, 'payoneer_payee_id': 1, 'payoneer_program_id': None, 'payoneer_payee_name': 'Captain Payoneer', 'payoneer_iframe_url': 'payoneer.com/iframe', 'payoneer_iframe_url_date': datetime.date(2022, 3, 3), 'payoneer_session_id': '2000', 'reference_payment_type_id': 7, } account = AccountFactory.create() account_payment_term = AccountPaymentTermFactory.create( account=account ) mock_models.Account.get_by_id_or_error.return_value = account mock__validate_account_id_unique.return_value = None mock_models.AccountPayee.create.return_value = mock_response mock_models.PaymentEntityPayoneerProgram.get_by_criteria.return_value = None # noqa: E501 res = logic.create_account_payee( account_id=1, payoneer_payee_id=1, payoneer_payee_name='Captain Payoneer', payoneer_iframe_url='payoneer.com/iframe', payoneer_iframe_url_date=datetime.date(2022, 3, 3), payoneer_session_id='2000', reference_payment_type_id=3, ) assert res.status == 201 assert res.message['account_id'] == mock_response['account_id'] assert res.message['account_payee_id'] == mock_response['account_payee_id'] assert res.message['payoneer_program_id'] == mock_response['payoneer_program_id'] assert res.message['payoneer_payee_id'] == mock_response['payoneer_payee_id'] assert res.message['payoneer_payee_name'] == mock_response['payoneer_payee_name'] assert res.message['payoneer_iframe_url'] == mock_response['payoneer_iframe_url'] assert parse_date(res.message['payoneer_iframe_url_date']) == \ mock_response['payoneer_iframe_url_date'] assert res.message['payoneer_session_id'] == mock_response['payoneer_session_id'] assert (res.message['reference_payment_type_id'] == mock_response['reference_payment_type_id']) mock_models.AccountPayee.create.assert_called_once_with( account_id=1, payoneer_payee_id=1, payoneer_payee_name='Captain Payoneer', payoneer_iframe_url='payoneer.com/iframe', payoneer_iframe_url_date=datetime.date(2022, 3, 3), payoneer_session_id='2000', reference_payment_type_id=3, ) mock_models.PaymentEntityPayoneerProgram.get_by_criteria.\ assert_called_once_with( payment_entity_id=account_payment_term.payment_entity_id, payment_currency='USD', agreement_type_id=1 ) @patch('abacus_account.logic.account_payee.models') def test_create_account_payee_error_already_exists(mock_model): """Test create_account_payee method error when account_payee already exist.""" account_payee = AccountPayeeFactory.create() mock_model.Account.get_by_id_or_error.return_value = account_payee.account res = logic.create_account_payee( account_id=account_payee.account_id, payoneer_payee_id=1, payoneer_payee_name='Captain Payoneer', payoneer_iframe_url='payoneer.com/iframe', payoneer_iframe_url_date=datetime.date(2022, 3, 3), payoneer_session_id='2000' ) assert res.status == 400 assert res.errors['message'] == \ error.ERROR_ACCOUNT_PAYEE_ALREADY_EXISTS.format( object_type='account_payee', object_id=account_payee.account_id ) mock_model.AccountPayee.create.assert_not_called() @patch('abacus_account.logic.account_payee.emit_account_change_payee_program_event') @patch('abacus_account.logic.account_payee.validate_payoneer_program') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee( mock_model, mock_validate, mock_kafka_event ): """Test update_account_payee function.""" reference_payment_type = ReferencePaymentTypeFactory.create() reference_payoneer_program = ReferencePayoneerProgramFactory.create( reference_payment_type_id=reference_payment_type.reference_payment_type_id ) mock_model.AccountPayee.commit_changes.return_value = True mock_kafka_event.return_value = True account = AccountFactory.create() account_payee = AccountPayeeFactory.create(account=account) mock_validate.return_value = None put_body = { 'payoneer_payee_name': 'Totally Different Name', 'reference_payment_type_id': reference_payment_type.reference_payment_type_id, 'payoneer_program_id': reference_payoneer_program.payoneer_program_id } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 200 assert account_payee.payoneer_payee_name == put_body.get('payoneer_payee_name') assert (account_payee.reference_payment_type_id == put_body.get('reference_payment_type_id')) mock_model.AccountPayee.commit_changes.assert_called_once() mock_validate.assert_called_once_with(account_payee, **put_body) @patch('abacus_account.logic.account_payee.validate_payoneer_program') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee_failure_program_payment_type_mismatch( mock_model, mock_validate ): """Test update_account_payee function.""" reference_payment_type = ReferencePaymentTypeFactory.create() reference_payoneer_program = ReferencePayoneerProgramFactory.create( reference_payment_type_id=reference_payment_type.reference_payment_type_id ) account = AccountFactory.create() account_payee = AccountPayeeFactory.create(account=account) mock_validate.return_value = None put_body = { 'payoneer_payee_name': 'Totally Different Name', 'reference_payment_type_id': 1, 'payoneer_program_id': reference_payoneer_program.payoneer_program_id } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 400 assert res.errors['message'] == error.ERROR_PROGRAM_PAYMENT_TYPE_MISMATCH assert not mock_model.AccountPayee.commit_changes.called @patch('abacus_account.logic.account_payee.validate_payoneer_program') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee_failurepayment_type_mismatch(mock_model, mock_validate): """Test update_account_payee function.""" account = AccountFactory.create() account_payee = AccountPayeeFactory.create( account=account, ) mock_validate.return_value = None put_body = { 'payoneer_payee_name': 'Totally Different Name', 'reference_payment_type_id': 1, } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 400 assert res.errors['message'] == error.ERROR_PROGRAM_PAYMENT_TYPE_MISMATCH assert not mock_model.AccountPayee.commit_changes.called @patch('abacus_account.logic.account_payee.validate_payoneer_program') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee_failure_program_mismatch(mock_model, mock_validate): """Test update_account_payee function.""" reference_payment_type = ReferencePaymentTypeFactory.create() reference_payoneer_program = ReferencePayoneerProgramFactory.create( reference_payment_type_id=reference_payment_type.reference_payment_type_id ) account = AccountFactory.create() account_payee = AccountPayeeFactory.create(account=account) mock_validate.return_value = None put_body = { 'payoneer_payee_name': 'Totally Different Name', 'payoneer_program_id': reference_payoneer_program.payoneer_program_id } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 400 assert res.errors['message'] == error.ERROR_PROGRAM_PAYMENT_TYPE_MISMATCH assert not mock_model.AccountPayee.commit_changes.called @patch('abacus_account.logic.account_payee.emit_account_change_payee_program_event') @patch('abacus_account.logic.account_payee.validate_payoneer_program') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee_change_payoneer_program_success( mock_model, mock_validate, mock_kafka, ): """Test update_account_payee function success.""" reference_payment_type = ReferencePaymentTypeFactory.create() account = AccountFactory.create() new_payoneer_program_id = 12 old_payoneer_program_id = 34 account_payee = AccountPayeeFactory.create( account=account, reference_payoneer_program=ReferencePayoneerProgramFactory.create( payoneer_program_id=old_payoneer_program_id, reference_payment_type_id=reference_payment_type.reference_payment_type_id, ), reference_payment_type_id=reference_payment_type.reference_payment_type_id ) ReferencePayoneerProgramFactory.create( payoneer_program_id=new_payoneer_program_id, reference_payment_type_id=reference_payment_type.reference_payment_type_id, ) mock_validate.return_value = None put_body = { 'payoneer_payee_name': 'Totally Different Name', 'payoneer_program_id': new_payoneer_program_id } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 200 assert account_payee.payoneer_payee_name == put_body.get('payoneer_payee_name') mock_model.AccountPayee.commit_changes.assert_called_once() mock_validate.assert_called_once_with(account_payee, **put_body) mock_kafka.assert_called_once_with( account_payee.account_payee_id, new_payoneer_program_id, old_payoneer_program_id ) @patch('abacus_account.logic.account_payee.emit_account_change_payee_program_event') @patch('abacus_account.logic.account_payee.validate_payoneer_program') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee_change_payoneer_program_without_changing_payee( mock_model, mock_validate, mock_kafka, ): """Test update_account_payee when program is not changed.""" reference_payment_type = ReferencePaymentTypeFactory.create() account = AccountFactory.create() new_payoneer_program_id = old_payoneer_program_id = 12 account_payee = AccountPayeeFactory.create( account=account, reference_payoneer_program=ReferencePayoneerProgramFactory.create( payoneer_program_id=old_payoneer_program_id, reference_payment_type_id=reference_payment_type.reference_payment_type_id, ), reference_payment_type_id=reference_payment_type.reference_payment_type_id, ) mock_validate.return_value = None put_body = { 'payoneer_payee_name': 'Totally Different Name', 'payoneer_program_id': new_payoneer_program_id } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 200 assert account_payee.payoneer_payee_name == put_body.get('payoneer_payee_name') mock_model.AccountPayee.commit_changes.assert_called_once() mock_validate.assert_called_once_with(account_payee, **put_body) mock_kafka.assert_not_called() @patch('abacus_account.logic.account_payee.emit_account_change_payee_program_event') @patch('abacus_account.logic.account_payee.validate_payoneer_program') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee_change_payoneer_program_and_program_id_not_provided( mock_model, mock_validate, mock_kafka, ): """Test update_account_payee when program is not provided in put body.""" account = AccountFactory.create() account_payee = AccountPayeeFactory.create( account=account ) mock_validate.return_value = None put_body = { 'payoneer_payee_name': 'Totally Different Name' } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 200 assert account_payee.payoneer_payee_name == put_body.get('payoneer_payee_name') mock_model.AccountPayee.commit_changes.assert_called_once() mock_validate.assert_called_once_with(account_payee, **put_body) mock_kafka.assert_not_called() @patch('abacus_account.logic.account_payee.emit_account_change_payee_program_event') @patch('abacus_account.logic.account_payee.validate_payoneer_program') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee_emits_kafka_after_commit( mock_model, mock_validate, mock_kafka, ): """Test Kafka event is emitted after DB commit.""" reference_payment_type = ReferencePaymentTypeFactory.create() account = AccountFactory.create() new_payoneer_program_id = 12 old_payoneer_program_id = 34 account_payee = AccountPayeeFactory.create( account=account, reference_payoneer_program=ReferencePayoneerProgramFactory.create( payoneer_program_id=old_payoneer_program_id, reference_payment_type_id=reference_payment_type.reference_payment_type_id, ), reference_payment_type_id=reference_payment_type.reference_payment_type_id ) ReferencePayoneerProgramFactory.create( payoneer_program_id=new_payoneer_program_id, reference_payment_type_id=reference_payment_type.reference_payment_type_id, ) mock_validate.return_value = None call_order = [] mock_model.AccountPayee.commit_changes.side_effect = \ lambda: call_order.append('commit') mock_kafka.side_effect = lambda *args: call_order.append('kafka') put_body = { 'payoneer_payee_name': 'Totally Different Name', 'payoneer_program_id': new_payoneer_program_id } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 200 mock_model.AccountPayee.commit_changes.assert_called_once() mock_kafka.assert_called_once_with( account_payee.account_payee_id, new_payoneer_program_id, old_payoneer_program_id ) assert call_order == ['commit', 'kafka'] @patch('abacus_account.logic.account_payee.emit_account_change_payee_program_event') @patch('abacus_account.logic.account_payee.validate_payoneer_program') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee_no_kafka_when_program_unchanged( mock_model, mock_validate, mock_kafka, ): """Test no Kafka event when program is unchanged.""" reference_payment_type = ReferencePaymentTypeFactory.create() account = AccountFactory.create() same_program_id = 12 account_payee = AccountPayeeFactory.create( account=account, reference_payoneer_program=ReferencePayoneerProgramFactory.create( payoneer_program_id=same_program_id, reference_payment_type_id=reference_payment_type.reference_payment_type_id, ), reference_payment_type_id=reference_payment_type.reference_payment_type_id, ) mock_validate.return_value = None put_body = { 'payoneer_payee_name': 'Totally Different Name', 'payoneer_program_id': same_program_id } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 200 mock_model.AccountPayee.commit_changes.assert_called_once() mock_kafka.assert_not_called() @patch('abacus_account.models') @patch('abacus_account.logic.account_payee.models') def test_update_account_payee_error_validation(mock_model, mock_validate_model): """Test update_account_payee function.""" account = AccountFactory.create() account_payee = AccountPayeeFactory.create(account=account) mock_validate_model.AccountPaymentTerm.query.filter_by.first.return_value = [] put_body = { 'payoneer_payee_name': 'Totally Different Name', 'payoneer_program_id': 1 } res = logic.update_account_payee(account_payee, **put_body) assert res.status == 400 assert res.errors['message'] == error.ERROR_PAYMENT_TERM_NOT_EXISTS.format( account_id=account.account_id) mock_model.AccountPayee.commit_changes.assert_not_called() @patch('abacus_account.logic.account_payee.models') def test_get_account_payee_by_account_id(mock_model): """Test get_account_payee_by_account_id function.""" account_payee = AccountPayeeFactory.create() account_id = account_payee.account_id expected_response = AccountPayeeDetailSchema().dump(account_payee) mock_model.Account.get_by_id_or_error.return_value = account_payee.account res = logic.get_account_payee_by_account_id(account_id) assert res.status == 200 assert res.message == expected_response @patch('abacus_account.logic.account_payee._validate_account_id_unique') @patch('abacus_account.logic.account_payee.models') def test_create_account_payee_sets_payoneer_program_success( mock_models, mock__validate_account_id_unique, reference_payment_entity_fixture ): """Test create_account_payee.""" ReferencePaymentTypeFactory.create(reference_payment_type_id=8) mock_response = { 'account_id': 1, 'account_payee_id': 1, 'payoneer_program_id': 7777, 'payoneer_payee_id': 1, 'payoneer_payee_name': 'Captain Payoneer', 'payoneer_iframe_url': 'payoneer.com/iframe', 'payoneer_iframe_url_date': datetime.date(2022, 3, 3), 'payoneer_session_id': '2000' } ReferencePayoneerProgramFactory.create( payoneer_program_id=7777, reference_payment_type_id=8 ) payment_entity_payoneer_program = PaymentEntityPayoneerProgramFactory.create( payoneer_program_id=7777, reference_payment_entity_id=5, ) account = AccountFactory.create() account_payment_term = AccountPaymentTermFactory.create( account=account, payment_entity_id=5, ) mock_models.Account.get_by_id_or_error.return_value = account mock__validate_account_id_unique.return_value = None mock_models.AccountPayee.create.return_value = mock_response mock_models.PaymentEntityPayoneerProgram.get_by_criteria.return_value = payment_entity_payoneer_program # noqa: E501 res = logic.create_account_payee( account_id=1, payoneer_payee_id=1, payoneer_payee_name='Captain Payoneer', payoneer_iframe_url='payoneer.com/iframe', payoneer_iframe_url_date=datetime.date(2022, 3, 3), payoneer_session_id='2000' ) assert res.status == 201 assert res.message['account_id'] == mock_response['account_id'] assert res.message['account_payee_id'] == mock_response['account_payee_id'] assert res.message['payoneer_program_id'] == mock_response['payoneer_program_id'] assert res.message['payoneer_payee_id'] == mock_response['payoneer_payee_id'] assert res.message['payoneer_payee_name'] == mock_response['payoneer_payee_name'] assert res.message['payoneer_iframe_url'] == mock_response['payoneer_iframe_url'] assert parse_date(res.message['payoneer_iframe_url_date']) == \ mock_response['payoneer_iframe_url_date'] assert res.message['payoneer_session_id'] == mock_response['payoneer_session_id'] mock_models.AccountPayee.create.assert_called_once_with( account_id=1, payoneer_program_id=7777, payoneer_payee_id=1, payoneer_payee_name='Captain Payoneer', payoneer_iframe_url='payoneer.com/iframe', payoneer_iframe_url_date=datetime.date(2022, 3, 3), payoneer_session_id='2000', reference_payment_type_id=8, ) mock_models.PaymentEntityPayoneerProgram.get_by_criteria.\ assert_called_once_with( payment_entity_id=account_payment_term.payment_entity_id, payment_currency='USD', agreement_type_id=1 )