DolibarrApiService.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Service\Dolibarr;
  4. use App\Entity\Organization\Organization;
  5. use App\Enum\Dolibarr\DolibarrDocTypeEnum;
  6. use App\Service\Rest\ApiRequestService;
  7. use JetBrains\PhpStorm\Pure;
  8. use Symfony\Component\HttpFoundation\Response;
  9. use Symfony\Component\HttpKernel\Exception\HttpException;
  10. use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
  11. use Symfony\Contracts\HttpClient\HttpClientInterface;
  12. /**
  13. * Service d'appel à l'API dolibarr.
  14. *
  15. * @see https://prod-erp.2iopenservice.com/api/index.php/explorer/
  16. */
  17. class DolibarrApiService extends ApiRequestService
  18. {
  19. /** @noinspection SenselessProxyMethodInspection Method shall be kept to allow dependency injections, even if empty */
  20. #[Pure]
  21. public function __construct(HttpClientInterface $dolibarr_client)
  22. {
  23. parent::__construct($dolibarr_client);
  24. }
  25. /**
  26. * Get a dolibarr society by its opentalent organization id.
  27. *
  28. * @return array<mixed>|null
  29. *
  30. * @throws \JsonException
  31. */
  32. public function getSociety(int $organizationId): ?array
  33. {
  34. // impossible to retrieve a society by its extrafield 2iopen_organization_id (thanks dolibarr), so
  35. // we need to store the organization id in two fields: 2iopen_organization_id and ref_int :(
  36. try {
  37. return $this->getJsonContent(
  38. 'thirdparties',
  39. [
  40. 'limit' => '1',
  41. 'sqlfilters' => '(ef.2iopen_organization_id:=:'.$organizationId.')',
  42. ]
  43. )[0];
  44. } catch (HttpException $e) {
  45. if ($e->getStatusCode() === 404) {
  46. // /!\ The dolibarr API will return a 404 error if no results are found...
  47. return null;
  48. }
  49. throw $e;
  50. }
  51. }
  52. /**
  53. * Get the first active contract for the given dolibarr society.
  54. *
  55. * @return array<mixed>|null
  56. */
  57. public function getActiveContract(int $socId): ?array
  58. {
  59. try {
  60. return $this->getJsonContent(
  61. 'contracts',
  62. ['limit' => '1', 'sqlfilters' => 'statut:=:1', 'thirdparty_ids' => $socId]
  63. )[0];
  64. } catch (HttpException $e) {
  65. if ($e->getStatusCode() === 404) {
  66. // /!\ The dolibarr API will return a 404 error if no results are found...
  67. return null;
  68. }
  69. throw $e;
  70. }
  71. }
  72. /**
  73. * Get a society bills by their society id.
  74. *
  75. * @return array<mixed>
  76. */
  77. public function getBills(int $socId): array
  78. {
  79. try {
  80. return $this->getJsonContent(
  81. 'invoices',
  82. [
  83. 'sortfield' => 'datef',
  84. 'sortorder' => 'DESC',
  85. 'limit' => 5,
  86. 'sqlfilters' => "(fk_soc:=:$socId) and (fk_statut:!=:0)"
  87. ]);
  88. } catch (HttpException $e) {
  89. if ($e->getStatusCode() === 404) {
  90. // /!\ The dolibarr API will return a 404 error if no results are found...
  91. return [];
  92. }
  93. throw $e;
  94. }
  95. }
  96. /**
  97. * Get the last order of the given society.
  98. *
  99. * @param int $socId
  100. * @return array|null
  101. * @throws \JsonException
  102. */
  103. public function getLastOrder(int $socId): ?array {
  104. try {
  105. $results = $this->getJsonContent(
  106. 'orders',
  107. [
  108. 'sortfield' => 't.date_valid',
  109. 'sortorder' => 'DESC',
  110. 'limit' => 1,
  111. 'sqlfilters' => 'fk_soc:=:'.$socId
  112. ]
  113. );
  114. } catch (HttpException $e) {
  115. if ($e->getStatusCode() === 404) {
  116. // /!\ The dolibarr API will return a 404 error if no results are found...
  117. return null;
  118. }
  119. throw $e;
  120. }
  121. return empty($results) ? null : $results[0];
  122. }
  123. /**
  124. * Get all the societies which are Opentalent client.
  125. *
  126. * @return array<mixed>
  127. *
  128. * @throws HttpException
  129. */
  130. public function getAllClients(): array
  131. {
  132. return $this->getJsonContent(
  133. 'thirdparties',
  134. ['limit' => '1000000', 'sqlfilters' => 'client:=:1']
  135. );
  136. }
  137. /**
  138. * Get the society contacts.
  139. *
  140. * @return array<mixed>
  141. *
  142. * @throws HttpException
  143. */
  144. public function getContacts(int $socId): array
  145. {
  146. try {
  147. return $this->getJsonContent(
  148. 'contacts',
  149. ['limit' => 1000, 'thirdparty_ids' => $socId],
  150. );
  151. } catch (HttpException $e) {
  152. if ($e->getStatusCode() === 404) {
  153. // /!\ The dolibarr API will return a 404 error if no results are found...
  154. return [];
  155. }
  156. throw $e;
  157. }
  158. }
  159. /**
  160. * Get the society contacts that have a non-null personId.
  161. *
  162. * @return array<mixed>
  163. *
  164. * @throws HttpException
  165. */
  166. public function getActiveOpentalentContacts(int $socId): array
  167. {
  168. // On est obligé ici de passer la query en dur, sinon les parenthèses sont encodées,
  169. // et dolibarr est pas content :(
  170. try {
  171. return $this->getJsonContent(
  172. 'contacts?limit=1000&t.statut=1&thirdparty_ids='.$socId.'&sqlfilters:=:(te.2iopen_person_id%3A%3E%3A0)'
  173. );
  174. } catch (HttpException $e) {
  175. if ($e->getStatusCode() === 404) {
  176. // /!\ The dolibarr API will return a 404 error if no results are found...
  177. return [];
  178. }
  179. throw $e;
  180. }
  181. }
  182. /**
  183. * Get the society tags.
  184. *
  185. * @param int $socId The society ID
  186. *
  187. * @return array<int> The array of tags associated with the society
  188. *
  189. * @throws HttpException|\JsonException if an HTTP error occurs
  190. */
  191. public function getSocietyTagsIds(int $socId): array
  192. {
  193. try {
  194. return array_map(
  195. function ($x) { return (int) $x['id']; },
  196. $this->getJsonContent("/thirdparties/$socId/categories")
  197. );
  198. } catch (HttpException $e) {
  199. if ($e->getStatusCode() === 404) {
  200. // /!\ The dolibarr API will return a 404 error if no results are found...
  201. return [];
  202. }
  203. throw $e;
  204. }
  205. }
  206. /**
  207. * Créé une société dans la DB dolibarr, et retourne l'id de celle-ci.
  208. */
  209. public function createSociety(Organization $organization, bool $client = false): mixed
  210. {
  211. $body = [
  212. 'name' => $organization->getName(),
  213. 'client' => $client ? 1 : 2,
  214. 'code_client' => -1,
  215. 'import_key' => 'crm',
  216. 'array_options' => ['options_2iopen_organization_id' => $organization->getId()],
  217. ];
  218. /** @var Response $response */
  219. $response = $this->post('/thirdparties', $body);
  220. return json_decode($response->getContent(), true);
  221. }
  222. /**
  223. * Delete the organization from Dolibarr.
  224. *
  225. * @throws \JsonException
  226. * @throws TransportExceptionInterface
  227. */
  228. public function switchSocietyToProspect(int $organizationId): void
  229. {
  230. $socId = $this->getSociety($organizationId)['id'];
  231. $res = $this->put(
  232. "thirdparties/$socId",
  233. ['client' => 2],
  234. );
  235. if ($res->getStatusCode() !== 200) {
  236. throw new HttpException($res->getStatusCode(), 'Error while updating the society in Dolibarr');
  237. }
  238. }
  239. /**
  240. * @return array<string, string|number> The resulting document. Ex :
  241. * {
  242. * "filename": "CO2502-0380.pdf",
  243. * "content-type": "application/pdf",
  244. * "filesize": 10660,
  245. * "content": "JVBERi0xLjcKJeLjz9MKNyAwIG9iago8PCAvV...",
  246. * "encoding": "base64"
  247. * }
  248. *
  249. * @throws \JsonException
  250. */
  251. public function downloadBillingDocPdf(string $type, string $docRef): array
  252. {
  253. if (!DolibarrDocTypeEnum::tryFrom($type)) {
  254. throw new \InvalidArgumentException(sprintf('Invalid type "%s" provided. Allowed values are: %s', $type, implode(', ', array_map(fn ($t) => $t->value, DolibarrDocTypeEnum::cases()))));
  255. }
  256. $route = 'documents/download?modulepart='.$type.'&original_file='.urlencode("$docRef/$docRef.pdf");
  257. return $this->getJsonContent($route);
  258. }
  259. }