feat: implement time-restricted intervention visibility and occupation management permissions for teams
This commit is contained in:
parent
86979307ae
commit
a42c46f336
3 changed files with 78 additions and 25 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ---
|
||||
|
|
|
|||
Loading…
Reference in a new issue