diff --git a/streetup/assets/models/parking.py b/streetup/assets/models/parking.py
index a0004ee..fd65233 100644
--- a/streetup/assets/models/parking.py
+++ b/streetup/assets/models/parking.py
@@ -133,7 +133,7 @@ class ParkingSpot(AbstractGeoAsset):
ordering = ['code', 'name_fr']
def get_absolute_url(self):
- return reverse('assets:sign_assets_detail', kwargs={'asset_model': 'parking_spot', 'asset_id': self.id})
+ return reverse('assets:parking_assets_detail', kwargs={'asset_model': 'parking_spot', 'asset_id': self.id})
def __str__(self):
type_label = self.get_spot_type_display()
diff --git a/streetup/assets/templates/assets/components/asset_interventions.html b/streetup/assets/templates/assets/components/asset_interventions.html
index 06e6fdf..59e8772 100644
--- a/streetup/assets/templates/assets/components/asset_interventions.html
+++ b/streetup/assets/templates/assets/components/asset_interventions.html
@@ -9,6 +9,11 @@
{{ interventions|length }}
{% endif %}
+ {% if can_add_intervention %}
+
+ {% endif %}
{% if interventions %}
@@ -37,6 +42,13 @@
{{ intervention.title }}
+ {% if intervention.maintain_type == 'corrective' %}
+
{% translate "Corrective" %}
+ {% elif intervention.maintain_type == 'preventive' %}
+
{% translate "Préventive" %}
+ {% elif intervention.maintain_type == 'ameliorative' %}
+
{% translate "Améliorative" %}
+ {% endif %}
{% if intervention.symptom %}
@@ -87,3 +99,135 @@
{% endif %}
+
+{% if can_add_intervention %}
+
+
+
+
+{% endif %}
diff --git a/streetup/assets/templatetags/asset_tags.py b/streetup/assets/templatetags/asset_tags.py
index 5064a06..64cdb48 100644
--- a/streetup/assets/templatetags/asset_tags.py
+++ b/streetup/assets/templatetags/asset_tags.py
@@ -438,19 +438,23 @@ def warranty_remaining_months(asset):
return remaining
-@register.inclusion_tag('assets/components/asset_interventions.html')
-def asset_interventions(asset):
+@register.inclusion_tag('assets/components/asset_interventions.html', takes_context=True)
+def asset_interventions(context, asset):
"""
Display all interventions associated with an asset.
+ Also provides context for adding a new intervention directly from the asset page.
"""
if asset is None or not hasattr(asset, 'pk') or asset.pk is None:
return {
'asset': asset,
'interventions': [],
+ 'can_add_intervention': False,
+ 'symptoms': [],
}
from django.contrib.contenttypes.models import ContentType
- from interventions.models import Intervention, InterventionAsset, STATUS_COLORS, STATUS_COLORS_DARK_TEXT
+ from interventions.models import Intervention, InterventionAsset, Symptom, STATUS_COLORS, STATUS_COLORS_DARK_TEXT
+ from interventions.permissions import can_add_intervention
asset_ct = ContentType.objects.get_for_model(asset)
intervention_ids = InterventionAsset.objects.filter(
@@ -464,10 +468,31 @@ def asset_interventions(asset):
'symptom', 'contract', 'assigned_provider', 'assigned_team', 'created_by'
).order_by('-creation_time'))
+ thematic = None
+ if hasattr(asset, 'category') and asset.category and asset.category.thematic:
+ thematic = asset.category.thematic
+
+ request = context.get('request')
+ user = request.user if request else None
+ can_add = False
+ symptoms = []
+
+ if user and user.is_authenticated:
+ can_add = can_add_intervention(user, thematic)
+ if can_add:
+ if thematic:
+ symptoms = list(Symptom.objects.filter(thematic=thematic, is_active=True).order_by('order_number', 'name_fr'))
+ else:
+ symptoms = list(Symptom.objects.filter(is_active=True).order_by('name_fr'))
+
return {
'asset': asset,
+ 'asset_model': asset_ct.model,
'interventions': interventions,
+ 'can_add_intervention': can_add,
+ 'symptoms': symptoms,
'status_colors': STATUS_COLORS,
'status_colors_dark_text': STATUS_COLORS_DARK_TEXT,
}
+
diff --git a/streetup/assets/urls.py b/streetup/assets/urls.py
index 631d153..779376e 100644
--- a/streetup/assets/urls.py
+++ b/streetup/assets/urls.py
@@ -42,6 +42,7 @@ urlpatterns = [
path('//update/', asset_editing.update_asset, name='update_asset'),
path('//archive/', asset_editing.archive_asset, name='archive_asset'),
path('//replace/', asset_editing.replace_asset, name='replace_asset'),
+ path('//create-intervention/', asset_editing.create_intervention_for_asset, name='create_intervention_for_asset'),
path('//documents/add/', asset_editing.asset_add_document, name='asset_add_document'),
path('//documents//delete/', asset_editing.asset_delete_document, name='asset_delete_document'),
path('//documents/', asset_editing.asset_document_list_html, name='asset_document_list_html'),
diff --git a/streetup/assets/views/asset_editing.py b/streetup/assets/views/asset_editing.py
index 5573d3e..647abec 100644
--- a/streetup/assets/views/asset_editing.py
+++ b/streetup/assets/views/asset_editing.py
@@ -2376,3 +2376,84 @@ def bulk_edit_assets(request):
}
})
+
+@require_POST
+def create_intervention_for_asset(request, asset_model, asset_id):
+ """
+ Create a new intervention directly linked to an asset.
+ Requires user to have intervention creation permission for the asset's thematic.
+ """
+ if not request.user.is_authenticated:
+ return JsonResponse({'success': False, 'error': _("Non authentifié.")}, status=401)
+
+ asset, model_class, content_type = _get_asset_by_ct(asset_model, asset_id)
+
+ thematic = None
+ if hasattr(asset, 'category') and asset.category and asset.category.thematic:
+ thematic = asset.category.thematic
+
+ from interventions.permissions import can_add_intervention
+ if not can_add_intervention(request.user, thematic):
+ return JsonResponse({'success': False, 'error': _("Permission refusée pour créer une intervention.")}, status=403)
+
+ title = request.POST.get('title', '').strip()
+ if not title:
+ return JsonResponse({'success': False, 'error': _("Le titre est obligatoire.")}, status=400)
+
+ symptom_id = request.POST.get('symptom_id')
+ maintain_type = request.POST.get('maintain_type', 'corrective')
+ priority = request.POST.get('priority', '3')
+ init_description = request.POST.get('init_description', '').strip()
+
+ from interventions.models import Intervention, InterventionAsset, Symptom, InterventionLocation
+
+ symptom = None
+ if symptom_id:
+ symptom = Symptom.objects.filter(pk=symptom_id, is_active=True).first()
+
+ geom = getattr(asset, 'geom', None)
+ if geom is not None:
+ from django.contrib.gis.geos import Polygon, MultiPolygon
+ if isinstance(geom, Polygon):
+ geom = MultiPolygon(geom)
+ elif not isinstance(geom, MultiPolygon):
+ geom = None
+
+ try:
+ with transaction.atomic():
+ intervention = Intervention.objects.create(
+ title=title,
+ thematic=thematic,
+ symptom=symptom,
+ maintain_type=maintain_type,
+ priority=priority,
+ init_description=init_description,
+ status='in_preparation',
+ created_by=request.user,
+ geom=geom,
+ )
+ InterventionAsset.objects.create(
+ intervention=intervention,
+ content_type=content_type,
+ object_id=asset.pk
+ )
+ loc_obj = getattr(asset, 'street', None) or getattr(asset, 'location', None) or getattr(asset, 'intersection', None)
+ if loc_obj:
+ loc_ct = ContentType.objects.get_for_model(loc_obj)
+ InterventionLocation.objects.get_or_create(
+ intervention=intervention,
+ content_type=loc_ct,
+ object_id=loc_obj.pk
+ )
+
+ redirect_url = reverse('interventions:intervention_detail', args=[intervention.id])
+ return JsonResponse({
+ 'success': True,
+ 'redirect_url': redirect_url,
+ 'intervention_id': intervention.id,
+ 'intervention_code': intervention.code,
+ })
+ except Exception as e:
+ return JsonResponse({'success': False, 'error': str(e)}, status=500)
+
+
diff --git a/streetup/assets/views/core.py b/streetup/assets/views/core.py
index 624d420..372901a 100644
--- a/streetup/assets/views/core.py
+++ b/streetup/assets/views/core.py
@@ -244,10 +244,11 @@ def locations_geojson(request):
def mobile_asset_detail(request, thematic_code, asset_model, asset_id):
"""Mobile-friendly asset detail using the generic template with the mobile base."""
try:
- content_type = ContentType.objects.get(app_label='assets', model=asset_model)
+ model_name = asset_model.lower().replace('_', '')
+ content_type = ContentType.objects.get(app_label='assets', model=model_name)
model_class = content_type.model_class()
except ContentType.DoesNotExist:
- raise Http404(_("Modèle %(asset_model)s inconnu.") % (asset_model))
+ raise Http404(_("Modèle %(asset_model)s inconnu.") % {'asset_model': asset_model})
asset = get_object_or_404(model_class, id=asset_id)
diff --git a/streetup/assets/views/sign.py b/streetup/assets/views/sign.py
index ce9512c..84fc228 100644
--- a/streetup/assets/views/sign.py
+++ b/streetup/assets/views/sign.py
@@ -775,10 +775,11 @@ def sign_streets_detail(request, street_id):
def sign_assets_detail(request, asset_model, asset_id):
try:
# Récupérer le ContentType pour le modèle fourni (spécifier l'app_label 'assets' pour éviter les conflits)
- content_type = ContentType.objects.get(app_label='assets', model=asset_model)
+ model_name = asset_model.lower().replace('_', '')
+ content_type = ContentType.objects.get(app_label='assets', model=model_name)
model_class = content_type.model_class()
except ContentType.DoesNotExist:
- raise Http404(_("Modèle %(asset_model)s inconnu.") % (asset_model))
+ raise Http404(_("Modèle %(asset_model)s inconnu.") % {'asset_model': asset_model})
# Récupérer l’objet asset
asset = get_object_or_404(model_class, id=asset_id)
diff --git a/streetup/assets/views/structures.py b/streetup/assets/views/structures.py
index b6764ba..cc02bdf 100644
--- a/streetup/assets/views/structures.py
+++ b/streetup/assets/views/structures.py
@@ -647,10 +647,11 @@ def structures_locations_detail(request, location_id):
def structures_assets_detail(request, asset_model, asset_id):
try:
# Récupérer le ContentType pour le modèle fourni
- content_type = ContentType.objects.get(model=asset_model)
+ model_name = asset_model.lower().replace('_', '')
+ content_type = ContentType.objects.get(app_label='assets', model=model_name)
model_class = content_type.model_class()
except ContentType.DoesNotExist:
- raise Http404(_("Modèle %(asset_model)s inconnu.") % (asset_model))
+ raise Http404(_("Modèle %(asset_model)s inconnu.") % {'asset_model': asset_model})
# Récupérer l’objet asset
asset = get_object_or_404(model_class, id=asset_id)
|