user = $user; $this->annee = $annee; $this->filters = $filters; } public function title(): string { $parts = ['Exécution Budgétaire', $this->annee]; if (!empty($this->filters['type'])) { $parts[] = ucfirst($this->filters['type']); } if (!empty($this->filters['envelope'])) { $parts[] = ucfirst($this->filters['envelope']); } if (!empty($this->filters['service'])) { $parts[] = $this->filters['service']; } return substr(implode(' - ', $parts), 0, 31); // Max 31 chars for Excel sheet title } public function collection() { $query = LigneBudget::with(['budget.service', 'commandes']) ->whereHas('budget', function($q) { $q->where('annee', $this->annee); }); // Role based access if (!$this->user->hasRole(['admin', 'directeur'])) { $query->whereHas('budget', function($q) { $q->where('service_id', $this->user->service_id); }); } // Dynamic filters if (!empty($this->filters['type'])) { $query->where('type_depense', $this->filters['type']); } if (!empty($this->filters['envelope'])) { $query->whereHas('budget', function($q) { $q->where('type_budget', $this->filters['envelope']); }); } if (!empty($this->filters['service'])) { $query->whereHas('budget.service', function($q) { $q->where('nom', $this->filters['service']); }); } $statutsConsommes = ['validee', 'commandee', 'partiellement_recue', 'recue_complete', 'cloturee']; $statutsEngages = ['brouillon', 'en_attente_validation']; return $query->get()->map(function($lb) use ($statutsConsommes, $statutsEngages) { // Travail en mémoire sur la relation déjà eager-loadée — zéro requête supplémentaire $commandes = $lb->commandes; $consomme = (float) $commandes->whereIn('statut', $statutsConsommes)->sum('montant_ttc'); $engage = (float) $commandes->whereIn('statut', $statutsEngages)->sum('montant_ttc'); $lb->consomme = $consomme; $lb->engage = $engage; $lb->total_cumule = $consomme + $engage; $lb->reste = (float) ($lb->montant_arbitre ?? 0) - $lb->total_cumule; $lb->percent = ($lb->montant_arbitre ?? 0) > 0 ? round(($lb->total_cumule / $lb->montant_arbitre) * 100, 2) : 0; return $lb; }); } public function headings(): array { return [ 'ID', 'Service', 'Type Budget', 'Ligne Budgétaire', 'Type Dépense', 'Enveloppe Arbitrée (€)', 'Consommé (€)', 'Engagé (€)', 'Total Engagé (€)', 'Reste (€)', 'Taux d\'exécution (%)' ]; } public function map($lb): array { return [ $lb->id, $lb->budget->service->nom ?? 'Agglo', $lb->budget->type_budget === 'agglo' ? 'Agglomération' : 'Mutualisé', $lb->nom, $lb->type_depense === 'fonctionnement' ? 'Fonctionnement' : 'Investissement', $lb->montant_arbitre, $lb->consomme, $lb->engage, $lb->total_cumule, $lb->reste, $lb->percent . '%' ]; } }