Add price list management across the API, store, services, routes, navigation, and sales views. Support quotes for either a client or a client group, including PDF download and nullable client validation for group-based recipients. Extend client groups to manage assigned clients directly from the form and detail views, and refresh supplier, intervention, stock, and order screens with updated interactions and layouts.
234 lines
7.4 KiB
PHP
234 lines
7.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\StoreQuoteRequest;
|
|
use App\Http\Requests\UpdateQuoteRequest;
|
|
use App\Http\Resources\QuoteResource;
|
|
use App\Models\Quote;
|
|
use App\Repositories\QuoteRepositoryInterface;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Http\Request;
|
|
use Barryvdh\DomPDF\Facade\Pdf;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use App\Mail\DocumentMail;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class QuoteController extends Controller
|
|
{
|
|
public function __construct(
|
|
protected QuoteRepositoryInterface $quoteRepository
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Display a listing of quotes.
|
|
*/
|
|
public function index(): AnonymousResourceCollection|JsonResponse
|
|
{
|
|
try {
|
|
$quotes = $this->quoteRepository->all();
|
|
return QuoteResource::collection($quotes);
|
|
} catch (\Exception $e) {
|
|
Log::error('Error fetching quotes: ' . $e->getMessage(), [
|
|
'exception' => $e,
|
|
'trace' => $e->getTraceAsString(),
|
|
]);
|
|
|
|
return response()->json([
|
|
'message' => 'Une erreur est survenue lors de la récupération des devis.',
|
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Store a newly created quote.
|
|
*/
|
|
public function store(StoreQuoteRequest $request): QuoteResource|JsonResponse
|
|
{
|
|
try {
|
|
$quote = $this->quoteRepository->create($request->validated());
|
|
return new QuoteResource($quote);
|
|
} catch (\Exception $e) {
|
|
Log::error('Error creating quote: ' . $e->getMessage(), [
|
|
'exception' => $e,
|
|
'trace' => $e->getTraceAsString(),
|
|
'data' => $request->validated(),
|
|
]);
|
|
|
|
return response()->json([
|
|
'message' => 'Une erreur est survenue lors de la création du devis.',
|
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display the specified quote.
|
|
*/
|
|
public function show(string $id): QuoteResource|JsonResponse
|
|
{
|
|
try {
|
|
$quote = $this->quoteRepository->find($id);
|
|
|
|
if (! $quote) {
|
|
return response()->json([
|
|
'message' => 'Devis non trouvé.',
|
|
], 404);
|
|
}
|
|
|
|
return new QuoteResource($quote);
|
|
} catch (\Exception $e) {
|
|
Log::error('Error fetching quote: ' . $e->getMessage(), [
|
|
'exception' => $e,
|
|
'trace' => $e->getTraceAsString(),
|
|
'quote_id' => $id,
|
|
]);
|
|
|
|
return response()->json([
|
|
'message' => 'Une erreur est survenue lors de la récupération du devis.',
|
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update the specified quote.
|
|
*/
|
|
public function update(UpdateQuoteRequest $request, string $id): QuoteResource|JsonResponse
|
|
{
|
|
try {
|
|
$updated = $this->quoteRepository->update($id, $request->validated());
|
|
|
|
if (! $updated) {
|
|
return response()->json([
|
|
'message' => 'Devis non trouvé ou échec de la mise à jour.',
|
|
], 404);
|
|
}
|
|
|
|
$quote = $this->quoteRepository->find($id);
|
|
return new QuoteResource($quote);
|
|
} catch (\Exception $e) {
|
|
Log::error('Error updating quote: ' . $e->getMessage(), [
|
|
'exception' => $e,
|
|
'trace' => $e->getTraceAsString(),
|
|
'quote_id' => $id,
|
|
'data' => $request->validated(),
|
|
]);
|
|
|
|
return response()->json([
|
|
'message' => 'Une erreur est survenue lors de la mise à jour du devis.',
|
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove the specified quote.
|
|
*/
|
|
public function destroy(string $id): JsonResponse
|
|
{
|
|
try {
|
|
$deleted = $this->quoteRepository->delete($id);
|
|
|
|
if (! $deleted) {
|
|
return response()->json([
|
|
'message' => 'Devis non trouvé ou échec de la suppression.',
|
|
], 404);
|
|
}
|
|
|
|
return response()->json([
|
|
'message' => 'Devis supprimé avec succès.',
|
|
], 200);
|
|
} catch (\Exception $e) {
|
|
Log::error('Error deleting quote: ' . $e->getMessage(), [
|
|
'exception' => $e,
|
|
'trace' => $e->getTraceAsString(),
|
|
'quote_id' => $id,
|
|
]);
|
|
|
|
return response()->json([
|
|
'message' => 'Une erreur est survenue lors de la suppression du devis.',
|
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send the quote by email to the client.
|
|
*/
|
|
public function sendByEmail(string $id): JsonResponse
|
|
{
|
|
try {
|
|
$quote = $this->quoteRepository->find($id);
|
|
|
|
if (!$quote) {
|
|
return response()->json(['message' => 'Devis non trouvé.'], 404);
|
|
}
|
|
|
|
if (!$quote->client || !$quote->client->email) {
|
|
return response()->json(['message' => 'Le client n\'a pas d\'adresse email.'], 422);
|
|
}
|
|
|
|
// Load lines to ensure they are available in the view
|
|
$quote->load('lines');
|
|
|
|
// Generate PDF
|
|
$pdfContent = Pdf::loadView('pdf.quote_pdf', ['quote' => $quote])->output();
|
|
|
|
// Send Email
|
|
Mail::to($quote->client->email)->send(new DocumentMail($quote, 'quote', $pdfContent));
|
|
|
|
return response()->json([
|
|
'message' => 'Le devis a été envoyé avec succès à ' . $quote->client->email,
|
|
], 200);
|
|
} catch (\Exception $e) {
|
|
Log::error('Error sending quote email: ' . $e->getMessage(), [
|
|
'exception' => $e,
|
|
'quote_id' => $id,
|
|
]);
|
|
|
|
return response()->json([
|
|
'message' => 'Une erreur est survenue lors de l\'envoi de l\'email.',
|
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Download the quote as a PDF.
|
|
*/
|
|
public function downloadPdf(string $id): Response|JsonResponse
|
|
{
|
|
try {
|
|
$quote = Quote::with(['client', 'group', 'lines'])->find($id);
|
|
|
|
if (! $quote) {
|
|
return response()->json([
|
|
'message' => 'Devis non trouvé.',
|
|
], 404);
|
|
}
|
|
|
|
$pdf = Pdf::loadView('pdf.quote_pdf', ['quote' => $quote]);
|
|
|
|
return $pdf->download('Devis_' . $quote->reference . '.pdf');
|
|
} catch (\Exception $e) {
|
|
Log::error('Error downloading quote PDF: ' . $e->getMessage(), [
|
|
'exception' => $e,
|
|
'quote_id' => $id,
|
|
]);
|
|
|
|
return response()->json([
|
|
'message' => 'Une erreur est survenue lors de la generation du PDF.',
|
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
|
], 500);
|
|
}
|
|
}
|
|
}
|