feat: promote existing base inspections to HotBoxInspection instances and add pending visual checks UI

This commit is contained in:
kdeterme 2026-09-18 16:14:04 +02:00
parent a52f205e42
commit f2fbe7e394
11 changed files with 131 additions and 2 deletions

View file

@ -1965,6 +1965,11 @@ msgstr ""
"Please answer each of the 4 visual checks of the Hot Box repair (Flatness, "
"Joints, Cracking, Drainage)."
msgid ""
"Contrôles visuels non encore renseignés (inspection planifiée ou en attente "
"d'évaluation)."
msgstr "Visual checks not yet filled in (scheduled or pending evaluation)."
#~ msgid "Renforcement de l'entretien préventif"
#~ msgstr "Reinforcement of preventive maintenance"

View file

@ -1973,6 +1973,13 @@ msgstr ""
"Veuillez répondre à chacun des 4 contrôles visuels de la réparation Hot Box "
"(Planéité, Joints, Fissuration, Évacuation des eaux)."
msgid ""
"Contrôles visuels non encore renseignés (inspection planifiée ou en attente "
"d'évaluation)."
msgstr ""
"Contrôles visuels non encore renseignés (inspection planifiée ou en attente "
"d'évaluation)."
#~ msgid "Renforcement de l'entretien préventif"
#~ msgstr "Renforcement de l’entretien préventif"

View file

@ -1964,6 +1964,13 @@ msgstr ""
"Gelieve elk van de 4 visuele controles van de Hot Box-herstelling te "
"beantwoorden (Vlakheid, Voegen, Scheurvorming, Afwatering)."
msgid ""
"Contrôles visuels non encore renseignés (inspection planifiée ou en attente "
"d'évaluation)."
msgstr ""
"Visuele controles nog niet ingevuld (geplande inspectie of in afwachting van"
" evaluatie)."
#~ msgid "Renforcement de l'entretien préventif"
#~ msgstr "Versterking van preventief onderhoud"

View file

@ -0,0 +1,35 @@
from django.db import migrations, models
def promote_existing_hotbox_inspections(apps, schema_editor):
Inspection = apps.get_model('inspections', 'Inspection')
HotBoxInspection = apps.get_model('inspections', 'HotBoxInspection')
db_alias = schema_editor.connection.alias
existing_hb_ids = set(HotBoxInspection.objects.using(db_alias).values_list('inspection_ptr_id', flat=True))
inspections_to_promote = Inspection.objects.using(db_alias).filter(
models.Q(checked_intervention__sub_type__code='hotbox') |
models.Q(mission_intervention__sub_type__code='hotbox')
).exclude(id__in=existing_hb_ids)
for insp in inspections_to_promote:
hb = HotBoxInspection(inspection_ptr=insp)
for f in insp._meta.fields:
setattr(hb, f.attname, getattr(insp, f.attname))
hb.save_base(raw=True, using=db_alias)
def reverse_func(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
('inspections', '0012_alter_hotboxinspection_water_drainage'),
]
operations = [
migrations.RunPython(promote_existing_hotbox_inspections, reverse_func),
]

View file

@ -598,7 +598,10 @@ class Inspection(models.Model):
return self.hotboxinspection
if self.is_hotbox_related and self.pk:
try:
hb, _ = HotBoxInspection.objects.get_or_create(inspection_ptr=self)
hb = HotBoxInspection(inspection_ptr=self)
for f in self._meta.fields:
setattr(hb, f.attname, getattr(self, f.attname))
hb.save_base(raw=True)
return hb
except Exception:
pass

View file

@ -8,6 +8,12 @@
</h6>
<ul class="list-group list-group-flush bg-transparent">
{% if not leaf.joint_level and not leaf.joint_sealing and not leaf.cracking and not leaf.water_drainage %}
<li class="list-group-item bg-transparent text-muted small fst-italic px-0 py-2">
<i class="bi bi-hourglass-split me-1 text-secondary"></i>{% translate "Contrôles visuels non encore renseignés (inspection planifiée ou en attente d'évaluation)." %}
</li>
{% endif %}
<!-- 1. Planéité -->
{% if leaf.joint_level %}
<li class="list-group-item bg-transparent d-flex justify-content-between align-items-center px-0 py-2.5 border-bottom-0">

View file

@ -2018,7 +2018,63 @@ class PostInterventionDurabilityInspectionTestCase(TestCase):
insp = schedule_post_intervention_inspection(intervention)
self.assertIsNotNone(insp)
self.assertIsInstance(insp.detailed_inspection, HotBoxInspection)
self.assertTrue(insp.is_hotbox_related)
def test_existing_base_inspection_promotion_and_update(self):
"""Vérifie qu'une inspection existante créée comme base Inspection pour un Hot Box est bien promue en HotBoxInspection et que ses choix sont sauvegardés."""
self.client.force_login(self.user)
intervention = self._create_finished_intervention(sub_type=self.hotbox_subtype)
interv_ct = ContentType.objects.get_for_model(Intervention)
# Création directe comme base Inspection (simulation d'une inspection créée avant la migration)
base_insp = Inspection.objects.create(
asset_content_type=interv_ct,
asset_object_id=intervention.pk,
nature='post_intervention',
checked_intervention=intervention,
status='scheduled',
result_status='pending',
)
# 1. Avant évaluation : get_inspection_detail_api renvoie le message d'attente
detail_url = reverse('inspections:get_inspection_detail_api', kwargs={'inspection_id': base_insp.id})
resp_detail = self.client.get(detail_url, HTTP_ACCEPT_LANGUAGE='fr')
self.assertEqual(resp_detail.status_code, 200)
detail_data = resp_detail.json()
self.assertTrue(detail_data.get('is_hotbox'))
self.assertIn("non encore renseignés", detail_data.get('details_html', ''))
# 2. Mise à jour via update_inspection_api (sauvegarde des 4 critères)
update_url = reverse('inspections:update_inspection_api', kwargs={'inspection_id': base_insp.id})
update_data = {
'status': 'completed',
'result_status': 'compliant',
'joint_level': 'flush',
'joint_sealing': 'good',
'cracking': 'none',
'water_drainage': 'not_checked',
'notes': 'Test mise à jour inspection Hot Box existante',
}
resp_update = self.client.post(update_url, update_data)
self.assertEqual(resp_update.status_code, 200)
self.assertTrue(resp_update.json()['success'])
# 3. Vérification que l'inspection est maintenant bien un HotBoxInspection avec ses choix
base_insp.refresh_from_db()
leaf = base_insp.detailed_inspection
self.assertIsInstance(leaf, HotBoxInspection)
self.assertEqual(leaf.joint_level, 'flush')
self.assertEqual(leaf.joint_sealing, 'good')
self.assertEqual(leaf.cracking, 'none')
self.assertEqual(leaf.water_drainage, 'not_checked')
# 4. Consultation du détail : les badges et choix sont bien présents
resp_detail_after = self.client.get(detail_url, HTTP_ACCEPT_LANGUAGE='fr')
detail_data_after = resp_detail_after.json()
self.assertEqual(detail_data_after['joint_level'], 'flush')
self.assertEqual(detail_data_after['water_drainage'], 'not_checked')
self.assertIn("Bien à niveau / Arasé", detail_data_after['details_html'])
self.assertIn("Non vérifié", detail_data_after['details_html'])
self.assertTrue(base_insp.is_hotbox_related)

View file

@ -987,6 +987,16 @@ def update_inspection_api(request, inspection_id):
inspection_obj = get_object_or_404(Inspection, pk=inspection_id)
inspection = inspection_obj.detailed_inspection
if not isinstance(inspection, HotBoxInspection) and (getattr(inspection, 'is_hotbox_related', False) or 'joint_level' in request.POST):
try:
hb = HotBoxInspection(inspection_ptr=inspection)
for f in inspection._meta.fields:
setattr(hb, f.attname, getattr(inspection, f.attname))
hb.save_base(raw=True)
inspection = hb
except Exception:
pass
if not inspection.can_edit(request.user):
return JsonResponse({
'success': False,