src/Controller/InstanceController.php line 335

Open in your IDE?
  1. <?php
  2. declare(strict_types 1);
  3. namespace App\Controller;
  4. use App\Form\Model\ApplicationFilterModel;
  5. use App\Form\Model\Instance\InstanceFilterModel;
  6. use App\Form\Model\Instance\InstanceModel;
  7. use App\Form\Model\Merchant\MerchantFilterModel;
  8. use App\Form\Model\OperationFilterModel;
  9. use App\Form\Model\Store\StoreFilterModel;
  10. use App\Form\Model\TransactionFiltersModel;
  11. use App\Form\Type\Instance\HashCalculatorType;
  12. use App\Form\Type\Instance\InstanceType;
  13. use App\Form\Type\InstanceFilterType;
  14. use App\Form\Type\Operation\OperationAddType;
  15. use App\Form\Type\Operation\OperationFilterType;
  16. use App\Manager\S3UploaderManager;
  17. use App\RequestManager\Account\ProgramRequestManager;
  18. use App\RequestManager\Application\ApplicationRequestManager;
  19. use App\RequestManager\InstanceRequestManager;
  20. use App\RequestManager\MerchantRequestManager;
  21. use App\RequestManager\OperationRequestManager;
  22. use App\RequestManager\TerminalRequestManager;
  23. use App\RequestManager\Transaction\TransactionV2RequestManager;
  24. use GuzzleHttp\Exception\GuzzleException;
  25. use Paynetics\Exception\ApiException;
  26. use Paynetics\Exception\RequestException;
  27. use Symfony\Component\Form\FormError;
  28. use Symfony\Component\HttpFoundation\JsonResponse;
  29. use Symfony\Component\HttpFoundation\RedirectResponse;
  30. use Symfony\Component\HttpFoundation\Request;
  31. use Symfony\Component\HttpFoundation\Response;
  32. use Symfony\Component\Serializer\Exception\ExceptionInterface;
  33. /**
  34.  * Class InstanceController.
  35.  */
  36. class InstanceController extends BaseController
  37. {
  38.     /**
  39.      * @required
  40.      */
  41.     public InstanceRequestManager $instanceRequestManager;
  42.     /**
  43.      * @required
  44.      */
  45.     public MerchantRequestManager $merchantRequestManager;
  46.     /**
  47.      * @required
  48.      */
  49.     public ApplicationRequestManager $applicationRequestManager;
  50.     /**
  51.      * @required
  52.      */
  53.     public TransactionV2RequestManager $transcationRequestManager;
  54.     /**
  55.      * @required
  56.      */
  57.     public TerminalRequestManager $terminalRequestManager;
  58.     /**
  59.      * @required
  60.      */
  61.     public ProgramRequestManager $programRequestManager;
  62.     /**
  63.      * @required
  64.      */
  65.     public OperationRequestManager $operationRequestManager;
  66.     /**
  67.      * @required
  68.      */
  69.     public S3UploaderManager $s3UploaderManager;
  70.     /**
  71.      * @throws ExceptionInterface
  72.      * @throws GuzzleException
  73.      * @throws \Exception
  74.      */
  75.     public function index(Request $requestint $page 1int $limit 20): Response
  76.     {
  77.         //        $this->isGranted(['ROLE_SUPER_ADMIN', 'ROLE_CARD_OPS', 'ROLE_SUPPORT', 'ROLE_PM', 'ROLE_DISPUTE', 'ROLE_TRANSFERS', 'ROLE_RISK_MANAGER', 'ROLE_KY_MANAGER',  'ROLE_KYB_MANAGER',  'ROLE_KYC_MANAGER']);
  78.         $filter $this->createForm(InstanceFilterType::class, new InstanceFilterModel(), ['action' => $this->generateUrl('instances')]);
  79.         $filter->handleRequest($request);
  80.         // For AJAX requests, also check for direct 'name' parameter
  81.         $filterData $filter->getData();
  82.         if ($request->isXmlHttpRequest() && $request->query->has('name')) {
  83.             $filterData->setName($request->query->get('name'));
  84.         }
  85.         try {
  86.             $instances $this->instanceRequestManager->getInstances($page$limit$filterData);
  87.         } catch (\Exception $e) {
  88.             throw new \Exception('Something went wrong');
  89.         }
  90.         if ('json' === $request->getContentType() || $request->isXmlHttpRequest()) {
  91.             return new JsonResponse($instances);
  92.         }
  93.         $instances $this->paginate($instances$page$limit);
  94.         return $this->render('instance/index.html.twig', [
  95.             'instances'   => $instances,
  96.             'filter'      => $filter->createView(),
  97.             'toolbarPage' => 'Instances',
  98.         ]);
  99.     }
  100.     /**
  101.      * @throws ApiException
  102.      * @throws GuzzleException
  103.      * @throws \JsonException
  104.      */
  105.     public function merchants(int $limitint $page$token): Response
  106.     {
  107.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_CARD_OPS''ROLE_SUPPORT''ROLE_PM''ROLE_DISPUTE''ROLE_TRANSFERS''ROLE_RISK_MANAGER''ROLE_KY_MANAGER',  'ROLE_KYB_MANAGER',  'ROLE_KYC_MANAGER']);
  108.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  109.         $merchantFilter = new MerchantFilterModel();
  110.         $merchantFilter->setInstance($token);
  111.         $merchants $this->merchantRequestManager->getMerchants($page$limit$merchantFilter);
  112.         $merchants $this->paginate($merchants$page$limit);
  113.         $toolbarPage 'Instance';
  114.         return $this->render('instance/merchants.html.twig'compact('instance''merchants''toolbarPage'));
  115.     }
  116.     /**
  117.      * @throws ApiException
  118.      * @throws ExceptionInterface
  119.      * @throws GuzzleException
  120.      * @throws \JsonException
  121.      */
  122.     public function view(string $token): Response
  123.     {
  124.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_CARD_OPS''ROLE_SUPPORT''ROLE_PM''ROLE_DISPUTE''ROLE_TRANSFERS''ROLE_RISK_MANAGER''ROLE_KY_MANAGER',  'ROLE_KYB_MANAGER',  'ROLE_KYC_MANAGER']);
  125.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  126.         $merchantFilter = new MerchantFilterModel();
  127.         $merchantFilter->setInstance($token);
  128.         $merchants $this->merchantRequestManager->getMerchants(11$merchantFilter);
  129.         $applicationFilter = new ApplicationFilterModel();
  130.         $applicationFilter->setInstance($token);
  131.         $applications $this->applicationRequestManager->getApplications(11$applicationFilter);
  132.         $transactionFilter = new TransactionFiltersModel();
  133.         $transactionFilter->setInstance($token);
  134.         $transactions $this->transcationRequestManager->getTransactions(11$transactionFilter);
  135.         $storeFilter = new StoreFilterModel();
  136.         $storeFilter->setInstance($token);
  137.         $stores $this->terminalRequestManager->getStores(11$storeFilter);
  138.         return $this->render('instance/show.html.twig', [
  139.             'instance'     => $instance,
  140.             'merchants'    => $merchants,
  141.             'stores'       => $stores,
  142.             'transactions' => $transactions,
  143.             'applications' => $applications,
  144.             'toolbarPage'  => 'Instance',
  145.         ]);
  146.     }
  147.     /**
  148.      * @throws ApiException
  149.      * @throws GuzzleException
  150.      */
  151.     public function create(Request $request): Response
  152.     {
  153.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_SUPPORT_MANAGER']);
  154.         $instanceForm $this->createForm(InstanceType::class, new InstanceModel());
  155.         $instanceForm->handleRequest($request);
  156.         $isAjax $request->isXmlHttpRequest();
  157.         if ($instanceForm->isSubmitted() && $instanceForm->isValid()) {
  158.             try {
  159.                 $instance $this->instanceRequestManager->create($instanceForm->getData());
  160.                 if ($isAjax) {
  161.                     return new JsonResponse(['success' => true'message' => 'Instance created successfully''token' => $instance['token']]);
  162.                 }
  163.                 return $this->redirectToRoute('instance_view', ['token' => $instance['token']]);
  164.             } catch (RequestException $exception) {
  165.                 foreach ($exception->getErrors() as $error) {
  166.                     $error = new FormError($error);
  167.                     $instanceForm->addError($error);
  168.                 }
  169.                 if (=== count($exception->getErrors())) {
  170.                     $message json_decode($exception->getMessage(), true);
  171.                     $error = new FormError($message['message'] ?? null);
  172.                     $instanceForm->addError($error);
  173.                 }
  174.             }
  175.         }
  176.         if ($isAjax) {
  177.             $formAction $this->generateUrl('instance_create');
  178.             return $this->render('instance/_partials/form-modal.html.twig', [
  179.                 'form' => $instanceForm->createView(),
  180.                 'formAction' => $formAction
  181.             ]);
  182.         }
  183.         return $this->render('instance/create.html.twig', [
  184.             'form'        => $instanceForm->createView(),
  185.             'toolbarPage' => 'Instance',
  186.         ]);
  187.     }
  188.     /**
  189.      * @throws ApiException
  190.      * @throws ExceptionInterface
  191.      * @throws GuzzleException
  192.      * @throws \JsonException
  193.      */
  194.     public function update(Request $requeststring $token): Response
  195.     {
  196.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_SUPPORT_MANAGER']);
  197.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  198.         $instanceModel = new InstanceModel();
  199.         $instanceModel->setApiKey($instance['api_key'] ?? null);
  200.         $instanceModel->setApiSecret($instance['api_secret'] ?? null);
  201.         $instanceModel->setAcquiringInstitutionIdentificationCode($instance['acquiring_institution_identification_code'] ?? null);
  202.         $this->denormalize($instanceInstanceModel::class, ['object_to_populate' => $instanceModel]);
  203.         $instanceForm $this->createForm(InstanceType::class, $instanceModel);
  204.         $instanceForm->handleRequest($request);
  205.         if ($instanceForm->isSubmitted() && $instanceForm->isValid()) {
  206.             try {
  207.                 $this->instanceRequestManager->update($instanceModel$token);
  208.                 return $this->redirectToRoute('instance_view'compact('token'));
  209.             } catch (RequestException $exception) {
  210.                 foreach ($exception->getErrors() as $error) {
  211.                     $error = new FormError($error);
  212.                     $instanceForm->addError($error);
  213.                 }
  214.                 if (=== count($exception->getErrors())) {
  215.                     $message json_decode($exception->getMessage(), true);
  216.                     $error = new FormError($message['message'] ?? null);
  217.                     $instanceForm->addError($error);
  218.                 }
  219.             }
  220.         }
  221.         return $this->render('instance/update.html.twig', [
  222.             'instance'    => $instance,
  223.             'form'        => $instanceForm->createView(),
  224.             'toolbarPage' => 'Instance',
  225.         ]);
  226.     }
  227.     /**
  228.      * @throws ApiException
  229.      * @throws GuzzleException
  230.      * @throws \JsonException
  231.      */
  232.     public function stores(string $tokenint $page 1int $limit 5): Response
  233.     {
  234.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  235.         $storeFilter = new StoreFilterModel();
  236.         $storeFilter->setInstance($token);
  237.         $stores $this->terminalRequestManager->getStores($page$limit$storeFilter);
  238.         $stores $this->paginate($stores$page$limit);
  239.         $toolbarPage 'Instance';
  240.         return $this->render('instance/stores.html.twig'compact('instance''stores''toolbarPage'));
  241.     }
  242.     /**
  243.      * @throws ApiException
  244.      * @throws GuzzleException
  245.      * @throws \JsonException
  246.      */
  247.     public function transactions(string $tokenint $page 1int $limit 5): Response
  248.     {
  249.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  250.         $transactionFilter = new TransactionFiltersModel();
  251.         $transactionFilter->setInstance($token);
  252.         $transactions $this->transcationRequestManager->getTransactions($page$limit$transactionFilter);
  253.         $transactions $this->paginate($transactions$page$limit);
  254.         $toolbarPage 'Instance';
  255.         return $this->render('instance/transactions.html.twig'compact('instance''transactions''toolbarPage'));
  256.     }
  257.     /**
  258.      * @throws ApiException
  259.      * @throws GuzzleException
  260.      * @throws \JsonException
  261.      */
  262.     public function applications(string $tokenint $page 1int $limit 5): Response
  263.     {
  264.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  265.         $applicationFilter = new ApplicationFilterModel();
  266.         $applicationFilter->setInstance($token);
  267.         $applications $this->applicationRequestManager->getApplications($page$limit$applicationFilter);
  268.         $applications $this->paginate($applications$page$limit);
  269.         $toolbarPage 'Instance';
  270.         return $this->render('instance/applications.html.twig'compact('instance''applications''toolbarPage'));
  271.     }
  272.     /**
  273.      * @throws ApiException
  274.      * @throws GuzzleException
  275.      * @throws \JsonException
  276.      */
  277.     public function programs(string $token): Response
  278.     {
  279.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_SUPPORT_MANAGER''ROLE_CARD_OPS']);
  280.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  281.         $programs $this->programRequestManager->listPrograms(00, ['instance' => $token]);
  282.         $toolbarPage 'Instance';
  283.         return $this->render('instance/programs.html.twig'compact('instance''programs''toolbarPage'));
  284.     }
  285.     /**
  286.      * @throws ApiException
  287.      * @throws GuzzleException
  288.      * @throws \JsonException
  289.      */
  290.     public function hashCalculator(Request $requeststring $token)
  291.     {
  292.         $this->isGranted(['ROLE_SUPPORT_MANAGER']);
  293.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  294.         $form $this->createForm(HashCalculatorType::class);
  295.         $form->handleRequest($request);
  296.         $headers = [];
  297.         if ($form->isSubmitted() && $form->isValid()) {
  298.             $data $form->getData();
  299.             if ('payoo' === $data['api']) {
  300.                 $headers = [
  301.                     'payoo-api-key'          => $instance['api_key'],
  302.                     'payoo-api-request-date' => $data['timestamp'],
  303.                     'payoo-api-hash'         => hash_hmac('sha256'$instance['api_key'] . $data['timestamp'] . $data['operation'], $instance['api_secret']),
  304.                 ];
  305.             } elseif ('webhook' === $data['api']) {
  306.                 $payload = !empty($data['payload']) ? json_encode(json_decode($data['payload'], true512JSON_THROW_ON_ERROR), JSON_THROW_ON_ERROR JSON_UNESCAPED_SLASHES JSON_UNESCAPED_UNICODE) : '';
  307.                 $headers = [
  308.                     'x-api-key'   => $instance['api_key'],
  309.                     'x-timestamp' => $data['timestamp'],
  310.                     'x-hash'      => hash_hmac('sha256'$payload$instance['api_secret']),
  311.                 ];
  312.             } else {
  313.                 $payload = !empty($data['payload']) ? json_encode(json_decode($data['payload'], true512JSON_THROW_ON_ERROR), JSON_THROW_ON_ERROR JSON_UNESCAPED_SLASHES JSON_UNESCAPED_UNICODE) : '';
  314.                 $headers = [
  315.                     'x-api-key'   => $instance['api_key'],
  316.                     'x-timestamp' => $data['timestamp'],
  317.                     'x-hash'      => hash_hmac('sha256'$instance['api_key'] . ($data['timestamp'] ?? '') . ($data['operation'] ?? '') . $payload$instance['api_secret']),
  318.                 ];
  319.             }
  320.         }
  321.         return $this->renderForm('instance/_partials/hash-calculator.html.twig'compact('instance''form''headers'));
  322.     }
  323.     /**
  324.      * @throws ApiException
  325.      * @throws GuzzleException
  326.      * @throws \JsonException
  327.      */
  328.     public function showApiSecret(string $token): JsonResponse
  329.     {
  330.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_SUPPORT_MANAGER']);
  331.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  332.         return new JsonResponse(['key' => $instance['api_secret']]);
  333.     }
  334.     /**
  335.      * @throws ApiException
  336.      * @throws GuzzleException
  337.      */
  338.     public function generateSharedKey(string $token): RedirectResponse
  339.     {
  340.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_SUPPORT_MANAGER']);
  341.         $this->instanceRequestManager->generateSharedKey($token);
  342.         return $this->redirectToRoute('instance_view', ['token' => $token]);
  343.     }
  344.     public function showSharedKey(string $token): JsonResponse
  345.     {
  346.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_SUPPORT_MANAGER']);
  347.         $key $this->instanceRequestManager->getSharedKey($token);
  348.         return new JsonResponse($key);
  349.     }
  350.     /**
  351.      * @throws ExceptionInterface
  352.      * @throws GuzzleException
  353.      */
  354.     public function statusChange(string $token): RedirectResponse
  355.     {
  356.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_SUPPORT_MANAGER''ROLE_CARD_OPS''ROLE_CARD_OPS_MANAGER']);
  357.         try {
  358.             $instance $this->instanceRequestManager->getInstancesByToken($token);
  359.             /**
  360.              * @var InstanceModel $instanceModel
  361.              */
  362.             $instanceModel $this->denormalize($instanceInstanceModel::class);
  363.             $instanceModel->setIsEnabled(!$instanceModel->getIsEnabled());
  364.             $this->instanceRequestManager->update($instanceModel$token);
  365.         } catch (\Exception $exception) {
  366.             return $this->redirectToRoute('instances');
  367.         }
  368.         return $this->redirectToRoute('instance_view'compact('token'));
  369.     }
  370.     /**
  371.      * @throws ApiException
  372.      * @throws ExceptionInterface
  373.      * @throws GuzzleException
  374.      * @throws \JsonException
  375.      */
  376.     public function operations(Request $requeststring $tokenint $page 1int $limit 15): Response
  377.     {
  378.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_SUPPORT''ROLE_SUPPORT_MANAGER']);
  379.         /** @var OperationFilterModel $filterModel */
  380.         $filterModel $this->denormalize($request->query->all(), OperationFilterModel::class, ['action' => $this->generateUrl('instance_operations', ['token' => $token])]);
  381.         $filterModel->setInstance($token);
  382.         $filters $this->createForm(OperationFilterType::class, $filterModel);
  383.         $filters->handleRequest($request);
  384.         // Get all operations for the instance (OperationMap)
  385.         $operationsByInstance $this->operationRequestManager->getOperationsByInstance($filterModel00);
  386.         $allOperationsByInstance $operationsByInstance;
  387.         if (null !== $filterModel->getOperation()) {
  388.             $filterModel->setOperation(null);
  389.             $allOperationsByInstance $this->operationRequestManager->getOperationsByInstance($filterModel00);
  390.         }
  391.         // Get all operations (Operation)
  392.         $operations $this->operationRequestManager->getOperations(00);
  393.         // Combine operation names for add select dropdown
  394.         $operationChoices array_combine(array_column($operations['items'], 'name'), array_column($operations['items'], 'name'));
  395.         // Extract operation names from $operationsByInstance
  396.         $existingOperations array_column(array_column($allOperationsByInstance['items'], 'operation'), 'name');
  397.         // Filter $operationChoices to remove existing operations
  398.         $operationChoices array_filter($operationChoices, function ($operation) use ($existingOperations) {
  399.             return !in_array($operation$existingOperations);
  400.         });
  401.         $addOperationForm $this->createForm(OperationAddType::class, ['operationChoices' => $operationChoices'instance' => $token]);
  402.         $addOperationForm->handleRequest($request);
  403.         if ($addOperationForm->isSubmitted()) {
  404.             $newOperationsFromExisting $addOperationForm->get('newOperationsFromExisting')->getData();
  405.             if (!empty($newOperationsFromExisting)) {
  406.                 foreach ($newOperationsFromExisting as $newOperation) {
  407.                     $filterModel->setOperation($newOperation);
  408.                     $filterModel->setValue(['enabled' => true]);
  409.                     $this->operationRequestManager->createOperationMap($filterModel);
  410.                 }
  411.                 $filterModel->setOperation(null);
  412.                 $filterModel->setValue(null);
  413.             }
  414.             return $this->redirectToRoute('instance_operations', ['token' => $token'page' => $page'limit' => $limit]);
  415.         }
  416.         // Slice the array to get the subset of operations for the current page
  417.         $maxPage ceil($operationsByInstance['total_items'] / $limit);
  418.         if ($page $maxPage) {
  419.             $page $maxPage;
  420.         }
  421.         if ($page 1) {
  422.             $page 1;
  423.         }
  424.         $operationsByInstance['items'] = array_slice($operationsByInstance['items'], ($page 1) * $limit$limit);
  425.         $operationsByInstance $this->paginate($operationsByInstance$page$limit);
  426.         $instance $this->instanceRequestManager->getInstancesByToken($token);
  427.         return $this->render('instance/operations.html.twig', [
  428.             'instance'         => $instance,
  429.             'operations'       => $operationsByInstance,
  430.             'addOperationForm' => $addOperationForm->createView(),
  431.             'toolbarPage'      => 'Instance',
  432.             'filters'          => $filters->createView(),
  433.         ]);
  434.     }
  435.     /**
  436.      * @throws \JsonException
  437.      */
  438.     public function handleOperationUpdateOrDelete(Request $requeststring $token): Response
  439.     {
  440.         $this->isGranted(['ROLE_SUPER_ADMIN''ROLE_SUPPORT''ROLE_SUPPORT_MANAGER']);
  441.         $content $request->getContent();
  442.         $data json_decode($contenttrue);
  443.         switch ($data['action']) {
  444.             case 'delete':
  445.                 $this->operationRequestManager->deleteOperationMap($data['operationToken']);
  446.                 return new JsonResponse(['message' => 'Operation deleted']);
  447.             case 'reason':
  448.                 $filterModel = new OperationFilterModel();
  449.                 $filterModel->setInstance($token);
  450.                 $filterModel->setOperation($data['operation']);
  451.                 $filterModel->setOperationToken($data['operationToken']);
  452.                 $filterModel->setReason($data['value']);
  453.                 $this->operationRequestManager->updateOperationMap($filterModel$data['operationToken']);
  454.                 return new JsonResponse(['message' => 'Reason updated']);
  455.             default:
  456.                 $json json_decode($data['value'], true512JSON_THROW_ON_ERROR);
  457.                 if (JSON_ERROR_NONE !== json_last_error()) {
  458.                     return new JsonResponse(['message' => 'Invalid JSON format'], Response::HTTP_BAD_REQUEST);
  459.                 }
  460.                 $filterModel = new OperationFilterModel();
  461.                 $filterModel->setInstance($token);
  462.                 $filterModel->setOperation($data['operation']);
  463.                 $filterModel->setOperationToken($data['operationToken']);
  464.                 $filterModel->setReason($data['reason']);
  465.                 $filterModel->setValue($json);
  466.                 $this->operationRequestManager->updateOperationMap($filterModel$filterModel->getOperationToken());
  467.                 return new JsonResponse($json);
  468.         }
  469.     }
  470. }