"""Unit tests for WorksheetPaymentCustom model.""" from datetime import datetime from decimal import Decimal from abacus_common_logic.connectors.database import db import pytest from sqlalchemy import select from werkzeug.exceptions import BadRequest, NotFound from payment.models.worksheet_payment_custom import WorksheetPaymentCustom from tests.conftest import _exec_sql from tests.utils.factories import WorksheetPaymentCustomFactory def test_create(mock_accounts, mock_contracts, mock_statement_periods): """Test create WorksheetPaymentCustom instance.""" WorksheetPaymentCustom.create( account_id=1, contract_id=1, currency_code='USD', amount=Decimal('100.00'), withholding_tax_amount=Decimal('-10.00'), withholding_tax_rate=Decimal('5.00'), vat_amount=Decimal('20.00'), vat_rate=Decimal('10.00'), amount_after_withholding_and_vat=Decimal('110.00'), activity_statement_period_id=1, statement_period_id=1, payment_name='test custom payment', ) worksheet_payment_customs = ( db.session.execute(select(WorksheetPaymentCustom)).scalars().all() ) assert len(worksheet_payment_customs) == 1 worksheet_payment_custom = worksheet_payment_customs[0] assert worksheet_payment_custom.account_id == 1 assert worksheet_payment_custom.contract_id == 1 assert worksheet_payment_custom.currency_code == 'USD' assert worksheet_payment_custom.amount == Decimal('100.00') assert worksheet_payment_custom.withholding_tax_amount == Decimal('-10.00') assert worksheet_payment_custom.withholding_tax_rate == Decimal('5.00') assert worksheet_payment_custom.vat_amount == Decimal('20.00') assert worksheet_payment_custom.vat_rate == Decimal('10.00') assert worksheet_payment_custom.amount_after_withholding_and_vat == Decimal( '110.00' ) assert worksheet_payment_custom.activity_statement_period_id == 1 assert worksheet_payment_custom.statement_period_id == 1 assert worksheet_payment_custom.payment_name == 'test custom payment' assert not worksheet_payment_custom.deleted_at assert not worksheet_payment_custom.deleted_by def test_create_with_positive_withholding_tax( mock_accounts, mock_contracts, mock_statement_periods ): """Test create WorksheetPaymentCustom with positive withholding tax (edge case).""" WorksheetPaymentCustom.create( account_id=1, contract_id=1, currency_code='USD', amount=Decimal('100.00'), withholding_tax_amount=Decimal('10.00'), # Positive for correction cases vat_amount=Decimal('20.00'), withholding_tax_rate=Decimal('10.00'), vat_rate=Decimal('20.00'), amount_after_withholding_and_vat=Decimal('130.00'), activity_statement_period_id=1, statement_period_id=1, payment_name='test correction payment', ) worksheet_payment_custom = ( db.session.execute(select(WorksheetPaymentCustom)).scalars().first() ) assert worksheet_payment_custom.withholding_tax_amount == Decimal('10.00') def test_create_with_negative_vat( mock_accounts, mock_contracts, mock_statement_periods ): """Test create WorksheetPaymentCustom with negative VAT (edge case).""" WorksheetPaymentCustom.create( account_id=1, contract_id=1, currency_code='USD', amount=Decimal('100.00'), withholding_tax_amount=Decimal('-10.00'), vat_amount=Decimal('-20.00'), # Negative for correction cases amount_after_withholding_and_vat=Decimal('70.00'), withholding_tax_rate=Decimal('10.00'), vat_rate=Decimal('20.00'), activity_statement_period_id=1, statement_period_id=1, payment_name='test correction payment', ) worksheet_payment_custom = ( db.session.execute(select(WorksheetPaymentCustom)).scalars().first() ) assert worksheet_payment_custom.vat_amount == Decimal('-20.00') def test_get_by_id(mock_accounts, mock_contracts, mock_statement_periods): """Test get_by_id method.""" created_item = WorksheetPaymentCustomFactory.create() found_item = WorksheetPaymentCustom.get_by_id( created_item.worksheet_payment_custom_id ) assert found_item == created_item created_item.update_attributes(deleted_at=datetime.now(), deleted_by='default_user') created_item.commit_changes() found_item = WorksheetPaymentCustom.get_by_id( created_item.worksheet_payment_custom_id ) assert found_item is None def test_soft_delete(mock_accounts, mock_contracts, mock_statement_periods): """Test soft delete WorksheetPaymentCustom instance.""" worksheet_payment_custom = WorksheetPaymentCustomFactory.create() assert worksheet_payment_custom.deleted_at is None assert worksheet_payment_custom.deleted_by is None worksheet_payment_custom._soft_delete() worksheet_payment_custom.commit_changes() assert worksheet_payment_custom.deleted_at is not None assert worksheet_payment_custom.deleted_by is not None def test_update_attributes(mock_accounts, mock_contracts, mock_statement_periods): """Test update_attributes method.""" worksheet_payment_custom = WorksheetPaymentCustomFactory.create( payment_name='original name' ) assert worksheet_payment_custom.payment_name == 'original name' worksheet_payment_custom.update_attributes(payment_name='updated name') worksheet_payment_custom.commit_changes() assert worksheet_payment_custom.payment_name == 'updated name' def test_is_sent_returns_false_when_no_state( mock_accounts, mock_contracts, mock_statement_periods ): """Test is_sent returns False when there is no abacus_state record.""" worksheet = WorksheetPaymentCustomFactory.create() assert worksheet.is_sent() is False def test_is_sent_returns_false_with_init_status( mock_accounts, mock_contracts, mock_statement_periods ): """Test is_sent returns False when status is 'init'.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'init' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'init', NULL, '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() assert worksheet.is_sent() is False def test_is_sent_returns_false_with_error_status( mock_accounts, mock_contracts, mock_statement_periods ): """Test is_sent returns False when status is 'error'.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'error' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'error', 'Payment failed', '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() assert worksheet.is_sent() is False def test_is_sent_returns_false_with_rejected_status( mock_accounts, mock_contracts, mock_statement_periods ): """Test is_sent returns False when status is 'rejected'.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'rejected' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'rejected', 'Payment rejected', '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() assert worksheet.is_sent() is False def test_is_sent_returns_true_with_complete_status( mock_accounts, mock_contracts, mock_statement_periods ): """Test is_sent returns True when status is 'complete'.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'complete' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'complete', NULL, '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() assert worksheet.is_sent() is True def test_is_sent_returns_true_with_running_status( mock_accounts, mock_contracts, mock_statement_periods ): """Test is_sent returns True when status is 'running'.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'running' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'running', NULL, '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() assert worksheet.is_sent() is True def test_is_sent_ignores_other_actions( mock_accounts, mock_contracts, mock_statement_periods ): """Test is_sent only checks send_payments action.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with different action SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'generate_export', 'complete', NULL, '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() assert worksheet.is_sent() is False def test_is_sent_ignores_other_tables( mock_accounts, mock_contracts, mock_statement_periods ): """Test is_sent only checks worksheet_payment_custom table.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state for different table with same ID SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('payment_group_payment', {worksheet_id}, 'send_payments', 'complete', NULL, '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() assert worksheet.is_sent() is False def test_delete_by_id_or_error_success( mock_accounts, mock_contracts, mock_statement_periods ): """Test delete_by_id_or_error successfully deletes when payment not sent.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id assert worksheet.deleted_at is None WorksheetPaymentCustom.delete_by_id_or_error(worksheet_id) # Refresh from database db.session.refresh(worksheet) assert worksheet.deleted_at is not None assert worksheet.deleted_by is not None def test_delete_by_id_or_error_fails_when_sent_complete( mock_accounts, mock_contracts, mock_statement_periods ): """Test delete_by_id_or_error raises error when payment is complete.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'complete' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'complete', NULL, '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() with pytest.raises(BadRequest) as exc_info: WorksheetPaymentCustom.delete_by_id_or_error(worksheet_id) assert 'already been sent' in str(exc_info.value.description) # Verify record was not deleted db.session.refresh(worksheet) assert worksheet.deleted_at is None def test_delete_by_id_or_error_fails_when_sent_running( mock_accounts, mock_contracts, mock_statement_periods ): """Test delete_by_id_or_error raises error when payment is running.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'running' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'running', NULL, '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() with pytest.raises(BadRequest) as exc_info: WorksheetPaymentCustom.delete_by_id_or_error(worksheet_id) assert 'already been sent' in str(exc_info.value.description) # Verify record was not deleted db.session.refresh(worksheet) assert worksheet.deleted_at is None def test_delete_by_id_or_error_succeeds_with_init_status( mock_accounts, mock_contracts, mock_statement_periods ): """Test delete_by_id_or_error succeeds when payment status is init.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'init' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'init', NULL, '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() WorksheetPaymentCustom.delete_by_id_or_error(worksheet_id) # Verify record was deleted db.session.refresh(worksheet) assert worksheet.deleted_at is not None def test_delete_by_id_or_error_succeeds_with_error_status( mock_accounts, mock_contracts, mock_statement_periods ): """Test delete_by_id_or_error succeeds when payment status is error.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'error' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'error', 'Payment failed', '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() WorksheetPaymentCustom.delete_by_id_or_error(worksheet_id) # Verify record was deleted db.session.refresh(worksheet) assert worksheet.deleted_at is not None def test_delete_by_id_or_error_succeeds_with_rejected_status( mock_accounts, mock_contracts, mock_statement_periods ): """Test delete_by_id_or_error succeeds when payment status is rejected.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Create abacus_state with 'rejected' status SQL_QUERY = f""" INSERT INTO abacus_state( `parent_table_name`, `parent_table_id`, `action_name`, `action_status`, `message`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ('worksheet_payment_custom', {worksheet_id}, 'send_payments', 'rejected', 'Payment rejected', '2', NOW(), '2', NOW()) """ _exec_sql(SQL_QUERY) db.session.commit() WorksheetPaymentCustom.delete_by_id_or_error(worksheet_id) # Verify record was deleted db.session.refresh(worksheet) assert worksheet.deleted_at is not None def test_delete_by_id_or_error_raises_404_for_nonexistent_id( mock_accounts, mock_contracts, mock_statement_periods ): """Test delete_by_id_or_error raises 404 for non-existent ID.""" nonexistent_id = 99999 with pytest.raises(NotFound): WorksheetPaymentCustom.delete_by_id_or_error(nonexistent_id) def test_delete_by_id_or_error_raises_404_for_already_deleted( mock_accounts, mock_contracts, mock_statement_periods ): """Test delete_by_id_or_error raises 404 for already deleted record.""" worksheet = WorksheetPaymentCustomFactory.create() worksheet_id = worksheet.worksheet_payment_custom_id # Soft delete the record worksheet._soft_delete() worksheet.commit_changes() with pytest.raises(NotFound): WorksheetPaymentCustom.delete_by_id_or_error(worksheet_id)