feat: add approval exception for urgent contract interventions and update status transition permissions
This commit is contained in:
parent
676e781943
commit
8fc2798c52
6 changed files with 351 additions and 20 deletions
|
|
@ -154,7 +154,7 @@ class ContractAdmin(admin.ModelAdmin):
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
('Options de workflow', {
|
('Options de workflow', {
|
||||||
'fields': ('needs_approval', 'needs_checking', 'uses_occupations', 'occupations_required', 'uses_intervention_manager', 'warn_if_no_prestation_on_processed', 'allow_team_members_edit'),
|
'fields': ('needs_approval', 'approval_except_urgent', 'needs_checking', 'uses_occupations', 'occupations_required', 'uses_intervention_manager', 'warn_if_no_prestation_on_processed', 'allow_team_members_edit'),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 6.0.7 on 2026-09-17 12:19
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0006_usercompanyteamaccess_can_tag'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='contract',
|
||||||
|
name='approval_except_urgent',
|
||||||
|
field=models.BooleanField(default=True, help_text="Indique si la nécessité d'approbation est levée pour les interventions à priorité urgente.", verbose_name='Sauf si urgence'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -350,6 +350,11 @@ class Contract(models.Model):
|
||||||
verbose_name=_("Nécessite une approbation"),
|
verbose_name=_("Nécessite une approbation"),
|
||||||
help_text=_("Indique si les interventions liées à ce contrat nécessitent une approbation avant d'être transmises pour traitement."),
|
help_text=_("Indique si les interventions liées à ce contrat nécessitent une approbation avant d'être transmises pour traitement."),
|
||||||
)
|
)
|
||||||
|
approval_except_urgent = models.BooleanField(
|
||||||
|
default=True,
|
||||||
|
verbose_name=_("Sauf si urgence"),
|
||||||
|
help_text=_("Indique si la nécessité d'approbation est levée pour les interventions à priorité urgente."),
|
||||||
|
)
|
||||||
needs_checking = models.BooleanField(
|
needs_checking = models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
verbose_name=_("Nécessite une vérification"),
|
verbose_name=_("Nécessite une vérification"),
|
||||||
|
|
|
||||||
|
|
@ -1322,6 +1322,71 @@ def can_approve_intervention(user, intervention):
|
||||||
).exists()
|
).exists()
|
||||||
|
|
||||||
|
|
||||||
|
def intervention_requires_approval(intervention):
|
||||||
|
"""
|
||||||
|
Détermine si une intervention liée à un contrat nécessite une approbation avant traitement.
|
||||||
|
Si le contrat a needs_approval=True :
|
||||||
|
- Si le contrat a approval_except_urgent=True et que l'intervention est urgente (priority='1'),
|
||||||
|
l'approbation n'est pas requise.
|
||||||
|
- Sinon, l'approbation est requise (y compris en cas d'urgence si approval_except_urgent=False).
|
||||||
|
"""
|
||||||
|
if not intervention or not intervention.contract_id:
|
||||||
|
return False
|
||||||
|
|
||||||
|
contract = getattr(intervention, 'contract', None)
|
||||||
|
if not contract or not getattr(contract, 'needs_approval', False):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Si le contrat prévoit 'sauf si urgence' et que l'intervention est urgente
|
||||||
|
if getattr(contract, 'approval_except_urgent', False) and getattr(intervention, 'priority', None) == '1':
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def user_has_explicit_contract_status_permission(user, contract_id, target_status='to_be_processed'):
|
||||||
|
"""
|
||||||
|
Vérifie si l'utilisateur a explicitement le droit de passer à ce statut sur ce contrat
|
||||||
|
via ses permissions de statut de contrat (UserContractStatusPermission.can_change_status_to).
|
||||||
|
Les administrateurs et superutilisateurs ont tous les droits.
|
||||||
|
Rétrocompatibilité : can_approve=True sur UserContractAccess confère le droit vers 'to_be_processed'.
|
||||||
|
"""
|
||||||
|
if not contract_id or not user or not user.is_authenticated:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if getattr(user, 'is_superuser', False):
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_config = UserConfig.objects.get(user=user)
|
||||||
|
except UserConfig.DoesNotExist:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if user_config.roles.filter(name='admin').exists():
|
||||||
|
return True
|
||||||
|
|
||||||
|
uca = UserContractAccess.objects.filter(
|
||||||
|
user_config=user_config,
|
||||||
|
contract_id=contract_id,
|
||||||
|
).first()
|
||||||
|
if not uca:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Permission explicite par statut sur le contrat
|
||||||
|
if UserContractStatusPermission.objects.filter(
|
||||||
|
user_contract=uca,
|
||||||
|
status=target_status,
|
||||||
|
can_change_status_to=True,
|
||||||
|
).exists():
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Rétrocompatibilité avec le flag can_approve
|
||||||
|
if target_status == 'to_be_processed' and uca.can_approve:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_allowed_transitions(request, intervention):
|
def get_allowed_transitions(request, intervention):
|
||||||
current_status = intervention.status
|
current_status = intervention.status
|
||||||
next_candidates = user_allowed_transitions(request.user, current_status, intervention=intervention)
|
next_candidates = user_allowed_transitions(request.user, current_status, intervention=intervention)
|
||||||
|
|
@ -1337,25 +1402,12 @@ def get_allowed_transitions(request, intervention):
|
||||||
if not can_approve_intervention(request.user, intervention):
|
if not can_approve_intervention(request.user, intervention):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Si l'intervention est en préparation, que le contrat exige une approbation,
|
# Si l'intervention est en préparation et nécessite une approbation :
|
||||||
# que la priorité n'est pas urgente, et que l'utilisateur est opérateur,
|
# seuls les utilisateurs ayant explicitement le droit de passer au statut 'à traiter'
|
||||||
# alors seul le passage à 'to_be_approved' est autorisé.
|
# sur ce contrat peuvent faire passer dans ce statut directement.
|
||||||
if (
|
# Pour les autres, seul le passage à 'to_be_approved' (ou 'canceled') est autorisé.
|
||||||
current_status == 'in_preparation'
|
if current_status == 'in_preparation' and intervention_requires_approval(intervention):
|
||||||
and intervention.contract_id
|
if not user_has_explicit_contract_status_permission(request.user, intervention.contract_id, 'to_be_processed'):
|
||||||
and getattr(intervention.contract, 'needs_approval', False)
|
|
||||||
and intervention.priority != '1'
|
|
||||||
):
|
|
||||||
try:
|
|
||||||
user_config = UserConfig.objects.get(user=request.user)
|
|
||||||
is_operator = user_config.roles.filter(name='operator').exists()
|
|
||||||
is_only_operator = is_operator and not user_config.roles.filter(
|
|
||||||
name__in=['admin', 'manager', 'controller', 'external_manager']
|
|
||||||
).exists()
|
|
||||||
except UserConfig.DoesNotExist:
|
|
||||||
is_only_operator = False
|
|
||||||
|
|
||||||
if is_only_operator:
|
|
||||||
next_candidates = [s for s in next_candidates if s in ('to_be_approved', 'canceled')]
|
next_candidates = [s for s in next_candidates if s in ('to_be_approved', 'canceled')]
|
||||||
|
|
||||||
# Un external_manager (sans rôle privilégié interne) ne peut annuler que les interventions
|
# Un external_manager (sans rôle privilégié interne) ne peut annuler que les interventions
|
||||||
|
|
|
||||||
247
loko/interventions/tests/test_contract_approval.py
Normal file
247
loko/interventions/tests/test_contract_approval.py
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
from django.test import TestCase, RequestFactory
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from common.models import UserConfig, Role, Thematic, UserThematics, UserContractAccess, UserContractStatusPermission
|
||||||
|
from contracts.models import Company, Contract
|
||||||
|
from interventions.models import Intervention, Symptom
|
||||||
|
from interventions.permissions import (
|
||||||
|
get_allowed_transitions,
|
||||||
|
intervention_requires_approval,
|
||||||
|
user_has_explicit_contract_status_permission,
|
||||||
|
)
|
||||||
|
from interventions.views.workflow import attempt_status_update
|
||||||
|
|
||||||
|
|
||||||
|
class ContractApprovalTests(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.User = get_user_model()
|
||||||
|
self.thematic, _ = Thematic.objects.get_or_create(code='trafficlights', defaults={'name': 'Feux de signalisation'})
|
||||||
|
|
||||||
|
# Roles
|
||||||
|
self.admin_role, _ = Role.objects.get_or_create(name='admin')
|
||||||
|
self.operator_role, _ = Role.objects.get_or_create(name='operator')
|
||||||
|
self.manager_role, _ = Role.objects.get_or_create(name='manager')
|
||||||
|
|
||||||
|
# Company
|
||||||
|
self.company = Company.objects.create(name='Prestataire Test')
|
||||||
|
today = timezone.now().date()
|
||||||
|
|
||||||
|
# Contract needing approval, with approval_except_urgent=True (default)
|
||||||
|
self.contract_approval_except_urgent = Contract.objects.create(
|
||||||
|
contract_number='CTR-APP-EXCEPT-URGENT',
|
||||||
|
company=self.company,
|
||||||
|
start_date=today,
|
||||||
|
end_date=today + timezone.timedelta(days=365),
|
||||||
|
is_active=True,
|
||||||
|
needs_approval=True,
|
||||||
|
approval_except_urgent=True,
|
||||||
|
)
|
||||||
|
self.contract_approval_except_urgent.thematics.add(self.thematic)
|
||||||
|
|
||||||
|
# Contract needing approval, with approval_except_urgent=False
|
||||||
|
self.contract_approval_strict = Contract.objects.create(
|
||||||
|
contract_number='CTR-APP-STRICT',
|
||||||
|
company=self.company,
|
||||||
|
start_date=today,
|
||||||
|
end_date=today + timezone.timedelta(days=365),
|
||||||
|
is_active=True,
|
||||||
|
needs_approval=True,
|
||||||
|
approval_except_urgent=False,
|
||||||
|
)
|
||||||
|
self.contract_approval_strict.thematics.add(self.thematic)
|
||||||
|
|
||||||
|
# Contract not needing approval
|
||||||
|
self.contract_no_approval = Contract.objects.create(
|
||||||
|
contract_number='CTR-NO-APPROVAL',
|
||||||
|
company=self.company,
|
||||||
|
start_date=today,
|
||||||
|
end_date=today + timezone.timedelta(days=365),
|
||||||
|
is_active=True,
|
||||||
|
needs_approval=False,
|
||||||
|
approval_except_urgent=True,
|
||||||
|
)
|
||||||
|
self.contract_no_approval.thematics.add(self.thematic)
|
||||||
|
|
||||||
|
# Users
|
||||||
|
# 1. Admin
|
||||||
|
self.admin_user = self.User.objects.create_user(username='admin_u', password='pwd')
|
||||||
|
self.admin_cfg = UserConfig.objects.create(user=self.admin_user, is_intern=True)
|
||||||
|
self.admin_cfg.roles.add(self.admin_role)
|
||||||
|
|
||||||
|
# 2. Operator without explicit contract status permission
|
||||||
|
self.op_user = self.User.objects.create_user(username='operator_u', password='pwd')
|
||||||
|
self.op_cfg = UserConfig.objects.create(user=self.op_user, is_intern=True)
|
||||||
|
self.op_cfg.roles.add(self.operator_role)
|
||||||
|
self.op_ut = UserThematics.objects.create(user_config=self.op_cfg, thematic=self.thematic, can_view_interventions=True, can_edit_interventions=True)
|
||||||
|
|
||||||
|
# 3. Manager without explicit contract status permission
|
||||||
|
self.mgr_user = self.User.objects.create_user(username='manager_u', password='pwd')
|
||||||
|
self.mgr_cfg = UserConfig.objects.create(user=self.mgr_user, is_intern=True)
|
||||||
|
self.mgr_cfg.roles.add(self.manager_role)
|
||||||
|
self.mgr_ut = UserThematics.objects.create(user_config=self.mgr_cfg, thematic=self.thematic, can_view_interventions=True, can_edit_interventions=True)
|
||||||
|
|
||||||
|
# 4. User with explicit contract status permission (can_change_status_to for to_be_processed)
|
||||||
|
self.authorized_user = self.User.objects.create_user(username='authorized_u', password='pwd')
|
||||||
|
self.authorized_cfg = UserConfig.objects.create(user=self.authorized_user, is_intern=True)
|
||||||
|
self.authorized_cfg.roles.add(self.operator_role)
|
||||||
|
self.auth_ut = UserThematics.objects.create(user_config=self.authorized_cfg, thematic=self.thematic, can_view_interventions=True, can_edit_interventions=True)
|
||||||
|
|
||||||
|
from common.models import UserThematicStatusPermission
|
||||||
|
for ut in [self.op_ut, self.mgr_ut, self.auth_ut]:
|
||||||
|
for st in ['in_preparation', 'to_be_approved', 'to_be_processed', 'canceled']:
|
||||||
|
UserThematicStatusPermission.objects.create(
|
||||||
|
user_thematic=ut,
|
||||||
|
status=st,
|
||||||
|
can_view=True,
|
||||||
|
can_edit=True,
|
||||||
|
can_change_status_to=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Give authorized_user explicit permission on contract_approval_strict
|
||||||
|
self.uca_strict = UserContractAccess.objects.create(
|
||||||
|
user_config=self.authorized_cfg,
|
||||||
|
contract=self.contract_approval_strict,
|
||||||
|
can_view_interventions=True,
|
||||||
|
)
|
||||||
|
UserContractStatusPermission.objects.create(
|
||||||
|
user_contract=self.uca_strict,
|
||||||
|
status='to_be_processed',
|
||||||
|
can_view=True,
|
||||||
|
can_edit=True,
|
||||||
|
can_change_status_to=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.symptom = Symptom.objects.create(name_fr="Test Symptôme", name_nl="Test Symptoom", thematic=self.thematic)
|
||||||
|
|
||||||
|
def test_intervention_requires_approval_helper(self):
|
||||||
|
# Sans contrat -> False
|
||||||
|
itv_no_contract = Intervention(status='in_preparation', priority='3')
|
||||||
|
self.assertFalse(intervention_requires_approval(itv_no_contract))
|
||||||
|
|
||||||
|
# Contrat sans needs_approval -> False
|
||||||
|
itv_no_app = Intervention(status='in_preparation', contract=self.contract_no_approval, priority='3')
|
||||||
|
self.assertFalse(intervention_requires_approval(itv_no_app))
|
||||||
|
|
||||||
|
# Contrat strict (approval_except_urgent=False) :
|
||||||
|
# - Priorité normale ('3') -> True
|
||||||
|
itv_strict_normal = Intervention(status='in_preparation', contract=self.contract_approval_strict, priority='3')
|
||||||
|
self.assertTrue(intervention_requires_approval(itv_strict_normal))
|
||||||
|
# - Priorité urgente ('1') -> True (car approval_except_urgent=False)
|
||||||
|
itv_strict_urgent = Intervention(status='in_preparation', contract=self.contract_approval_strict, priority='1')
|
||||||
|
self.assertTrue(intervention_requires_approval(itv_strict_urgent))
|
||||||
|
|
||||||
|
# Contrat avec approval_except_urgent=True :
|
||||||
|
# - Priorité normale ('3') -> True
|
||||||
|
itv_except_normal = Intervention(status='in_preparation', contract=self.contract_approval_except_urgent, priority='3')
|
||||||
|
self.assertTrue(intervention_requires_approval(itv_except_normal))
|
||||||
|
# - Priorité urgente ('1') -> False (urgence dispense d'approbation)
|
||||||
|
itv_except_urgent = Intervention(status='in_preparation', contract=self.contract_approval_except_urgent, priority='1')
|
||||||
|
self.assertFalse(intervention_requires_approval(itv_except_urgent))
|
||||||
|
|
||||||
|
def test_user_has_explicit_contract_status_permission_helper(self):
|
||||||
|
# Admin -> True
|
||||||
|
self.assertTrue(user_has_explicit_contract_status_permission(self.admin_user, self.contract_approval_strict.id, 'to_be_processed'))
|
||||||
|
|
||||||
|
# Opérateur sans accès au contrat -> False
|
||||||
|
self.assertFalse(user_has_explicit_contract_status_permission(self.op_user, self.contract_approval_strict.id, 'to_be_processed'))
|
||||||
|
|
||||||
|
# Manager sans accès au contrat -> False
|
||||||
|
self.assertFalse(user_has_explicit_contract_status_permission(self.mgr_user, self.contract_approval_strict.id, 'to_be_processed'))
|
||||||
|
|
||||||
|
# Utilisateur avec permission explicite can_change_status_to=True -> True
|
||||||
|
self.assertTrue(user_has_explicit_contract_status_permission(self.authorized_user, self.contract_approval_strict.id, 'to_be_processed'))
|
||||||
|
|
||||||
|
# Rétrocompatibilité : avec can_approve=True sur UserContractAccess
|
||||||
|
user_legacy = self.User.objects.create_user(username='legacy_u', password='pwd')
|
||||||
|
cfg_legacy = UserConfig.objects.create(user=user_legacy, is_intern=True)
|
||||||
|
UserContractAccess.objects.create(user_config=cfg_legacy, contract=self.contract_approval_strict, can_approve=True)
|
||||||
|
self.assertTrue(user_has_explicit_contract_status_permission(user_legacy, self.contract_approval_strict.id, 'to_be_processed'))
|
||||||
|
|
||||||
|
def test_get_allowed_transitions_strict_approval(self):
|
||||||
|
itv_urgent = Intervention.objects.create(
|
||||||
|
title='Test Urgent Strict',
|
||||||
|
status='in_preparation',
|
||||||
|
contract=self.contract_approval_strict,
|
||||||
|
thematic=self.thematic,
|
||||||
|
symptom=self.symptom,
|
||||||
|
priority='1', # Urgent
|
||||||
|
)
|
||||||
|
|
||||||
|
# Pour un opérateur sans droit explicite : seul to_be_approved et canceled doivent être proposés
|
||||||
|
req_op = self.factory.get('/')
|
||||||
|
req_op.user = self.op_user
|
||||||
|
transitions_op = [t['to'] for t in get_allowed_transitions(req_op, itv_urgent)]
|
||||||
|
self.assertIn('to_be_approved', transitions_op)
|
||||||
|
self.assertNotIn('to_be_processed', transitions_op)
|
||||||
|
|
||||||
|
# Même chose pour un MANAGER sans droit explicite sur ce contrat :
|
||||||
|
# Pas de condition de rôle -> le manager est restreint à to_be_approved aussi
|
||||||
|
req_mgr = self.factory.get('/')
|
||||||
|
req_mgr.user = self.mgr_user
|
||||||
|
transitions_mgr = [t['to'] for t in get_allowed_transitions(req_mgr, itv_urgent)]
|
||||||
|
self.assertIn('to_be_approved', transitions_mgr)
|
||||||
|
self.assertNotIn('to_be_processed', transitions_mgr)
|
||||||
|
|
||||||
|
# Pour l'utilisateur autorisé ayant can_change_status_to sur ce contrat : to_be_processed est disponible
|
||||||
|
req_auth = self.factory.get('/')
|
||||||
|
req_auth.user = self.authorized_user
|
||||||
|
transitions_auth = [t['to'] for t in get_allowed_transitions(req_auth, itv_urgent)]
|
||||||
|
self.assertIn('to_be_processed', transitions_auth)
|
||||||
|
|
||||||
|
# Pour l'administrateur : to_be_processed est disponible
|
||||||
|
req_admin = self.factory.get('/')
|
||||||
|
req_admin.user = self.admin_user
|
||||||
|
transitions_admin = [t['to'] for t in get_allowed_transitions(req_admin, itv_urgent)]
|
||||||
|
self.assertIn('to_be_processed', transitions_admin)
|
||||||
|
|
||||||
|
def test_get_allowed_transitions_except_urgent(self):
|
||||||
|
# Sur un contrat avec approval_except_urgent=True :
|
||||||
|
itv_urgent = Intervention.objects.create(
|
||||||
|
title='Test Urgent Except Urgent',
|
||||||
|
status='in_preparation',
|
||||||
|
contract=self.contract_approval_except_urgent,
|
||||||
|
thematic=self.thematic,
|
||||||
|
symptom=self.symptom,
|
||||||
|
priority='1', # Urgent
|
||||||
|
)
|
||||||
|
|
||||||
|
req_op = self.factory.get('/')
|
||||||
|
req_op.user = self.op_user
|
||||||
|
transitions_op = [t['to'] for t in get_allowed_transitions(req_op, itv_urgent)]
|
||||||
|
# L'urgence dispense d'approbation : to_be_processed doit être proposé à l'opérateur
|
||||||
|
self.assertIn('to_be_processed', transitions_op)
|
||||||
|
|
||||||
|
# Mais si l'intervention n'est pas urgente (priorité 3) :
|
||||||
|
itv_normal = Intervention.objects.create(
|
||||||
|
title='Test Normal Except Urgent',
|
||||||
|
status='in_preparation',
|
||||||
|
contract=self.contract_approval_except_urgent,
|
||||||
|
thematic=self.thematic,
|
||||||
|
symptom=self.symptom,
|
||||||
|
priority='3', # Normal
|
||||||
|
)
|
||||||
|
transitions_op_normal = [t['to'] for t in get_allowed_transitions(req_op, itv_normal)]
|
||||||
|
self.assertIn('to_be_approved', transitions_op_normal)
|
||||||
|
self.assertNotIn('to_be_processed', transitions_op_normal)
|
||||||
|
|
||||||
|
def test_attempt_status_update_enforces_contract_approval(self):
|
||||||
|
itv_strict = Intervention.objects.create(
|
||||||
|
title='Test Security Workflow',
|
||||||
|
status='in_preparation',
|
||||||
|
contract=self.contract_approval_strict,
|
||||||
|
thematic=self.thematic,
|
||||||
|
symptom=self.symptom,
|
||||||
|
priority='1', # Urgent mais approval_except_urgent=False
|
||||||
|
)
|
||||||
|
|
||||||
|
req = self.factory.post('/')
|
||||||
|
# L'opérateur non autorisé tente de passer directement à to_be_processed
|
||||||
|
success, msg, _ = attempt_status_update(req, itv_strict, self.op_user, 'to_be_processed')
|
||||||
|
self.assertFalse(success)
|
||||||
|
self.assertIn("nécessite une approbation", str(msg))
|
||||||
|
|
||||||
|
# L'utilisateur avec droit explicite sur ce contrat peut passer à to_be_processed
|
||||||
|
success_auth, _, _ = attempt_status_update(req, itv_strict, self.authorized_user, 'to_be_processed')
|
||||||
|
self.assertTrue(success_auth)
|
||||||
|
|
@ -433,6 +433,15 @@ def attempt_status_update(request, intervention, user, new_status, pause_reason=
|
||||||
from interventions.permissions import can_approve_intervention
|
from interventions.permissions import can_approve_intervention
|
||||||
if not can_approve_intervention(user, intervention):
|
if not can_approve_intervention(user, intervention):
|
||||||
return False, _("Vous n'avez pas le droit d'approuver les interventions de ce contrat."), False
|
return False, _("Vous n'avez pas le droit d'approuver les interventions de ce contrat."), False
|
||||||
|
|
||||||
|
# Si l'intervention est en préparation et nécessite une approbation,
|
||||||
|
# seuls les utilisateurs ayant explicitement le droit de passer à 'to_be_processed'
|
||||||
|
# sur ce contrat peuvent effectuer cette transition directement.
|
||||||
|
if current_status == 'in_preparation' and new_status == 'to_be_processed':
|
||||||
|
from interventions.permissions import intervention_requires_approval, user_has_explicit_contract_status_permission
|
||||||
|
if intervention_requires_approval(intervention):
|
||||||
|
if not user_has_explicit_contract_status_permission(user, intervention.contract_id, 'to_be_processed'):
|
||||||
|
return False, _("Cette intervention nécessite une approbation avant d'être transmise pour traitement."), False
|
||||||
|
|
||||||
# Vérifie la transition dans la matrice
|
# Vérifie la transition dans la matrice
|
||||||
# allowed_transitions = ALLOWED_TRANSITIONS.get(current_status, [])
|
# allowed_transitions = ALLOWED_TRANSITIONS.get(current_status, [])
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue