src/Controller/Api/OrganizationController.php line 210

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'])) {
  238.                             return new JsonResponse(['error' => $error['type']], Response::HTTP_BAD_REQUEST);
  239.                         }
  240.                     }
  241.                     $document->setYousignLink($signerRequest['signature_link']);
  242.                 } catch (\Exception $e) {
  243.                     return new JsonResponse(
  244.                         ['error' => $e->getMessage()],
  245.                         $e->getCode() ?: Response::HTTP_INTERNAL_SERVER_ERROR
  246.                     );
  247.                 }
  248.                 return $this->json(['linkContratDomiciliation' => $document->getYousignLink()]);
  249.             }
  250.             $documentId $signatureRequest['documents'][0]['id'];
  251.             $path PathGenerator::generatePathForDocument($document);
  252.             // if status is draft, activate the signature request
  253.             if ('draft' === $signatureRequest['status']) {
  254.                 $newDocumentRequest $this->yousignAPI->replaceDocument(
  255.                     $signatureRequestId,
  256.                     $this->documentFilesService->read($path),
  257.                     $documentId
  258.                 );
  259.                 $processYousign->setLastUploadedFileAt(new \DateTime());
  260.                 $this->em->flush();
  261.                 $user $this->em->getRepository(User::class)->findOneBy(['email' => 'william@digidom.pro']);
  262.                 $signers = [];
  263.                 if ($user) {
  264.                     switch ($organization->getStatus()) {
  265.                         case OrganizationStatusEnum::NEW_PAYMENT:
  266.                             $status 'validation-client';
  267.                             break;
  268.                         case OrganizationStatusEnum::DOCS_MISSING:
  269.                             $status 'non-urgent-client';
  270.                             break;
  271.                         default:
  272.                             $status 'autres';
  273.                             break;
  274.                     }
  275.                     $redirectTo getenv('URL_NEW_ADMIN').'/kyc/'.$status;
  276.                     $signers[] = $this->yousignAPI->getSignerData($user, [
  277.                         'success' => $redirectTo,
  278.                         'error' => $redirectTo,
  279.                     ]);
  280.                 }
  281.                 $redirectToSuccess $this->params->get('uri_tunnel').'/contrat/'.$organization->getId().'?signed=true';
  282.                 $redirectToCancel $this->params->get('uri_tunnel').'/contrat/'.$organization->getId().'?signed=false';
  283.                 $signers[] = $this->yousignAPI->getSignerData($legalRepresentative, [
  284.                     'success' => $redirectToSuccess,
  285.                     'error' => $redirectToCancel,
  286.                 ]);
  287.                 foreach ($signers as $signerData) {
  288.                     $this->yousignAPI->addSigner($signatureRequestId$signerData);
  289.                 }
  290.                 if ($newDocumentRequest) {
  291.                     $processYousign->setExternalFileId($newDocumentRequest['id']);
  292.                     $this->em->flush();
  293.                 }
  294.                 $this->yousignAPI->activate($signatureRequestId);
  295.             }
  296.             $signers $this->yousignAPI->getSigners($signatureRequestId);
  297.             $signer $signers[1];
  298.             // get link to sign the document
  299.             $document->setYousignLink($signer['signature_link']);
  300.             $this->em->flush();
  301.             if ($document->getYousignLink()) {
  302.                 return $this->json(['linkContratDomiciliation' => $document->getYousignLink()]);
  303.             }
  304.             return $this->json(['message' => 'Domiciliation contract not found'], Response::HTTP_BAD_REQUEST);
  305.         } elseif ('gocardless' === $type) {
  306.             $linkGocardless null;
  307.             $sessionID null;
  308.             $source $request->get('source'); // 'TUNNEL' or 'DASHBOARD'
  309.             if (null === $source) {
  310.                 $source '';
  311.             }
  312.             if (null === $organization->getMandatID()) {
  313.                 $linkGocardless $this->organizationUtils->generateURLGocardLess($organization$source);
  314.             }
  315.             $params = [
  316.                 'linkGocardless' => $linkGocardless,
  317.                 'sessionID' => $sessionID,
  318.             ];
  319.             return $this->json($params);
  320.         }
  321.         return $this->json(['message' => 'Type not found'], Response::HTTP_NOT_FOUND);
  322.     }
  323.     /**
  324.      * @Route("/{organizationID}/doc-to-validate-number", name="app_organization_doc_to_validate_number", methods={"GET"})
  325.      */
  326.     public function docToValidateNumbers(string $organizationID): JsonResponse
  327.     {
  328.         /** @var ?Organization $organization */
  329.         $organization $this->em->getRepository(Organization::class)->find($organizationID);
  330.         $organizationDocs $organization && $organization->getDocuments() ? $organization->getDocuments() : [];
  331.         $topLegalRepresentatives null !== $organization $organization->getLegalRepresentatives() : [];
  332.         $legalRepresentativeDocs = [];
  333.         foreach ($topLegalRepresentatives as $legalRepresentative) {
  334.             $legalRepresentativeDocs[] = $this->documentUtils->getLegalRepresentativeWithChildrenDocuments($legalRepresentative);
  335.         }
  336.         $dispatchedLrDocs = [];
  337.         foreach ($legalRepresentativeDocs as $docs) {
  338.             foreach ($docs as $doc) {
  339.                 $dispatchedLrDocs[] = $doc;
  340.             }
  341.         }
  342.         $allDocs array_merge_recursive($organizationDocs$dispatchedLrDocs);
  343.         $toApproveDoc array_filter($allDocs, function ($document) {
  344.             if (DocumentStatusEnum::TO_APPROVE === $document->getStatus()) {
  345.                 return $document;
  346.             }
  347.         });
  348.         return new JsonResponse(count($toApproveDoc), Response::HTTP_OK);
  349.     }
  350.     /**
  351.      * @Route("/{id}/regenerate-certificate", name="app_organization_regenerate_certificate", methods={"GET"})
  352.      */
  353.     public function regenerateCertificateDomiciliation(Request $request$id): JsonResponse
  354.     {
  355.         /** @var ?Organization $organization */
  356.         $organization $this->em->getRepository(Organization::class)->find($id);
  357.         if (null !== $organization) {
  358.             try {
  359.                 $this->organizationUtils->generateDocs(
  360.                     $organization,
  361.                     false,
  362.                     [DocumentTypeOrganizationEnum::DOMICILIATION_CERTIFICATE]
  363.                 );
  364.                 $this->em->refresh($organization);
  365.                 foreach ($organization->getDocuments() as $document) {
  366.                     if (DocumentTypeOrganizationEnum::DOMICILIATION_CERTIFICATE === $document->getType()) {
  367.                         $urlAPI $this->router->generate(
  368.                             'app_document_view',
  369.                             ['id' => $this->encryptor->encrypt($document->getId())]
  370.                         );
  371.                         $url $request->getSchemeAndHttpHost().$urlAPI;
  372.                         $url str_replace('http://''https://'$url);
  373.                         return $this->json(['url' => $url]);
  374.                     }
  375.                 }
  376.                 return $this->json(['message' => 'Domiciliation certificate not found'], Response::HTTP_NOT_FOUND);
  377.             } catch (\Exception $e) {
  378.                 return $this->json(['message' => 'Error'], Response::HTTP_INTERNAL_SERVER_ERROR);
  379.             }
  380.         }
  381.         return $this->json(['message' => 'Organization not found'], Response::HTTP_NOT_FOUND);
  382.     }
  383.     /**
  384.      * @Route("/account-statement/{id}/download", requirements={"id"="\d+"}, name="app_organization_account_statement_download", methods={"GET"})
  385.      */
  386.     public function downloadAccountStatementForOrganization(Request $requeststring $id): PdfResponse
  387.     {
  388.         $organizationRepository $this->em->getRepository(Organization::class);
  389.         $startDate $request->query->get('startDate');
  390.         $endDate $request->query->get('endDate');
  391.         $startDate = !strtotime($startDate) ? date('Y-m-01') : $startDate;
  392.         $endDate = !strtotime($endDate) ? date('Y-m-t'strtotime('-6 months')) : $endDate;
  393.         $accountDataForTemplate $organizationRepository->getOrganizationAccountStatementQuery(
  394.             $startDate,
  395.             $endDate,
  396.             $id
  397.         );
  398.         $organization $organizationRepository->getOrganizationInformationForAccountStatement($id)[0] ?? null;
  399.         if ([] === $organization) {
  400.             throw $this->createNotFoundException('Organization not found');
  401.         }
  402.         $organization['CountryTranslation'] = PostalAddress::getCountryName($organization['addressCountry'] ?? 'FR');
  403.         $legalName $organization['legalName'] ?? '';
  404.         $publicDir $this->kernel->getProjectDir().'/public/';
  405.         $filename iconv('UTF-8''ASCII//TRANSLIT''Releve-de-compte-'.$legalName.'-'.$startDate.'&'.$endDate.'.pdf');
  406.         $toPay array_reduce($accountDataForTemplate, static function ($carry$item) {
  407.             return $carry + (float) $item['toPay'];
  408.         }, 0);
  409.         $paid array_reduce($accountDataForTemplate, static function ($carry$item) {
  410.             return $carry + (float) $item['paid'];
  411.         }, 0);
  412.         $twigData = [
  413.             'startDate' => $startDate,
  414.             'endDate' => $endDate,
  415.             'accountStatements' => $accountDataForTemplate,
  416.             'publicDir' => $publicDir,
  417.             'organization' => $organization,
  418.             'toPay' => number_format($toPay2),
  419.             'paid' => number_format($paid2),
  420.             'due' => number_format($toPay $paid2),
  421.         ];
  422.         try {
  423.             return new PdfResponse(
  424.                 $this->pdf->getOutputFromHtml(
  425.                     $this->twig->render('billing/account_statement.html.twig'$twigData)
  426.                 ),
  427.                 $filename
  428.             );
  429.         } catch (\Exception $e) {
  430.             throw $this->createNotFoundException('Error while generating PDF');
  431.         }
  432.     }
  433.     /**
  434.      * @Route("/postal-power/{id}/download", requirements={"id"="\d+"}, name="app_organization_postal_power_download", methods={"GET"})
  435.      */
  436.     public function downloadPostalPowerOfAttorney(Request $requeststring $id)
  437.     {
  438.         $siren $request->query->get('siren');
  439.         $companyName $request->query->get('companyName');
  440.         $storeStreetAddress $request->query->get('storeStreetAddress');
  441.         $companyPostalCode $request->query->get('companyPostalCode');
  442.         $lrName $request->query->get('lrName');
  443.         $lrQuality $request->query->get('lrQuality');
  444.         $missingParams $this->checkParamsForPostalAttorneyDownload($siren$companyName$storeStreetAddress$companyPostalCode$lrName$lrQuality);
  445.         if (!empty($missingParams)) {
  446.             $missingParamsList implode(', '$missingParams);
  447.             $message "Les paramètres suivants sont manquants : $missingParamsList";
  448.             return new JsonResponse(['message' => $message], Response::HTTP_BAD_REQUEST);
  449.         }
  450.         $digidomData = [
  451.             'siren' => $this->appUtils->stringToArray(self::DIGIDOM_SIREN14),
  452.             'companyName' => $this->appUtils->stringToArray(self::DIGIDOM_COMPANY_NAME38),
  453.             'storeStreetAddress' => $this->appUtils->stringToArray(self::DIGIDOM_STORE_STREET_ADDRESS38),
  454.             'companyPostalCode' => $this->appUtils->stringToArray(self::DIGIDOM_COMPANY_POSTAL_CODE38),
  455.         ];
  456.         $twigData = [
  457.             'siren' => $this->appUtils->stringToArray($siren14),
  458.             'companyName' => $this->appUtils->stringToArray($companyName38),
  459.             'storeStreetAddress' => $this->appUtils->stringToArray($storeStreetAddress38),
  460.             'companyPostalCode' => $this->appUtils->stringToArray($companyPostalCode38),
  461.             'lrData' => [
  462.                 'name' => $lrName,
  463.                 'quality' => $lrQuality,
  464.             ],
  465.             'digidomData' => $digidomData,
  466.         ];
  467.         $options = [
  468.             'orientation' => 'Landscape',
  469.             'margin-bottom' => '0',
  470.             'margin-top' => '0',
  471.             'margin-right' => '1',
  472.             'margin-left' => '1',
  473.         ];
  474.         try {
  475.             return new PdfResponse(
  476.                 $this->pdf->getOutputFromHtml(
  477.                     $this->twig->render('documents/annexes/procuration/procuration_postal.html.twig'$twigData),
  478.                     $options
  479.                 ),
  480.             );
  481.         } catch (\Exception $e) {
  482.             throw $this->createNotFoundException('Error while generating PDF');
  483.         }
  484.     }
  485.     private function checkParamsForPostalAttorneyDownload($siren$legalName$agency$postalCode$lrName$lrQuality): array
  486.     {
  487.         $requiredParams = [
  488.             'siren' => $siren,
  489.             'legalName' => $legalName,
  490.             'agency' => $agency,
  491.             'postalCode' => $postalCode,
  492.             'lrName' => $lrName,
  493.             'lrQuality' => $lrQuality,
  494.         ];
  495.         $missingParams = [];
  496.         foreach ($requiredParams as $paramName => $paramValue) {
  497.             if (null === $paramValue) {
  498.                 $missingParams[] = $paramName;
  499.             }
  500.         }
  501.         return $missingParams;
  502.     }
  503.     /**
  504.      * @param string $documentType
  505.      *
  506.      * @return JsonResponse
  507.      *
  508.      * @Route("/{id}/generate-status", name="app_generate_organization_doc_status", methods={"GET"})
  509.      */
  510.     public function generateStatusDocument($id)
  511.     {
  512.         /** @var Organization $organization */
  513.         $organization $this->em->getRepository(Organization::class)->find($id);
  514.         if ($organization && $this->documentUtils->checkGenerateStatus($organization)) {
  515.             $trans DocumentTypeOrganizationEnum::getReadableValue(DocumentTypeOrganizationEnum::STATUS);
  516.             $document = new Document();
  517.             $document
  518.                 ->setType(DocumentTypeOrganizationEnum::STATUS)
  519.                 ->setStatus(DocumentStatusEnum::APPROVED)
  520.                 ->setOrganization($organization)
  521.                 ->setName($this->translator->trans($trans));
  522.             $organization->addDocument($document);
  523.             $this->em->persist($organization);
  524.             $this->em->flush();
  525.             return $this->json(['message' => 'Document generated'], Response::HTTP_OK);
  526.         }
  527.         return $this->json(['message' => 'Organization not found'], Response::HTTP_BAD_REQUEST);
  528.     }
  529.     /**
  530.      * @Route("/{id}/regenerate", name="app_organization_regenerate_contrat", methods={"GET"})
  531.      */
  532.     public function regenerateContratDomiciliation($id): JsonResponse
  533.     {
  534.         /** @var Organization $organization */
  535.         $organization $this->em->getRepository(Organization::class)->find($id);
  536.         if (!$organization) {
  537.             return $this->json(['message' => 'Organization not found'], Response::HTTP_NOT_FOUND);
  538.         }
  539.         $processYousignRepo $this->em->getRepository(ProcessYousign::class);
  540.         // delete procedure yousign for the subscriber can regenerate the request signature
  541.         $processYousign $processYousignRepo->findOneBy(['organization' => $organization]);
  542.         // delete signature request
  543.         if ($processYousign) {
  544.             try {
  545.                 foreach ($processYousign->getSignatures() as $signature) {
  546.                     $this->em->remove($signature);
  547.                 }
  548.                 $this->em->remove($processYousign);
  549.                 $organization->setProcessYousign(null);
  550.                 $this->em->flush();
  551.             } catch (\Exception $e) {
  552.                 // nothing to do
  553.             }
  554.         }
  555.         try {
  556.             $document $this->organizationUtils->generateDocs(
  557.                 $organization,
  558.                 false,
  559.                 [DocumentTypeOrganizationEnum::DOMICILIATION_CONTRACT]
  560.             );
  561.             if ($document->getYousignError()) {
  562.                 return $this->json(['message' => explode('|'$document->getYousignError())], Response::HTTP_BAD_REQUEST);
  563.             }
  564.             return $this->json(['message' => 'Contrat regénéré']);
  565.         } catch (\Exception $e) {
  566.             return $this->json(['message' => 'Error'], Response::HTTP_INTERNAL_SERVER_ERROR);
  567.         }
  568.     }
  569.     /**
  570.      * @Route("/{id}/potential-case", name="app_organization_potential_case", methods={"GET"})
  571.      */
  572.     public function getOrganizationPotentialCase(string $id): JsonResponse
  573.     {
  574.         $potentialCase $this->em->getRepository(Organization::class)->getOrganizationPotentialCase($id);
  575.         if (null === $potentialCase[0]['id']) {
  576.             $potentialCase null;
  577.         }
  578.         return new JsonResponse($potentialCaseResponse::HTTP_OK);
  579.     }
  580.     /**
  581.      * @Route("/{id}/update-mandate", name="app_organization_update_mandate", methods={"GET"})
  582.      */
  583.     public function updateMandate($id)
  584.     {
  585.         $repository $this->em->getRepository(Organization::class);
  586.         /** @var Organization $organization */
  587.         $organization $repository->find($id);
  588.         if ($organization) {
  589.             $linkGocardless $this->organizationUtils->generateURLGocardLess($organization'DASHBOARD');
  590.             if ($linkGocardless) {
  591.                 $data = [
  592.                     'linkGocardless' => $linkGocardless,
  593.                     'sessionID' => $this->session->get('session_id'),
  594.                 ];
  595.                 return $this->json($dataResponse::HTTP_OK);
  596.             }
  597.             return $this->json(
  598.                 ['message' => 'Error gocardless'],
  599.                 Response::HTTP_INTERNAL_SERVER_ERROR
  600.             );
  601.         }
  602.         return $this->json(['message' => 'Organization not found'], Response::HTTP_NOT_FOUND);
  603.     }
  604.     /**
  605.      * @Route("/checked", name="app_organization_checked", methods={"GET"})
  606.      */
  607.     public function checkedLost()
  608.     {
  609.         /** @var OrganizationRepository $repository */
  610.         $repository $this->em->getRepository(Organization::class);
  611.         $aOrganizations $repository->getOrganizationWithStatus([OrganizationStatusEnum::NEW]);
  612.         $now time();
  613.         $expiration $now 30 86400;
  614.         $count 0;
  615.         /** @var Organization $organization */
  616.         foreach ($aOrganizations as $organization) {
  617.             $startingDate $organization->getDomiciliationStartDate();
  618.             if (null !== $startingDate) {
  619.                 $startingDate $startingDate->getTimestamp();
  620.             } elseif (null !== $organization->getCreatedAt()) {
  621.                 $startingDate $organization->getCreatedAt()->getTimestamp();
  622.             }
  623.             if ($expiration $startingDate
  624.                 && null !== $startingDate) {
  625.                 $organization->setStatus(OrganizationStatusEnum::LOST);
  626.                 $this->em->persist($organization);
  627.                 ++$count;
  628.             }
  629.         }
  630.         $this->em->flush();
  631.         return $this->json(['result' => 'success''count' => $count]);
  632.     }
  633.     /**
  634.      * @Route(
  635.      *     name="organization_document_to_check",
  636.      *     path="/{id}/documents_to_checked",
  637.      *     methods={"GET"},
  638.      *     defaults={"_api_item_operation_name"="get_document_to_checked"}
  639.      * )
  640.      */
  641.     public function documentsToCheck($id)
  642.     {
  643.         $repository $this->em->getRepository(Organization::class);
  644.         $organization $repository->find($id);
  645.         if (!$organization instanceof Organization) {
  646.             return $this->json([]);
  647.         }
  648.         $aDocuments $organization->getDocuments();
  649.         $aDocs = [];
  650.         foreach ($aDocuments as $document) {
  651.             if (DocumentStatusEnum::TO_APPROVE == $document->getStatus()) {
  652.                 $aDocs[] = $document;
  653.             }
  654.         }
  655.         if (null !== $organization->getLegalRepresentatives()) {
  656.             /** @var LegalRepresentative $legalRepresentative */
  657.             foreach ($organization->getLegalRepresentatives()->toArray() as $legalRepresentative) {
  658.                 /** @var Document $document */
  659.                 foreach ($legalRepresentative->getPerson()->getDocuments()->toArray() as $document) {
  660.                     if (DocumentStatusEnum::TO_APPROVE === $document->getStatus()) {
  661.                         $aDocs[] = $document;
  662.                     }
  663.                 }
  664.                 /*
  665.                  * Get document of parent where LegalRepresentative = LEGAL
  666.                  */
  667.                 if (null !== $legalRepresentative->getParent()) {
  668.                     /** @var Document $document */
  669.                     foreach ($legalRepresentative->getParent()->getPerson()->getDocuments()->toArray() as $document) {
  670.                         if (DocumentStatusEnum::TO_APPROVE === $document->getStatus()) {
  671.                             $aDocs[] = $document;
  672.                         }
  673.                     }
  674.                 }
  675.             }
  676.         }
  677.         return $this->json($aDocs);
  678.     }
  679.     /**
  680.      * @Route("/{id}/missing-documents", name="app_organization_missing_documents", methods={"GET"})
  681.      *
  682.      * @param EntityManagerInterface $em
  683.      *
  684.      * @return JsonResponse
  685.      */
  686.     public function getMissingDocuments(
  687.         $id,
  688.         OrganizationUtils $organizationUtils,
  689.         LegalRepresentativeUtils $legalRepresentativeUtils
  690.     ) {
  691.         $repository $this->em->getRepository(Organization::class);
  692.         /** @var Organization $organization */
  693.         $organization $repository->findOneBy(['id' => (int) $id]);
  694.         $missingDocuments = [];
  695.         if ($organization) {
  696.             foreach ($organization->getLegalRepresentatives() as $legalRepresentative) {
  697.                 $mandatoryDocuments $legalRepresentativeUtils->getMandatoryDocuments($legalRepresentative);
  698.                 foreach ($legalRepresentative->getPerson()->getDocuments() as $document) {
  699.                     if (DocumentStatusEnum::NOT_APPROVED != $document->getStatus()
  700.                         && isset($mandatoryDocuments[$document->getType()])) {
  701.                         unset($mandatoryDocuments[$document->getType()]);
  702.                     }
  703.                 }
  704.                 $missingDocuments['LR'][$legalRepresentative->getId()] = [
  705.                     'person' => [
  706.                         'id' => $legalRepresentative->getPerson()->getId(),
  707.                         'familyName' => $legalRepresentative->getPerson()->getFamilyName(),
  708.                         'givenName' => $legalRepresentative->getPerson()->getGivenName(),
  709.                         'legalName' => $legalRepresentative->getPerson()->getLegalName(),
  710.                         'type' => $legalRepresentative->getPerson()->getType(),
  711.                     ],
  712.                     'missingDocuments' => $mandatoryDocuments,
  713.                 ];
  714.             }
  715.             $mandatoryDocuments $organizationUtils->getMandatoryDocuments($organization);
  716.             foreach ($organization->getDocuments() as $document) {
  717.                 if (DocumentStatusEnum::NOT_APPROVED != $document->getStatus()
  718.                     && isset($mandatoryDocuments[$document->getType()])) {
  719.                     unset($mandatoryDocuments[$document->getType()]);
  720.                 }
  721.             }
  722.             $missingDocuments['Organization']['missingDocuments'] = $mandatoryDocuments;
  723.         }
  724.         return $this->json($missingDocuments);
  725.     }
  726.     /**
  727.      * @Route("/{id}/ordered-documents", name="app_organization_ordered_documents", methods={"GET"})
  728.      *
  729.      * @param EntityManagerInterface $em
  730.      *
  731.      * @return JsonResponse
  732.      */
  733.     public function getOrderedDocuments($id)
  734.     {
  735.         $repository $this->em->getRepository(Organization::class);
  736.         /** @var Organization $organization */
  737.         $organization $repository->findOneBy(['id' => (int) $id]);
  738.         if (!$organization) {
  739.             return $this->json(['error' => 'No organization found']);
  740.         }
  741.         $orgInvoices $organization->getInvoices()->filter(fn (Invoice $invoice) => InvoiceStatusEnum::DRAFT != $invoice->getStatus());
  742.         $orderedInvoices = [];
  743.         /** @var Invoice $invoice */
  744.         foreach ($orgInvoices as $invoice) {
  745.             $createdAt $invoice->getCreatedAt();
  746.             $url $this->generateUrl('app_invoice_view', [
  747.                 'id' => $this->encryptor->encrypt($invoice->getId()),
  748.             ]);
  749.             $orderedInvoices[$createdAt->format('Y')][$createdAt->format('m')][] = [
  750.                 'id' => $invoice->getId(),
  751.                 'createdAt' => $invoice->getCreatedAt(),
  752.                 'status' => $invoice->getStatus(),
  753.                 'path' => $url,
  754.                 'name' => $invoice->getName(),
  755.             ];
  756.         }
  757.         $orgLetters $organization->getLetters()->filter(fn (Letter $letter) => LetterTypeEnum::NOTICE != $letter->getType());
  758.         $isMailScanning SubscriptionUtils::hasAccessTo($organization->getSubscriptions(), ProductKeyEnum::NUMERISATION_COURRIER);
  759.         $orderedLetters = [];
  760.         $loopId 1;
  761.         /** @var Letter $letter */
  762.         foreach ($orgLetters as $letter) {
  763.             $createdAt $letter->getCreatedAt();
  764.             $urlRecto $this->generateUrl('app_letter_view', [
  765.                 'id' => $this->encryptor->encrypt($letter->getId()),
  766.                 'type' => 'recto',
  767.             ]);
  768.             $urlVerso $this->generateUrl('app_letter_view', [
  769.                 'id' => $this->encryptor->encrypt($letter->getId()),
  770.                 'type' => 'verso',
  771.             ]);
  772.             $urlContent $this->generateUrl('app_letter_view', [
  773.                 'id' => $this->encryptor->encrypt($letter->getId()),
  774.                 'type' => 'content',
  775.             ]);
  776.             if ($isMailScanning && null === $letter->getContentPathAWS()) {
  777.                 continue;
  778.             }
  779.             $orderedLetters[$createdAt->format('Y')][$createdAt->format('m')][] = [
  780.                 'id' => $letter->getId(),
  781.                 'createdAt' => $letter->getCreatedAt(),
  782.                 'status' => $letter->getStatus(),
  783.                 'path_recto' => $urlRecto,
  784.                 'path_verso' => $urlVerso,
  785.                 'path_content' => $urlContent,
  786.                 'name' => 'COURRIER-'.$loopId,
  787.             ];
  788.             ++$loopId;
  789.         }
  790.         $orgDocuments = [];
  791.         foreach ($organization->getDocuments() as $document) {
  792.             if (DocumentStatusEnum::APPROVED == $document->getStatus()) {
  793.                 $orgDocuments[] = $document;
  794.             }
  795.         }
  796.         $orderedOrgDocuments = [];
  797.         /** @var Document $document */
  798.         foreach ($orgDocuments as $document) {
  799.             $url $this->generateUrl('app_document_view', [
  800.                 'id' => $this->encryptor->encrypt($document->getId()),
  801.             ]);
  802.             $orderedOrgDocuments[] = [
  803.                 'id' => $document->getId(),
  804.                 'createdAt' => $document->getCreatedAt(),
  805.                 'status' => $document->getStatus(),
  806.                 'extension' => $document->getExtension(),
  807.                 'type' => $document->getType(),
  808.                 'path' => $url,
  809.                 'name' => $document->getName(),
  810.             ];
  811.         }
  812.         return $this->json([
  813.             'invoices' => $orderedInvoices,
  814.             'letters' => $orderedLetters,
  815.             'documents' => [
  816.                 'organization' => $orderedOrgDocuments,
  817.             ],
  818.         ]);
  819.     }
  820.     /**
  821.      * @Route("/{id}/prescribed", name="app_organization_prescribed", methods={"GET"})
  822.      *
  823.      * @return JsonResponse
  824.      */
  825.     public function getOrganizationPerscribed(Request $request$id)
  826.     {
  827.         $page $request->query->get('page');
  828.         $max $request->query->get('max-result');
  829.         $name $request->query->get('legal-name');
  830.         $isAuthorizePrescriber $request->query->get('authorize-prescriber');
  831.         if (null === $max) {
  832.             $max 30;
  833.         }
  834.         $repository $this->em->getRepository(Organization::class);
  835.         /** @var Organization $organizations */
  836.         $organizations $repository->getOrganizationPrescribed($id$page$max$name$isAuthorizePrescriber);
  837.         $data $organizations['data'];
  838.         $total $organizations['total'];
  839.         return $this->json(['data' => $data'total' => $total]);
  840.     }
  841.     /**
  842.      * @Route("/{id}/facturation", name="app_organization_prescribed_facturation", methods={"GET"})
  843.      *
  844.      * @return JsonResponse
  845.      */
  846.     public function getOrganizationPrecribedFacturation(Request $request$id)
  847.     {
  848.         $page $request->query->get('page');
  849.         $max $request->query->get('max-result');
  850.         $name $request->query->get('legal-name');
  851.         if (null === $max) {
  852.             $max 30;
  853.         }
  854.         $repository $this->em->getRepository(Organization::class);
  855.         /** @var Organization $organizations */
  856.         $organizations $repository->getPrescribedOrganizationId($id$name);
  857.         /** @var InvoiceRepository $invoiceRepository */
  858.         $invoiceRepository $this->em->getRepository(Invoice::class);
  859.         $quoteRepository $this->em->getRepository(Quote::class);
  860.         /** @var Invoice $invoices */
  861.         $invoices $invoiceRepository->getPrescribedInvoices($organizations$page$max);
  862.         /** @var Quote $quotes */
  863.         $quotes $quoteRepository->getPrescribedQuotes($organizations$page$max);
  864.         return $this->json([
  865.             'invoices' => $invoices['data'],
  866.             'quotes' => $quotes['data'],
  867.             'total_invoice' => $invoices['total'],
  868.             'total_quote' => $quotes['total'],
  869.         ]);
  870.     }
  871.     /**
  872.      * @Route("/{id}/letters", name="app_organization_letter", methods={"GET"})
  873.      *
  874.      * @return JsonResponse
  875.      */
  876.     public function getOrganizationLetters(Request $request$id)
  877.     {
  878.         $page $request->query->get('page');
  879.         $max $request->query->get('max-result');
  880.         $prescriberId = (int) $request->query->get('prescriber-id');
  881.         $data = [];
  882.         $total 0;
  883.         if (null === $max) {
  884.             $max 30;
  885.         }
  886.         if (null === $prescriberId) {
  887.             return $this->json([
  888.                 'message' => 'Letter not found',
  889.             ], Response::HTTP_NOT_FOUND);
  890.         }
  891.         $repository $this->em->getRepository(Organization::class);
  892.         /** @var Organization $organization */
  893.         $organization $repository->find($id);
  894.         if ($organization) {
  895.             if ($prescriberId !== $organization->getPrescriber()->getId()) {
  896.                 return $this->json([
  897.                     'message' => 'Letter not found',
  898.                 ], Response::HTTP_NOT_FOUND);
  899.             }
  900.             $letterRepository $this->em->getRepository(Letter::class);
  901.             /** @var Letter $letters */
  902.             $letters $letterRepository->getOrganizationLetters($id$page$max);
  903.             $data $letters['data'];
  904.             $total $letters['total'];
  905.         }
  906.         return $this->json(['data' => $data'total' => $total]);
  907.     }
  908.     /**
  909.      * @Route("/{id}/details", name="app_organization_details", methods={"GET"})
  910.      *
  911.      * @return JsonResponse
  912.      */
  913.     public function getOrganizationDetails(Request $request$id)
  914.     {
  915.         $prescriberId = (int) $request->query->get('prescriber-id');
  916.         $organizationDetails = [];
  917.         if (null === $prescriberId) {
  918.             return $this->json([
  919.                 'message' => 'Organization not found',
  920.             ], Response::HTTP_NOT_FOUND);
  921.         }
  922.         $repository $this->em->getRepository(Organization::class);
  923.         /** @var Organization $organization */
  924.         $organization $repository->find($id);
  925.         if ($organization && $organization->getPrescriber()) {
  926.             $organizationPrescriber $organization->getPrescriber();
  927.             if ($organizationPrescriber->getId() === $prescriberId) {
  928.                 $organizationDetails $organization;
  929.             } else {
  930.                 return $this->json([
  931.                     'message' => 'Organization not found',
  932.                 ], Response::HTTP_NOT_FOUND);
  933.             }
  934.         } else {
  935.             return $this->json([
  936.                 'message' => 'Organization not found',
  937.             ], Response::HTTP_NOT_FOUND);
  938.         }
  939.         return $this->json(['organization' => $organizationDetails]);
  940.     }
  941.     /**
  942.      * @Route("/{id}/balEmpty/{isEmpty}", name="app_organization_bal_empty", methods={"GET"})
  943.      *
  944.      * @return JsonResponse
  945.      */
  946.     public function setOrganizationEmptyBal(int $idbool $isEmpty)
  947.     {
  948.         $repository $this->em->getRepository(Organization::class);
  949.         /** @var Organization $organization */
  950.         $organization $repository->findOneBy(['id' => $id]);
  951.         if (!$organization) {
  952.             return $this->json(['error' => 'No organization found']);
  953.         }
  954.         $organization->setIsEmptybal($isEmpty);
  955.         $this->segmentAPI->trackNewLetterSignature(null$organization);
  956.         return $this->json(['message' => 'ok']);
  957.     }
  958.     /**
  959.      * @Route("/diagnostic/{id}", name="app_organization_diagnostic", methods={"GET"})
  960.      */
  961.     public function diagnosticOrganization(int $id): JsonResponse
  962.     {
  963.         $organization $this->em->getRepository(Organization::class)->find($id);
  964.         if (!$organization instanceof Organization) {
  965.             return $this->json(['error' => 'No organization found']);
  966.         }
  967.         return $this->json($this->organizationDiagnosticService->diagnosticOrganization($organization));
  968.     }
  969.     /**
  970.      * @Route("/filleul/{orgaId}", name="app_organization_filleul", methods={"GET"})
  971.      */
  972.     public function getFilleul(int $orgaIdOrganizationRepository $organizationRepository): JsonResponse
  973.     {
  974.         $encryptedParentId 'DIGIPAR'.$orgaId;
  975.         $allOrga $organizationRepository->findBy(['encryptedParentId' => $encryptedParentId]);
  976.         $aData = [];
  977.         foreach ($allOrga as $organization) {
  978.             $aData[] = [
  979.                 'id' => $organization->getId(),
  980.                 'legalName' => $organization->getLegalName(),
  981.                 'stores' => null !== $organization->getStore() ? $this->storeObject($organization->getStore()) : null,
  982.             ];
  983.         }
  984.         return new JsonResponse($aDataResponse::HTTP_OK);
  985.     }
  986.     private function storeObject($store): ?object
  987.     {
  988.         if ($store) {
  989.             return (object) [
  990.                 'id' => $store->getId(),
  991.                 'name' => $store->getName(),
  992.                 'postalAddress' => [
  993.                     'id' => $store->getPostalAddress()->getId(),
  994.                     'addressCountry' => $store->getPostalAddress()->getAddressCountry(),
  995.                     'addressLocality' => $store->getPostalAddress()->getAddressLocality(),
  996.                     'addressRegion' => $store->getPostalAddress()->getAddressRegion(),
  997.                     'postalCode' => $store->getPostalAddress()->getPostalCode(),
  998.                     'streetAddress' => $store->getPostalAddress()->getStreetAddress(),
  999.                 ],
  1000.             ];
  1001.         }
  1002.         return null;
  1003.     }
  1004.     /**
  1005.      * @Route("/with-same-name", name="app_organization_with_sameName", methods={"POST"})
  1006.      *
  1007.      * @throws ExceptionInterface
  1008.      */
  1009.     public function organizationWithSameName(Request $request): JsonResponse
  1010.     {
  1011.         $params json_decode($request->getContent() ?: '{}'true512JSON_THROW_ON_ERROR);
  1012.         $data $this->organizationRepository->getOrganizationWithSameName(null$params);
  1013.         return new JsonResponse(
  1014.             $this->serializer->normalize($data'jsonld', ['groups' => 'read_comparisonkyc']),
  1015.             Response::HTTP_OK
  1016.         );
  1017.     }
  1018. }