from sqlalchemy import func, select from payment.api import db """Functional tests for worksheet_tax_correction_vat endpoints.""" from datetime import datetime from decimal import Decimal import pytest from payment.constants import constants from payment.models import WorksheetTaxCorrectionVAT from tests.utils.factories import ( PaymentGroupPaymentAccountDetailFactory, WorksheetAccountContractClosingBalanceFactory, WorksheetAccountContractPayableDetailsFactory, WorksheetPayableBalanceAfterTaxFactory, WorksheetTaxCorrectionVATFactory, ) def test_bulk_create_worksheet_tax_correction_vat_success( fixture_client, mock_statement_periods, mock_accounts, mock_contracts ): """Test for bulk_create_worksheet_tax_correction_vat endpoint. POST: /tax-corrections/vat/bulk """ post_data = ( { 'payable_detail_type_id': 1, 'account_id': 1, 'contract_id': 1, 'correction_statement_period_id': 1, 'base_amount_payee_currency': 10.00, 'payee_currency_code': 'USD', 'vat_currency_code': 'USD', 'vat_rate': 10.00, 'vat_amount_payee_currency': 10.00, 'vat_amount_vat_currency': 10.00, 'net_amount_payee_currency': 10.00, 'note': 'test note 1', }, { 'payable_detail_type_id': 2, 'account_id': 2, 'contract_id': 2, 'correction_statement_period_id': 2, 'base_amount_payee_currency': 10.00, 'payee_currency_code': 'USD', 'vat_currency_code': 'USD', 'vat_rate': 10.00, 'vat_amount_payee_currency': 10.00, 'vat_amount_vat_currency': 10.00, 'net_amount_payee_currency': 10.00, 'note': 'test note 1', }, ) res = fixture_client.post('/tax-corrections/vat/bulk', json=post_data) assert res.status_code == 201 assert res.json == constants.BULK_ENDPOINT_SUCCESS_RESPONSE assert db.session.execute( select(func.count()).select_from(select(WorksheetTaxCorrectionVAT).subquery()) ).scalar_one() == len(post_data) def test_bulk_create_worksheet_tax_correction_vat_failure_validation( fixture_client, mock_statement_periods, mock_accounts, mock_contracts ): """Test for bulk_create_worksheet_tax_correction_vat endpoint failure validation. POST: /tax-corrections/vat/bulk """ post_data = ( { 'payable_detail_type_id': 1, 'account_id': 1, 'correction_statement_period_id': 1, 'base_amount_payee_currency': 10.00, 'payee_currency_code': 'USD', 'vat_currency_code': 'USD', 'vat_rate': 10.00, 'vat_amount_payee_currency': 10.00, 'vat_amount_vat_currency': 10.00, 'net_amount_payee_currency': 10.00, 'note': 'test note 1', }, { 'payable_detail_type_id': 2, 'contract_id': 2, 'correction_statement_period_id': 2, 'base_amount_payee_currency': 10.00, 'payee_currency_code': 'USD', 'vat_currency_code': 'USD', 'vat_rate': 10.00, 'vat_amount_payee_currency': 10.00, 'vat_amount_vat_currency': 10.00, 'net_amount_payee_currency': 10.00, 'note': 'test note 1', }, ) res = fixture_client.post('/tax-corrections/vat/bulk', json=post_data) assert res.status_code == 400 assert res.json == { 'code': 'error', 'message': { 'json': { '0': {'contract_id': ['Must be specified.']}, '1': {'account_id': ['Must be specified.']}, } }, } assert ( db.session.execute( select(func.count()).select_from( select(WorksheetTaxCorrectionVAT).subquery() ) ).scalar_one() == 0 ) @pytest.mark.parametrize( ('correction_status',), ( (constants.CORRECTION_STATUSES.ACTIVE,), (constants.CORRECTION_STATUSES.PENDING,), ), ) def test_get_tax_corrections_vat_success( fixture_client, correction_status, mock_accounts, mock_contracts, mock_abacus_event, mock_ledger_account_contracts, ): """Test for get_tax_corrections_vat endpoint. POST: /tax-corrections/vat/{correction_status} """ statement_period_id_1 = 1 payable_detail_type_id = constants.CORRECTION_TYPE_TO_PAYABLE_DETAIL_TYPE_ID.get( constants.CORRECTION_TYPES.VAT ) deleted_at = ( datetime.now() if correction_status == constants.CORRECTION_STATUSES.PENDING else None ) worksheet_closing_balance = WorksheetAccountContractClosingBalanceFactory.create() worksheet_after_tax1 = WorksheetPayableBalanceAfterTaxFactory.create( # noqa worksheet_account_contract_closing_balance_id=worksheet_closing_balance.worksheet_account_contract_closing_balance_id, statement_period_id=statement_period_id_1, ) PaymentGroupPaymentAccountDetailFactory.create( # noqa worksheet_account_contract_payable_after_tax_id=worksheet_after_tax1.worksheet_account_contract_payable_after_tax_id, deleted_at=deleted_at, ) correction1 = WorksheetTaxCorrectionVATFactory.create( contract_id=worksheet_closing_balance.contract_id, account_id=worksheet_closing_balance.account_id, payable_detail_type_id=payable_detail_type_id, correction_statement_period_id=statement_period_id_1, ) WorksheetAccountContractPayableDetailsFactory.create( # noqa worksheet_account_contract_payable_after_tax=worksheet_after_tax1, statement_period_id=statement_period_id_1, payable_detail_type_id=payable_detail_type_id, target_table=WorksheetTaxCorrectionVAT.__tablename__, target_id=correction1.worksheet_tax_correction_vat_id, ) statement_period_id_2 = 2 worksheet_after_tax2 = WorksheetPayableBalanceAfterTaxFactory.create( # noqa worksheet_account_contract_closing_balance_id=worksheet_closing_balance.worksheet_account_contract_closing_balance_id, statement_period_id=statement_period_id_2, ) PaymentGroupPaymentAccountDetailFactory.create( # noqa worksheet_account_contract_payable_after_tax_id=worksheet_after_tax2.worksheet_account_contract_payable_after_tax_id, deleted_at=deleted_at, ) correction2 = WorksheetTaxCorrectionVATFactory.create( contract_id=worksheet_closing_balance.contract_id, account_id=worksheet_closing_balance.account_id, payable_detail_type_id=payable_detail_type_id, correction_statement_period_id=statement_period_id_2, wht_rate=Decimal('10.00'), wht_amount_payee_currency=Decimal('10.01'), wht_amount_vat_currency=Decimal('10.02'), ) WorksheetAccountContractPayableDetailsFactory.create( # noqa worksheet_account_contract_payable_after_tax=worksheet_after_tax2, statement_period_id=statement_period_id_2, payable_detail_type_id=payable_detail_type_id, target_table=WorksheetTaxCorrectionVAT.__tablename__, target_id=correction2.worksheet_tax_correction_vat_id, ) res = fixture_client.post( f'/tax-corrections/vat/{correction_status}' f'/?limit=1&offset=1' ) assert res.status_code == 200, res.text assert res.json == { 'items': [ { 'worksheet_tax_correction_vat_id': correction2.worksheet_tax_correction_vat_id, 'payable_detail_type_id': correction2.payable_detail_type_id, 'account_id': correction2.account_id, 'contract_id': correction2.contract_id, 'correction_statement_period_id': correction2.correction_statement_period_id, 'base_amount_payee_currency': str( correction2.base_amount_payee_currency ), 'payee_currency_code': correction2.payee_currency_code, 'vat_category': 'closing_balance', 'vat_currency_code': correction2.vat_currency_code, 'vat_rate': str(correction2.vat_rate), 'vat_amount_payee_currency': str(correction2.vat_amount_payee_currency), 'vat_amount_vat_currency': str(correction2.vat_amount_vat_currency), 'net_amount_payee_currency': str(correction2.net_amount_payee_currency), 'wht_rate': str(correction2.wht_rate), 'wht_amount_payee_currency': str(correction2.wht_amount_payee_currency), 'wht_amount_vat_currency': str(correction2.wht_amount_vat_currency), 'note': correction2.note, } ], 'total_count': 2, } res = fixture_client.post( f'/tax-corrections/vat/{correction_status}' f'/?limit=1&offset=0', json={'filters': {'correction_statement_period_id': 1, 'contract_ids': [1]}}, ) assert res.status_code == 200, res.text assert res.json == { 'items': [ { 'worksheet_tax_correction_vat_id': correction1.worksheet_tax_correction_vat_id, 'payable_detail_type_id': correction1.payable_detail_type_id, 'account_id': correction1.account_id, 'contract_id': correction1.contract_id, 'correction_statement_period_id': correction1.correction_statement_period_id, 'base_amount_payee_currency': str( correction1.base_amount_payee_currency ), 'payee_currency_code': correction1.payee_currency_code, 'vat_category': 'closing_balance', 'vat_currency_code': correction1.vat_currency_code, 'vat_rate': str(correction1.vat_rate), 'vat_amount_payee_currency': str(correction1.vat_amount_payee_currency), 'vat_amount_vat_currency': str(correction1.vat_amount_vat_currency), 'net_amount_payee_currency': str(correction1.net_amount_payee_currency), 'wht_rate': correction1.wht_rate, 'wht_amount_payee_currency': correction1.wht_amount_payee_currency, 'wht_amount_vat_currency': correction1.wht_amount_vat_currency, 'note': correction1.note, } ], 'total_count': 1, } res = fixture_client.post( f'/tax-corrections/vat/{correction_status}', json={ 'filters': { 'correction_statement_period_id': 999, 'contract_ids': [999, 12344], } }, ) assert res.status_code == 200, res.text assert res.json == {'items': [], 'total_count': 0} @pytest.mark.parametrize( ('correction_status',), ( (constants.CORRECTION_STATUSES.ACTIVE,), (constants.CORRECTION_STATUSES.PENDING,), ), ) def test_get_tax_corrections_vat_failure(fixture_client, correction_status): """Test for get_tax_corrections_vat endpoint failure validation. POST: /tax-corrections/vat/{correction_status} """ res = fixture_client.post( f'/tax-corrections/vat/{correction_status}' f'/?limit=1a&offset=0b' ) assert res.status_code == 400, res.text assert res.json == { 'code': 'error', 'message': { 'query': { 'limit': ['Not a valid integer.'], 'offset': ['Not a valid integer.'], } }, } res = fixture_client.post( f'/tax-corrections/vat/{correction_status}', json={ 'filters': {'correction_statement_period_id': '1a', 'contract_ids': ['1b']} }, ) assert res.status_code == 400, res.text assert res.json == { 'code': 'error', 'message': { 'json': { 'filters': { 'contract_ids': { '0': ['Must be an integer greater or ' 'equal to 0.'] }, 'correction_statement_period_id': [ 'Must be an integer ' 'greater or equal to ' '0.' ], } } }, } def test_bulk_delete_worksheet_tax_correction_vat_success( fixture_client, mock_statement_periods, mock_contracts, mock_accounts ): """Test bulk_delete_worksheet_tax_correction_vat endpoint.""" worksheet_tax_correction_to_delete = WorksheetTaxCorrectionVATFactory.create() body = {'worksheet_tax_correction_vat_ids': [1]} res = fixture_client.delete('/tax-corrections/vat/bulk/', json=body) assert res.status_code == 204, res.text assert db.session.execute( select(WorksheetTaxCorrectionVAT).where( WorksheetTaxCorrectionVAT.deleted_at.isnot(None) ) ).scalars().all() == [worksheet_tax_correction_to_delete] def test_bulk_delete_worksheet_tax_correction_vat_failure( fixture_client, mock_statement_periods, mock_contracts, mock_accounts ): """Test delete worksheet_tax_correction_vat endpoint.""" WorksheetTaxCorrectionVATFactory.create() body = {'worksheet_tax_correction_vat_ids': [-1]} res = fixture_client.delete('/tax-corrections/vat/bulk/', json=body) assert res.status_code == 400 assert res.json['message'] == { 'json': { 'worksheet_tax_correction_vat_ids': { '0': ['Must be greater than or equal to 0.'] } } } res = fixture_client.delete('/tax-corrections/vat/bulk/') assert res.status_code == 400 assert res.json['message'] == { 'json': {'worksheet_tax_correction_vat_ids': ['Must be specified.']} }