from django.test import TestCase, Client from django.contrib.auth.models import User from django.contrib.gis.geos import Polygon, MultiPolygon from django.urls import reverse from django.utils import timezone from assets.models import ParkingLocation, ParkingSpot, AssetInspection, ParkingSpotInspection from common.models import Thematic, UserConfig, UserThematics class ParkingSpotAndInspectionTest(TestCase): def setUp(self): self.user = User.objects.create_user(username="inspector_user", password="password123") self.client = Client() # Create thematic and user thematic permissions self.thematic, _ = Thematic.objects.get_or_create( code="parking", defaults={ "name_fr": "Stationnement & Mobilité", "name_nl": "Parkeren & Mobiliteit" } ) self.user_config = UserConfig.objects.create(user=self.user) UserThematics.objects.create( user_config=self.user_config, thematic=self.thematic, can_view_assets=True ) self.client.force_login(self.user) poly = Polygon(((648000, 670000), (648010, 670000), (648010, 670010), (648000, 670010), (648000, 670000)), srid=3812) multi_poly = MultiPolygon(poly, srid=3812) self.parking_loc = ParkingLocation.objects.create( code="PARK-LOC-01", name_fr="Zone vélo Grand Place", geom=multi_poly ) self.spot = ParkingSpot.objects.create( code="SPOT-VELO-01", name_fr="Stationnement vélo Grand Place", location=self.parking_loc, spot_type="bicycle", standard_stand_count=3, cargo_stand_count=2, stand_type="mixed", has_scooter_drop_zone=True, scooter_capacity=10, geom=poly ) def test_parking_spot_creation_and_stand_counts(self): self.assertEqual(self.spot.standard_stand_count, 3) self.assertEqual(self.spot.cargo_stand_count, 2) self.assertEqual(self.spot.total_stand_count, 5) self.assertTrue(self.spot.has_scooter_drop_zone) self.assertTrue(self.spot.is_compliant) self.assertEqual(self.spot.inspection_status, "unknown") self.assertIsNotNone(self.spot.geojson) def test_parking_spot_inspection_default_does_not_update_counts(self): # Par défaut, apply_physical_counts_to_asset est False inspection = ParkingSpotInspection.objects.create( asset=self.spot, inspector=self.user, inspection_date=timezone.now(), result_status="updated", verified_standard_stand_count=4, verified_cargo_stand_count=3, verified_has_scooter_drop_zone=True, verified_marking_quality="good", apply_changes_to_asset=True, apply_physical_counts_to_asset=False, notes="Arceaux constatés" ) self.spot.refresh_from_db() self.assertEqual(self.spot.standard_stand_count, 3) # Non modifié self.assertEqual(self.spot.cargo_stand_count, 2) # Non modifié self.assertEqual(self.spot.validation_status, "validated") # Statut génerique mis à jour self.assertEqual(self.spot.inspection_status, "updated") def test_parking_spot_inspection_with_counts_opt_in_updates_asset(self): inspection = ParkingSpotInspection.objects.create( asset=self.spot, inspector=self.user, inspection_date=timezone.now(), result_status="updated", verified_standard_stand_count=4, verified_cargo_stand_count=3, verified_has_scooter_drop_zone=True, verified_marking_quality="good", apply_changes_to_asset=True, apply_physical_counts_to_asset=True, notes="Ajout récent de 1 arceau classique et 1 arceau cargo" ) self.spot.refresh_from_db() self.assertEqual(self.spot.standard_stand_count, 4) # Modifié avec l'opt-in self.assertEqual(self.spot.cargo_stand_count, 3) # Modifié avec l'opt-in self.assertEqual(self.spot.total_stand_count, 7) self.assertEqual(self.spot.validation_status, "validated") self.assertEqual(self.spot.inspection_status, "updated") self.assertIsNotNone(self.spot.last_inspection_date) self.assertTrue(self.spot.is_compliant) def test_generic_asset_inspection_non_compliance(self): inspection = AssetInspection.objects.create( asset=self.spot, inspector=self.user, inspection_date=timezone.now(), result_status="non_compliant", notes="Arceau cargo tordu suite à un choc de livraison", apply_changes_to_asset=True ) self.spot.refresh_from_db() self.assertFalse(self.spot.is_compliant) self.assertEqual(self.spot.inspection_status, "non_compliant") self.assertEqual(self.spot.non_compliance_reason, "Arceau cargo tordu suite à un choc de livraison") def test_parking_assets_geojson_view(self): url = reverse('assets:parking_assets_geojson') response = self.client.get(url) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(data.get("type"), "FeatureCollection") features = data.get("features", []) self.assertEqual(len(features), 1) feat = features[0] self.assertEqual(feat["properties"]["code"], "SPOT-VELO-01") self.assertEqual(feat["properties"]["standard_stand_count"], 3) self.assertEqual(feat["properties"]["cargo_stand_count"], 2) self.assertEqual(feat["properties"]["total_stand_count"], 5) self.assertTrue(feat["properties"]["has_scooter_drop_zone"]) def test_parking_assets_autocomplete_view(self): url = reverse('assets:parking_autocomplete_assets') response = self.client.get(url, {'q': 'Grand Place'}) self.assertEqual(response.status_code, 200) data = response.json() results = data.get("results", []) self.assertEqual(len(results), 1) self.assertEqual(results[0]["code"], "SPOT-VELO-01") def test_parking_thematic_config(self): from assets.views.core import build_thematic_config config = build_thematic_config([self.thematic]) self.assertIn("parking", config) self.assertEqual(config["parking"]["assets_geojson_url"], reverse("assets:parking_assets_geojson")) self.assertEqual(config["parking"]["locations_geojson_url"], reverse("assets:parking_locations_geojson"))