src/Controller/Api/OrganizationController.php line 1160

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Api;
  3. use App\Enum\DocumentStatusEnum;
  4. use App\Enum\DocumentTypeOrganizationEnum;
  5. use App\Enum\InvoiceStatusEnum;
  6. use App\Enum\LetterTypeEnum;
  7. use App\Enum\OrganizationStatusEnum;
  8. use App\Enum\ProductKeyEnum;
  9. use App\Repository\OrganizationRepository;
  10. use App\Service\DocumentFilesService;
  11. use App\Service\DocumentUtils;
  12. use App\Service\EncryptorDataUtils;
  13. use App\Service\LegalRepresentativeUtils;
  14. use App\Service\Organization\OrganizationDiagnosticService;
  15. use App\Service\OrganizationUtils;
  16. use App\Service\SegmentAPI;
  17. use App\Service\SubscriptionUtils;
  18. use App\Traits\SentryNotifyTrait;
  19. use App\Utils\AppUtils;
  20. use App\Utils\InvoiceUtils;
  21. use Doctrine\ORM\EntityManagerInterface;
  22. use Evo\Domain\Core\SignatureServiceInterface;
  23. use Evo\Infrastructure\MappingORM\Document;
  24. use Evo\Infrastructure\MappingORM\Invoice;
  25. use Evo\Infrastructure\MappingORM\LegalRepresentative;
  26. use Evo\Infrastructure\MappingORM\Letter;
  27. use Evo\Infrastructure\MappingORM\Organization;
  28. use Evo\Infrastructure\MappingORM\PostalAddress;
  29. use Evo\Infrastructure\MappingORM\ProcessYousign;
  30. use Evo\Infrastructure\MappingORM\Quote;
  31. use Evo\Infrastructure\MappingORM\Subscription;
  32. use Evo\Infrastructure\MappingORM\User;
  33. use Evo\Infrastructure\PdfGenerator\PathGenerator;
  34. use Evo\Infrastructure\Repository\InvoiceRepository;
  35. use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
  36. use Knp\Snappy\Pdf;
  37. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  38. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  39. use Symfony\Component\HttpFoundation\JsonResponse;
  40. use Symfony\Component\HttpFoundation\Request;
  41. use Symfony\Component\HttpFoundation\Response;
  42. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  43. use Symfony\Component\HttpKernel\KernelInterface;
  44. use Symfony\Component\Routing\Annotation\Route;
  45. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  46. use Symfony\Component\Routing\RouterInterface;
  47. use Symfony\Component\Serializer\Exception\ExceptionInterface;
  48. use Symfony\Component\Serializer\SerializerInterface;
  49. use Symfony\Contracts\Translation\TranslatorInterface;
  50. use Twig\Environment;
  51. /**
  52.  * @Route("/organization")
  53.  */
  54. class OrganizationController extends AbstractController
  55. {
  56.     use SentryNotifyTrait;
  57.     public const DIGIDOM_SIREN '797978996';
  58.     public const DIGIDOM_COMPANY_NAME 'KOAH DIGIDOM';
  59.     public const DIGIDOM_STORE_STREET_ADDRESS '10 RUE DE PENTHIEVRE';
  60.     public const DIGIDOM_COMPANY_POSTAL_CODE '75008 PARIS';
  61.     private EntityManagerInterface $em;
  62.     private OrganizationUtils $organizationUtils;
  63.     private InvoiceUtils $invoiceUtils;
  64.     private EncryptorDataUtils $encryptor;
  65.     private ?Request $request null;
  66.     private UrlGeneratorInterface $router;
  67.     private SessionInterface $session;
  68.     private DocumentUtils $documentUtils;
  69.     private TranslatorInterface $translator;
  70.     private SegmentAPI $segmentAPI;
  71.     private OrganizationDiagnosticService $organizationDiagnosticService;
  72.     private AppUtils $appUtils;
  73.     private OrganizationRepository $organizationRepository;
  74.     private SerializerInterface $serializer;
  75.     private KernelInterface $kernel;
  76.     private Pdf $pdf;
  77.     private Environment $twig;
  78.     private LegalRepresentativeUtils $legalRepresentativeUtils;
  79.     private SignatureServiceInterface $yousignAPI;
  80.     private DocumentFilesService $documentFilesService;
  81.     private ParameterBagInterface $params;
  82.     public function __construct(
  83.         EntityManagerInterface $em,
  84.         InvoiceUtils $invoiceUtils,
  85.         DocumentUtils $documentUtils,
  86.         OrganizationUtils $organizationUtils,
  87.         LegalRepresentativeUtils $legalRepresentativeUtils,
  88.         SignatureServiceInterface $yousignAPI,
  89.         DocumentFilesService $documentFilesService,
  90.         ParameterBagInterface $params,
  91.         EncryptorDataUtils $encryptor,
  92.         RouterInterface $router,
  93.         SessionInterface $session,
  94.         TranslatorInterface $translator,
  95.         SegmentAPI $segmentAPI,
  96.         OrganizationDiagnosticService $organizationDiagnosticService,
  97.         AppUtils $appUtils,
  98.         OrganizationRepository $organizationRepository,
  99.         SerializerInterface $serializer,
  100.         KernelInterface $kernel,
  101.         Pdf $pdf,
  102.         Environment $twig
  103.     ) {
  104.         $this->em $em;
  105.         $this->documentUtils $documentUtils;
  106.         $this->organizationUtils $organizationUtils;
  107.         $this->invoiceUtils $invoiceUtils;
  108.         $this->legalRepresentativeUtils $legalRepresentativeUtils;
  109.         $this->yousignAPI $yousignAPI;
  110.         $this->documentFilesService $documentFilesService;
  111.         $this->params $params;
  112.         $this->encryptor $encryptor;
  113.         $this->router $router;
  114.         $this->session $session;
  115.         $this->translator $translator;
  116.         $this->segmentAPI $segmentAPI;
  117.         $this->organizationDiagnosticService $organizationDiagnosticService;
  118.         $this->appUtils $appUtils;
  119.         $this->organizationRepository $organizationRepository;
  120.         $this->serializer $serializer;
  121.         $this->kernel $kernel;
  122.         $this->pdf $pdf;
  123.         $this->twig $twig;
  124.     }
  125.     /**
  126.      * @Route("/{id}/get-dom-subscription", name="app_organization_get_dom_subscription", methods={"GET"})
  127.      */
  128.     public function getDomSubscription($id): JsonResponse
  129.     {
  130.         $organization $this->em->getRepository(Organization::class)->find($id);
  131.         if (!$organization instanceof Organization) {
  132.             return $this->json(['message' => 'Organization not found'], Response::HTTP_NOT_FOUND);
  133.         }
  134.         $data SubscriptionUtils::getDomSubscription($organization);
  135.         if (!$data instanceof Subscription) {
  136.             return $this->json(['message' => 'Subscription not found'], Response::HTTP_NOT_FOUND);
  137.         }
  138.         return $this->json($dataResponse::HTTP_OK);
  139.     }
  140.     /**
  141.      * @Route("/{id}/summary", name="app_organization_summary", methods={"GET"})
  142.      */
  143.     public function summary($idRequest $request)
  144.     {
  145.         $header $request->headers->get('Authorization');
  146.         $data explode(' '$header);
  147.         $token end($data);
  148.         $status $request->get('status');
  149.         if (!$token) {
  150.             return $this->json(['result' => 'Accès refusé'], Response::HTTP_FORBIDDEN);
  151.         }
  152.         $repository $this->em->getRepository(Organization::class);
  153.         /** @var Organization $organisation */
  154.         $organisation $repository->find($id);
  155.         if (!$organisation) {
  156.             return $this->json(['result' => 'Organization not found'], Response::HTTP_NOT_FOUND);
  157.         }
  158.         if (!$this->organizationUtils->checkPermission($organisation$token)) {
  159.             return $this->json(['result' => 'Accès refusé'], Response::HTTP_FORBIDDEN);
  160.         }
  161.         $result array_merge_recursive($organisation->getInvoices()->toArray(), $organisation->getQuotes()->toArray());
  162.         foreach ($result as $key => $data) {
  163.             /*
  164.              * Filter
  165.              */
  166.             if ($status && !in_array($data->getStatus(), $status)) {
  167.                 unset($result[$key]);
  168.                 continue;
  169.             }
  170.             if ($data instanceof Invoice) {
  171.                 $data->setType('Invoice');
  172.             } elseif ($data instanceof Quote) {
  173.                 $data->setType('Quote');
  174.             }
  175.             $result[$key] = $data;
  176.         }
  177.         $result array_values($result);
  178.         $this->invoiceUtils->sortByCreatedDate($result);
  179.         return $this->json($result);
  180.     }
  181.     /**
  182.      * @Route("/{id}/generate-link/{type}", name="app_generate_link_externe", methods={"GET"})
  183.      */
  184.     public function generateLinkYousign(int $idRequest $requeststring $type 'yousign'): JsonResponse
  185.     {
  186.         $repository $this->em->getRepository(Organization::class);
  187.         $organization $repository->find($id);
  188.         if (!$organization instanceof Organization) {
  189.             return $this->json(['result' => 'Organization not found'], Response::HTTP_NOT_FOUND);
  190.         }
  191.         if ('yousign' === $type) {
  192.             $document $this->organizationUtils->getContratDomiciliation($organization);
  193.             if (!$document) {
  194.                 return new JsonResponse(['error' => 'process_yousign.not_found'], Response::HTTP_NOT_FOUND);
  195.             }
  196.             $legalRepresentative $this->legalRepresentativeUtils->getFirstPhysicalRepresentative($organization);
  197.             if (!$legalRepresentative) {
  198.                 return new JsonResponse(['error' => 'lr.not_found'], Response::HTTP_NOT_FOUND);
  199.             }
  200.             if (!in_array($organization->getStatus(), [
  201.                 OrganizationStatusEnum::NEW,
  202.                 OrganizationStatusEnum::NEW_PAYMENT,
  203.                 OrganizationStatusEnum::DOCS_MISSING,
  204.                 OrganizationStatusEnum::DOCS_EXPIRED,
  205.                 OrganizationStatusEnum::OK,
  206.             ], true)) {
  207.                 return new JsonResponse(['error' => 'Organization status not allowed'], Response::HTTP_BAD_REQUEST);
  208.             }
  209.             $processYousign $organization->getProcessYousign();
  210.             if (!$processYousign) {
  211.                 return new JsonResponse(['error' => 'process_yousign.not_found'], Response::HTTP_NOT_FOUND);
  212.             }
  213.             $signatureRequestId $processYousign->getSignatureRequestId();
  214.             $signatureRequest $this->yousignAPI->getSignatureRequest($signatureRequestId);
  215.             if ('ongoing' === $signatureRequest['status']) {
  216.                 // update signer
  217.                 $signers $this->yousignAPI->getSigners($signatureRequestId);
  218.                 $signer $signers[1];
  219.                 if ('signed' === $signer['status']) {
  220.                     $urlAPI $this->router->generate('app_document_view', [
  221.                         'id' => $this->encryptor->encrypt($document->getId()),
  222.                     ]);
  223.                     $url $request->getSchemeAndHttpHost().$urlAPI;
  224.                     $url str_replace('http://''https://'$url);
  225.                     $header $request->headers->get('Authorization');
  226.                     $data explode(' '$header);
  227.                     $token end($data);
  228.                     $url "$url/$token";
  229.                     return $this->json(['linkContratDomiciliation' => $url]);
  230.                 }
  231.                 $signerData $this->yousignAPI->getSignerData($legalRepresentative);
  232.                 try {
  233.                     $signerRequest $this->yousignAPI
  234.                         ->updateSigner($signatureRequestId$signer['id'], ['info' => $signerData['info']]);
  235.                     if (!$this->yousignAPI->isResponseValid($signerRequest)) {
  236.                         $error json_decode($signerRequesttrue);
  237.                         if (isset($error['type']) && isset($error['invalid_params']) && is_array($error['invalid_params'])) {
  238.                             $errorMessage = [];
  239.                             foreach ($error['invalid_params'] as $invalidParam) {
  240.                                 $errorMessage[$invalidParam['name']] = $error['type'].'.'.str_replace(['['']'], ['.'''], $invalidParam['name']);
  241.                             }
  242.                             return new JsonResponse(['error' => array_values($errorMessage)], Response::HTTP_BAD_REQUEST);
  243.                         }
  244.                     }
  245.                     $document->setYousignLink($signerRequest['signature_link']);
  246.                 } catch (\Exception $e) {
  247.                     return new JsonResponse(
  248.                         ['error' => $e->getMessage()],
  249.                         $e->getCode() ?: Response::HTTP_INTERNAL_SERVER_ERROR
  250.                     );
  251.                 }
  252.                 return $this->json(['linkContratDomiciliation' => $document->getYousignLink()]);
  253.             }
  254.             $documentId $signatureRequest['documents'][0]['id'];
  255.             $path PathGenerator::generatePathForDocument($document);
  256.             // if status is draft, activate the signature request
  257.             if ('draft' === $signatureRequest['status']) {
  258.                 $newDocumentRequest $this->yousignAPI->replaceDocument(
  259.                     $signatureRequestId,
  260.                     $this->documentFilesService->read($path),
  261.                     $documentId
  262.                 );
  263.                 $processYousign->setLastUploadedFileAt(new \DateTime());
  264.                 $this->em->flush();
  265.                 $user $this->em->getRepository(User::class)->findOneBy(['email' => 'william@digidom.pro']);
  266.                 $signers = [];
  267.                 if ($user) {
  268.                     switch ($organization->getStatus()) {
  269.                         case OrganizationStatusEnum::NEW_PAYMENT:
  270.                             $status 'validation-client';
  271.                             break;
  272.                         case OrganizationStatusEnum::DOCS_MISSING:
  273.                             $status 'non-urgent-client';
  274.                             break;
  275.                         default:
  276.                             $status 'autres';
  277.                             break;
  278.                     }
  279.                     $redirectTo getenv('URL_NEW_ADMIN').'/kyc/'.$status;
  280.                     $signers[] = $this->yousignAPI->getSignerData($user, [
  281.                         'success' => $redirectTo,
  282.                         'error' => $redirectTo,
  283.                     ]);
  284.                 }
  285.                 $redirectToSuccess $this->params->get('uri_tunnel').'/contrat/'.$organization->getId().'?signed=true';
  286.                 $redirectToCancel $this->params->get('uri_tunnel').'/contrat/'.$organization->getId().'?signed=false';
  287.                 $signers[] = $this->yousignAPI->getSignerData($legalRepresentative, [
  288.                     'success' => $redirectToSuccess,
  289.                     'error' => $redirectToCancel,
  290.                 ]);
  291.                 foreach ($signers as $signerData) {
  292.                     $this->yousignAPI->addSigner($signatureRequestId$signerData);
  293.                 }
  294.                 if ($newDocumentRequest) {
  295.                     $processYousign->setExternalFileId($newDocumentRequest['id']);
  296.                     $this->em->flush();
  297.                 }
  298.                 $this->yousignAPI->activate($signatureRequestId);
  299.             }
  300.             $signers $this->yousignAPI->getSigners($signatureRequestId);
  301.             $signer $signers[1];
  302.             // get link to sign the document
  303.             $document->setYousignLink($signer['signature_link']);
  304.             $this->em->flush();
  305.             if ($document->getYousignLink()) {
  306.                 return $this->json(['linkContratDomiciliation' => $document->getYousignLink()]);
  307.             }
  308.             return $this->json(['message' => 'Domiciliation contract not found'], Response::HTTP_BAD_REQUEST);
  309.         } elseif ('gocardless' === $type) {
  310.             $linkGocardless null;
  311.             $sessionID null;
  312.             $source $request->get('source'); // 'TUNNEL' or 'DASHBOARD'
  313.             if (null === $source) {
  314.                 $source '';
  315.             }
  316.             if (null === $organization->getMandatID()) {
  317.                 $linkGocardless $this->organizationUtils->generateURLGocardLess($organization$source);
  318.             }
  319.             $params = [
  320.                 'linkGocardless' => $linkGocardless,
  321.                 'sessionID' => $sessionID,
  322.             ];
  323.             return $this->json($params);
  324.         }
  325.         return $this->json(['message' => 'Type not found'], Response::HTTP_NOT_FOUND);
  326.     }
  327.     /**
  328.      * @Route("/{organizationID}/doc-to-validate-number", name="app_organization_doc_to_validate_number", methods={"GET"})
  329.      */
  330.     public function docToValidateNumbers(string $organizationID): JsonResponse
  331.     {
  332.         /** @var ?Organization $organization */
  333.         $organization $this->em->getRepository(Organization::class)->find($organizationID);
  334.         $organizationDocs $organization && $organization->getDocuments() ? $organization->getDocuments() : [];
  335.         $topLegalRepresentatives null !== $organization $organization->getLegalRepresentatives() : [];
  336.         $legalRepresentativeDocs = [];
  337.         foreach ($topLegalRepresentatives as $legalRepresentative) {
  338.             $legalRepresentativeDocs[] = $this->documentUtils->getLegalRepresentativeWithChildrenDocuments($legalRepresentative);
  339.         }
  340.         $dispatchedLrDocs = [];
  341.         foreach ($legalRepresentativeDocs as $docs) {
  342.             foreach ($docs as $doc) {
  343.                 $dispatchedLrDocs[] = $doc;
  344.             }
  345.         }
  346.         $allDocs array_merge_recursive($organizationDocs$dispatchedLrDocs);
  347.         $toApproveDoc array_filter($allDocs, function ($document) {
  348.             if (DocumentStatusEnum::TO_APPROVE === $document->getStatus()) {
  349.                 return $document;
  350.             }
  351.         });
  352.         return new JsonResponse(count($toApproveDoc), Response::HTTP_OK);
  353.     }
  354.     /**
  355.      * @Route("/{id}/regenerate-certificate", name="app_organization_regenerate_certificate", methods={"GET"})
  356.      */
  357.     public function regenerateCertificateDomiciliation(Request $request$id): JsonResponse
  358.     {
  359.         /** @var ?Organization $organization */
  360.         $organization $this->em->getRepository(Organization::class)->find($id);
  361.         if (null !== $organization) {
  362.             try {
  363.                 $this->organizationUtils->generateDocs(
  364.                     $organization,
  365.                     false,
  366.                     [DocumentTypeOrganizationEnum::DOMICILIATION_CERTIFICATE]
  367.                 );
  368.                 $this->em->refresh($organization);
  369.                 foreach ($organization->getDocuments() as $document) {
  370.                     if (DocumentTypeOrganizationEnum::DOMICILIATION_CERTIFICATE === $document->getType()) {
  371.                         $urlAPI $this->router->generate(
  372.                             'app_document_view',
  373.                             ['id' => $this->encryptor->encrypt($document->getId())]
  374.                         );
  375.                         $url $request->getSchemeAndHttpHost().$urlAPI;
  376.                         $url str_replace('http://''https://'$url);
  377.                         return $this->json(['url' => $url]);
  378.                     }
  379.                 }
  380.                 return $this->json(['message' => 'Domiciliation certificate not found'], Response::HTTP_NOT_FOUND);
  381.             } catch (\Exception $e) {
  382.                 return $this->json(['message' => 'Error'], Response::HTTP_INTERNAL_SERVER_ERROR);
  383.             }
  384.         }
  385.         return $this->json(['message' => 'Organization not found'], Response::HTTP_NOT_FOUND);
  386.     }
  387.     /**
  388.      * @Route("/account-statement/{id}/download", requirements={"id"="\d+"}, name="app_organization_account_statement_download", methods={"GET"})
  389.      */
  390.     public function downloadAccountStatementForOrganization(Request $requeststring $id): PdfResponse
  391.     {
  392.         $organizationRepository $this->em->getRepository(Organization::class);
  393.         $startDate $request->query->get('startDate');
  394.         $endDate $request->query->get('endDate');
  395.         $startDate = !strtotime($startDate) ? date('Y-m-01') : $startDate;
  396.         $endDate = !strtotime($endDate) ? date('Y-m-t'strtotime('-6 months')) : $endDate;
  397.         $accountDataForTemplate $organizationRepository->getOrganizationAccountStatementQuery(
  398.             $startDate,
  399.             $endDate,
  400.             $id
  401.         );
  402.         $organization $organizationRepository->getOrganizationInformationForAccountStatement($id)[0] ?? null;
  403.         if ([] === $organization) {
  404.             throw $this->createNotFoundException('Organization not found');
  405.         }
  406.         $organization['CountryTranslation'] = PostalAddress::getCountryName($organization['addressCountry'] ?? 'FR');
  407.         $legalName $organization['legalName'] ?? '';
  408.         $publicDir $this->kernel->getProjectDir().'/public/';
  409.         $filename iconv('UTF-8''ASCII//TRANSLIT''Releve-de-compte-'.$legalName.'-'.$startDate.'&'.$endDate.'.pdf');
  410.         $toPay array_reduce($accountDataForTemplate, static function ($carry$item) {
  411.             return $carry + (float) $item['toPay'];
  412.         }, 0);
  413.         $paid array_reduce($accountDataForTemplate, static function ($carry$item) {
  414.             return $carry + (float) $item['paid'];
  415.         }, 0);
  416.         $twigData = [
  417.             'startDate' => $startDate,
  418.             'endDate' => $endDate,
  419.             'accountStatements' => $accountDataForTemplate,
  420.             'publicDir' => $publicDir,
  421.             'organization' => $organization,
  422.             'toPay' => number_format($toPay2),
  423.             'paid' => number_format($paid2),
  424.             'due' => number_format($toPay $paid2),
  425.         ];
  426.         try {
  427.             return new PdfResponse(
  428.                 $this->pdf->getOutputFromHtml(
  429.                     $this->twig->render('billing/account_statement.html.twig'$twigData)
  430.                 ),
  431.                 $filename
  432.             );
  433.         } catch (\Exception $e) {
  434.             throw $this->createNotFoundException('Error while generating PDF');
  435.         }
  436.     }
  437.     /**
  438.      * @Route("/postal-power/{id}/download", requirements={"id"="\d+"}, name="app_organization_postal_power_download", methods={"GET"})
  439.      */
  440.     public function downloadPostalPowerOfAttorney(Request $requeststring $id)
  441.     {
  442.         $siren $request->query->get('siren');
  443.         $companyName $request->query->get('companyName');
  444.         $storeStreetAddress $request->query->get('storeStreetAddress');
  445.         $companyPostalCode $request->query->get('companyPostalCode');
  446.         $lrName $request->query->get('lrName');
  447.         $lrQuality $request->query->get('lrQuality');
  448.         $missingParams $this->checkParamsForPostalAttorneyDownload($siren$companyName$storeStreetAddress$companyPostalCode$lrName$lrQuality);
  449.         if (!empty($missingParams)) {
  450.             $missingParamsList implode(', '$missingParams);
  451.             $message "Les paramètres suivants sont manquants : $missingParamsList";
  452.             return new JsonResponse(['message' => $message], Response::HTTP_BAD_REQUEST);
  453.         }
  454.         $digidomData = [
  455.             'siren' => $this->appUtils->stringToArray(self::DIGIDOM_SIREN14),
  456.             'companyName' => $this->appUtils->stringToArray(self::DIGIDOM_COMPANY_NAME38),
  457.             'storeStreetAddress' => $this->appUtils->stringToArray(self::DIGIDOM_STORE_STREET_ADDRESS38),
  458.             'companyPostalCode' => $this->appUtils->stringToArray(self::DIGIDOM_COMPANY_POSTAL_CODE38),
  459.         ];
  460.         $twigData = [
  461.             'siren' => $this->appUtils->stringToArray($siren14),
  462.             'companyName' => $this->appUtils->stringToArray($companyName38),
  463.             'storeStreetAddress' => $this->appUtils->stringToArray($storeStreetAddress38),
  464.             'companyPostalCode' => $this->appUtils->stringToArray($companyPostalCode38),
  465.             'lrData' => [
  466.                 'name' => $lrName,
  467.                 'quality' => $lrQuality,
  468.             ],
  469.             'digidomData' => $digidomData,
  470.         ];
  471.         $options = [
  472.             'orientation' => 'Landscape',
  473.             'margin-bottom' => '0',
  474.             'margin-top' => '0',
  475.             'margin-right' => '1',
  476.             'margin-left' => '1',
  477.         ];
  478.         try {
  479.             return new PdfResponse(
  480.                 $this->pdf->getOutputFromHtml(
  481.                     $this->twig->render('documents/annexes/procuration/procuration_postal.html.twig'$twigData),
  482.                     $options
  483.                 ),
  484.             );
  485.         } catch (\Exception $e) {
  486.             throw $this->createNotFoundException('Error while generating PDF');
  487.         }
  488.     }
  489.     private function checkParamsForPostalAttorneyDownload($siren$legalName$agency$postalCode$lrName$lrQuality): array
  490.     {
  491.         $requiredParams = [
  492.             'siren' => $siren,
  493.             'legalName' => $legalName,
  494.             'agency' => $agency,
  495.             'postalCode' => $postalCode,
  496.             'lrName' => $lrName,
  497.             'lrQuality' => $lrQuality,
  498.         ];
  499.         $missingParams = [];
  500.         foreach ($requiredParams as $paramName => $paramValue) {
  501.             if (null === $paramValue) {
  502.                 $missingParams[] = $paramName;
  503.             }
  504.         }
  505.         return $missingParams;
  506.     }
  507.     /**
  508.      * @param string $documentType
  509.      *
  510.      * @return JsonResponse
  511.      *
  512.      * @Route("/{id}/generate-status", name="app_generate_organization_doc_status", methods={"GET"})
  513.      */
  514.     public function generateStatusDocument($id)
  515.     {
  516.         /** @var Organization $organization */
  517.         $organization $this->em->getRepository(Organization::class)->find($id);
  518.         if ($organization && $this->documentUtils->checkGenerateStatus($organization)) {
  519.             $trans DocumentTypeOrganizationEnum::getReadableValue(DocumentTypeOrganizationEnum::STATUS);
  520.             $document = new Document();
  521.             $document
  522.                 ->setType(DocumentTypeOrganizationEnum::STATUS)
  523.                 ->setStatus(DocumentStatusEnum::APPROVED)
  524.                 ->setOrganization($organization)
  525.                 ->setName($this->translator->trans($trans));
  526.             $organization->addDocument($document);
  527.             $this->em->persist($organization);
  528.             $this->em->flush();
  529.             return $this->json(['message' => 'Document generated'], Response::HTTP_OK);
  530.         }
  531.         return $this->json(['message' => 'Organization not found'], Response::HTTP_BAD_REQUEST);
  532.     }
  533.     /**
  534.      * @Route("/{id}/regenerate", name="app_organization_regenerate_contrat", methods={"GET"})
  535.      */
  536.     public function regenerateContratDomiciliation($id): JsonResponse
  537.     {
  538.         /** @var Organization $organization */
  539.         $organization $this->em->getRepository(Organization::class)->find($id);
  540.         if (!$organization) {
  541.             return $this->json(['message' => 'Organization not found'], Response::HTTP_NOT_FOUND);
  542.         }
  543.         $processYousignRepo $this->em->getRepository(ProcessYousign::class);
  544.         // delete procedure yousign for the subscriber can regenerate the request signature
  545.         $processYousign $processYousignRepo->findOneBy(['organization' => $organization]);
  546.         // delete signature request
  547.         if ($processYousign) {
  548.             try {
  549.                 foreach ($processYousign->getSignatures() as $signature) {
  550.                     $this->em->remove($signature);
  551.                 }
  552.                 $this->em->remove($processYousign);
  553.                 $organization->setProcessYousign(null);
  554.                 $this->em->flush();
  555.             } catch (\Exception $e) {
  556.                 // nothing to do
  557.             }
  558.         }
  559.         try {
  560.             $document $this->organizationUtils->generateDocs(
  561.                 $organization,
  562.                 false,
  563.                 [DocumentTypeOrganizationEnum::DOMICILIATION_CONTRACT]
  564.             );
  565.             if ($document->getYousignError()) {
  566.                 return $this->json(['message' => explode('|'$document->getYousignError())], Response::HTTP_BAD_REQUEST);
  567.             }
  568.             return $this->json(['message' => 'Contrat regénéré']);
  569.         } catch (\Exception $e) {
  570.             return $this->json(['message' => 'Error'], Response::HTTP_INTERNAL_SERVER_ERROR);
  571.         }
  572.     }
  573.     /**
  574.      * @Route("/{id}/potential-case", name="app_organization_potential_case", methods={"GET"})
  575.      */
  576.     public function getOrganizationPotentialCase(string $id): JsonResponse
  577.     {
  578.         $potentialCase $this->em->getRepository(Organization::class)->getOrganizationPotentialCase($id);
  579.         if (null === $potentialCase[0]['id']) {
  580.             $potentialCase null;
  581.         }
  582.         return new JsonResponse($potentialCaseResponse::HTTP_OK);
  583.     }
  584.     /**
  585.      * @Route("/{id}/update-mandate", name="app_organization_update_mandate", methods={"GET"})
  586.      */
  587.     public function updateMandate($id)
  588.     {
  589.         $repository $this->em->getRepository(Organization::class);
  590.         /** @var Organization $organization */
  591.         $organization $repository->find($id);
  592.         if ($organization) {
  593.             $linkGocardless $this->organizationUtils->generateURLGocardLess($organization'DASHBOARD');
  594.             if ($linkGocardless) {
  595.                 $data = [
  596.                     'linkGocardless' => $linkGocardless,
  597.                     'sessionID' => $this->session->get('session_id'),
  598.                 ];
  599.                 return $this->json($dataResponse::HTTP_OK);
  600.             }
  601.             return $this->json(
  602.                 ['message' => 'Error gocardless'],
  603.                 Response::HTTP_INTERNAL_SERVER_ERROR
  604.             );
  605.         }
  606.         return $this->json(['message' => 'Organization not found'], Response::HTTP_NOT_FOUND);
  607.     }
  608.     /**
  609.      * @Route("/checked", name="app_organization_checked", methods={"GET"})
  610.      */
  611.     public function checkedLost()
  612.     {
  613.         /** @var OrganizationRepository $repository */
  614.         $repository $this->em->getRepository(Organization::class);
  615.         $aOrganizations $repository->getOrganizationWithStatus([OrganizationStatusEnum::NEW]);
  616.         $now time();
  617.         $expiration $now 30 86400;
  618.         $count 0;
  619.         /** @var Organization $organization */
  620.         foreach ($aOrganizations as $organization) {
  621.             $startingDate $organization->getDomiciliationStartDate();
  622.             if (null !== $startingDate) {
  623.                 $startingDate $startingDate->getTimestamp();
  624.             } elseif (null !== $organization->getCreatedAt()) {
  625.                 $startingDate $organization->getCreatedAt()->getTimestamp();
  626.             }
  627.             if ($expiration $startingDate
  628.                 && null !== $startingDate) {
  629.                 $organization->setStatus(OrganizationStatusEnum::LOST);
  630.                 $this->em->persist($organization);
  631.                 ++$count;
  632.             }
  633.         }
  634.         $this->em->flush();
  635.         return $this->json(['result' => 'success''count' => $count]);
  636.     }
  637.     /**
  638.      * @Route(
  639.      *     name="organization_document_to_check",
  640.      *     path="/{id}/documents_to_checked",
  641.      *     methods={"GET"},
  642.      *     defaults={"_api_item_operation_name"="get_document_to_checked"}
  643.      * )
  644.      */
  645.     public function documentsToCheck($id)
  646.     {
  647.         $repository $this->em->getRepository(Organization::class);
  648.         $organization $repository->find($id);
  649.         if (!$organization instanceof Organization) {
  650.             return $this->json([]);
  651.         }
  652.         $aDocuments $organization->getDocuments();
  653.         $aDocs = [];
  654.         foreach ($aDocuments as $document) {
  655.             if (DocumentStatusEnum::TO_APPROVE == $document->getStatus()) {
  656.                 $aDocs[] = $document;
  657.             }
  658.         }
  659.         if (null !== $organization->getLegalRepresentatives()) {
  660.             /** @var LegalRepresentative $legalRepresentative */
  661.             foreach ($organization->getLegalRepresentatives()->toArray() as $legalRepresentative) {
  662.                 /** @var Document $document */
  663.                 foreach ($legalRepresentative->getPerson()->getDocuments()->toArray() as $document) {
  664.                     if (DocumentStatusEnum::TO_APPROVE === $document->getStatus()) {
  665.                         $aDocs[] = $document;
  666.                     }
  667.                 }
  668.                 /*
  669.                  * Get document of parent where LegalRepresentative = LEGAL
  670.                  */
  671.                 if (null !== $legalRepresentative->getParent()) {
  672.                     /** @var Document $document */
  673.                     foreach ($legalRepresentative->getParent()->getPerson()->getDocuments()->toArray() as $document) {
  674.                         if (DocumentStatusEnum::TO_APPROVE === $document->getStatus()) {
  675.                             $aDocs[] = $document;
  676.                         }
  677.                     }
  678.                 }
  679.             }
  680.         }
  681.         return $this->json($aDocs);
  682.     }
  683.     /**
  684.      * @Route("/{id}/missing-documents", name="app_organization_missing_documents", methods={"GET"})
  685.      *
  686.      * @param EntityManagerInterface $em
  687.      *
  688.      * @return JsonResponse
  689.      */
  690.     public function getMissingDocuments(
  691.         $id,
  692.         OrganizationUtils $organizationUtils,
  693.         LegalRepresentativeUtils $legalRepresentativeUtils
  694.     ) {
  695.         $repository $this->em->getRepository(Organization::class);
  696.         /** @var Organization $organization */
  697.         $organization $repository->findOneBy(['id' => (int) $id]);
  698.         $missingDocuments = [];
  699.         if ($organization) {
  700.             foreach ($organization->getLegalRepresentatives() as $legalRepresentative) {
  701.                 $mandatoryDocuments $legalRepresentativeUtils->getMandatoryDocuments($legalRepresentative);
  702.                 foreach ($legalRepresentative->getPerson()->getDocuments() as $document) {
  703.                     if (DocumentStatusEnum::NOT_APPROVED != $document->getStatus()
  704.                         && isset($mandatoryDocuments[$document->getType()])) {
  705.                         unset($mandatoryDocuments[$document->getType()]);
  706.                     }
  707.                 }
  708.                 $missingDocuments['LR'][$legalRepresentative->getId()] = [
  709.                     'person' => [
  710.                         'id' => $legalRepresentative->getPerson()->getId(),
  711.                         'familyName' => $legalRepresentative->getPerson()->getFamilyName(),
  712.                         'givenName' => $legalRepresentative->getPerson()->getGivenName(),
  713.                         'legalName' => $legalRepresentative->getPerson()->getLegalName(),
  714.                         'type' => $legalRepresentative->getPerson()->getType(),
  715.                     ],
  716.                     'missingDocuments' => $mandatoryDocuments,
  717.                 ];
  718.             }
  719.             $mandatoryDocuments $organizationUtils->getMandatoryDocuments($organization);
  720.             foreach ($organization->getDocuments() as $document) {
  721.                 if (DocumentStatusEnum::NOT_APPROVED != $document->getStatus()
  722.                     && isset($mandatoryDocuments[$document->getType()])) {
  723.                     unset($mandatoryDocuments[$document->getType()]);
  724.                 }
  725.             }
  726.             $missingDocuments['Organization']['missingDocuments'] = $mandatoryDocuments;
  727.         }
  728.         return $this->json($missingDocuments);
  729.     }
  730.     /**
  731.      * @Route("/{id}/ordered-documents", name="app_organization_ordered_documents", methods={"GET"})
  732.      *
  733.      * @param EntityManagerInterface $em
  734.      *
  735.      * @return JsonResponse
  736.      */
  737.     public function getOrderedDocuments($id)
  738.     {
  739.         $repository $this->em->getRepository(Organization::class);
  740.         /** @var Organization $organization */
  741.         $organization $repository->findOneBy(['id' => (int) $id]);
  742.         if (!$organization) {
  743.             return $this->json(['error' => 'No organization found']);
  744.         }
  745.         $orgInvoices $organization->getInvoices()->filter(fn (Invoice $invoice) => InvoiceStatusEnum::DRAFT != $invoice->getStatus());
  746.         $orderedInvoices = [];
  747.         /** @var Invoice $invoice */
  748.         foreach ($orgInvoices as $invoice) {
  749.             $createdAt $invoice->getCreatedAt();
  750.             $url $this->generateUrl('app_invoice_view', [
  751.                 'id' => $this->encryptor->encrypt($invoice->getId()),
  752.             ]);
  753.             $orderedInvoices[$createdAt->format('Y')][$createdAt->format('m')][] = [
  754.                 'id' => $invoice->getId(),
  755.                 'createdAt' => $invoice->getCreatedAt(),
  756.                 'status' => $invoice->getStatus(),
  757.                 'path' => $url,
  758.                 'name' => $invoice->getName(),
  759.             ];
  760.         }
  761.         $orgLetters $organization->getLetters()->filter(fn (Letter $letter) => LetterTypeEnum::NOTICE != $letter->getType());
  762.         $isMailScanning SubscriptionUtils::hasAccessTo($organization->getSubscriptions(), ProductKeyEnum::NUMERISATION_COURRIER);
  763.         $orderedLetters = [];
  764.         $loopId 1;
  765.         /** @var Letter $letter */
  766.         foreach ($orgLetters as $letter) {
  767.             $createdAt $letter->getCreatedAt();
  768.             $urlRecto $this->generateUrl('app_letter_view', [
  769.                 'id' => $this->encryptor->encrypt($letter->getId()),
  770.                 'type' => 'recto',
  771.             ]);
  772.             $urlVerso $this->generateUrl('app_letter_view', [
  773.                 'id' => $this->encryptor->encrypt($letter->getId()),
  774.                 'type' => 'verso',
  775.             ]);
  776.             $urlContent $this->generateUrl('app_letter_view', [
  777.                 'id' => $this->encryptor->encrypt($letter->getId()),
  778.                 'type' => 'content',
  779.             ]);
  780.             if ($isMailScanning && null === $letter->getContentPathAWS()) {
  781.                 continue;
  782.             }
  783.             $orderedLetters[$createdAt->format('Y')][$createdAt->format('m')][] = [
  784.                 'id' => $letter->getId(),
  785.                 'createdAt' => $letter->getCreatedAt(),
  786.                 'status' => $letter->getStatus(),
  787.                 'path_recto' => $urlRecto,
  788.                 'path_verso' => $urlVerso,
  789.                 'path_content' => $urlContent,
  790.                 'name' => 'COURRIER-'.$loopId,
  791.             ];
  792.             ++$loopId;
  793.         }
  794.         $orgDocuments = [];
  795.         foreach ($organization->getDocuments() as $document) {
  796.             if (DocumentStatusEnum::APPROVED == $document->getStatus()) {
  797.                 $orgDocuments[] = $document;
  798.             }
  799.         }
  800.         $orderedOrgDocuments = [];
  801.         /** @var Document $document */
  802.         foreach ($orgDocuments as $document) {
  803.             $url $this->generateUrl('app_document_view', [
  804.                 'id' => $this->encryptor->encrypt($document->getId()),
  805.             ]);
  806.             $orderedOrgDocuments[] = [
  807.                 'id' => $document->getId(),
  808.                 'createdAt' => $document->getCreatedAt(),
  809.                 'status' => $document->getStatus(),
  810.                 'extension' => $document->getExtension(),
  811.                 'type' => $document->getType(),
  812.                 'path' => $url,
  813.                 'name' => $document->getName(),
  814.             ];
  815.         }
  816.         return $this->json([
  817.             'invoices' => $orderedInvoices,
  818.             'letters' => $orderedLetters,
  819.             'documents' => [
  820.                 'organization' => $orderedOrgDocuments,
  821.             ],
  822.         ]);
  823.     }
  824.     /**
  825.      * @Route("/{id}/prescribed", name="app_organization_prescribed", methods={"GET"})
  826.      *
  827.      * @return JsonResponse
  828.      */
  829.     public function getOrganizationPerscribed(Request $request$id)
  830.     {
  831.         $page $request->query->get('page');
  832.         $max $request->query->get('max-result');
  833.         $name $request->query->get('legal-name');
  834.         $isAuthorizePrescriber $request->query->get('authorize-prescriber');
  835.         if (null === $max) {
  836.             $max 30;
  837.         }
  838.         $repository $this->em->getRepository(Organization::class);
  839.         /** @var Organization $organizations */
  840.         $organizations $repository->getOrganizationPrescribed($id$page$max$name$isAuthorizePrescriber);
  841.         $data $organizations['data'];
  842.         $total $organizations['total'];
  843.         return $this->json(['data' => $data'total' => $total]);
  844.     }
  845.     /**
  846.      * @Route("/{id}/facturation", name="app_organization_prescribed_facturation", methods={"GET"})
  847.      *
  848.      * @return JsonResponse
  849.      */
  850.     public function getOrganizationPrecribedFacturation(Request $request$id)
  851.     {
  852.         $page $request->query->get('page');
  853.         $max $request->query->get('max-result');
  854.         $name $request->query->get('legal-name');
  855.         if (null === $max) {
  856.             $max 30;
  857.         }
  858.         $repository $this->em->getRepository(Organization::class);
  859.         /** @var Organization $organizations */
  860.         $organizations $repository->getPrescribedOrganizationId($id$name);
  861.         /** @var InvoiceRepository $invoiceRepository */
  862.         $invoiceRepository $this->em->getRepository(Invoice::class);
  863.         $quoteRepository $this->em->getRepository(Quote::class);
  864.         /** @var Invoice $invoices */
  865.         $invoices $invoiceRepository->getPrescribedInvoices($organizations$page$max);
  866.         /** @var Quote $quotes */
  867.         $quotes $quoteRepository->getPrescribedQuotes($organizations$page$max);
  868.         return $this->json([
  869.             'invoices' => $invoices['data'],
  870.             'quotes' => $quotes['data'],
  871.             'total_invoice' => $invoices['total'],
  872.             'total_quote' => $quotes['total'],
  873.         ]);
  874.     }
  875.     /**
  876.      * @Route("/{id}/letters", name="app_organization_letter", methods={"GET"})
  877.      *
  878.      * @return JsonResponse
  879.      */
  880.     public function getOrganizationLetters(Request $request$id)
  881.     {
  882.         $page $request->query->get('page');
  883.         $max $request->query->get('max-result');
  884.         $prescriberId = (int) $request->query->get('prescriber-id');
  885.         $data = [];
  886.         $total 0;
  887.         if (null === $max) {
  888.             $max 30;
  889.         }
  890.         if (null === $prescriberId) {
  891.             return $this->json([
  892.                 'message' => 'Letter not found',
  893.             ], Response::HTTP_NOT_FOUND);
  894.         }
  895.         $repository $this->em->getRepository(Organization::class);
  896.         /** @var Organization $organization */
  897.         $organization $repository->find($id);
  898.         if ($organization) {
  899.             if ($prescriberId !== $organization->getPrescriber()->getId()) {
  900.                 return $this->json([
  901.                     'message' => 'Letter not found',
  902.                 ], Response::HTTP_NOT_FOUND);
  903.             }
  904.             $letterRepository $this->em->getRepository(Letter::class);
  905.             /** @var Letter $letters */
  906.             $letters $letterRepository->getOrganizationLetters($id$page$max);
  907.             $data $letters['data'];
  908.             $total $letters['total'];
  909.         }
  910.         return $this->json(['data' => $data'total' => $total]);
  911.     }
  912.     /**
  913.      * @Route("/{id}/details", name="app_organization_details", methods={"GET"})
  914.      *
  915.      * @return JsonResponse
  916.      */
  917.     public function getOrganizationDetails(Request $request$id)
  918.     {
  919.         $prescriberId = (int) $request->query->get('prescriber-id');
  920.         $organizationDetails = [];
  921.         if (null === $prescriberId) {
  922.             return $this->json([
  923.                 'message' => 'Organization not found',
  924.             ], Response::HTTP_NOT_FOUND);
  925.         }
  926.         $repository $this->em->getRepository(Organization::class);
  927.         /** @var Organization $organization */
  928.         $organization $repository->find($id);
  929.         if ($organization && $organization->getPrescriber()) {
  930.             $organizationPrescriber $organization->getPrescriber();
  931.             if ($organizationPrescriber->getId() === $prescriberId) {
  932.                 $organizationDetails $organization;
  933.             } else {
  934.                 return $this->json([
  935.                     'message' => 'Organization not found',
  936.                 ], Response::HTTP_NOT_FOUND);
  937.             }
  938.         } else {
  939.             return $this->json([
  940.                 'message' => 'Organization not found',
  941.             ], Response::HTTP_NOT_FOUND);
  942.         }
  943.         return $this->json(['organization' => $organizationDetails]);
  944.     }
  945.     /**
  946.      * @Route("/{id}/balEmpty/{isEmpty}", name="app_organization_bal_empty", methods={"GET"})
  947.      *
  948.      * @return JsonResponse
  949.      */
  950.     public function setOrganizationEmptyBal(int $idbool $isEmpty)
  951.     {
  952.         $repository $this->em->getRepository(Organization::class);
  953.         /** @var Organization $organization */
  954.         $organization $repository->findOneBy(['id' => $id]);
  955.         if (!$organization) {
  956.             return $this->json(['error' => 'No organization found']);
  957.         }
  958.         $organization->setIsEmptybal($isEmpty);
  959.         $this->segmentAPI->trackNewLetterSignature(null$organization);
  960.         return $this->json(['message' => 'ok']);
  961.     }
  962.     /**
  963.      * @Route("/diagnostic/{id}", name="app_organization_diagnostic", methods={"GET"})
  964.      */
  965.     public function diagnosticOrganization(int $id): JsonResponse
  966.     {
  967.         $organization $this->em->getRepository(Organization::class)->find($id);
  968.         if (!$organization instanceof Organization) {
  969.             return $this->json(['error' => 'No organization found']);
  970.         }
  971.         return $this->json($this->organizationDiagnosticService->diagnosticOrganization($organization));
  972.     }
  973.     /**
  974.      * @Route("/filleul/{orgaId}", name="app_organization_filleul", methods={"GET"})
  975.      */
  976.     public function getFilleul(int $orgaIdOrganizationRepository $organizationRepository): JsonResponse
  977.     {
  978.         $encryptedParentId 'DIGIPAR'.$orgaId;
  979.         $allOrga $organizationRepository->findBy(['encryptedParentId' => $encryptedParentId]);
  980.         $aData = [];
  981.         foreach ($allOrga as $organization) {
  982.             $aData[] = [
  983.                 'id' => $organization->getId(),
  984.                 'legalName' => $organization->getLegalName(),
  985.                 'stores' => null !== $organization->getStore() ? $this->storeObject($organization->getStore()) : null,
  986.             ];
  987.         }
  988.         return new JsonResponse($aDataResponse::HTTP_OK);
  989.     }
  990.     private function storeObject($store): ?object
  991.     {
  992.         if ($store) {
  993.             return (object) [
  994.                 'id' => $store->getId(),
  995.                 'name' => $store->getName(),
  996.                 'postalAddress' => [
  997.                     'id' => $store->getPostalAddress()->getId(),
  998.                     'addressCountry' => $store->getPostalAddress()->getAddressCountry(),
  999.                     'addressLocality' => $store->getPostalAddress()->getAddressLocality(),
  1000.                     'addressRegion' => $store->getPostalAddress()->getAddressRegion(),
  1001.                     'postalCode' => $store->getPostalAddress()->getPostalCode(),
  1002.                     'streetAddress' => $store->getPostalAddress()->getStreetAddress(),
  1003.                 ],
  1004.             ];
  1005.         }
  1006.         return null;
  1007.     }
  1008.     /**
  1009.      * @Route("/with-same-name", name="app_organization_with_sameName", methods={"POST"})
  1010.      *
  1011.      * @throws ExceptionInterface
  1012.      */
  1013.     public function organizationWithSameName(Request $request): JsonResponse
  1014.     {
  1015.         $params json_decode($request->getContent() ?: '{}'true512JSON_THROW_ON_ERROR);
  1016.         $data $this->organizationRepository->getOrganizationWithSameName(null$params);
  1017.         return new JsonResponse(
  1018.             $this->serializer->normalize($data'jsonld', ['groups' => 'read_comparisonkyc']),
  1019.             Response::HTTP_OK
  1020.         );
  1021.     }
  1022. }