diff --git a/loko/interventions/permissions.py b/loko/interventions/permissions.py index a00bcd5..887b1df 100644 --- a/loko/interventions/permissions.py +++ b/loko/interventions/permissions.py @@ -253,17 +253,15 @@ def can_view_intervention(user, intervention): return False # 2. Restriction aux interventions assignées - assigned_only_teams = company_member.teams.filter(restrict_to_assigned_interventions=True) - if assigned_only_teams.exists(): - unrestricted_teams = company_member.teams.filter(restrict_to_assigned_interventions=False) - unrestricted_companies = set(unrestricted_teams.values_list('company_id', flat=True)) - - is_assigned_to_user = (intervention.assigned_member == company_member) - is_assigned_to_user_team = (intervention.assigned_team in company_member.teams.all()) - is_unrestricted_company = (intervention.assigned_provider_id in unrestricted_companies) - - if not (is_assigned_to_user or is_assigned_to_user_team or is_unrestricted_company): - return False + unrestricted_teams = company_member.teams.filter(restrict_to_assigned_interventions=False) + unrestricted_companies = set(unrestricted_teams.values_list('company_id', flat=True)) + + is_assigned_to_user = (intervention.assigned_member == company_member) + is_assigned_to_user_team = (intervention.assigned_team in company_member.teams.all()) + is_unrestricted_company = (intervention.assigned_provider_id in unrestricted_companies) + + if not (is_assigned_to_user or is_assigned_to_user_team or is_unrestricted_company): + return False contract = intervention.contract thematic = intervention.thematic @@ -510,11 +508,12 @@ def get_accessible_interventions_for_technician(user): company_member = CompanyMember.objects.prefetch_related('teams__company', 'visible_maintain_types').filter(user=user).first() if company_member: - user_companies = company_member.teams.values_list('company_id', flat=True).distinct() + unrestricted_teams = company_member.teams.filter(restrict_to_assigned_interventions=False) + unrestricted_companies = unrestricted_teams.values_list('company_id', flat=True).distinct() qs = base_qs.filter( Q(assigned_member__user=user) | Q(assigned_team__in=company_member.teams.all(), status__in=['to_be_processed', 'assigned']) | - Q(assigned_member__isnull=True, assigned_team__isnull=True, assigned_provider_id__in=user_companies, status__in=['to_be_processed', 'assigned']) + Q(assigned_member__isnull=True, assigned_team__isnull=True, assigned_provider_id__in=unrestricted_companies, status__in=['to_be_processed', 'assigned']) ) # Appliquer le filtre des types de maintenance visibles (sauf pour les interventions assignées) visible_types = company_member.get_visible_maintain_type_codes() @@ -677,8 +676,7 @@ def filter_viewable_interventions_for_user(user, limit_to_default_thematic=False user_roles = set(user_config.roles.values_list('name', flat=True)) if user_config else set() privileged_roles = {'admin', 'top_manager', 'manager', 'controller', 'operator', 'external_manager'} - restricted_teams = company_member.teams.filter(restrict_to_assigned_interventions=True) - if restricted_teams.exists() and not (user_roles & privileged_roles): + if not (user_roles & privileged_roles): unrestricted_teams = company_member.teams.filter(restrict_to_assigned_interventions=False) unrestricted_companies = list(unrestricted_teams.values_list('company_id', flat=True).distinct()) @@ -720,15 +718,13 @@ def filter_viewable_interventions_for_user(user, limit_to_default_thematic=False privileged_roles = {'admin', 'top_manager', 'manager', 'controller', 'operator', 'external_manager'} if not (user_roles & privileged_roles): # 1. Restriction aux interventions assignées par équipe - assigned_only_teams = company_member.teams.filter(restrict_to_assigned_interventions=True) - if assigned_only_teams.exists(): - unrestricted_teams = company_member.teams.filter(restrict_to_assigned_interventions=False) - unrestricted_companies = list(unrestricted_teams.values_list('company_id', flat=True).distinct()) - - assign_filter = Q(assigned_member=company_member) | Q(assigned_team__in=list(company_member.teams.all())) - if unrestricted_companies: - assign_filter |= Q(assigned_provider_id__in=unrestricted_companies) - qs = qs.filter(assign_filter) + unrestricted_teams = company_member.teams.filter(restrict_to_assigned_interventions=False) + unrestricted_companies = list(unrestricted_teams.values_list('company_id', flat=True).distinct()) + + assign_filter = Q(assigned_member=company_member) | Q(assigned_team__in=list(company_member.teams.all())) + if unrestricted_companies: + assign_filter |= Q(assigned_provider_id__in=unrestricted_companies) + qs = qs.filter(assign_filter) # 2. Restriction de visibilité quotidienne par équipe restricted_teams = company_member.teams.filter(restrict_today_interventions_visibility=True) diff --git a/loko/interventions/tests/test_visibility_permissions.py b/loko/interventions/tests/test_visibility_permissions.py index d3eae01..47d474b 100644 --- a/loko/interventions/tests/test_visibility_permissions.py +++ b/loko/interventions/tests/test_visibility_permissions.py @@ -386,6 +386,63 @@ class TeamAssignedOnlyVisibilityTests(TestCase): visible_qs = filter_viewable_interventions_for_user(self.tech_user) self.assertIn(itv_unassigned, visible_qs) + def test_visibility_no_teams_assigned(self): + from interventions.models import Intervention + from interventions.permissions import can_view_intervention, filter_viewable_interventions_for_user + + # Member belongs to NO team (self.member.teams is empty) + self.member.teams.clear() + + # 1. Assigned to team + itv_team = Intervention.objects.create( + title='Team Task', + status='to_be_processed', + contract=self.contract, + thematic=self.thematic, + assigned_provider=self.company, + assigned_team=self.team_restricted, + ) + # 2. Assigned to member + itv_member = Intervention.objects.create( + title='Member Task', + status='to_be_processed', + contract=self.contract, + thematic=self.thematic, + assigned_provider=self.company, + assigned_member=self.member, + ) + # 3. Unassigned company task + itv_unassigned = Intervention.objects.create( + title='Unassigned Task', + status='to_be_processed', + contract=self.contract, + thematic=self.thematic, + assigned_provider=self.company, + ) + # 4. Assigned to other team + itv_other = Intervention.objects.create( + title='Other Team Task', + status='to_be_processed', + contract=self.contract, + thematic=self.thematic, + assigned_provider=self.company, + assigned_team=self.other_team, + ) + + # Check individual visibility: only directly assigned task is visible + self.assertFalse(can_view_intervention(self.tech_user, itv_team)) + self.assertTrue(can_view_intervention(self.tech_user, itv_member)) + self.assertFalse(can_view_intervention(self.tech_user, itv_unassigned)) + self.assertFalse(can_view_intervention(self.tech_user, itv_other)) + + # Check list visibility: only directly assigned task is visible + visible_qs = filter_viewable_interventions_for_user(self.tech_user) + self.assertEqual(visible_qs.count(), 1) + self.assertIn(itv_member, visible_qs) + self.assertNotIn(itv_team, visible_qs) + self.assertNotIn(itv_unassigned, visible_qs) + self.assertNotIn(itv_other, visible_qs) + def test_is_restricted_team_context(self): from interventions.models import Intervention from django.urls import reverse diff --git a/loko/interventions/views/mobile.py b/loko/interventions/views/mobile.py index 0215429..7994948 100644 --- a/loko/interventions/views/mobile.py +++ b/loko/interventions/views/mobile.py @@ -829,7 +829,7 @@ def intervention_detail_mobile(request, intervention_id): privileged_roles = {'admin', 'top_manager', 'manager', 'controller', 'operator', 'external_manager'} if not (user_roles & privileged_roles): matching_teams = company_member.teams.filter(company=intervention.assigned_provider) - if matching_teams.exists() and not matching_teams.filter(restrict_to_assigned_interventions=False).exists(): + if not matching_teams.filter(restrict_to_assigned_interventions=False).exists(): is_restricted_team = True # --- Timeline mobile : transitions, statuts, rôles ---