feat: add unit tests and views for asset editing and export functionality

This commit is contained in:
Karl Determe 2026-08-27 16:06:34 +02:00
parent 0b190526f8
commit 6b8978254b
3 changed files with 81 additions and 7 deletions

View file

@ -3964,5 +3964,71 @@ class TrafficLightProgrammingTest(TestCase):
self.assertIn("addProgrammingModal", content) 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")

View file

@ -632,8 +632,8 @@ def replace_asset(request, asset_model, asset_id):
# Copy attributes if requested # Copy attributes if requested
if copy_attributes: if copy_attributes:
for field in model_class._meta.get_fields(): for field in model_class._meta.fields:
if field.auto_created or field.name in ('id', 'code', 'replaced_by'): if field.primary_key or field.name in ('id', 'code', 'replaced_by', 'marked_as_removed_date', 'marked_as_removed_by', 'uninstallation_date'):
continue continue
if hasattr(asset, field.name): if hasattr(asset, field.name):
setattr(new_asset, field.name, getattr(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.status = 'active'
new_asset.installation_date = timezone.now() new_asset.installation_date = timezone.now()
new_asset.uninstallation_date = None 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 # Override with new data
for field_name, value in new_data.items(): 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 # Find the ForeignKey field that points to the location model
location_set = False location_set = False
for field in model_class._meta.get_fields(): for field in model_class._meta.fields:
if hasattr(field, 'related_model') and field.related_model: if field.is_relation and field.many_to_one and field.related_model:
related_model_name = field.related_model._meta.model_name.lower() related_model_name = field.related_model._meta.model_name.lower()
if related_model_name == location_model_name: if related_model_name == location_model_name:
# This is a ForeignKey to the location model # This is a ForeignKey to the location model
@ -1839,8 +1843,8 @@ def create_asset_api(request):
# Handle generic location for other thematics # Handle generic location for other thematics
elif location_id: elif location_id:
for field in asset_class._meta.get_fields(): for field in asset_class._meta.fields:
if hasattr(field, 'related_model') and field.related_model and not field.auto_created: if field.is_relation and field.many_to_one and field.related_model:
try: try:
loc_instance = field.related_model.objects.get(pk=location_id) loc_instance = field.related_model.objects.get(pk=location_id)
setattr(new_asset, field.name, loc_instance) setattr(new_asset, field.name, loc_instance)

View file

@ -20,7 +20,11 @@ from assets.permissions import can_view_asset
def _get_asset_location(asset): def _get_asset_location(asset):
"""Return the parent location of an asset by inspecting FK fields.""" """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) related = getattr(field, 'related_model', None)
if related and issubclass(related, AbstractLocation): if related and issubclass(related, AbstractLocation):
try: try: