"""Test statement period logic.""" from unittest.mock import MagicMock, patch import pytest from royalties.constants import error from royalties.constants.constants import STATEMENT_PERIOD_STATUSES from royalties.logic import statement_period as logic from royalties.tests.utils.factories import ( StatementPeriodFactory, StatementPeriodPaymentEntityFactory, ) test_statement_period_name = '2025-01' @patch('royalties.logic.statement_period.models') def test_get_recent_statement_periods(mock_models): """Test the logic for getting recent statement periods.""" result = logic.get_recent_statement_periods() mock_models.StatementPeriod.get_recent_periods.assert_called_once() assert result.status == 200 @patch('royalties.logic.statement_period.models') def test_get_upcoming_statement_periods(mock_models): """Test the logic for getting upcoming statement periods.""" result = logic.get_upcoming_statement_periods() mock_models.StatementPeriod.get_upcoming_periods.assert_called_once() assert result.status == 200 @patch('royalties.logic.statement_period.models') def test_get_current_statement_period(mock_models): """Test the logic for getting the current statement period.""" result = logic.get_current_statement_period() mock_models.StatementPeriod.get_current_statement_period.assert_called_once() assert result.status == 200 @patch('royalties.logic.statement_period._validate_statement_period_can_close') @patch('royalties.logic.statement_period.models') @patch('royalties.logic.statement_period.close_bulk_dp_collaborator_statements') def test_close_statement_period(mock_close_bulk, mock_models, mock_validation): """Test the logic for closing current statement period.""" current_period = MagicMock( statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT, statement_period_name=test_statement_period_name, ) next_period = MagicMock( statement_period_status=STATEMENT_PERIOD_STATUSES.OPEN, statement_period_id=2 ) mock_validation.return_value = (current_period, next_period) mock_close_bulk.return_value = {} result = logic.close_statement_period(1) mock_validation.assert_called_with(1) mock_close_bulk.assert_called_with( test_statement_period_name, next_period.statement_period_id ) current_period.close_period.assert_called_once() next_period.update_attributes.assert_called_with( statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT ) mock_models.StatementPeriod.commit_changes.assert_called_once() assert result.status == 201 @patch('royalties.logic.statement_period._validate_statement_period_can_close') @patch('royalties.logic.statement_period.models') @patch('royalties.logic.statement_period.close_bulk_dp_collaborator_statements') def test_close_statement_period_bulk_close_failed( mock_close_bulk, mock_models, mock_validation ): """Test the logic for closing current statement period.""" current_period = MagicMock( statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT, statement_period_name=test_statement_period_name, ) next_period = MagicMock( statement_period_status=STATEMENT_PERIOD_STATUSES.OPEN, statement_period_id=2 ) mock_validation.return_value = (current_period, next_period) mock_close_bulk.side_effect = Exception(error.ERROR_STATEMENT_PERIOD_COLLABORATORS) result = logic.close_statement_period(1) mock_validation.assert_called_with(1) mock_close_bulk.assert_called_with( test_statement_period_name, next_period.statement_period_id ) current_period.close_period.assert_not_called() next_period.update_attributes.assert_not_called() mock_models.StatementPeriod.commit_changes.assert_not_called() assert result.status == 400 assert result.errors['message'] == error.ERROR_STATEMENT_PERIOD_COLLABORATORS @patch('royalties.logic.statement_period.models') @patch('royalties.logic.statement_period.close_bulk_dp_collaborator_statements') def test_close_statement_period_not_current_period_error(mock_close_bulk, mock_models): """Test the logic to show error if specified period is not current one.""" current_period = MagicMock(statement_period_status=STATEMENT_PERIOD_STATUSES.CLOSED) mock_close_bulk.return_value = {} mock_models.StatementPeriod.get_by_id_or_error.return_value = current_period result = logic.close_statement_period(1) assert result.status == 400 assert result.errors['message'] == error.ERROR_STATEMENT_PERIOD_CURRENT_STATUS mock_close_bulk.assert_not_called() @patch('royalties.logic.statement_period.models') @patch('royalties.logic.statement_period.close_bulk_dp_collaborator_statements') def test_close_statement_period_has_active_acc_period_error( mock_close_bulk, mock_models ): """Test the logic to show error if there active acc periods.""" current_period = MagicMock( statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT, statement_period_name=test_statement_period_name, ) mock_models.StatementPeriod.get_by_id_or_error.return_value = current_period mock_close_bulk.return_value = {} mock_models.StatementPeriod.has_active_accounting_periods.return_value = True result = logic.close_statement_period(1) assert result.status == 400 assert result.errors['message'] == error.ERROR_STATEMENT_PERIOD_HAS_ACC_PERIODS mock_close_bulk.assert_not_called() @patch('royalties.logic.statement_period.models') def test_validate_statement_period_state(mock_models): """Test _validate_statement_period state.""" mock_statement_period = StatementPeriodFactory.create( statement_period_status=STATEMENT_PERIOD_STATUSES.OPEN ) with pytest.raises(Exception, match=error.ERROR_NO_CURRENT_STATEMENT_PERIOD): mock_models.StatementPeriod.get_by_id_or_error.return_value = ( mock_statement_period ) logic._validate_statement_period_state( mock_statement_period.statement_period_id ) @patch('royalties.logic.statement_period.models') def test_get_statement_period_exchange_rates(mock_models): """Test get_statement_period_exchange_rates method.""" mock_statement_period = MagicMock() mock_models.StatementPeriod.get_by_id_or_error.return_value = mock_statement_period result = logic.get_statement_period_exchange_rates(mock_statement_period, 'json') mock_statement_period.stream_all_fx_rates.assert_called_once() assert result.status == 200 @patch('royalties.logic.statement_period.models') def test_validate_statement_period_can_close_error_not_closed_balances( mock_models, reference_payment_entity_fixtures ): """Test _validate_statement_period_can_close logic with not closed balances.""" current_period = MagicMock( statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT, all_balances_closed=False, ) statement_period_payment_entity = StatementPeriodPaymentEntityFactory.create( reference_payment_entity_id=1, statement_period_id=current_period.statement_period_id, is_visible_to_customer=True, ) next_period = MagicMock(statement_period_status=STATEMENT_PERIOD_STATUSES.OPEN) mock_models.StatementPeriod.get_by_id_or_error.return_value = current_period mock_models.StatementPeriod.get_by_id.return_value = next_period current_period.has_active_accounting_periods.return_value = False current_period.statement_period_payment_entities = [statement_period_payment_entity] with pytest.raises(Exception) as excinfo: logic._validate_statement_period_can_close(1) assert str(excinfo.value) == error.ERROR_BALANCES_ARE_NOT_CLOSED @patch('royalties.logic.statement_period.models') def test_validate_close_period_not_current_period_error(mock_models): """Test _validate_statement_period_can_close logic. if specified period is not current one. """ current_period = MagicMock(statement_period_status=STATEMENT_PERIOD_STATUSES.CLOSED) mock_models.StatementPeriod.get_by_id_or_error.return_value = current_period with pytest.raises(Exception, match=error.ERROR_STATEMENT_PERIOD_CURRENT_STATUS): logic._validate_statement_period_can_close(1) @patch('royalties.logic.statement_period.models') def test_validate_close_period_has_active_acc_period_error(mock_models): """Test _validate_statement_period_can_close logic if there active acc periods.""" current_period = MagicMock( statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT ) mock_models.StatementPeriod.get_by_id_or_error.return_value = current_period current_period.has_active_accounting_periods.return_value = True with pytest.raises(Exception, match=error.ERROR_STATEMENT_PERIOD_HAS_ACC_PERIODS): logic._validate_statement_period_can_close(1) @patch('royalties.logic.statement_period.models') def test_validate_close_period_payment_entity_error( mock_models, reference_payment_entity_fixtures ): """Test _validate_statement_period_can_close logic. if payment entity doesn't have is_visible_to_customer field set to true. """ current_period = MagicMock( statement_period_status=STATEMENT_PERIOD_STATUSES.CURRENT ) statement_period_payment_entity = StatementPeriodPaymentEntityFactory.create( reference_payment_entity_id=1, statement_period_id=current_period.statement_period_id, is_visible_to_customer=False, ) mock_models.StatementPeriod.get_by_id_or_error.return_value = current_period current_period.has_active_accounting_periods.return_value = False current_period.statement_period_payment_entities = [statement_period_payment_entity] with pytest.raises(Exception, match=error.ERROR_STATEMENT_PERIOD_PAYMENT_ENTITY): logic._validate_statement_period_can_close(1) @patch('royalties.logic.statement_period.models') def test_get_statement_periods_by_ids(mock_models): """Test getting statement periods by IDs.""" statement_periods = StatementPeriodFactory.create_batch(4) statement_period_ids = [sp.statement_period_id for sp in statement_periods] mock_models.StatementPeriod.get_by_ids.return_value = statement_periods response = logic.get_statement_periods_by_ids(statement_period_ids) assert response.status == 200 assert len(response.message) == len(statement_periods) mock_models.StatementPeriod.get_by_ids.assert_called_once_with(statement_period_ids) @patch('royalties.logic.statement_period.models') def test_get_statement_periods_by_years(mock_models): """Test get_statement_periods_by_years logic.""" statement_periods = StatementPeriodFactory.create_batch(4) statement_years = [sp.statement_year for sp in statement_periods] mock_models.StatementPeriod.get_by_statement_years.return_value = statement_periods response = logic.get_statement_periods_by_years(statement_years) assert response.status == 200 assert len(response.message) == len(statement_periods) mock_models.StatementPeriod.get_by_statement_years.assert_called_once_with( statement_years )