"""Unit tests for Worksheet Payment Contract Advance schemas.""" import decimal from marshmallow import ValidationError import pytest from payment.constants.constants import ( WORKSHEET_PAYABLE_BALANCE_AFTER_TAX_SORTABLE_COLUMNS, ) from payment.schemas.worksheet_payable_balance_after_tax import ( WorksheetPayableAfterTaxFilterSchema, WorksheetPayableBalanceAfterTaxBulkUpdateSchema, WorksheetPayableBalanceAfterTaxListSchema, WorksheetPayableBalanceAfterTaxOverviewSchema, WorksheetPayableBalanceAfterTaxSchema, ) from tests.utils.factories import WorksheetPayableBalanceAfterTaxFactory def test_worksheet_payable_balance_after_tax_schema_dump(): """Test WorksheetPayableBalanceAfterTaxSchema.""" worksheet_payable_balance_after_tax = WorksheetPayableBalanceAfterTaxFactory.build() # Test dump data = WorksheetPayableBalanceAfterTaxSchema().dump( worksheet_payable_balance_after_tax ) assert data == { 'worksheet_account_contract_closing_balance_id': worksheet_payable_balance_after_tax.worksheet_account_contract_closing_balance_id, # noqa 'contract_id': worksheet_payable_balance_after_tax.contract_id, 'account_id': worksheet_payable_balance_after_tax.account_id, 'statement_period_id': worksheet_payable_balance_after_tax.statement_period_id, 'abacus_event_id': worksheet_payable_balance_after_tax.abacus_event_id, 'payable_amount_pre_tax': str( worksheet_payable_balance_after_tax.payable_amount_pre_tax ), 'tax_withholding_amount': str( worksheet_payable_balance_after_tax.tax_withholding_amount ), 'vat_amount': str(worksheet_payable_balance_after_tax.vat_amount), 'payable_amount_post_tax': str( worksheet_payable_balance_after_tax.payable_amount_post_tax ), 'currency_code': worksheet_payable_balance_after_tax.currency_code, 'country_of_tax_residence': worksheet_payable_balance_after_tax.country_of_tax_residence, # noqa 'country_of_tax_policy': worksheet_payable_balance_after_tax.country_of_tax_policy, # noqa } def test_worksheet_payable_balance_after_tax_schema_load(): """Test WorksheetPayableBalanceAfterTaxSchema load data.""" worksheet_payable_balance_after_tax = WorksheetPayableBalanceAfterTaxFactory.build() data = { 'worksheet_account_contract_closing_balance_id': worksheet_payable_balance_after_tax.worksheet_account_contract_closing_balance_id, # noqa 'contract_id': worksheet_payable_balance_after_tax.contract_id, 'account_id': worksheet_payable_balance_after_tax.account_id, 'statement_period_id': worksheet_payable_balance_after_tax.statement_period_id, 'abacus_event_id': worksheet_payable_balance_after_tax.abacus_event_id, 'payable_amount_pre_tax': str( worksheet_payable_balance_after_tax.payable_amount_pre_tax ), 'tax_withholding_amount': str( worksheet_payable_balance_after_tax.tax_withholding_amount ), 'vat_amount': str(worksheet_payable_balance_after_tax.vat_amount), 'payable_amount_post_tax': str( worksheet_payable_balance_after_tax.payable_amount_post_tax ), 'currency_code': worksheet_payable_balance_after_tax.currency_code, 'country_of_tax_residence': worksheet_payable_balance_after_tax.country_of_tax_residence, # noqa 'country_of_tax_policy': worksheet_payable_balance_after_tax.country_of_tax_policy, # noqa } # Test load loaded_data = WorksheetPayableBalanceAfterTaxSchema().load(data) assert loaded_data == { 'worksheet_account_contract_closing_balance_id': worksheet_payable_balance_after_tax.worksheet_account_contract_closing_balance_id, # noqa 'contract_id': worksheet_payable_balance_after_tax.contract_id, 'account_id': worksheet_payable_balance_after_tax.account_id, 'statement_period_id': worksheet_payable_balance_after_tax.statement_period_id, 'abacus_event_id': worksheet_payable_balance_after_tax.abacus_event_id, 'payable_amount_pre_tax': worksheet_payable_balance_after_tax.payable_amount_pre_tax, # noqa 'tax_withholding_amount': worksheet_payable_balance_after_tax.tax_withholding_amount, # noqa 'vat_amount': worksheet_payable_balance_after_tax.vat_amount, # noqa 'payable_amount_post_tax': worksheet_payable_balance_after_tax.payable_amount_post_tax, # noqa 'currency_code': worksheet_payable_balance_after_tax.currency_code, 'country_of_tax_residence': worksheet_payable_balance_after_tax.country_of_tax_residence, # noqa 'country_of_tax_policy': worksheet_payable_balance_after_tax.country_of_tax_policy, # noqa } def test_worksheet_payable_balance_after_tax_schema_load_no_taxes(): """Test WorksheetPayableBalanceAfterTaxSchema load data.""" worksheet_payable_balance_after_tax = WorksheetPayableBalanceAfterTaxFactory.build() data = { 'worksheet_account_contract_closing_balance_id': worksheet_payable_balance_after_tax.worksheet_account_contract_closing_balance_id, # noqa 'contract_id': worksheet_payable_balance_after_tax.contract_id, 'account_id': worksheet_payable_balance_after_tax.account_id, 'statement_period_id': worksheet_payable_balance_after_tax.statement_period_id, 'abacus_event_id': worksheet_payable_balance_after_tax.abacus_event_id, 'payable_amount_pre_tax': str( worksheet_payable_balance_after_tax.payable_amount_pre_tax ), 'tax_withholding_amount': None, 'vat_amount': None, 'payable_amount_post_tax': str( worksheet_payable_balance_after_tax.payable_amount_post_tax ), 'currency_code': worksheet_payable_balance_after_tax.currency_code, 'country_of_tax_residence': worksheet_payable_balance_after_tax.country_of_tax_residence, # noqa 'country_of_tax_policy': worksheet_payable_balance_after_tax.country_of_tax_policy, # noqa } # Test load loaded_data = WorksheetPayableBalanceAfterTaxSchema().load(data) assert loaded_data == { 'worksheet_account_contract_closing_balance_id': worksheet_payable_balance_after_tax.worksheet_account_contract_closing_balance_id, # noqa 'contract_id': worksheet_payable_balance_after_tax.contract_id, 'account_id': worksheet_payable_balance_after_tax.account_id, 'statement_period_id': worksheet_payable_balance_after_tax.statement_period_id, 'abacus_event_id': worksheet_payable_balance_after_tax.abacus_event_id, 'payable_amount_pre_tax': worksheet_payable_balance_after_tax.payable_amount_pre_tax, # noqa 'tax_withholding_amount': None, 'vat_amount': None, 'payable_amount_post_tax': worksheet_payable_balance_after_tax.payable_amount_post_tax, # noqa 'currency_code': worksheet_payable_balance_after_tax.currency_code, 'country_of_tax_residence': worksheet_payable_balance_after_tax.country_of_tax_residence, # noqa 'country_of_tax_policy': worksheet_payable_balance_after_tax.country_of_tax_policy, # noqa } def test_worksheet_payable_balance_after_tax_schema_load_validation(): """Test WorksheetPayableBalanceAfterTaxSchema load data validation.""" data = { 'worksheet_account_contract_closing_balance_id': -1, 'contract_id': -1, 'account_id': -1, 'statement_period_id': -1, 'abacus_event_id': -1, 'payable_amount_pre_tax': '-100.00', 'tax_withholding_amount': '-10.00', 'vat_amount': '11.01', 'payable_amount_post_tax': '-110.00', 'currency_code': '', 'country_of_tax_residence': '', 'country_of_tax_policy': '', } with pytest.raises(ValidationError) as exc: WorksheetPayableBalanceAfterTaxSchema().load(data) assert exc.value.messages == { 'worksheet_account_contract_closing_balance_id': [ 'Must be greater than or equal to 0.' ], 'contract_id': ['Must be greater than or equal to 0.'], 'account_id': ['Must be greater than or equal to 0.'], 'statement_period_id': ['Must be greater than or equal to 0.'], 'abacus_event_id': ['Must be greater than or equal to 0.'], 'currency_code': ['Must be specified.'], 'country_of_tax_residence': ['Must be specified.'], 'country_of_tax_policy': ['Must be specified.'], } def test_worksheet_payable_balance_after_tax_list_schema_dump(): """Test WorksheetPayableBalanceAfterTaxListSchema.""" worksheet_payable_balance_after_tax = WorksheetPayableBalanceAfterTaxFactory.build() # Test dump data = WorksheetPayableBalanceAfterTaxListSchema().dump( {'items': [worksheet_payable_balance_after_tax], 'total_count': 1} ) assert data == { 'items': [ { 'worksheet_account_contract_payable_after_tax_id': worksheet_payable_balance_after_tax.worksheet_account_contract_payable_after_tax_id, # noqa 'worksheet_account_contract_closing_balance_id': worksheet_payable_balance_after_tax.worksheet_account_contract_closing_balance_id, # noqa 'contract_id': worksheet_payable_balance_after_tax.contract_id, 'account_id': worksheet_payable_balance_after_tax.account_id, 'statement_period_id': worksheet_payable_balance_after_tax.statement_period_id, # noqa 'abacus_event_id': worksheet_payable_balance_after_tax.abacus_event_id, 'payable_amount_pre_tax': str( worksheet_payable_balance_after_tax.payable_amount_pre_tax ), 'tax_withholding_amount': str( worksheet_payable_balance_after_tax.tax_withholding_amount ), 'vat_amount': str(worksheet_payable_balance_after_tax.vat_amount), 'payable_amount_post_tax': str( worksheet_payable_balance_after_tax.payable_amount_post_tax ), 'currency_code': worksheet_payable_balance_after_tax.currency_code, 'country_of_tax_residence': worksheet_payable_balance_after_tax.country_of_tax_residence, # noqa 'country_of_tax_policy': worksheet_payable_balance_after_tax.country_of_tax_policy, # noqa } ], 'total_count': 1, } def test_aggregated_schema_dump(): schema = WorksheetPayableBalanceAfterTaxOverviewSchema() data = { 'payable_amount_pre_tax': decimal.Decimal('100.00'), 'tax_withholding_amount': decimal.Decimal('10.00'), 'vat_amount': decimal.Decimal('5.00'), 'payable_amount_post_tax': decimal.Decimal('85.00'), } result = schema.dump(data) assert result['payable_amount_pre_tax'] == '100.00' assert result['tax_withholding_amount'] == '10.00' assert result['vat_amount'] == '5.00' assert result['payable_amount_post_tax'] == '85.00' def test_worksheet_payable_balance_after_tax_bulk_update_schema_dump(): """Test WorksheetPayableBalanceAfterTaxBulkUpdateSchema dump.""" data = { 'worksheet_account_contract_payable_after_tax_id': 123, 'tax_withholding_amount': decimal.Decimal('15.00'), 'vat_amount': decimal.Decimal('7.50'), 'payable_amount_post_tax': decimal.Decimal('77.50'), } result = WorksheetPayableBalanceAfterTaxBulkUpdateSchema().dump(data) assert result == { 'worksheet_account_contract_payable_after_tax_id': 123, 'tax_withholding_amount': '15.00', 'vat_amount': '7.50', 'payable_amount_post_tax': '77.50', } def test_worksheet_payable_balance_after_tax_bulk_update_schema_load(): """Test WorksheetPayableBalanceAfterTaxBulkUpdateSchema load.""" data = { 'worksheet_account_contract_payable_after_tax_id': 123, 'tax_withholding_amount': '15.00', 'vat_amount': '7.50', 'payable_amount_post_tax': '77.50', } result = WorksheetPayableBalanceAfterTaxBulkUpdateSchema().load(data) assert result == { 'worksheet_account_contract_payable_after_tax_id': 123, 'tax_withholding_amount': decimal.Decimal('15.00'), 'vat_amount': decimal.Decimal('7.50'), 'payable_amount_post_tax': decimal.Decimal('77.50'), } def test_worksheet_payable_balance_after_tax_bulk_update_schema_validation(): """Test WorksheetPayableBalanceAfterTaxBulkUpdateSchema validation.""" # Missing required field data = { 'worksheet_account_contract_payable_after_tax_id': 123, 'tax_withholding_amount': '15.00', 'vat_amount': '7.50', # Missing payable_amount_post_tax } with pytest.raises(ValidationError) as exc: WorksheetPayableBalanceAfterTaxBulkUpdateSchema().load(data) assert 'payable_amount_post_tax' in exc.value.messages def test_worksheet_payable_balance_after_tax_bulk_update_schema_invalid_id(): """Test WorksheetPayableBalanceAfterTaxBulkUpdateSchema with invalid ID.""" data = { 'worksheet_account_contract_payable_after_tax_id': -1, 'tax_withholding_amount': '15.00', 'vat_amount': '7.50', 'payable_amount_post_tax': '77.50', } with pytest.raises(ValidationError) as exc: WorksheetPayableBalanceAfterTaxBulkUpdateSchema().load(data) assert 'worksheet_account_contract_payable_after_tax_id' in exc.value.messages def test_worksheet_payable_balance_after_tax_bulk_update_schema_many(): """Test WorksheetPayableBalanceAfterTaxBulkUpdateSchema with many=True.""" data = [ { 'worksheet_account_contract_payable_after_tax_id': 123, 'tax_withholding_amount': '15.00', 'vat_amount': '7.50', 'payable_amount_post_tax': '77.50', }, { 'worksheet_account_contract_payable_after_tax_id': 456, 'tax_withholding_amount': '25.00', 'vat_amount': '12.50', 'payable_amount_post_tax': '162.50', }, ] result = WorksheetPayableBalanceAfterTaxBulkUpdateSchema(many=True).load(data) assert len(result) == 2 assert result[0]['worksheet_account_contract_payable_after_tax_id'] == 123 assert result[0]['tax_withholding_amount'] == decimal.Decimal('15.00') assert result[1]['worksheet_account_contract_payable_after_tax_id'] == 456 assert result[1]['tax_withholding_amount'] == decimal.Decimal('25.00') def test_worksheet_payable_balance_after_tax_bulk_update_schema_nullable_fields(): """Test WorksheetPayableBalanceAfterTaxBulkUpdateSchema with nullable tax fields.""" # Test with null tax_withholding_amount and vat_amount data = { 'worksheet_account_contract_payable_after_tax_id': 123, 'tax_withholding_amount': None, 'vat_amount': None, 'payable_amount_post_tax': '100.00', } result = WorksheetPayableBalanceAfterTaxBulkUpdateSchema().load(data) assert result == { 'worksheet_account_contract_payable_after_tax_id': 123, 'tax_withholding_amount': None, 'vat_amount': None, 'payable_amount_post_tax': decimal.Decimal('100.00'), } # Test with missing tax_withholding_amount and vat_amount (should also be valid) data_without_tax_fields = { 'worksheet_account_contract_payable_after_tax_id': 456, 'payable_amount_post_tax': '200.00', } result2 = WorksheetPayableBalanceAfterTaxBulkUpdateSchema().load( data_without_tax_fields ) assert result2['worksheet_account_contract_payable_after_tax_id'] == 456 assert result2['payable_amount_post_tax'] == decimal.Decimal('200.00') # Fields not provided should not be in the result or be None assert result2.get('tax_withholding_amount') is None assert result2.get('vat_amount') is None def test_filter_schema_valid_fields(): schema = WorksheetPayableAfterTaxFilterSchema() data = { 'sort_by': WORKSHEET_PAYABLE_BALANCE_AFTER_TAX_SORTABLE_COLUMNS[0], 'sort_order': 'asc', 'search_term': 'test', } result = schema.load(data) assert result['sort_by'] == WORKSHEET_PAYABLE_BALANCE_AFTER_TAX_SORTABLE_COLUMNS[0] assert result['sort_order'] == 'asc' assert result['search_term'] == 'test' def test_filter_schema_invalid_sort_by(): schema = WorksheetPayableAfterTaxFilterSchema() data = { 'sort_by': 'invalid_column', 'sort_order': 'asc', } try: schema.load(data) assert False, 'Should have raised ValidationError for invalid sort_by' except ValidationError as exc: assert 'sort_by' in exc.messages def test_filter_schema_invalid_sort_order(): schema = WorksheetPayableAfterTaxFilterSchema() data = { 'sort_by': WORKSHEET_PAYABLE_BALANCE_AFTER_TAX_SORTABLE_COLUMNS[0], 'sort_order': 'invalid_order', } try: schema.load(data) assert False, 'Should have raised ValidationError for invalid sort_order' except ValidationError as exc: assert 'sort_order' in exc.messages def test_filter_schema_search_term_none(): schema = WorksheetPayableAfterTaxFilterSchema() data = { 'search_term': None, } result = schema.load(data) assert result['search_term'] is None