loko/streetup/assets/views/buildings.py

200 lines
6.8 KiB
Python

import json
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.db.models import Q, F
from django.http import JsonResponse
from django.urls import reverse
from django.utils.translation import gettext as _, get_language
from django.contrib.gis.geos import GEOSGeometry
from common.models import UserThematics
from common.utils import check_thematic_access
from assets.models.buildings import (
PublicBuilding, BuildingLevel, BuildingRoom, BuildingEquipment, PublicBuildingDocument,
USAGE_TYPE_CHOICES, BUILDING_STATUS_CHOICES, DPE_RATING_CHOICES, ERP_CATEGORY_CHOICES
)
def publicbuildings_locations_geojson(request):
"""
Vue GeoJSON pour les emplacements des bâtiments publics (vide car les bâtiments sont gérés directement comme assets).
"""
return JsonResponse({"type": "FeatureCollection", "features": []})
def publicbuildings_assets_geojson(request):
"""
Vue GeoJSON renvoyant la collection de bâtiments publics pour la carte unifiée des assets.
"""
lang = get_language() if get_language() in ('fr', 'nl') else 'fr'
if request.method == "POST":
try:
data = json.loads(request.body)
except json.JSONDecodeError:
return JsonResponse({"error": "Invalid JSON"}, status=400)
statuses = data.get('asset_status', [])
categories = data.get('category') or []
if isinstance(categories, str):
categories = [categories]
filter_geom_raw = data.get("filter_geom")
if filter_geom_raw:
try:
filter_geom = GEOSGeometry(json.dumps(filter_geom_raw['geometry']), srid=4326)
filter_geom.transform(3812)
except Exception as e:
return JsonResponse({"error": f"Invalid geometry: {str(e)}"}, status=400)
else:
filter_geom = None
search_q = (data.get('q') or '').strip()
else:
statuses = request.GET.getlist('asset_status')
categories = request.GET.getlist('category', [])
filter_geom = None
search_q = request.GET.get('q', '').strip()
qs = PublicBuilding.objects.all()
if categories:
qs = qs.filter(category__id__in=categories)
if statuses:
qs = qs.filter(building_status__in=statuses)
if filter_geom:
qs = qs.filter(geom__intersects=filter_geom)
if search_q:
qs = qs.filter(
Q(code__icontains=search_q) |
Q(name_fr__icontains=search_q) |
Q(name_nl__icontains=search_q) |
Q(address__icontains=search_q) |
Q(owner__icontains=search_q)
)
features = []
from assets.views.core import get_element_type_label
for b in qs:
geometry = None
if b.geom:
geom_4326 = b.geom.clone()
geom_4326.transform(4326)
geometry = json.loads(geom_4326.json)
elif b.lon is not None and b.lat is not None:
geometry = {"type": "Point", "coordinates": [b.lon, b.lat]}
detail_url = reverse('assets:publicbuilding_detail', kwargs={'pk': b.pk})
features.append({
"type": "Feature",
"id": b.id,
"geometry": geometry,
"properties": {
"code": b.code,
"name": b.get_name(),
"category": b.category.get_name() if b.category else _("Bâtiment public"),
"category_id": b.category_id,
"status": b.building_status,
"building_status": b.building_status,
"building_status_display": b.get_building_status_display(),
"usage_type": b.usage_type,
"usage_type_display": b.get_usage_type_display(),
"owner": b.owner or '',
"is_erp": b.is_erp,
"erp_category": b.erp_category or '',
"dpe_rating": b.dpe_rating or '',
"lon": b.lon,
"lat": b.lat,
"color": "#2B579A",
"display_color": "#2B579A",
"asset_type": "publicbuilding",
"detail_url": detail_url,
"element_type": get_element_type_label("publicbuilding"),
"thematic": "publicbuildings",
"is_location": False,
}
})
return JsonResponse({"type": "FeatureCollection", "features": features})
@login_required
def buildings_index(request):
"""
Vue principale (Index / Liste) des Bâtiments Publics.
"""
lang = get_language()
buildings = PublicBuilding.objects.all()
# Search filter
search_query = request.GET.get('q', '').strip()
if search_query:
buildings = buildings.filter(
Q(code__icontains=search_query) |
Q(name_fr__icontains=search_query) |
Q(name_nl__icontains=search_query) |
Q(address__icontains=search_query) |
Q(owner__icontains=search_query)
)
# Usage filter
usage_filter = request.GET.get('usage_type')
if usage_filter:
buildings = buildings.filter(usage_type=usage_filter)
# Status filter
status_filter = request.GET.get('building_status')
if status_filter:
buildings = buildings.filter(building_status=status_filter)
# ERP filter
erp_filter = request.GET.get('is_erp')
if erp_filter in ['true', '1']:
buildings = buildings.filter(is_erp=True)
elif erp_filter in ['false', '0']:
buildings = buildings.filter(is_erp=False)
# DPE rating filter
dpe_filter = request.GET.get('dpe_rating')
if dpe_filter:
buildings = buildings.filter(dpe_rating=dpe_filter)
context = {
'buildings': buildings,
'search_query': search_query,
'usage_type_choices': USAGE_TYPE_CHOICES,
'building_status_choices': BUILDING_STATUS_CHOICES,
'dpe_rating_choices': DPE_RATING_CHOICES,
'selected_usage': usage_filter,
'selected_status': status_filter,
'selected_erp': erp_filter,
'selected_dpe': dpe_filter,
'active_tab': 'buildings',
}
return render(request, 'assets/buildings/publicbuilding_list.html', context)
@login_required
def building_detail(request, pk):
"""
Vue détaillée d'un Bâtiment Public avec ses niveaux, pièces et équipements.
"""
building = get_object_or_404(PublicBuilding, pk=pk)
levels = building.levels.all().prefetch_related('rooms')
rooms = building.rooms.all()
equipments = building.equipments.all()
documents = building.documents.select_related('document').all()
context = {
'building': building,
'levels': levels,
'rooms': rooms,
'equipments': equipments,
'documents': documents,
}
return render(request, 'assets/buildings/publicbuilding_detail.html', context)