diff --git a/migrations/Version20260321250000.php b/migrations/Version20260321250000.php new file mode 100644 index 0000000..aa7dbdd --- /dev/null +++ b/migrations/Version20260321250000.php @@ -0,0 +1,30 @@ +addSql('ALTER TABLE billet_buyer ADD COLUMN IF NOT EXISTS payment_method VARCHAR(50) DEFAULT NULL'); + $this->addSql('ALTER TABLE billet_buyer ADD COLUMN IF NOT EXISTS card_brand VARCHAR(50) DEFAULT NULL'); + $this->addSql('ALTER TABLE billet_buyer ADD COLUMN IF NOT EXISTS card_last4 VARCHAR(4) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE billet_buyer DROP COLUMN IF EXISTS payment_method'); + $this->addSql('ALTER TABLE billet_buyer DROP COLUMN IF EXISTS card_brand'); + $this->addSql('ALTER TABLE billet_buyer DROP COLUMN IF EXISTS card_last4'); + } +} diff --git a/src/Controller/OrderController.php b/src/Controller/OrderController.php index 202236c..0a62e88 100644 --- a/src/Controller/OrderController.php +++ b/src/Controller/OrderController.php @@ -185,7 +185,7 @@ class OrderController extends AbstractController } #[Route('/commande/{id}/confirmation', name: 'app_order_success', requirements: ['id' => '\d+'], methods: ['GET'])] - public function success(int $id, Request $request, EntityManagerInterface $em, BilletOrderService $billetOrderService): Response + public function success(int $id, Request $request, EntityManagerInterface $em, BilletOrderService $billetOrderService, StripeService $stripeService): Response { $order = $em->getRepository(BilletBuyer::class)->find($id); if (!$order) { @@ -193,8 +193,10 @@ class OrderController extends AbstractController } $redirectStatus = $request->query->getString('redirect_status'); + $paymentIntentId = $request->query->getString('payment_intent'); if ('succeeded' === $redirectStatus && BilletBuyer::STATUS_PENDING === $order->getStatus()) { + $this->savePaymentDetails($order, $paymentIntentId, $stripeService, $em); $billetOrderService->generateOrderTickets($order); $billetOrderService->generateAndSendTickets($order); } @@ -294,4 +296,41 @@ class OrderController extends AbstractController return $totalHT; } + + /** + * @codeCoverageIgnore Requires live Stripe API + */ + private function savePaymentDetails(BilletBuyer $order, string $paymentIntentId, StripeService $stripeService, EntityManagerInterface $em): void + { + if (!$paymentIntentId) { + return; + } + + $organizer = $order->getEvent()->getAccount(); + if (!$organizer->getStripeAccountId()) { + return; + } + + try { + $pi = $stripeService->getClient()->paymentIntents->retrieve( + $paymentIntentId, + ['expand' => ['payment_method']], + ['stripe_account' => $organizer->getStripeAccountId()] + ); + + $pm = $pi->payment_method; + if ($pm) { + $order->setPaymentMethod($pm->type ?? null); + if (isset($pm->card)) { + $order->setCardBrand($pm->card->brand ?? null); + $order->setCardLast4($pm->card->last4 ?? null); + } + } + + $order->setStripeSessionId($paymentIntentId); + $em->flush(); + } catch (\Exception) { + // Stripe failure is non-blocking + } + } } diff --git a/src/Entity/BilletBuyer.php b/src/Entity/BilletBuyer.php index ea8c8e6..e670dcc 100644 --- a/src/Entity/BilletBuyer.php +++ b/src/Entity/BilletBuyer.php @@ -54,6 +54,15 @@ class BilletBuyer #[ORM\Column(length: 255, nullable: true)] private ?string $stripeSessionId = null; + #[ORM\Column(length: 50, nullable: true)] + private ?string $paymentMethod = null; + + #[ORM\Column(length: 50, nullable: true)] + private ?string $cardBrand = null; + + #[ORM\Column(length: 4, nullable: true)] + private ?string $cardLast4 = null; + #[ORM\Column] private \DateTimeImmutable $createdAt; @@ -208,6 +217,42 @@ class BilletBuyer return $this; } + public function getPaymentMethod(): ?string + { + return $this->paymentMethod; + } + + public function setPaymentMethod(?string $paymentMethod): static + { + $this->paymentMethod = $paymentMethod; + + return $this; + } + + public function getCardBrand(): ?string + { + return $this->cardBrand; + } + + public function setCardBrand(?string $cardBrand): static + { + $this->cardBrand = $cardBrand; + + return $this; + } + + public function getCardLast4(): ?string + { + return $this->cardLast4; + } + + public function setCardLast4(?string $cardLast4): static + { + $this->cardLast4 = $cardLast4; + + return $this; + } + public function getCreatedAt(): \DateTimeImmutable { return $this->createdAt; diff --git a/templates/order/public.html.twig b/templates/order/public.html.twig index 73c4dc4..2e6ed28 100644 --- a/templates/order/public.html.twig +++ b/templates/order/public.html.twig @@ -39,6 +39,14 @@ Annulee {% endif %}
+ {% if order.paymentMethod %} ++ Paiement : {{ order.paymentMethod }} + {% if order.cardBrand and order.cardLast4 %} + — {{ order.cardBrand|upper }} **** {{ order.cardLast4 }} + {% endif %} +
+ {% endif %} diff --git a/templates/pdf/billet.html.twig b/templates/pdf/billet.html.twig index 4dce1d2..4a97ebe 100644 --- a/templates/pdf/billet.html.twig +++ b/templates/pdf/billet.html.twig @@ -382,6 +382,7 @@