From 1c5e099598a6e23a544c885b54251f33b6cd9d54 Mon Sep 17 00:00:00 2001 From: Serreau Jovann Date: Thu, 9 Apr 2026 07:54:01 +0200 Subject: [PATCH] feat: E-Flex - sauvegarde PaymentMethod CB + echeances auto (1ere +2j, suivantes tous les 2 mois) - Checkout Session avec setup_future_usage=off_session + customer Stripe pour sauvegarder la carte et permettre les prelevements futurs - Webhook payment_intent.succeeded stocke le PaymentMethod sur EFlex si pas deja configure (permet cron auto ensuite) - 1ere echeance = creation +2 jours (pas de champ startDate) - Echeances suivantes = tous les 2 mois apres la 1ere - Retrait du champ date 1ere echeance du formulaire (automatique) - Info dans le formulaire: "La 1ere echeance sera due 2 jours apres la signature. Les suivantes tous les 2 mois." Co-Authored-By: Claude Opus 4.6 (1M context) --- src/Controller/Admin/EFlexController.php | 10 ++++------ src/Controller/EFlexProcessController.php | 18 +++++++++++++++++- src/Controller/WebhookStripeController.php | 10 ++++++++++ templates/admin/clients/show.html.twig | 5 +---- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/Controller/Admin/EFlexController.php b/src/Controller/Admin/EFlexController.php index a7ad474..8cc8c5d 100644 --- a/src/Controller/Admin/EFlexController.php +++ b/src/Controller/Admin/EFlexController.php @@ -42,10 +42,8 @@ class EFlexController extends AbstractController $description = trim($request->request->getString('description')); $totalAmount = $request->request->getString('totalAmount'); $nbEcheances = $request->request->getInt('nbEcheances'); - $startDate = $request->request->getString('startDate'); - $paymentMethod = $request->request->getString('paymentMethod', EFlex::METHOD_SEPA); - if ('' === $description || $nbEcheances < 2 || $nbEcheances > 36 || '' === $startDate) { + if ('' === $description || $nbEcheances < 2 || $nbEcheances > 36) { $this->addFlash('error', 'Donnees invalides. Minimum 2 echeances, maximum 36.'); return $this->redirectToRoute('app_admin_clients_show', ['id' => $customerId, 'tab' => 'esyflex']); @@ -55,12 +53,12 @@ class EFlexController extends AbstractController $monthlyAmount = round($totalFloat / $nbEcheances, 2); $eflex = new EFlex($customer, $description, number_format($totalFloat, 2, '.', '')); - $eflex->setPaymentMethod($paymentMethod); - $start = new \DateTimeImmutable($startDate); + // 1ere echeance = maintenant +2 jours, les suivantes tous les 2 mois + $firstDate = (new \DateTimeImmutable())->modify('+2 days'); for ($i = 1; $i <= $nbEcheances; ++$i) { - $scheduledAt = $start->modify('+'.($i - 1).' months'); + $scheduledAt = 1 === $i ? $firstDate : $firstDate->modify('+'.($i - 1) * 2 .' months'); $amount = $i === $nbEcheances ? number_format($totalFloat - ($monthlyAmount * ($nbEcheances - 1)), 2, '.', '') : number_format($monthlyAmount, 2, '.', ''); diff --git a/src/Controller/EFlexProcessController.php b/src/Controller/EFlexProcessController.php index 2ed24e4..01d2fec 100644 --- a/src/Controller/EFlexProcessController.php +++ b/src/Controller/EFlexProcessController.php @@ -313,13 +313,28 @@ class EFlexProcessController extends AbstractController // @codeCoverageIgnoreStart \Stripe\Stripe::setApiKey($stripeSk); + $customer = $eflex->getCustomer(); + + // Creer le customer Stripe si besoin + $stripeCustomerId = $eflex->getStripeCustomerId() ?? $customer->getStripeCustomerId(); + if (null === $stripeCustomerId) { + $stripeCustomer = \Stripe\Customer::create([ + 'email' => $customer->getEmail(), + 'name' => $customer->getFullName(), + ]); + $stripeCustomerId = $stripeCustomer->id; + $customer->setStripeCustomerId($stripeCustomerId); + $eflex->setStripeCustomerId($stripeCustomerId); + $this->em->flush(); + } + $successUrl = $this->generateUrl('app_eflex_process', ['id' => $id], UrlGeneratorInterface::ABSOLUTE_URL); $cancelUrl = $successUrl; $checkoutSession = \Stripe\Checkout\Session::create([ 'mode' => 'payment', 'payment_method_types' => ['card'], - 'customer_email' => $eflex->getCustomer()->getEmail(), + 'customer' => $stripeCustomerId, 'line_items' => [[ 'price_data' => [ 'currency' => 'eur', @@ -331,6 +346,7 @@ class EFlexProcessController extends AbstractController 'quantity' => 1, ]], 'payment_intent_data' => [ + 'setup_future_usage' => 'off_session', 'metadata' => [ 'eflex_id' => (string) $eflex->getId(), 'eflex_line_id' => (string) $line->getId(), diff --git a/src/Controller/WebhookStripeController.php b/src/Controller/WebhookStripeController.php index 9f0b1bb..0ddd817 100644 --- a/src/Controller/WebhookStripeController.php +++ b/src/Controller/WebhookStripeController.php @@ -685,6 +685,16 @@ class WebhookStripeController extends AbstractController $line->setPaidAt(new \DateTimeImmutable()); $line->setStripePaymentIntentId($paymentIntent->id); $line->setPaidMethod('stripe'); + + // Sauvegarder le PaymentMethod pour les prelevements futurs (si pas deja fait) + if (null === $eflex->getStripePaymentMethodId()) { + $pmId = $paymentIntent->payment_method ?? null; + if (null !== $pmId) { + $eflex->setStripePaymentMethodId((string) $pmId); + $eflex->setState(\App\Entity\EFlex::STATE_ACTIVE); + } + } + $this->em->flush(); if ($eflex->getNbPaid() >= $eflex->getNbLines()) { diff --git a/templates/admin/clients/show.html.twig b/templates/admin/clients/show.html.twig index 599d144..81a5f88 100644 --- a/templates/admin/clients/show.html.twig +++ b/templates/admin/clients/show.html.twig @@ -1284,11 +1284,8 @@ -
- - -
+

La 1ere echeance sera due 2 jours apres la signature. Les suivantes tous les 2 mois.