feat(nature): create timeline planning events and display due date on asset interventions
- Create InterventionPlanificationTimeLine events (expected_begin and expected_end) during Fulcrum tree interventions import and maintenance dates synchronization - Display planned/completion date instead of creation_time in asset_interventions.html - Add unit test assertions for planning timeline events
This commit is contained in:
parent
74ef7d3a34
commit
af411b2105
3 changed files with 80 additions and 1 deletions
|
|
@ -972,8 +972,73 @@ class Command(BaseCommand):
|
||||||
InterventionAsset.objects.bulk_create(chunk, batch_size=BATCH_SIZE)
|
InterventionAsset.objects.bulk_create(chunk, batch_size=BATCH_SIZE)
|
||||||
self.log(f" Insertion liens : {min(i + BATCH_SIZE, len(assets_to_create))} / {len(assets_to_create)}")
|
self.log(f" Insertion liens : {min(i + BATCH_SIZE, len(assets_to_create))} / {len(assets_to_create)}")
|
||||||
|
|
||||||
|
# Synchronisation des événements de planification timeline
|
||||||
|
self.sync_intervention_planning_events()
|
||||||
|
|
||||||
self.log(f"Importation des interventions terminée. Total en base : {Intervention.objects.count()}")
|
self.log(f"Importation des interventions terminée. Total en base : {Intervention.objects.count()}")
|
||||||
|
|
||||||
|
def sync_intervention_planning_events(self):
|
||||||
|
"""
|
||||||
|
Crée ou met à jour les événements de la timeline de planification (InterventionPlanificationTimeLine) :
|
||||||
|
- 'expected_end' : échéance prévisionnelle calculée depuis in_deadline
|
||||||
|
- 'expected_begin' : date de début / diagnostic initial depuis dia_date
|
||||||
|
"""
|
||||||
|
self.log("--- Synchronisation des événements de planification (timeline) ---")
|
||||||
|
from django.db import connection
|
||||||
|
|
||||||
|
with connection.cursor() as cur:
|
||||||
|
# 1. Échéances prévisionnelles (expected_end)
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO interventions_interventionplanificationtimeline (
|
||||||
|
intervention_id, event_time, event_type, event_description
|
||||||
|
)
|
||||||
|
SELECT i.id, i.expected_end_time, 'expected_end', 'Échéance prévisionnelle'
|
||||||
|
FROM interventions_intervention i
|
||||||
|
WHERE i.expected_end_time IS NOT NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM interventions_interventionplanificationtimeline p
|
||||||
|
WHERE p.intervention_id = i.id AND p.event_type = 'expected_end'
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
created_end = cur.rowcount
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
UPDATE interventions_interventionplanificationtimeline p
|
||||||
|
SET event_time = i.expected_end_time
|
||||||
|
FROM interventions_intervention i
|
||||||
|
WHERE p.intervention_id = i.id
|
||||||
|
AND p.event_type = 'expected_end'
|
||||||
|
AND p.event_time != i.expected_end_time;
|
||||||
|
""")
|
||||||
|
updated_end = cur.rowcount
|
||||||
|
self.log(f" Échéance prévisionnelle (expected_end) : {created_end} créés, {updated_end} mis à jour")
|
||||||
|
|
||||||
|
# 2. Diagnostics initiaux (expected_begin)
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO interventions_interventionplanificationtimeline (
|
||||||
|
intervention_id, event_time, event_type, event_description
|
||||||
|
)
|
||||||
|
SELECT i.id, i.expected_begin_time, 'expected_begin', 'Diagnostic initial'
|
||||||
|
FROM interventions_intervention i
|
||||||
|
WHERE i.expected_begin_time IS NOT NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM interventions_interventionplanificationtimeline p
|
||||||
|
WHERE p.intervention_id = i.id AND p.event_type = 'expected_begin'
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
created_begin = cur.rowcount
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
UPDATE interventions_interventionplanificationtimeline p
|
||||||
|
SET event_time = i.expected_begin_time
|
||||||
|
FROM interventions_intervention i
|
||||||
|
WHERE p.intervention_id = i.id
|
||||||
|
AND p.event_type = 'expected_begin'
|
||||||
|
AND p.event_time != i.expected_begin_time;
|
||||||
|
""")
|
||||||
|
updated_begin = cur.rowcount
|
||||||
|
self.log(f" Diagnostic initial (expected_begin) : {created_begin} créés, {updated_begin} mis à jour")
|
||||||
|
|
||||||
def sync_tree_maintenance_dates(self, gestion_file=None):
|
def sync_tree_maintenance_dates(self, gestion_file=None):
|
||||||
"""
|
"""
|
||||||
Synchronise les dates et périodicités de maintenance sur les arbres :
|
Synchronise les dates et périodicités de maintenance sur les arbres :
|
||||||
|
|
@ -981,10 +1046,13 @@ class Command(BaseCommand):
|
||||||
- pruning_frequency_years : périodicité extraite du délai/titre (ex: Dans 1 an -> 1)
|
- pruning_frequency_years : périodicité extraite du délai/titre (ex: Dans 1 an -> 1)
|
||||||
- last_phytosanitary_date : max(expected_begin_time) des interventions de diagnostic
|
- last_phytosanitary_date : max(expected_begin_time) des interventions de diagnostic
|
||||||
- last_pruning_date : date d'exécution de la dernière taille (depuis gestion.csv ou interventions passées)
|
- last_pruning_date : date d'exécution de la dernière taille (depuis gestion.csv ou interventions passées)
|
||||||
|
- timeline de planification : synchronisation des événements expected_begin / expected_end
|
||||||
"""
|
"""
|
||||||
self.log("--- Synchronisation des dates de maintenance sur les arbres ---")
|
self.log("--- Synchronisation des dates de maintenance sur les arbres ---")
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
|
|
||||||
|
self.sync_intervention_planning_events()
|
||||||
|
|
||||||
content_type_tree = ContentType.objects.get_for_model(NatureTree)
|
content_type_tree = ContentType.objects.get_for_model(NatureTree)
|
||||||
|
|
||||||
with connection.cursor() as cur:
|
with connection.cursor() as cur:
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,9 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="pe-3">
|
<td class="pe-3">
|
||||||
<small class="text-muted">{{ intervention.creation_time|date:"d/m/Y" }}</small>
|
<small class="text-muted" title="{% if intervention.end_time %}{% translate 'Date de réalisation' %}{% elif intervention.expected_end_time %}{% translate 'Échéance prévisionnelle' %}{% elif intervention.expected_begin_time %}{% translate 'Date de début prévisionnelle' %}{% else %}{% translate 'Date de création' %}{% endif %}">
|
||||||
|
{{ intervention.end_time|default:intervention.expected_end_time|default:intervention.expected_begin_time|default:intervention.creation_time|date:"d/m/Y" }}
|
||||||
|
</small>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,15 @@ class ImportFulcrumTreesCommandTest(TestCase):
|
||||||
self.assertEqual(tree.next_inspection_date, date(2025, 5, 10))
|
self.assertEqual(tree.next_inspection_date, date(2025, 5, 10))
|
||||||
self.assertEqual(tree.pruning_frequency_years, 1)
|
self.assertEqual(tree.pruning_frequency_years, 1)
|
||||||
|
|
||||||
|
# Vérifications événements de planification (timeline)
|
||||||
|
self.assertEqual(itv.planned_events.count(), 2)
|
||||||
|
begin_event = itv.planned_events.filter(event_type='expected_begin').first()
|
||||||
|
self.assertIsNotNone(begin_event)
|
||||||
|
self.assertEqual(begin_event.event_time.date(), date(2024, 5, 10))
|
||||||
|
end_event = itv.planned_events.filter(event_type='expected_end').first()
|
||||||
|
self.assertIsNotNone(end_event)
|
||||||
|
self.assertEqual(end_event.event_time.date(), date(2025, 5, 10))
|
||||||
|
|
||||||
# Vérification liaison InterventionAsset
|
# Vérification liaison InterventionAsset
|
||||||
links = InterventionAsset.objects.filter(intervention=itv)
|
links = InterventionAsset.objects.filter(intervention=itv)
|
||||||
self.assertEqual(links.count(), 1)
|
self.assertEqual(links.count(), 1)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue