From 6b8978254b959fd8b1746b699e5bbdc2f5455cce Mon Sep 17 00:00:00 2001 From: Karl Determe Date: Thu, 27 Aug 2026 16:06:34 +0200 Subject: [PATCH] feat: add unit tests and views for asset editing and export functionality --- loko/assets/tests.py | 66 ++++++++++++++++++++++++++++++ loko/assets/views/asset_editing.py | 16 +++++--- loko/assets/views/export.py | 6 ++- 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/loko/assets/tests.py b/loko/assets/tests.py index 19b89d2..da1c3d8 100644 --- a/loko/assets/tests.py +++ b/loko/assets/tests.py @@ -3964,5 +3964,71 @@ class TrafficLightProgrammingTest(TestCase): self.assertIn("addProgrammingModal", content) +class ReplaceAssetStructureGeoAssetTest(TestCase): + def setUp(self): + from common.models import Thematic, UserConfig, UserThematics, Role + from assets.models.structures import Structure, StructureLocation, StructureGeoAsset, StructureAssetModel + from assets.models import AssetCategory + + self.thematic = Thematic.objects.create(code="structures", name_fr="Ouvrages d'art") + self.user = User.objects.create_user(username="replace_user", password="password") + self.user_config = UserConfig.objects.create(user=self.user, is_intern=True) + self.admin_role, _ = Role.objects.get_or_create(name='admin') + self.user_config.roles.add(self.admin_role) + + self.user_thematic = UserThematics.objects.create( + user_config=self.user_config, + thematic=self.thematic, + can_view_assets=True, + can_edit_assets=True, + ) + + self.struct = Structure.objects.create(code="WTB99", name_fr="Tunnel Test") + self.loc = StructureLocation.objects.create(code="WTB99A", name_fr="Location Test", structure=self.struct) + self.category = AssetCategory.objects.create(thematic=self.thematic, code="CAT_TEST", name_fr="Cat Test") + self.model = StructureAssetModel.objects.create(code="MOD_TEST", name_fr="Mod Test", category=self.category) + self.asset = StructureGeoAsset.objects.create( + code="WTB99A-000001", + name_fr="Asset Original", + structure=self.struct, + location=self.loc, + model=self.model, + category=self.category, + status="active" + ) + + def test_replace_asset_structuregeoasset_success(self): + from django.urls import reverse + from assets.models.structures import StructureGeoAsset + + self.client.force_login(self.user) + url = reverse('assets:replace_asset', kwargs={'asset_model': 'structuregeoasset', 'asset_id': self.asset.id}) + + response = self.client.post( + url, + data=json.dumps({'copy_attributes': True}), + content_type='application/json' + ) + self.assertEqual(response.status_code, 200) + data = response.json() + self.assertTrue(data['success']) + + # Old asset should be archived and marked as removed + self.asset.refresh_from_db() + self.assertEqual(self.asset.status, 'removed') + self.assertIsNotNone(self.asset.replaced_by) + self.assertNotEqual(self.asset.code, "WTB99A-000001") + + # New asset should have the original code and status active + new_asset = self.asset.replaced_by + self.assertEqual(new_asset.code, "WTB99A-000001") + self.assertEqual(new_asset.status, "active") + self.assertEqual(new_asset.structure, self.struct) + self.assertEqual(new_asset.location, self.loc) + self.assertEqual(new_asset.model, self.model) + self.assertEqual(new_asset.name_fr, "Asset Original") + + + diff --git a/loko/assets/views/asset_editing.py b/loko/assets/views/asset_editing.py index eaf7632..45d0061 100644 --- a/loko/assets/views/asset_editing.py +++ b/loko/assets/views/asset_editing.py @@ -632,8 +632,8 @@ def replace_asset(request, asset_model, asset_id): # Copy attributes if requested if copy_attributes: - for field in model_class._meta.get_fields(): - if field.auto_created or field.name in ('id', 'code', 'replaced_by'): + for field in model_class._meta.fields: + if field.primary_key or field.name in ('id', 'code', 'replaced_by', 'marked_as_removed_date', 'marked_as_removed_by', 'uninstallation_date'): continue if hasattr(asset, field.name): setattr(new_asset, field.name, getattr(asset, field.name)) @@ -642,6 +642,10 @@ def replace_asset(request, asset_model, asset_id): new_asset.status = 'active' new_asset.installation_date = timezone.now() new_asset.uninstallation_date = None + new_asset.marked_as_removed_date = None + new_asset.marked_as_removed_by = None + if hasattr(new_asset, 'updated_by') and request.user.is_authenticated: + new_asset.updated_by = request.user # Override with new data for field_name, value in new_data.items(): @@ -845,8 +849,8 @@ def create_asset(request, thematic_code, location_type, location_id): # Find the ForeignKey field that points to the location model location_set = False - for field in model_class._meta.get_fields(): - if hasattr(field, 'related_model') and field.related_model: + for field in model_class._meta.fields: + if field.is_relation and field.many_to_one and field.related_model: related_model_name = field.related_model._meta.model_name.lower() if related_model_name == location_model_name: # This is a ForeignKey to the location model @@ -1839,8 +1843,8 @@ def create_asset_api(request): # Handle generic location for other thematics elif location_id: - for field in asset_class._meta.get_fields(): - if hasattr(field, 'related_model') and field.related_model and not field.auto_created: + for field in asset_class._meta.fields: + if field.is_relation and field.many_to_one and field.related_model: try: loc_instance = field.related_model.objects.get(pk=location_id) setattr(new_asset, field.name, loc_instance) diff --git a/loko/assets/views/export.py b/loko/assets/views/export.py index e7fc0ec..2523415 100644 --- a/loko/assets/views/export.py +++ b/loko/assets/views/export.py @@ -20,7 +20,11 @@ from assets.permissions import can_view_asset def _get_asset_location(asset): """Return the parent location of an asset by inspecting FK fields.""" - for field in asset._meta.get_fields(): + if hasattr(asset, 'get_location'): + loc = asset.get_location() + if loc is not None: + return loc + for field in asset._meta.fields: related = getattr(field, 'related_model', None) if related and issubclass(related, AbstractLocation): try: