loko/streetup/inspections/tests.py

334 lines
13 KiB
Python

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 django.utils import timezone
from assets.models import NatureRWIZ, NatureRWIAsset, ParkingSpot
from interventions.models import Intervention
from common.models import Thematic
from .models import Inspection, ParkingSpotInspection, GiepInspection, InspectionDocument
from .registry import get_inspection_partial_template
User = get_user_model()
class InspectionModelAndViewsTestCase(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user(
username='inspector_user',
password='password123',
first_name='Jean',
last_name='Valjean'
)
from common.models import UserConfig, Role, UserThematics
admin_role, _ = Role.objects.get_or_create(name='admin')
config = UserConfig.objects.create(user=self.user)
config.roles.add(admin_role)
self.water_thematic, _ = Thematic.objects.get_or_create(
code='water',
defaults={'name_fr': 'Gestion de l\'Eau / GIEP'}
)
UserThematics.objects.create(
user_config=config,
thematic=self.water_thematic,
can_view_assets=True,
can_edit_assets=True
)
self.thematic, _ = Thematic.objects.get_or_create(
code='parking',
defaults={'name_fr': 'Stationnement'}
)
self.spot = ParkingSpot.objects.create(
name_fr='Emplacement Vélo Test'
)
self.spot_ct = ContentType.objects.get_for_model(ParkingSpot)
self.rwiz = NatureRWIZ.objects.create(
name_fr='Zone GIEP Test'
)
self.rwiz_ct = ContentType.objects.get_for_model(NatureRWIZ)
self.mission_interv = Intervention.objects.create(
title="Mission inspection GIEP Nord",
thematic=self.thematic,
status="in_progress"
)
self.work_interv = Intervention.objects.create(
title="Travaux réfection par Prestataire A",
thematic=self.thematic,
status="done"
)
def test_inspection_creation_with_interventions(self):
insp = Inspection.objects.create(
asset_content_type=self.spot_ct,
asset_object_id=self.spot.id,
inspector=self.user,
mission_intervention=self.mission_interv,
checked_intervention=self.work_interv,
nature='technical',
inspector_role='provider',
result_status='compliant',
notes="Tiers contrôle OK"
)
self.assertTrue(insp.is_mission_inspection)
self.assertTrue(insp.is_cross_check)
self.assertEqual(insp.mission_intervention, self.mission_interv)
self.assertEqual(insp.checked_intervention, self.work_interv)
self.assertIn(insp, self.mission_interv.generated_inspections.all())
self.assertIn(insp, self.work_interv.quality_inspections.all())
def test_giep_inspection_model(self):
giep_insp = GiepInspection.objects.create(
asset_content_type=self.rwiz_ct,
asset_object_id=self.rwiz.id,
inspector=self.user,
result_status='compliant',
date_derniere_pluie='aujourdhui',
orage_moins_une_heure=True,
data={
'ouvrages': [
{'local_id': '0', 'device_type': 'evc', 'name': 'Noue 1'}
]
}
)
self.assertEqual(giep_insp.detailed_inspection, giep_insp)
self.assertIn("1 ouvrage(s) GIEP", giep_insp.details_summary)
self.assertIn(str(giep_insp.get_date_derniere_pluie_display()), giep_insp.details_summary)
def test_create_inspection_api(self):
self.client.login(username='inspector_user', password='password123')
url = reverse('inspections:create_inspection_api')
response = self.client.post(url, {
'content_type_id': self.spot_ct.id,
'object_id': self.spot.id,
'result_status': 'compliant',
'nature': 'visual',
'inspector_role': 'provider',
'mission_intervention_id': self.mission_interv.id,
'checked_intervention_id': self.work_interv.id,
'notes': 'Inspection via API'
})
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertTrue(data['success'])
insp = Inspection.objects.get(pk=data['inspection_id'])
self.assertEqual(insp.mission_intervention, self.mission_interv)
self.assertEqual(insp.checked_intervention, self.work_interv)
def test_create_giep_inspection_api(self):
self.client.login(username='inspector_user', password='password123')
url = reverse('inspections:create_inspection_api')
import json
giep_json = json.dumps({
'ouvrages': [
{'local_id': '0', 'device_type': 'evc', 'questions': {'engorgement': 'aucun'}}
]
})
response = self.client.post(url, {
'content_type_id': self.rwiz_ct.id,
'object_id': self.rwiz.id,
'result_status': 'compliant',
'nature': 'visual',
'inspector_role': 'observer',
'date_derniere_pluie': 'moins_24h',
'orage_moins_une_heure': 'false',
'giep_data': giep_json,
'notes': 'Inspection GIEP via API'
})
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertTrue(data['success'])
insp = GiepInspection.objects.get(pk=data['inspection_id'])
self.assertEqual(insp.date_derniere_pluie, 'moins_24h')
self.assertFalse(insp.orage_moins_une_heure)
self.assertEqual(len(insp.data.get('ouvrages', [])), 1)
def test_registry_giep_template(self):
tmpl_rwiz = get_inspection_partial_template('naturerwiz')
tmpl_asset = get_inspection_partial_template('naturerwiasset')
self.assertEqual(tmpl_rwiz, 'inspections/components/asset_fields/_naturerwiz.html')
self.assertIsNone(tmpl_asset)
def test_registry_detail_templates(self):
from .registry import get_inspection_detail_partial_template
giep_insp = GiepInspection(asset=self.rwiz)
parking_insp = ParkingSpotInspection(asset=self.spot)
tmpl_giep = get_inspection_detail_partial_template(giep_insp)
tmpl_parking = get_inspection_detail_partial_template(parking_insp)
self.assertEqual(tmpl_giep, 'inspections/components/asset_details/_naturerwiz.html')
self.assertEqual(tmpl_parking, 'inspections/components/asset_details/_parkingspot.html')
def test_zirw_detail_view_renders_cleanly(self):
self.client.login(username='inspector_user', password='password123')
url = reverse('assets:zirw_detail', kwargs={'location_id': self.rwiz.id})
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_spatial_location_resolution_for_rwi_asset(self):
from assets.templatetags.asset_tags import asset_location_link
from django.contrib.gis.geos import Polygon, MultiPolygon, Point
poly = Polygon(((0, 0), (0, 10), (10, 10), (10, 0), (0, 0)), srid=3812)
rwiz_poly = NatureRWIZ.objects.create(
code="RWIZ-TEST",
name_fr="Zone Test Polygons",
geom=MultiPolygon(poly, srid=3812)
)
rwi_asset = NatureRWIAsset.objects.create(
code="RWI-TEST-01",
geom=Point(5, 5, srid=3812)
)
ctx = asset_location_link({'request': None}, rwi_asset)
self.assertEqual(ctx['location'], rwiz_poly)
def test_can_edit_inspection_permissions(self):
other_user = User.objects.create_user(
username='regular_user',
password='password123'
)
insp = Inspection.objects.create(
asset_content_type=self.spot_ct,
asset_object_id=self.spot.id,
inspector=self.user,
result_status='compliant',
notes="Initial note"
)
# Author can edit
self.assertTrue(insp.can_edit(self.user))
# Superuser can edit
admin_user = User.objects.create_superuser(
username='admin_superuser',
password='password123'
)
self.assertTrue(insp.can_edit(admin_user))
# Other non-author non-admin cannot edit
self.assertFalse(insp.can_edit(other_user))
def test_update_inspection_api_author_success(self):
insp = Inspection.objects.create(
asset_content_type=self.spot_ct,
asset_object_id=self.spot.id,
inspector=self.user,
result_status='compliant',
notes="Initial note"
)
initial_updated_at = insp.updated_at
self.client.login(username='inspector_user', password='password123')
url = reverse('inspections:update_inspection_api', kwargs={'inspection_id': insp.id})
response = self.client.post(url, {
'result_status': 'non_compliant',
'notes': 'Modifié par auteur',
'nature': 'detailed'
})
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertTrue(data['success'])
insp.refresh_from_db()
self.assertEqual(insp.result_status, 'non_compliant')
self.assertEqual(insp.notes, 'Modifié par auteur')
self.assertEqual(insp.nature, 'detailed')
self.assertGreaterEqual(insp.updated_at, initial_updated_at)
def test_update_inspection_api_forbidden(self):
other_user = User.objects.create_user(
username='other_user_stranger',
password='password123'
)
insp = Inspection.objects.create(
asset_content_type=self.spot_ct,
asset_object_id=self.spot.id,
inspector=self.user,
result_status='compliant',
notes="Original note"
)
self.client.login(username='other_user_stranger', password='password123')
url = reverse('inspections:update_inspection_api', kwargs={'inspection_id': insp.id})
response = self.client.post(url, {
'result_status': 'damaged',
'notes': 'Hacked note'
})
self.assertEqual(response.status_code, 403)
data = response.json()
self.assertFalse(data['success'])
insp.refresh_from_db()
self.assertEqual(insp.result_status, 'compliant')
self.assertEqual(insp.notes, 'Original note')
def test_update_parking_spot_inspection_api(self):
from inspections.models import ParkingSpotInspection
ps_insp = ParkingSpotInspection.objects.create(
asset_content_type=self.spot_ct,
asset_object_id=self.spot.id,
inspector=self.user,
result_status='compliant',
notes="Initial parking inspection",
verified_standard_stand_count=5,
verified_cargo_stand_count=2,
verified_marking_quality='good'
)
self.client.login(username='inspector_user', password='password123')
url = reverse('inspections:update_inspection_api', kwargs={'inspection_id': ps_insp.id})
response = self.client.post(url, {
'result_status': 'partially_compliant',
'verified_standard_stand_count': '10',
'verified_cargo_stand_count': '4',
'verified_drop_off_stand_count': '1',
'verified_has_scooter_drop_zone': 'true',
'verified_marking_quality': 'damaged',
'apply_physical_counts_to_asset': 'true'
})
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertTrue(data['success'])
ps_insp.refresh_from_db()
self.assertEqual(ps_insp.result_status, 'partially_compliant')
self.assertEqual(ps_insp.verified_standard_stand_count, 10)
self.assertEqual(ps_insp.verified_cargo_stand_count, 4)
self.assertEqual(ps_insp.verified_drop_off_stand_count, 1)
self.assertTrue(ps_insp.verified_has_scooter_drop_zone)
self.assertEqual(ps_insp.verified_marking_quality, 'damaged')
def test_delete_inspection_document_api(self):
from inspections.models import InspectionDocument
from django.core.files.uploadedfile import SimpleUploadedFile
insp = Inspection.objects.create(
asset_content_type=self.spot_ct,
asset_object_id=self.spot.id,
inspector=self.user,
result_status='compliant'
)
dummy_file = SimpleUploadedFile("test_doc.txt", b"file content", content_type="text/plain")
doc = InspectionDocument.objects.create(
inspection=insp,
file=dummy_file
)
self.client.login(username='inspector_user', password='password123')
url = reverse('inspections:delete_inspection_document_api', kwargs={'document_id': doc.id})
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
self.assertTrue(response.json()['success'])
self.assertFalse(InspectionDocument.objects.filter(id=doc.id).exists())