feat: add reprogrammation intervention type restricted to trafficlights thematic and update forms accordingly
This commit is contained in:
parent
f810041e98
commit
46f1d0d384
12 changed files with 171 additions and 5 deletions
Binary file not shown.
|
|
@ -149,6 +149,10 @@ msgstr "Construction"
|
|||
msgid "Ramassage"
|
||||
msgstr "Collection"
|
||||
|
||||
#: interventions/models.py:105
|
||||
msgid "Reprogrammation"
|
||||
msgstr "Reprogramming"
|
||||
|
||||
#: interventions/models.py:108
|
||||
msgid "Avarie"
|
||||
msgstr "Damage"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -149,6 +149,10 @@ msgstr "Construction"
|
|||
msgid "Ramassage"
|
||||
msgstr "Ramassage"
|
||||
|
||||
#: interventions/models.py:105
|
||||
msgid "Reprogrammation"
|
||||
msgstr "Reprogrammation"
|
||||
|
||||
#: interventions/models.py:108
|
||||
msgid "Avarie"
|
||||
msgstr "Avarie"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -149,6 +149,10 @@ msgstr "Bouw"
|
|||
msgid "Ramassage"
|
||||
msgstr "Ophaling"
|
||||
|
||||
#: interventions/models.py:105
|
||||
msgid "Reprogrammation"
|
||||
msgstr "Herprogrammering"
|
||||
|
||||
#: interventions/models.py:108
|
||||
msgid "Avarie"
|
||||
msgstr "Schade"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 6.0.7 on 2026-08-19 08:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('interventions', '0003_operationtemplate_team'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='intervention',
|
||||
name='type',
|
||||
field=models.CharField(blank=True, choices=[('fixing', 'Dépannage'), ('repair', 'Réparation'), ('repair_post_preventive', 'Réparation post préventif'), ('replace', 'Remplacement'), ('care', 'Entretien'), ('control', 'Contrôle'), ('inspection', 'Inspection'), ('build', 'Construction'), ('collection', 'Ramassage'), ('reprogramming', 'Reprogrammation')], null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -102,8 +102,26 @@ TYPE_CHOICES = [
|
|||
('inspection', _('Inspection')),
|
||||
('build', _('Construction')),
|
||||
('collection', _('Ramassage')),
|
||||
('reprogramming', _('Reprogrammation')),
|
||||
]
|
||||
|
||||
|
||||
def get_type_choices(thematic=None):
|
||||
"""
|
||||
Renvoie la liste des choix de type d'intervention selon la thématique.
|
||||
Le type 'reprogramming' (Reprogrammation) n'est disponible que pour la thématique 'trafficlights'.
|
||||
"""
|
||||
thematic_code = None
|
||||
if thematic:
|
||||
if isinstance(thematic, str):
|
||||
thematic_code = thematic
|
||||
elif hasattr(thematic, 'code'):
|
||||
thematic_code = thematic.code
|
||||
|
||||
if thematic_code == 'trafficlights':
|
||||
return list(TYPE_CHOICES)
|
||||
return [c for c in TYPE_CHOICES if c[0] != 'reprogramming']
|
||||
|
||||
ORIGIN_TYPE_CHOICES = [
|
||||
('damage', _('Avarie')),
|
||||
('defect', _('Défaut/Panne')),
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ from interventions.models import (
|
|||
OperationStatus,
|
||||
STATUS_ORDERS,
|
||||
InterventionDocument,
|
||||
get_type_choices,
|
||||
)
|
||||
from django.db.models import Q
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
|
@ -1665,6 +1666,114 @@ class InterventionGeojsonExternalFilterTests(TestCase):
|
|||
self.assertIn(self.itv_external.id, ids_ext)
|
||||
|
||||
|
||||
class TrafficlightsReprogrammingTypeTests(TestCase):
|
||||
def setUp(self):
|
||||
User = get_user_model()
|
||||
self.user = User.objects.create_user(username='admin_tl', password='pwd')
|
||||
self.role_admin = Role.objects.create(name='admin')
|
||||
self.user_config = UserConfig.objects.create(user=self.user, is_intern=True)
|
||||
self.user_config.roles.add(self.role_admin)
|
||||
|
||||
self.tl_thematic = Thematic.objects.create(code='trafficlights', name_fr='Feux tricolores', name_nl='Verkeerslichten')
|
||||
self.struct_thematic = Thematic.objects.create(code='structures', name_fr='Ouvrages d\'art', name_nl='Kunstwerken')
|
||||
|
||||
UserThematics.objects.create(user_config=self.user_config, thematic=self.tl_thematic, can_edit_interventions=True)
|
||||
UserThematics.objects.create(user_config=self.user_config, thematic=self.struct_thematic, can_edit_interventions=True)
|
||||
|
||||
self.itv_tl = Intervention.objects.create(
|
||||
code='ITV-TL-001',
|
||||
title='Intervention Feux',
|
||||
status='in_preparation',
|
||||
thematic=self.tl_thematic,
|
||||
type='fixing',
|
||||
created_by=self.user
|
||||
)
|
||||
self.itv_struct = Intervention.objects.create(
|
||||
code='ITV-ST-001',
|
||||
title='Intervention Ouvrage',
|
||||
status='in_preparation',
|
||||
thematic=self.struct_thematic,
|
||||
type='fixing',
|
||||
created_by=self.user
|
||||
)
|
||||
|
||||
def test_get_type_choices(self):
|
||||
tl_choices = [c[0] for c in get_type_choices(self.tl_thematic)]
|
||||
self.assertIn('reprogramming', tl_choices)
|
||||
self.assertIn('fixing', tl_choices)
|
||||
|
||||
tl_str_choices = [c[0] for c in get_type_choices('trafficlights')]
|
||||
self.assertIn('reprogramming', tl_str_choices)
|
||||
|
||||
struct_choices = [c[0] for c in get_type_choices(self.struct_thematic)]
|
||||
self.assertNotIn('reprogramming', struct_choices)
|
||||
self.assertIn('fixing', struct_choices)
|
||||
|
||||
struct_str_choices = [c[0] for c in get_type_choices('structures')]
|
||||
self.assertNotIn('reprogramming', struct_str_choices)
|
||||
|
||||
none_choices = [c[0] for c in get_type_choices(None)]
|
||||
self.assertNotIn('reprogramming', none_choices)
|
||||
|
||||
def test_intervention_form_choices(self):
|
||||
from interventions.views.forms import InterventionForm
|
||||
form_tl = InterventionForm(thematic=self.tl_thematic, user=self.user)
|
||||
tl_choices = [c[0] for c in form_tl.fields['type'].choices]
|
||||
self.assertIn('reprogramming', tl_choices)
|
||||
|
||||
form_struct = InterventionForm(thematic=self.struct_thematic, user=self.user)
|
||||
struct_choices = [c[0] for c in form_struct.fields['type'].choices]
|
||||
self.assertNotIn('reprogramming', struct_choices)
|
||||
|
||||
def test_preventive_intervention_form_choices(self):
|
||||
from interventions.views.forms import PreventiveInterventionForm
|
||||
form_tl = PreventiveInterventionForm(thematic=self.tl_thematic, user=self.user)
|
||||
tl_choices = [c[0] for c in form_tl.fields['type'].choices]
|
||||
self.assertIn('reprogramming', tl_choices)
|
||||
|
||||
form_struct = PreventiveInterventionForm(thematic=self.struct_thematic, user=self.user)
|
||||
struct_choices = [c[0] for c in form_struct.fields['type'].choices]
|
||||
self.assertNotIn('reprogramming', struct_choices)
|
||||
|
||||
def test_intervention_detail_context(self):
|
||||
self.client.force_login(self.user)
|
||||
|
||||
resp_tl = self.client.get(reverse('interventions:intervention_detail', kwargs={'intervention_id': self.itv_tl.id}))
|
||||
self.assertEqual(resp_tl.status_code, 200)
|
||||
tl_type_choices = [c[0] for c in resp_tl.context['type_choices']]
|
||||
self.assertIn('reprogramming', tl_type_choices)
|
||||
|
||||
resp_struct = self.client.get(reverse('interventions:intervention_detail', kwargs={'intervention_id': self.itv_struct.id}))
|
||||
self.assertEqual(resp_struct.status_code, 200)
|
||||
struct_type_choices = [c[0] for c in resp_struct.context['type_choices']]
|
||||
self.assertNotIn('reprogramming', struct_type_choices)
|
||||
|
||||
def test_update_intervention_type_reprogramming(self):
|
||||
self.client.force_login(self.user)
|
||||
|
||||
# Updating trafficlights intervention to reprogramming -> SUCCESS
|
||||
update_url_tl = reverse('interventions:update_intervention', kwargs={'intervention_id': self.itv_tl.id})
|
||||
resp = self.client.post(
|
||||
update_url_tl,
|
||||
data=json.dumps({'type': 'reprogramming'}),
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.itv_tl.refresh_from_db()
|
||||
self.assertEqual(self.itv_tl.type, 'reprogramming')
|
||||
|
||||
# Updating structures intervention to reprogramming -> REJECTED
|
||||
update_url_struct = reverse('interventions:update_intervention', kwargs={'intervention_id': self.itv_struct.id})
|
||||
resp = self.client.post(
|
||||
update_url_struct,
|
||||
data=json.dumps({'type': 'reprogramming'}),
|
||||
content_type='application/json'
|
||||
)
|
||||
self.itv_struct.refresh_from_db()
|
||||
self.assertEqual(self.itv_struct.type, 'fixing')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ from interventions.models import (InterventionSubscription, Intervention, Interv
|
|||
Operation, OperationTemplate, OperationTemplateItem, OperationStatus, OperationStatusSet, MeasurementDefinition,
|
||||
GuidedOperationTemplate, GuidedOperationData, GuidedOperationMedia,
|
||||
InterventionPostPeriodQuantity, InterventionEmailLog, InterventionAssignment)
|
||||
from interventions.models import STATUS_CHOICES, STATUS_ORDERS, MAINTAIN_CHOICES, TYPE_CHOICES, ORIGIN_TYPE_CHOICES, PAUSE_REASON_CHOICES
|
||||
from interventions.models import STATUS_CHOICES, STATUS_ORDERS, MAINTAIN_CHOICES, TYPE_CHOICES, ORIGIN_TYPE_CHOICES, PAUSE_REASON_CHOICES, get_type_choices
|
||||
from interventions.views.forms import (InterventionForm, InterventionNoteForm, InterventionDocumentForm,
|
||||
InterventionOccupationForm, PreventiveInterventionForm, AssetsLinkForm,
|
||||
LinkExistingInterventionsForm)
|
||||
|
|
@ -637,7 +637,7 @@ def intervention_detail(request, intervention_id):
|
|||
'providers': providers,
|
||||
'contracts': contracts,
|
||||
'maintain_choices': MAINTAIN_CHOICES,
|
||||
'type_choices': TYPE_CHOICES,
|
||||
'type_choices': get_type_choices(intervention.thematic),
|
||||
'origin_type_choices': ORIGIN_TYPE_CHOICES,
|
||||
'priority_choices': Intervention._meta.get_field('priority').choices,
|
||||
'symptoms': Symptom.objects.filter(is_active=True, thematic=intervention.thematic).order_by('name_fr'),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import bleach
|
|||
import json
|
||||
import re
|
||||
|
||||
from interventions.models import Intervention, InterventionNote, InterventionDocument, Symptom, OperationTemplate, InterventionOccupation, SourceCategory, OperationStatusSet, MeasurementDefinition, TYPE_CHOICES
|
||||
from interventions.models import Intervention, InterventionNote, InterventionDocument, Symptom, OperationTemplate, InterventionOccupation, SourceCategory, OperationStatusSet, MeasurementDefinition, TYPE_CHOICES, get_type_choices
|
||||
from assets.models import AssetCategory
|
||||
from common.models import UserConfig, UserThematics
|
||||
from contracts.models import Contract, ContractOrder, CompanyMember
|
||||
|
|
@ -93,6 +93,11 @@ class InterventionForm(forms.ModelForm):
|
|||
(val, lbl) for val, lbl in self.fields['status'].choices if val in allowed_statuses
|
||||
]
|
||||
|
||||
# Filtrer les types selon la thématique (ex: reprogrammation uniquement pour trafficlights)
|
||||
thematic_obj = thematic or (self.instance.thematic if self.instance and getattr(self.instance, 'pk', None) else None)
|
||||
if 'type' in self.fields:
|
||||
self.fields['type'].choices = get_type_choices(thematic_obj)
|
||||
|
||||
type_value = self.initial.get('type') or self.data.get('type')
|
||||
maintain_type_value = self.initial.get('maintain_type') or self.data.get('maintain_type')
|
||||
if type_value == 'inspection':
|
||||
|
|
@ -515,6 +520,9 @@ class PreventiveInterventionForm(forms.Form):
|
|||
def __init__(self, *args, user=None, thematic=None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if 'type' in self.fields:
|
||||
self.fields['type'].choices = get_type_choices(thematic)
|
||||
|
||||
type_value = self.initial.get('type') or (self.data.get('type') if self.data else None) or 'care'
|
||||
if type_value == 'inspection':
|
||||
self.fields['status'].choices = [
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ from interventions.models import (InterventionSubscription, Intervention, Interv
|
|||
GuidedOperationTemplate, GuidedOperationData, GuidedOperationMedia,
|
||||
InterventionPostPeriodQuantity, InterventionEmailLog, InterventionAssignment,
|
||||
DirectContractRouting)
|
||||
from interventions.models import STATUS_CHOICES, STATUS_ORDERS, MAINTAIN_CHOICES, TYPE_CHOICES, ORIGIN_TYPE_CHOICES, PAUSE_REASON_CHOICES
|
||||
from interventions.models import STATUS_CHOICES, STATUS_ORDERS, MAINTAIN_CHOICES, TYPE_CHOICES, ORIGIN_TYPE_CHOICES, PAUSE_REASON_CHOICES, get_type_choices
|
||||
from interventions.views.forms import (InterventionForm, InterventionNoteForm, InterventionDocumentForm,
|
||||
InterventionOccupationForm, PreventiveInterventionForm, AssetsLinkForm,
|
||||
LinkExistingInterventionsForm)
|
||||
|
|
@ -2505,7 +2505,8 @@ def _update_intervention_field(intervention, field, new_value, user_config=None)
|
|||
return False, _('Maintain Type not found')
|
||||
|
||||
elif field == "type":
|
||||
if new_value in dict(TYPE_CHOICES).keys():
|
||||
allowed_types = dict(get_type_choices(intervention.thematic)).keys()
|
||||
if new_value in allowed_types:
|
||||
intervention.type = new_value
|
||||
return True, None
|
||||
return False, _('Type not found')
|
||||
|
|
|
|||
Loading…
Reference in a new issue