diff --git a/loko/assets/locale/en/LC_MESSAGES/django.mo b/loko/assets/locale/en/LC_MESSAGES/django.mo
index 7403fb2..0907baa 100644
Binary files a/loko/assets/locale/en/LC_MESSAGES/django.mo and b/loko/assets/locale/en/LC_MESSAGES/django.mo differ
diff --git a/loko/assets/locale/en/LC_MESSAGES/django.po b/loko/assets/locale/en/LC_MESSAGES/django.po
index de2ba79..12c34b9 100644
--- a/loko/assets/locale/en/LC_MESSAGES/django.po
+++ b/loko/assets/locale/en/LC_MESSAGES/django.po
@@ -7366,6 +7366,10 @@ msgstr "GIEP zones"
msgid "Aucune localisation GIEP trouvée à proximité"
msgstr "No location found"
+#: assets/templates/assets/trafficlights_intersection_detail.html:52
+msgid "Modèle du contrôleur"
+msgstr "Controller model"
+
#~ msgid "StreetUp"
#~ msgstr "StreetUp"
diff --git a/loko/assets/locale/fr/LC_MESSAGES/django.mo b/loko/assets/locale/fr/LC_MESSAGES/django.mo
index 6814813..b163d65 100644
Binary files a/loko/assets/locale/fr/LC_MESSAGES/django.mo and b/loko/assets/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/loko/assets/locale/fr/LC_MESSAGES/django.po b/loko/assets/locale/fr/LC_MESSAGES/django.po
index f29f9e8..9d0c0a7 100644
--- a/loko/assets/locale/fr/LC_MESSAGES/django.po
+++ b/loko/assets/locale/fr/LC_MESSAGES/django.po
@@ -7417,6 +7417,10 @@ msgstr "Zones GIEP"
msgid "Aucune localisation GIEP trouvée à proximité"
msgstr "Aucune localisation GIEP trouvée à proximité"
+#: assets/templates/assets/trafficlights_intersection_detail.html:52
+msgid "Modèle du contrôleur"
+msgstr "Modèle du contrôleur"
+
#~ msgid "StreetUp"
#~ msgstr "StreetUp"
diff --git a/loko/assets/locale/nl/LC_MESSAGES/django.mo b/loko/assets/locale/nl/LC_MESSAGES/django.mo
index ac13f1e..c78b6f2 100644
Binary files a/loko/assets/locale/nl/LC_MESSAGES/django.mo and b/loko/assets/locale/nl/LC_MESSAGES/django.mo differ
diff --git a/loko/assets/locale/nl/LC_MESSAGES/django.po b/loko/assets/locale/nl/LC_MESSAGES/django.po
index 58d42ca..7c6165d 100644
--- a/loko/assets/locale/nl/LC_MESSAGES/django.po
+++ b/loko/assets/locale/nl/LC_MESSAGES/django.po
@@ -7360,6 +7360,10 @@ msgstr "GIEP-zones"
msgid "Aucune localisation GIEP trouvée à proximité"
msgstr "Geen locatie gevonden."
+#: assets/templates/assets/trafficlights_intersection_detail.html:52
+msgid "Modèle du contrôleur"
+msgstr "Controllermodel"
+
#~ msgid "StreetUp"
#~ msgstr "StraatUp"
diff --git a/loko/assets/models/trafficlights.py b/loko/assets/models/trafficlights.py
index e083269..61819c2 100644
--- a/loko/assets/models/trafficlights.py
+++ b/loko/assets/models/trafficlights.py
@@ -192,6 +192,18 @@ class TrafficLightIntersection(AbstractLocation):
latest_controller = self.controllers.filter(status='active').order_by('-installation_date').first()
return latest_controller.connected_to_control_center if latest_controller else None
+ @property
+ def controller_model_name(self):
+ """
+ Get the model name of the active controller (or most recently installed controller).
+ """
+ latest_controller = self.controllers.filter(status='active').order_by('-installation_date').first()
+ if not latest_controller:
+ latest_controller = self.controllers.order_by('-installation_date').first()
+ if latest_controller and latest_controller.model:
+ return latest_controller.model.get_name() or latest_controller.model.code
+ return None
+
def get_absolute_url(self):
return reverse("assets:trafficlights_intersections_detail", kwargs={"intersection_id": self.id})
diff --git a/loko/assets/templates/assets/trafficlights_intersection_detail.html b/loko/assets/templates/assets/trafficlights_intersection_detail.html
index c1e4160..cf65ce4 100644
--- a/loko/assets/templates/assets/trafficlights_intersection_detail.html
+++ b/loko/assets/templates/assets/trafficlights_intersection_detail.html
@@ -48,6 +48,8 @@
{% endif %}
{{ intersection.current_index|default:""}}
+
+ {{ intersection.controller_model_name|default:""}}
{% if intersection.master %}
{{ intersection.master.code|default:"/" }}
diff --git a/loko/assets/tests.py b/loko/assets/tests.py
index e9562f8..19f58d2 100644
--- a/loko/assets/tests.py
+++ b/loko/assets/tests.py
@@ -3235,3 +3235,102 @@ class CreateInterventionForAssetWorkflowTest(TestCase):
self.assertEqual(first_event.event_user, self.user)
+class TrafficLightIntersectionControllerModelTest(TestCase):
+ def setUp(self):
+ self.thematic, _ = Thematic.objects.get_or_create(
+ code="trafficlights",
+ defaults={
+ "name_fr": "Feux de signalisation",
+ "name_nl": "Verkeerslichten"
+ }
+ )
+ self.user, _ = User.objects.get_or_create(username="tl_ctrl_testuser")
+ self.user.set_password("password123")
+ self.user.save()
+ self.config, _ = UserConfig.objects.get_or_create(user=self.user, defaults={"limit_assets_to_contracts": False})
+ self.config.limit_assets_to_contracts = False
+ self.config.save()
+ UserThematics.objects.get_or_create(
+ user_config=self.config,
+ thematic=self.thematic,
+ defaults={"can_view_assets": True}
+ )
+
+ from django.contrib.gis.geos import Point
+ geom_intersection = Point(648000, 670000, srid=3812)
+
+ self.intersection = TrafficLightIntersection.objects.create(
+ code="TL_INT_001",
+ name_fr="Carrefour Test",
+ geom=geom_intersection,
+ lon=4.3508,
+ lat=50.8465,
+ current_index="IDX-12345"
+ )
+
+ self.category, _ = AssetCategory.objects.get_or_create(
+ code="TL_CONTROLLER_CAT",
+ defaults={
+ "name_fr": "Contrôleur de trafic",
+ "name_nl": "Verkeersregelaar",
+ "thematic": self.thematic
+ }
+ )
+
+ from assets.models import TrafficLightControllerModel, TrafficLightController
+ self.controller_model = TrafficLightControllerModel.objects.create(
+ code="CTRL_MOD_01",
+ name_fr="Siemens Sitraffic C1000",
+ name_nl="Siemens Sitraffic C1000 NL",
+ category=self.category
+ )
+
+ self.controller = TrafficLightController.objects.create(
+ code="CTRL_001",
+ intersection=self.intersection,
+ model=self.controller_model,
+ geom=geom_intersection,
+ lon=4.3508,
+ lat=50.8465,
+ status="active"
+ )
+
+ def test_controller_model_name_property(self):
+ self.assertEqual(self.intersection.controller_model_name, "Siemens Sitraffic C1000")
+
+ def test_controller_model_name_none_when_no_controller(self):
+ from django.contrib.gis.geos import Point
+ empty_intersection = TrafficLightIntersection.objects.create(
+ code="TL_INT_EMPTY",
+ name_fr="Carrefour Sans Contrôleur",
+ geom=Point(648000, 670000, srid=3812)
+ )
+ self.assertIsNone(empty_intersection.controller_model_name)
+
+ def test_detail_view_renders_controller_model_name(self):
+ self.client.force_login(self.user)
+ # Test French
+ response_fr = self.client.get(
+ reverse("assets:trafficlights_intersections_detail", args=[self.intersection.id]),
+ HTTP_HOST="localhost",
+ HTTP_ACCEPT_LANGUAGE="fr"
+ )
+ self.assertEqual(response_fr.status_code, 200)
+ content_fr = response_fr.content.decode("utf-8")
+ self.assertIn("Modèle du contrôleur", content_fr)
+ self.assertIn("Siemens Sitraffic C1000", content_fr)
+ self.assertIn("IDX-12345", content_fr)
+
+ # Test Dutch
+ response_nl = self.client.get(
+ reverse("assets:trafficlights_intersections_detail", args=[self.intersection.id]),
+ HTTP_HOST="localhost",
+ HTTP_ACCEPT_LANGUAGE="nl"
+ )
+ self.assertEqual(response_nl.status_code, 200)
+ content_nl = response_nl.content.decode("utf-8")
+ self.assertIn("Controllermodel", content_nl)
+ self.assertIn("Siemens Sitraffic C1000 NL", content_nl)
+
+
+