"""Tests fro worksheet_account_contract_payable_details handler.""" from unittest.mock import call, patch from payment.constants.constants import DEFAULT_BULK_MAX_LIMIT from payment.constants.error import ERROR_BULK_MAX_LIMIT from payment.schemas.worksheet_account_contract_payable_details import ( PaginatedWorksheetAccountContractPayableDetailsOutputSchema, WorksheetAccountContractPayableDetailsBulkDeleteSchema, WorksheetAccountContractPayableDetailsCreateSchema, ) from tests.utils.factories import WorksheetAccountContractPayableDetailsFactory @patch('payment.blueprints.worksheet_account_contract_payable_details.logic') def test_bulk_create_worksheet_account_contract_payable_details_success( mock_logic, fixture_client, faker ): """Test bulk_create_worksheet_account_contract_payable_details view success.""" event_id = faker.pyint() statement_period_id = faker.pyint() expected_create_params = [ { 'worksheet_account_contract_payable_after_tax_id': faker.pyint(), 'account_id': faker.pyint(), 'contract_id': faker.pyint(), 'target_table': faker.pystr(), 'target_id': faker.pyint(), 'reference_target_table': faker.pystr(), 'reference_target_id': faker.pyint(), 'payable_detail_type_id': faker.pyint(), 'amount_payable': faker.pydecimal(), 'currency': faker.pystr(min_chars=3, max_chars=3), 'notes': faker.pystr(), } for n in range(0, faker.pyint(min_value=1, max_value=10)) ] post_body = [ {**item, 'amount_payable': str(item['amount_payable'])} for item in expected_create_params ] mock_instances = WorksheetAccountContractPayableDetailsFactory.build_batch( len(expected_create_params) ) mock_logic.bulk_create.return_value = mock_instances res = fixture_client.post( f'/worksheet-account-contract-payable-details' f'/event/{event_id}' f'/statement-period/{statement_period_id}' f'/bulk/', json=post_body, ) assert res.status_code == 201, res.text assert res.json == WorksheetAccountContractPayableDetailsCreateSchema( many=True ).dump(mock_instances) assert mock_logic.bulk_create.call_args_list == [ call(event_id, statement_period_id, tuple(expected_create_params)) ] @patch('payment.blueprints.worksheet_account_contract_payable_details.logic') def test_bulk_create_worksheet_account_contract_payable_details_failure_validation( mock_logic, fixture_client, faker ): """Test bulk_create_worksheet_account_contract_payable_details view failure.""" event_id = faker.pyint() statement_period_id = faker.pyint() post_body = [ faker.pydict(allowed_types=[str, int, bool]) for n in range(0, faker.pyint(min_value=1, max_value=10)) ] res = fixture_client.post( f'/worksheet-account-contract-payable-details' f'/event/{event_id}' f'/statement-period/{statement_period_id}' f'/bulk/', json=post_body, ) assert res.status_code == 400, res.text assert not mock_logic.bulk_create.called @patch('payment.blueprints.worksheet_account_contract_payable_details.logic') def test_bulk_delete_worksheet_account_contract_payable_details( mock_logic, fixture_client, faker ): """Test bulk_delete_worksheet_account_contract_payable_details endpoint.""" event_id = faker.pyint() res = fixture_client.delete( f'/worksheet-account-contract-payable-details' f'/event/{event_id}/' ) assert res.status_code == 204, res.text assert mock_logic.bulk_delete.call_args_list == [call(event_id)] @patch( 'payment.blueprints.worksheet_account_contract_payable_details.logic.get_filtered_active_records' # noqa: E501 ) def test_get_by_statement_period_id_with_default_args(mock_logic, fixture_client): """Test get contracts payable details by statement period id.""" worksheet_account_contract_payable_details = ( WorksheetAccountContractPayableDetailsFactory.build() ) mock_response = { 'items': [worksheet_account_contract_payable_details], 'total_count': 1, } mock_logic.return_value = mock_response res = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/' f'{worksheet_account_contract_payable_details.statement_period_id}/' ) assert res.status_code == 200 assert ( res.json['items'] == PaginatedWorksheetAccountContractPayableDetailsOutputSchema().dump( mock_response )['items'] ) assert res.json['total_count'] == mock_response['total_count'] assert mock_logic.call_args_list == [ call( statement_period_id=worksheet_account_contract_payable_details.statement_period_id, # noqa: E501 worksheet_after_tax_ids=None, detail_groups=None, limit=100, offset=0, ) ] @patch( 'payment.blueprints.worksheet_account_contract_payable_details.logic.get_filtered_active_records' # noqa: E501 ) def test_get_by_statement_period_id(mock_logic, fixture_client): """Test get contracts payable details by statement period id.""" worksheet_account_contract_payable_details = ( WorksheetAccountContractPayableDetailsFactory.build() ) mock_response = { 'items': [worksheet_account_contract_payable_details], 'total_count': 1, } mock_logic.return_value = mock_response res = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/' f'{worksheet_account_contract_payable_details.statement_period_id}/' f'?limit=10&offset=5' ) assert res.status_code == 200 assert ( res.json['items'] == PaginatedWorksheetAccountContractPayableDetailsOutputSchema().dump( mock_response )['items'] ) assert res.json['total_count'] == mock_response['total_count'] assert mock_logic.call_args_list == [ call( statement_period_id=worksheet_account_contract_payable_details.statement_period_id, # noqa: E501 worksheet_after_tax_ids=None, detail_groups=None, limit=10, offset=5, ), ] @patch( 'payment.blueprints.worksheet_account_contract_payable_details.logic.get_filtered_active_records' # noqa: E501 ) def test_get_by_worksheet_after_tax_ids(mock_logic, fixture_client): """Test get contracts payable details by worksheet payable after tax ids.""" worksheet_account_contract_payable_details = ( WorksheetAccountContractPayableDetailsFactory.build() ) mock_response = { 'items': [worksheet_account_contract_payable_details], 'total_count': 1, } mock_logic.return_value = mock_response json_body = {'filters': {'worksheet_payable_after_tax_ids': [1, 2, 3]}} res = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/' f'{worksheet_account_contract_payable_details.statement_period_id}/', json=json_body, ) assert res.status_code == 200 assert ( res.json['items'] == PaginatedWorksheetAccountContractPayableDetailsOutputSchema().dump( mock_response )['items'] ) assert res.json['total_count'] == mock_response['total_count'] assert mock_logic.call_args_list == [ call( statement_period_id=worksheet_account_contract_payable_details.statement_period_id, # noqa: E501 worksheet_after_tax_ids=[1, 2, 3], detail_groups=None, limit=100, offset=0, ) ] @patch( 'payment.blueprints.worksheet_account_contract_payable_details.logic.get_filtered_active_records' # noqa: E501 ) def test_get_by_detail_groups(mock_logic, fixture_client): """Test get contracts payable details by worksheet payable after tax ids.""" worksheet_account_contract_payable_details = ( WorksheetAccountContractPayableDetailsFactory.build() ) mock_response = { 'items': [worksheet_account_contract_payable_details], 'total_count': 1, } mock_logic.return_value = mock_response json_body = {'filters': {'detail_groups': ['name1', 'name2']}} res = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/' f'{worksheet_account_contract_payable_details.statement_period_id}/', json=json_body, ) assert res.status_code == 200 assert ( res.json['items'] == PaginatedWorksheetAccountContractPayableDetailsOutputSchema().dump( mock_response )['items'] ) assert res.json['total_count'] == mock_response['total_count'] assert mock_logic.call_args_list == [ call( statement_period_id=worksheet_account_contract_payable_details.statement_period_id, # noqa: E501 worksheet_after_tax_ids=None, detail_groups=['name1', 'name2'], limit=100, offset=0, ) ] @patch( 'payment.blueprints.worksheet_account_contract_payable_details.logic.' 'bulk_soft_delete_corrections_by_worksheet_payable_after_tax_ids' ) def test_bulk_soft_delete_corrections_success( mock_logic, fixture_client, faker, mocker ): """DELETE /worksheet-account-contract-payable-details/bulk success.""" payload = { 'worksheet_account_contract_payable_after_tax_ids': [ faker.pyint(min_value=1), faker.pyint(min_value=1), ] } spy_validation = mocker.spy( WorksheetAccountContractPayableDetailsBulkDeleteSchema, 'load' ) res = fixture_client.delete( '/worksheet-account-contract-payable-details/bulk', json=payload, ) assert res.status_code == 204, res.text assert spy_validation.called assert mock_logic.call_args_list == [ call(payload['worksheet_account_contract_payable_after_tax_ids']) ] @patch( 'payment.blueprints.worksheet_account_contract_payable_details.logic.' 'bulk_soft_delete_corrections_by_worksheet_payable_after_tax_ids' ) def test_bulk_soft_delete_corrections_missing_ids_returns_400( mock_logic, fixture_client ): """Missing ids in request body fails validation.""" res = fixture_client.delete( '/worksheet-account-contract-payable-details/bulk', json={}, ) assert res.status_code == 400, res.text assert not mock_logic.called @patch( 'payment.blueprints.worksheet_account_contract_payable_details.logic.' 'bulk_soft_delete_corrections_by_worksheet_payable_after_tax_ids' ) def test_bulk_soft_delete_corrections_empty_list_returns_400( mock_logic, fixture_client ): """Empty id list fails validation.""" res = fixture_client.delete( '/worksheet-account-contract-payable-details/bulk', json={'worksheet_account_contract_payable_after_tax_ids': []}, ) assert res.status_code == 400, res.text assert not mock_logic.called @patch( 'payment.blueprints.worksheet_account_contract_payable_details.logic.' 'bulk_soft_delete_corrections_by_worksheet_payable_after_tax_ids' ) def test_bulk_soft_delete_corrections_exceeds_limit_returns_400( mock_logic, fixture_client ): """Over the bulk limit fails validation.""" limit = DEFAULT_BULK_MAX_LIMIT payload = { 'worksheet_account_contract_payable_after_tax_ids': list(range(1, limit + 2)) } res = fixture_client.delete( '/worksheet-account-contract-payable-details/bulk', json=payload, ) assert res.status_code == 400, res.text assert ERROR_BULK_MAX_LIMIT.format(limit) in res.json['message']['json']['_schema'] assert not mock_logic.called