```
✨ feat(ReserverController): Génère un devis PDF provisoire basé sur la session. 🎨 style(flow_confirmed.twig): Ajoute un lien pour télécharger le devis provisoire. ```
This commit is contained in:
@@ -24,11 +24,15 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use App\Service\Pdf\DevisPdfService;
|
||||
use App\Entity\Devis;
|
||||
use App\Entity\DevisLine;
|
||||
use App\Entity\CustomerAddress;
|
||||
|
||||
class ReserverController extends AbstractController
|
||||
{
|
||||
@@ -40,6 +44,88 @@ class ReserverController extends AbstractController
|
||||
$this->kernel = $kernel;
|
||||
}
|
||||
|
||||
#[Route('/flow/{sessionId}/devis', name: 'reservation_generate_devis', methods: ['GET'])]
|
||||
public function generateDevis(
|
||||
string $sessionId,
|
||||
OrderSessionRepository $repository,
|
||||
ProductRepository $productRepository,
|
||||
KernelInterface $kernel
|
||||
): Response {
|
||||
$session = $repository->findOneBy(['uuid' => $sessionId]);
|
||||
if (!$session) {
|
||||
return $this->redirectToRoute('reservation');
|
||||
}
|
||||
|
||||
$sessionData = $session->getProducts();
|
||||
$ids = $sessionData['ids'] ?? [];
|
||||
$startStr = $sessionData['start'] ?? null;
|
||||
$endStr = $sessionData['end'] ?? null;
|
||||
|
||||
// Calcul de la durée
|
||||
$duration = 1;
|
||||
$start = null;
|
||||
$end = null;
|
||||
if ($startStr && $endStr) {
|
||||
try {
|
||||
$start = new \DateTimeImmutable($startStr);
|
||||
$end = new \DateTimeImmutable($endStr);
|
||||
if ($end >= $start) {
|
||||
$duration = $start->diff($end)->days + 1;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$duration = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Création des objets temporaires pour le PDF
|
||||
$customer = new Customer();
|
||||
$customer->setName($session->getCustomer() ? $session->getCustomer()->getName() : 'Client');
|
||||
$customer->setSurname($session->getCustomer() ? $session->getCustomer()->getSurname() : 'Temporaire');
|
||||
$customer->setEmail($session->getCustomer() ? $session->getCustomer()->getEmail() : '');
|
||||
$customer->setPhone($session->getCustomer() ? $session->getCustomer()->getPhone() : '');
|
||||
|
||||
// Adresse de facturation
|
||||
$billAddress = new CustomerAddress();
|
||||
$billAddress->setAddress($session->getBillingAddress() ?? '');
|
||||
$billAddress->setZipcode($session->getBillingZipCode() ?? '');
|
||||
$billAddress->setCity($session->getBillingTown() ?? '');
|
||||
|
||||
// Adresse de prestation
|
||||
$shipAddress = new CustomerAddress();
|
||||
$shipAddress->setAddress($session->getAdressEvent() ?? '');
|
||||
$shipAddress->setAddress2($session->getAdress2Event() ?? '');
|
||||
$shipAddress->setZipcode($session->getZipCodeEvent() ?? '');
|
||||
$shipAddress->setCity($session->getTownEvent() ?? '');
|
||||
|
||||
$devis = new Devis();
|
||||
$devis->setCustomer($customer);
|
||||
$devis->setBillAddress($billAddress);
|
||||
$devis->setAddressShip($shipAddress);
|
||||
$devis->setNum('PROVISOIRE');
|
||||
$devis->setStartAt($start);
|
||||
$devis->setEndAt($end);
|
||||
|
||||
if (!empty($ids)) {
|
||||
$products = $productRepository->findBy(['id' => $ids]);
|
||||
foreach ($products as $product) {
|
||||
$line = new DevisLine();
|
||||
$line->setProduct($product->getName());
|
||||
$line->setPriceHt($product->getPriceDay());
|
||||
$line->setPriceHtSup($product->getPriceSup());
|
||||
$line->setDay($duration);
|
||||
$devis->addDevisLine($line);
|
||||
}
|
||||
}
|
||||
|
||||
$pdfService = new DevisPdfService($kernel, $devis, $productRepository);
|
||||
$content = $pdfService->generate();
|
||||
|
||||
return new Response($content, 200, [
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-Disposition' => 'attachment; filename="devis_provisoire.pdf"'
|
||||
]);
|
||||
}
|
||||
|
||||
private function loadSimplifiedCommunes(): array
|
||||
{
|
||||
if ($this->simplifiedCommunes !== null) {
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<div class="flex-1">
|
||||
<h4 class="font-bold text-slate-800">{{ item.product.name }}</h4>
|
||||
<p class="text-xs text-slate-500 line-clamp-1 mb-2">{{ item.product.description }}</p>
|
||||
|
||||
|
||||
<div class="text-xs text-slate-600 bg-slate-50 p-2 rounded-lg border border-slate-100 inline-block">
|
||||
<div class="flex flex-wrap gap-x-3 gap-y-1">
|
||||
<span>1er jour : <strong class="text-slate-800">{{ item.price1Day|number_format(2, ',', ' ') }} €</strong></span>
|
||||
@@ -115,7 +115,7 @@
|
||||
</svg>
|
||||
Informations de l'événement
|
||||
</h3>
|
||||
|
||||
|
||||
{# Billing Address #}
|
||||
<div>
|
||||
<div class="flex items-center gap-3 mb-6 pb-2 border-b border-slate-100">
|
||||
@@ -124,7 +124,7 @@
|
||||
</span>
|
||||
<h4 class="font-bold text-lg text-slate-900">Adresse de facturation</h4>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="md:col-span-2">
|
||||
<span class="block text-xs text-slate-500 uppercase tracking-wide mb-2">Adresse complète</span>
|
||||
@@ -214,7 +214,10 @@
|
||||
</div>
|
||||
|
||||
<div class="pt-6 border-t border-slate-100 mt-8 flex flex-col md:flex-row justify-center gap-4">
|
||||
<a href="#" class="w-full md:w-auto px-8 py-4 bg-gray-200 text-gray-800 font-bold rounded-2xl shadow-sm hover:shadow-md hover:scale-[1.01] transition-all flex items-center justify-center gap-2 text-lg">
|
||||
<a data-turbo="false" href="{{ path('reservation_generate_devis', {sessionId: session.uuid}) }}" class="w-full md:w-auto px-8 py-4 bg-gray-200 text-gray-800 font-bold rounded-2xl shadow-sm hover:shadow-md hover:scale-[1.01] transition-all flex items-center justify-center gap-2 text-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
Télécharger le devis
|
||||
</a>
|
||||
<a href="#" class="w-full md:w-auto px-8 py-4 bg-green-500 text-white font-bold rounded-2xl shadow-lg shadow-green-200 hover:shadow-xl hover:scale-[1.02] transition-all flex items-center justify-center gap-2 text-lg">
|
||||
|
||||
Reference in New Issue
Block a user