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>
This commit is contained in:
@@ -6,6 +6,8 @@ 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;
|
||||
@@ -16,47 +18,61 @@ 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' => Commande::count(),
|
||||
'en_cours' => Commande::enCours()->count(),
|
||||
'en_retard' => Commande::enRetard()->count(),
|
||||
'brouillons' => Commande::parStatut('brouillon')->count(),
|
||||
'en_attente_validation' => Commande::parStatut('en_attente_validation')->count(),
|
||||
'validees' => Commande::parStatut('validee')->count(),
|
||||
'commandees' => Commande::parStatut('commandee')->count(),
|
||||
'partiellement_recues' => Commande::parStatut('partiellement_recue')->count(),
|
||||
'recues_complete' => Commande::parStatut('recue_complete')->count(),
|
||||
'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 = Commande::with(['service', 'fournisseur', 'demandeur'])
|
||||
$commandesRecentes = (clone $baseCommande)->with(['service', 'fournisseur', 'demandeur'])
|
||||
->latest()
|
||||
->limit(8)
|
||||
->get();
|
||||
|
||||
$commandesEnRetard = Commande::enRetard()
|
||||
$commandesEnRetard = (clone $baseCommande)->enRetard()
|
||||
->with(['service', 'fournisseur', 'demandeur'])
|
||||
->orderBy('date_souhaitee')
|
||||
->limit(10)
|
||||
->get();
|
||||
|
||||
$commandesUrgentes = Commande::urgentes()
|
||||
$commandesUrgentes = (clone $baseCommande)->urgentes()
|
||||
->enCours()
|
||||
->with(['service', 'fournisseur', 'demandeur'])
|
||||
->latest()
|
||||
->limit(5)
|
||||
->get();
|
||||
|
||||
$statsParStatut = Commande::select('statut', DB::raw('count(*) as total'))
|
||||
$statsParStatut = (clone $baseCommande)->select('statut', DB::raw('count(*) as total'))
|
||||
->groupBy('statut')
|
||||
->get()
|
||||
->keyBy('statut');
|
||||
|
||||
$statsParService = Service::withCount([
|
||||
$statsParServiceQuery = Service::withCount([
|
||||
'commandes',
|
||||
'commandes as commandes_en_cours_count' => fn ($q) => $q->enCours(),
|
||||
])->get();
|
||||
]);
|
||||
|
||||
if ($isRestricted) {
|
||||
$statsParServiceQuery->where('id', $serviceId);
|
||||
}
|
||||
|
||||
$statsParService = $statsParServiceQuery->get();
|
||||
|
||||
$montantParMois = Commande::select(
|
||||
$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'),
|
||||
@@ -70,7 +86,7 @@ class DashboardController extends Controller
|
||||
|
||||
// Stats Contrats
|
||||
$contratsQuery = Contrat::query();
|
||||
if (!$user->hasRole('admin')) {
|
||||
if (!$user->hasRole(['admin', 'raf'])) {
|
||||
$contratsQuery->where('service_id', $user->service_id);
|
||||
}
|
||||
$tousContrats = $contratsQuery->get();
|
||||
@@ -88,6 +104,40 @@ class DashboardController extends Controller
|
||||
'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',
|
||||
@@ -98,6 +148,7 @@ class DashboardController extends Controller
|
||||
'montantParMois',
|
||||
'statsContrats',
|
||||
'statsDomaines',
|
||||
'budgetsStats',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user