DolibarrSyncServiceTest.php 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  1. <?php
  2. namespace App\Tests\Service\Dolibarr;
  3. use App\Entity\Access\Access;
  4. use App\Entity\Access\FunctionType;
  5. use App\Entity\Core\AddressPostal;
  6. use App\Entity\Core\ContactPoint;
  7. use App\Entity\Network\Network;
  8. use App\Entity\Network\NetworkOrganization;
  9. use App\Entity\Organization\Organization;
  10. use App\Entity\Organization\OrganizationAddressPostal;
  11. use App\Entity\Organization\Settings;
  12. use App\Entity\Person\Person;
  13. use App\Enum\Access\FunctionEnum;
  14. use App\Enum\Access\RoleEnum;
  15. use App\Enum\Core\ContactPointTypeEnum;
  16. use App\Enum\Network\NetworkEnum;
  17. use App\Enum\Organization\AddressPostalOrganizationTypeEnum;
  18. use App\Enum\Organization\SettingsProductEnum;
  19. use App\Repository\Access\AccessRepository;
  20. use App\Repository\Access\FunctionTypeRepository;
  21. use App\Repository\Organization\OrganizationRepository;
  22. use App\Service\Core\AddressPostalUtils;
  23. use App\Service\Dolibarr\DolibarrApiService;
  24. use App\Service\Dolibarr\DolibarrSyncService;
  25. use App\Service\Rest\Operation\CreateOperation;
  26. use App\Service\Rest\Operation\UpdateOperation;
  27. use App\Service\Utils\ArrayUtils;
  28. use Doctrine\Common\Collections\ArrayCollection;
  29. use libphonenumber\PhoneNumber;
  30. use libphonenumber\PhoneNumberUtil;
  31. use PHPUnit\Framework\MockObject\MockObject;
  32. use PHPUnit\Framework\TestCase;
  33. use Psr\Log\LoggerInterface;
  34. use Symfony\Contracts\HttpClient\ResponseInterface;
  35. use Symfony\Contracts\Translation\TranslatorInterface;
  36. class TestableDolibarrSyncService extends DolibarrSyncService {
  37. public function getDolibarrSocietiesIndex(): array { return parent::getDolibarrSocietiesIndex(); }
  38. public function findDolibarrContactFor(array $dolibarrContacts, Person $person): ?array { return parent::findDolibarrContactFor($dolibarrContacts, $person); }
  39. public function getActiveMembersIndex(): array { return parent::getActiveMembersIndex(); }
  40. public function sanitizeDolibarrData(?array $data): ?array { return parent::sanitizeDolibarrData($data); }
  41. public function getOrganizationPostalAddress(Organization $organization): ?AddressPostal { return parent::getOrganizationPostalAddress($organization); }
  42. public function getOrganizationPhone(Organization $organization): ?string { return parent::getOrganizationPhone($organization); }
  43. public function getOrganizationEmail(Organization $organization): ?string { return parent::getOrganizationEmail($organization); }
  44. public function getOrganizationNetworkId(Organization $organization): ?int { return parent::getOrganizationNetworkId($organization); }
  45. public function countWithMission(array $missions, array $members): int { return parent::countWithMission($missions, $members); }
  46. public function getPersonContact(Person $person): ?ContactPoint { return parent::getPersonContact($person); }
  47. public function formatContactPosition(array $missions, ?string $gender = 'X'): string { return parent::formatContactPosition($missions, $gender); }
  48. public function formatPhoneNumber(PhoneNumber $phoneNumber): string { return parent::formatPhoneNumber($phoneNumber); }
  49. }
  50. class DolibarrSyncServiceTest extends TestCase
  51. {
  52. private MockObject | OrganizationRepository $organizationRepository;
  53. private MockObject | AccessRepository $accessRepository;
  54. private MockObject | FunctionTypeRepository $functionTypeRepository;
  55. private MockObject | DolibarrApiService $dolibarrApiService;
  56. private MockObject | AddressPostalUtils $addressPostalUtils;
  57. private MockObject | ArrayUtils $arrayUtils;
  58. private MockObject | TranslatorInterface $translator;
  59. private MockObject | LoggerInterface $logger;
  60. public function setUp(): void {
  61. $this->organizationRepository = $this->getMockBuilder(OrganizationRepository::class)
  62. ->disableOriginalConstructor()
  63. ->getMock();
  64. $this->accessRepository = $this->getMockBuilder(AccessRepository::class)
  65. ->disableOriginalConstructor()
  66. ->getMock();
  67. $this->functionTypeRepository = $this->getMockBuilder(FunctionTypeRepository::class)
  68. ->disableOriginalConstructor()
  69. ->getMock();
  70. $this->dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
  71. ->disableOriginalConstructor()
  72. ->getMock();
  73. $this->addressPostalUtils = $this->getMockBuilder(AddressPostalUtils::class)
  74. ->disableOriginalConstructor()
  75. ->getMock();
  76. $this->arrayUtils = $this->getMockBuilder(ArrayUtils::class)
  77. ->disableOriginalConstructor()
  78. ->getMock();
  79. $this->translator = $this->getMockBuilder(TranslatorInterface::class)
  80. ->disableOriginalConstructor()
  81. ->getMock();
  82. $this->logger = $this->getMockBuilder(LoggerInterface::class)
  83. ->disableOriginalConstructor()
  84. ->getMock();
  85. $this->logger->method('info')->willReturnSelf();
  86. $this->logger->method('debug')->willReturnSelf();
  87. $this->logger->method('warning')->willReturnSelf();
  88. $this->logger->method('error')->willReturnSelf();
  89. }
  90. public function testScan(): void
  91. {
  92. $dolibarrSyncService = $this->getMockBuilder(TestableDolibarrSyncService::class)
  93. ->setConstructorArgs([$this->organizationRepository, $this->accessRepository, $this->functionTypeRepository,
  94. $this->dolibarrApiService, $this->addressPostalUtils, $this->arrayUtils, $this->translator, $this->logger])
  95. ->setMethodsExcept(['scan'])
  96. ->getMock();
  97. $dolibarrSociety1 = [
  98. 'id' => 1,
  99. 'name' => 'Organization 10',
  100. 'address' => '1 Rue Qwerty',
  101. 'zip' => '01024',
  102. 'town' => 'Ram',
  103. 'email' => 'some@email.com',
  104. 'phone' => null,
  105. 'status' => 0,
  106. 'parent' => '0',
  107. 'array_options' => [
  108. 'options_2iopeninfoopentalent' => '',
  109. 'options_2iopen_software_opentalent' => 'Opentalent Artist'
  110. ]
  111. ];
  112. $dolibarrSociety2 = ['id' => 2, "array_options" => []];
  113. $dolibarrSociety3 = ['id' => 3, "array_options" => []];
  114. // Get societies
  115. $dolibarrSyncService
  116. ->expects(self::once())
  117. ->method('getDolibarrSocietiesIndex')
  118. ->willReturn([
  119. 10 => $dolibarrSociety1,
  120. 20 => $dolibarrSociety2,
  121. 30 => $dolibarrSociety3
  122. ]);
  123. // Get members
  124. $activeMembers1 = [11 => [FunctionEnum::PRESIDENT()->getValue()], 12 => [FunctionEnum::STUDENT()->getValue()], 13 => [FunctionEnum::TREASURER()->getValue()]];
  125. $activeMembers2 = [21 => [FunctionEnum::PRESIDENT()->getValue()]];
  126. $dolibarrSyncService
  127. ->expects(self::once())
  128. ->method('getActiveMembersIndex')
  129. ->willReturn([
  130. 10 => $activeMembers1,
  131. 20 => $activeMembers2,
  132. 30 => [],
  133. ]);
  134. // Function types
  135. $functionType1 = $this->getMockBuilder(FunctionType::class)->getMock();
  136. $functionType1->method('getMission')->willReturn(FunctionEnum::DIRECTOR()->getValue());
  137. $functionType2 = $this->getMockBuilder(FunctionType::class)->getMock();
  138. $functionType2->method('getMission')->willReturn(FunctionEnum::PRESIDENT()->getValue());
  139. $this->functionTypeRepository
  140. ->expects($this->once())
  141. ->method('findBy')
  142. ->with(['roleByDefault' => RoleEnum::ROLE_ADMIN()->getValue()])
  143. ->willReturn([$functionType1, $functionType2]);
  144. // Get CMF and FFEC ids
  145. $this->dolibarrApiService->method('getSociety')->willReturnMap(
  146. [
  147. [12097, ['id' => 10]],
  148. [91295, ['id' => 20]]
  149. ]
  150. );
  151. // -- Loop over organizations --
  152. $dolibarrSyncService
  153. ->expects(self::exactly(5)) // 3 organizations and 2 contacts
  154. ->method('sanitizeDolibarrData')
  155. ->willReturnCallback(function ($args) { return $args; });
  156. $organization1 = $this->getMockBuilder(Organization::class)->getMock();
  157. $organization1->method('getId')->willReturn(10);
  158. $organization1->method('getName')->willReturn('Organization 10');
  159. $organization2 = $this->getMockBuilder(Organization::class)->getMock();
  160. $organization2->method('getId')->willReturn(20);
  161. $organization2->method('getName')->willReturn('Organization 20');
  162. $this->organizationRepository->method('find')
  163. ->willReturnMap([
  164. [10, null, null, $organization1],
  165. [20, null, null, $organization2],
  166. [30, null, null, null]
  167. ]);
  168. $addressPostal = $this->getMockBuilder(AddressPostal::class)->getMock();
  169. $dolibarrSyncService
  170. ->expects(self::exactly(2))
  171. ->method('getOrganizationPostalAddress')
  172. ->willReturnMap([
  173. [$organization1, $addressPostal],
  174. [$organization2, null],
  175. ]);
  176. $this->addressPostalUtils
  177. ->method('getFullStreetAddress')
  178. ->with($addressPostal)
  179. ->willReturn('1 Rue Azerty');
  180. $addressPostal->method('getAddressOwner')->willReturn('Mr Keyboard');
  181. $addressPostal->method('getPostalCode')->willReturn('01110');
  182. $addressPostal->method('getAddressCity')->willReturn('ByteCity');
  183. $dolibarrSyncService
  184. ->expects(self::exactly(2))
  185. ->method('getOrganizationEmail')
  186. ->willReturnMap([
  187. [$organization1, 'foo@bar.net'],
  188. [$organization2, null],
  189. ]);
  190. $dolibarrSyncService
  191. ->expects(self::exactly(2))
  192. ->method('getOrganizationPhone')
  193. ->willReturnMap([
  194. [$organization1, '0102030405'],
  195. [$organization2, null],
  196. ]);
  197. $dolibarrSyncService
  198. ->expects(self::exactly(2))
  199. ->method('getOrganizationNetworkId')
  200. ->willReturnMap([
  201. [$organization1, NetworkEnum::CMF()->getValue()],
  202. [$organization2, null],
  203. ]);
  204. $settings1 = $this->getMockBuilder(Settings::class)->getMock();
  205. $settings1->method('getProduct')->willReturn(SettingsProductEnum::SCHOOL()->getValue());
  206. $organization1->method('getSettings')->willReturn($settings1);
  207. $settings2 = $this->getMockBuilder(Settings::class)->getMock();
  208. $settings1->method('getProduct')->willReturn(SettingsProductEnum::ARTIST()->getValue());
  209. $organization2->method('getSettings')->willReturn($settings2);
  210. $dolibarrSyncService->method('countWithMission')->willReturnMap([
  211. [[FunctionEnum::STUDENT()->getValue()], $activeMembers1, 1],
  212. [[FunctionEnum::ADHERENT()->getValue()], $activeMembers1, 2],
  213. [[FunctionEnum::DIRECTOR()->getValue(), FunctionEnum::PRESIDENT()->getValue()], $activeMembers1, 1],
  214. [[FunctionEnum::DIRECTOR()->getValue(), FunctionEnum::PRESIDENT()->getValue()], $activeMembers2, 2]
  215. ]);
  216. $this->translator->method('trans')->willReturnMap([
  217. ['STUDENTS_COUNT', [], null, null, "Nombre d'élèves"],
  218. ['ADHERENTS_COUNT', [], null, null, "Nombre d'adhérents"],
  219. ['ADMIN_ACCESS_COUNT', [], null, null, "Nombre d'accès admin"],
  220. ['school', [], null, null, 'Opentalent School'],
  221. ['artist', [], null, null, 'Opentalent Artist'],
  222. ['Mr', [], null, null, 'MR'],
  223. ]);
  224. $this->arrayUtils
  225. ->expects(self::exactly(3))
  226. ->method('getChanges')
  227. ->willReturnCallback(
  228. function (array $initialArray, array $newArray, bool $recursive = false, ?callable $callback = null) {
  229. if (in_array('name', $newArray, true)) {
  230. // Organization 1 name is already defined and has not been changed
  231. unset($newArray['name']);
  232. }
  233. if (in_array('statut', $newArray, true)) {
  234. // Contact 1 statut is already defined and has not been changed
  235. unset($newArray['statut']);
  236. }
  237. return $newArray;
  238. }
  239. );
  240. $contactData1 = [
  241. 'id' => '1',
  242. 'civility_code' => '',
  243. 'lastname' => 'Dupond',
  244. 'firstname' => 'Bob',
  245. 'email' => 'abcd@mail.com',
  246. 'phone_pro' => '+33478570000',
  247. 'phone_mobile' => '+33682980000',
  248. 'poste' => 'Secrétaire',
  249. 'statut' => '1',
  250. 'array_options' => [
  251. 'options_2iopen_person_id' => ''
  252. ]
  253. ];
  254. // An obsolete contact that should be disabled
  255. $obsoleteContactData = [
  256. 'id' => '4',
  257. 'lastname' => 'Doe',
  258. 'firstname' => 'John',
  259. 'statut' => '1',
  260. 'array_options' => [
  261. 'options_2iopen_person_id' => 300
  262. ]
  263. ];
  264. // An obsolete contact that should is already disabled
  265. $obsoleteContactData2 = [
  266. 'id' => '5',
  267. 'lastname' => 'Foo',
  268. 'firstname' => 'John',
  269. 'statut' => '0',
  270. 'array_options' => [
  271. 'options_2iopen_person_id' => 400
  272. ]
  273. ];
  274. $dolibarrSocietyContacts1 = [$contactData1, $obsoleteContactData, $obsoleteContactData2];
  275. $dolibarrSocietyContacts2 = [];
  276. $this->dolibarrApiService->method('getContacts')->willReturnMap([
  277. [1, $dolibarrSocietyContacts1],
  278. [2, $dolibarrSocietyContacts2]
  279. ]);
  280. // Loop over contacts
  281. // NB: Student will be skipped since it has no office role
  282. $person1 = $this->getMockBuilder(Person::class)->getMock();
  283. $person1->method('getId')->willReturn(100);
  284. $person1->method('getName')->willReturn('Dupont');
  285. $person1->method('getGivenName')->willReturn('Hercules');
  286. $person1->method('getGender')->willReturn('Mr');
  287. $person2 = $this->getMockBuilder(Person::class)->getMock();
  288. $person2->method('getId')->willReturn(200);
  289. $person2->method('getName')->willReturn('Simpson');
  290. $person2->method('getGivenName')->willReturn('Lisa');
  291. $person2->method('getGender')->willReturn(null);
  292. // An invalid person that should be ignored
  293. $invalidPerson = $this->getMockBuilder(Person::class)->getMock();
  294. $invalidPerson->method('getId')->willReturn(900);
  295. $invalidPerson->method('getName')->willReturn('');
  296. $invalidPerson->method('getGivenName')->willReturn('');
  297. $access1 = $this->getMockBuilder(Access::class)->getMock();
  298. $access1->method('getPerson')->willReturn($person1);
  299. $access2 = $this->getMockBuilder(Access::class)->getMock();
  300. $access2->method('getPerson')->willReturn($person2);
  301. $access3 = $this->getMockBuilder(Access::class)->getMock();
  302. $access3->method('getPerson')->willReturn($invalidPerson);
  303. $this->accessRepository->method('find')->willReturnMap([
  304. [11, null, null, $access1],
  305. [21, null, null, $access2],
  306. [13, null, null, $access3],
  307. ]);
  308. $dolibarrSyncService->method('findDolibarrContactFor')->willReturnMap([
  309. [$dolibarrSocietyContacts1, $person1, $contactData1],
  310. [$dolibarrSocietyContacts2, $person2, null]
  311. ]);
  312. $contactPoint1 = $this->getMockBuilder(ContactPoint::class)->getMock();
  313. $contactPoint1->method('getEmail')->willReturn('mail@domain.net');
  314. $phone = $this->getMockBuilder(PhoneNumber::class)->getMock();
  315. $contactPoint1->method('getTelphone')->willReturn($phone);
  316. $mobilePhone = $this->getMockBuilder(PhoneNumber::class)->getMock();
  317. $contactPoint1->method('getMobilPhone')->willReturn($mobilePhone);
  318. $dolibarrSyncService->method('getPersonContact')->willReturnMap([
  319. [$person1, $contactPoint1],
  320. [$person2, null],
  321. ]);
  322. $dolibarrSyncService->method('formatPhoneNumber')->willReturnMap([
  323. [$phone, '0102030405'],
  324. [$mobilePhone, '0607080910'],
  325. ]);
  326. $dolibarrSyncService->method('formatContactPosition')->willReturnMap([
  327. [[FunctionEnum::PRESIDENT()->getValue()], 'Mr', 'Président'],
  328. [[FunctionEnum::PRESIDENT()->getValue()], null, 'Président(e)'],
  329. ]);
  330. $this->logger->expects(self::exactly(2))->method('error')->withConsecutive(
  331. ["Person 900 miss a lastname and/or a firstname, ignored."],
  332. ["Organization 30 not found in the Opentalent DB"],
  333. );
  334. $progressionCallbackExpectedCalls = [[1, 3], [2, 3], [3, 3]];
  335. $progressionCallback = static function ($i, $total) use (&$progressionCallbackExpectedCalls) {
  336. [$expectedI, $expectedTotal] = array_shift($progressionCallbackExpectedCalls);
  337. if ($i !== $expectedI || $total !== $expectedTotal) {
  338. throw new \AssertionError(
  339. 'Progression callback error, expected parameters are (' . $expectedI . ',' . $expectedTotal . ')' .
  340. ', got (' . $i . ', ' . $total . ')'
  341. );
  342. }
  343. };
  344. $operations = $dolibarrSyncService->scan($progressionCallback);
  345. $this->assertCount(5, $operations);
  346. $this->assertEqualsCanonicalizing(
  347. [
  348. '[PUT thirdparties/1]',
  349. "address : `1 Rue Qwerty` => `Mr Keyboard\n1 Rue Azerty`",
  350. 'zip : `01024` => `01110`',
  351. 'town : `Ram` => `ByteCity`',
  352. 'email : `some@email.com` => `foo@bar.net`',
  353. 'phone : `` => `0102030405`',
  354. 'parent : `0` => `10`',
  355. "array_options.options_2iopen_software_opentalent : `Opentalent Artist` => `Opentalent School`",
  356. "array_options.options_2iopeninfoopentalent : `` => `Nombre d'élèves : 1\nNombre d'adhérents : 2\nNombre d'accès admin : 1`",
  357. 'status : `0` => `1`'
  358. ],
  359. $operations[0]->getChangeLog()
  360. );
  361. $this->assertEqualsCanonicalizing(
  362. [
  363. '[PUT contacts/1]',
  364. 'civility_code : `` => `MR`',
  365. 'lastname : `Dupond` => `Dupont`',
  366. 'firstname : `Bob` => `Hercules`',
  367. 'email : `abcd@mail.com` => `mail@domain.net`',
  368. 'phone_pro : `+33478570000` => `0102030405`',
  369. 'phone_mobile : `+33682980000` => `0607080910`',
  370. 'poste : `Secrétaire` => `Président`',
  371. 'array_options.options_2iopen_person_id : `` => `100`'
  372. ],
  373. $operations[1]->getChangeLog()
  374. );
  375. $this->assertEqualsCanonicalizing(
  376. ['[PUT contacts/4]', 'statut : `1` => `0`'],
  377. $operations[2]->getChangeLog()
  378. );
  379. $this->assertEqualsCanonicalizing(
  380. [
  381. '[PUT thirdparties/2]',
  382. 'address : (new) => ``',
  383. 'email : (new) => ``',
  384. 'name : (new) => `Organization 20`',
  385. 'parent : (new) => ``',
  386. 'phone : (new) => ``',
  387. 'status : (new) => `1`',
  388. 'town : (new) => ``',
  389. 'zip : (new) => ``',
  390. 'array_options.options_2iopeninfoopentalent : (new) => `Nombre d\'accès admin : 2`',
  391. ],
  392. $operations[3]->getChangeLog()
  393. );
  394. $this->assertEqualsCanonicalizing(
  395. [
  396. '[POST contacts]',
  397. 'civility_code : (new) => ``',
  398. 'lastname : (new) => `Simpson`',
  399. 'firstname : (new) => `Lisa`',
  400. 'email : (new) => ``',
  401. 'phone_pro : (new) => ``',
  402. 'phone_mobile : (new) => ``',
  403. 'poste : (new) => `Président(e)`',
  404. 'statut : (new) => `1`',
  405. 'array_options.options_2iopen_person_id : (new) => `200`',
  406. 'socid : (new) => `2`'
  407. ],
  408. $operations[4]->getChangeLog()
  409. );
  410. $this->assertCount(0, $progressionCallbackExpectedCalls);
  411. }
  412. public function testExecuteError()
  413. {
  414. $operation = new CreateOperation('operation 1', 'thirdparty', ['data' => 1]);
  415. $this->assertEquals($operation->getStatus(), $operation::STATUS_READY);
  416. $responseError = $this->getMockBuilder(ResponseInterface::class)->getMock();
  417. $responseError->method('getStatusCode')->willReturn(500);
  418. $this->dolibarrApiService->method('request')->willReturn($responseError);
  419. // POST operation will returned a server error
  420. $syncService = $this->newDolibarrSyncService();
  421. $operation = $syncService->execute([$operation])[0];
  422. $this->assertEquals($operation::STATUS_ERROR, $operation->getStatus());
  423. }
  424. public function testExecuteInvalid()
  425. {
  426. $operation = new UpdateOperation('operation 1', 'thirdparty', 1, ['data' => 1]);
  427. $responseInvalid = $this->getMockBuilder(ResponseInterface::class)->getMock();
  428. $responseInvalid->method('getStatusCode')->willReturn(200);
  429. $responseInvalid->method('toArray')->willReturn(['data' => 0]);
  430. $this->dolibarrApiService->method('request')->willReturn($responseInvalid);
  431. // POST operation will return a different content that the one which were posted, this should log a warning
  432. $this->logger->expects($this->once())->method('warning');
  433. $syncService = $this->newDolibarrSyncService();
  434. $operation = $syncService->execute([$operation])[0];
  435. $this->assertEquals($operation::STATUS_DONE, $operation->getStatus());
  436. }
  437. public function testExecuteOk() {
  438. $operation = new CreateOperation('operation 1', 'thirdparty', ['data' => 1]);
  439. $responseOk = $this->getMockBuilder(ResponseInterface::class)->getMock();
  440. $responseOk->method('getStatusCode')->willReturn(200);
  441. $responseOk->method('toArray')->willReturn(['data' => 1]);
  442. $this->dolibarrApiService->method('request')->willReturn($responseOk);
  443. $syncService = $this->newDolibarrSyncService();
  444. $operation = $syncService->execute([$operation])[0];
  445. $this->assertEquals($operation::STATUS_DONE, $operation->getStatus());
  446. }
  447. public function testGetDolibarrSocietiesIndex() {
  448. $this->dolibarrApiService
  449. ->expects($this->once())
  450. ->method('getAllClients')
  451. ->willReturn(
  452. $this->getJsonContentFromFixture('thirdparties.json')
  453. );
  454. $syncService = $this->newDolibarrSyncService();
  455. $index = $syncService->getDolibarrSocietiesIndex();
  456. $this->assertEquals("13930", $index[13930]['array_options']['options_2iopen_organization_id']);
  457. }
  458. public function testFindDolibarrContactFor() {
  459. $contacts = $this->getJsonContentFromFixture('contacts.json');
  460. // Find by id
  461. $person1 = $this->getMockBuilder(Person::class)->getMock();
  462. $person1->method('getId')->willReturn(108939);
  463. $contact1 = TestableDolibarrSyncService::findDolibarrContactFor($contacts, $person1);
  464. $this->assertEquals("5868", $contact1['id']);
  465. // Find by full name (contact already has another person id, it should not be returned)
  466. $person2 = $this->getMockBuilder(Person::class)->getMock();
  467. $person2->method('getId')->willReturn(-1);
  468. $person2->method('getName')->willReturn('dupont');
  469. $person2->method('getGivenName')->willReturn('Valerie');
  470. $contact2 = TestableDolibarrSyncService::findDolibarrContactFor($contacts, $person2);
  471. $this->assertEquals(null, $contact2);
  472. // Find by full name (contact has no person id, it should be returned)
  473. $person3 = $this->getMockBuilder(Person::class)->getMock();
  474. $person3->method('getId')->willReturn(-1);
  475. $person3->method('getName')->willReturn('ZORRO');
  476. $person3->method('getGivenName')->willReturn('Fabrice');
  477. $contact3 = TestableDolibarrSyncService::findDolibarrContactFor($contacts, $person3);
  478. $this->assertEquals("5872", $contact3['id']);
  479. // Do not find
  480. $person4 = $this->getMockBuilder(Person::class)->getMock();
  481. $person4->method('getId')->willReturn(-1);
  482. $contact4 = TestableDolibarrSyncService::findDolibarrContactFor($contacts, $person4);
  483. $this->assertEquals(null, $contact4);
  484. }
  485. public function testActiveMembersIndex() {
  486. $this->accessRepository
  487. ->expects($this->once())
  488. ->method('getAllActiveMembersAndMissions')
  489. ->willReturn(
  490. [
  491. ['id' => 123, 'organization_id' => 1, 'mission' => FunctionEnum::PRESIDENT()->getValue()],
  492. ['id' => 123, 'organization_id' => 1, 'mission' => FunctionEnum::TEACHER()->getValue()],
  493. ['id' => 124, 'organization_id' => 1, 'mission' => FunctionEnum::ADMINISTRATIVE_STAFF()->getValue()],
  494. ['id' => 125, 'organization_id' => 2, 'mission' => FunctionEnum::ADHERENT()->getValue()],
  495. ]
  496. );
  497. $syncService = $this->newDolibarrSyncService();
  498. $this->assertEquals(
  499. [
  500. 1 => [
  501. 123 => [FunctionEnum::PRESIDENT()->getValue(), FunctionEnum::TEACHER()->getValue()],
  502. 124 => [FunctionEnum::ADMINISTRATIVE_STAFF()->getValue()]
  503. ],
  504. 2 => [
  505. 125 => [FunctionEnum::ADHERENT()->getValue()]
  506. ]
  507. ],
  508. $syncService->getActiveMembersIndex()
  509. );
  510. }
  511. public function testSanitizeDolibarrData() {
  512. $this->assertEquals(null, TestableDolibarrSyncService::sanitizeDolibarrData(null));
  513. $this->assertEquals(
  514. ['a' => 'A', 'b' => null, 'c' => ['d' => 'D', 'e' => null]],
  515. TestableDolibarrSyncService::sanitizeDolibarrData(
  516. ['a' => 'A', 'b' => '', 'c' => ['d' => 'D', 'e' => '']]
  517. )
  518. );
  519. }
  520. public function testGetOrganizationPostalAddress() {
  521. $organization = $this->getMockBuilder(Organization::class)->getMock();
  522. $organizationAddressPostal1 = $this->getMockBuilder(OrganizationAddressPostal::class)->getMock();
  523. $organizationAddressPostal2 = $this->getMockBuilder(OrganizationAddressPostal::class)->getMock();
  524. $organizationAddressPostal3 = $this->getMockBuilder(OrganizationAddressPostal::class)->getMock();
  525. $addressPostal = $this->getMockBuilder(AddressPostal::class)->getMock();
  526. $organizationAddressPostal1->method('getType')->willReturn(AddressPostalOrganizationTypeEnum::ADDRESS_PRACTICE()->getValue());
  527. $organizationAddressPostal2->method('getType')->willReturn(AddressPostalOrganizationTypeEnum::ADDRESS_BILL()->getValue());
  528. $organizationAddressPostal3->method('getType')->willReturn(AddressPostalOrganizationTypeEnum::ADDRESS_OTHER()->getValue());
  529. $organizationAddressPostal2->method('getAddressPostal')->willReturn($addressPostal);
  530. $organization->expects($this->once())
  531. ->method('getOrganizationAddressPostals')
  532. ->willReturn(
  533. new ArrayCollection([$organizationAddressPostal1, $organizationAddressPostal2, $organizationAddressPostal3])
  534. );
  535. $syncService = $this->newDolibarrSyncService($organization);
  536. $this->assertEquals(
  537. $addressPostal,
  538. $syncService->getOrganizationPostalAddress($organization)
  539. );
  540. $organization2 = $this->getMockBuilder(Organization::class)->getMock();
  541. $organization2->expects($this->once())
  542. ->method('getOrganizationAddressPostals')
  543. ->willReturn(new ArrayCollection([]));
  544. $this->assertEquals(
  545. null,
  546. $syncService->getOrganizationPostalAddress($organization2)
  547. );
  548. }
  549. public function testGetOrganizationPhoneWithExistingPhone()
  550. {
  551. $organization = $this->getMockBuilder(Organization::class)->getMock();
  552. $contactPoint1 = $this->getMockBuilder(ContactPoint::class)->getMock();
  553. $contactPoint2 = $this->getMockBuilder(ContactPoint::class)->getMock();
  554. $contactPoint3 = $this->getMockBuilder(ContactPoint::class)->getMock();
  555. $contactPoint1->method('getContactType')->willReturn(ContactPointTypeEnum::OTHER()->getValue());
  556. $contactPoint2->method('getContactType')->willReturn(ContactPointTypeEnum::BILL()->getValue());
  557. $contactPoint3->method('getContactType')->willReturn(ContactPointTypeEnum::PRINCIPAL()->getValue());
  558. $phoneUtil = PhoneNumberUtil::getInstance();
  559. $phoneNumber = $phoneUtil->parse('0161626365', "FR");
  560. $contactPoint2->method('getTelphone')->willReturn($phoneNumber);
  561. $organization
  562. ->expects($this->once())
  563. ->method('getContactPoints')
  564. ->willReturn(
  565. new ArrayCollection([$contactPoint1, $contactPoint2, $contactPoint3])
  566. );
  567. $syncService = $this->newDolibarrSyncService();
  568. $this->assertEquals(
  569. '+33161626365',
  570. $syncService->getOrganizationPhone($organization)
  571. );
  572. }
  573. public function testGetOrganizationPhoneWithMobilePhone() {
  574. $organization = $this->getMockBuilder(Organization::class)->getMock();
  575. $contactPoint1 = $this->getMockBuilder(ContactPoint::class)->getMock();
  576. $contactPoint2 = $this->getMockBuilder(ContactPoint::class)->getMock();
  577. $contactPoint3 = $this->getMockBuilder(ContactPoint::class)->getMock();
  578. $contactPoint1->method('getContactType')->willReturn(ContactPointTypeEnum::OTHER()->getValue());
  579. $contactPoint2->method('getContactType')->willReturn(ContactPointTypeEnum::BILL()->getValue());
  580. $contactPoint3->method('getContactType')->willReturn(ContactPointTypeEnum::PRINCIPAL()->getValue());
  581. $contactPoint2->expects($this->once())->method('getTelphone')->willReturn(null);
  582. $phoneUtil = PhoneNumberUtil::getInstance();
  583. $phoneNumber = $phoneUtil->parse('0661626365', "FR");
  584. $contactPoint2->method('getMobilPhone')->willReturn($phoneNumber);
  585. $organization
  586. ->expects($this->once())
  587. ->method('getContactPoints')
  588. ->willReturn(
  589. new ArrayCollection([$contactPoint1, $contactPoint2, $contactPoint3])
  590. );
  591. $syncService = $this->newDolibarrSyncService();
  592. $this->assertEquals(
  593. '+33661626365',
  594. $syncService->getOrganizationPhone($organization)
  595. );
  596. }
  597. public function testGetOrganizationPhoneWithNoPhone() {
  598. $organization = $this->getMockBuilder(Organization::class)->getMock();
  599. $organization
  600. ->expects($this->once())
  601. ->method('getContactPoints')
  602. ->willReturn(new ArrayCollection([]));
  603. $syncService = $this->newDolibarrSyncService();
  604. $this->assertEquals(
  605. null,
  606. $syncService->getOrganizationPhone($organization)
  607. );
  608. }
  609. public function testGetOrganizationEmailWithExistingEmail() {
  610. $organization = $this->getMockBuilder(Organization::class)->getMock();
  611. $contactPoint1 = $this->getMockBuilder(ContactPoint::class)->getMock();
  612. $contactPoint2 = $this->getMockBuilder(ContactPoint::class)->getMock();
  613. $contactPoint3 = $this->getMockBuilder(ContactPoint::class)->getMock();
  614. $contactPoint1->method('getContactType')->willReturn(ContactPointTypeEnum::OTHER()->getValue());
  615. $contactPoint2->method('getContactType')->willReturn(ContactPointTypeEnum::BILL()->getValue());
  616. $contactPoint3->method('getContactType')->willReturn(ContactPointTypeEnum::PRINCIPAL()->getValue());
  617. $contactPoint2->method('getEmail')->willReturn('email@email.com');
  618. $organization
  619. ->expects($this->once())
  620. ->method('getContactPoints')
  621. ->willReturn(
  622. new ArrayCollection([$contactPoint1, $contactPoint2, $contactPoint3])
  623. );
  624. $syncService = $this->newDolibarrSyncService();
  625. $this->assertEquals(
  626. 'email@email.com',
  627. $syncService->getOrganizationEmail($organization)
  628. );
  629. }
  630. public function testGetOrganizationEmailWithNoEmail() {
  631. $organization = $this->getMockBuilder(Organization::class)->getMock();
  632. $organization
  633. ->expects($this->once())
  634. ->method('getContactPoints')
  635. ->willReturn(new ArrayCollection([]));
  636. $syncService = $this->newDolibarrSyncService();
  637. $this->assertEquals(
  638. null,
  639. $syncService->getOrganizationEmail($organization)
  640. );
  641. }
  642. public function testGetOrganizationNetworkId() {
  643. $organization = $this->getMockBuilder(Organization::class)->getMock();
  644. $network = $this->getMockBuilder(Network::class)->getMock();
  645. $network->method('getId')->willReturn(3);
  646. $networkOrganization = $this->getMockBuilder(NetworkOrganization::class)->getMock();
  647. $networkOrganization->method('getNetwork')->willReturn($network);
  648. $organization->method('getNetworkOrganizations')->willReturn(new ArrayCollection([$networkOrganization]));
  649. $syncService = $this->newDolibarrSyncService();
  650. $this->assertEquals(
  651. 3,
  652. $syncService->getOrganizationNetworkId($organization)
  653. );
  654. }
  655. public function testGetOrganizationNetworkIdWithMultipleResult() {
  656. $organization = $this->getMockBuilder(Organization::class)->getMock();
  657. $network1 = $this->getMockBuilder(Network::class)->getMock();
  658. $network1->method('getId')->willReturn(3);
  659. $networkOrganization1 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
  660. $networkOrganization1->method('getNetwork')->willReturn($network1);
  661. $networkOrganization1->method('getEndDate')->willReturn(new \DateTime('2000-01-01'));
  662. $network2 = $this->getMockBuilder(Network::class)->getMock();
  663. $network2->method('getId')->willReturn(4);
  664. $networkOrganization2 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
  665. $networkOrganization2->method('getNetwork')->willReturn($network2);
  666. $networkOrganization2->method('getEndDate')->willReturn(null);
  667. $organization->method('getNetworkOrganizations')->willReturn(
  668. new ArrayCollection([$networkOrganization1, $networkOrganization2])
  669. );
  670. $syncService = $this->newDolibarrSyncService();
  671. $this->assertEquals(
  672. 4,
  673. $syncService->getOrganizationNetworkId($organization)
  674. );
  675. }
  676. public function testGetOrganizationNetworkIdWithNoResult() {
  677. $organization = $this->getMockBuilder(Organization::class)->getMock();
  678. $network = $this->getMockBuilder(Network::class)->getMock();
  679. $network->method('getId')->willReturn(3);
  680. $networkOrganization = $this->getMockBuilder(NetworkOrganization::class)->getMock();
  681. $networkOrganization->method('getNetwork')->willReturn($network);
  682. $networkOrganization->method('getEndDate')->willReturn(new \DateTime('2000-01-01'));
  683. $organization->method('getNetworkOrganizations')->willReturn(new ArrayCollection([$networkOrganization]));
  684. $syncService = $this->newDolibarrSyncService();
  685. $this->assertEquals(
  686. null,
  687. $syncService->getOrganizationNetworkId($organization)
  688. );
  689. }
  690. public function testCountWithMission() {
  691. $members = [
  692. 123 => [FunctionEnum::PRESIDENT()->getValue(), FunctionEnum::TEACHER()->getValue()],
  693. 124 => [FunctionEnum::TEACHER()->getValue()],
  694. 125 => [FunctionEnum::STUDENT()->getValue()],
  695. 126 => [FunctionEnum::TREASURER()->getValue()],
  696. ];
  697. $this->assertEquals(
  698. 2,
  699. TestableDolibarrSyncService::countWithMission([FunctionEnum::TEACHER()->getValue()], $members)
  700. );
  701. $this->assertEquals(
  702. 3,
  703. TestableDolibarrSyncService::countWithMission(
  704. [FunctionEnum::TEACHER()->getValue(), FunctionEnum::TREASURER()->getValue()],
  705. $members
  706. )
  707. );
  708. $this->assertEquals(
  709. 1,
  710. TestableDolibarrSyncService::countWithMission([FunctionEnum::STUDENT()->getValue()], $members)
  711. );
  712. $this->assertEquals(
  713. 0,
  714. TestableDolibarrSyncService::countWithMission([FunctionEnum::ARCHIVIST()->getValue()], $members)
  715. );
  716. }
  717. public function testGetPersonContact() {
  718. $person = $this->getMockBuilder(Person::class)->getMock();
  719. $contactPoint1 = $this->getMockBuilder(ContactPoint::class)->getMock();
  720. $contactPoint2 = $this->getMockBuilder(ContactPoint::class)->getMock();
  721. $contactPoint1->method('getContactType')->willReturn(ContactPointTypeEnum::OTHER()->getValue());
  722. $contactPoint2->method('getContactType')->willReturn(ContactPointTypeEnum::PRINCIPAL()->getValue());
  723. $person->expects($this->once())->method('getContactPoints')->willReturn(new ArrayCollection([$contactPoint1, $contactPoint2]));
  724. $syncService = $this->newDolibarrSyncService();
  725. $this->assertEquals(
  726. $contactPoint2,
  727. $syncService->getPersonContact($person)
  728. );
  729. $person2 = $this->getMockBuilder(Person::class)->getMock();
  730. $person2->expects($this->once())->method('getContactPoints')->willReturn(new ArrayCollection([]));
  731. $this->assertEquals(null, $syncService->getPersonContact($person2));
  732. }
  733. public function testFormatContactPosition() {
  734. $this->translator->method('trans')->willReturnMap(
  735. [
  736. [FunctionEnum::PRESIDENT()->getValue(), ['gender' => 'X'], null, null, 'Président(e)'],
  737. [FunctionEnum::PRESIDENT()->getValue(), ['gender' => 'M'], null, null, 'Président'],
  738. [FunctionEnum::PRESIDENT()->getValue(), ['gender' => 'F'], null, null, 'Présidente'],
  739. [FunctionEnum::DIRECTOR()->getValue(), ['gender' => 'X'], null, null, 'Directeur(ice)'],
  740. [FunctionEnum::DIRECTOR()->getValue(), ['gender' => 'M'], null, null, 'Directeur'],
  741. [FunctionEnum::DIRECTOR()->getValue(), ['gender' => 'F'], null, null, 'Directrice'],
  742. ]
  743. );
  744. $syncService = $this->newDolibarrSyncService();
  745. $this->assertEquals(
  746. 'Président(e)',
  747. $syncService->formatContactPosition([FunctionEnum::PRESIDENT()->getValue()])
  748. );
  749. $this->assertEquals(
  750. 'Président',
  751. $syncService->formatContactPosition([FunctionEnum::PRESIDENT()->getValue()], 'MISTER')
  752. );
  753. $this->assertEquals(
  754. 'Présidente',
  755. $syncService->formatContactPosition([FunctionEnum::PRESIDENT()->getValue()], 'MISS')
  756. );
  757. $this->assertEquals(
  758. 'Présidente, Directrice',
  759. $syncService->formatContactPosition(
  760. [FunctionEnum::PRESIDENT()->getValue(), FunctionEnum::DIRECTOR()->getValue()],
  761. 'MISS'
  762. )
  763. );
  764. $this->assertEquals(
  765. 'Président, Directeur',
  766. $syncService->formatContactPosition(
  767. [FunctionEnum::PRESIDENT()->getValue(), FunctionEnum::DIRECTOR()->getValue(), FunctionEnum::ADHERENT()->getValue()],
  768. 'MISTER'
  769. )
  770. );
  771. }
  772. public function testFormatPhoneNumber() {
  773. $phoneUtil = PhoneNumberUtil::getInstance();
  774. $phoneNumber = $phoneUtil->parse('01 02 03 04 05', "FR");
  775. $this->assertEquals(
  776. '+33102030405',
  777. TestableDolibarrSyncService::formatPhoneNumber($phoneNumber)
  778. );
  779. }
  780. }