"""Fnctional tests fro worksheet_account_contract_payable_details.""" from abacus_common_logic.connectors.database import db from sqlalchemy import func, select from payment.constants.constants import DEFAULT_BULK_MAX_LIMIT from payment.models import WorksheetAccountContractPayableDetails from tests.utils.factories import ( WorksheetAccountContractPayableDetailsFactory, WorksheetPayableBalanceAfterTaxFactory, ) def test_bulk_create_worksheet_account_contract_payable_details_success( fixture_client, mock_statement_periods, mock_exchange_rates, mock_contracts, mock_accounts, mock_abacus_event, mock_ledger_account_contracts, mock_worksheet_account_contract_closing_balance, ): """Test bulk_create_worksheet_account_contract_payable_details view success.""" event_id = 1 statement_period_id = 1 item1 = WorksheetAccountContractPayableDetailsFactory.create() item2 = WorksheetAccountContractPayableDetailsFactory.create() post_body = [ { 'worksheet_account_contract_payable_after_tax_id': item1.worksheet_account_contract_payable_after_tax_id, 'account_id': item1.account_id, 'contract_id': item1.contract_id, 'target_table': item1.target_table, 'target_id': item1.target_id, 'reference_target_table': item1.reference_target_table, 'reference_target_id': item1.reference_target_id, 'payable_detail_type_id': item1.payable_detail_type_id, 'amount_payable': str(item1.amount_payable), 'currency': item1.currency, 'notes': item1.notes, }, { 'worksheet_account_contract_payable_after_tax_id': item2.worksheet_account_contract_payable_after_tax_id, 'account_id': item2.account_id, 'contract_id': item2.contract_id, 'target_table': item2.target_table, 'target_id': item2.target_id, 'reference_target_table': item2.reference_target_table, 'reference_target_id': item2.reference_target_id, 'payable_detail_type_id': item2.payable_detail_type_id, 'amount_payable': str(item2.amount_payable), 'currency': item2.currency, 'notes': item2.notes, }, ] assert ( db.session.execute( select(func.count()).select_from( select(WorksheetAccountContractPayableDetails).subquery() ) ).scalar_one() == 2 ) 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 == post_body assert ( db.session.execute( select(func.count()).select_from( select(WorksheetAccountContractPayableDetails).subquery() ) ).scalar_one() == 4 ) def test_bulk_create_worksheet_account_contract_payable_details_failure_validation( 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 ( db.session.execute( select(func.count()).select_from( select(WorksheetAccountContractPayableDetails).subquery() ) ).scalar_one() == 0 ) def test_bulk_delete_worksheet_account_contract_payable_details( fixture_client, mock_statement_periods, mock_exchange_rates, mock_contracts, mock_accounts, mock_abacus_event, mock_ledger_account_contracts, mock_worksheet_account_contract_closing_balance, ): """Test bulk_delete_worksheet_account_contract_payable_details endpoint.""" detail1 = WorksheetAccountContractPayableDetailsFactory.create( worksheet_account_contract_payable_after_tax__abacus_event_id=1 ) WorksheetAccountContractPayableDetailsFactory.create( worksheet_account_contract_payable_after_tax__abacus_event_id=2 ) res = fixture_client.delete('/worksheet-account-contract-payable-details/event/1/') assert res.status_code == 204, res.text assert db.session.execute( select(WorksheetAccountContractPayableDetails).where( WorksheetAccountContractPayableDetails.deleted_at != None # noqa ) ).scalars().all() == [detail1] def test_get_by_statement_period_id_success( fixture_client, mock_contracts, mock_accounts, mock_abacus_event, mock_statement_periods, mock_ledger_account_contracts, mock_worksheet_account_contract_closing_balance, ): """Test successful retrieval of worksheet_account_contract_payable_details.""" statement_period_id = 1 payable_after_tax_id = 1 limit = 10 offset = 0 WorksheetAccountContractPayableDetailsFactory.create( statement_period_id=statement_period_id, worksheet_account_contract_payable_after_tax_id=payable_after_tax_id, ) response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/' # noqa: E501 f'?limit={limit}&offset={offset}' ) assert response.status_code == 200 assert response.json['total_count'] == 1 assert response.json['items'][0]['statement_period_id'] == statement_period_id response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/' # noqa: E501 ) assert response.status_code == 200 assert response.json['total_count'] == 1 assert response.json['items'][0]['statement_period_id'] == statement_period_id post_body = {'filters': {'worksheet_payable_after_tax_ids': [1]}} response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/', # noqa: E501 json=post_body, ) assert response.status_code == 200 assert response.json['total_count'] == 1 assert response.json['items'][0]['statement_period_id'] == statement_period_id assert ( response.json['items'][0]['worksheet_account_contract_payable_after_tax_id'] == payable_after_tax_id ) # noqa: E501 WorksheetAccountContractPayableDetailsFactory.create( statement_period_id=2, worksheet_account_contract_payable_after_tax_id=2 ) post_body = {'filters': {'worksheet_payable_after_tax_ids': [2]}} response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/', # noqa: E501 json=post_body, ) assert response.status_code == 200 assert response.json['total_count'] == 0 WorksheetAccountContractPayableDetailsFactory.create( statement_period_id=3, payable_detail_type_id=3 ) post_body = {'filters': {'detail_groups': ['vat_amount']}} response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/3/', # noqa: E501 json=post_body, ) assert response.status_code == 200 assert response.json['total_count'] == 1 WorksheetAccountContractPayableDetailsFactory.create( statement_period_id=3, payable_detail_type_id=3 ) post_body = {'filters': {'detail_groups': ['pre_tax_amount']}} response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/3/', # noqa: E501 json=post_body, ) assert response.status_code == 200 assert response.json['total_count'] == 0 post_body = {'other_key': {}} response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/', # noqa: E501 json=post_body, ) assert response.status_code == 400 def test_get_by_statement_period_id_fail( fixture_client, mock_contracts, mock_accounts, mock_abacus_event, mock_statement_periods, mock_ledger_account_contracts, mock_worksheet_account_contract_closing_balance, ): """Test retrieval of worksheet_account_contract_payable_details with no data.""" statement_period_id = 1 response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/' # noqa: E501 ) assert response.status_code == 200 assert response.json['total_count'] == 0 assert response.json['items'] == [] response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/' # noqa: E501 '?limit=10&offset=0' ) assert response.status_code == 200 assert response.json['total_count'] == 0 assert response.json['items'] == [] response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/' # noqa: E501 '?limit=10&offset=0' ) assert response.status_code == 200 assert response.json['total_count'] == 0 assert response.json['items'] == [] WorksheetAccountContractPayableDetailsFactory.create(statement_period_id=1) response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/' # noqa: E501 ) assert response.status_code == 200 assert response.json['total_count'] == 1 assert response.json['items'][0]['statement_period_id'] == statement_period_id response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/' # noqa: E501 '?limit=0&offset=1' ) assert response.status_code == 400 assert response.json['message'] == { 'query': { 'limit': [ 'Must be greater than or equal to 1 and less than or equal to 300.' ] } } response = fixture_client.post( f'/worksheet-account-contract-payable-details/statement-period/{statement_period_id}/' # noqa: E501 '?limit=1&offset=-1' ) assert response.status_code == 400 assert response.json['message'] == { 'query': {'offset': ['Must be greater than or equal to 0.']} } response = fixture_client.post( '/worksheet-account-contract-payable-details/statement-period/-1/' '?limit=1&offset=0' ) assert response.status_code == 404 def test_bulk_soft_delete_corrections_success( fixture_client, mock_statement_periods, mock_exchange_rates, mock_contracts, mock_accounts, mock_abacus_event, mock_ledger_account_contracts, mock_worksheet_account_contract_closing_balance, ): """Bulk soft delete vat/wht corrections by after_tax_id.""" after_tax = WorksheetPayableBalanceAfterTaxFactory.create() after_tax_id = after_tax.worksheet_account_contract_payable_after_tax_id wht_correction = WorksheetAccountContractPayableDetailsFactory.create( worksheet_account_contract_payable_after_tax=after_tax, payable_detail_type_id=4, ) vat_correction = WorksheetAccountContractPayableDetailsFactory.create( worksheet_account_contract_payable_after_tax=after_tax, payable_detail_type_id=5, ) closing_balance = WorksheetAccountContractPayableDetailsFactory.create( worksheet_account_contract_payable_after_tax=after_tax, payable_detail_type_id=1, ) payment_allocation = WorksheetAccountContractPayableDetailsFactory.create( worksheet_account_contract_payable_after_tax=after_tax, payable_detail_type_id=6, ) res = fixture_client.delete( '/worksheet-account-contract-payable-details/bulk', json={ 'worksheet_account_contract_payable_after_tax_ids': [after_tax_id], }, ) assert res.status_code == 204, res.text assert res.data == b'' db.session.expire_all() deleted_ids = { d.worksheet_account_contract_payable_details_id for d in db.session.execute( select(WorksheetAccountContractPayableDetails).where( WorksheetAccountContractPayableDetails.deleted_at.isnot(None) ) ) .scalars() .all() } assert deleted_ids == { wht_correction.worksheet_account_contract_payable_details_id, vat_correction.worksheet_account_contract_payable_details_id, } assert ( closing_balance.worksheet_account_contract_payable_details_id not in deleted_ids ) assert ( payment_allocation.worksheet_account_contract_payable_details_id not in deleted_ids ) def test_bulk_soft_delete_corrections_idempotent_for_missing( fixture_client, mock_statement_periods, mock_exchange_rates, mock_contracts, mock_accounts, mock_abacus_event, mock_ledger_account_contracts, mock_worksheet_account_contract_closing_balance, ): """Calling the endpoint with non-existent ids returns 204 and is a no-op.""" res = fixture_client.delete( '/worksheet-account-contract-payable-details/bulk', json={'worksheet_account_contract_payable_after_tax_ids': [999999]}, ) assert res.status_code == 204, res.text def test_bulk_soft_delete_corrections_missing_payload_returns_400(fixture_client): """Missing required field fails validation.""" res = fixture_client.delete( '/worksheet-account-contract-payable-details/bulk', json={}, ) assert res.status_code == 400, res.text def test_bulk_soft_delete_corrections_over_limit_returns_400(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