src/Controller/MainController.php line 47

  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Order;
  4. use App\Entity\Package;
  5. use App\Entity\UserFeature;
  6. use App\Services\AmeriaPaymentService;
  7. use Doctrine\ORM\EntityManagerInterface;
  8. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpKernel\KernelInterface;
  11. use Symfony\Component\Routing\Annotation\Route;
  12. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  13. use Symfony\Bundle\FrameworkBundle\Console\Application;
  14. use Symfony\Component\Console\Input\ArrayInput;
  15. use Symfony\Component\Console\Output\BufferedOutput;
  16. class MainController extends BaseController
  17. {
  18.     private AmeriaPaymentService $paymentService;
  19.     public function __construct(EntityManagerInterface $entityManagerAmeriaPaymentService $paymentService)
  20.     {
  21.         parent::__construct($entityManager);
  22.         $this->paymentService $paymentService;
  23.     }
  24.     #[Route('api/result/save'name'page_api_save'methods: ['POST'])]
  25.     public function resultSave(Request $request)
  26.     {
  27.         $payloadString $request->request->get('payload');
  28.         // Decode JSON string → array
  29.         $payload json_decode($payloadStringtrue);
  30.         dump($payload);
  31.         die;
  32.     }
  33.     #[Route('/checkout/{id}'name'page_checkout')]
  34.     public function checkout(Package $packageKernelInterface $kernel): \Symfony\Component\HttpFoundation\RedirectResponse
  35.     {
  36. //        $application = new Application($kernel);
  37. //        $application->setAutoExit(false);
  38. //
  39. //        $input = new ArrayInput([
  40. //            'command' => 'doctrine:schema:update',
  41. //            '--force' => true,
  42. //        ]);
  43. //
  44. //        $output = new BufferedOutput();
  45. //
  46. //        $application->run($input, $output);
  47. //
  48. //        dump($output->fetch());
  49. //        die;
  50.         $order = new Order();
  51.         $order->setPackage($package);
  52.         $order->setUser($this->getUser());
  53.         $order->setPrice($package->getPrice());
  54.         $this->entityManager->persist($order);
  55.         $this->entityManager->flush();
  56.         $backUrl $this->generateUrl('payment_callback', [], UrlGeneratorInterface::ABSOLUTE_URL);
  57.         $opaque bin2hex(random_bytes(16));
  58.         $paymentId $this->paymentService->initializePayment([
  59.             'order_id'    => $order->getId(),
  60.             'amount'      => (float)$order->getPrice(),
  61.             'currency'    => 'AMD',
  62.             'back_url'    => $backUrl,
  63.             'opaque'      => $opaque,
  64.             'description' => 'Payment for Order #' $order->getId()
  65.         ]);
  66.         $order->setPaymentId($paymentId);
  67.         $order->setOpaque($opaque);
  68.         $this->entityManager->flush();
  69.         return $this->redirect($this->paymentService->getRedirectUrl($paymentId'am'));
  70.     }
  71.     #[Route('/order/callback'name'payment_callback')]
  72.     public function paymentCallback(Request $request)
  73.     {
  74.         $paymentId   $request->query->get('paymentID');
  75.         $opaqueToken $request->query->get('opaque');
  76.         if (!$paymentId) {
  77.             return $this->redirectToRoute('payment_error_view', ['msg' => 'missing_parameters']);
  78.         }
  79.         // 1. Audit local record state
  80.         $localPayment $this->entityManager->getRepository(Order::class)->findOneBy(['paymentId' => $paymentId]);
  81.         if (!$localPayment) {
  82.             return $this->redirectToRoute('payment_error_view', ['msg' => 'payment_not_found']);
  83.         }
  84.         if ($localPayment->getStatus() === \App\Enum\Order::CALCULATED) {
  85.             return $this->redirectToRoute('page_success', ['orderId' => $localPayment->getPaymentId()]);
  86.         }
  87.         // Verify state security token
  88.         if ($localPayment->getOpaque() !== $opaqueToken) {
  89.             return $this->redirectToRoute('payment_error_view', ['msg' => 'token_mismatch']);
  90.         }
  91.         // 2. Query actual data payload live from server to guarantee status legitimacy
  92.         $details $this->paymentService->getPaymentDetails($paymentId);
  93.         $responseCode $details['ResponseCode'] ?? null;
  94.         /**
  95.          * Simple Buy Logic Processing:
  96.          * Ameria Status Definition rules:
  97.          * Status = 3 means Authorized (Hold applied, configuration might require Confirm call)
  98.          * Status = 10 means Settled / Cleared Successfully
  99.          */
  100.         if ($responseCode == 00) {
  101.             // If setup enforces authorization check, execute final confirm statement
  102. //            if ($status == 3) {
  103. //                $confirmResult = $this->paymentService->confirmPayment($paymentId, (float)$localPayment->getPrice());
  104. //                if (($confirmResult['ResponseCode'] ?? null) !== 00) {
  105. //                    $localPayment->setStatus(\App\Enum\Order::FAILED);
  106. //                    $this->entityManager->flush();
  107. //                    return $this->redirectToRoute('payment_error_view', ['msg' => 'capture_failed']);
  108. //                }
  109. //            }
  110.             $localPayment->setStatus(\App\Enum\Order::SUCCESS);
  111.             $this->entityManager->flush();
  112.             foreach ($localPayment->getPackage()->getPackageFeatures() as $packageFeature) {
  113.                 $userFeature = new UserFeature();
  114.                 $userFeature->setUser($this->getUser());
  115.                 $userFeature->setType($packageFeature->getType());
  116.                 $userFeature->setOrder($localPayment);
  117.                 $userFeature->setPackage($localPayment->getPackage());
  118.                 $userFeature->setAttempt($packageFeature->getAttempt());
  119.                 if ($packageFeature->getDuration() && $packageFeature->getDuration()?->format('%r%y%m%d%h%i%s%f') !== '0000000') {
  120.                     $now = new \DateTime();
  121.                     $expire $now->add($packageFeature->getDuration());
  122.                     $userFeature->setDatetime($expire);
  123.                 }
  124.                 $this->entityManager->persist($userFeature);
  125.             }
  126.             $localPayment->setStatus(\App\Enum\Order::CALCULATED);
  127.             $this->entityManager->flush();
  128.             return $this->redirectToRoute('page_success', ['orderId' => $localPayment->getPaymentId()]);
  129.         }
  130.         return $this->redirectToRoute('payment_error_view', ['msg' => 'bank_declined''code' => $responseCode]);
  131.     }
  132.     #[Route('/order/success'name'page_success')]
  133.     public function success(): \Symfony\Component\HttpFoundation\Response
  134.     {
  135.         return $this->render('@web/page/order/success.html.twig',[]);
  136.     }
  137.     #[Route('/order/error'name'payment_error_view'methods: ['GET'])]
  138.     public function error(Request $request)
  139.     {
  140.         return $this->render('@web/page/order/error.html.twig', [
  141.             'message' => $request->query->get('msg'),
  142.             'code'    => $request->query->get('code')
  143.         ]);
  144.     }
  145. }