diff --git a/src/Controller/Admin/EcheancierController.php b/src/Controller/Admin/EcheancierController.php index 6968aaf..136f1df 100644 --- a/src/Controller/Admin/EcheancierController.php +++ b/src/Controller/Admin/EcheancierController.php @@ -296,7 +296,7 @@ class EcheancierController extends AbstractController $slug = $docuSeal->getSubmitterSlug($submitterId); $signUrl = null !== $slug ? rtrim($docuSealUrl, '/').'/s/'.$slug : null; - $processUrl = $urlGenerator->generate('app_echeancier_process', [ + $processUrl = $urlGenerator->generate('app_echeancier_verify', [ 'id' => $echeancier->getId(), ], UrlGeneratorInterface::ABSOLUTE_URL); diff --git a/src/Controller/EcheancierProcessController.php b/src/Controller/EcheancierProcessController.php index cf44d7f..a812049 100644 --- a/src/Controller/EcheancierProcessController.php +++ b/src/Controller/EcheancierProcessController.php @@ -3,29 +3,118 @@ namespace App\Controller; use App\Entity\Echeancier; +use App\Service\DocuSealService; +use App\Service\MailerService; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; +use Twig\Environment; class EcheancierProcessController extends AbstractController { public function __construct( private EntityManagerInterface $em, + private MailerService $mailer, + private Environment $twig, ) { } /** - * Page de detail echeancier avant signature (publique). + * Verification par code email avant d'acceder a l'echeancier. */ - #[Route('/echeancier/process/{id}', name: 'app_echeancier_process', requirements: ['id' => '\d+'])] - public function process(int $id): Response + #[Route('/echeancier/verify/{id}', name: 'app_echeancier_verify', requirements: ['id' => '\d+'])] + public function verify(int $id, Request $request): Response { $echeancier = $this->em->getRepository(Echeancier::class)->find($id); if (null === $echeancier) { throw $this->createNotFoundException('Echeancier introuvable.'); } + $customer = $echeancier->getCustomer(); + $session = $request->getSession(); + $sessionKey = 'echeancier_verified_'.$echeancier->getId(); + + if ($session->get($sessionKey, false)) { + return $this->redirectToRoute('app_echeancier_process', ['id' => $id]); + } + + if (null === $customer->getEmail()) { + $session->set($sessionKey, true); + + return $this->redirectToRoute('app_echeancier_process', ['id' => $id]); + } + + $codeKey = 'echeancier_code_'.$id; + $codeExpiresKey = 'echeancier_code_expires_'.$id; + $error = null; + + if ('POST' === $request->getMethod()) { + $code = trim($request->request->getString('code')); + $storedCode = $session->get($codeKey); + $expiresAt = $session->get($codeExpiresKey, 0); + + if (time() > $expiresAt) { + $error = 'Code expire. Cliquez sur "Renvoyer" pour en recevoir un nouveau.'; + $session->remove($codeKey); + $session->remove($codeExpiresKey); + } elseif ($code === $storedCode) { + $session->set($sessionKey, true); + $session->remove($codeKey); + $session->remove($codeExpiresKey); + + return $this->redirectToRoute('app_echeancier_process', ['id' => $id]); + } else { + $error = 'Code incorrect. Veuillez reessayer.'; + } + } + + // Envoyer le code si pas encore envoye ou expire + if (null === $session->get($codeKey) || time() > $session->get($codeExpiresKey, 0)) { + $code = str_pad((string) random_int(0, 999999), 6, '0', \STR_PAD_LEFT); + $session->set($codeKey, $code); + $session->set($codeExpiresKey, time() + 900); + + $this->mailer->sendEmail( + $customer->getEmail(), + 'Code de verification - Echeancier', + $this->twig->render('emails/order_verify_code.html.twig', [ + 'customer' => $customer, + 'advert' => null, + 'code' => $code, + ]), + null, + null, + false, + ); + } + + return $this->render('echeancier/verify.html.twig', [ + 'echeancier' => $echeancier, + 'customer' => $customer, + 'error' => $error, + ]); + } + + /** + * Page de detail echeancier avant signature (protegee par code). + */ + #[Route('/echeancier/process/{id}', name: 'app_echeancier_process', requirements: ['id' => '\d+'])] + public function process(int $id, Request $request): Response + { + $echeancier = $this->em->getRepository(Echeancier::class)->find($id); + if (null === $echeancier) { + throw $this->createNotFoundException('Echeancier introuvable.'); + } + + // Verifier si authentifie + $session = $request->getSession(); + if (!$session->get('echeancier_verified_'.$echeancier->getId(), false)) { + return $this->redirectToRoute('app_echeancier_verify', ['id' => $id]); + } + if (\in_array($echeancier->getState(), [Echeancier::STATE_SIGNED, Echeancier::STATE_ACTIVE, Echeancier::STATE_COMPLETED], true)) { return $this->render('echeancier/signed.html.twig', [ 'echeancier' => $echeancier, @@ -33,12 +122,66 @@ class EcheancierProcessController extends AbstractController ]); } + if (Echeancier::STATE_CANCELLED === $echeancier->getState()) { + return $this->render('echeancier/refused.html.twig', [ + 'echeancier' => $echeancier, + 'customer' => $echeancier->getCustomer(), + ]); + } + return $this->render('echeancier/process.html.twig', [ 'echeancier' => $echeancier, 'customer' => $echeancier->getCustomer(), ]); } + /** + * Redirige vers DocuSeal pour signer. + */ + #[Route('/echeancier/sign/{id}', name: 'app_echeancier_sign', requirements: ['id' => '\d+'])] + public function sign( + int $id, + DocuSealService $docuSeal, + #[Autowire(env: 'DOCUSEAL_URL')] string $docuSealUrl = '', + ): Response { + $echeancier = $this->em->getRepository(Echeancier::class)->find($id); + if (null === $echeancier) { + throw $this->createNotFoundException('Echeancier introuvable.'); + } + + $submitterId = (int) ($echeancier->getSubmissionId() ?? '0'); + if ($submitterId <= 0) { + throw $this->createNotFoundException('Echeancier non envoye pour signature.'); + } + + $slug = $docuSeal->getSubmitterSlug($submitterId); + if (null === $slug) { + throw $this->createNotFoundException('Lien de signature introuvable.'); + } + + return $this->redirect(rtrim($docuSealUrl, '/').'/s/'.$slug); + } + + /** + * Refuse l'echeancier. + */ + #[Route('/echeancier/refuse/{id}', name: 'app_echeancier_refuse', requirements: ['id' => '\d+'])] + public function refuse(int $id): Response + { + $echeancier = $this->em->getRepository(Echeancier::class)->find($id); + if (null === $echeancier) { + throw $this->createNotFoundException('Echeancier introuvable.'); + } + + $echeancier->setState(Echeancier::STATE_CANCELLED); + $this->em->flush(); + + return $this->render('echeancier/refused.html.twig', [ + 'echeancier' => $echeancier, + 'customer' => $echeancier->getCustomer(), + ]); + } + /** * Callback DocuSeal apres signature du client. */ diff --git a/templates/echeancier/process.html.twig b/templates/echeancier/process.html.twig index d035f29..99838c9 100644 --- a/templates/echeancier/process.html.twig +++ b/templates/echeancier/process.html.twig @@ -83,6 +83,25 @@ Une fois le contrat signe, un email vous sera envoye pour effectuer la configuration des prelevements automatiques.

+

+ Les prelevements seront effectues via Stripe, plateforme de paiement securisee. Vous recevrez un email de confirmation a chaque echeance. +

+ + {# Boutons signer / refuser #} + {% if echeancier.submissionId %} +
+ + Signer l'echeancier + + + Refuser + +
+ {% endif %} +

Pour toute question : contact@e-cosplay.fr

diff --git a/templates/echeancier/refused.html.twig b/templates/echeancier/refused.html.twig new file mode 100644 index 0000000..ecc11d8 --- /dev/null +++ b/templates/echeancier/refused.html.twig @@ -0,0 +1,25 @@ +{% extends 'base.html.twig' %} + +{% block title %}Echeancier refuse - Association E-Cosplay{% endblock %} + +{% block body %} +
+
+
+ + + +

Echeancier refuse

+
+
+

+ L'echeancier de paiement a ete refuse. +

+

+ Si vous souhaitez discuter d'autres modalites de paiement, contactez-nous a + contact@e-cosplay.fr +

+
+
+
+{% endblock %} diff --git a/templates/echeancier/verify.html.twig b/templates/echeancier/verify.html.twig new file mode 100644 index 0000000..fcdbcd6 --- /dev/null +++ b/templates/echeancier/verify.html.twig @@ -0,0 +1,34 @@ +{% extends 'base.html.twig' %} + +{% block title %}Verification - Echeancier - Association E-Cosplay{% endblock %} + +{% block body %} +
+
+
+

Verification

+

Un code a ete envoye a {{ customer.email }}

+
+
+ {% if error %} +
{{ error }}
+ {% endif %} + +

+ Saisissez le code de verification a 6 chiffres recu par email pour acceder a votre echeancier. +

+ +
+
+ + +
+ +
+ +

Le code expire dans 15 minutes.

+
+
+
+{% endblock %}