src/Controller/Application/ApplicationController.php line 122

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Application;
  3. use App\Builder\ApplicationCommentBuilder;
  4. use App\BusinessManager\ApplicationBusinessManager;
  5. use App\Constant\DocumentType;
  6. use App\Controller\BaseController;
  7. use App\Form\Helper\FormHelper;
  8. use App\Form\Model\AcquiringModel;
  9. use App\Form\Model\Application\ManualRiskFactor;
  10. use App\Form\Model\ApplicationFilterModel;
  11. use App\Form\Model\ApplicationModel;
  12. use App\Form\Model\ExportApplicationModel;
  13. use App\Form\Type\Application\ManualRiskFactorType;
  14. use App\Form\Type\Application\WorkflowType;
  15. use App\Form\Type\ApplicationFilterType;
  16. use App\Form\Type\ApplicationJsonType;
  17. use App\Form\Type\ApplicationType;
  18. use App\Form\Type\ExportApplicationType;
  19. use App\Form\Type\User\UserCommentType;
  20. use App\Repository\ApplicationClickHouseRepository;
  21. use App\Repository\UserRepository;
  22. use App\RequestManager\Account\BalanceRequestManager;
  23. use App\RequestManager\Application\ApplicationProductStatusRequestManager;
  24. use App\RequestManager\Application\ApplicationRequestManager;
  25. use App\RequestManager\Application\CompanyRequestManager;
  26. use App\RequestManager\IdentificationRequestManager;
  27. use App\RequestManager\InstanceRequestManager;
  28. use App\RequestManager\PayooRequestManager;
  29. use App\RequestManager\RiskV3RequestManager;
  30. use GuzzleHttp\Exception\GuzzleException;
  31. use OldSound\RabbitMqBundle\RabbitMq\ProducerInterface;
  32. use Paynetics\Exception\ApiException;
  33. use Paynetics\Exception\RequestException;
  34. use Symfony\Component\HttpFoundation\HeaderUtils;
  35. use Symfony\Component\HttpFoundation\RedirectResponse;
  36. use Symfony\Component\HttpFoundation\Request;
  37. use Symfony\Component\HttpFoundation\Response;
  38. use Symfony\Component\Serializer\Exception\ExceptionInterface;
  39. /**
  40.  * Class ApplicationController.
  41.  */
  42. class ApplicationController extends BaseController
  43. {
  44.     /**
  45.      * @required
  46.      */
  47.     public PayooRequestManager $payooRequestManager;
  48.     /**
  49.      * @required
  50.      */
  51.     public ApplicationRequestManager $applicationRequestManager;
  52.     /**
  53.      * @required
  54.      */
  55.     public ApplicationProductStatusRequestManager $applicationProductStatusRequestManager;
  56.     /**
  57.      * @required
  58.      */
  59.     public IdentificationRequestManager $identificationService;
  60.     /**
  61.      * @required
  62.      */
  63.     public UserRepository $userRepository;
  64.     /**
  65.      * @required
  66.      */
  67.     public ApplicationClickHouseRepository $applicationRepository;
  68.     /**
  69.      * @required
  70.      */
  71.     public RiskV3RequestManager $riskRequestManager;
  72.     /**
  73.      * @required
  74.      */
  75.     public BalanceRequestManager $balanceRequestManager;
  76.     /**
  77.      * @required
  78.      */
  79.     public InstanceRequestManager $instanceRequestManager;
  80.     /**
  81.      * @required
  82.      */
  83.     public ProducerInterface $applicationWorkflowProducer;
  84.     /**
  85.      * @required
  86.      */
  87.     public ProducerInterface $riskLeProducer;
  88.     /**
  89.      * @required
  90.      */
  91.     public RiskV3RequestManager $riskV3RequestManager;
  92.     /**
  93.      * @required
  94.      */
  95.     public CompanyRequestManager $companyRequestManager;
  96.     /**
  97.      * @required
  98.      */
  99.     public ApplicationBusinessManager $applicationBusinessManager;
  100.     /**
  101.      * @throws ApiException
  102.      * @throws GuzzleException
  103.      * @throws \JsonException
  104.      * @throws ExceptionInterface
  105.      */
  106.     public function index(Request $requestint $page 1int $limit 20): Response
  107.     {
  108.         $this->isGranted(['ROLE_SUPPORT''ROLE_KYB''ROLE_CARD_OPS''ROLE_DISPUTE''ROLE_PM''ROLE_READ_ONLY']);
  109.         $filter $this->createForm(ApplicationFilterType::class, new ApplicationFilterModel(), ['action' => $this->generateUrl('applications')]);
  110.         $filter->handleRequest($request);
  111.         $applicationsData $this->applicationRepository->getApplications($page$limit$filter->getData());
  112.         $applications $this->paginate($applicationsData$page$limit);
  113.         // Create export form
  114.         $exportModel = new ExportApplicationModel();
  115.         $exportForm $this->createForm(ExportApplicationType::class, $exportModel, [
  116.             'action' => $this->generateUrl('export'),
  117.         ]);
  118.         return $this->render('application/index.html.twig', [
  119.             'applications' => $applications,
  120.             'current' => $page,
  121.             'page' => $page,
  122.             'filter' => $filter->createView(),
  123.             'exportForm' => $exportForm->createView(),
  124.         ]);
  125.     }
  126.     public function create(Request $request): Response
  127.     {
  128.         $this->isGranted(['ROLE_SUPPORT''ROLE_KYB']);
  129.         // Create the form using our new ApplicationJsonType
  130.         $form $this->createForm(ApplicationJsonType::class);
  131.         $form->handleRequest($request);
  132.         if ($form->isSubmitted()) {
  133.             $data $form->getData();
  134.             foreach ($data['company']['company_members'] as $id => $companyMember) {
  135.                 if (true == $companyMember['is_deleted']) {
  136.                     unset($data['company']['company_members'][$id]);
  137.                 }
  138.             }
  139.             if ($form->isValid()) {
  140.                 try {
  141.                     // Process company members' documents
  142.                     if (isset($data['company']['company_members'])) {
  143.                         foreach ($data['company']['company_members'] as &$member) {
  144.                             if (isset($member['documents'])) {
  145.                                 // Filter out empty document entries
  146.                                 $member['documents'] = array_filter($member['documents'], function ($doc) {
  147.                                     return !empty($doc) && isset($doc['file']);
  148.                                 });
  149.                                 // Reset array keys to be sequential
  150.                                 $member['documents'] = array_values($member['documents']);
  151.                                 foreach ($member['documents'] as &$document) {
  152.                                     if (isset($document['file']) && $document['file'] instanceof \Symfony\Component\HttpFoundation\File\UploadedFile) {
  153.                                         // Get file extension BEFORE converting to base64
  154.                                         $document['file_type'] = pathinfo($document['file']->getClientOriginalName(), PATHINFO_EXTENSION);
  155.                                         // Convert file to base64
  156.                                         $document['file'] = base64_encode(file_get_contents($document['file']->getPathname()));
  157.                                     }
  158.                                 }
  159.                             }
  160.                         }
  161.                     }
  162.                     // Process company documents
  163.                     if (isset($data['company']['documents'])) {
  164.                         // Filter out empty document entries
  165.                         $data['company']['documents'] = array_filter($data['company']['documents'], function ($doc) {
  166.                             return !empty($doc) && isset($doc['file']);
  167.                         });
  168.                         // Reset array keys to be sequential
  169.                         $data['company']['documents'] = array_values($data['company']['documents']);
  170.                         foreach ($data['company']['documents'] as &$document) {
  171.                             if (isset($document['file']) && $document['file'] instanceof \Symfony\Component\HttpFoundation\File\UploadedFile) {
  172.                                 // Get file extension BEFORE converting to base64
  173.                                 $document['file_type'] = pathinfo($document['file']->getClientOriginalName(), PATHINFO_EXTENSION);
  174.                                 // Convert file to base64
  175.                                 $document['file'] = base64_encode(file_get_contents($document['file']->getPathname()));
  176.                             }
  177.                         }
  178.                     }
  179.                     // Set IP address and fingerprint
  180.                     $data['ip_address'] = $request->getClientIp();
  181.                     $data['fingerprint'] = $request->headers->get('User-Agent');
  182.                     $data['channel'] = 'admin';
  183.                     // Create the application
  184.                     $result $this->applicationRequestManager->createApplication($data);
  185.                     $this->addFlash('success''Application created successfully');
  186.                     return $this->redirectToRoute('application_view', [
  187.                         'token' => $result['token'] ?? null,
  188.                         'product' => $data['products'][0] ?? 'pos',
  189.                     ]);
  190.                 } catch (\Exception $e) {
  191.                     // TODO remove before deploy on prod
  192.                     $errorMessage 'Error creating application: '.$e->getMessage();
  193.                     //                $this->addFlash('error', 'Error creating application: ' . $e->getMessage());
  194.                 }
  195.             }
  196.         }
  197.         return $this->renderForm('application/create.html.twig', [
  198.             'form' => $form,
  199.             'errorMessage' => $errorMessage ?? null,
  200.         ]);
  201.     }
  202.     /**
  203.      * @throws ApiException
  204.      * @throws GuzzleException
  205.      * @throws \JsonException
  206.      */
  207.     public function view(string $tokenstring $product): Response
  208.     {
  209.         $this->isGranted(['ROLE_SUPPORT''ROLE_KYB''ROLE_CARD_OPS''ROLE_DISPUTE''ROLE_PM']);
  210.         $application $this->applicationRequestManager->getApplication($token);
  211.         $aps array_filter($application['application_product_statuses'] ?? [], function ($aps) use ($product) {
  212.             return ($aps['product']['name'] ?? null) === $product;
  213.         });
  214.         if (empty($aps)) {
  215.             throw new \Exception('Product '.$product.' not found for application');
  216.         }
  217.         $aps end($aps);
  218.         $documents $this->identificationService->getDocumentsList($application['company']['token'], 'company''create');
  219.         $documentTypes array_column(
  220.             $this->identificationService->getTypes()['items'] ?? [],
  221.             'name',
  222.             'code'
  223.         );
  224.         return $this->render('application/show.html.twig', [
  225.             'application' => $application,
  226.             'aps' => $aps,
  227.             'product' => $product,
  228.             'documents' => $documents,
  229.             'documentTypes' => $documentTypes,
  230.         ]);
  231.     }
  232.     public function merchant(string $token): RedirectResponse
  233.     {
  234.         try {
  235.             $application $this->applicationRequestManager->getByMerchant($token);
  236.             $product $application['application_product_statuses'][0]['product']['name'];
  237.         } catch (\Throwable $e) {
  238.             return $this->redirectToRoute('merchants_show', ['token' => $token]);
  239.         }
  240.         return $this->redirectToRoute('application_view', ['token' => $application['token'], 'product' => $product]);
  241.     }
  242.     /**
  243.      * @throws ApiException
  244.      * @throws GuzzleException
  245.      */
  246.     public function reassign(string $tokenstring $productstring $admin): RedirectResponse
  247.     {
  248.         $this->applicationProductStatusRequestManager->update($token$product, ['reviewer' => $admin]);
  249.         return $this->redirectToRoute('application_view'compact('token''product'));
  250.     }
  251.     /**
  252.      * @throws ApiException
  253.      * @throws GuzzleException
  254.      * @throws \JsonException
  255.      */
  256.     public function additionalInfo(Request $requeststring $tokenstring $product): Response
  257.     {
  258.         $application $this->applicationRequestManager->getApplication($token);
  259.         $aps array_filter($application['application_product_statuses'] ?? [], function ($aps) use ($product) {
  260.             return ($aps['product']['name'] ?? null) === $product;
  261.         });
  262.         if (empty($aps)) {
  263.             throw new \Exception('Product '.$product.' not found for application');
  264.         }
  265.         $aps end($aps);
  266.         if (isset($application['comments']) && is_array($application['comments'])) {
  267.             $tokens = [];
  268.             foreach ($application['comments'] as $comment) {
  269.                 if (isset($comment['comment_by']) && !empty($comment['comment_by'])) {
  270.                     $tokens[] = $comment['comment_by'];
  271.                 }
  272.             }
  273.             $usernameMap $this->userRepository->findUsernamesByTokens(array_unique($tokens));
  274.             foreach ($application['comments'] as &$comment) {
  275.                 if (isset($comment['comment_by']) && isset($usernameMap[$comment['comment_by']])) {
  276.                     $comment['comment_by'] = $usernameMap[$comment['comment_by']];
  277.                 } else {
  278.                     $comment['comment_by'] = 'Unknown User';
  279.                 }
  280.             }
  281.         }
  282.         $commentForm $this->createForm(UserCommentType::class);
  283.         $commentForm->handleRequest($request);
  284.         if ($commentForm->isSubmitted() && $commentForm->isValid()) {
  285.             $commentData $commentForm->getData();
  286.             $comment $commentData->getComment();
  287.             if (!empty($comment)) {
  288.                 $data ApplicationCommentBuilder::createComment($token$this->getUser()->getToken(), $comment);
  289.                 $this->applicationRequestManager->createComment($data);
  290.                 $this->addFlash('success''Comment added successfully');
  291.                 return $this->redirectToRoute('application_additional_info', [
  292.                     'token' => $token,
  293.                     'product' => $product,
  294.                 ]);
  295.             }
  296.         }
  297.         return $this->render('application/additional-info.html.twig', [
  298.             'application' => $application,
  299.             'aps' => $aps,
  300.             'product' => $product,
  301.             'commentForm' => $commentForm->createView(),
  302.         ]);
  303.     }
  304.     /**
  305.      * @throws ApiException
  306.      * @throws GuzzleException
  307.      * @throws \JsonException
  308.      */
  309.     public function statusLogs(string $tokenstring $productint $page 1int $limit 20): Response
  310.     {
  311.         $this->isGranted(['ROLE_SUPPORT''ROLE_KYB''ROLE_DISPUTE']);
  312.         $application $this->applicationRequestManager->getApplication($token);
  313.         $logs $this->applicationRequestManager->statusLogs($token$page$limit);
  314.         foreach ($logs['items'] as &$log) {
  315.             if (isset($log['admin'])) {
  316.                 $log['admin'] = $this->userRepository->findOneBy(['token' => $log['admin']])->getUsername();
  317.             } else {
  318.                 $log['admin'] = 'Automatically';
  319.             }
  320.         }
  321.         $aps array_filter($application['application_product_statuses'] ?? [], function ($aps) use ($product) {
  322.             return ($aps['product']['name'] ?? null) === $product;
  323.         });
  324.         if (empty($aps)) {
  325.             throw new \Exception('Product '.$product.' not found for application');
  326.         }
  327.         $aps end($aps);
  328.         return $this->render('application/status-logs.html.twig'compact('application''logs''product''aps'));
  329.     }
  330.     /**
  331.      * @throws ApiException
  332.      * @throws GuzzleException
  333.      * @throws \JsonException
  334.      */
  335.     public function mccAuditLogs(string $tokenstring $productint $page 1int $limit 20): Response
  336.     {
  337.         $this->isGranted(['ROLE_SUPPORT''ROLE_KYB''ROLE_DISPUTE']);
  338.         $application $this->applicationRequestManager->getApplication($token);
  339.         $logs $this->applicationRequestManager->mccAuditLogs($token$page$limit);
  340.         foreach ($logs['items'] as &$log) {
  341.             if (isset($log['admin'])) {
  342.                 $user $this->userRepository->findOneBy(['token' => $log['admin']]);
  343.                 $log['admin'] = $user $user->getUsername() : $log['admin'];
  344.             } else {
  345.                 $log['admin'] = 'Automatically';
  346.             }
  347.         }
  348.         $aps array_filter($application['application_product_statuses'] ?? [], function ($aps) use ($product) {
  349.             return ($aps['product']['name'] ?? null) === $product;
  350.         });
  351.         if (empty($aps)) {
  352.             throw new \Exception('Product '.$product.' not found for application');
  353.         }
  354.         $aps end($aps);
  355.         $documentTypes array_flip(DocumentType::DOCUMENT_TYPES_NAMES);
  356.         return $this->render('application/mcc-audit-logs.html.twig'compact('application''logs''documentTypes''product''aps'));
  357.     }
  358.     /**
  359.      * @throws ApiException
  360.      * @throws GuzzleException
  361.      * @throws \JsonException
  362.      */
  363.     public function workflow(Request $requeststring $tokenstring $product): Response
  364.     {
  365.         $this->isGranted(['ROLE_DEVELOPER''ROLE_DISPUTE']);
  366.         $application $this->applicationRequestManager->getApplication($token);
  367.         $workflow $this->applicationRequestManager->workflow($token);
  368.         $aps array_filter($application['application_product_statuses'] ?? [], function ($aps) use ($product) {
  369.             return ($aps['product']['name'] ?? null) === $product;
  370.         });
  371.         if (empty($aps)) {
  372.             throw new \Exception('Product '.$product.' not found for application');
  373.         }
  374.         $aps end($aps);
  375.         $documents $this->identificationService->getDocumentsList($application['company']['token'], 'company''create');
  376.         $documentTypes array_flip(DocumentType::DOCUMENT_TYPES_NAMES);
  377.         $form $this->createForm(WorkflowType::class, null, ['instance' => $application['instance']]);
  378.         $form->handleRequest($request);
  379.         if ($form->isSubmitted() && $form->isValid()) {
  380.             $this->applicationWorkflowProducer->publish(json_encode([
  381.                 'application' => $token,
  382.                 'criteria' => $form->getData()['criteria'],
  383.             ], JSON_THROW_ON_ERROR));
  384.         }
  385.         $form $form->createView();
  386.         return $this->render('application/workflow.html.twig'compact('application''workflow''aps''product''documents''documentTypes''form'));
  387.     }
  388.     /**
  389.      * @throws ApiException
  390.      * @throws GuzzleException
  391.      * @throws \JsonException
  392.      * @throws \Exception
  393.      */
  394.     public function risk(Request $requeststring $tokenstring $product): Response
  395.     {
  396.         $this->isGranted(['ROLE_SUPPORT''ROLE_KYB''ROLE_CARD_OPS''ROLE_DISPUTE''ROLE_PM']);
  397.         $application $this->applicationRequestManager->getApplication($token);
  398.         $aps array_filter($application['application_product_statuses'] ?? [], static function ($aps) use ($product) {
  399.             return ($aps['product']['name'] ?? null) === $product;
  400.         });
  401.         if (empty($aps)) {
  402.             throw new \Exception('Product '.$product.' not found for application');
  403.         }
  404.         $aps end($aps);
  405.         $manualRiskFromModel = new ManualRiskFactor();
  406.         $manualRiskFromModel->setBehaviour($application['behaviour']);
  407.         $manualRiskFromModel->setReputation($application['reputation']);
  408.         $manualRiskFromModel->setPostSar($application['post_sar']);
  409.         $manualRiskFromModel->setSanctionTfMatch($application['sanction_tf_match']);
  410.         $manualRiskFromModel->setUboBehaviour($application['ubo_behaviour']);
  411.         $manualRiskFromModel->setUboReputation($application['ubo_reputation']);
  412.         $manualRiskFromModel->setUboPostSar($application['ubo_post_sar']);
  413.         $manualRiskFromModel->setUboSanctionTfMatch($application['ubo_sanction_tf_match']);
  414.         $manualRiskFrom $this->createForm(ManualRiskFactorType::class, $manualRiskFromModel);
  415.         $manualRiskFrom->handleRequest($request);
  416.         if ($manualRiskFrom->isSubmitted() && $manualRiskFrom->isValid()) {
  417.             /**
  418.              * @var ManualRiskFactor $formData
  419.              */
  420.             $formData $manualRiskFrom->getData();
  421.             $data = [];
  422.             $data['reputation'] = $formData->getReputation();
  423.             $data['behaviour'] = $formData->getBehaviour();
  424.             $data['post_sar'] = $formData->getPostSar();
  425.             $data['sanction_tf_match'] = $formData->getSanctionTfMatch();
  426.             $data['ubo_reputation'] = $formData->getUboReputation();
  427.             $data['ubo_behaviour'] = $formData->getUboBehaviour();
  428.             $data['ubo_post_sar'] = $formData->getUboPostSar();
  429.             $data['ubo_sanction_tf_match'] = $formData->getUboSanctionTfMatch();
  430.             $data['instance'] = $application['instance'];
  431.             $data['due_diligence'] = $application['due_diligence'] ?? null;
  432.             $this->applicationRequestManager->updateV2($token$data);
  433.             $this->riskLeProducer->publish(json_encode([
  434.                 'application' => $token,
  435.             ], JSON_THROW_ON_ERROR));
  436.             return $this->redirectToRoute('application_risk', ['token' => $token'product' => $product]);
  437.         }
  438.         $documents $this->identificationService->getDocumentsList($application['company']['token'], 'company''create');
  439.         if(empty($application['merchant'])) {
  440.             $risk null;
  441.         } else {
  442.             $risk $this->riskRequestManager->loadApplicationScore($application['merchant']);
  443.         }
  444.         return $this->render('application/risk.html.twig', [
  445.             'application' => $application,
  446.             'application_token' => $token,
  447.             'aps' => $aps,
  448.             'product' => $product,
  449.             'documents' => $documents,
  450.             'risk' => $risk ?? null,
  451.             'manualRiskForm' => $manualRiskFrom->createView(),
  452.         ]);
  453.     }
  454.     /**
  455.      * @throws ApiException
  456.      * @throws GuzzleException
  457.      */
  458.     public function downloadRiskFile(Request $request, ?string $token null): Response
  459.     {
  460.         $this->isGranted(['ROLE_KYC''ROLE_KYB''ROLE_TRANSFERS''ROLE_SUPPORT''ROLE_SUPPORT_MANAGER''ROLE_TRANSFERS_MANAGER''ROLE_TRANSACTION_MANAGER''ROLE_CARD_OPS''ROLE_CARD_OPS_MANAGER''ROLE_RISK_MANAGER''ROLE_DISPUTE']);
  461.         $response = new Response($this->riskV3RequestManager->downloadRiskFile(null$token));
  462.         $disposition HeaderUtils::makeDisposition(
  463.             HeaderUtils::DISPOSITION_ATTACHMENT,
  464.             'risk-score-'.$token.'.xlsx'
  465.         );
  466.         $response->headers->set('Content-Disposition'$disposition);
  467.         return $response;
  468.     }
  469.     /**
  470.      * @throws ApiException
  471.      * @throws ExceptionInterface
  472.      * @throws GuzzleException
  473.      * @throws RequestException
  474.      * @throws \JsonException
  475.      */
  476.     public function update(Request $requeststring $tokenstring $product): Response
  477.     {
  478.         $this->isGranted(['ROLE_KYB']);
  479.         try {
  480.             $applicationData $this->applicationRequestManager->getApplication($token);
  481.         } catch (RequestException $e) {
  482.             if (11002 === $e->getCode()) {
  483.                 return new Response($e->getMessage(), 404);
  484.             }
  485.             throw $e;
  486.         }
  487.         // Extract Application Product Status (aps) for navigation
  488.         $aps array_filter($applicationData['application_product_statuses'] ?? [], function ($aps) use ($product) {
  489.             return ($aps['product']['name'] ?? null) === $product;
  490.         });
  491.         $aps = !empty($aps) ? end($aps) : null;
  492.         if (isset($applicationData['company']['incorporation_date'])) {
  493.             $dateTime = new \DateTime($applicationData['company']['incorporation_date']);
  494.             $applicationData['company']['incorporation_date'] = $dateTime->format('Y-m-d');
  495.         }
  496.         // Capture due_diligence before denormalization (snake_case from API)
  497.         $dueDiligence $applicationData['due_diligence'] ?? null;
  498.         $acquiringData = [];
  499.         if (isset($applicationData['acquiring']) && is_array($applicationData['acquiring'])) {
  500.             foreach ($applicationData['acquiring'] as $acquiring) {
  501.                 $acquiringModel = new AcquiringModel();
  502.                 $acquiringModel->setType($acquiring['type'] ?? null);
  503.                 $acquiringModel->setFeeGroup($acquiring['fee_group'] ?? null);
  504.                 $acquiringModel->setSupportedAuthorizationTypes($acquiring['supported_authorization_types'] ?? []);
  505.                 $acquiringModel->setDescriptor($acquiring['descriptor'] ?? null);
  506.                 if (($acquiring['type'] ?? '') === 'e-commerce' || ($acquiring['type'] ?? '') === 'pos') {
  507.                     $acquiringModel->setRegister3ds($acquiring['register3ds'] ?? false);
  508.                 }
  509.                 $acquiringData[] = $acquiringModel;
  510.             }
  511.         }
  512.         /**
  513.          * @var ApplicationModel $applicationModel
  514.          */
  515.         $applicationModel $this->denormalize($applicationData ?? [], ApplicationModel::class);
  516.         $applicationModel->setProducts([$product]);
  517.         $applicationModel->setAcquiring($acquiringData);
  518.         $applicationModel->setDueDiligence($dueDiligence);
  519.         $form $this->createForm(ApplicationType::class, $applicationModel);
  520.         $form->handleRequest($request);
  521.         if ($form->isSubmitted() && $form->isValid()) {
  522.             try {
  523.                 $this->applicationBusinessManager->updateFromModel($token$form->getData(), $request->get('syncWithBanks'false));
  524.                 return $this->redirectToRoute('application_view', ['token' => $token'product' => $product]);
  525.             } catch (RequestException $e) {
  526.                 if (11001 === $e->getCode()) {
  527.                     foreach ($e->getErrors() as $key => $message) {
  528.                         FormHelper::addFieldError($form$key$message);
  529.                     }
  530.                 }
  531.             }
  532.         }
  533.         return $this->renderForm('application/company/update.html.twig', [
  534.             'form' => $form,
  535.             'application' => $applicationData,
  536.             'product' => $product,
  537.             'aps' => $aps,
  538.             'token' => $token,
  539.         ]);
  540.     }
  541.     /**
  542.      * @return RedirectResponse
  543.      */
  544.     public function updateCompanySingle($token$product$company$field$value)
  545.     {
  546.         $this->isGranted(['ROLE_KYB']);
  547.         $data['token'] = $company;
  548.         $data[$field] = $value;
  549.         try {
  550.             $this->applicationRequestManager->updateCompany($token$data);
  551.         } catch (GuzzleException|ApiException $e) {
  552.         }
  553.         return $this->redirectToRoute('application_view_trade_register', ['token' => $token'product' => $product]);
  554.     }
  555.     /**
  556.      * @throws ApiException
  557.      * @throws GuzzleException
  558.      */
  559.     public function updateStatus(string $tokenstring $statusstring $product): RedirectResponse
  560.     {
  561.         $this->isGranted(['ROLE_KYB']);
  562.         $this->applicationRequestManager->updateApplicationStatus($token$status$product$this->getUser()->getToken());
  563.         return $this->redirectToRoute('application_view', ['token' => $token'product' => $product]);
  564.     }
  565. }