from django.test import TestCase, Client from django.urls import reverse from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from assets.models.parking import ParkingSpot from assets.models.inspection import AssetInspection, ParkingSpotInspection from interventions.models import Intervention User = get_user_model() class InspectionViewsTestCase(TestCase): def setUp(self): self.user = User.objects.create_user( username='test_inspector', password='password123', first_name='Jean', last_name='Dupont' ) from common.models import UserConfig UserConfig.objects.get_or_create(user=self.user) self.client = Client() self.client.login(username='test_inspector', password='password123') self.spot = ParkingSpot.objects.create( code='PK-001', name_fr='Emplacement Vélo Test', spot_type='bicycle', standard_stand_count=5 ) self.spot_ct = ContentType.objects.get_for_model(ParkingSpot) def test_inspections_list_view(self): insp = AssetInspection.objects.create( asset_content_type=self.spot_ct, asset_object_id=self.spot.id, inspector=self.user, result_status='compliant', nature='visual' ) response = self.client.get(reverse('assets:inspections_list')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'PK-001') self.assertContains(response, 'Mes inspections') def test_quick_inspection_map_view(self): response = self.client.get(reverse('assets:quick_inspection_map')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Inspection Rapide') def test_quick_inspection_map_mobile_view(self): response = self.client.get(reverse('mobile:quick_inspection_map_mobile')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Inspection Rapide') def test_create_inspection_api_compliant(self): response = self.client.post(reverse('assets:create_inspection_api'), { 'content_type_id': self.spot_ct.id, 'object_id': self.spot.id, 'result_status': 'compliant', 'nature': 'visual', 'inspector_role': 'observer', 'notes': 'Tout est parfait', }) self.assertEqual(response.status_code, 200) data = response.json() self.assertTrue(data['success']) self.spot.refresh_from_db() self.assertEqual(self.spot.inspection_status, 'compliant') self.assertTrue(self.spot.is_compliant) def test_create_inspection_api_damaged_creates_intervention(self): response = self.client.post(reverse('assets:create_inspection_api'), { 'content_type_id': self.spot_ct.id, 'object_id': self.spot.id, 'result_status': 'damaged', 'nature': 'visual', 'notes': 'Arceau tordu', 'create_intervention': 'true', }) self.assertEqual(response.status_code, 200) data = response.json() self.assertTrue(data['success']) self.assertIsNotNone(data['created_intervention_code']) self.spot.refresh_from_db() self.assertEqual(self.spot.inspection_status, 'damaged') self.assertFalse(self.spot.is_compliant) interv = Intervention.objects.filter(code=data['created_intervention_code']).first() self.assertIsNotNone(interv) self.assertEqual(interv.status, 'in_preparation') def test_quick_inspection_map_permissions_can_inspect(self): from common.models import UserConfig, UserThematics, Thematic t_parking = Thematic.objects.get(code='parking') t_other, _ = Thematic.objects.get_or_create(code='publiclighting', defaults={'name_fr': 'Éclairage public'}) user_config, _ = UserConfig.objects.get_or_create(user=self.user) UserThematics.objects.create(user_config=user_config, thematic=t_parking, can_inspect=True) UserThematics.objects.create(user_config=user_config, thematic=t_other, can_inspect=False) response = self.client.get(reverse('assets:quick_inspection_map')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'parking') self.assertNotContains(response, 'publiclighting') def test_no_inspectable_thematic_hides_button_and_returns_403(self): from common.models import UserConfig, UserThematics, Thematic t_parking = Thematic.objects.get(code='parking') user_config, _ = UserConfig.objects.get_or_create(user=self.user) UserThematics.objects.create(user_config=user_config, thematic=t_parking, can_inspect=False) # 1. Page liste des inspections -> Bouton 'Nouvelle inspection' masqué resp_list = self.client.get(reverse('assets:inspections_list')) self.assertEqual(resp_list.status_code, 200) self.assertNotContains(resp_list, reverse('assets:quick_inspection_map')) # 2. Tentative d'accès direct à quick_inspection_map -> HTTP 403 Forbidden resp_map = self.client.get(reverse('assets:quick_inspection_map')) self.assertEqual(resp_map.status_code, 403) def test_create_inspection_api_with_photo(self): from django.core.files.uploadedfile import SimpleUploadedFile test_photo = SimpleUploadedFile("test_inspection.jpg", b"fake_image_bytes", content_type="image/jpeg") response = self.client.post(reverse('assets:create_inspection_api'), { 'content_type_id': self.spot_ct.id, 'object_id': self.spot.id, 'result_status': 'compliant', 'nature': 'visual', 'notes': 'Inspection avec photo', 'photos': [test_photo], }) self.assertEqual(response.status_code, 200) data = response.json() self.assertTrue(data['success']) inspection = AssetInspection.objects.get(id=data['inspection_id']) self.assertEqual(inspection.documents.count(), 1) doc = inspection.documents.first() self.assertTrue(doc.is_image) self.assertTrue(doc.filename.startswith('test_inspection')) def test_inspections_geojson_view(self): from django.contrib.gis.geos import Polygon self.spot.geom = Polygon(((4.35, 50.85), (4.36, 50.85), (4.36, 50.86), (4.35, 50.86), (4.35, 50.85)), srid=4326) self.spot.save() insp = AssetInspection.objects.create( asset_content_type=self.spot_ct, asset_object_id=self.spot.id, inspector=self.user, result_status='compliant', nature='visual' ) response = self.client.post( reverse('assets:inspections_geojson'), data={'thematic': 'parking', 'period': '3m'}, content_type='application/json' ) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(data['type'], 'FeatureCollection') self.assertEqual(data['features'][0]['properties']['inspections'][0]['id'], insp.id) self.assertEqual(data['features'][0]['properties']['inspections_count'], 1) def test_inspections_list_search_by_asset_code(self): self.spot.code = "SPOT-TEST-SEARCH-99" self.spot.save() insp = AssetInspection.objects.create( asset_content_type=self.spot_ct, asset_object_id=self.spot.id, inspector=self.user, result_status='compliant', nature='visual' ) response = self.client.get(reverse('assets:inspections_list') + '?tab=all&q=SEARCH-99') self.assertEqual(response.status_code, 200) self.assertIn(insp, response.context['inspections']) def test_inspections_list_filter_thematics_uses_can_view_assets(self): from common.models import UserConfig, UserThematics, Thematic t_parking = Thematic.objects.get(code='parking') t_lighting, _ = Thematic.objects.get_or_create(code='publiclighting', defaults={'name_fr': 'Éclairage public'}) user_config, _ = UserConfig.objects.get_or_create(user=self.user) # L'utilisateur a les droits de voir les assets parking mais pas d'inspecter, et pas de voir l'éclairage public UserThematics.objects.create(user_config=user_config, thematic=t_parking, can_view_assets=True, can_inspect=False) UserThematics.objects.create(user_config=user_config, thematic=t_lighting, can_view_assets=False, can_inspect=False) resp = self.client.get(reverse('assets:inspections_list')) self.assertEqual(resp.status_code, 200) self.assertIn(t_parking, resp.context['thematics']) self.assertNotIn(t_lighting, resp.context['thematics']) self.assertFalse(resp.context['can_inspect']) def test_user_without_config_returns_none(self): from assets.views.inspections import get_user_viewable_thematics, get_user_inspectable_thematics user_no_config = User.objects.create_user(username='no_config_user', password='pwd') self.assertIsNone(get_user_viewable_thematics(user_no_config)) self.assertIsNone(get_user_inspectable_thematics(user_no_config)) def test_asset_inspections_templatetag(self): from assets.templatetags.asset_tags import asset_inspections from assets.models import AssetInspection insp = AssetInspection.objects.create( asset=self.spot, inspector=self.user, result_status='compliant', nature='visual' ) dummy_context = {'request': self.client.get('/').wsgi_request} data = asset_inspections(dummy_context, self.spot) self.assertEqual(data['total_count'], 1) self.assertIn(insp, data['inspections']) self.assertEqual(data['asset_pk'], self.spot.pk)