authorize('viewAny', Source::class); $user = auth()->user(); $query = Source::with(['sourceType', 'depot', 'lieu']) ->withCount('releves'); if (! $user->isSectionManager()) { $assignedIds = $user->sourcesAssignees()->pluck('sources.id'); $query->where(function ($q) use ($assignedIds) { $q->where('status', SourceStatus::Termine) ->orWhereIn('id', $assignedIds); }); } if ($request->filled('status')) { $query->where('status', $request->input('status')); } if ($request->filled('source_type_id')) { $query->where('source_type_id', $request->integer('source_type_id')); } if ($request->filled('lieu_id')) { $lieuIds = $this->getLieuDescendantIds($request->integer('lieu_id')); $query->whereIn('lieu_id', $lieuIds); } if ($request->filled('annee_debut')) { $annee = $request->integer('annee_debut'); $query->where(function ($q) use ($annee) { $q->whereNull('annee_fin')->orWhere('annee_fin', '>=', $annee); }); } if ($request->filled('annee_fin')) { $annee = $request->integer('annee_fin'); $query->where(function ($q) use ($annee) { $q->whereNull('annee_debut')->orWhere('annee_debut', '<=', $annee); }); } $sourceTypes = SourceType::orderBy('nom')->get(['id', 'nom']); $lieuSelectionne = $request->filled('lieu_id') ? Lieu::find($request->integer('lieu_id'), ['id', 'nom', 'nom_long']) : null; $sources = $query->orderBy('nom')->paginate(25)->withQueryString(); return view('sources.index', compact('sources', 'sourceTypes', 'lieuSelectionne')); } private function getLieuDescendantIds(int $lieuId): array { $rows = DB::select(" WITH RECURSIVE descendants AS ( SELECT id FROM lieux WHERE id = ? UNION ALL SELECT l.id FROM lieux l INNER JOIN descendants d ON l.lieu_parent_id = d.id ) SELECT id FROM descendants ", [$lieuId]); return collect($rows)->pluck('id')->toArray(); } public function create(): View { $this->authorize('create', Source::class); $user = auth()->user(); $sourceTypes = SourceType::orderBy('nom')->get(['id', 'nom']); $depots = Depot::orderBy('nom')->get(['id', 'nom']); $sections = $user->isAdmin() ? Section::orderBy('nom')->get(['id', 'nom']) : $user->sections()->orderBy('nom')->get(['id', 'nom']); return view('sources.create', compact('sourceTypes', 'depots', 'sections')); } public function store(StoreSourceRequest $request): RedirectResponse { $source = Source::create($request->validated()); return redirect()->route('sources.show', $source) ->with('success', 'Source créée.'); } public function show(Source $source): View { $this->authorize('view', $source); $source->load(['sourceType.fields', 'depot', 'section', 'membres', 'releves']); $availableUsers = User::where('is_active', true)->orderBy('name')->get(['id', 'name', 'email']); return view('sources.show', compact('source', 'availableUsers')); } public function edit(Source $source): View { $this->authorize('update', $source); $source->loadMissing('lieu', 'section'); $user = auth()->user(); $sourceTypes = SourceType::orderBy('nom')->get(['id', 'nom']); $depots = Depot::orderBy('nom')->get(['id', 'nom']); $sections = $user->isAdmin() ? Section::orderBy('nom')->get(['id', 'nom']) : $user->sections()->orderBy('nom')->get(['id', 'nom']); return view('sources.edit', compact('source', 'sourceTypes', 'depots', 'sections')); } public function update(UpdateSourceRequest $request, Source $source): RedirectResponse { $source->update($request->validated()); return redirect()->route('sources.show', $source) ->with('success', 'Source mise à jour.'); } public function destroy(Source $source): RedirectResponse { $this->authorize('delete', $source); $source->delete(); return redirect()->route('sources.index') ->with('success', 'Source supprimée.'); } public function addMembre(Request $request, Source $source): RedirectResponse { $this->authorize('assignMembre', $source); $data = $request->validate([ 'user_id' => ['required', 'exists:users,id'], ]); $source->membres()->syncWithoutDetaching([$data['user_id']]); // Passer automatiquement en_cours si la source est à_faire if ($source->status === SourceStatus::AFaire) { $source->update(['status' => SourceStatus::EnCours]); } return back()->with('success', 'Membre assigné.'); } public function removeMembre(Source $source, User $user): RedirectResponse { $this->authorize('assignMembre', $source); $source->membres()->detach($user->id); return back()->with('success', 'Membre retiré.'); } public function transition(Request $request, Source $source): RedirectResponse { $this->authorize('transition', $source); $data = $request->validate([ 'status' => ['required', 'string'], ]); $newStatus = SourceStatus::from($data['status']); if (! $source->canTransitionTo($newStatus, auth()->user())) { return back()->with('error', 'Transition non autorisée.'); } $previousStatus = $source->status; $source->update(['status' => $newStatus]); $user = auth()->user(); if ($newStatus === SourceStatus::AValider) { // Notifier admins + responsables de section $source->load('sourceType', 'depot'); User::whereIn('role', ['admin', 'section_manager']) ->where('id', '!=', $user->id) ->get() ->each(fn ($u) => $u->notify(new SourceAValiderNotification($source, $user))); } if ($newStatus === SourceStatus::EnCours && $previousStatus === SourceStatus::AValider) { // Rejet : notifier les membres assignés $source->membres() ->where('users.id', '!=', $user->id) ->get() ->each(fn ($m) => $m->notify(new SourceRejeteeNotification($source, $user))); } return back()->with('success', 'Statut mis à jour : ' . $newStatus->label()); } }