"""Unit tests for contract_flowthrough logic.""" from datetime import datetime from unittest.mock import MagicMock from unittest.mock import patch from abacus_common_logic.constants.constants import SYSTEM_TIMEZONE from abacus_common_logic.utils.users import get_flask_user_id from freezegun import freeze_time import pytest from abacus_contract.constants.constants import \ CONTRACT_FLOWTHROUGH_STATUSES from abacus_contract.constants.error import \ ERROR_CONTRACT_FLOWTHROUGH_ALREADY_EXISTS from abacus_contract.logic import contract_flowthrough as logic from abacus_contract.utils.exception import ObjectAlreadyExistException from tests.utils.factories import ContractFactory from tests.utils.factories import ContractFlowthroughFactory @patch('abacus_contract.logic.contract_flowthrough.ContractFlowthrough') @patch('abacus_contract.logic.contract_flowthrough.Contract') def test_get_contract_flowthrough_by_contract_id( mock_contract_model, mock_contract_flowthrough_model ): """Test getting a contract_flowthrough by contract_id.""" mock_contract = ContractFactory.create() mock_contract_flowthrough = ContractFlowthroughFactory.create( contract=mock_contract ) mock_contract_model.get_by_id_or_error.return_value = mock_contract mock_contract_flowthrough_model.get_by_contract_id.return_value = \ mock_contract_flowthrough contract_id = mock_contract.contract_id res = logic.get_contract_flowthrough_by_contract_id(contract_id) assert res.status == 200 assert res.message['contract_id'] == contract_id def test_get_non_existent_contract_flowthrough_by_contract_id(): """Test getting a non-existent contract_flowthrough by contract_id.""" mock_contract = ContractFactory.create() contract_id = mock_contract.contract_id res = logic.get_contract_flowthrough_by_contract_id(contract_id) assert res.status == 200 assert res.message == dict() @patch('abacus_contract.logic.contract_flowthrough.ContractFlowthrough') def test_soft_delete_contract_flowthrough(mock_model): """Test soft deleting contract_flowthrough.""" mock_contract_flowthrough = ContractFlowthroughFactory.create() mock_contract_flowthrough._soft_delete = MagicMock() res = logic.soft_delete_contract_flowthrough(mock_contract_flowthrough) assert res.status == 204 assert res.message is None mock_contract_flowthrough._soft_delete.assert_called_once() mock_model.commit_changes.assert_called_once() @patch('abacus_contract.logic.contract_flowthrough.db') def test_update_contract_flowthrough_rate(mock_db): """Test updating contract_flowthrough rate.""" mock_contract_flowthrough = ContractFlowthroughFactory.create() mock_put_request_body = { 'flowthrough_rate': 2.10 } mock_contract_flowthrough.update_attributes = MagicMock() mock_db.session.commit.return_value = True res = logic.update_contract_flowthrough( mock_contract_flowthrough, **mock_put_request_body ) assert res.status == 200 mock_contract_flowthrough.update_attributes.assert_called_once_with( **mock_put_request_body ) mock_db.session.commit.assert_called_once() @freeze_time(datetime(2025, 3, 3, 0, 0, 0, tzinfo=SYSTEM_TIMEZONE)) @patch('abacus_contract.logic.contract_flowthrough.db') def test_update_contract_flowthrough_status_to_paused(mock_db): """Test updating contract_flowthrough to PAUSED.""" mock_contract_flowthrough = ContractFlowthroughFactory.create() mock_put_request_body = { 'flowthrough_rate': 1.78, 'flowthrough_status': CONTRACT_FLOWTHROUGH_STATUSES.PAUSED, 'has_automatic_shutoff': 0 } mock_contract_flowthrough.update_attributes = MagicMock() mock_db.session.commit.return_value = True res = logic.update_contract_flowthrough( mock_contract_flowthrough, **mock_put_request_body ) assert res.status == 200 mock_contract_flowthrough.update_attributes.assert_called_once_with( **mock_put_request_body, previous_flowthrough_status='active', status_last_modified_by=get_flask_user_id(), status_last_modified=datetime(2025, 3, 3, 0, 0, 0, tzinfo=SYSTEM_TIMEZONE) ) mock_db.session.commit.assert_called_once() @patch('abacus_contract.logic.contract_flowthrough.db') @patch('abacus_contract.logic.contract_flowthrough' '._check_whether_contract_flowthrough_exist') @patch('abacus_contract.logic.contract_flowthrough.ContractFlowthrough') def test_create_contract_flowthrough( mock_contract_flowthrough_model, mock_validation, mock_db ): """Test creating contract_flowthrough.""" mock_contract = ContractFactory.create() mock_contract_flowthrough = ContractFlowthroughFactory.create( contract=mock_contract ) mock_post_request = { 'reference_flowthrough_calculation_id': 2, 'flowthrough_rate': '90.78', 'has_automatic_shutoff': 1, 'recoupment_cap': 908786 } mock_validation.return_value = True mock_contract_flowthrough_model.build.return_value = \ mock_contract_flowthrough mock_db.session.commit.return_value = True res = logic.create_contract_flowthrough( mock_contract.contract_id, **mock_post_request ) assert res.status == 201 mock_contract_flowthrough_model.build.assert_called_once_with( contract_id=mock_contract.contract_id, reference_flowthrough_calculation_id=2, flowthrough_rate='90.78', has_automatic_shutoff=1, recoupment_cap=908786 ) mock_db.session.commit.assert_called_once() @patch('abacus_contract.logic.contract_flowthrough.db') @patch('abacus_contract.logic.contract_flowthrough' '._check_whether_contract_flowthrough_exist') @patch('abacus_contract.logic.contract_flowthrough.ContractFlowthrough') def test_create_contract_flowthrough_validation_error( mock_contract_flowthrough_model, mock_validation, mock_db ): """Test validation error is thrown when creating contract_flowthrough.""" mock_contract = ContractFactory.create() mock_post_request = { 'reference_flowthrough_calculation_id': 2, 'flowthrough_rate': '90.78', 'has_automatic_shutoff': 1, 'recoupment_cap': 908786 } mock_validation.side_effect = ObjectAlreadyExistException('Already Exist') mock_contract_flowthrough_model.build.return_value = False mock_db.session.commit.return_value = False res = logic.create_contract_flowthrough( mock_contract.contract_id, **mock_post_request ) assert res.status == 409 assert res.errors['message'] == 'Already Exist' mock_contract_flowthrough_model.build.assert_not_called() mock_db.session.commit.assert_not_called() @patch('abacus_contract.logic.contract_flowthrough.ContractFlowthrough') def test__check_whether_contract_flowthrough_exist(mock_contract_flowthrough_model): """Test _check_whether_contract_flowthrough_exist function". returns False if the contact_flowthrough is not added to a contract. """ mock_contract = ContractFactory.create() mock_contract_flowthrough_model.get_by_contract_id.return_value = None res = logic._check_whether_contract_flowthrough_exist(mock_contract.contract_id) assert res is False @patch('abacus_contract.logic.contract_flowthrough.ContractFlowthrough') def test__check_whether_contract_flowthrough_exist_error( mock_contract_flowthrough_model ): """Test _check_whether_contract_flowthrough_exist function". throws an error if the contact_flowthrough is added to a contract. """ mock_contract = ContractFactory.create() mock_contract_flowthrough = ContractFlowthroughFactory.create( contract=mock_contract ) mock_contract_flowthrough_model.get_by_contract_id.return_value = \ mock_contract_flowthrough with pytest.raises(ObjectAlreadyExistException) as excinfo: logic._check_whether_contract_flowthrough_exist(mock_contract.contract_id) assert str(excinfo.value) == \ ERROR_CONTRACT_FLOWTHROUGH_ALREADY_EXISTS.format( contract_id=mock_contract.contract_id)