Files
dsi-commander/app/Http/Controllers/CommandeController.php

248 lines
10 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Article;
use App\Models\Categorie;
use App\Models\Commande;
use App\Models\Fournisseur;
use App\Models\Service;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;
class CommandeController extends Controller
{
public function index(Request $request): Response
{
$query = Commande::with(['service', 'fournisseur', 'demandeur'])
->when($request->service_id, fn ($q) => $q->parService($request->service_id))
->when($request->fournisseur_id, fn ($q) => $q->parFournisseur($request->fournisseur_id))
->when($request->statut, fn ($q) => $q->parStatut($request->statut))
->when($request->priorite, fn ($q) => $q->where('priorite', $request->priorite))
->when($request->date_from, fn ($q) => $q->whereDate('date_demande', '>=', $request->date_from))
->when($request->date_to, fn ($q) => $q->whereDate('date_demande', '<=', $request->date_to))
->when($request->search, function ($q) use ($request) {
$q->where(function ($sub) use ($request) {
$sub->where('numero_commande', 'like', "%{$request->search}%")
->orWhere('objet', 'like', "%{$request->search}%")
->orWhereHas('fournisseur', fn ($f) => $f->where('nom', 'like', "%{$request->search}%"));
});
});
$commandes = $query->latest()->paginate(20)->withQueryString();
return Inertia::render('Commandes/Index', [
'commandes' => $commandes,
'services' => Service::all(),
'fournisseurs' => Fournisseur::active()->orderBy('nom')->get(),
'filters' => $request->only(['search', 'service_id', 'fournisseur_id', 'statut', 'priorite', 'date_from', 'date_to']),
]);
}
public function create(): Response
{
$this->authorize('create', Commande::class);
return Inertia::render('Commandes/Create', [
'services' => Service::all(),
'fournisseurs' => Fournisseur::active()->orderBy('nom')->get(),
'categories' => Categorie::active()->orderBy('ordre')->get(),
'articles' => Article::active()->with('categorie')->orderBy('designation')->get(),
]);
}
public function store(Request $request): RedirectResponse
{
$this->authorize('create', Commande::class);
$validated = $request->validate([
'service_id' => 'required|exists:services,id',
'fournisseur_id' => 'nullable|exists:fournisseurs,id',
'objet' => 'required|string|max:255',
'description' => 'nullable|string',
'justification' => 'nullable|string',
'priorite' => 'required|in:normale,haute,urgente',
'reference_fournisseur' => 'nullable|string|max:100',
'imputation_budgetaire' => 'nullable|string|max:100',
'date_demande' => 'required|date',
'date_souhaitee' => 'nullable|date|after_or_equal:date_demande',
'date_livraison_prevue' => 'nullable|date',
'notes' => 'nullable|string',
'notes_fournisseur' => 'nullable|string',
'lignes' => 'array',
'lignes.*.designation' => 'required|string|max:255',
'lignes.*.reference' => 'nullable|string|max:100',
'lignes.*.quantite' => 'required|numeric|min:0.001',
'lignes.*.unite' => 'nullable|string|max:30',
'lignes.*.prix_unitaire_ht' => 'nullable|numeric|min:0',
'lignes.*.taux_tva' => 'nullable|numeric|min:0|max:100',
'lignes.*.categorie_id' => 'nullable|exists:categories,id',
'lignes.*.article_id' => 'nullable|exists:articles,id',
'lignes.*.notes' => 'nullable|string',
]);
DB::transaction(function () use ($validated, $request) {
$commande = Commande::create([
...$validated,
'numero_commande' => Commande::genererNumero(),
'user_id' => $request->user()->id,
'statut' => 'brouillon',
]);
foreach ($validated['lignes'] ?? [] as $index => $ligne) {
$commande->lignes()->create(array_merge($ligne, ['ordre' => $index]));
}
});
return redirect()->route('commandes.index')
->with('success', 'Commande créée avec succès.');
}
public function show(Commande $commande): Response
{
$this->authorize('view', $commande);
$commande->load([
'service', 'fournisseur', 'demandeur', 'validateur', 'acheteur',
'lignes.categorie',
'historique.user',
'piecesJointes.user',
]);
$transitionsDisponibles = collect(Commande::STATUT_TRANSITIONS[$commande->statut] ?? [])
->filter(fn ($statut) => request()->user()->hasRole('admin') || $this->userCanTransition(request()->user(), $commande, $statut))
->values();
return Inertia::render('Commandes/Show', [
'commande' => $commande,
'transitionsDisponibles' => $transitionsDisponibles,
]);
}
public function edit(Commande $commande): Response
{
$this->authorize('update', $commande);
$commande->load('lignes.categorie');
return Inertia::render('Commandes/Edit', [
'commande' => $commande,
'services' => Service::all(),
'fournisseurs' => Fournisseur::active()->orderBy('nom')->get(),
'categories' => Categorie::active()->orderBy('ordre')->get(),
'articles' => Article::active()->with('categorie')->orderBy('designation')->get(),
]);
}
public function update(Request $request, Commande $commande): RedirectResponse
{
$this->authorize('update', $commande);
$validated = $request->validate([
'service_id' => 'required|exists:services,id',
'fournisseur_id' => 'nullable|exists:fournisseurs,id',
'objet' => 'required|string|max:255',
'description' => 'nullable|string',
'justification' => 'nullable|string',
'priorite' => 'required|in:normale,haute,urgente',
'reference_fournisseur' => 'nullable|string|max:100',
'imputation_budgetaire' => 'nullable|string|max:100',
'date_demande' => 'required|date',
'date_souhaitee' => 'nullable|date',
'date_livraison_prevue' => 'nullable|date',
'notes' => 'nullable|string',
'notes_fournisseur' => 'nullable|string',
'lignes' => 'array',
'lignes.*.id' => 'nullable|integer',
'lignes.*.designation' => 'required|string|max:255',
'lignes.*.reference' => 'nullable|string|max:100',
'lignes.*.quantite' => 'required|numeric|min:0.001',
'lignes.*.quantite_recue' => 'nullable|numeric|min:0',
'lignes.*.unite' => 'nullable|string|max:30',
'lignes.*.prix_unitaire_ht' => 'nullable|numeric|min:0',
'lignes.*.taux_tva' => 'nullable|numeric|min:0|max:100',
'lignes.*.categorie_id' => 'nullable|exists:categories,id',
'lignes.*.article_id' => 'nullable|exists:articles,id',
'lignes.*.notes' => 'nullable|string',
]);
DB::transaction(function () use ($validated, $commande) {
$commande->update($validated);
$lignesData = $validated['lignes'] ?? [];
$lignesIds = collect($lignesData)->pluck('id')->filter()->all();
// Supprimer les lignes retirées
$commande->lignes()->whereNotIn('id', $lignesIds)->delete();
foreach ($lignesData as $index => $ligneData) {
$commande->lignes()->updateOrCreate(
['id' => $ligneData['id'] ?? null],
array_merge($ligneData, ['ordre' => $index, 'commande_id' => $commande->id])
);
}
});
return redirect()->route('commandes.show', $commande)
->with('success', 'Commande mise à jour.');
}
public function destroy(Commande $commande): RedirectResponse
{
$this->authorize('delete', $commande);
$commande->delete();
return redirect()->route('commandes.index')
->with('success', 'Commande supprimée.');
}
public function transition(Request $request, Commande $commande): RedirectResponse
{
$validated = $request->validate([
'statut' => 'required|string',
'commentaire' => 'nullable|string|max:1000',
]);
$this->authorize('transition', [$commande, $validated['statut']]);
$ok = $commande->transitionnerVers($validated['statut'], $request->user(), $validated['commentaire'] ?? null);
if (!$ok) {
return back()->with('error', 'Transition non autorisée.');
}
return redirect()->route('commandes.show', $commande)
->with('success', 'Statut mis à jour : ' . Commande::STATUTS_LABELS[$validated['statut']]);
}
private function userCanTransition($user, Commande $commande, string $statut): bool
{
try {
$this->authorize('transition', [$commande, $statut]);
return true;
} catch (\Exception) {
return false;
}
}
public function exportPdf(Commande $commande)
{
$this->authorize('view', $commande);
$commande->load([
'service', 'fournisseur', 'demandeur', 'validateur', 'acheteur',
'lignes.categorie',
]);
$pdf = \Barryvdh\DomPDF\Facade\Pdf::loadView('pdf.commande', [
'commande' => $commande,
]);
return $pdf->stream('commande-' . $commande->numero_commande . '.pdf');
}
}