211 lines
10 KiB
Python
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))
|