src/Controller/V1/OrderPaymentController.php line 236

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controller\V1;
  4. use App\Entity\Local\GiftCard;
  5. use App\Entity\Local\Response\PaymentStartResponse;
  6. use App\Entity\Local\Response\PaymentStatusResponse;
  7. use App\Entity\Local\SessionBase;
  8. use App\Entity\Local\PaymentRedirect;
  9. use App\Entity\Vista\LoyaltyMember;
  10. use App\Entity\Vista\Order;
  11. use App\Entity\Vista\Session;
  12. use App\Exceptions\PaymentException;
  13. use App\Repository\BookingRepository as BookingHelper;
  14. use App\Helper\MPay24Helper;
  15. use App\Helper\PaymentHelper;
  16. use App\Manager\SessionDetailsManager;
  17. use App\Helper\UserHelper;
  18. use App\Repository\MailingRepositoryInterface as MailingRepository;
  19. use App\Repository\MPay24OrderPaymentTransactionRepository;
  20. use App\Repository\OrderRepositoryInterface;
  21. use App\Repository\RestrictionsRepository;
  22. use App\Repository\SessionRepositoryInterface;
  23. use Doctrine\Common\Persistence\ManagerRegistry;
  24. use Doctrine\ORM\EntityManager;
  25. use FOS\RestBundle\Controller\Annotations as Rest;
  26. use FOS\RestBundle\Controller\Annotations\Get;
  27. use FOS\RestBundle\Controller\Annotations\Post;
  28. use FOS\RestBundle\Controller\Annotations\Route;
  29. use FOS\RestBundle\Controller\Annotations\View;
  30. use Nelmio\ApiDocBundle\Annotation\Model;
  31. use Nelmio\ApiDocBundle\Annotation\Security as NelmioSecurity;
  32. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  33. use Swagger\Annotations as SWG;
  34. use Symfony\Component\HttpFoundation\RedirectResponse;
  35. use Symfony\Component\HttpFoundation\Request;
  36. use Symfony\Component\HttpFoundation\Response;
  37. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  38. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  39. use App\Security\Security;
  40. use Psr\Log\LoggerInterface;
  41. use App\Entity\Vista\PayableInterface;
  42. use App\Repository\GiftCardsRepository;
  43. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  44. /**
  45.  * @Route("/orders/{orderId}/payment", requirements={"orderId"=".+"})
  46.  * @SWG\Tag(name="Order_v1")
  47.  */
  48. class OrderPaymentController extends AbstractController
  49. {
  50.     /** @var MPay24Helper */
  51.     protected $mPay24Helper;
  52.     /** @var PaymentHelper */
  53.     protected $paymentHelper;
  54.     /** @var EntityManager */
  55.     protected $em;
  56.     /** @var OrderRepositoryInterface */
  57.     protected $orderRepository;
  58.     /** @var RestrictionsRepository */
  59.     protected $restrictionsRepository;
  60.     /** @var BookingHelper */
  61.     protected $bookingHelper;
  62.     /** @var SessionDetailsManager */
  63.     protected $sessionDetailsHelper;
  64.     /** @var UserHelper */
  65.     protected $userHelper;
  66.     /** @var MPay24OrderPaymentTransactionRepository */
  67.     protected $mPay24OrderPaymentTransactionRepository;
  68.     /** @var SessionRepositoryInterface */
  69.     private $sessionRepository;
  70.     /** @var GiftCardsRepository */
  71.     private $giftCardsRepository;
  72.     /** @var MailingRepository */
  73.     private $mailer;
  74.     /** @var LoggerInterface */
  75.     protected $logger;
  76.     public function __construct(
  77.         MPay24Helper $mPay24Helper,
  78.         PaymentHelper $paymentHelper,
  79.         OrderRepositoryInterface $orderRepository,
  80.         RestrictionsRepository $restrictionsRepository,
  81.         ManagerRegistry $managerRegistry,
  82.         BookingHelper $bookingHelper,
  83.         SessionDetailsManager $sessionDetailsHelper,
  84.         UserHelper $userHelper,
  85.         MPay24OrderPaymentTransactionRepository $mPay24OrderPaymentTransactionRepository,
  86.         SessionRepositoryInterface $sessionRepository,
  87.         MailingRepository $mailer,
  88.         GiftCardsRepository $giftCardsRepository,
  89.         LoggerInterface $logger
  90.     ) {
  91.         $this->mPay24Helper $mPay24Helper;
  92.         $this->paymentHelper $paymentHelper;
  93.         $this->orderRepository $orderRepository;
  94.         $this->restrictionsRepository $restrictionsRepository;
  95.         $this->em $managerRegistry->getManager();
  96.         $this->bookingHelper $bookingHelper;
  97.         $this->sessionDetailsHelper $sessionDetailsHelper;
  98.         $this->userHelper $userHelper;
  99.         $this->mPay24OrderPaymentTransactionRepository $mPay24OrderPaymentTransactionRepository;
  100.         $this->sessionRepository $sessionRepository;
  101.         $this->mailer $mailer;
  102.         $this->giftCardsRepository=$giftCardsRepository;
  103.         $this->logger $logger;
  104.     }
  105.     /**
  106.      * @param string $orderId
  107.      * @return Order
  108.      * @throws \Doctrine\ORM\ORMException
  109.      * @throws \Doctrine\ORM\OptimisticLockException
  110.      */
  111.     protected function renewOrder(string $orderId): Order
  112.     {
  113.         $order $this->orderRepository->findOneBy([
  114.             'userSessionId' => $orderId,
  115.             'state' => Order::STATE_PAYMENT_STARTED,
  116.         ]);
  117.         if (null === $order) {
  118.             return $this->orderRepository->findBySessionId($orderIdOrder::STATE_NEW);
  119.         }
  120.         $order->setState(Order::STATE_NEW);
  121.         $this->orderRepository->save($order);
  122.         if ($transaction $this->mPay24OrderPaymentTransactionRepository->find($order->getUserSessionId())) {
  123.             $transaction->setPaymentHasBeenStarted(false);
  124.             $this->mPay24OrderPaymentTransactionRepository->saveTransaction($transaction);
  125.         }
  126.         return $order;
  127.     }
  128.     /**
  129.      * @Post("/start")
  130.      * @Rest\QueryParam(name="email", allowBlank=true)
  131.      * @View()
  132.      *
  133.      * @SWG\Response(
  134.      *     response=200,
  135.      *     description="The payment has started",
  136.      *     @Model(type=\App\Entity\Local\Response\PaymentStartResponse::class))
  137.      *
  138.      * @param             $orderId
  139.      * @param Security    $security
  140.      * @param string|null $email
  141.      *
  142.      * @return PaymentStartResponse
  143.      * @throws \Doctrine\ORM\ORMException
  144.      * @throws \Doctrine\ORM\OptimisticLockException
  145.      * @throws \Throwable
  146.      */
  147.     public function startPaymentAction($orderIdSecurity $securitystring $email null)
  148.     {
  149.         $time_start microtime(true);
  150.         /** @var Order $order */
  151.         $order $this->renewOrder($orderId);        
  152.         $user $security->getUser();
  153.         if( $order->getSession()){
  154.             $session $this->sessionDetailsHelper->loadSession($order->getCinemaId(), $order->getSession()->getId());
  155.             if ($user) {
  156.                 $this->checkTransactionHistory($order$session$user);
  157.             }
  158.         } else {
  159.             // concessions direct purchase
  160.         }
  161.         $restrictions $this->restrictionsRepository->findOrCreate();
  162.         if( $order->getPriceInCents() < ) {
  163.             $this->logger->info('Order value is zero, omitting payment');
  164.             $hash $this->paymentHelper->startOrderPayment($order$user ?? (string) $email);
  165.             $order->setState(Order::STATE_PAYMENT_FINISHED);
  166.             $succ=$this->paymentFinishZeroValue($order);
  167.             $return = (new PaymentStartResponse())
  168.             ->setPaymentPageUrl($succ)
  169.             ->setOrderId(null)
  170.             ->setRestrictions($restrictions);        
  171.             $execution_time microtime(true) - $time_starterror_log(sprintf("%s %s(%s) orderId $orderId execution_time $execution_time "date('Y-m-d H:i:s'),  __METHOD____LINE__));
  172.             return $return;
  173.         } else {
  174.             if(getenv('RAIFFEISEN_ADDRESS')) { // Raiffeisen
  175.                 $paymentPageUrl = (getenv('DEV_SIRMA') ? 'http://' getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) .
  176.                     sprintf("/api/v1/orders/ord-%s/payment/raiffeisen-redirect/%s/%s/%s"$orderId$this->paymentHelper->startOrderPayment($order$user ?? (string) $email), $order->getOrderTotalValueInCents(), $order->getCinemaId());
  177.             } else if(getenv('CPAY_ADDRESS')) { // cPay
  178.                 $paymentPageUrl = (getenv('DEV_SIRMA') ? 'http://' getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) .
  179.                     sprintf("/api/v1/orders/%s/payment/cpay-redirect/%s/%s/%s"$orderId$this->paymentHelper->startOrderPayment($order$user ?? (string) $email), intval($order->getOrderTotalValueInCents()), $order->getCinemaId());
  180.             } else if(getenv('KOM_BANK_ADDRESS')) {
  181.                 $paymentPageUrl = (getenv('DEV_SIRMA') ? 'http://' getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) .
  182.                 sprintf("/api/v1/orders/%s/payment/kom-bank-redirect/%s/%s/%s"$orderId$this->paymentHelper->startOrderPayment($order$user ?? (string) $email), $order->getOrderTotalValueInCents(), $order->getCinemaId());
  183.             } else { // mpay24
  184.                 $paymentPageUrl $this->mPay24Helper->startOrderPayment($order$user ?? (string) $email);
  185.             }
  186.             $response = (new PaymentStartResponse())
  187.                 ->setPaymentPageUrl($paymentPageUrl)
  188.                 ->setOrderId(null)
  189.                 ->setRestrictions($restrictions);
  190.             $order->setState(Order::STATE_PAYMENT_STARTED);
  191.             $this->em->flush();
  192.             $execution_time microtime(true) - $time_starterror_log(sprintf("%s %s(%s) orderId $orderId execution_time $execution_time "date('Y-m-d H:i:s'),  __METHOD____LINE__));
  193.             return $response;
  194.         }
  195.     }
  196.     /**
  197.      * @Get("/finish/{hash}", name="payment_finish")
  198.      *
  199.      * @SWG\Response(
  200.      *     response=200,
  201.      *     description="The payment is finished",
  202.      *     @Model(type=\App\Entity\Local\MPay24OrderPaymentTransaction::class))
  203.      *
  204.      * @param $orderId
  205.      * @param $hash
  206.      * @param Request $request
  207.      * @return Response
  208.      * @throws \Doctrine\ORM\ORMException
  209.      * @throws \Doctrine\ORM\OptimisticLockException
  210.      * @throws \GuzzleHttp\Exception\GuzzleException
  211.      */
  212.     public function finishPaymentAction($orderId$hashRequest $request)
  213.     {
  214.         try {
  215.             $order $this->orderRepository->findBySessionId($orderIdOrder::STATE_PAYMENT_STARTED);
  216.         } catch (\Exception $ex) {
  217.             $this->orderRepository->findBySessionId($orderIdOrder::STATE_PAYMENT_FINISHED);
  218.             $response = new Response(PaymentHelper::PAYMENT_RESPONSE_OK);
  219.         return $response;
  220.         }
  221.         $result $this->mPay24Helper->finishPayment($order$hash$request->query->all());
  222.         if ($result->getOrderToBeUpdated()) {
  223.             $order->setState(Order::STATE_PAYMENT_FINISHED);
  224.             $this->em->flush();
  225.         }
  226.         return new Response($result->getResponse());
  227.     }
  228.     /**
  229.      * @Get("/status")
  230.      * @View()
  231.      *
  232.      * @SWG\Response(
  233.      *     response=200,
  234.      *     description="Status of the payment",
  235.      *     @Model(type=\App\Entity\Local\Response\PaymentStatusResponse::class))
  236.      *
  237.      * @param $orderId
  238.      * @return PaymentStatusResponse
  239.      * @throws \ReflectionException
  240.      * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface
  241.      */
  242.     public function getPaymentStatusAction($orderId)
  243.     {
  244.         [$status] = $this->mPay24Helper->requestStatus($orderId);
  245.         return (new PaymentStatusResponse())->setState($status);
  246.     }
  247.     /**
  248.      * @Get("/status-final")
  249.      * @View()
  250.      *
  251.      * @SWG\Response(
  252.      *     response=200,
  253.      *     description="Final status of the payment",
  254.      *     @Model(type=\App\Entity\Local\Response\PaymentStatusResponse::class))
  255.      *
  256.      * @param $orderId
  257.      * @return PaymentStatusResponse
  258.      */
  259.     public function getPaymentStatusFinalAction($orderId) {
  260.         $time_start microtime(true);
  261.         if(getenv('KOM_BANK_ADDRESS') || getenv('RAIFFEISEN_ADDRESS') || getenv('CPAY_ADDRESS')) {
  262.             [$status$mPay24State$statusExtended] = $this->paymentHelper->getStatus($orderId);
  263.         } else {
  264.             [$status$mPay24State$statusExtended] = $this->mPay24Helper->getStatus($orderId);
  265.         }
  266.         $return = (new PaymentStatusResponse())
  267.             ->setStatus($status)
  268.             ->setMPay24State($mPay24State)
  269.             ->setStatusExtended($statusExtended);
  270.         $execution_time microtime(true) - $time_starterror_log(sprintf("%s %s(%s) orderId $orderId execution_time $execution_time "date('Y-m-d H:i:s'),  __METHOD____LINE__));
  271.         return $return;
  272.     }
  273.     /**
  274.      * Redirect endpoint for Raiffeisen
  275.      *
  276.      * @Get("/raiffeisen-redirect/{hash}/{amountCents}/{cinemaId}", name="raiffeisen_redirect")
  277.      *
  278.      * @SWG\Response(
  279.      *     response=200,
  280.      *     description="Stub empty result",
  281.      *     @SWG\Schema(type="string"))
  282.      *
  283.      * @param $orderId
  284.      * @param $hash
  285.      * @param $amountCents
  286.      * @param $cinemaId
  287.      * @return Response
  288.      */
  289.     public function handleRaiffeisenRedirect($orderId$hash$amountCents$cinemaId) {
  290.         $paymentPageUrl getenv('RAIFFEISEN_ADDRESS') ? getenv('RAIFFEISEN_ADDRESS') : 'https://ecg.test.upc.ua/rbko/enter'// 'https://ecg.test.upc.ua/go/enter' https://ecg.test.upc.ua/rbko/enter
  291.         $certPath   getenv('RAIFFEISEN_CERT_PATH')   ? getenv('RAIFFEISEN_CERT_PATH') : 'config/certificates/';
  292.         $certPass   getenv('RAIFFEISEN_CERT_PASS')   ? getenv('RAIFFEISEN_CERT_PASS') : 'cineplexx';
  293.         $OrderID rand();
  294.         $SD $orderId;
  295.         $ids $this->paymentHelper->getMerchant($cinemaId);
  296.         //error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'),  __METHOD__, __LINE__) . " SD $SD cinemaId $cinemaId " . var_export($ids, true));
  297.         $merchantId $ids && array_key_exists('id'$ids) ? $ids['id'] : '1755375';            //Merchant Id defined by bank to user
  298.         $terminalId $ids && array_key_exists('pass'$ids)  ? $ids['pass'] : 'E7883395'//Store key value, defined by bank.
  299.         $env getenv('APP_ENV');
  300.         if ($env == 'dev') {
  301.             $env 'stage';
  302.         }
  303.         $country getenv('APP_COUNTRY');;
  304.         if (!$cert_store file_get_contents(__DIR__ "/../../../{$certPath}Raiffeisen_{$country}_$env.p12")) {
  305.             echo "Error: Unable to read the cert file\n";
  306.             exit;
  307.         }
  308.         $cert_info = [];
  309.         if (openssl_pkcs12_read($cert_store$cert_info$certPass)) {
  310.             //error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'),  __METHOD__, __LINE__) . $cert_info['pkey']);
  311.         } else {
  312.             error_log(sprintf("%s %s(%s) "date('Y-m-d H:i:s'),  __METHOD____LINE__) . "Error: Unable to read the cert store.\n");
  313.         }
  314.         $response null;
  315.         if($cert_info && array_key_exists('pkey'$cert_info)) {
  316.             $privKey $cert_info['pkey'];
  317.             //error_log("privKey $privKey");
  318.             $pkeyId openssl_get_privatekey($privKey);
  319.             $purchaseTime date("ymdHis") ;
  320.             $currencyId $this->getRaiffeisenCurrency();
  321.             $data "$merchantId;$terminalId;$purchaseTime;$OrderID;$currencyId;$amountCents;$SD;";
  322.             $signature null;
  323.             openssl_sign($data $signature$pkeyId);
  324.             openssl_free_key($pkeyId);
  325.             $b64sign base64_encode($signature);
  326.             //error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'),  __METHOD__, __LINE__) . "data $data b64sign $b64sign");
  327.             $version 1;
  328.             $locale = ($country == 'bih' || $country == 'bil') ? 'rs' 'sq';
  329.             $paymentRedirect = (new PaymentRedirect())
  330.                 ->setRedirectUrl($paymentPageUrl)
  331.                 ->setFormTitle('Raiffeisen Bank')
  332.                 ->setPaymentData([
  333.                     'Version'      => $version,
  334.                     'MerchantID'   => $merchantId,
  335.                     'TerminalID'   => $terminalId,
  336.                     'TotalAmount'  => $amountCents,
  337.                     'Currency'     => $currencyId,
  338.                     'locale'       => $locale,
  339.                     'PurchaseTime' => $purchaseTime,
  340.                     'OrderID'      => $OrderID,
  341.                     'SD'           => $SD,
  342.                     'Signature'    => $b64sign
  343.                 ]);
  344.             
  345.             $response $this->render('web/redirect.html.twig', ['paymentRedirect' => $paymentRedirect] );
  346.             //error_log(sprintf("%s %s(%s) payment_finish orderId $orderId", date('Y-m-d H:i:s'), __METHOD__, __LINE__));
  347.         } else {
  348.             $response = new Response();
  349.         }
  350.         $response->headers->set('Content-Type''text/html; charset=UTF-8'); // Content-Type: text/html; charset=UTF-8
  351.         return $response;
  352.     }
  353.     
  354.     /**
  355.      * Redirect endpoint for KomBank
  356.      *
  357.      * @Get("/kom-bank-redirect/{hash}/{amount}/{cinemId}", name="kom_bank_redirect", defaults={"email"=""})
  358.      *
  359.      * @SWG\Response(
  360.      *     response=200,
  361.      *     description="Stub empty result",
  362.      *     @SWG\Schema(type="string"))
  363.      *
  364.      * @param $orderId
  365.      * @param $hash
  366.      * @param $amount
  367.      * @param $cinemId
  368.      * @return Response
  369.      */
  370.     public function handleKomBankRedirect(string $orderId$hash$amount$cinemId) {
  371.         $response $this->getKombankRedirectForm($orderId,  sprintf('/api/v1/orders/%s/payment/handle-redirect-post/%s'$orderId$hash), sprintf('%.2f'$amount 100), $cinemId);
  372.         // $response = $this->getKombankRedirectForm($orderId,  sprintf('%s/payment-return/%s/handle-redirect-post/%s', getenv('WEBSITE_SCHEME_AND_HTTP_HOST'), $orderId, $hash), sprintf('%.2f', $amount / 100), $cinemId);
  373.         //error_log(sprintf("%s %s(%s) payment_finish orderId $orderId", date('Y-m-d H:i:s'), __METHOD__, __LINE__));
  374.         return $response;
  375.     }
  376.     
  377.     /**
  378.      * Redirect endpoint for Cpay
  379.      *
  380.      * @Get("/cpay-redirect/{hash}/{amount}/{cinemId}", name="cpay_redirect")
  381.      *
  382.      * @SWG\Response(
  383.      *     response=200,
  384.      *     description="Stub empty result",
  385.      *     @SWG\Schema(type="string"))
  386.      *
  387.      * @param $orderId
  388.      * @param $hash
  389.      * @param $amount
  390.      * @param $cinemId
  391.      * @return Response
  392.      */
  393.     public function handleCpayRedirectAction(string $orderId$hash$amount$cinemId) {
  394.         $time_start microtime(true);
  395.         $response $this->getCpayRedirectForm($orderId,  sprintf('/api/v1/orders/%s/payment/handle-redirect-post/%s'$orderId$hash), $amount$cinemId);
  396.         //error_log(sprintf("%s %s(%s) payment_finish orderId $orderId", date('Y-m-d H:i:s'), __METHOD__, __LINE__));
  397.         $execution_time microtime(true) - $time_starterror_log(sprintf("%s %s(%s) orderId $orderId execution_time $execution_time "date('Y-m-d H:i:s'),  __METHOD____LINE__));
  398.         return $response;
  399.     }
  400.     
  401.     /**
  402.      * Redirect endpoint for KomBank
  403.      *
  404.      * @Route("/kom-bank-booking/{hash}/{amount}/{cinemId}", methods={"GET"}, name="kom_bank_booking")
  405.      *
  406.      * @SWG\Response(
  407.      *     response=200,
  408.      *     description="Stub empty result",
  409.      *     @SWG\Schema(type="string"))
  410.      *
  411.      * @param $orderId
  412.      * @param $hash
  413.      * @param $amount
  414.      * @param $cinemId
  415.      * @return Response
  416.      */
  417.     public function getKombankBookingRedirect(string $orderId$hash$amount$cinemId) {
  418.         $response $this->getKombankRedirectForm($orderId,  sprintf('/api/v1/users/bookings/%s/payment-finish-kombank/%s'$orderId$hash), sprintf('%.2f'$amount 100), $cinemId);
  419.         //error_log(sprintf("%s %s(%s) payment_finish orderId $orderId", date('Y-m-d H:i:s'), __METHOD__, __LINE__));
  420.         return $response;
  421.     }
  422.     /**
  423.      * Redirect endpoint for Cpay
  424.      *
  425.      * @Route("/cpay-booking/{hash}/{amount}/{cinemId}", methods={"GET"}, name="cpay_bank_booking")
  426.      *
  427.      * @SWG\Response(
  428.      *     response=200,
  429.      *     description="Stub empty result",
  430.      *     @SWG\Schema(type="string"))
  431.      *
  432.      * @param $orderId
  433.      * @param $hash
  434.      * @param $amount
  435.      * @param $cinemId
  436.      * @return Response
  437.      */
  438.     public function getCpayBookingRedirect(string $orderId$hash$amount$cinemId) {
  439.         $time_start microtime(true);
  440.         $response $this->getCpayRedirectForm($orderId,  sprintf('/api/v1/users/bookings/%s/payment-finish-cpay/%s'$orderId$hash), $amount$cinemId);
  441.         //error_log(sprintf("%s %s(%s) payment_finish orderId $orderId", date('Y-m-d H:i:s'), __METHOD__, __LINE__));
  442.         $execution_time microtime(true) - $time_starterror_log(sprintf("%s %s(%s) orderId $orderId execution_time $execution_time "date('Y-m-d H:i:s'),  __METHOD____LINE__));
  443.         return $response;
  444.     }
  445.     public function getRaiffeisenCurrency() {
  446.         switch(getenv('APP_COUNTRY')){
  447.             case 'alb': return '008';
  448.             case 'bih': return '977';
  449.             case 'bil': return '977';
  450.             default: return '978';
  451.         }        
  452.     }
  453.     /**
  454.      * Redirect endpoint for Raiffeisen
  455.      *
  456.      * @Post("/raiffeisen-response", name="raiffeisen_response")
  457.      *
  458.      * @SWG\Response(
  459.      *     response=200,
  460.      *     description="Stub empty result",
  461.      *     @SWG\Schema(type="string"))
  462.      *
  463.      * @param $orderId
  464.      * @param Request $request
  465.      * @return Response
  466.      */
  467.     public function handleRaiffeisenResponse($orderIdRequest $request) { // bkn- ord- TranCode
  468.         $time_start microtime(true);
  469.         //$queryParams = json_decode($request->getContent(), true);; // json_decode($request->getContent(), true);
  470.         $queryParams $_POST;
  471.         //$request->request->all();
  472.         $result $orderId;
  473.         if ($result == 'notify') {
  474.             $merchantId $queryParams['MerchantID'];
  475.             $terminalId $queryParams['TerminalID'];
  476.             $orderIdFake $queryParams['OrderID'];
  477.             $currencyId $this->getRaiffeisenCurrency();
  478.             $totalAmount $queryParams['TotalAmount'];
  479.             $xid $queryParams['XID'];
  480.             $purchaseTime $queryParams['PurchaseTime'];
  481.             $responsetext = <<<TEXT
  482. MerchantID="$merchantId"
  483. TerminalID="$terminalId"
  484. OrderID="$orderIdFake"
  485. Currency="$currencyId"
  486. TotalAmount="$totalAmount"
  487. XID="$xid"
  488. PurchaseTime="$purchaseTime"
  489. Response.action=approve
  490. TEXT;
  491.             $response = new Response($responsetext);
  492.             $response->headers->set('Content-Type''text/plain; charset=UTF-8');
  493.             return $response;
  494.         }
  495.         $orderIdComposed $request->get('SD');
  496.         //error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'),  __METHOD__, __LINE__) . " $orderIdComposed queryParams " . var_export($queryParams, true));
  497.         // http://93.123.103.157:8124/api/v1/orders/success/payment/raiffeisen-response success  https://app.cineplexx-ks.eu http://93.123.103.157:8124 https://ial-stage.cineplexx-ks.eu
  498.         // http://93.123.103.157:8124/api/v1/orders/error/payment/raiffeisen-response error
  499.         // http://93.123.103.157:8124/api/v1/orders/notify/payment/raiffeisen-response notify
  500.         if (!preg_match('/^(ord-|bkn-)(.+$)/'$orderIdComposed$matches) || count($matches) < 3) {
  501.             $return = new RedirectResponse(sprintf(
  502.                 '%s/purchase/payment/%s',
  503.                 getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
  504.                 $orderIdComposed
  505.             ));
  506.             return $return;
  507.         }
  508.         $paymentType $matches[1];
  509.         $orderId $matches[2];
  510.         
  511.         if ($paymentType == 'bkn-') {
  512.             $this->logger->info('handleRaiffeisenResponse: paymentType = bkn');
  513.             $return $this->paymentFinishRaiffeisen($orderId$queryParams$result);
  514.             return $return;
  515.         }
  516.         try {
  517.             $order $this->orderRepository->findBySessionId($orderIdOrder::STATE_PAYMENT_STARTED);
  518.         } catch (\Exception $ex) {
  519.             $this->orderRepository->findBySessionId($orderIdOrder::STATE_PAYMENT_FINISHED);
  520.             //error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'),  __METHOD__, __LINE__) . ' ex ' . var_export($ex, true));
  521.             $return = new RedirectResponse(sprintf(
  522.                 '%s/purchase/payment/%s/%s',
  523.                 getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
  524.                 $result,
  525.                 $orderId
  526.             ));
  527.             return $return;
  528.         }
  529.         
  530.         $this->logger->info('handleRaiffeisenResponse: result = ['.$result.']');
  531.         if ('success' === $result) {
  532.             $queryParams['STATUS'] = 'BILLED';
  533.         } else {
  534.             $queryParams['STATUS'] = 'FAILED';
  535.         }
  536.         
  537.         $transaction $this->mPay24OrderPaymentTransactionRepository->find($order->getPaymentId());
  538.         
  539.         $payment $this->paymentHelper->finishPayment($order$transaction->getHash(), $queryParams);
  540.         if ($payment->getOrderToBeUpdated()) {
  541.             $order->setState(Order::STATE_PAYMENT_FINISHED);
  542.             $this->em->flush();
  543.         }
  544.         $return = new RedirectResponse(sprintf(
  545.             '%s/purchase/payment/%s/%s',
  546.             getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
  547.             $result,
  548.             $orderId
  549.         ));
  550.         return $return;
  551.     }
  552.     // CIN311
  553.     /*
  554.     * @param Order $order
  555.     * @param Request $request
  556.     * @return string
  557.     */
  558.     private function paymentFinishZeroValue($order
  559.     {
  560.         /** @var Order $order */
  561.         $transaction $this->paymentHelper->getTransaction($order->getPaymentId());
  562.         $queryParams=[];
  563.         $queryParams['STATUS'] = 'BILLED';
  564.         if ($transaction) {
  565.             $hash $transaction->getHash();
  566.             $this->logger->info("finishing zero value payment");
  567.             $response $this->paymentHelper->finishPayment($order$hash$queryParams);
  568.             
  569.             return $response->getResponse()==PaymentHelper::PAYMENT_RESPONSE_OK 'success':'error';
  570.         }
  571.         return 'error';
  572. }
  573.     //////
  574.     private function paymentFinishRaiffeisen($orderId$queryParams$result) {
  575.         $time_start microtime(true);
  576.         $transaction $this->paymentHelper->getTransaction($orderId);
  577.         $memberId $transaction->getMemberId();
  578.         $member = (new LoyaltyMember())->setMemberId($memberId);
  579.         $user $this->userHelper->validate($member);
  580.         $booking $this->bookingHelper->findBooking((int) $transaction->getVistaBookingNumber(), $user);
  581.         if (null === $booking) {
  582.             throw new \InvalidArgumentException(sprintf(
  583.                 'Invalid transaction, booking with number %s doesn\'t exist',
  584.                 $transaction->getVistaBookingNumber()
  585.             ));
  586.         }
  587.         if ($booking->isPaid() && 'success' === $result) {
  588.             $return = new RedirectResponse(sprintf(
  589.                 '%s/purchase/payment/%s/%s',
  590.                 getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
  591.                 $result,
  592.                 $orderId
  593.             ));
  594.             return $return;
  595.         }
  596.         if ('success' === $result) {
  597.             $queryParams['STATUS'] = 'BILLED';
  598.         } else {
  599.             $queryParams['STATUS'] = 'FAILED';
  600.         }
  601.         if (!$booking->isPaid() && 'success' === $result) {
  602.             $hash $transaction->getHash();
  603.             $this->paymentHelper->finishPayment($booking$hash$queryParams);
  604.             $return = new RedirectResponse(sprintf(
  605.                 '%s/purchase/payment/%s/%s',
  606.                 getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
  607.                 $result,
  608.                 $orderId
  609.             ));
  610.             return $return;
  611.         }
  612.         $return = new RedirectResponse(sprintf(
  613.             '%s/purchase/payment/%s/%s',
  614.             getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
  615.             $result,
  616.             $orderId
  617.         ));
  618.         return $return;
  619.     }
  620.     /**
  621.      * Redirect endpoint for KomBank
  622.      *
  623.      * @Post("/handle-redirect-post/{hash}/{result}", name="payment_handle_post_redirect")
  624.      *
  625.      * @SWG\Response(
  626.      *     response=200,
  627.      *     description="Stub empty result",
  628.      *     @SWG\Schema(type="string"))
  629.      *
  630.      * @param $orderId
  631.      * @param $result
  632.      * @return Response
  633.      */
  634.     public function handlePaymentPostRedirectAction($orderId$hash$result) {
  635.         $time_start microtime(true);
  636.         $queryParams $_POST;
  637.         //error_log(sprintf("%s %s(%s) orderId $orderId result $result hash $hash ", date('Y-m-d H:i:s'),  __METHOD__, __LINE__));
  638.         $state Order::STATE_PAYMENT_STARTED;
  639.         $order null;
  640.         try {
  641.             $order $this->orderRepository->findBySessionId($orderId$state);
  642.         } catch (\Exception $ex) {
  643.             if (!getenv('CPAY_ADDRESS')) {
  644.                 $this->orderRepository->findBySessionId($orderId$state);
  645.                 $return = new Response(PaymentHelper::PAYMENT_RESPONSE_OK);
  646.                 $execution_time microtime(true) - $time_starterror_log(sprintf("%s %s(%s) orderId $orderId execution_time $execution_time "date('Y-m-d H:i:s'),  __METHOD____LINE__));
  647.                 return $return;
  648.             }
  649.         }
  650.         
  651.         $redirectUrl '%s/purchase/payment/success/%s';
  652.         if ('success' === $result) {
  653.             $queryParams['STATUS'] = 'BILLED';
  654.         } else {
  655.             $redirectUrl '%s/purchase/payment/error/%s';
  656.             $queryParams['STATUS'] = 'FAILED';
  657.         }
  658.         if ($order) {
  659.             $payment $this->paymentHelper->finishPayment($order$hash$queryParams);
  660.             if ($payment->getOrderToBeUpdated()) {
  661.                 $order->setState(Order::STATE_PAYMENT_FINISHED);
  662.                 $this->em->flush();
  663.             }
  664.         }
  665.         
  666.         $redirectURL sprintf(
  667.             $redirectUrl,
  668.             getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
  669.             $orderId
  670.         );
  671.         $response $this->render('web/payment-redirect.html.twig', ['redirectUrl' => $redirectURL] );
  672.         $response->headers->set('Content-Type''text/html; charset=UTF-8');
  673.         return $response;
  674.     }
  675.     /**
  676.      * Redirect endpoint for MPay24
  677.      *
  678.      * @Get("/handle-redirect/{result}", name="payment_handle_redirect")
  679.      *
  680.      * @SWG\Response(
  681.      *     response=200,
  682.      *     description="Stub empty result",
  683.      *     @SWG\Schema(type="string"))
  684.      *
  685.      * @param $orderId
  686.      * @param $result
  687.      * @return Response
  688.      */
  689.     public function handlePaymentRedirectAction($orderId$result) {
  690.         if ('success' === $result) {
  691.             return new RedirectResponse(sprintf// missing /api/v1/orders/$orderId
  692.                 '%s/purchase/payment-success/%s',
  693.                 getenv('DEV_SIRMA') ? 'http://' getenv('DEV_SIRMA') : getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
  694.                 $orderId
  695.             ));
  696.         } else {
  697.             return new RedirectResponse(sprintf(
  698.                 '%s/purchase/payment-failure/%s',
  699.                 getenv('DEV_SIRMA') ? 'http://' getenv('DEV_SIRMA') : getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
  700.                 $orderId
  701.             ));
  702.         }
  703.     }
  704.     /**
  705.      * @Post("/reserveTickets")
  706.      * @NelmioSecurity(name="Bearer")
  707.      * @ParamConverter("order", options={"mapping": {"orderId": "userSessionId"}})
  708.      * @View()
  709.      *
  710.      * @SWG\Response(
  711.      *     response=200,
  712.      *     description="The payment has started",
  713.      *     @Model(type=\App\Entity\Vista\Booking::class))
  714.      *
  715.      * @param $orderId
  716.      * @param Security $security
  717.      * @return mixed
  718.      * @throws \Doctrine\ORM\ORMException
  719.      * @throws \Doctrine\ORM\OptimisticLockException
  720.      * @throws \GuzzleHttp\Exception\GuzzleException
  721.      * @throws \Throwable
  722.      */
  723.     public function reserveTicketsAction($orderIdSecurity $security) {
  724.         $user $security->getUser();
  725.         $order $this->renewOrder($orderId);
  726.         $session $this->sessionDetailsHelper->loadSession($order->getCinemaId(), $order->getSession()->getId());
  727.         $this->checkBookingHistory($order$session$user);
  728.         $user $this->userHelper->validate($user);
  729.         
  730.         $result $this->paymentHelper->reserveTickets($user$order);
  731.         
  732.         if ($result) {
  733.             $order->setState(Order::STATE_RESERVED);
  734.         }
  735.         $this->em->flush();
  736.         return $result;
  737.     }
  738.     /**
  739.      * @Post("/with-bonus-card")
  740.      * @NelmioSecurity(name="Bearer")
  741.      * @View()
  742.      *
  743.      * @SWG\Response(
  744.      *     response=200,
  745.      *     description="The payment is finished",
  746.      *     @Model(type=\App\Entity\Local\MPay24OrderPaymentTransaction::class))
  747.      *
  748.      * @param $orderId
  749.      * @param Security $security
  750.      * @return mixed
  751.      * @throws \Doctrine\ORM\ORMException
  752.      * @throws \Doctrine\ORM\OptimisticLockException
  753.      * @throws \GuzzleHttp\Exception\GuzzleException
  754.      * @throws \Throwable
  755.      */
  756.     public function vistaPaymentAction($orderIdSecurity $security) {
  757.         $order $this->orderRepository->findBySessionId($orderId);
  758.         /** @var LoyaltyMember $loyaltyMember */
  759.         if (!($loyaltyMember $security->getUser())) {
  760.             throw new AccessDeniedException('Only authorized users can make payments with bonus card');
  761.         }
  762.         if( $order->getSession()){
  763.             $session $this->sessionDetailsHelper->loadSession($order->getCinemaId(), $order->getSession()->getId());
  764.             $this->checkTransactionHistory($order$session$loyaltyMember);
  765.         } else {
  766.             $this->logger->info("processing payment for concessions direct purchase");
  767.         }
  768.         $booking $this->paymentHelper->makeVistaPayment($loyaltyMember""$order, []);
  769.         $order->setState(Order::STATE_PAYMENT_FINISHED);
  770.         $this->em->flush();
  771.         return $booking;
  772.     }
  773.     /**
  774.      * @Post("/with-gift-card")
  775.      * @NelmioSecurity(name="Bearer")
  776.      * @ParamConverter("giftcards", converter="fos_rest.request_body", class="array")
  777.      * @Rest\QueryParam(name="email", allowBlank=true)
  778.      * @View()
  779.      *
  780.      * @SWG\Response(
  781.      *     response=200,
  782.      *     description="The payment is finished",
  783.      *     @Model(type=\App\Entity\Local\MPay24OrderPaymentTransaction::class))
  784.      *
  785.      * @param $orderId
  786.      * @param array $giftcards
  787.      * @param string $email
  788.      * @param Security $security
  789.      * @return mixed
  790.      * @throws \Doctrine\ORM\ORMException
  791.      * @throws \Doctrine\ORM\OptimisticLockException
  792.      * @throws \GuzzleHttp\Exception\GuzzleException
  793.      * @throws \Throwable
  794.      */
  795.     public function payWithGiftCardAction($orderId$giftcards$emailSecurity $security
  796.     {
  797.         $this->logger->debug('paying with ' .count($giftcards). ' giftcard(s) for '.$email);
  798.         $order $this->orderRepository->findBySessionId($orderId);
  799.         $usedgiftcards=[];
  800.         foreach($giftcards as $gcitem){
  801.             $gc=(new GiftCard)
  802.                 ->setNumber($gcitem['Number'])
  803.                 ->setValueInCents($this->giftCardsRepository->getGiftCardValue($gcitem['Number']));
  804.             $usedgiftcards[]=$gc;
  805.         }        
  806.         $loyaltyMember $security->getUser();
  807.         
  808.         usort($usedgiftcards, function($a$b){
  809.             return $a->getValueInCents() - $b->getValueInCents();
  810.         });
  811.         $this->logger->info('found '.count($usedgiftcards). ' giftcards and sorted them');        
  812.         if( $order->getSession() and $loyaltyMember){
  813.             $session $this->sessionDetailsHelper->loadSession($order->getCinemaId(), $order->getSession()->getId());
  814.             $this->checkTransactionHistory($order$session$loyaltyMember);
  815.         }
  816.         $booking $this->paymentHelper->makeVistaPayment($loyaltyMember$email$order$usedgiftcards);
  817.         $order->setState(Order::STATE_PAYMENT_FINISHED);
  818.         $this->em->flush();
  819.         return $booking;
  820.     }
  821.     /**
  822.      * @Post("/apply-gift-card")
  823.      * @NelmioSecurity(name="Bearer")
  824.      * @ParamConverter("giftcards", converter="fos_rest.request_body", class="array")
  825.      * @View()
  826.      *
  827.      * @SWG\Response(
  828.      *     response=200,
  829.      *     description="gift card applied",
  830.      *     @Model(type=\App\Entity\Local\MPay24OrderPaymentTransaction::class))
  831.      *
  832.      * @param $orderId
  833.      * @param array $giftcards
  834.      * @param Security $security
  835.      * @return mixed
  836.      * @throws \Doctrine\ORM\ORMException
  837.      * @throws \Doctrine\ORM\OptimisticLockException
  838.      * @throws \GuzzleHttp\Exception\GuzzleException
  839.      * @throws \Throwable
  840.      */
  841.     public function applyGiftCardAction($orderId$giftcardsSecurity $security
  842.     {
  843.         try {
  844.             $order $this->renewOrder($orderId);        
  845.         } catch (\Throwable $ex) {
  846.             // must be a reservation :|
  847.             return;
  848.         }
  849.         if (count($giftcards) < 1) {
  850.             // remove all giftcards to let the user remove giftcards from the order
  851.             $this->paymentHelper->removeAllGiftCardsFromOrder($order);
  852.             $this->em->flush();                      
  853.         } else {
  854.             $this->logger->debug('applying ' count($giftcards) . ' giftcard(s) to ' $orderId);
  855.             $usedgiftcards = [];
  856.             foreach($giftcards as $gcitem){
  857.                 $gc=(new GiftCard)
  858.                     ->setNumber($gcitem['Number'])
  859.                     ->setValueInCents($this->giftCardsRepository->getGiftCardValue($gcitem['Number']));
  860.                 $usedgiftcards[]=$gc;
  861.             }        
  862.             usort($usedgiftcards, function($a$b){
  863.                 return $a->getValueInCents() - $b->getValueInCents();
  864.             });
  865.             $this->logger->info('found '.count($usedgiftcards). ' giftcards and sorted them');        
  866.             $result $this->paymentHelper->applyGiftCardsToOrder($order$usedgiftcards);
  867.             if ($result) {
  868.                 $order->setOrderTotalValueInCents($result->getOrderValueRemaining());
  869.                 $this->em->flush();       
  870.             }
  871.         }
  872.         return $order;
  873.     }
  874.     /**
  875.      * @Get("/tickets")
  876.      * @View()
  877.      *
  878.      * @SWG\Response(
  879.      *     response=200,
  880.      *     description="Tickets of the payment",
  881.      *     @Model(type=\App\Entity\Vista\Booking::class))
  882.      *
  883.      * @param $orderId
  884.      * @return mixed
  885.      */
  886.     public function getTicketsAction($orderId) {
  887.         $transaction $this->paymentHelper->getTransaction($orderId);
  888.         if (!$transaction->getVistaBookingId() || !$transaction->getCinemaId()) {
  889.             throw new \InvalidArgumentException(sprintf(
  890.                 'Unpaid order, payment was not processed by MPay24, order id: %s',
  891.                 $orderId
  892.             ));
  893.         }
  894.         // TODO: check if vista booking exists
  895.         
  896.         return $this->bookingHelper->getById($transaction->getVistaBookingId(), $transaction->getCinemaId());
  897.     }
  898.     /**
  899.      * @Route("/tickets/pdf", methods={"GET"})
  900.      * @Rest\View()
  901.      *
  902.      * @SWG\Response(
  903.      *     response="200",
  904.      *     description="Success")
  905.      *
  906.      * @param Security $security
  907.      * @param string $orderId
  908.      * @return Response
  909.      */
  910.     public function pdfAction(Security $securitystring $orderId) {
  911.         $transaction $this->paymentHelper->getTransaction($orderId);
  912.         if (!$transaction->getVistaBookingId() || !$transaction->getCinemaId()) {
  913.             throw new \InvalidArgumentException(sprintf(
  914.                 'Unpaid order, payment was not processed by MPay24, order id: %s',
  915.                 $orderId
  916.             ));
  917.         }
  918.         $booking $this->bookingHelper->getById($transaction->getVistaBookingId(), $transaction->getCinemaId());
  919.         if (null === $booking) {
  920.             throw new NotFoundHttpException();
  921.         }
  922.         /** @var LoyaltyMember $user */
  923.         $user $security->getUser();
  924.         $param = [];
  925.         $param['cinemaId'] = $booking->getCinemaId();
  926.         if ($booking->getTickets()) {
  927.             $param['sessionId'] = $booking->getTickets()[0]->getSessionId();
  928.         }
  929.         $session $this->sessionRepository->findOneBy($param);
  930.         
  931.         $pdf $this->mailer->downloadTicketPdf($booking$session$user$transaction->getEmail());
  932.         $response = new Response($pdf->getBody()->getContents());
  933.         $response->headers->set('Content-type''application/pdf');
  934.         return $response;
  935.     }
  936.     /**
  937.      * Check order restrictions
  938.      *
  939.      * @param Order         $order
  940.      * @param Session       $session
  941.      * @param LoyaltyMember $user
  942.      *
  943.      * @throws \Throwable
  944.      */
  945.     protected function checkTransactionHistory(Order $orderSession $session, ?LoyaltyMember $user) {
  946.         $isBonus false;
  947.         if (SessionBase::STATUS_RED === $session->getStatus()) {
  948.             throw PaymentException::create(
  949.                 'You can only buy tickets at the desk for this session, hurry up!',
  950.                 PaymentException::CODE_PAYMENT_SESSION_RED
  951.             );
  952.         }
  953.         foreach ($order->getTickets() as $ticket) {
  954.             if ($ticket->isLoyaltyTicket()) {
  955.                 $isBonus true;
  956.             }
  957.         }
  958.         $total $order->getTicketsCount();
  959.         $bonusTicketsTotal $order->getBonusTicketsCount();
  960.         if( ! is_null($user)){
  961.             $restrictions $this->sessionDetailsHelper->calculateRestrictions(
  962.                 $user,
  963.                 (int) $session->getCinemaId(),
  964.                 $session->getShowtime()
  965.             );
  966.             if (!$isBonus && ($total $restrictions->getMaxTickets())) {
  967.                 throw new \InvalidArgumentException('Max tickets per order limit reached');
  968.             }
  969.             if ($isBonus && ($bonusTicketsTotal $restrictions->getMaxBonusCardTickets())) {
  970.                 throw new \InvalidArgumentException('Max bonus card tickets per day limit reached');
  971.             }
  972.         }
  973.     }
  974.     /**
  975.      * Check user bookings
  976.      *
  977.      * @param Order         $order
  978.      * @param Session       $session
  979.      * @param LoyaltyMember $user
  980.      *
  981.      * @throws PaymentException
  982.      * @throws \Throwable
  983.      */
  984.     protected function checkBookingHistory(Order $orderSession $sessionLoyaltyMember $user) {
  985.         $total $order->getTicketsCount();
  986.         $bonusTicketsTotal $order->getBonusTicketsCount();
  987.         $restrictions $this->sessionDetailsHelper->calculateRestrictions(
  988.             $user,
  989.             (int) $session->getCinemaId(),
  990.             $session->getShowtime()
  991.         );
  992.         if (SessionBase::STATUS_YELLOW === $session->getStatus()) {
  993.             throw PaymentException::create(
  994.                 'You can only buy tickets for this session, reservation not possible!',
  995.                 PaymentException::CODE_PAYMENT_SESSION_YELLOW
  996.             );
  997.         }
  998.         if (SessionBase::STATUS_RED === $session->getStatus()) {
  999.             throw PaymentException::create(
  1000.                 'You cannot reserve tickets for this session. Please, buy tickets at the desk.',
  1001.                 PaymentException::CODE_PAYMENT_SESSION_RED
  1002.             );
  1003.         }
  1004.         $isBonus false;
  1005.         foreach ($order->getTickets() as $ticket) {
  1006.             $ticket->isLoyaltyTicket() and $isBonus true;
  1007.         }
  1008.         if (!$isBonus && ($total $restrictions->getMaxReservedTickets())) {
  1009.             throw new \InvalidArgumentException('Max reserved tickets per day limit reached');
  1010.         }
  1011.         if ($isBonus && ($bonusTicketsTotal $restrictions->getMaxReservedBonusTickets())) {
  1012.             throw new \InvalidArgumentException('Max reserved bonus card tickets per day limit reached');
  1013.         }
  1014.     }
  1015.     
  1016.     private function getKombankRedirectForm($orderIdstring $responseUrlstring $amount$cinemaId): Response {
  1017.         $paymentPageUrl getenv('KOM_BANK_ADDRESS') ? getenv('KOM_BANK_ADDRESS') : "https://entegrasyon.asseco-see.com.tr/fim/est3Dgate";
  1018.         $okUrl   = (getenv('DEV_SIRMA') ? 'http://' getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) . "$responseUrl/success";  // "/api/v1/orders/$orderId/payment/handle-redirect-post/success"
  1019.         $failUrl = (getenv('DEV_SIRMA') ? 'http://' getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) . "$responseUrl/error";      //URL which client be redirected if authentication is not successful
  1020.         $callbackUrl getenv('KOM_BANK_CALLBACKURL');      //URL which callback to client
  1021.         $rnd microtime();                //A random number, such as date/time
  1022.         $currencyVal "941";            //Currency code, 949 for TL, ISO_4217 standard RSD     941     2     Serbian dinar
  1023.         $storetype "3D_PAY_HOSTING";    //3D authentication model
  1024.         $lang "sr";                    //Language parameter, "tr" for Turkish (default), "en" for English 
  1025.         $instalment "";                //Instalment count, if there's no instalment should left blank
  1026.         $transactionType "Auth";        //transaction type
  1027.         $refreshtime 10;
  1028.         $hashAlgorithm 'ver3';
  1029.         $ids $this->paymentHelper->getMerchant($cinemaId);
  1030.         //error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'),  __METHOD__, __LINE__) . " orderId $orderId cinemaId $cinemaId " . var_export($ids, true));
  1031.         $clientId $ids && array_key_exists('id'$ids) ? $ids['id'] : '250300000';            //Merchant Id defined by bank to user
  1032.         $storekey $ids && array_key_exists('pass'$ids)  ? $ids['pass'] : 'SKEY1234'//Store key value, defined by bank.
  1033.         $params = [
  1034.             'amount'      => $amount,
  1035.             'callbackUrl' => $callbackUrl,
  1036.             'clientid'    => $clientId,
  1037.             'currency'    => $currencyVal,
  1038.             'failUrl'     => $failUrl,
  1039.             'hashAlgorithm' => $hashAlgorithm,
  1040.             'Instalment'  => $instalment,
  1041.             'lang'        => $lang,
  1042.             'oid'         => $orderId,
  1043.             'okUrl'       => $okUrl,
  1044.             'refreshtime' => $refreshtime,
  1045.             'rnd'         => $rnd,
  1046.             'storetype'   => $storetype,
  1047.             'TranType'    => $transactionType
  1048.         ];
  1049.         
  1050.         $hash $this->generateKomBankHash($params$storekey);
  1051.         $paymentRedirect = (new PaymentRedirect())
  1052.             ->setRedirectUrl($paymentPageUrl)
  1053.             ->setFormTitle('Komercijalna Bank')
  1054.             ->setPaymentData(
  1055.                 array_merge($params, ['hash' => $hash])
  1056.             );
  1057.         
  1058.         $response $this->render('web/redirect.html.twig', ['paymentRedirect' => $paymentRedirect] );
  1059.         //error_log(sprintf("%s %s(%s) payment_finish orderId $orderId", date('Y-m-d H:i:s'), __METHOD__, __LINE__));
  1060.         $response->headers->set('Content-Type''text/html; charset=UTF-8'); // Content-Type: text/html; charset=UTF-8
  1061.         return $response;
  1062.     }
  1063.     private function generateKomBankHash(array $paramsstring $storekey): string
  1064.     {
  1065.         $hashval "";
  1066.         foreach ($params as $param) {
  1067.             $escapedParamValue str_replace("|""\\|"str_replace("\\""\\\\"$param));
  1068.             if ($param != "hash" && $param != "encoding") {
  1069.                 $hashval $hashval $escapedParamValue "|";
  1070.             }
  1071.         }
  1072.         $escapedStoreKey str_replace("|""\\|"str_replace("\\""\\\\"$storekey));
  1073.         $hashval $hashval $escapedStoreKey;
  1074.         $calculatedHashValue hash('sha512'$hashval);
  1075.         return base64_encode (pack('H*',$calculatedHashValue));
  1076.     }
  1077.     
  1078.     private function getCpayRedirectForm($orderIdstring $responseUrlstring $amount$cinemaId): Response {
  1079.         // inspired by https://github.com/c0nevski/CaSys-php-implementation
  1080.         // https://www.cpay.com.mk/client/Page/default.aspx?xml_id=/mk-MK/.loginToPay/
  1081.         $paymentPageUrl getenv('CPAY_ADDRESS') ? getenv('CPAY_ADDRESS') : 'https://www.cpay.com.mk/client/Page/default.aspx?xml_id=/mk-MK/.loginToPay/.simple/';
  1082.         $okUrl   = (getenv('DEV_SIRMA') ? 'http://' getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) . "$responseUrl/success";  // "/api/v1/orders/$orderId/payment/handle-redirect-post/success"
  1083.         $failUrl = (getenv('DEV_SIRMA') ? 'http://' getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) . "$responseUrl/error";      //URL which client be redirected if authentication is not successful
  1084.         $ids $this->paymentHelper->getMerchant($cinemaId);
  1085.         //error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'),  __METHOD__, __LINE__) . " SD $SD cinemaId $cinemaId " . var_export($ids, true));
  1086.         $merchantId $ids && array_key_exists('id'$ids) ? $ids['id'] : '1755375';            //Merchant Id defined by bank to user getenv('CPAY_MERCHANT_ID')
  1087.         $md5password $ids && array_key_exists('pass'$ids)  ? $ids['pass'] : 'E7883395'//Store key value, defined by bank. getenv('CPAY_PASS')
  1088.         $paymentValues = [
  1089.             'PaymentOKURL'   => $okUrl// strana kade formata kje prenasocuva koga plakjanjeto e uspeshno
  1090.             'PaymentFailURL' => $failUrl// strana kade formata kje prenasocuva koga plakjanjeto e neuspeshno
  1091.             'AmountToPay'    => $amount// $mult; // cenata sto treba da se plati pomnozena so 100
  1092.             'AmountCurrency' => 'MKD'// valuta vo koja se vrsi plakjanjeto
  1093.             'PayToMerchant'  => $merchantId,  // "Tuka obicno imate dadeno 10 cifren broj - ova e fiksno od caSys"; // ova ne treba da se menuva, ova e dadeno od CaSys
  1094.             'MerchantName'   => 'Cineplexx Macedonia'// ova ne treba da se menuva, ova e dadeno od CaSys
  1095.             'Details1'       => 'CINEPLEXX'// Moze da se napise sto bilo - go pisuva vo casys formata za plakanje kako detali 1
  1096.             'Details2'       => $orderId// unikatni redni broevi
  1097.             'OriginalAmount' => sprintf('%.2f'floatval($amount) / 100)
  1098.         ];
  1099.         $fieldNames '';
  1100.         $fieldLens '';
  1101.         $fieldValues '';
  1102.         $postForm '';
  1103.         foreach($paymentValues as $key => $value) {
  1104.             $fieldNames  .= "$key,";
  1105.             $fieldLens   .= sprintf("%03d"mb_strlen($value'UTF-8'));
  1106.             $fieldValues .= "$value";
  1107.             $postForm    .= "<input id='$key' name='$key' value='$value' type='hidden' />\n";
  1108.         }
  1109.         $fieldValues .= $md5password;
  1110.         $CheckSumHeader sprintf("%02d"count($paymentValues)) . "$fieldNames$fieldLens";
  1111.         $CheckSum md5("$CheckSumHeader$fieldValues");  //ova generira md5 od checkshumheader
  1112.         $paymentValues['CheckSumHeader'] = $CheckSumHeader;
  1113.         $paymentValues['CheckSum']       = $CheckSum;
  1114.         $paymentRedirect = (new PaymentRedirect())
  1115.             ->setRedirectUrl($paymentPageUrl)
  1116.             ->setFormTitle('CPay Bank')
  1117.             ->setPaymentData($paymentValues);
  1118.         
  1119.         $response $this->render('web/redirect.html.twig', ['paymentRedirect' => $paymentRedirect] );
  1120.         //error_log(sprintf("%s %s(%s) payment_finish orderId $orderId", date('Y-m-d H:i:s'), __METHOD__, __LINE__));
  1121.         $response->headers->set('Content-Type''text/html; charset=UTF-8'); // Content-Type: text/html; charset=UTF-8
  1122.         return $response;
  1123.     }
  1124. }