diff --git a/migrations/Version20260212144324.php b/migrations/Version20260212144324.php new file mode 100644 index 0000000..a8da4ca --- /dev/null +++ b/migrations/Version20260212144324.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE facture ADD facture_file_name VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE facture ADD facture_file_size INT DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE facture DROP facture_file_name'); + $this->addSql('ALTER TABLE facture DROP facture_file_size'); + } +} diff --git a/src/Controller/Dashboard/ContratsController.php b/src/Controller/Dashboard/ContratsController.php index df7a224..76a9d98 100644 --- a/src/Controller/Dashboard/ContratsController.php +++ b/src/Controller/Dashboard/ContratsController.php @@ -7,6 +7,7 @@ use App\Entity\ContratsLine; use App\Entity\ContratsOption; use App\Entity\ContratsPayments; use App\Entity\Devis; +use App\Entity\Facture; use App\Event\Signature\ContratEvent; use App\Form\Type\ContratsType; use App\Logger\AppLogger; @@ -14,6 +15,7 @@ use App\Repository\ContratsRepository; use App\Repository\DevisRepository; use App\Service\Mailer\Mailer; use App\Service\Pdf\ContratPdfService; +use App\Service\Pdf\FacturePdfService; use App\Service\Pdf\PlPdf; use App\Service\Signature\Client; use Doctrine\ORM\EntityManagerInterface; @@ -70,7 +72,7 @@ class ContratsController extends AbstractController } #[Route('/view/{id}', name: 'app_crm_contrats_view', options: ['sitemap' => false], methods: ['GET', 'POST'])] - public function view(Contrats $contrat, Request $request): Response + public function view(Contrats $contrat,Mailer $mailer, Request $request): Response { // 1. Actions sur la Caution (Libérer / Encaisser) if ($action = $request->query->get('action')) { @@ -86,6 +88,45 @@ class ContratsController extends AbstractController if ($request->query->has('act')) { $act = $request->query->get('act'); + if ($act === 'generateInvoice') { + $facturePdfService = new FacturePdfService($this->kernel,$contrat); + // Utilisation du service pour générer le binaire du PDF + $pdfContent = $facturePdfService->generate(); + $filename = 'Facture_Ludikevent_' . $contrat->getNumReservation() . '.pdf'; + $attachment = new \Symfony\Component\Mime\Part\DataPart($pdfContent, $filename, 'application/pdf'); + $fc = $contrat->getFacture(); + if(!$fc instanceof Facture){ + $fc = new Facture(); + $fc->setContrat($contrat); + $fc->setCreateAt(new \DateTimeImmutable('now')); + $fc->setUpdateAt(new \DateTimeImmutable()); + $fc->setNum('F' . $contrat->getNumReservation()); + $this->em->persist($fc); + } + $tmpPath = sys_get_temp_dir() . '/facture_' . uniqid() . '.pdf'; + file_put_contents($tmpPath,$pdfContent); // generate() retourne le contenu ou Output('S') + + $fc->setFactureFile(new UploadedFile($tmpPath,"facture.pdf","application/pdf",0,true)); + $fc->setUpdateAt(new \DateTimeImmutable()); + $this->em->persist($fc); + $this->em->flush(); + + $mailer->send( + $contrat->getCustomer()->getEmail(), + $contrat->getCustomer()->getSurname() . ' ' . $contrat->getCustomer()->getName(), + "Votre facture Ludikevent - #" . $contrat->getNumReservation(), + "mails/customer/invoice.twig", // Créez ce template simple + ['contrat' => $contrat], + [$attachment] // Passage de la pièce jointe + ); + return new Response($pdfContent, 200, [ + 'Content-Type' => 'application/pdf', + 'Content-Disposition' => HeaderUtils::makeDisposition( + HeaderUtils::DISPOSITION_INLINE, + 'Facture_Ludikevent_' . $contrat->getNumReservation() . '.pdf' + ) + ]); + } if ($act == "downloadFilePv" && $contrat->getEtatLieux()) { $etatLieux = $contrat->getEtatLieux(); diff --git a/src/Controller/Dashboard/FactureController.php b/src/Controller/Dashboard/FactureController.php index d4cedbb..d11a79c 100644 --- a/src/Controller/Dashboard/FactureController.php +++ b/src/Controller/Dashboard/FactureController.php @@ -4,6 +4,7 @@ namespace App\Controller\Dashboard; use App\Logger\AppLogger; use App\Repository\ContratsPaymentsRepository; +use App\Repository\FactureRepository; use Doctrine\ORM\QueryBuilder; use Knp\Component\Pager\PaginatorInterface; use PhpOffice\PhpSpreadsheet\Spreadsheet; @@ -22,6 +23,7 @@ class FactureController extends AbstractController { public function __construct( private readonly ContratsPaymentsRepository $contratsPaymentsRepo, + private readonly FactureRepository $factureRepository, private readonly AppLogger $appLogger, private readonly UploaderHelper $uploaderHelper ) { @@ -43,9 +45,19 @@ class FactureController extends AbstractController ->setParameter('end', $endDate) ->orderBy('p.paymentAt', 'DESC'); + $queryBuilderFacture = $this->factureRepository->createQueryBuilder('p') + ->leftJoin('p.contrat', 'c') + ->leftJoin('c.customer', 'u') + ->where('p.createAt BETWEEN :start AND :end') + ->setParameter('start', $startDate) + ->setParameter('end', $endDate) + ->orderBy('p.createAt', 'DESC'); + if (!empty($searchTerm)) { $queryBuilder->andWhere('u.name LIKE :q OR u.surname LIKE :q OR c.numReservation LIKE :q OR p.type LIKE :q') ->setParameter('q', '%' . $searchTerm . '%'); + $queryBuilderFacture->andWhere('u.name LIKE :q OR u.surname LIKE :q OR c.numReservation LIKE :q OR p.type LIKE :q') + ->setParameter('q', '%' . $searchTerm . '%'); } // 3. Export Excel (Action Rapide) @@ -58,6 +70,7 @@ class FactureController extends AbstractController return $this->render('dashboard/contrats/facture.twig', [ 'pagination' => $paginator->paginate($queryBuilder, $request->query->getInt('page', 1), 15), + 'pagination2' => $paginator->paginate($queryBuilderFacture, $request->query->getInt('page', 1), 15), 'startDate' => $startDate->format('Y-m-d'), 'endDate' => $endDate->format('Y-m-d'), 'searchTerm' => $searchTerm, diff --git a/src/Entity/Facture.php b/src/Entity/Facture.php index 7cbee9e..13eebda 100644 --- a/src/Entity/Facture.php +++ b/src/Entity/Facture.php @@ -4,8 +4,12 @@ namespace App\Entity; use App\Repository\FactureRepository; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\HttpFoundation\File\File; +use Vich\UploaderBundle\Mapping\Attribute\Uploadable; +use Vich\UploaderBundle\Mapping\Attribute\UploadableField; #[ORM\Entity(repositoryClass: FactureRepository::class)] +#[Uploadable] class Facture { #[ORM\Id] @@ -25,6 +29,12 @@ class Facture #[ORM\Column] private ?\DateTimeImmutable $updateAt = null; + #[UploadableField(mapping: 'contrat_docuseal', fileNameProperty: 'factureFileName', size: 'factureFileSize')] + private ?File $factureFile = null; + #[ORM\Column(nullable: true)] + private ?string $factureFileName = null; + #[ORM\Column(nullable: true)] + private ?int $factureFileSize = null; public function getId(): ?int { return $this->id; @@ -77,4 +87,52 @@ class Facture return $this; } + + /** + * @return string|null + */ + public function getFactureFileName(): ?string + { + return $this->factureFileName; + } + + /** + * @return File|null + */ + public function getFactureFile(): ?File + { + return $this->factureFile; + } + + /** + * @return int|null + */ + public function getFactureFileSize(): ?int + { + return $this->factureFileSize; + } + + /** + * @param string|null $factureFileName + */ + public function setFactureFileName(?string $factureFileName): void + { + $this->factureFileName = $factureFileName; + } + + /** + * @param File|null $factureFile + */ + public function setFactureFile(?File $factureFile): void + { + $this->factureFile = $factureFile; + } + + /** + * @param int|null $factureFileSize + */ + public function setFactureFileSize(?int $factureFileSize): void + { + $this->factureFileSize = $factureFileSize; + } } diff --git a/src/Service/Pdf/FacturePdfService.php b/src/Service/Pdf/FacturePdfService.php new file mode 100644 index 0000000..f14f993 --- /dev/null +++ b/src/Service/Pdf/FacturePdfService.php @@ -0,0 +1,298 @@ +contrat = $contrat; + $this->logo = $kernel->getProjectDir()."/public/provider/images/favicon.png"; + + $this->AliasNbPages(); + $this->SetAutoPageBreak(true, 30); + } + + protected function clean(?string $text): string + { + if (!$text) return ''; + $text = iconv('UTF-8', 'windows-1252//TRANSLIT//IGNORE', $text); + return str_replace('€', chr(128), $text); + } + + protected function euro(): string + { + return ' ' . chr(128); + } + + public function Header() + { + if ($this->page > 0 && !$this->isExtraPage) { + $this->SetY(10); + if (file_exists($this->logo)) { + $this->Image($this->logo, 10, 10, 12); + $this->SetX(25); + } + + $this->SetFont('Arial', 'B', 14); + $this->Cell(0, 7, $this->clean('Lilian SEGARD - Ludikevent'), 0, 1, 'L'); + + $this->SetX(25); + $this->SetFont('Arial', '', 8); + $this->SetTextColor(80, 80, 80); + $this->Cell(0, 4, $this->clean('SIRET : 930 488 408 00012 | RCS : 930 488 408'), 0, 1, 'L'); + $this->SetX(25); + $this->Cell(0, 4, $this->clean('6 Rue du Château – 02800 Danizy – France'), 0, 1, 'L'); + $this->SetX(25); + $this->Cell(0, 4, $this->clean('contact@ludikevent.fr | 06 14 17 24 47'), 0, 1, 'L'); + + $this->SetY(40); + $this->SetFont('Arial', 'B', 18); + $this->SetTextColor(37, 99, 235); + // On utilise le numéro de réservation comme base de numéro de facture + $this->Cell(0, 10, $this->clean('FACTURE N° F' . $this->contrat->getNumReservation()), 0, 1, 'L'); + + $this->SetFont('Arial', '', 10); + $this->SetTextColor(0, 0, 0); + $this->Cell(0, 5, $this->clean('Date de facturation : ' . date('d/m/Y')), 0, 1, 'L'); + $this->Cell(0, 5, $this->clean('Référence commande : #' . $this->contrat->getNumReservation()), 0, 1, 'L'); + + $this->Ln(5); + $this->SetDrawColor(37, 99, 235); + $this->SetLineWidth(0.5); + $this->Line(10, $this->GetY(), 200, $this->GetY()); + } + } + + public function generate(): string + { + $this->AddPage(); + $this->renderCustomerBlock(); + $this->renderInvoiceTable(); + $this->renderPaymentsHistory(); + $this->renderFooterMentions(); + return $this->Output('S'); + } + + private function renderCustomerBlock(): void + { + $this->SetY(65); + $this->SetFont('Arial', 'B', 10); + $this->SetFillColor(245, 245, 245); + $this->Cell(95, 7, $this->clean(" FACTURÉ À"), 0, 0, 'L', true); + $this->Cell(5, 7, "", 0, 0); + $this->Cell(95, 7, $this->clean(" DÉTAILS ÉVÉNEMENT"), 0, 1, 'L', true); + + $this->Ln(2); + $startY = $this->GetY(); + $this->SetFont('Arial', '', 10); + + // Client + $this->SetX(10); + $customer = $this->contrat->getCustomer(); + $this->MultiCell(95, 5, $this->clean( + $customer->getSurname() . ' ' . $customer->getName() . "\n" . + $this->contrat->getAddressEvent() . "\n" . + $this->contrat->getZipCodeEvent() . " " . $this->contrat->getTownEvent() + ), 0, 'L'); + + // Event + $this->SetXY(110, $startY); + $this->MultiCell(95, 5, $this->clean( + "Date début : " . $this->contrat->getDateAt()->format('d/m/Y') . "\n" . + "Date fin : " . $this->contrat->getEndAt()->format('d/m/Y') . "\n" . + "Lieu : " . $this->contrat->getTownEvent() + ), 0, 'L'); + + $this->Ln(10); + } + + private function renderInvoiceTable(): void + { + $tvaEnabled = isset($_ENV['TVA_ENABLED']) && $_ENV['TVA_ENABLED'] === "true"; + $tvaRate = $tvaEnabled ? 0.20 : 0; + + $this->SetFont('Arial', 'B', 9); + $this->SetFillColor(37, 99, 235); + $this->SetTextColor(255, 255, 255); + $this->Cell(110, 8, $this->clean("Désignation"), 1, 0, 'L', true); + $this->Cell(40, 8, $this->clean("Quantité / Durée"), 1, 0, 'C', true); + $this->Cell(40, 8, $this->clean("Total HT"), 1, 1, 'C', true); + + $this->SetTextColor(0, 0, 0); + $this->SetFont('Arial', '', 9); + + $totalHt = 0; + $devis = $this->contrat->getDevis(); + $formule = $devis?->getFormule(); + $interval = $this->contrat->getDateAt()->diff($this->contrat->getEndAt()); + $nbJours = $interval->days + 1; + + // Logique Formule ou Lignes standards + if ($formule) { + $fPrice = $formule->getPrice1j() ?? 0; + if ($nbJours >= 2 && $formule->getPrice2j()) $fPrice = $formule->getPrice2j(); + if ($nbJours >= 5 && $formule->getPrice5j()) $fPrice = $formule->getPrice5j(); + + $this->Cell(110, 7, $this->clean("Location Formule : " . $formule->getName()), 1, 0, 'L'); + $this->Cell(40, 7, $nbJours . " jour(s)", 1, 0, 'C'); + $this->Cell(40, 7, number_format($fPrice, 2, ',', ' ') . $this->euro(), 1, 1, 'R'); + $totalHt += $fPrice; + } + + foreach ($this->contrat->getContratsLines() as $line) { + if (!$formule) { + $price = $line->getPrice1DayHt() + ($line->getPriceSupDayHt() * ($nbJours - 1)); + $this->Cell(110, 7, $this->clean($line->getName()), 1, 0, 'L'); + $this->Cell(40, 7, $nbJours . " jour(s)", 1, 0, 'C'); + $this->Cell(40, 7, number_format($price, 2, ',', ' ') . $this->euro(), 1, 1, 'R'); + $totalHt += $price; + } else { + // Si formule, les lignes sont listées à 0 pour info + $this->SetTextColor(100, 100, 100); + $this->Cell(110, 6, $this->clean(" - " . $line->getName()), 1, 0, 'L'); + $this->Cell(40, 6, "Inclus", 1, 0, 'C'); + $this->Cell(40, 6, "0,00" . $this->euro(), 1, 1, 'R'); + $this->SetTextColor(0, 0, 0); + } + } + + foreach ($this->contrat->getContratsOptions() as $opt) { + $priceOpt = ($formule && stripos($opt->getName(), 'livraison') === false) ? 0 : $opt->getPrice(); + $this->Cell(110, 7, $this->clean("Option : " . $opt->getName()), 1, 0, 'L'); + $this->Cell(40, 7, "Forfait", 1, 0, 'C'); + $this->Cell(40, 7, number_format($priceOpt, 2, ',', ' ') . $this->euro(), 1, 1, 'R'); + $totalHt += $priceOpt; + } + + // Remises + $promotion = $devis?->getOrderSession()?->getPromotion(); + if ($promotion) { + $discount = $totalHt * (($promotion['percentage'] ?? 0) / 100); + $this->SetTextColor(37, 99, 235); + $this->Cell(150, 7, $this->clean("Remise : " . $promotion['name'] . " (-" . $promotion['percentage'] . "%)"), 1, 0, 'L'); + $this->Cell(40, 7, "-" . number_format($discount, 2, ',', ' ') . $this->euro(), 1, 1, 'R'); + $totalHt -= $discount; + $this->SetTextColor(0, 0, 0); + } + + // Totaux + $this->Ln(5); + $this->SetX(120); + $this->SetFont('Arial', 'B', 10); + $this->Cell(40, 8, $this->clean("TOTAL HT"), 0, 0, 'L'); + $this->Cell(30, 8, number_format($totalHt, 2, ',', ' ') . $this->euro(), 0, 1, 'R'); + + if ($tvaEnabled) { + $tvaVal = $totalHt * $tvaRate; + $this->SetX(120); + $this->SetFont('Arial', '', 10); + $this->Cell(40, 8, $this->clean("TVA (20%)"), 0, 0, 'L'); + $this->Cell(30, 8, number_format($tvaVal, 2, ',', ' ') . $this->euro(), 0, 1, 'R'); + $totalTtc = $totalHt + $tvaVal; + } else { + $totalTtc = $totalHt; + } + + $this->SetX(120); + $this->SetFont('Arial', 'B', 12); + $this->SetFillColor(37, 99, 235); $this->SetTextColor(255, 255, 255); + $this->Cell(40, 10, $this->clean(" TOTAL TTC"), 0, 0, 'L', true); + $this->Cell(30, 10, number_format($totalTtc, 2, ',', ' ') . $this->euro(), 0, 1, 'R', true); + $this->SetTextColor(0, 0, 0); + } + + private function renderPaymentsHistory(): void + { + $this->Ln(10); + $this->SetFont('Arial', 'B', 10); + $this->Cell(0, 7, $this->clean("RÈGLEMENTS REÇUS"), 'B', 1, 'L'); + $this->Ln(2); + + $this->SetFont('Arial', '', 9); + $totalPaid = 0; + foreach ($this->contrat->getContratsPayments() as $payment) { + if ($payment->getType() !== 'caution' && str_contains(strtolower($payment->getState()), 'complete')) { + $this->Cell(50, 6, $payment->getPaymentAt()->format('d/m/Y'), 0, 0, 'L'); + $this->Cell(100, 6, $this->clean("Paiement " . $payment->getType()), 0, 0, 'L'); + $this->Cell(40, 6, number_format($payment->getAmount(), 2, ',', ' ') . $this->euro(), 0, 1, 'R'); + $totalPaid += $payment->getAmount(); + } + } + + $this->Ln(2); + $this->SetFont('Arial', 'B', 11); + $solde = $this->getTotalTtc() - $totalPaid; + + $this->Cell(150, 8, $this->clean("SOLDE À PAYER"), 0, 0, 'R'); + if($solde <=0.05){ + $this->SetTextColor(16,185,129); + } else { + $this->SetTextColor(200,38,38); + } + $this->Cell(40, 8, number_format(max(0, $solde), 2, ',', ' ') . $this->euro(), 0, 1, 'R'); + $this->SetTextColor(0, 0, 0); + } + + private function getTotalTtc(): float + { + $totalHt = 0; + $nbJours = $this->contrat->getDateAt()->diff($this->contrat->getEndAt())->days + 1; + $devis = $this->contrat->getDevis(); + $formule = $devis?->getFormule(); + + if ($formule) { + $fPrice = $formule->getPrice1j() ?? 0; + if ($nbJours >= 2 && $formule->getPrice2j()) $fPrice = $formule->getPrice2j(); + if ($nbJours >= 5 && $formule->getPrice5j()) $fPrice = $formule->getPrice5j(); + $totalHt += $fPrice; + } + + foreach ($this->contrat->getContratsLines() as $line) { + if (!$formule) $totalHt += $line->getPrice1DayHt() + ($line->getPriceSupDayHt() * ($nbJours - 1)); + } + + foreach ($this->contrat->getContratsOptions() as $opt) { + $totalHt += ($formule && stripos($opt->getName(), 'livraison') === false) ? 0 : $opt->getPrice(); + } + + if ($devis && $devis->getOrderSession() && $devis->getOrderSession()->getPromotion()) { + $totalHt -= $totalHt * (($devis->getOrderSession()->getPromotion()['percentage'] ?? 0) / 100); + } + + $tvaEnabled = isset($_ENV['TVA_ENABLED']) && $_ENV['TVA_ENABLED'] === "true"; + return $tvaEnabled ? $totalHt * 1.20 : $totalHt; + } + + private function renderFooterMentions(): void + { + $this->SetY(-40); + $this->SetFont('Arial', 'I', 8); + $this->SetTextColor(100, 100, 100); + + if (!(isset($_ENV['TVA_ENABLED']) && $_ENV['TVA_ENABLED'] === "true")) { + $this->Cell(0, 4, $this->clean("TVA non applicable, art. 293 B du CGI"), 0, 1, 'C'); + } + + $this->Cell(0, 4, $this->clean("En votre aimable règlement. Cordialement,"), 0, 1, 'C'); + $this->SetFont('Arial', 'B', 8); + $this->Cell(0, 4, $this->clean("Ludikevent - Lilian SEGARD"), 0, 1, 'C'); + } + + public function Footer() + { + $this->SetY(-15); + $this->SetFont('Arial', 'I', 7); + $this->SetTextColor(150, 150, 150); + $this->Cell(0, 10, $this->clean('Facture F' . $this->contrat->getNumReservation() . ' - Page ' . $this->PageNo() . '/{nb}'), 0, 0, 'C'); + } +} diff --git a/templates/dashboard/base.twig b/templates/dashboard/base.twig index 980fca8..4661193 100644 --- a/templates/dashboard/base.twig +++ b/templates/dashboard/base.twig @@ -46,16 +46,16 @@ {% import _self as menu %} {{ menu.nav_link(path('app_crm'), 'Dashboard', '', 'app_crm') }} -{# {{ menu.nav_link(path('app_crm_reservation'), 'Planing de réservation', '', 'app_crm_reservation') }}#} + {{ menu.nav_link(path('app_crm_reservation'), 'Planing de réservation', '', 'app_crm_reservation') }} {{ menu.nav_link(path('app_template_point_controle_index'), 'Modèles de contrôle', '', 'app_template_point_controle_index') }} {{ menu.nav_link(path('app_crm_product'), 'Produits', '', 'app_crm_product') }} {{ menu.nav_link(path('app_crm_formules'), 'Formules', '', 'app_crm_formules') }} -{# {{ menu.nav_link(path('app_crm_promotion'), 'Promotions', '', 'app_crm_promotion') }}#} -{# {{ menu.nav_link(path('app_crm_facture'), 'Facture', '', 'app_crm_facture') }}#} + {{ menu.nav_link(path('app_crm_promotion'), 'Promotions', '', 'app_crm_promotion') }} + {{ menu.nav_link(path('app_crm_facture'), 'Facture', '', 'app_crm_facture') }} {{ menu.nav_link(path('app_crm_customer'), 'Clients', '', 'app_crm_customer') }} -{# {{ menu.nav_link(path('app_crm_devis'), 'Devis', '', 'app_crm_devis') }}#} -{# {{ menu.nav_link(path('app_crm_contrats'), 'Contrat de location', '', 'app_crm_contrats') }}#} -{# {{ menu.nav_link(path('app_crm_prestataire'), 'Prestataires', '', 'app_crm_prestataire') }}#} + {{ menu.nav_link(path('app_crm_devis'), 'Devis', '', 'app_crm_devis') }} + {{ menu.nav_link(path('app_crm_contrats'), 'Contrat de location', '', 'app_crm_contrats') }} + {{ menu.nav_link(path('app_crm_prestataire'), 'Prestataires', '', 'app_crm_prestataire') }} {% set pendingCount = getPendingOrderSessionCount() %} diff --git a/templates/dashboard/contrats/facture.twig b/templates/dashboard/contrats/facture.twig index 9d6235d..cdcfd94 100644 --- a/templates/dashboard/contrats/facture.twig +++ b/templates/dashboard/contrats/facture.twig @@ -111,12 +111,62 @@ Date Client - Montant TTC Statut - Section factures en développement + {% for confirmedPaiement in pagination2 %} + + +
+ {{ confirmedPaiement.createAt|date('d/m/Y') }} + Encaissé +
+ + + +
+ + {{ confirmedPaiement.contrat.customer.name }} {{ confirmedPaiement.contrat.customer.surname }} + + {{ confirmedPaiement.contrat.customer.email }} +
+ + + + + {{ confirmedPaiement.contrat.numReservation }} + + + + + + {% if confirmedPaiement.factureFileName !="" %} +
+ + + + + {% else %} + Aucun fichier + {% endif %} + + + {% else %} + + +
+ + + +

Aucune donnée trouvée pour cette recherche

+
+ + + {% endfor %} diff --git a/templates/dashboard/contrats/list.twig b/templates/dashboard/contrats/list.twig index da0460f..c8e8db8 100644 --- a/templates/dashboard/contrats/list.twig +++ b/templates/dashboard/contrats/list.twig @@ -95,6 +95,7 @@ 'edl_validated': { 'color': 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30', 'label': '✅ EDL Validé' }, 'return_edl_progress': { 'color': 'bg-orange-500/10 text-orange-400 border-orange-500/20', 'label': '🔍 EDL Retour...' }, 'edl_return_done': { 'color': 'bg-purple-500/10 text-purple-400 border-purple-500/20', 'label': '📦 Retour Effectué' }, + 'edl_return_finised': { 'color': 'bg-purple-500/10 text-purple-400 border-purple-500/20', 'label': '📦 Retour Effectué' }, 'edl_return_refused': { 'color': 'bg-red-600 text-white border-red-500', 'label': '❌ Signature Refusée' } } %} diff --git a/templates/dashboard/contrats/view.twig b/templates/dashboard/contrats/view.twig index 827fa5a..742e110 100644 --- a/templates/dashboard/contrats/view.twig +++ b/templates/dashboard/contrats/view.twig @@ -4,6 +4,16 @@ {% block actions %}