Przeglądaj źródła

add basic structure for sync service

Olivier Massot 3 lat temu
rodzic
commit
2062d3e036

+ 22 - 0
src/Service/Dolibarr/DolibarrApiService.php

@@ -68,4 +68,26 @@ class DolibarrApiService extends ApiRequestService
             return [];
         }
     }
+
+    /**
+     * Get all the societies which are Opentalent active client
+     * @throws HttpException
+     */
+    public function getAllClients(): array
+    {
+        return $this->getJsonContent(
+            "thirdparties",
+            ["sqlfilters" => "client=1"]);
+    }
+
+    /**
+     * Get all the contacts that have a non-null personId
+     * @throws HttpException
+     */
+    public function getAllOpentalentContacts(): array
+    {
+        return $this->getJsonContent(
+            "contacts",
+            ["sqlfilters" => "(t.person_id:>:0)"]);
+    }
 }

+ 0 - 8
src/Service/Dolibarr/DolibarrSync/DolibarrSyncJob.php

@@ -1,8 +0,0 @@
-<?php
-
-namespace App\Service\Dolibarr\DolibarrSync;
-
-class DolibarrSyncJob
-{
-
-}

+ 103 - 0
src/Service/Dolibarr/DolibarrSync/DolibarrSyncOperation.php

@@ -2,7 +2,110 @@
 
 namespace App\Service\Dolibarr\DolibarrSync;
 
+use App\Service\Dolibarr\DolibarrApiService;
+use HttpException;
+use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
+use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
+use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
+use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
+use Symfony\Contracts\Service\Attribute\Required;
+
+/**
+ * Single synchronization operation, corresponding to a single request
+ * to the Dolibarr API
+ */
 class DolibarrSyncOperation
 {
+    const STATUS_READY = 0;
+    const STATUS_PENDING = 1;
+    const STATUS_DONE = 2;
+    const STATUS_ERROR = 3;
+
+    private DolibarrApiService $dolibarrApiService;
+    private int $status = self::STATUS_READY;
+    private string $label;
+    private string $method;
+    private string $path;
+    private array $parameters;
+    private string $errorMessage = "";
+
+    #[Required]
+    public function setDolibarrApiService(DolibarrApiService $dolibarrApiService) {
+        $this->dolibarrApiService = $dolibarrApiService;
+    }
+
+    public function __construct(string $label, string $method, string $path, array $parameters = []) {
+        $this->label = $label;
+        $this->method = $method;
+        $this->path = $path;
+        $this->parameters = $parameters;
+    }
+
+    /**
+     * Execute the operation and update its status according to the result
+     *
+     * @throws HttpException
+     */
+    public function execute() {
+        $this->status = self::STATUS_PENDING;
+        try {
+            $this->dolibarrApiService->request($this->method, $this->path, $this->parameters);
+            $this->status = self::STATUS_DONE;
+        } catch (ClientExceptionInterface | TransportExceptionInterface | RedirectionExceptionInterface | ServerExceptionInterface $e) {
+            $this->status = self::STATUS_ERROR;
+            $this->errorMessage = '' . $e;
+        }
+    }
+
+    /**
+     * @return string
+     */
+    public function getLabel(): string
+    {
+        return $this->label;
+    }
+
+    /**
+     * @return int
+     */
+    public function getStatus(): int
+    {
+        return $this->status;
+    }
+
+    /**
+     * @return string
+     */
+    public function getMethod(): string
+    {
+        return $this->method;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPath(): string
+    {
+        return $this->path;
+    }
+
+    /**
+     * @return array
+     */
+    public function getParameters(): array
+    {
+        return $this->parameters;
+    }
+
+    /**
+     * @return string
+     */
+    public function getErrorMessage(): string
+    {
+        return $this->errorMessage;
+    }
 
+    public function __toString(): string {
+        return $this->getLabel() . " > " . $this->getMethod() . " " . $this->getPath() . " " . json_encode($this->getParameters());
+    }
 }

+ 139 - 5
src/Service/Dolibarr/DolibarrSync/DolibarrSyncService.php

@@ -1,8 +1,13 @@
 <?php
 
-namespace App\Service\Dolibarr;
+namespace App\Service\Dolibarr\DolibarrSync;
 
+use App\Entity\Core\AddressPostal;
+use App\Entity\Organization\OrganizationAddressPostal;
 use App\Repository\Organization\OrganizationRepository;
+use App\Service\Dolibarr\DolibarrApiService;
+use Exception;
+use HttpException;
 
 /**
  * Push the data from the Opentalent DB into the Dolibarr DB, trough both applications
@@ -13,18 +18,147 @@ use App\Repository\Organization\OrganizationRepository;
 class DolibarrSyncService
 {
     public function __construct(
-        private OrganizationRepository $organizationRepository
+        private OrganizationRepository $organizationRepository,
+        private DolibarrApiService $dolibarrApiService
     ) {}
 
     /**
      * Performs a scan, comparing data from the Opentalent DB and the data returned
      * by the Dolibarr API
      *
-     * Returns an array of DolibarrSyncOperation
+     * Errors during the scan are recorded in the $this->scanErrors
+     *
+     * Returns an array of DolibarrSyncOperations
+     *
+     * @return array<DolibarrSyncOperation>
+     * @throws HttpException
      */
-    public function scan() {
-        foreach ($this->organizationRepository->getAll() as $organization) {
+    public function scan(): array {
+
+        // Index the dolibarr clients by organization ids
+        $dolibarrClientsIndex = [];
+        foreach ($this->dolibarrApiService->getAllClients() as $clientData) {
+            if (!$clientData["array_options"]["2iopen_organization_id"] > 0) {
+                $this->logScanError(
+                    "Missing organization id : " . $clientData["name"] . "(" . $clientData["code_client"] .")"
+                );
+                continue;
+            }
+
+            $dolibarrClientsIndex[$clientData["organization_id"]] = $clientData;
+        }
+
+        // Index the dolibarr contacts by person ids
+        $dolibarrContactsIndex = [];
+        foreach ($this->dolibarrApiService->getAllOpentalentContacts() as $contactData) {
+            if (!$contactData["array_options"]["2iopen_person_id"] > 0) {
+                $this->logScanError(
+                    "Missing person id : " . $contactData["name"] . "(" . $clientData["code_client"] .")"
+                );
+                continue;
+            }
+
+            $dolibarrContactsIndex[$contactData["organization_id"]] = $contactData;
+        }
+
+        // Loop over the Opentalent organizations, and create the operations list
+        $operations = [];
+        foreach ($this->organizationRepository->findAll() as $organization) {
+            if (!isset($dolibarrClientsIndex["organization_id"])) {
+                // this organization is not a client, probably a federation member
+                continue;
+            }
+
+            $dolibarrClient = $dolibarrClientsIndex[$organization->getId()];
+
+            // ** Sync contact data of the client
+            // Postal address
+            /** @var AddressPostal | null */
+            $mainAddress = null;
+            foreach ($organization->getOrganizationAddressPostals() as $postalAddress) {
+                if ($postalAddress->getType() == 'PRINCIPAL') {
+                    $mainAddress = $postalAddress->getAddress();
+                }
+            }
+
+            if ($mainAddress !== null) {
+                $params = [];
+
+                $streetAddress = implode('\n', array_filter([
+                    trim($mainAddress->getStreetAddress()),
+                    trim($mainAddress->getStreetAddressSecond()),
+                    trim($mainAddress->getStreetAddressThird())
+                ]), function ($x) { return $x !== null and strlen($x) > 0; });
+
+                if ($streetAddress !== $dolibarrClient['address']) {
+                    $params['address'] = $streetAddress;
+                }
+
+                if ($mainAddress->getPostalCode() !== $dolibarrClient['zip']) {
+                    $params['zip'] = $mainAddress->getPostalCode();
+                }
+
+                if ($mainAddress->getAddressCity() !== $dolibarrClient['town']) {
+                    $params['town'] = $mainAddress->getAddressCity();
+                }
+
+                if ($params) {
+                    $operations[] = new DolibarrSyncOperation(
+                        'Organization ' . $organization->getId() . ': update address',
+                        'PUT',
+                        'thirdparties/' . $dolibarrClient['id'],
+                        $params
+                    );
+                }
+            }
+        }
 
+        return $operations;
+    }
+
+    /**
+     * Execute the operations listed with the DolibarrSyncService::scan method
+     *
+     * Returns an array of DolibarrSyncOperations
+     *
+     * @param array<DolibarrSyncOperation> $operations
+     * @return array<DolibarrSyncOperation>
+     * @throws Exception
+     */
+    public function execute(array $operations): array
+    {
+        foreach ($operations as $operation) {
+            if ($operation->getStatus() !== DolibarrSyncOperation::STATUS_READY) {
+                // operation has already been treated
+                continue;
+            }
+            $operation->execute();
         }
+
+        return $operations;
+    }
+
+    /**
+     * Scan and execute the sync process
+     *
+     * @throws HttpException
+     * @return array<DolibarrSyncOperation>
+     * @throws Exception
+     */
+    public function run(): array
+    {
+        $operations = $this->scan();
+
+        $this->execute($operations);
+
+        return $operations;
+    }
+
+    /**
+     * Log a new scanning error
+     * @param $errorMsg
+     */
+    private function logScanError($errorMsg) {
+        // TODO : implement
     }
 }