OrganizationFactory.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. <?php
  2. namespace App\Service\Organization;
  3. use App\ApiResources\Organization\OrganizationCreationRequest;
  4. use App\ApiResources\Organization\OrganizationMemberCreationRequest;
  5. use App\Entity\Access\Access;
  6. use App\Entity\Core\AddressPostal;
  7. use App\Entity\Core\ContactPoint;
  8. use App\Entity\Education\Cycle;
  9. use App\Entity\Network\NetworkOrganization;
  10. use App\Entity\Organization\Organization;
  11. use App\Entity\Organization\OrganizationAddressPostal;
  12. use App\Entity\Organization\Parameters;
  13. use App\Entity\Organization\Settings;
  14. use App\Entity\Organization\Subdomain;
  15. use App\Entity\Person\Person;
  16. use App\Entity\Person\PersonAddressPostal;
  17. use App\Enum\Core\ContactPointTypeEnum;
  18. use App\Enum\Education\CycleEnum;
  19. use App\Enum\Network\NetworkEnum;
  20. use App\Enum\Organization\AddressPostalOrganizationTypeEnum;
  21. use App\Enum\Organization\SettingsProductEnum;
  22. use App\Enum\Person\AddressPostalPersonTypeEnum;
  23. use App\Repository\Core\CountryRepository;
  24. use App\Repository\Organization\OrganizationIdentificationRepository;
  25. use App\Repository\Organization\OrganizationRepository;
  26. use App\Repository\Person\PersonRepository;
  27. use App\Service\ApiLegacy\ApiLegacyRequestService;
  28. use App\Service\Dolibarr\DolibarrApiService;
  29. use App\Service\Organization\Utils as OrganizationUtils;
  30. use App\Service\Typo3\BindFileService;
  31. use App\Service\Typo3\SubdomainService;
  32. use App\Service\Typo3\Typo3Service;
  33. use App\Service\Utils\DatesUtils;
  34. use Doctrine\ORM\EntityManagerInterface;
  35. use Elastica\Param;
  36. use libphonenumber\NumberParseException;
  37. use libphonenumber\PhoneNumberUtil;
  38. use Psr\Log\LoggerInterface;
  39. use Symfony\Component\HttpFoundation\Response;
  40. use Symfony\Component\String\ByteString;
  41. use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
  42. use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
  43. use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
  44. use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
  45. use Symfony\Contracts\Service\Attribute\Required;
  46. class OrganizationFactory
  47. {
  48. private LoggerInterface $logger;
  49. protected PhoneNumberUtil $phoneNumberUtil;
  50. public function __construct(
  51. private readonly SubdomainService $subdomainService,
  52. private readonly OrganizationRepository $organizationRepository,
  53. private readonly CountryRepository $countryRepository,
  54. private readonly OrganizationUtils $organizationUtils,
  55. private readonly Typo3Service $typo3Service,
  56. private readonly DolibarrApiService $dolibarrApiService,
  57. private readonly EntityManagerInterface $entityManager,
  58. private readonly PersonRepository $personRepository,
  59. private readonly BindFileService $bindFileService,
  60. private readonly OrganizationIdentificationRepository $organizationIdentificationRepository,
  61. private readonly ApiLegacyRequestService $apiLegacyRequestService,
  62. ) {
  63. $this->phoneNumberUtil = PhoneNumberUtil::getInstance();
  64. }
  65. #[Required]
  66. /** @see https://symfony.com/doc/current/logging/channels_handlers.html#how-to-autowire-logger-channels */
  67. public function setLoggerInterface(LoggerInterface $adminLogger): void
  68. {
  69. $this->logger = $adminLogger;
  70. }
  71. /**
  72. * Créé une nouvelle organisation à partir des données contenues dans une OrganizationCreationRequest.
  73. *
  74. * @throws TransportExceptionInterface
  75. * @throws \Throwable
  76. */
  77. public function create(OrganizationCreationRequest $organizationCreationRequest): Organization
  78. {
  79. $this->logger->info(
  80. "Start the creation of a new organization named '".$organizationCreationRequest->getName()."'"
  81. );
  82. $this->entityManager->beginTransaction();
  83. try {
  84. // On vérifie si cette organisation n'existe pas déjà
  85. $this->interruptIfOrganizationExists($organizationCreationRequest);
  86. // On vérifie la validité et la disponibilité du sous domaine
  87. $this->validateSubdomain($organizationCreationRequest->getSubdomain());
  88. $this->logger->info("Subdomain is valid and available : '".$organizationCreationRequest->getSubdomain()."'");
  89. // On construit l'organisation et ses relations
  90. $organization = $this->makeOrganizationWithRelations($organizationCreationRequest);
  91. $this->logger->info('Organization created with all its relations');
  92. // On persiste et on commit, les objets liés seront persistés en cascade
  93. $this->entityManager->persist($organization);
  94. $this->entityManager->flush();
  95. $this->entityManager->commit();
  96. $this->logger->debug(' - New entities committed in DB');
  97. $this->logger->info('Organization persisted in the DB');
  98. } catch (\Throwable $e) {
  99. $this->logger->critical("An error happened, operation cancelled\n".$e);
  100. $this->entityManager->rollback();
  101. throw $e;
  102. }
  103. $withError = false;
  104. // Création de la société Dolibarr
  105. try {
  106. $dolibarrId = $this->dolibarrApiService->createSociety(
  107. $organization,
  108. $organizationCreationRequest->isClient()
  109. );
  110. $this->logger->info('New dolibarr structure created (uid : '.$dolibarrId.')');
  111. } catch (\Throwable $e) {
  112. $this->logger->critical('An error happened while creating the dolibarr society, please proceed manually.');
  113. $this->logger->debug($e);
  114. $withError = true;
  115. }
  116. // Register the subdomain into the BindFile (takes up to 5min to take effect)
  117. try {
  118. $this->bindFileService->registerSubdomain($organizationCreationRequest->getSubdomain());
  119. $this->logger->info('Subdomain registered');
  120. } catch (\Throwable $e) {
  121. $this->logger->critical('An error happened while updating the bind file, please proceed manually.');
  122. $this->logger->debug($e);
  123. $withError = true;
  124. }
  125. // Création du site typo3 (on est obligé d'attendre que l'organisation soit persistée en base)
  126. if ($organizationCreationRequest->getCreateWebsite()) {
  127. try {
  128. $rootUid = $this->createTypo3Website($organization);
  129. $this->logger->info('Typo3 website created (root uid: '.$rootUid.')');
  130. } catch (\Throwable $e) {
  131. $this->logger->critical('An error happened while creating the typo3 website, please proceed manually.');
  132. $this->logger->debug($e);
  133. $withError = true;
  134. }
  135. } else {
  136. $this->logger->warning('Typo3 website creation was not required');
  137. }
  138. // Création de l'organisation dans la base adminassos (géré par la V1)
  139. try {
  140. $this->updateAdminassosDb($organization);
  141. $this->logger->info('Adminassos db updated');
  142. } catch (\Throwable $e) {
  143. $this->logger->critical('An error happened while updating the adminassos db, please proceed manually.');
  144. $this->logger->debug($e);
  145. $withError = true;
  146. }
  147. if ($withError) {
  148. $organizationCreationRequest->setStatus(OrganizationCreationRequest::STATUS_OK_WITH_ERRORS);
  149. $this->logger->warning('-- Operation ended with errors, check the logs for more information --');
  150. } else {
  151. $organizationCreationRequest->setStatus(OrganizationCreationRequest::STATUS_OK);
  152. }
  153. return $organization;
  154. }
  155. /**
  156. * Lève une exception si cette organisation existe déjà.
  157. */
  158. protected function interruptIfOrganizationExists(OrganizationCreationRequest $organizationCreationRequest): void
  159. {
  160. if (
  161. $organizationCreationRequest->getSiretNumber()
  162. && $this->organizationIdentificationRepository->findOneBy(
  163. ['siretNumber' => $organizationCreationRequest->getSiretNumber()]
  164. )
  165. ) {
  166. throw new \RuntimeException("This siret number is already registered : '".$organizationCreationRequest->getSiretNumber()."'");
  167. }
  168. if (
  169. $organizationCreationRequest->getWaldecNumber()
  170. && $this->organizationIdentificationRepository->findOneBy(
  171. ['waldecNumber' => $organizationCreationRequest->getWaldecNumber()]
  172. )
  173. ) {
  174. throw new \RuntimeException("This RNA identifier (waldec number) is already registered : '".$organizationCreationRequest->getWaldecNumber()."'");
  175. }
  176. if (
  177. $organizationCreationRequest->getIdentifier()
  178. && $this->organizationIdentificationRepository->findOneBy(
  179. ['identifier' => $organizationCreationRequest->getIdentifier()]
  180. )
  181. ) {
  182. throw new \RuntimeException("This CMF identifier is already registered : '".$organizationCreationRequest->getIdentifier()."'");
  183. }
  184. $normalizedName = $this->normalizeIdentificationField($organizationCreationRequest->getName());
  185. if (
  186. $this->organizationIdentificationRepository->findOneBy(
  187. ['normalizedName' => $normalizedName, 'addressCity' => $organizationCreationRequest->getCity()]
  188. )
  189. ) {
  190. throw new \RuntimeException("An organization named '".$organizationCreationRequest->getName()."' already exists in ".$organizationCreationRequest->getCity());
  191. }
  192. $address = $this->normalizeIdentificationField(implode(' ', [
  193. $organizationCreationRequest->getStreetAddress1(),
  194. $organizationCreationRequest->getStreetAddress2(),
  195. $organizationCreationRequest->getStreetAddress3(),
  196. ]));
  197. if (
  198. $this->organizationIdentificationRepository->findOneBy(
  199. [
  200. 'normalizedAddress' => $address,
  201. 'addressCity' => $organizationCreationRequest->getCity(),
  202. 'postalCode' => $organizationCreationRequest->getPostalCode(),
  203. ]
  204. )
  205. ) {
  206. throw new \RuntimeException('An organization already exists at this address.');
  207. }
  208. }
  209. /**
  210. * Vérifie la disponibilité et la validité d'un sous domaine.
  211. *
  212. * @throws \Exception
  213. */
  214. protected function validateSubdomain(string $subdomainValue): void
  215. {
  216. if (!$this->subdomainService->isValidSubdomain($subdomainValue)) {
  217. throw new \RuntimeException('Not a valid subdomain : '.$subdomainValue);
  218. }
  219. if ($this->subdomainService->isReservedSubdomain($subdomainValue)) {
  220. throw new \RuntimeException('This subdomain is not available : '.$subdomainValue);
  221. }
  222. if ($this->subdomainService->isRegistered($subdomainValue)) {
  223. throw new \RuntimeException('This subdomain is already registered : '.$subdomainValue);
  224. }
  225. }
  226. /**
  227. * Créé une nouvelle instance d'organisation, et toutes les instances liées (paramètres, contact, adresses, ...),
  228. * selon le contenu de la requête de création.
  229. *
  230. * @throws \Throwable
  231. */
  232. protected function makeOrganizationWithRelations(
  233. OrganizationCreationRequest $organizationCreationRequest,
  234. ): Organization {
  235. // Création de l'organisation
  236. $organization = $this->makeOrganization($organizationCreationRequest);
  237. $this->logger->debug(' - Organization created');
  238. // Création des Parameters
  239. $parameters = $this->makeParameters($organizationCreationRequest);
  240. $organization->setParameters($parameters);
  241. $this->logger->debug(' - Parameters created');
  242. // Création des Settings
  243. $settings = $this->makeSettings($organizationCreationRequest);
  244. $organization->setSettings($settings);
  245. $this->logger->debug(' - Settings created');
  246. // Création de l'adresse postale
  247. $organizationAddressPostal = $this->makePostalAddress($organizationCreationRequest);
  248. $organization->addOrganizationAddressPostal($organizationAddressPostal);
  249. $this->logger->debug(' - OrganizationAddressPostal created');
  250. // Création du point de contact
  251. $contactPoint = $this->makeContactPoint($organizationCreationRequest);
  252. $organization->addContactPoint($contactPoint);
  253. $this->logger->debug(' - ContactPoint created');
  254. // Rattachement au réseau
  255. $networkOrganization = $this->makeNetworkOrganization($organizationCreationRequest);
  256. $organization->addNetworkOrganization($networkOrganization);
  257. $this->logger->debug(' - NetworkOrganization created');
  258. // Créé l'admin
  259. $adminAccess = $this->makeAdminAccess($organizationCreationRequest);
  260. $organization->addAccess($adminAccess);
  261. $this->logger->debug(' - Admin access created');
  262. // Création des cycles
  263. foreach ($this->makeCycles() as $cycle) {
  264. $organization->addCycle($cycle);
  265. }
  266. $this->logger->debug(' - Cycles created');
  267. // Création du président (si renseigné)
  268. $presidentCreationRequest = $organizationCreationRequest->getPresident();
  269. if ($presidentCreationRequest !== null) {
  270. $presidentCreationRequest->setCreationDate($organizationCreationRequest->getCreationDate());
  271. $presidentCreationRequest->setAuthorId($organizationCreationRequest->getAuthorId());
  272. $presidentAccess = $this->makeAccess($presidentCreationRequest);
  273. $presidentAccess->setCreateDate($organizationCreationRequest->getCreationDate());
  274. $presidentAccess->setCreatedBy($organizationCreationRequest->getAuthorId());
  275. $organization->addAccess($presidentAccess);
  276. $this->logger->debug(' - President access created');
  277. }
  278. // Création du directeur (si renseigné)
  279. $directorCreationRequest = $organizationCreationRequest->getDirector();
  280. if ($directorCreationRequest !== null) {
  281. $directorCreationRequest->setCreationDate($organizationCreationRequest->getCreationDate());
  282. $directorCreationRequest->setAuthorId($organizationCreationRequest->getAuthorId());
  283. $directorAccess = $this->makeAccess($directorCreationRequest);
  284. $directorAccess->setCreateDate($organizationCreationRequest->getCreationDate());
  285. $directorAccess->setCreatedBy($organizationCreationRequest->getAuthorId());
  286. $organization->addAccess($directorAccess);
  287. $this->logger->debug(' - Director access created');
  288. }
  289. // Création du sous-domaine
  290. $subdomain = $this->makeSubdomain($organizationCreationRequest);
  291. $organization->addSubdomain($subdomain);
  292. // <--- Pour la rétrocompatibilité avec la v1 ; pourra être supprimé lorsque la migration sera achevée
  293. $parameters = $organization->getParameters();
  294. $parameters->setSubDomain($organizationCreationRequest->getSubdomain());
  295. $parameters->setOtherWebsite('https://'.$organizationCreationRequest->getSubdomain().'.opentalent.fr');
  296. // --->
  297. $this->logger->debug(' - Subdomain created');
  298. return $organization;
  299. }
  300. /**
  301. * Créé une nouvelle instance d'organisation.
  302. */
  303. protected function makeOrganization(OrganizationCreationRequest $organizationCreationRequest): Organization
  304. {
  305. // Création de l'organisation
  306. $organization = new Organization();
  307. $organization->setName($organizationCreationRequest->getName());
  308. $organization->setLegalStatus($organizationCreationRequest->getLegalStatus());
  309. $organization->setPrincipalType($organizationCreationRequest->getPrincipalType());
  310. $organization->setIdentifier($organizationCreationRequest->getIdentifier());
  311. $organization->setCreationDate($organizationCreationRequest->getCreationDate());
  312. $organization->setCreateDate($organizationCreationRequest->getCreationDate());
  313. $organization->setCreatedBy($organizationCreationRequest->getAuthorId());
  314. return $organization;
  315. }
  316. /**
  317. * Create a new Parameters object from the data in an OrganizationCreationRequest.
  318. *
  319. * @param OrganizationCreationRequest $organizationCreationRequest The organization creation request
  320. *
  321. * @return Parameters The created Parameters object
  322. *
  323. * @throws \Throwable If there is an error
  324. */
  325. protected function makeParameters(OrganizationCreationRequest $organizationCreationRequest): Parameters
  326. {
  327. $parameters = new Parameters();
  328. return $parameters;
  329. }
  330. /**
  331. * Creates a new instance of the Settings class based on the given OrganizationCreationRequest object.
  332. *
  333. * @param OrganizationCreationRequest $organizationCreationRequest the OrganizationCreationRequest object containing the required data
  334. *
  335. * @return Settings the newly created instance of the Settings class
  336. */
  337. protected function makeSettings(OrganizationCreationRequest $organizationCreationRequest): Settings
  338. {
  339. $settings = new Settings();
  340. $settings->setProduct($organizationCreationRequest->getProduct());
  341. // TODO: à revoir, pour étendre à d'autres pays (voir à remplacer le champs 'country' par un champs 'currency'?)
  342. $settings->setCountry(
  343. $organizationCreationRequest->getCountryId() === 41 ? 'SWITZERLAND' : 'FRANCE'
  344. );
  345. $settings->setCreateDate($organizationCreationRequest->getCreationDate());
  346. $settings->setCreatedBy($organizationCreationRequest->getAuthorId());
  347. return $settings;
  348. }
  349. /**
  350. * Creates a new instance of the OrganizationAddressPostal class based on the given OrganizationCreationRequest object.
  351. *
  352. * @param OrganizationCreationRequest $organizationCreationRequest the OrganizationCreationRequest object containing the required data
  353. *
  354. * @return OrganizationAddressPostal the newly created instance of the OrganizationAddressPostal class
  355. */
  356. protected function makePostalAddress(OrganizationCreationRequest $organizationCreationRequest): OrganizationAddressPostal
  357. {
  358. $country = $this->countryRepository->find($organizationCreationRequest->getCountryId());
  359. if (!$country) {
  360. throw new \RuntimeException('No country found for id '.$organizationCreationRequest->getCountryId());
  361. }
  362. $addressPostal = new AddressPostal();
  363. $addressPostal->setStreetAddress($organizationCreationRequest->getStreetAddress1());
  364. $addressPostal->setStreetAddressSecond($organizationCreationRequest->getStreetAddress2());
  365. $addressPostal->setStreetAddressThird($organizationCreationRequest->getStreetAddress3());
  366. $addressPostal->setPostalCode($organizationCreationRequest->getPostalCode());
  367. $addressPostal->setAddressCity($organizationCreationRequest->getCity());
  368. $addressPostal->setAddressCountry($country);
  369. $addressPostal->setCreateDate($organizationCreationRequest->getCreationDate());
  370. $addressPostal->setCreatedBy($organizationCreationRequest->getAuthorId());
  371. $organizationAddressPostal = new OrganizationAddressPostal();
  372. $organizationAddressPostal->setAddressPostal($addressPostal);
  373. $organizationAddressPostal->setType(AddressPostalOrganizationTypeEnum::ADDRESS_HEAD_OFFICE);
  374. $organizationAddressPostal->setCreateDate($organizationCreationRequest->getCreationDate());
  375. $organizationAddressPostal->setCreatedBy($organizationCreationRequest->getAuthorId());
  376. return $organizationAddressPostal;
  377. }
  378. /**
  379. * Creates a new instance of the ContactPoint class based on the given OrganizationCreationRequest object.
  380. *
  381. * @param OrganizationCreationRequest $organizationCreationRequest the OrganizationCreationRequest object containing the required data
  382. *
  383. * @return ContactPoint the newly created instance of the ContactPoint class
  384. *
  385. * @throws NumberParseException
  386. */
  387. protected function makeContactPoint(OrganizationCreationRequest $organizationCreationRequest): ContactPoint
  388. {
  389. if (!$this->phoneNumberUtil->isPossibleNumber($organizationCreationRequest->getPhoneNumber())) {
  390. throw new \RuntimeException('Phone number is invalid or missing');
  391. }
  392. $phoneNumber = $this->phoneNumberUtil->parse($organizationCreationRequest->getPhoneNumber());
  393. $contactPoint = new ContactPoint();
  394. $contactPoint->setContactType(ContactPointTypeEnum::PRINCIPAL);
  395. $contactPoint->setEmail($organizationCreationRequest->getEmail());
  396. $contactPoint->setTelphone($phoneNumber);
  397. $contactPoint->setCreateDate($organizationCreationRequest->getCreationDate());
  398. $contactPoint->setCreatedBy($organizationCreationRequest->getAuthorId());
  399. return $contactPoint;
  400. }
  401. /**
  402. * Creates a new instance of the NetworkOrganization class based on the given OrganizationCreationRequest object.
  403. *
  404. * @param OrganizationCreationRequest $organizationCreationRequest the OrganizationCreationRequest object containing the required data
  405. *
  406. * @return NetworkOrganization the newly created instance of the NetworkOrganization class
  407. *
  408. * @throws \RuntimeException|\Exception if no parent organization is found for the given parent ID or if no network is found for the given network ID
  409. */
  410. protected function makeNetworkOrganization(OrganizationCreationRequest $organizationCreationRequest): NetworkOrganization
  411. {
  412. $parent = $this->organizationRepository->find($organizationCreationRequest->getParentId());
  413. if (!$parent) {
  414. throw new \RuntimeException('No parent organization found for id '.$organizationCreationRequest->getParentId());
  415. }
  416. if ($parent->getSettings()->getProduct() !== SettingsProductEnum::MANAGER) {
  417. throw new \RuntimeException("Parent organization must have the product 'manager' (actual product: '".$parent->getSettings()->getProduct()->value."')");
  418. }
  419. $networkOrganization = $this->organizationUtils->getActiveNetworkOrganization($parent);
  420. if (!$networkOrganization) {
  421. throw new \RuntimeException('No network found for parent '.$organizationCreationRequest->getParentId());
  422. }
  423. $network = $networkOrganization->getNetwork();
  424. // Si réseau CMF, on vérifie que le matricule est valide
  425. if ($network->getId() === NetworkEnum::CMF->value) {
  426. if (!preg_match("/FR\d{12}/", $organizationCreationRequest->getIdentifier())) {
  427. throw new \RuntimeException('CMF identifier is missing or invalid.');
  428. }
  429. }
  430. $networkOrganization = new NetworkOrganization();
  431. $networkOrganization->setParent($parent);
  432. $networkOrganization->setNetwork($network);
  433. $networkOrganization->setStartDate(DatesUtils::new());
  434. $networkOrganization->setCreateDate($organizationCreationRequest->getCreationDate());
  435. $networkOrganization->setCreatedBy($organizationCreationRequest->getAuthorId());
  436. return $networkOrganization;
  437. }
  438. /**
  439. * Creates a new instance of the Access class with admin access based on the given OrganizationCreationRequest object.
  440. *
  441. * @param OrganizationCreationRequest $organizationCreationRequest the OrganizationCreationRequest object containing the required data
  442. *
  443. * @return Access the newly created instance of the Access class with admin access
  444. */
  445. protected function makeAdminAccess(OrganizationCreationRequest $organizationCreationRequest): Access
  446. {
  447. $admin = new Person();
  448. $admin->setUsername('admin'.strtolower($organizationCreationRequest->getSubdomain()));
  449. $randomString = ByteString::fromRandom(32)->toString();
  450. $admin->setPassword($randomString);
  451. $admin->setEnabled(true);
  452. $adminAccess = new Access();
  453. $adminAccess->setAdminAccess(true);
  454. $adminAccess->setPerson($admin);
  455. $adminAccess->setLoginEnabled(true);
  456. $adminAccess->setCreateDate($organizationCreationRequest->getCreationDate());
  457. $adminAccess->setCreatedBy($organizationCreationRequest->getAuthorId());
  458. $contactPoint = new ContactPoint();
  459. $contactPoint->setContactType(ContactPointTypeEnum::PRINCIPAL);
  460. $contactPoint->setEmail($organizationCreationRequest->getEmail());
  461. $admin->addContactPoint($contactPoint);
  462. return $adminAccess;
  463. }
  464. /**
  465. * Creates an array of Cycle objects based on a predefined set of data.
  466. *
  467. * @return Cycle[] an array of Cycle objects
  468. */
  469. protected function makeCycles(): array
  470. {
  471. $cyclesData = [
  472. ['Cycle initiation', 10, CycleEnum::INITIATION_CYCLE],
  473. ['Cycle 1', 20, CycleEnum::CYCLE_1],
  474. ['Cycle 2', 30, CycleEnum::CYCLE_2],
  475. ['Cycle 3', 40, CycleEnum::CYCLE_3],
  476. ['Cycle 4', 50, CycleEnum::CYCLE_4],
  477. ['Hors cycle', 60, CycleEnum::OUT_CYCLE],
  478. ];
  479. $cycles = [];
  480. foreach ($cyclesData as $cycleData) {
  481. $cycle = new Cycle();
  482. $cycle->setLabel($cycleData[0]);
  483. $cycle->setOrder($cycleData[1]);
  484. $cycle->setCycleEnum($cycleData[2]);
  485. $cycle->setIsSystem(false);
  486. $cycles[] = $cycle;
  487. }
  488. return $cycles;
  489. }
  490. /**
  491. * Creates an Access object based on the given OrganizationMemberCreationRequest.
  492. *
  493. * @param int|OrganizationMemberCreationRequest $creationRequestData the request object containing the
  494. * necessary data for creating a Person object,
  495. * or the id of an existing one
  496. *
  497. * @return Access the created Access object
  498. *
  499. * @throws NumberParseException
  500. */
  501. protected function makeAccess(
  502. int|OrganizationMemberCreationRequest $creationRequestData,
  503. ): Access {
  504. if (is_int($creationRequestData)) {
  505. $person = $this->personRepository->find($creationRequestData);
  506. } else {
  507. $person = new Person();
  508. $person->setUsername($creationRequestData->getUsername());
  509. $person->setPassword(ByteString::fromRandom(32)->toString());
  510. $person->setGender($creationRequestData->getGender());
  511. $person->setName(
  512. ucfirst(strtolower($creationRequestData->getName()))
  513. );
  514. $person->setGivenName(
  515. ucfirst(strtolower($creationRequestData->getGivenName()))
  516. );
  517. $personPostalAddress = $this->makePersonPostalAddress($creationRequestData);
  518. $person->addPersonAddressPostal($personPostalAddress);
  519. $contactPoint = $this->makePersonContactPoint($creationRequestData);
  520. $person->addContactPoint($contactPoint);
  521. $person->setCreateDate($creationRequestData->getCreationDate());
  522. $person->setCreatedBy($creationRequestData->getAuthorId());
  523. }
  524. $access = new Access();
  525. $access->setPerson($person);
  526. return $access;
  527. }
  528. /**
  529. * Creates a PersonAddressPostal object based on the given OrganizationMemberCreationRequest.
  530. *
  531. * @param OrganizationMemberCreationRequest $organizationMemberCreationRequest the request object containing the
  532. * necessary data for creating a
  533. * PersonAddressPostal object
  534. *
  535. * @return PersonAddressPostal the created PersonAddressPostal object
  536. */
  537. protected function makePersonPostalAddress(OrganizationMemberCreationRequest $organizationMemberCreationRequest): PersonAddressPostal
  538. {
  539. $addressPostal = new AddressPostal();
  540. $addressPostal->setStreetAddress($organizationMemberCreationRequest->getStreetAddress1());
  541. $addressPostal->setStreetAddressSecond($organizationMemberCreationRequest->getStreetAddress2());
  542. $addressPostal->setStreetAddressThird($organizationMemberCreationRequest->getStreetAddress3());
  543. $addressPostal->setPostalCode($organizationMemberCreationRequest->getPostalCode());
  544. $addressPostal->setAddressCity($organizationMemberCreationRequest->getCity());
  545. $addressPostal->setCreateDate($organizationMemberCreationRequest->getCreationDate());
  546. $addressPostal->setCreatedBy($organizationMemberCreationRequest->getAuthorId());
  547. $country = $this->countryRepository->find($organizationMemberCreationRequest->getCountryId());
  548. $addressPostal->setAddressCountry($country);
  549. $personAddressPostal = new PersonAddressPostal();
  550. $personAddressPostal->setAddressPostal($addressPostal);
  551. $personAddressPostal->setType(AddressPostalPersonTypeEnum::ADDRESS_PRINCIPAL);
  552. $personAddressPostal->setCreateDate($organizationMemberCreationRequest->getCreationDate());
  553. $personAddressPostal->setCreatedBy($organizationMemberCreationRequest->getAuthorId());
  554. return $personAddressPostal;
  555. }
  556. /**
  557. * Creates a new instance of the ContactPoint class based on the given OrganizationCreationRequest object.
  558. *
  559. * @param OrganizationMemberCreationRequest $organizationMemberCreationRequest the OrganizationMemberCreationRequest object containing the required data
  560. *
  561. * @return ContactPoint the newly created instance of the ContactPoint class
  562. *
  563. * @throws NumberParseException
  564. */
  565. protected function makePersonContactPoint(OrganizationMemberCreationRequest $organizationMemberCreationRequest): ContactPoint
  566. {
  567. $phoneNumber = $this->phoneNumberUtil->parse($organizationMemberCreationRequest->getPhone());
  568. $contactPoint = new ContactPoint();
  569. $contactPoint->setContactType(ContactPointTypeEnum::PRINCIPAL);
  570. $contactPoint->setEmail($organizationMemberCreationRequest->getEmail());
  571. $contactPoint->setTelphone($phoneNumber);
  572. if ($organizationMemberCreationRequest->getMobile() !== null) {
  573. $mobileNumber = $this->phoneNumberUtil->parse($organizationMemberCreationRequest->getMobile());
  574. $contactPoint->setMobilPhone($mobileNumber);
  575. }
  576. $contactPoint->setCreateDate($organizationMemberCreationRequest->getCreationDate());
  577. $contactPoint->setCreatedBy($organizationMemberCreationRequest->getAuthorId());
  578. return $contactPoint;
  579. }
  580. protected function makeSubdomain(OrganizationCreationRequest $organizationCreationRequest): Subdomain
  581. {
  582. $subdomain = new Subdomain();
  583. $subdomain->setSubdomain($organizationCreationRequest->getSubdomain());
  584. $subdomain->setActive(true);
  585. return $subdomain;
  586. }
  587. /**
  588. * Créé le site Typo3 et retourne l'id de la page racine du site nouvellement créé, ou null en cas d'erreur.
  589. *
  590. * @throws RedirectionExceptionInterface
  591. * @throws ClientExceptionInterface
  592. * @throws TransportExceptionInterface
  593. * @throws ServerExceptionInterface
  594. */
  595. protected function createTypo3Website(Organization $organization): ?int
  596. {
  597. $response = $this->typo3Service->createSite($organization->getId());
  598. $content = json_decode($response->getContent(), true);
  599. $rootPageUid = $content['root_uid'];
  600. if ($response->getStatusCode() === Response::HTTP_OK && $rootPageUid > 0) {
  601. // TODO: revoir l'utilité du champs cmsId
  602. $organization->setCmsId($rootPageUid);
  603. $this->entityManager->persist($organization);
  604. $this->entityManager->flush();
  605. return $rootPageUid;
  606. } else {
  607. $this->logger->critical("/!\ A critical error happened while creating the Typo3 website");
  608. $this->logger->debug($response->getContent());
  609. }
  610. return null;
  611. }
  612. protected function updateAdminassosDb(Organization $organization): void
  613. {
  614. $response = $this->apiLegacyRequestService->post(
  615. '/_internal/secure/organization/creation-event',
  616. ['organizationId' => $organization->getId()]
  617. );
  618. if ($response->getStatusCode() !== Response::HTTP_OK) {
  619. throw new \RuntimeException('An error happened while updating the adminassos database: '.$response->getContent());
  620. }
  621. }
  622. /**
  623. * Normalise la chaine comme sont normalisées les champs de l'entité OrganizationIdentification.
  624. *
  625. * @øee sql/schema-extensions/003-view_organization_identification.sql
  626. */
  627. protected function normalizeIdentificationField(string $value): string
  628. {
  629. $value = strtolower(trim($value));
  630. $value = preg_replace('/[éèê]/u', 'e', $value);
  631. $value = preg_replace('/[à]/u', 'a', $value);
  632. $value = preg_replace('/[ç]/u', 'c', $value);
  633. return preg_replace('/[^a-z0-9]+/u', '+', $value);
  634. }
  635. }