"""Tests for Payment Group Payment handlers.""" from unittest.mock import call, patch from abacus_common_logic.marshalling.base import PaginationSchema from payment.models import Items from payment.schemas.payment_group_payment import ( PaymentGroupPaymentDetailSchema, PaymentGroupPaymentListSchema, PaymentGroupPaymentOverviewSchema, PaymentGroupPaymentStatusOverviewSchema, PaymentGroupPaymentTotalsSchema, ) from payment.schemas.payment_group_payment_account import ( PaymentGroupPaymentAccountListItemsSchema, PaymentGroupPaymentAccountPaginationSchema, PaymentGroupPaymentAccountSchema, ) from payment.schemas.payment_group_payment_batch import ( PaymentGroupPaymentBatchStatusSchema, ) from tests.utils.factories import ( PaymentGroupPaymentAccountFactory, PaymentGroupPaymentBatchFactory, PaymentGroupPaymentFactory, ) @patch('payment.blueprints.payment_group_payment.logic.create_payment_group_payment') def test_create_payment_group_payment(mock_logic, fixture_client, mocker): """Test POST /payment-group-payment/ handler.""" post_body = {'payment_group_id': 123, 'payment_name': 'Payment Name'} payment = PaymentGroupPaymentFactory.build() mock_logic.return_value = payment spy_validation = mocker.spy(PaymentGroupPaymentDetailSchema, 'load') spy_serialization = mocker.spy(PaymentGroupPaymentDetailSchema, 'dump') res = fixture_client.post('/payment-group-payment/', json=post_body) assert res.status_code == 201 assert res.json == PaymentGroupPaymentDetailSchema().dump(payment) assert mock_logic.call_args_list == [call(**post_body)] assert spy_validation.called assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.account_logic') def test_bulk_create_payment_group_payment_accounts( mock_logic, fixture_client, fresh_db, mock_accounts, mocker ): """Test POST /payment-group-payment//accounts/.""" payment_group_payment = PaymentGroupPaymentFactory.create() payment_group_payment_id = payment_group_payment.payment_group_payment_id payment_group_payment_accounts = PaymentGroupPaymentAccountFactory.create_batch( 2, payment_group_payment_id=payment_group_payment_id ) mock_logic.bulk_create.return_value = payment_group_payment_accounts spy_validation = mocker.spy(PaymentGroupPaymentAccountSchema, 'load') spy_serialization = mocker.spy(PaymentGroupPaymentAccountSchema, 'dump') create_params = [ { 'account_id': 123, 'contracts_payable': [ { 'contract_id': 123, 'current_balance': '1000.00', 'currency_code': 'USD', } ], 'currency_code': 'USD', 'current_balance': 1000.00, 'last_payment': 500.00, 'tax_withholding': None, 'balance_after_tax': 1000.00, 'payoneer_program_id': 1, }, { 'account_id': 456, 'contracts_payable': [ { 'contract_id': 456, 'current_balance': '500.00', 'currency_code': 'GBP', } ], 'currency_code': 'GBP', 'current_balance': 500.00, 'last_payment': 1000.00, 'tax_withholding': 200.00, 'balance_after_tax': 300.00, 'payoneer_program_id': 1, }, ] validated_params = PaymentGroupPaymentAccountSchema( exclude=( 'payment_group_payment_account_id', 'payment_group_payment_id', 'current_statement_period_id', ), many=True, ).load(create_params) res = fixture_client.post( f'/payment-group-payment/{payment_group_payment_id}/accounts/', json=create_params, ) assert res.status_code == 201 assert res.json == PaymentGroupPaymentAccountSchema(many=True).dump( payment_group_payment_accounts ) assert mock_logic.bulk_create.call_args_list == [ call(payment_group_payment_id, tuple(validated_params)) ] assert spy_validation.called assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.account_logic') def test_get_payment_group_payment_accounts_success( mock_logic, fixture_client, mocker, fresh_db, mock_accounts ): """GET /payment-group-payment//accounts/ success.""" payment_group_payment = PaymentGroupPaymentFactory.create() payment_group_payment_id = payment_group_payment.payment_group_payment_id payment_group_payment_accounts = PaymentGroupPaymentAccountFactory.create_batch( 2, payment_group_payment_id=payment_group_payment_id ) mock_logic.get_accounts_list.return_value = Items(payment_group_payment_accounts, 2) spy_validation = mocker.spy(PaymentGroupPaymentAccountPaginationSchema, 'load') spy_serialization = mocker.spy(PaymentGroupPaymentAccountListItemsSchema, 'dump') mock_request_params = { 'limit': 100, 'offset': 0, 'sort_by': 'account_name', 'sort_order': 'asc', } res = fixture_client.get( f'/payment-group-payment/{payment_group_payment_id}/accounts/' ) assert res.status_code == 200 assert res.json == PaymentGroupPaymentAccountListItemsSchema().dump( Items(payment_group_payment_accounts, 2) ) assert mock_logic.get_accounts_list.call_args_list == [ call(payment_group_payment_id=payment_group_payment_id, **mock_request_params) ] assert spy_validation.called assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.account_logic') def test_get_payment_group_payment_accounts_with_sorting_success( mock_logic, fixture_client, mocker, fresh_db, mock_accounts ): """GET /payment-group-payment//accounts/ success.""" payment_group_payment = PaymentGroupPaymentFactory.create() payment_group_payment_id = payment_group_payment.payment_group_payment_id payment_group_payment_accounts = PaymentGroupPaymentAccountFactory.create_batch( 2, payment_group_payment_id=payment_group_payment_id ) mock_logic.get_accounts_list.return_value = Items(payment_group_payment_accounts, 2) spy_validation = mocker.spy(PaymentGroupPaymentAccountPaginationSchema, 'load') spy_serialization = mocker.spy(PaymentGroupPaymentAccountListItemsSchema, 'dump') payment_group_payment_id = 123 default_request_params = {'limit': 100, 'offset': 0} request_params = { **default_request_params, **{'sort_by': 'vat_amount', 'sort_order': 'asc'}, } res = fixture_client.get( f'/payment-group-payment/{payment_group_payment_id}/accounts/?sort_by=vat_amount' ) assert res.status_code == 200 assert res.json == PaymentGroupPaymentAccountListItemsSchema().dump( Items(payment_group_payment_accounts, 2) ) assert mock_logic.get_accounts_list.call_args_list == [ call(payment_group_payment_id=payment_group_payment_id, **request_params) ] assert spy_validation.called assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.account_logic') def test_get_payment_group_payment_accounts_error(mock_logic, fixture_client, mocker): """Test error is raised when request params are invalid.""" spy_validation = mocker.spy(PaginationSchema, 'load') spy_serialization = mocker.spy(PaymentGroupPaymentAccountListItemsSchema, 'dump') res = fixture_client.get( '/payment-group-payment/123/accounts?limit=wrong', ) assert res.status_code == 400 assert spy_validation.called assert not spy_serialization.called assert not mock_logic.get_accounts_list.called @patch('payment.logic.payment_group_payment.get_payment_group_payments') def test_get_payment_group_payment_list(mock_logic, fixture_client, mocker): """Test GET /payment-group-payment/ handler.""" mock_response = Items([PaymentGroupPaymentFactory.build()], 1) mock_logic.return_value = mock_response spy_validation = mocker.spy(PaginationSchema, 'load') spy_serialization = mocker.spy(PaymentGroupPaymentListSchema, 'dump') res = fixture_client.get('/payment-group-payment/?limit=10&offset=0') assert res.status_code == 200 assert res.json == PaymentGroupPaymentListSchema().dump(mock_response) assert mock_logic.call_args_list == [call(10, 0)] assert spy_validation.called assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.account_logic') def test_get_payment_group_payment_pending_accounts_success( mock_logic, fixture_client, mocker, fresh_db, mock_accounts ): """GET /payment-group-payment//accounts/pending.""" payment_group_payment = PaymentGroupPaymentFactory.create() payment_group_payment_id = payment_group_payment.payment_group_payment_id payment_group_payment_accounts = PaymentGroupPaymentAccountFactory.create_batch( 2, payment_group_payment_id=payment_group_payment_id ) mock_logic.get_accounts_list.return_value = Items(payment_group_payment_accounts, 2) spy_validation = mocker.spy(PaymentGroupPaymentAccountPaginationSchema, 'load') spy_serialization = mocker.spy(PaymentGroupPaymentAccountListItemsSchema, 'dump') default_params = { 'limit': 100, 'offset': 0, 'sort_by': 'account_name', 'sort_order': 'asc', } res = fixture_client.get( f'/payment-group-payment/{payment_group_payment_id}/accounts/pending/' ) assert res.status_code == 200 assert res.json == PaymentGroupPaymentAccountListItemsSchema().dump( Items(payment_group_payment_accounts, 2) ) assert mock_logic.get_accounts_list.call_args_list == [ call( is_pending=True, payment_group_payment_id=payment_group_payment_id, **default_params, ) ] assert spy_validation.called assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.account_logic') def test_get_payment_overview(mock_logic, fixture_client, mocker): """Test getting overview of payment_group_payment.""" payment_group_payment_id = 111 expected_response = [ { 'account_count': 10, 'currency_code': 'EUR', 'currency_total': '1000.00', 'payment_group_payment_id': payment_group_payment_id, }, { 'account_count': 2, 'currency_code': 'GBP', 'currency_total': '200.00', 'payment_group_payment_id': payment_group_payment_id, }, ] mock_logic.get_totals_by_payment_group_payment.return_value = expected_response spy_serialization = mocker.spy(PaymentGroupPaymentOverviewSchema, 'dump') res = fixture_client.get( f'/payment-group-payment/{payment_group_payment_id}/overview' ) assert res.status_code == 200 assert res.json == expected_response mock_logic.get_totals_by_payment_group_payment.assert_called_once_with( payment_group_payment_id ) assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.account_logic') def test_get_payment_totals_grouped_by_program_id(mock_logic, fixture_client, mocker): """Test getting payment totals grouped by program_id.""" payment_group_payment_id = 1 expected_response = [ { 'account_count': 5, 'currency_code': 'EUR', 'currency_total': '1000.00', 'payoneer_program_id': 1, 'payment_entity_name': 'AWAL-UK', }, { 'account_count': 2, 'currency_code': 'USD', 'currency_total': '1500.00', 'payoneer_program_id': 2, 'payment_entity_name': 'AWAL-UK', }, ] mock_logic.get_totals_grouped_by_program_id.return_value = expected_response spy_serialization = mocker.spy(PaymentGroupPaymentTotalsSchema, 'dump') res = fixture_client.get( f'/payment-group-payment/{payment_group_payment_id}/program-currency-totals' ) assert res.status_code == 200 assert res.json == expected_response mock_logic.get_totals_grouped_by_program_id.assert_called_once_with( payment_group_payment_id ) assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.payment_batch_logic') def test_get_payment_group_payment_batches(mock_logic, fixture_client): """Test to get a list of payment batches by payment_group_payment_id and batch status.""" # noqa: E501 payment_group_payment_id = 1 payment_batch_status = 'failed' mock_batches = PaymentGroupPaymentBatchFactory.build_batch(2) mock_logic.get_payment_group_payment_batches.return_value = mock_batches res = fixture_client.get( f'/payment-group-payment/{payment_group_payment_id}/payment-batches/{payment_batch_status}' # noqa: E501 ) assert res.status_code == 200 assert res.json == PaymentGroupPaymentBatchStatusSchema(many=True).dump( mock_batches ) mock_logic.get_payment_group_payment_batches.assert_called_once_with( payment_group_payment_id, payment_batch_status ) @patch('payment.blueprints.payment_group_payment.logic') def test_get_payment_status_overview(mock_logic, fixture_client, mocker): """Test to the get payment status overview for a payment_group_payment.""" payment_group_payment_id = 1 expected_response = { 'number_of_canceled_payments': 1, 'number_of_failed_payments': 1, 'number_of_pending_payments': 2, 'number_of_successful_payments': 1, 'number_of_payments_failed_with_batch': 2, 'payment_group_payment_id': payment_group_payment_id, } mock_logic.get_payment_status_overview.return_value = expected_response spy_serialization = mocker.spy(PaymentGroupPaymentStatusOverviewSchema, 'dump') res = fixture_client.get( f'/payment-group-payment/{payment_group_payment_id}/payment-status-overview/' ) assert res.status_code == 200 assert res.json == expected_response mock_logic.get_payment_status_overview.assert_called_once_with( payment_group_payment_id ) assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.logic') def test_payment_status_overview_by_payment_group_payment_id_dataloader( mock_logic, fixture_client ): """Test to the get payment status overview for a payment_group_payment.""" payment_group_payment_id = 1 mock_logic.dataload_payment_status_overviews.return_value = { 'items': [ { 'data': { 'number_of_canceled_payments': 1, 'number_of_failed_payments': 1, 'number_of_pending_payments': 2, 'number_of_successful_payments': 1, 'number_of_payments_failed_with_batch': 2, 'payment_group_payment_id': payment_group_payment_id, } } ] } res = fixture_client.post( f'/payment-group-payment/payment-status-overview/dataloader', json=[payment_group_payment_id], ) assert res.status_code == 200 mock_logic.dataload_payment_status_overviews.assert_called_once_with( [payment_group_payment_id] ) assert res.json == { 'items': [ { 'data': { 'number_of_canceled_payments': 1, 'number_of_failed_payments': 1, 'number_of_pending_payments': 2, 'number_of_successful_payments': 1, 'number_of_payments_failed_with_batch': 2, 'payment_group_payment_id': payment_group_payment_id, } } ] } @patch('payment.blueprints.payment_group_payment.logic.get_payment_group_payment') def test_get_payment_group_payment(mock_logic, fixture_client, mocker, faker): """Test GET /payment-group-payment// handler.""" payment = PaymentGroupPaymentFactory.build() payment_id = faker.pyint() mock_logic.return_value = payment spy_serialization = mocker.spy(PaymentGroupPaymentDetailSchema, 'dump') res = fixture_client.get(f'/payment-group-payment/{payment_id}/') assert res.status_code == 200 assert res.json == PaymentGroupPaymentDetailSchema().dump(payment) assert mock_logic.call_args_list == [call(payment_id)] assert spy_serialization.called @patch('payment.blueprints.payment_group_payment.logic.delete_payment_group_payment') def test_delete_payment_group_payment(mock_logic, fixture_client, faker): """Test DELETE /payment-group-payment// handler.""" payment_id = faker.pyint() res = fixture_client.delete(f'/payment-group-payment/{payment_id}/') assert res.status_code == 204 assert mock_logic.call_args_list == [call(payment_id)]