loko/streetup/reporting/views_dashboard.py
2026-07-22 14:48:40 +02:00

338 lines
12 KiB
Python

import json
from django.contrib.auth.decorators import login_required
from django.db import connection
from django.shortcuts import render
from django.utils.translation import get_language
from common.models import UserConfig, Thematic
from reporting.models import ReportingContractConfig
def _can_access_reporting(user):
if user.is_superuser:
return True
try:
user_config = UserConfig.objects.get(user=user)
return user_config.can_access_view("reporting")
except UserConfig.DoesNotExist:
return False
@login_required
def dashboard(request):
if not _can_access_reporting(request.user):
from django.core.exceptions import PermissionDenied
raise PermissionDenied
# Determine which contracts are accessible for the selector
try:
user_config = UserConfig.objects.prefetch_related("roles").get(user=request.user)
is_unrestricted = (
request.user.is_superuser
or user_config.roles.filter(name__in=["admin", "top_manager", "operator"]).exists()
)
except UserConfig.DoesNotExist:
user_config = None
is_unrestricted = request.user.is_superuser
# Reporting-enabled contracts
enabled_qs = (
ReportingContractConfig.objects.filter(is_enabled=True)
.select_related("contract")
.order_by("contract__contract_number")
)
if is_unrestricted:
accessible_contracts = [
{"id": rc.contract.id, "number": rc.contract.contract_number}
for rc in enabled_qs
]
else:
user_contract_ids = set(
user_config.contracts.values_list("id", flat=True)
) if user_config else set()
accessible_contracts = [
{"id": rc.contract.id, "number": rc.contract.contract_number}
for rc in enabled_qs
if rc.contract.id in user_contract_ids
]
# Build thematic → contract_ids map from mv_interventions
# (only corrective interventions with dt_to_be_processed, for accessible contracts)
accessible_contract_ids = [c["id"] for c in accessible_contracts]
lang = get_language() or "fr"
if accessible_contract_ids:
placeholders = ", ".join(["%s"] * len(accessible_contract_ids))
sql = f"""
SELECT
thematic_id,
MAX(thematic_name_fr) AS name_fr,
MAX(thematic_name_nl) AS name_nl,
ARRAY_AGG(DISTINCT contract_id) AS contract_ids
FROM reporting.mv_interventions
WHERE maintenance_type = 'corrective'
AND dt_to_be_processed IS NOT NULL
AND thematic_id IS NOT NULL
AND contract_id IN ({placeholders})
GROUP BY thematic_id
ORDER BY MAX(thematic_name_fr) ASC
"""
with connection.cursor() as cursor:
cursor.execute(sql, accessible_contract_ids)
rows = cursor.fetchall()
# Fetch thematic codes to map thematic IDs to codes
thematic_ids = [r[0] for r in rows]
thematic_codes = {
t.id: t.code
for t in Thematic.objects.filter(id__in=thematic_ids)
} if thematic_ids else {}
accessible_thematics = []
thematic_contract_map = {} # { thematic_id: [contract_id, ...] }
thematic_code_map = {} # { thematic_id: code }
for thematic_id, name_fr, name_nl, contract_ids in rows:
name = name_nl if lang == "nl" else name_fr
contract_ids_clean = sorted(int(c) for c in (contract_ids or []) if c is not None)
code = thematic_codes.get(thematic_id)
thematic_code_map[thematic_id] = code
accessible_thematics.append({
"id": thematic_id,
"name": name,
"name_fr": name_fr,
"name_nl": name_nl,
"code": code,
})
thematic_contract_map[thematic_id] = contract_ids_clean
else:
accessible_thematics = []
thematic_contract_map = {}
thematic_code_map = {}
# Saved preferences for this page
saved_prefs = {}
if user_config:
saved_prefs = (user_config.reporting_preferences or {}).get("dashboard", {})
return render(request, "reporting/dashboard.html", {
"accessible_contracts": accessible_contracts,
"accessible_thematics": accessible_thematics,
"thematic_contract_map_json": json.dumps(thematic_contract_map),
"thematic_code_map_json": json.dumps(thematic_code_map),
"saved_prefs_json": json.dumps(saved_prefs),
})
@login_required
def volume_dashboard(request):
if not _can_access_reporting(request.user):
from django.core.exceptions import PermissionDenied
raise PermissionDenied
# Determine which contracts are accessible for the selector
try:
user_config = UserConfig.objects.prefetch_related("roles").get(user=request.user)
is_unrestricted = (
request.user.is_superuser
or user_config.roles.filter(name__in=["admin", "top_manager", "operator"]).exists()
)
except UserConfig.DoesNotExist:
user_config = None
is_unrestricted = request.user.is_superuser
# Reporting-enabled contracts
enabled_qs = (
ReportingContractConfig.objects.filter(is_enabled=True)
.select_related("contract__company")
.order_by("contract__contract_number")
)
if is_unrestricted:
accessible_contracts = [
{
"id": rc.contract.id,
"number": rc.contract.contract_number,
"company_name": rc.contract.company.name
}
for rc in enabled_qs
]
else:
user_contract_ids = set(
user_config.contracts.values_list("id", flat=True)
) if user_config else set()
accessible_contracts = [
{
"id": rc.contract.id,
"number": rc.contract.contract_number,
"company_name": rc.contract.company.name
}
for rc in enabled_qs
if rc.contract.id in user_contract_ids
]
# Build thematic → contract_ids map from mv_interventions
accessible_contract_ids = [c["id"] for c in accessible_contracts]
lang = get_language() or "fr"
if accessible_contract_ids:
placeholders = ", ".join(["%s"] * len(accessible_contract_ids))
sql = f"""
SELECT
thematic_id,
MAX(thematic_name_fr) AS name_fr,
MAX(thematic_name_nl) AS name_nl,
ARRAY_AGG(DISTINCT contract_id) AS contract_ids
FROM reporting.mv_interventions
WHERE maintenance_type = 'corrective'
AND dt_to_be_processed IS NOT NULL
AND thematic_id IS NOT NULL
AND contract_id IN ({placeholders})
GROUP BY thematic_id
ORDER BY MAX(thematic_name_fr) ASC
"""
with connection.cursor() as cursor:
cursor.execute(sql, accessible_contract_ids)
rows = cursor.fetchall()
# Fetch thematic codes to map thematic IDs to codes
thematic_ids = [r[0] for r in rows]
thematic_codes = {
t.id: t.code
for t in Thematic.objects.filter(id__in=thematic_ids)
} if thematic_ids else {}
accessible_thematics = []
thematic_contract_map = {} # { thematic_id: [contract_id, ...] }
thematic_code_map = {} # { thematic_id: code }
for thematic_id, name_fr, name_nl, contract_ids in rows:
name = name_nl if lang == "nl" else name_fr
contract_ids_clean = sorted(int(c) for c in (contract_ids or []) if c is not None)
code = thematic_codes.get(thematic_id)
thematic_code_map[thematic_id] = code
accessible_thematics.append({
"id": thematic_id,
"name": name,
"name_fr": name_fr,
"name_nl": name_nl,
"code": code,
})
thematic_contract_map[thematic_id] = contract_ids_clean
else:
accessible_thematics = []
thematic_contract_map = {}
thematic_code_map = {}
# Saved preferences for this page
saved_prefs = {}
if user_config:
saved_prefs = (user_config.reporting_preferences or {}).get("volume_dashboard", {})
return render(request, "reporting/volume_dashboard.html", {
"accessible_contracts": accessible_contracts,
"accessible_thematics": accessible_thematics,
"thematic_contract_map_json": json.dumps(thematic_contract_map),
"thematic_code_map_json": json.dumps(thematic_code_map),
"saved_prefs_json": json.dumps(saved_prefs),
})
@login_required
def observations_dashboard(request):
if not _can_access_reporting(request.user):
from django.core.exceptions import PermissionDenied
raise PermissionDenied
# Determine which thematic, category, symptom are accessible
try:
user_config = UserConfig.objects.prefetch_related("roles").get(user=request.user)
is_unrestricted = (
request.user.is_superuser
or user_config.roles.filter(name__in=["admin", "top_manager", "operator"]).exists()
)
except UserConfig.DoesNotExist:
user_config = None
is_unrestricted = request.user.is_superuser
lang = get_language() or "fr"
from common.models import Thematic
from assets.models import AssetCategory
from interventions.models import Symptom
from observations.permissions import get_observation_access_context
if is_unrestricted:
allowed_tids = list(Thematic.objects.values_list("id", flat=True))
else:
access_context = get_observation_access_context(request.user, user_config=user_config)
allowed_tids = list(access_context.thematic_ids) if access_context else []
if allowed_tids:
thematics_qs = Thematic.objects.filter(id__in=allowed_tids).order_by("name_fr")
all_categories_qs = AssetCategory.objects.filter(thematic_id__in=allowed_tids).order_by("name_fr")
symptoms_qs = Symptom.objects.filter(thematic_id__in=allowed_tids).order_by("name_fr")
accessible_thematics = [
{
"id": t.id,
"name": t.name_nl if lang == "nl" else t.name_fr,
"code": t.code
}
for t in thematics_qs
]
accessible_categories = [
{
"id": c.id,
"name": c.name_nl if lang == "nl" else c.name_fr,
"thematic_id": c.thematic_id
}
for c in all_categories_qs
]
accessible_symptoms = [
{
"id": s.id,
"name": s.name_nl if lang == "nl" else s.name_fr,
"thematic_id": s.thematic_id
}
for s in symptoms_qs
]
# Build thematic → list of category IDs mapping
thematic_category_map = {}
for c in accessible_categories:
tid = c["thematic_id"]
if tid not in thematic_category_map:
thematic_category_map[tid] = []
thematic_category_map[tid].append(c["id"])
# Build thematic → list of symptom IDs mapping
thematic_symptom_map = {}
for s in accessible_symptoms:
tid = s["thematic_id"]
if tid not in thematic_symptom_map:
thematic_symptom_map[tid] = []
thematic_symptom_map[tid].append(s["id"])
else:
accessible_thematics = []
accessible_categories = []
accessible_symptoms = []
thematic_category_map = {}
thematic_symptom_map = {}
# Saved preferences for this page
saved_prefs = {}
if user_config:
saved_prefs = (user_config.reporting_preferences or {}).get("observations_dashboard", {})
return render(request, "reporting/observations_dashboard.html", {
"accessible_thematics": accessible_thematics,
"accessible_categories": accessible_categories,
"accessible_symptoms": accessible_symptoms,
"thematic_category_map_json": json.dumps(thematic_category_map),
"thematic_symptom_map_json": json.dumps(thematic_symptom_map),
"saved_prefs_json": json.dumps(saved_prefs),
})