- 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
237 lines
10 KiB
Python
237 lines
10 KiB
Python
import json
|
|
import tempfile
|
|
import os
|
|
from datetime import date
|
|
from django.test import TestCase
|
|
from django.core.management import call_command
|
|
from django.contrib.gis.geos import Point
|
|
|
|
from common.models import Thematic
|
|
from assets.models import NatureTree, AssetCategory
|
|
from contracts.models import Contract, ContractOrder, Company
|
|
from interventions.models import Intervention, InterventionAsset
|
|
|
|
|
|
class ImportFulcrumTreesCommandTest(TestCase):
|
|
def setUp(self):
|
|
self.thematic = Thematic.objects.create(name_fr="Nature", name_nl="Natuur")
|
|
self.category = AssetCategory.objects.create(id=60, name_fr="Arbres", name_nl="Bomen")
|
|
self.company = Company.objects.create(name="Krinkels")
|
|
self.contract = Contract.objects.create(
|
|
company=self.company,
|
|
contract_number="E19.051",
|
|
description="Marché E19.051",
|
|
start_date=date(2020, 1, 1),
|
|
end_date=date(2030, 12, 31)
|
|
)
|
|
self.contract.thematics.add(self.thematic)
|
|
|
|
def test_import_fulcrum_trees_and_interventions(self):
|
|
# 1. Préparer gestion.csv temporaire
|
|
gestion_content = (
|
|
"com_id,com_typ,com_nom,_status,com_dat,com_ech\n"
|
|
"BC-TEST-001,Marché E19.051 - Diagnostic,Élagage test,commande,2024-05-10,2024-06-15\n"
|
|
)
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f_ges:
|
|
f_ges.write(gestion_content)
|
|
ges_path = f_ges.name
|
|
|
|
# 2. Préparer arbes.geojson temporaire
|
|
mock_tree_uuid = "11111111-2222-3333-4444-555555555555"
|
|
tree_geojson = {
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{
|
|
"type": "Feature",
|
|
"geometry": {
|
|
"type": "Point",
|
|
"coordinates": [4.3517, 50.8503]
|
|
},
|
|
"properties": {
|
|
"_record_id": mock_tree_uuid,
|
|
"id_sit_pos": "099.01.001",
|
|
"id_visuel": "V-9901",
|
|
"sit_id": "099.01",
|
|
"pos_id": "001",
|
|
"sit_nom": "Boulevard du Test",
|
|
"comm_commune": "Bruxelles",
|
|
"arb_ess": "Platanus x hispanica",
|
|
"arb_vern": "Platane commun",
|
|
"arb_tax": "Platanus hispanica",
|
|
"arb_haut": 18.5,
|
|
"arb_circ": 140.0,
|
|
"arb_diam_tmp": 8.0,
|
|
"arb_st": "V",
|
|
"arb_vital": "Bo",
|
|
"arb_ont": "Ad",
|
|
"ges_conduite": "LI",
|
|
"cf_sit": 4.5,
|
|
"arb_anpla": "1995",
|
|
"maj_date": "2024-05-10T00:00:00.000Z"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.geojson', delete=False) as f_arb:
|
|
json.dump(tree_geojson, f_arb)
|
|
arb_path = f_arb.name
|
|
|
|
# 3. Préparer interventions.geojson temporaire
|
|
mock_itv_uuid = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
|
itv_geojson = {
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{
|
|
"type": "Feature",
|
|
"geometry": {
|
|
"type": "Point",
|
|
"coordinates": [4.3517, 50.8503]
|
|
},
|
|
"properties": {
|
|
"_record_id": mock_itv_uuid,
|
|
"_title": "099.01.001, Formation, Dans 1 an",
|
|
"rec_interv_com": "Taille branches basses",
|
|
"sit_nom": "Boulevard du Test",
|
|
"comm_commune": "Bruxelles",
|
|
"sit_id": "099.01",
|
|
"pos_id": "001",
|
|
"dia_comma": "BC-TEST-001",
|
|
"dia_date": "2024-05-10T00:00:00.000Z",
|
|
"in_deadline": "2025-05-10T00:00:00.000Z",
|
|
"rec_delai": "Pla-1",
|
|
"rec_interv": "FO",
|
|
"in_fin_yn": "no",
|
|
"mater_arbres_lk": [mock_tree_uuid]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.geojson', delete=False) as f_itv:
|
|
json.dump(itv_geojson, f_itv)
|
|
itv_path = f_itv.name
|
|
|
|
try:
|
|
# Exécuter la commande
|
|
call_command(
|
|
'import_fulcrum_trees',
|
|
arbes_file=arb_path,
|
|
gestion_file=ges_path,
|
|
interventions_file=itv_path,
|
|
managing_authority="Test Authority",
|
|
management_type="regional",
|
|
code_prefix="TEST-ARB-"
|
|
)
|
|
|
|
# Vérifications gestion / bon de commande
|
|
order = ContractOrder.objects.filter(order_code="BC-TEST-001").first()
|
|
self.assertIsNotNone(order)
|
|
self.assertEqual(order.contract.contract_number, "E19.051")
|
|
self.assertEqual(order.order_status, "sent")
|
|
|
|
# Vérifications arbre
|
|
tree = NatureTree.objects.filter(external_reference=mock_tree_uuid).first()
|
|
self.assertIsNotNone(tree)
|
|
self.assertEqual(tree.code, "TEST-ARB-099.01.001")
|
|
self.assertEqual(tree.managing_authority, "Test Authority")
|
|
self.assertEqual(tree.management_type, "regional")
|
|
self.assertEqual(tree.circumference, 140.0)
|
|
self.assertEqual(tree.height, 18.5)
|
|
self.assertIsNotNone(tree.amenity_value)
|
|
self.assertGreater(tree.amenity_value, 0)
|
|
self.assertIsNotNone(tree.carbon_stock)
|
|
self.assertGreater(tree.carbon_stock, 0)
|
|
self.assertIsNotNone(tree.cooling_indicator)
|
|
|
|
# Vérifications intervention
|
|
itv = Intervention.objects.filter(source_ref=mock_itv_uuid).first()
|
|
self.assertIsNotNone(itv)
|
|
self.assertEqual(itv.order_id, order.id)
|
|
self.assertEqual(itv.priority, "3") # Pla-1 -> 3
|
|
self.assertEqual(itv.status, "to_be_planned")
|
|
self.assertIsNotNone(itv.expected_begin_time)
|
|
self.assertEqual(itv.expected_begin_time.date(), date(2024, 5, 10))
|
|
self.assertIsNotNone(itv.expected_end_time)
|
|
self.assertEqual(itv.expected_end_time.date(), date(2025, 5, 10))
|
|
|
|
# Vérifications dates de maintenance sur l'arbre
|
|
self.assertEqual(tree.last_phytosanitary_date, date(2024, 5, 10))
|
|
self.assertEqual(tree.next_inspection_date, date(2025, 5, 10))
|
|
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
|
|
links = InterventionAsset.objects.filter(intervention=itv)
|
|
self.assertEqual(links.count(), 1)
|
|
self.assertEqual(links.first().object_id, tree.id)
|
|
|
|
# Test mise à jour sans duplication
|
|
tree_geojson['features'][0]['properties']['arb_circ'] = 145.0
|
|
with open(arb_path, 'w') as f_arb_update:
|
|
json.dump(tree_geojson, f_arb_update)
|
|
|
|
call_command(
|
|
'import_fulcrum_trees',
|
|
arbes_file=arb_path,
|
|
gestion_file=ges_path,
|
|
interventions_file=itv_path,
|
|
skip_gestion=True,
|
|
skip_interventions=True
|
|
)
|
|
|
|
# Le nombre d'arbres ne doit pas avoir augmenté
|
|
self.assertEqual(NatureTree.objects.filter(external_reference=mock_tree_uuid).count(), 1)
|
|
tree.refresh_from_db()
|
|
self.assertEqual(tree.circumference, 145.0)
|
|
|
|
finally:
|
|
if os.path.exists(ges_path): os.remove(ges_path)
|
|
if os.path.exists(arb_path): os.remove(arb_path)
|
|
if os.path.exists(itv_path): os.remove(itv_path)
|
|
|
|
def test_import_fulcrum_regional_trees_alias(self):
|
|
from io import StringIO
|
|
out = StringIO()
|
|
call_command('import_fulcrum_regional_trees', skip_trees=True, skip_gestion=True, skip_interventions=True, stdout=out)
|
|
self.assertIn("FIN DE L'IMPORTATION", out.getvalue())
|
|
|
|
def test_attach_trees_to_green_sections(self):
|
|
from assets.models import NatureLocation
|
|
from django.contrib.gis.geos import Polygon, MultiPolygon
|
|
# Créer une section verte polygonale
|
|
poly = Polygon(((648000, 670000), (648100, 670000), (648100, 670100), (648000, 670100), (648000, 670000)), srid=3812)
|
|
loc = NatureLocation.objects.create(
|
|
code="WAT_R22_008",
|
|
name_fr="Boulevard du Souverain",
|
|
geom=MultiPolygon(poly, srid=3812)
|
|
)
|
|
# Créer un arbre à l'intérieur du polygone (sans location)
|
|
pt = Point(648050, 670050, srid=3812)
|
|
pt_4326 = pt.clone().transform(4326, clone=True)
|
|
tree = NatureTree.objects.create(
|
|
code="TR-ATTACH-TEST",
|
|
name_fr="Arbre test Souverain",
|
|
category=self.category,
|
|
geom=pt,
|
|
lon=pt_4326.x,
|
|
lat=pt_4326.y,
|
|
location=None
|
|
)
|
|
self.assertEqual(loc.nature_trees.count(), 0)
|
|
|
|
# Exécuter le rattachement
|
|
call_command('attach_trees_to_green_sections', max_distance=25, skip_sync_munis=True)
|
|
|
|
tree.refresh_from_db()
|
|
self.assertEqual(tree.location_id, loc.id)
|
|
self.assertEqual(loc.nature_trees.count(), 1)
|
|
|
|
|
|
|