fix(interventions): resolve UnboundLocalError contracts_qs for external managers
This commit is contained in:
parent
927c049d02
commit
8df84704dc
2 changed files with 99 additions and 21 deletions
|
|
@ -2195,6 +2195,77 @@ class InterventionRolePersonFilteringTests(TestCase):
|
||||||
self.assertIn(self.itv_type_inspection.id, itv_ids_insp)
|
self.assertIn(self.itv_type_inspection.id, itv_ids_insp)
|
||||||
self.assertNotIn(self.itv_controller.id, itv_ids_insp)
|
self.assertNotIn(self.itv_controller.id, itv_ids_insp)
|
||||||
|
|
||||||
|
def test_interventions_index_external_manager(self):
|
||||||
|
"""Verify that an external manager (is_intern=False) can access interventions index without 500 error."""
|
||||||
|
ext_manager = self.User.objects.create_user(
|
||||||
|
username='ext_manager_test_user',
|
||||||
|
password='pwd',
|
||||||
|
first_name='Eric',
|
||||||
|
last_name='Gestionnaire'
|
||||||
|
)
|
||||||
|
role_ext_mgr, _ = Role.objects.get_or_create(name='external_manager')
|
||||||
|
ext_config = UserConfig.objects.create(user=ext_manager, is_intern=False)
|
||||||
|
ext_config.roles.add(role_ext_mgr)
|
||||||
|
UserThematics.objects.create(
|
||||||
|
user_config=ext_config,
|
||||||
|
thematic=self.thematic,
|
||||||
|
can_view_interventions=True,
|
||||||
|
can_edit_interventions=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a contract accessible to this external manager
|
||||||
|
from datetime import date, timedelta
|
||||||
|
contract = Contract.objects.create(
|
||||||
|
contract_number='CONT-EXT-01',
|
||||||
|
company=self.company,
|
||||||
|
start_date=date.today(),
|
||||||
|
end_date=date.today() + timedelta(days=365),
|
||||||
|
uses_intervention_manager=True
|
||||||
|
)
|
||||||
|
contract.thematics.add(self.thematic)
|
||||||
|
from common.models import UserContractAccess
|
||||||
|
UserContractAccess.objects.create(
|
||||||
|
user_config=ext_config,
|
||||||
|
contract=contract,
|
||||||
|
can_view_interventions=True,
|
||||||
|
can_approve=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.client.login(username='ext_manager_test_user', password='pwd')
|
||||||
|
url = reverse('interventions:interventions_index')
|
||||||
|
resp = self.client.get(url, follow=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn('role_persons_data', resp.context)
|
||||||
|
role_data = resp.context['role_persons_data']
|
||||||
|
self.assertIn('manager', role_data)
|
||||||
|
self.assertIn('controller', role_data)
|
||||||
|
self.assertIn('inspector', role_data)
|
||||||
|
manager_ids = [m['id'] for m in role_data['manager']]
|
||||||
|
self.assertIn(ext_manager.id, manager_ids)
|
||||||
|
|
||||||
|
def test_interventions_index_non_intern_user_without_contracts(self):
|
||||||
|
"""Verify that a non-intern user without any contracts can access interventions index without 500 error."""
|
||||||
|
ext_user = self.User.objects.create_user(
|
||||||
|
username='ext_simple_user',
|
||||||
|
password='pwd'
|
||||||
|
)
|
||||||
|
role_technician, _ = Role.objects.get_or_create(name='technician')
|
||||||
|
ext_config = UserConfig.objects.create(user=ext_user, is_intern=False)
|
||||||
|
ext_config.roles.add(role_technician)
|
||||||
|
UserThematics.objects.create(
|
||||||
|
user_config=ext_config,
|
||||||
|
thematic=self.thematic,
|
||||||
|
can_view_interventions=True,
|
||||||
|
can_edit_interventions=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.client.login(username='ext_simple_user', password='pwd')
|
||||||
|
url = reverse('interventions:interventions_index')
|
||||||
|
resp = self.client.get(url, follow=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn('role_persons_data', resp.context)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -239,10 +239,10 @@ def index(request):
|
||||||
key=lambda t: (t[3] if t[3] is not None else t[0], 1 if t[3] is not None else 0, t[1])
|
key=lambda t: (t[3] if t[3] is not None else t[0], 1 if t[3] is not None else 0, t[1])
|
||||||
)
|
)
|
||||||
|
|
||||||
# Providers and contracts (intern users only)
|
from django.contrib.auth import get_user_model
|
||||||
provider_choices = []
|
User = get_user_model()
|
||||||
contract_choices = []
|
|
||||||
if user_config.is_intern:
|
# Providers and contracts
|
||||||
is_admin = user_config.roles.filter(name='admin').exists() or request.user.is_superuser
|
is_admin = user_config.roles.filter(name='admin').exists() or request.user.is_superuser
|
||||||
contracts_qs = Contract.objects.select_related('company').prefetch_related('thematics')
|
contracts_qs = Contract.objects.select_related('company').prefetch_related('thematics')
|
||||||
if not is_admin:
|
if not is_admin:
|
||||||
|
|
@ -255,9 +255,10 @@ def index(request):
|
||||||
contracts_qs = contracts_qs.filter(thematics__code__in=authorized_thematic_codes)
|
contracts_qs = contracts_qs.filter(thematics__code__in=authorized_thematic_codes)
|
||||||
contracts_qs = contracts_qs.filter(id__in=accessible_contract_ids).distinct()
|
contracts_qs = contracts_qs.filter(id__in=accessible_contract_ids).distinct()
|
||||||
|
|
||||||
|
provider_choices = []
|
||||||
|
contract_choices = []
|
||||||
|
if user_config.is_intern:
|
||||||
# Build contract choices with thematic codes
|
# Build contract choices with thematic codes
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
User = get_user_model()
|
|
||||||
for contract in contracts_qs:
|
for contract in contracts_qs:
|
||||||
thematic_codes = list(contract.thematics.values_list('code', flat=True))
|
thematic_codes = list(contract.thematics.values_list('code', flat=True))
|
||||||
managers_qs = User.objects.filter(
|
managers_qs = User.objects.filter(
|
||||||
|
|
@ -359,18 +360,24 @@ def index(request):
|
||||||
# Build role-persons data (Gestionnaire / Contrôleur / Inspecteur)
|
# Build role-persons data (Gestionnaire / Contrôleur / Inspecteur)
|
||||||
# 1. Managers
|
# 1. Managers
|
||||||
user_access_map = defaultdict(set)
|
user_access_map = defaultdict(set)
|
||||||
for uca in UserContractAccess.objects.filter(contract__in=contracts_qs, can_approve=True):
|
for uca in UserContractAccess.objects.filter(
|
||||||
|
Q(contract__in=contracts_qs) & (Q(can_approve=True) | Q(user_config__roles__name__in=['manager', 'external_manager']))
|
||||||
|
):
|
||||||
user_access_map[uca.user_config.user_id].add(uca.contract_id)
|
user_access_map[uca.user_config.user_id].add(uca.contract_id)
|
||||||
managed_itv_map = defaultdict(set)
|
managed_itv_map = defaultdict(set)
|
||||||
for itv_data in Intervention.objects.filter(contract__in=contracts_qs, intervention_manager__isnull=False).values('intervention_manager_id', 'contract_id').distinct():
|
for itv_data in Intervention.objects.filter(contract__in=contracts_qs, intervention_manager__isnull=False).values('intervention_manager_id', 'contract_id').distinct():
|
||||||
managed_itv_map[itv_data['intervention_manager_id']].add(itv_data['contract_id'])
|
managed_itv_map[itv_data['intervention_manager_id']].add(itv_data['contract_id'])
|
||||||
|
|
||||||
manager_users_qs = (
|
manager_q = (
|
||||||
User.objects.filter(
|
|
||||||
Q(config__usercontractaccess__contract__in=contracts_qs, config__usercontractaccess__can_approve=True) |
|
Q(config__usercontractaccess__contract__in=contracts_qs, config__usercontractaccess__can_approve=True) |
|
||||||
Q(managed_interventions__contract__in=contracts_qs) |
|
Q(config__usercontractaccess__contract__in=contracts_qs, config__roles__name__in=['manager', 'external_manager']) |
|
||||||
Q(config__roles__name='manager')
|
Q(managed_interventions__contract__in=contracts_qs)
|
||||||
)
|
)
|
||||||
|
if user_config.is_intern:
|
||||||
|
manager_q |= Q(config__roles__name='manager')
|
||||||
|
|
||||||
|
manager_users_qs = (
|
||||||
|
User.objects.filter(manager_q)
|
||||||
.prefetch_related('companymember_set__teams', 'config__company')
|
.prefetch_related('companymember_set__teams', 'config__company')
|
||||||
.distinct()
|
.distinct()
|
||||||
.order_by('first_name', 'last_name', 'username')
|
.order_by('first_name', 'last_name', 'username')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue