Files
dsi-commander/app/Http/Controllers/DashboardController.php
jeremy bayse 04fc56cd70 feat: dashboard amélioré, exports budgets, alertes expiration et correctifs
## Dashboard
- Refonte complète du tableau de bord avec widgets budgets, commandes, contrats
- Intégration des données d'exécution budgétaire en temps réel

## Exports & Rapports
- BudgetExecutionExport : export Excel de l'exécution budgétaire
- Template PDF budgets (budgets_pdf.blade.php)
- Routes d'export PDF et Excel

## Alertes & Notifications
- Commande CheckExpirations : détection des contrats/assets arrivant à échéance
- Mail ExpiringElementsMail avec template Blade
- Planification via routes/console.php

## Correctifs
- CommandePolicy et ContratPolicy : ajustements des règles d'autorisation
- ContratController : corrections mineures
- Commande model : ajustements relations/casts
- AuthenticatedLayout : refonte navigation avec icônes budgets
- Assets/Form.vue : corrections formulaire
- Seeder rôles/permissions mis à jour
- Dépendances composer mises à jour (barryvdh/laravel-dompdf, maatwebsite/excel)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 20:20:49 +02:00

155 lines
6.1 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Commande;
use App\Models\Service;
use App\Models\Contrat;
use App\Models\Domaine;
use App\Models\Budget;
use App\Models\LigneBudget;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;
class DashboardController extends Controller
{
public function index(Request $request): Response
{
$user = $request->user();
$isRestricted = !$user->hasRole(['admin', 'directeur', 'raf']);
$serviceId = $user->service_id;
$baseCommande = Commande::query();
if ($isRestricted) {
$baseCommande->where('service_id', $serviceId);
}
$stats = [
'total' => (clone $baseCommande)->count(),
'en_cours' => (clone $baseCommande)->enCours()->count(),
'en_retard' => (clone $baseCommande)->enRetard()->count(),
'brouillons' => (clone $baseCommande)->parStatut('brouillon')->count(),
'en_attente_validation' => (clone $baseCommande)->parStatut('en_attente_validation')->count(),
'validees' => (clone $baseCommande)->parStatut('validee')->count(),
'commandees' => (clone $baseCommande)->parStatut('commandee')->count(),
'partiellement_recues' => (clone $baseCommande)->parStatut('partiellement_recue')->count(),
'recues_complete' => (clone $baseCommande)->parStatut('recue_complete')->count(),
];
$commandesRecentes = (clone $baseCommande)->with(['service', 'fournisseur', 'demandeur'])
->latest()
->limit(8)
->get();
$commandesEnRetard = (clone $baseCommande)->enRetard()
->with(['service', 'fournisseur', 'demandeur'])
->orderBy('date_souhaitee')
->limit(10)
->get();
$commandesUrgentes = (clone $baseCommande)->urgentes()
->enCours()
->with(['service', 'fournisseur', 'demandeur'])
->latest()
->limit(5)
->get();
$statsParStatut = (clone $baseCommande)->select('statut', DB::raw('count(*) as total'))
->groupBy('statut')
->get()
->keyBy('statut');
$statsParServiceQuery = Service::withCount([
'commandes',
'commandes as commandes_en_cours_count' => fn ($q) => $q->enCours(),
]);
if ($isRestricted) {
$statsParServiceQuery->where('id', $serviceId);
}
$statsParService = $statsParServiceQuery->get();
$montantParMois = (clone $baseCommande)->select(
DB::raw('YEAR(date_demande) as annee'),
DB::raw('MONTH(date_demande) as mois'),
DB::raw('SUM(montant_ttc) as total_ttc'),
DB::raw('COUNT(*) as nb_commandes')
)
->whereYear('date_demande', now()->year)
->whereNotIn('statut', ['annulee'])
->groupBy('annee', 'mois')
->orderBy('mois')
->get();
// Stats Contrats
$contratsQuery = Contrat::query();
if (!$user->hasRole(['admin', 'raf'])) {
$contratsQuery->where('service_id', $user->service_id);
}
$tousContrats = $contratsQuery->get();
$statsContrats = [
'total' => $tousContrats->count(),
'proches' => $tousContrats->filter(fn($c) => $c->est_proche_echeance && !$c->est_en_retard)->count(),
'en_retard' => $tousContrats->filter(fn($c) => $c->est_en_retard)->count(),
];
// Stats Domaines (Visibles par tous)
$tousDomaines = Domaine::all();
$statsDomaines = [
'total' => $tousDomaines->count(),
'proches' => $tousDomaines->filter(fn($d) => $d->est_proche_echeance && !$d->est_en_retard)->count(),
'en_retard' => $tousDomaines->filter(fn($d) => $d->est_en_retard)->count(),
];
// Stats Budget
$anneeCourante = now()->year;
$budgetQuery = LigneBudget::whereHas('budget', function($q) use ($anneeCourante) {
$q->where('annee', $anneeCourante);
});
if ($isRestricted) {
$budgetQuery->whereHas('budget', function($q) use ($serviceId) {
$q->where('service_id', $serviceId);
});
}
$budgetsStats = [];
foreach (['agglo', 'mutualise'] as $typeBudget) {
$budgetQueryType = (clone $budgetQuery)->whereHas('budget', fn($q) => $q->where('type_budget', $typeBudget));
$baseCommandeType = (clone $baseCommande)->whereHas('ligneBudget.budget', function($q) use ($anneeCourante, $typeBudget) {
$q->where('annee', $anneeCourante)->where('type_budget', $typeBudget);
})->whereNotIn('statut', ['annulee']);
$budgetsStats[$typeBudget] = [
'total_arbitre' => $budgetQueryType->sum('montant_arbitre'),
'consomme' => $baseCommandeType->sum('montant_ttc'),
'fonctionnement' => [
'total_arbitre' => (clone $budgetQueryType)->where('type_depense', 'fonctionnement')->sum('montant_arbitre'),
'consomme' => (clone $baseCommandeType)->whereHas('ligneBudget', fn($q) => $q->where('type_depense', 'fonctionnement'))->sum('montant_ttc'),
],
'investissement' => [
'total_arbitre' => (clone $budgetQueryType)->where('type_depense', 'investissement')->sum('montant_arbitre'),
'consomme' => (clone $baseCommandeType)->whereHas('ligneBudget', fn($q) => $q->where('type_depense', 'investissement'))->sum('montant_ttc'),
],
];
}
return Inertia::render('Dashboard/Index', compact(
'stats',
'commandesRecentes',
'commandesEnRetard',
'commandesUrgentes',
'statsParStatut',
'statsParService',
'montantParMois',
'statsContrats',
'statsDomaines',
'budgetsStats',
));
}
}