fix: prevent forced intervention status transition to to_be_planned during unassignment if unauthorized
This commit is contained in:
parent
aa6c0d0603
commit
6e02156034
2 changed files with 36 additions and 5 deletions
|
|
@ -738,6 +738,31 @@ class ExternalManagerScheduleUpdateTests(TestCase):
|
||||||
self.assertIsNone(self.itv.planned_begin_time)
|
self.assertIsNone(self.itv.planned_begin_time)
|
||||||
self.assertIsNone(self.itv.planned_end_time)
|
self.assertIsNone(self.itv.planned_end_time)
|
||||||
|
|
||||||
|
def test_external_manager_unassign_without_to_be_planned_permission_keeps_current_status(self):
|
||||||
|
# Disable can_change_status_to on to_be_planned
|
||||||
|
UserContractStatusPermission.objects.filter(
|
||||||
|
user_contract=self.uca,
|
||||||
|
status='to_be_planned',
|
||||||
|
).update(can_change_status_to=False)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'intervention_id': self.itv.id,
|
||||||
|
'assigned_member_id': None,
|
||||||
|
'assigned_team_id': None,
|
||||||
|
'unassign': True,
|
||||||
|
}
|
||||||
|
res = self.client.post(self.update_url, data=json.dumps(payload), content_type='application/json')
|
||||||
|
self.assertEqual(res.status_code, 200)
|
||||||
|
self.assertTrue(res.json().get('success'))
|
||||||
|
|
||||||
|
self.itv.refresh_from_db()
|
||||||
|
# Status remains to_be_processed since user cannot transition to to_be_planned
|
||||||
|
self.assertEqual(self.itv.status, 'to_be_processed')
|
||||||
|
self.assertIsNone(self.itv.assigned_member)
|
||||||
|
self.assertIsNone(self.itv.assigned_team)
|
||||||
|
self.assertIsNone(self.itv.planned_begin_time)
|
||||||
|
self.assertIsNone(self.itv.planned_end_time)
|
||||||
|
|
||||||
def test_external_manager_cannot_assign_member_of_different_company(self):
|
def test_external_manager_cannot_assign_member_of_different_company(self):
|
||||||
new_begin = timezone.now() + timedelta(days=1)
|
new_begin = timezone.now() + timedelta(days=1)
|
||||||
new_end = new_begin + timedelta(hours=2)
|
new_end = new_begin + timedelta(hours=2)
|
||||||
|
|
@ -776,7 +801,9 @@ class ExternalManagerScheduleUpdateTests(TestCase):
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
|
|
||||||
itv_assigned.refresh_from_db()
|
itv_assigned.refresh_from_db()
|
||||||
self.assertEqual(itv_assigned.status, 'to_be_planned')
|
# Since 'assigned' -> 'to_be_planned' is not an allowed transition in ALLOWED_TRANSITIONS,
|
||||||
|
# the status remains 'assigned' while unassigning member/team/dates
|
||||||
|
self.assertEqual(itv_assigned.status, 'assigned')
|
||||||
self.assertIsNone(itv_assigned.assigned_member)
|
self.assertIsNone(itv_assigned.assigned_member)
|
||||||
self.assertIsNone(itv_assigned.assigned_team)
|
self.assertIsNone(itv_assigned.assigned_team)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -560,7 +560,7 @@ def _interventions_events_by_members(
|
||||||
planned_begin = getattr(itv, 'planned_begin_time', None)
|
planned_begin = getattr(itv, 'planned_begin_time', None)
|
||||||
return bool(planned_begin and planned_begin > timezone.now())
|
return bool(planned_begin and planned_begin > timezone.now())
|
||||||
|
|
||||||
backlog_allowed_statuses = {'in_preparation', 'to_be_approved', 'to_be_planned', 'to_be_processed'}
|
backlog_allowed_statuses = {'in_preparation', 'to_be_approved', 'to_be_planned', 'to_be_processed', 'assigned'}
|
||||||
PRE_PROCESSING_STATUSES = {'in_preparation', 'to_be_approved', 'to_be_planned'}
|
PRE_PROCESSING_STATUSES = {'in_preparation', 'to_be_approved', 'to_be_planned'}
|
||||||
backlog_allowed_types = {'corrective', 'preventive', 'ameliorative'}
|
backlog_allowed_types = {'corrective', 'preventive', 'ameliorative'}
|
||||||
maintain_type_labels = dict(MAINTAIN_CHOICES)
|
maintain_type_labels = dict(MAINTAIN_CHOICES)
|
||||||
|
|
@ -1010,7 +1010,7 @@ def _interventions_events_by_teams_daily(
|
||||||
})
|
})
|
||||||
|
|
||||||
# Compute backlog groups for the assignment sidebar
|
# Compute backlog groups for the assignment sidebar
|
||||||
backlog_allowed_statuses = {'in_preparation', 'to_be_approved', 'to_be_planned', 'to_be_processed'}
|
backlog_allowed_statuses = {'in_preparation', 'to_be_approved', 'to_be_planned', 'to_be_processed', 'assigned'}
|
||||||
backlog_allowed_types = {'corrective', 'preventive', 'ameliorative'}
|
backlog_allowed_types = {'corrective', 'preventive', 'ameliorative'}
|
||||||
maintain_type_labels = dict(MAINTAIN_CHOICES)
|
maintain_type_labels = dict(MAINTAIN_CHOICES)
|
||||||
contract_filter = None if allowed_contract_ids is None else set(allowed_contract_ids)
|
contract_filter = None if allowed_contract_ids is None else set(allowed_contract_ids)
|
||||||
|
|
@ -1293,9 +1293,13 @@ def interventions_schedule_update(request):
|
||||||
# If intervention was "to_be_planned" and is now assigned -> change to "to_be_processed"
|
# If intervention was "to_be_planned" and is now assigned -> change to "to_be_processed"
|
||||||
if prev_status == 'to_be_planned' and is_now_assigned:
|
if prev_status == 'to_be_planned' and is_now_assigned:
|
||||||
new_status = 'to_be_processed'
|
new_status = 'to_be_processed'
|
||||||
# If intervention is being unassigned (back to backlog) -> change to "to_be_planned"
|
# If intervention is being unassigned (back to backlog) -> change to "to_be_planned" only if user has transition rights
|
||||||
elif is_unassigning and prev_status in ('to_be_processed', 'assigned'):
|
elif is_unassigning and prev_status in ('to_be_processed', 'assigned'):
|
||||||
|
allowed_transitions = user_allowed_transitions(request.user, prev_status, intervention=intervention)
|
||||||
|
if 'to_be_planned' in allowed_transitions or is_admin:
|
||||||
new_status = 'to_be_planned'
|
new_status = 'to_be_planned'
|
||||||
|
else:
|
||||||
|
new_status = prev_status
|
||||||
|
|
||||||
if new_status != prev_status:
|
if new_status != prev_status:
|
||||||
intervention.status = new_status
|
intervention.status = new_status
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue