From ecb3bbddd1ccf92c928c6b95ea810b2b8cea7a9a Mon Sep 17 00:00:00 2001 From: kdeterme Date: Fri, 18 Sep 2026 13:46:53 +0200 Subject: [PATCH] feat: require all four hotbox inspection questions to be answered and update validation logic --- ...lter_hotboxinspection_cracking_and_more.py | 33 +++++ loko/inspections/models.py | 21 ++- .../components/asset_fields/_hotbox.html | 42 +++--- .../components/edit_inspection_modal.html | 121 +++++++++++++----- loko/inspections/tests.py | 42 ++++-- loko/inspections/views.py | 51 +++++--- 6 files changed, 232 insertions(+), 78 deletions(-) create mode 100644 loko/inspections/migrations/0011_alter_hotboxinspection_cracking_and_more.py diff --git a/loko/inspections/migrations/0011_alter_hotboxinspection_cracking_and_more.py b/loko/inspections/migrations/0011_alter_hotboxinspection_cracking_and_more.py new file mode 100644 index 0000000..4ab8543 --- /dev/null +++ b/loko/inspections/migrations/0011_alter_hotboxinspection_cracking_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 6.0.7 on 2026-09-18 10:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('inspections', '0010_hotboxinspection'), + ] + + operations = [ + migrations.AlterField( + model_name='hotboxinspection', + name='cracking', + field=models.CharField(blank=True, choices=[('none', 'Aucune fissure'), ('minor', 'Petites fissures / Faïençage'), ('major', 'Grosses fissures / Fissures ouvertes')], default=None, max_length=50, null=True, verbose_name='Fissuration'), + ), + migrations.AlterField( + model_name='hotboxinspection', + name='joint_level', + field=models.CharField(blank=True, choices=[('flush', 'Bien à niveau / Arasé'), ('slight_bump_hollow', 'Léger décalage / Creux ou bosse'), ('step', 'Ressaut important (> 1-2 cm)')], default=None, max_length=50, null=True, verbose_name='Planéité / Arasement'), + ), + migrations.AlterField( + model_name='hotboxinspection', + name='joint_sealing', + field=models.CharField(blank=True, choices=[('good', 'Joints bien fermés / scellés'), ('cracked', 'Joints fissurés ou abîmés'), ('open', 'Joints ouverts ou décollés')], default=None, max_length=50, null=True, verbose_name='Joints de raccordement'), + ), + migrations.AlterField( + model_name='hotboxinspection', + name='water_drainage', + field=models.CharField(blank=True, choices=[('good', 'Bon écoulement / Pas de flaque'), ('stagnation', "Eau stagnante / Flaque d'eau")], default=None, max_length=50, null=True, verbose_name='Évacuation des eaux pluviales'), + ), + ] diff --git a/loko/inspections/models.py b/loko/inspections/models.py index 69c76df..baf7d45 100644 --- a/loko/inspections/models.py +++ b/loko/inspections/models.py @@ -586,6 +586,8 @@ class Inspection(models.Model): @property def detailed_inspection(self): """Downcast à la sous-classe spécialisée si disponible (ex: ParkingSpotInspection, GiepInspection, SignPanelInspection, HotBoxInspection).""" + if self.__class__ is not Inspection: + return self if hasattr(self, 'parkingspotinspection'): return self.parkingspotinspection if hasattr(self, 'giepinspection'): @@ -1062,7 +1064,7 @@ class HotBoxInspection(Inspection): joint_level = models.CharField( max_length=50, choices=JOINT_LEVEL_CHOICES, - default='flush', + default=None, null=True, blank=True, verbose_name=_("Planéité / Arasement") @@ -1076,7 +1078,7 @@ class HotBoxInspection(Inspection): joint_sealing = models.CharField( max_length=50, choices=JOINT_SEALING_CHOICES, - default='good', + default=None, null=True, blank=True, verbose_name=_("Joints de raccordement") @@ -1090,7 +1092,7 @@ class HotBoxInspection(Inspection): cracking = models.CharField( max_length=50, choices=CRACKING_CHOICES, - default='none', + default=None, null=True, blank=True, verbose_name=_("Fissuration") @@ -1103,7 +1105,7 @@ class HotBoxInspection(Inspection): water_drainage = models.CharField( max_length=50, choices=WATER_DRAINAGE_CHOICES, - default='good', + default=None, null=True, blank=True, verbose_name=_("Évacuation des eaux pluviales") @@ -1116,7 +1118,7 @@ class HotBoxInspection(Inspection): def compute_status(self): """ Calcule automatiquement le statut de conformité ('compliant', 'non_compliant', 'damaged') - selon la sévérité des constats visuels. + selon la sévérité des constats visuels, ou None si l'évaluation n'est pas complète. """ if self.joint_level == 'step' or self.joint_sealing == 'open' or self.cracking == 'major': return 'damaged' @@ -1127,7 +1129,14 @@ class HotBoxInspection(Inspection): self.water_drainage == 'stagnation' ): return 'non_compliant' - return 'compliant' + if self.joint_level and self.joint_sealing and self.cracking and self.water_drainage: + return 'compliant' + return None + + @property + def is_fully_evaluated(self): + """Indique si les 4 questions de l'inspection ont été renseignées.""" + return bool(self.joint_level and self.joint_sealing and self.cracking and self.water_drainage) def inspection_document_upload_path(instance, filename): diff --git a/loko/inspections/templates/inspections/components/asset_fields/_hotbox.html b/loko/inspections/templates/inspections/components/asset_fields/_hotbox.html index 6715b47..281541a 100644 --- a/loko/inspections/templates/inspections/components/asset_fields/_hotbox.html +++ b/loko/inspections/templates/inspections/components/asset_fields/_hotbox.html @@ -6,25 +6,25 @@ {% translate "Contrôle visuel de réparation Hot Box" %} - - {% translate "Suggéré : Conforme" %} + + {% translate "4 questions à évaluer" %}

- {% translate "Évaluez visuellement la zone réparée sur les 4 critères simples ci-dessous :" %} + {% translate "Évaluez visuellement la zone réparée sur les 4 critères ci-dessous (sans valeur par défaut) :" %}

- +