diff --git a/app_new/core/routes/dashboard.py b/app_new/core/routes/dashboard.py index b3a052c..9f9fc8f 100644 --- a/app_new/core/routes/dashboard.py +++ b/app_new/core/routes/dashboard.py @@ -13,6 +13,7 @@ from ..models.college import Building, Room from ..models.company import Part from app_new.constants import INTERVENTION_STATUSES, EQUIPMENT_STATUSES from sqlalchemy import func +from ..authorization import has_permission dashboard_bp = Blueprint('dashboard', __name__) @@ -25,20 +26,33 @@ def index(): from ..services.planning_service import PlanningService from ..models.planning import ScheduledTask, AdminTask from ..models.maintenance import Lot + + dashboard_permissions = { + 'intervention': has_permission('intervention.view', current_user), + 'intervention_manage': has_permission('intervention.manage', current_user), + 'patrimoine': has_permission('patrimoine.view', current_user), + 'planning': has_permission('planning.view', current_user), + 'planning_manage': has_permission('planning.manage', current_user), + 'stock': has_permission('stock.view', current_user), + 'prevention': has_permission('prevention.view', current_user), + 'ent': has_permission('integration.ent.view', current_user), + 'outlook': has_permission('integration.outlook.view', current_user), + 'ai': has_permission('system.configure', current_user), + } # Statistiques stats = { - 'interventions_total': Intervention.query.count(), - 'interventions_en_cours': Intervention.query.filter_by(status='en_cours').count(), - 'interventions_en_attente': Intervention.query.filter_by(status='en_attente').count(), - 'interventions_urgentes': Intervention.query.filter_by(priority='urgente', is_deleted=False).count(), - 'equipments_total': Equipment.query.count(), - 'equipments_actifs': Equipment.query.filter_by(status='en_service', is_deleted=False).count(), - 'equipments_panne': Equipment.query.filter(Equipment.status.in_(['en_panne', 'hors_service', 'hs']), Equipment.is_deleted.is_(False)).count(), - 'buildings_total': Building.query.count(), - 'rooms_total': Room.query.count(), - 'companies_total': Company.query.count(), - 'parts_low_stock': Part.query.filter(Part.quantity <= Part.min_quantity).count(), + 'interventions_total': Intervention.query.count() if dashboard_permissions['intervention'] else 0, + 'interventions_en_cours': Intervention.query.filter_by(status='en_cours').count() if dashboard_permissions['intervention'] else 0, + 'interventions_en_attente': Intervention.query.filter_by(status='en_attente').count() if dashboard_permissions['intervention'] else 0, + 'interventions_urgentes': Intervention.query.filter_by(priority='urgente', is_deleted=False).count() if dashboard_permissions['intervention'] else 0, + 'equipments_total': Equipment.query.count() if dashboard_permissions['patrimoine'] else 0, + 'equipments_actifs': Equipment.query.filter_by(status='en_service', is_deleted=False).count() if dashboard_permissions['patrimoine'] else 0, + 'equipments_panne': Equipment.query.filter(Equipment.status.in_(['en_panne', 'hors_service', 'hs']), Equipment.is_deleted.is_(False)).count() if dashboard_permissions['patrimoine'] else 0, + 'buildings_total': Building.query.count() if dashboard_permissions['patrimoine'] else 0, + 'rooms_total': Room.query.count() if dashboard_permissions['patrimoine'] else 0, + 'companies_total': Company.query.count() if dashboard_permissions['intervention'] else 0, + 'parts_low_stock': Part.query.filter(Part.quantity <= Part.min_quantity).count() if dashboard_permissions['stock'] else 0, } # Contrôle des lots : un lot présent doit être rattaché à au moins un @@ -52,8 +66,9 @@ def index(): ) .group_by(Equipment.lot_id) .all() + if dashboard_permissions['patrimoine'] else {} ) - lots = Lot.query.order_by(Lot.name).all() + lots = Lot.query.order_by(Lot.name).all() if dashboard_permissions['patrimoine'] else [] lots_without_equipment = [ lot for lot in lots if lot.is_present and equipment_counts.get(lot.id, 0) == 0 @@ -77,14 +92,14 @@ def index(): stats['lots_missing_duration'] = len(lots_missing_duration) # Dernières interventions - recent_interventions = Intervention.query.order_by(Intervention.created_at.desc()).limit(10).all() + recent_interventions = Intervention.query.order_by(Intervention.created_at.desc()).limit(10).all() if dashboard_permissions['intervention'] else [] # Interventions urgentes - urgent_interventions = Intervention.query.filter_by(priority='urgente', is_deleted=False).limit(5).all() + urgent_interventions = Intervention.query.filter_by(priority='urgente', is_deleted=False).limit(5).all() if dashboard_permissions['intervention'] else [] # Interventions du jour (planning) today = date.today() - day_schedule = PlanningService.get_day_schedule(today) + day_schedule = PlanningService.get_day_schedule(today) if dashboard_permissions['planning'] else None # Interprétations en attente (non traitées) from ...outlook.models import OutlookMailInterpretation @@ -94,12 +109,12 @@ def index(): outlook_interpretations = OutlookMailInterpretation.query.filter_by( status='pending', user_id=current_user.id - ).order_by(OutlookMailInterpretation.created_at.desc()).limit(10).all() + ).order_by(OutlookMailInterpretation.created_at.desc()).limit(10).all() if dashboard_permissions['outlook'] else [] # Récupérer les interprétations ENT ent_interpretations = EntMessageInterpretation.query.filter_by( status='pending' - ).order_by(EntMessageInterpretation.created_at.desc()).limit(10).all() + ).order_by(EntMessageInterpretation.created_at.desc()).limit(10).all() if dashboard_permissions['ent'] else [] # Combiner les deux listes avec une source pending_interpretations = [] @@ -148,7 +163,8 @@ def index(): lots_without_equipment=lots_without_equipment, lots_missing_duration=lots_missing_duration, today=today, - statuses=INTERVENTION_STATUSES) + statuses=INTERVENTION_STATUSES, + dashboard_permissions=dashboard_permissions) @dashboard_bp.route('/api/stats') @@ -158,28 +174,33 @@ def api_stats(): from datetime import date, timedelta from sqlalchemy import func + can_intervention = has_permission('intervention.view', current_user) + can_patrimoine = has_permission('patrimoine.view', current_user) + # Interventions par mois (6 derniers mois) six_months_ago = date.today() - timedelta(days=180) monthly = db.session.query( func.date_format(Intervention.created_at, '%Y-%m').label('month'), func.count().label('count') - ).filter(Intervention.created_at >= six_months_ago).group_by('month').order_by('month').all() + ).filter(Intervention.created_at >= six_months_ago).group_by('month').order_by('month').all() if can_intervention else [] monthly_data = [{'month': r.month, 'count': r.count} for r in monthly] # Interventions par statut status_data = {} - for status_val, info in INTERVENTION_STATUSES.items(): - count = Intervention.query.filter_by(status=status_val).count() - if count > 0: - status_data[info['label']] = count + if can_intervention: + for status_val, info in INTERVENTION_STATUSES.items(): + count = Intervention.query.filter_by(status=status_val).count() + if count > 0: + status_data[info['label']] = count # Equipements par statut equip_status = {} - for s in EQUIPMENT_STATUSES: - count = Equipment.query.filter_by(status=s).count() - if count > 0: - equip_status[s] = count + if can_patrimoine: + for s in EQUIPMENT_STATUSES: + count = Equipment.query.filter_by(status=s).count() + if count > 0: + equip_status[s] = count # Top 5 equipements les plus intervenus top_equip = db.session.query( @@ -188,7 +209,7 @@ def api_stats(): ).join(Intervention, Intervention.equipment_id == Equipment.id)\ .group_by(Equipment.id)\ .order_by(func.count(Intervention.id).desc())\ - .limit(5).all() + .limit(5).all() if can_intervention and can_patrimoine else [] top_data = [{'name': r.name, 'count': r.count} for r in top_equip] @@ -213,26 +234,26 @@ def search(): } if query: - # Recherche interventions - results['interventions'] = Intervention.query.filter( - db.or_( - Intervention.title.ilike(f'%{query}%'), - Intervention.description.ilike(f'%{query}%') - ) - ).limit(10).all() + if has_permission('intervention.view', current_user): + results['interventions'] = Intervention.query.filter( + db.or_( + Intervention.title.ilike(f'%{query}%'), + Intervention.description.ilike(f'%{query}%') + ) + ).limit(10).all() - # Recherche équipements - results['equipments'] = Equipment.query.filter( - db.or_( - Equipment.name.ilike(f'%{query}%'), - Equipment.serial_number.ilike(f'%{query}%') - ) - ).limit(10).all() + if has_permission('patrimoine.view', current_user): + results['equipments'] = Equipment.query.filter( + db.or_( + Equipment.name.ilike(f'%{query}%'), + Equipment.serial_number.ilike(f'%{query}%') + ) + ).limit(10).all() - # Recherche salles - results['rooms'] = Room.query.filter( - Room.name.ilike(f'%{query}%') - ).limit(10).all() + if has_permission('patrimoine.view', current_user): + results['rooms'] = Room.query.filter( + Room.name.ilike(f'%{query}%') + ).limit(10).all() return render_template('dashboard/search.html', query=query, results=results) @@ -245,31 +266,36 @@ def alerts(): from app_new.core.models.company import Alert alerts_list = Alert.query.filter_by(is_read=False).order_by(Alert.created_at.desc()).all() + can_intervention = has_permission('intervention.view', current_user) + can_patrimoine = has_permission('patrimoine.view', current_user) + can_outlook = has_permission('integration.outlook.view', current_user) + can_ent = has_permission('integration.ent.view', current_user) + # Interventions urgentes (statut haute priorité) urgent_interventions = Intervention.query.filter( Intervention.priority == 'haute', Intervention.status.in_(['planifiee', 'en_cours', 'en_attente']) - ).order_by(Intervention.scheduled_date.desc()).all() + ).order_by(Intervention.scheduled_date.desc()).all() if can_intervention else [] # Équipements en panne from app_new.core.models.equipment import Equipment equipments_panne = Equipment.query.filter( Equipment.status.in_(['en_panne', 'hors_service', 'hs']), Equipment.is_deleted.is_(False), - ).all() + ).all() if can_patrimoine else [] # Équipements à jeter - equipments_to_trash = Equipment.query.filter_by(status='a_jeter').all() + equipments_to_trash = Equipment.query.filter_by(status='a_jeter').all() if can_patrimoine else [] # Interprétations en attente from ...outlook.models import OutlookMailInterpretation from ...ent.interpretation_models import EntMessageInterpretation pending_outlook = OutlookMailInterpretation.query.filter_by( status='pending', user_id=current_user.id - ).order_by(OutlookMailInterpretation.created_at.desc()).all() + ).order_by(OutlookMailInterpretation.created_at.desc()).all() if can_outlook else [] pending_ent = EntMessageInterpretation.query.filter_by( status='pending' - ).order_by(EntMessageInterpretation.created_at.desc()).all() + ).order_by(EntMessageInterpretation.created_at.desc()).all() if can_ent else [] return render_template('dashboard/alerts.html', alerts=alerts_list, @@ -301,6 +327,10 @@ def create_month_interventions(): from ..models.maintenance import Intervention from ..models.company import Company from flask_login import current_user + + if not (has_permission('planning.manage', current_user) or has_permission('intervention.manage', current_user)): + from flask import abort + abort(403) today = date.today() one_month_later = today + timedelta(days=30) diff --git a/app_new/templates/dashboard/index.html b/app_new/templates/dashboard/index.html index f5ffda3..f4e0e36 100644 --- a/app_new/templates/dashboard/index.html +++ b/app_new/templates/dashboard/index.html @@ -11,33 +11,35 @@ {% block content %}
{{ day_schedule.leave }}