loko/loko/interventions/tests/test_team_members_edit.py

211 lines
10 KiB
Python

from datetime import timedelta
from django.test import TestCase, RequestFactory
from django.contrib.auth import get_user_model
from django.utils import timezone
from common.models import Role, UserConfig, Thematic, UserThematics, UserContractAccess, UserContractStatusPermission
from contracts.models import Company, CompanyTeam, CompanyMember, Contract
from interventions.models import Intervention, STATUS_CHOICES
from interventions.permissions import can_edit_intervention, can_manage_occupations, can_view_intervention, filter_viewable_interventions_for_user
from interventions.views.workflow import attempt_status_update
class TeamMembersEditTests(TestCase):
def setUp(self):
self.User = get_user_model()
self.role_tech, _ = Role.objects.get_or_create(name='technician')
self.company = Company.objects.create(name='Prestataire Test')
self.team1 = CompanyTeam.objects.create(name='Équipe Alpha', company=self.company)
self.team2 = CompanyTeam.objects.create(name='Équipe Bêta', company=self.company)
self.thematic = Thematic.objects.create(code='roads', name_fr='Voirie', name_nl='Wegen')
# Utilisateur Tech A (Membre de l'Équipe Alpha)
self.user_a = self.User.objects.create_user(username='tech_a', password='pwd')
self.config_a = UserConfig.objects.create(user=self.user_a, is_intern=False)
self.config_a.roles.add(self.role_tech)
self.member_a = CompanyMember.objects.create(user=self.user_a, name='Technicien A')
self.member_a.teams.add(self.team1)
# Utilisateur Tech B (Collègue dans l'Équipe Alpha)
self.user_b = self.User.objects.create_user(username='tech_b', password='pwd')
self.config_b = UserConfig.objects.create(user=self.user_b, is_intern=False)
self.config_b.roles.add(self.role_tech)
self.member_b = CompanyMember.objects.create(user=self.user_b, name='Technicien B')
self.member_b.teams.add(self.team1)
# Utilisateur Tech C (Technicien dans une autre équipe: Bêta)
self.user_c = self.User.objects.create_user(username='tech_c', password='pwd')
self.config_c = UserConfig.objects.create(user=self.user_c, is_intern=False)
self.config_c.roles.add(self.role_tech)
self.member_c = CompanyMember.objects.create(user=self.user_c, name='Technicien C')
self.member_c.teams.add(self.team2)
# Contrat avec allow_team_members_edit=False
self.contract_no_team_edit = Contract.objects.create(
company=self.company,
contract_number='C-NO-TEAM-EDIT',
start_date=timezone.now().date() - timedelta(days=10),
end_date=timezone.now().date() + timedelta(days=10),
is_active=True,
allow_team_members_edit=False,
)
self.contract_no_team_edit.thematics.add(self.thematic)
# Contrat avec allow_team_members_edit=True
self.contract_with_team_edit = Contract.objects.create(
company=self.company,
contract_number='C-WITH-TEAM-EDIT',
start_date=timezone.now().date() - timedelta(days=10),
end_date=timezone.now().date() + timedelta(days=10),
is_active=True,
allow_team_members_edit=True,
)
self.contract_with_team_edit.thematics.add(self.thematic)
# Permissions thématiques et contrats pour les 3 techniciens
for cfg in [self.config_a, self.config_b, self.config_c]:
UserThematics.objects.create(
user_config=cfg,
thematic=self.thematic,
can_view_interventions=True,
can_edit_interventions=True,
)
for contract in [self.contract_no_team_edit, self.contract_with_team_edit]:
uca = UserContractAccess.objects.create(
user_config=cfg,
contract=contract,
can_view_interventions=True,
)
for status in ['assigned', 'in_progress', 'on_pause', 'finished', 'to_be_processed']:
UserContractStatusPermission.objects.create(
user_contract=uca,
status=status,
can_view=True,
can_edit=True,
can_change_status_to=True,
)
def test_default_behavior_team_member_cannot_edit_assigned_intervention(self):
"""Si allow_team_members_edit=False, Tech B ne peut pas modifier l'intervention assignée à Tech A."""
intervention = Intervention.objects.create(
title='Intervention Test 1',
thematic=self.thematic,
contract=self.contract_no_team_edit,
assigned_provider=self.company,
assigned_member=self.member_a,
status='assigned',
)
# Tech A peut modifier
self.assertTrue(can_edit_intervention(self.user_a, intervention))
# Tech B (même équipe) ne peut PAS modifier
self.assertFalse(can_edit_intervention(self.user_b, intervention))
# Tentative de passage à 'in_progress' par Tech B
factory = RequestFactory()
request = factory.post(f'/interventions/{intervention.id}/update_status/', {'new_status': 'in_progress'})
request.user = self.user_b
success, msg, _ = attempt_status_update(request, intervention, self.user_b, 'in_progress')
self.assertFalse(success)
self.assertEqual(intervention.status, 'assigned')
def test_allow_team_members_edit_true_allows_colleague_to_edit_and_transition(self):
"""Si allow_team_members_edit=True, Tech B (même équipe) peut modifier et faire avancer l'intervention."""
intervention = Intervention.objects.create(
title='Intervention Test 2',
thematic=self.thematic,
contract=self.contract_with_team_edit,
assigned_provider=self.company,
assigned_member=self.member_a,
status='assigned',
)
# Tech A peut modifier
self.assertTrue(can_edit_intervention(self.user_a, intervention))
# Tech B (même équipe) PEUT modifier
self.assertTrue(can_edit_intervention(self.user_b, intervention))
# Tech B peut passer au statut 'in_progress'
factory = RequestFactory()
request = factory.post(f'/interventions/{intervention.id}/update_status/', {'new_status': 'in_progress'})
request.user = self.user_b
success, msg, _ = attempt_status_update(request, intervention, self.user_b, 'in_progress')
self.assertTrue(success)
intervention.refresh_from_db()
self.assertEqual(intervention.status, 'in_progress')
# Tech B peut toujours éditer lorsque le statut est 'in_progress', 'on_pause', 'finished'
self.assertTrue(can_edit_intervention(self.user_b, intervention))
# Tech B peut mettre en pause
success, msg, _ = attempt_status_update(request, intervention, self.user_b, 'on_pause', pause_reason='order_material')
self.assertTrue(success)
intervention.refresh_from_db()
self.assertEqual(intervention.status, 'on_pause')
self.assertTrue(can_edit_intervention(self.user_b, intervention))
def test_allow_team_members_edit_true_rejects_unrelated_technician(self):
"""Même si allow_team_members_edit=True, un technicien d'une autre équipe (Tech C) ne peut pas modifier."""
intervention = Intervention.objects.create(
title='Intervention Test 3',
thematic=self.thematic,
contract=self.contract_with_team_edit,
assigned_provider=self.company,
assigned_member=self.member_a,
status='assigned',
)
# Tech C (Équipe Bêta, membre_a est dans Équipe Alpha) ne peut PAS modifier
self.assertFalse(can_edit_intervention(self.user_c, intervention))
def test_can_manage_occupations_for_team_colleague(self):
"""Vérifie la gestion des occupations entre collègues d'une même équipe selon le paramètre du contrat."""
# Cas 1 : allow_team_members_edit=False et pas de assigned_team
itv1 = Intervention.objects.create(
title='Intervention Occupations 1',
thematic=self.thematic,
contract=self.contract_no_team_edit,
assigned_provider=self.company,
assigned_member=self.member_a,
status='in_progress',
)
self.assertTrue(can_manage_occupations(self.user_a, itv1))
self.assertFalse(can_manage_occupations(self.user_b, itv1))
# Cas 2 : allow_team_members_edit=True
itv2 = Intervention.objects.create(
title='Intervention Occupations 2',
thematic=self.thematic,
contract=self.contract_with_team_edit,
assigned_provider=self.company,
assigned_member=self.member_a,
status='in_progress',
)
self.assertTrue(can_manage_occupations(self.user_a, itv2))
self.assertTrue(can_manage_occupations(self.user_b, itv2))
self.assertFalse(can_manage_occupations(self.user_c, itv2))
def test_visibility_with_restrict_to_assigned_interventions(self):
"""Vérifie que la restriction aux interventions assignées permet la visibilité aux collègues si allow_team_members_edit=True."""
self.team1.restrict_to_assigned_interventions = True
self.team1.save()
# Intervention sur contrat avec allow_team_members_edit=True
itv = Intervention.objects.create(
title='Intervention Visibilité',
thematic=self.thematic,
contract=self.contract_with_team_edit,
assigned_provider=self.company,
assigned_member=self.member_a,
status='assigned',
)
self.assertTrue(can_view_intervention(self.user_a, itv))
self.assertTrue(can_view_intervention(self.user_b, itv))
self.assertIn(itv, filter_viewable_interventions_for_user(self.user_b))