|
4 | 4 |
|
5 | 5 | import hope.apps.household.api.serializers.household # noqa: F401, isort: skip - resolve circular import; must load before grievance views |
6 | 6 |
|
| 7 | +from rest_framework.exceptions import PermissionDenied |
| 8 | + |
| 9 | +from extras.test_utils.factories.account import AdminAreaLimitedToFactory, UserFactory |
| 10 | +from extras.test_utils.factories.geo import AreaFactory |
| 11 | +from extras.test_utils.factories.grievance import TicketNeedsAdjudicationDetailsFactory |
| 12 | +from extras.test_utils.factories.household import HouseholdFactory |
7 | 13 | from hope.apps.grievance.api.views import GrievanceTicketGlobalViewSet |
8 | 14 | from hope.apps.grievance.models import GrievanceTicket |
9 | 15 | from hope.apps.grievance.notifications import GrievanceNotification |
| 16 | +from hope.models import Individual, User |
10 | 17 |
|
11 | 18 |
|
12 | 19 | @pytest.fixture |
@@ -46,6 +53,62 @@ def test_validate_preconditions_no_permissions_needed(mock_check_permission, moc |
46 | 53 | mock_check_permission.assert_not_called() |
47 | 54 |
|
48 | 55 |
|
| 56 | +@pytest.fixture |
| 57 | +def adjudication_selected_individual(db) -> Individual: |
| 58 | + area = AreaFactory() |
| 59 | + household = HouseholdFactory(admin2=area) |
| 60 | + # HouseholdFactory creates head_of_household; reuse it so program/admin2 stay consistent. |
| 61 | + return household.head_of_household |
| 62 | + |
| 63 | + |
| 64 | +@pytest.fixture |
| 65 | +def adjudication_user(adjudication_selected_individual: Individual) -> User: |
| 66 | + return UserFactory() |
| 67 | + |
| 68 | + |
| 69 | +@pytest.fixture |
| 70 | +def adjudication_ticket(adjudication_selected_individual: Individual) -> GrievanceTicket: |
| 71 | + details = TicketNeedsAdjudicationDetailsFactory( |
| 72 | + ticket__status=GrievanceTicket.STATUS_FOR_APPROVAL, |
| 73 | + ticket__business_area=adjudication_selected_individual.business_area, |
| 74 | + golden_records_individual=adjudication_selected_individual, |
| 75 | + ) |
| 76 | + details.selected_individuals.add(adjudication_selected_individual) |
| 77 | + return details.ticket |
| 78 | + |
| 79 | + |
| 80 | +@pytest.mark.django_db |
| 81 | +def test_validate_preconditions_close_adjudication_partner_has_access( |
| 82 | + mock_viewset, adjudication_user: User, adjudication_ticket: GrievanceTicket |
| 83 | +) -> None: |
| 84 | + # Partner has no AdminAreaLimitedTo rows → full area access for the program. |
| 85 | + GrievanceTicketGlobalViewSet._validate_status_change_preconditions( |
| 86 | + mock_viewset, adjudication_user, adjudication_ticket, GrievanceTicket.STATUS_CLOSED, [] |
| 87 | + ) |
| 88 | + |
| 89 | + |
| 90 | +@pytest.mark.django_db |
| 91 | +def test_validate_preconditions_close_adjudication_partner_no_access( |
| 92 | + mock_viewset, |
| 93 | + adjudication_user: User, |
| 94 | + adjudication_selected_individual: Individual, |
| 95 | + adjudication_ticket: GrievanceTicket, |
| 96 | +) -> None: |
| 97 | + # Limit the partner to a *different* area in this program → access to the |
| 98 | + # individual's admin2 is denied. |
| 99 | + other_area = AreaFactory() |
| 100 | + AdminAreaLimitedToFactory( |
| 101 | + partner=adjudication_user.partner, |
| 102 | + program=adjudication_selected_individual.program, |
| 103 | + areas=[other_area], |
| 104 | + ) |
| 105 | + |
| 106 | + with pytest.raises(PermissionDenied, match="does not have access to close ticket"): |
| 107 | + GrievanceTicketGlobalViewSet._validate_status_change_preconditions( |
| 108 | + mock_viewset, adjudication_user, adjudication_ticket, GrievanceTicket.STATUS_CLOSED, [] |
| 109 | + ) |
| 110 | + |
| 111 | + |
49 | 112 | @patch("hope.apps.grievance.api.views.clear_cache") |
50 | 113 | def test_build_notifications_no_matching_status(mock_clear_cache, mock_user, mock_ticket, mock_old_ticket): |
51 | 114 | mock_ticket.status = GrievanceTicket.STATUS_IN_PROGRESS |
|
0 commit comments