diff --git a/src/Command/StripeSyncCommand.php b/src/Command/StripeSyncCommand.php index 40ca9a9..6a68708 100644 --- a/src/Command/StripeSyncCommand.php +++ b/src/Command/StripeSyncCommand.php @@ -121,13 +121,15 @@ class StripeSyncCommand extends Command foreach ($pendingOrders as $order) { $paymentIntentId = $order->getStripeSessionId(); - if (!$paymentIntentId) { - $io->text(sprintf(' [SKIP] Order #%s — no payment intent ID', $order->getOrderNumber())); + $stripeAccountId = $order->getEvent()?->getAccount()?->getStripeAccountId(); + + if (!$paymentIntentId || !$stripeAccountId) { + $io->text(sprintf(' [SKIP] Order #%s — no payment intent ID or Stripe account', $order->getOrderNumber())); continue; } try { - $paymentIntent = $this->stripeService->retrievePaymentIntent($paymentIntentId); + $paymentIntent = $this->stripeService->retrievePaymentIntent($paymentIntentId, $stripeAccountId); $stripeStatus = $paymentIntent->status; match ($stripeStatus) { diff --git a/src/Controller/AdminController.php b/src/Controller/AdminController.php index 1ea73e9..e075406 100644 --- a/src/Controller/AdminController.php +++ b/src/Controller/AdminController.php @@ -582,6 +582,29 @@ class AdminController extends AbstractController ]); } + #[Route('/commandes/{id}/forcer-validation', name: 'app_admin_order_force_validate', requirements: ['id' => '\d+'], methods: ['POST'])] + public function forceValidateOrder(int $id, EntityManagerInterface $em, BilletOrderService $billetOrderService): Response + { + $order = $em->getRepository(BilletBuyer::class)->find($id); + if (!$order) { + throw $this->createNotFoundException(); + } + + if (BilletBuyer::STATUS_PENDING !== $order->getStatus()) { + $this->addFlash('error', 'Seules les commandes en attente peuvent etre forcees.'); + + return $this->redirectToRoute('app_admin_orders'); + } + + $billetOrderService->generateOrderTickets($order); + $billetOrderService->generateAndSendTickets($order); + $billetOrderService->notifyOrganizer($order); + + $this->addFlash('success', 'Commande '.$order->getOrderNumber().' validee avec succes. Billets generes et envoyes.'); + + return $this->redirectToRoute('app_admin_orders'); + } + #[Route('/commandes/{id}/billets', name: 'app_admin_order_tickets', requirements: ['id' => '\d+'], methods: ['GET'])] public function orderTickets(int $id, EntityManagerInterface $em, BilletOrderService $billetOrderService): Response { diff --git a/src/Service/StripeService.php b/src/Service/StripeService.php index 92995e3..8cfbc64 100644 --- a/src/Service/StripeService.php +++ b/src/Service/StripeService.php @@ -167,9 +167,11 @@ class StripeService /** * @codeCoverageIgnore Requires live Stripe API */ - public function retrievePaymentIntent(string $paymentIntentId): \Stripe\PaymentIntent + public function retrievePaymentIntent(string $paymentIntentId, ?string $stripeAccountId = null): \Stripe\PaymentIntent { - return $this->stripe->paymentIntents->retrieve($paymentIntentId); + $options = $stripeAccountId ? ['stripe_account' => $stripeAccountId] : []; + + return $this->stripe->paymentIntents->retrieve($paymentIntentId, null, $options); } /** diff --git a/templates/admin/orders.html.twig b/templates/admin/orders.html.twig index c9191f4..d938c0a 100644 --- a/templates/admin/orders.html.twig +++ b/templates/admin/orders.html.twig @@ -100,9 +100,13 @@ Invitation {% endif %} - + {% if order.status == 'paid' %} Billets + {% elseif order.status == 'pending' %} +
+ +
{% endif %} diff --git a/tests/Controller/AdminControllerTest.php b/tests/Controller/AdminControllerTest.php index b4e0ff5..1d55847 100644 --- a/tests/Controller/AdminControllerTest.php +++ b/tests/Controller/AdminControllerTest.php @@ -2,8 +2,10 @@ namespace App\Tests\Controller; +use App\Entity\BilletBuyer; use App\Entity\Event; use App\Entity\User; +use App\Service\BilletOrderService; use App\Service\EventIndexService; use App\Service\MailerService; use App\Service\MeilisearchService; @@ -743,6 +745,89 @@ class AdminControllerTest extends WebTestCase self::assertResponseIsSuccessful(); } + public function testForceValidateOrderPending(): void + { + $client = static::createClient(); + $admin = $this->createUser(['ROLE_ROOT']); + $em = static::getContainer()->get(EntityManagerInterface::class); + + $organizer = $this->createUser(['ROLE_ORGANIZER']); + + $event = new Event(); + $event->setTitle('Test Event Force'); + $event->setAccount($organizer); + $event->setStartAt(new \DateTimeImmutable('+1 day')); + $event->setEndAt(new \DateTimeImmutable('+2 days')); + $event->setAddress('1 rue test'); + $event->setZipcode('75001'); + $event->setCity('Paris'); + $em->persist($event); + + $order = new BilletBuyer(); + $order->setEvent($event); + $order->setEmail('buyer@test.fr'); + $order->setFirstName('Jean'); + $order->setLastName('Test'); + $order->setStatus(BilletBuyer::STATUS_PENDING); + $em->persist($order); + $em->flush(); + + $billetOrderService = $this->createMock(BilletOrderService::class); + $billetOrderService->expects(self::once())->method('generateOrderTickets'); + $billetOrderService->expects(self::once())->method('generateAndSendTickets'); + $billetOrderService->expects(self::once())->method('notifyOrganizer'); + static::getContainer()->set(BilletOrderService::class, $billetOrderService); + + $client->loginUser($admin); + $client->request('POST', '/admin/commandes/'.$order->getId().'/forcer-validation'); + + self::assertResponseRedirects('/admin/commandes'); + } + + public function testForceValidateOrderNonPendingFails(): void + { + $client = static::createClient(); + $admin = $this->createUser(['ROLE_ROOT']); + $em = static::getContainer()->get(EntityManagerInterface::class); + + $organizer = $this->createUser(['ROLE_ORGANIZER']); + + $event = new Event(); + $event->setTitle('Test Event Paid'); + $event->setAccount($organizer); + $event->setStartAt(new \DateTimeImmutable('+1 day')); + $event->setEndAt(new \DateTimeImmutable('+2 days')); + $event->setAddress('1 rue test'); + $event->setZipcode('75001'); + $event->setCity('Paris'); + $em->persist($event); + + $order = new BilletBuyer(); + $order->setEvent($event); + $order->setEmail('buyer2@test.fr'); + $order->setFirstName('Pierre'); + $order->setLastName('Test'); + $order->setStatus(BilletBuyer::STATUS_PAID); + $em->persist($order); + $em->flush(); + + $client->loginUser($admin); + $client->request('POST', '/admin/commandes/'.$order->getId().'/forcer-validation'); + + self::assertResponseRedirects('/admin/commandes'); + } + + public function testForceValidateOrderNotFound(): void + { + $client = static::createClient(); + $admin = $this->createUser(['ROLE_ROOT']); + + $client->loginUser($admin); + $client->request('POST', '/admin/commandes/999999/forcer-validation'); + + self::assertResponseStatusCodeSame(404); + } + public function testLogsPage(): void { $client = static::createClient();