Bläddra i källkod

Merge branch 'feature/dolibarr_service' into develop

Olivier Massot 4 år sedan
förälder
incheckning
83aef382a8

+ 5 - 1
.env

@@ -41,4 +41,8 @@ JWT_PASSPHRASE=opentalent
 
 ###> opentalent config folder ###
 OPENTALENT_CONFIG=/config/opentalent
-###< opentalent config folder ###
+###< opentalent config folder ###
+
+###> dolibarr client ###
+DOLIBARR_BASE_URI='https://prod-erp.2iopenservice.com/api/index.php/'
+###< dolibarr client ###

+ 2 - 0
config/packages/framework.yaml

@@ -22,3 +22,5 @@ framework:
                 base_uri: 'https://entreprise.data.gouv.fr/api/sirene/v3/etablissements/'
             openstreetmap:
                 base_uri: 'https://nominatim.openstreetmap.org/'
+            dolibarr_client:
+                base_uri: '%env(DOLIBARR_BASE_URI)%'

+ 39 - 75
src/ApiResources/Dolibarr/DolibarrAccount.php

@@ -5,173 +5,137 @@ namespace App\ApiResources\Dolibarr;
 
 use ApiPlatform\Core\Annotation\ApiProperty;
 use ApiPlatform\Core\Annotation\ApiResource;
+use Symfony\Component\Serializer\Annotation\Groups;
 
 /**
  * Données de l'organization retournées par l'API Dolibarr
- *
- * @ApiResource(
- *     compositeIdentifier=false,
- *     itemOperations={
- *         "get"={
- *             "method"="GET",
- *             "path"="/dolibarr/account/{organizationId}"
- *          }
- *     }
- * )
+ * (aussi nommé 'ThirdParty' ou 'Society' dans dolibarr)
  */
+#[ApiResource(
+    itemOperations: [
+        'get' => [
+            'method' => 'GET',
+            'path' => '/dolibarr/account/{organizationId}',
+            'requirements' => ['organizationId' => '\d+'],
+            'normalization_context' => [
+                'groups' => ['dolibarr_get']
+            ],
+        ],
+    ],
+    compositeIdentifier: false,
+)]
 class DolibarrAccount
 {
-    /**
-     * @var int
-     * @ApiProperty(identifier=true)
-     */
+    #[ApiProperty(identifier: true)]
+    #[Groups('dolibarr_get')]
     private int $organizationId;
+
     /**
      * Dolibarr societies pk
-     * @var int
      */
+    #[Groups('dolibarr_get')]
     private int $socId;
+
     /**
      * Opentalent client ref
-     * @var string
      */
-    private string $clientNumber;
+    #[Groups('dolibarr_get')]
+    private string $clientNumber = "";
+
     /**
      * Opentalent product owned
-     * @var string
      */
-    private string $product;
+    #[Groups('dolibarr_get')]
+    private string $product = "";
+
     /**
-     * Services currently actives
-     * @var array
+     * Contract and services currently active
      */
-    private array $services;
+    #[Groups('dolibarr_get')]
+    private ?object $contract = null;
+
     /**
      * Sms credit remaining
-     * @var string
      */
-    private string $smsCredit;
+    #[Groups('dolibarr_get')]
+    private string $smsCredit = "";
+
     /**
      * Last bills
-     * @var array
      */
-    private array $bills;
+    #[Groups('dolibarr_get')]
+    private array $bills = [];
 
-    /**
-     * @return int
-     */
     public function getOrganizationId(): int
     {
         return $this->organizationId;
     }
 
-    /**
-     * @param int $organizationId
-     */
     public function setOrganizationId(int $organizationId): void
     {
         $this->organizationId = $organizationId;
     }
 
-    /**
-     * @return int
-     */
     public function getSocId(): int
     {
         return $this->socId;
     }
 
-    /**
-     * @param int $socId
-     */
     public function setSocId(int $socId): void
     {
         $this->socId = $socId;
     }
 
-    /**
-     * @return string
-     */
     public function getClientNumber(): string
     {
         return $this->clientNumber;
     }
 
-    /**
-     * @param string $clientNumber
-     */
     public function setClientNumber(string $clientNumber): void
     {
         $this->clientNumber = $clientNumber;
     }
 
-    /**
-     * @return string
-     */
     public function getProduct(): string
     {
         return $this->product;
     }
 
-    /**
-     * @param string $product
-     */
     public function setProduct(string $product): void
     {
         $this->product = $product;
     }
 
-    /**
-     * @return array
-     */
-    public function getServices(): array
+    public function getContract(): ?object
     {
-        return $this->services;
+        return $this->contract;
     }
 
-    /**
-     * @param array $services
-     */
-    public function setServices(array $services): void
+    public function setContract(?object $contract): void
     {
-        $this->services = $services;
+        $this->contract = $contract;
     }
 
-    /**
-     * @return string
-     */
     public function getSmsCredit(): string
     {
         return $this->smsCredit;
     }
 
-    /**
-     * @param string $smsCredit
-     */
     public function setSmsCredit(string $smsCredit): void
     {
         $this->smsCredit = $smsCredit;
     }
 
-    /**
-     * @return array
-     */
     public function getBills(): array
     {
         return $this->bills;
     }
 
-    /**
-     * @param array $bills
-     */
     public function setBills(array $bills): void
     {
         $this->bills = $bills;
     }
 
-    /**
-     * @param DolibarrBill $bill
-     */
     public function addBill(DolibarrBill $bill): void
     {
         $this->bills[] = $bill;

+ 59 - 53
src/ApiResources/Dolibarr/DolibarrBill.php

@@ -5,92 +5,88 @@ namespace App\ApiResources\Dolibarr;
 
 use ApiPlatform\Core\Annotation\ApiProperty;
 use ApiPlatform\Core\Annotation\ApiResource;
+use Symfony\Component\Serializer\Annotation\Groups;
 
 /**
  * Bill of a society, retrieved from dolibarr
- *
- * @ApiResource(
- *     compositeIdentifier=false,
- *     collectionOperations={
- *         "get"={
- *             "method"="GET",
- *             "path"="/dolibarr/bills/{socId}"
- *          }
- *     }
- * )
  */
+#[ApiResource(
+    collectionOperations: [
+        'get' => [
+            'method' => 'GET',
+            'path' => '/dolibarr/bills/{socId}',
+            'requirements' => ['socId' => '\d+'],
+            'normalization_context' => [
+                'groups' => ['dolibarr_get']
+            ]
+        ],
+    ]
+)]
 class DolibarrBill
 {
     /**
-     * @var string
-     * @ApiProperty(identifier=true)
+     * Id of the dolibarr bill ( = invoice)
      */
-    private string $billId;
+    #[ApiProperty(identifier: true)]
+    #[Groups('dolibarr_get')]
+    private int $id;
+
     /**
      * Id of the society
-     * @var int
      */
+    #[Groups('dolibarr_get')]
     private int $socId;
+
     /**
      * Date of the bill
-     * @var int
      */
-    private int $date;
+    #[Groups('dolibarr_get')]
+    private \DateTime $date;
+
     /**
-     * Amount incl VAT
-     * @var float
+     * Amount (tax excluded)
      */
-    private float $amount;
+    #[Groups('dolibarr_get')]
+    private float $taxExcludedAmount;
+
     /**
-     * Is the bill paid or not
-     * @var bool
+     * Amount (tax included)
      */
-    private bool $paid;
+    #[Groups('dolibarr_get')]
+    private float $taxIncludedAmount;
 
     /**
-     * @return string
+     * Is the bill paid or not
      */
-    public function getBillId(): string
+    #[Groups('dolibarr_get')]
+    private bool $paid;
+
+    public function getId(): int
     {
-        return $this->billId;
+        return $this->id;
     }
 
-    /**
-     * @param string $billId
-     */
-    public function setBillId(string $billId): void
+    public function setId(int $id): void
     {
-        $this->billId = $billId;
+        $this->id = $id;
     }
 
-    /**
-     * @return int
-     */
     public function getSocId(): int
     {
         return $this->socId;
     }
 
-    /**
-     * @param int $socId
-     */
     public function setSocId(int $socId): void
     {
         $this->socId = $socId;
     }
 
-    /**
-     * @return int
-     */
-    public function getDate(): int
+    public function getDate(): \DateTime
     {
         return $this->date;
     }
 
-    /**
-     * @param int $date
-     */
-    public function setDate(int $date): void
+    public function setDate(\DateTime $date): void
     {
         $this->date = $date;
     }
@@ -98,30 +94,40 @@ class DolibarrBill
     /**
      * @return float
      */
-    public function getAmount(): float
+    public function getTaxExcludedAmount(): float
     {
-        return $this->amount;
+        return $this->taxExcludedAmount;
     }
 
     /**
-     * @param float $amount
+     * @param float $taxExcludedAmount
      */
-    public function setAmount(float $amount): void
+    public function setTaxExcludedAmount(float $taxExcludedAmount): void
     {
-        $this->amount = $amount;
+        $this->taxExcludedAmount = $taxExcludedAmount;
     }
 
     /**
-     * @return bool
+     * @return float
      */
-    public function getPaid(): bool
+    public function getTaxIncludedAmount(): float
     {
-        return $this->paid;
+        return $this->taxIncludedAmount;
     }
 
     /**
-     * @param bool $paid
+     * @param float $taxIncludedAmount
      */
+    public function setTaxIncludedAmount(float $taxIncludedAmount): void
+    {
+        $this->taxIncludedAmount = $taxIncludedAmount;
+    }
+
+    public function getPaid(): bool
+    {
+        return $this->paid;
+    }
+
     public function setPaid(bool $paid): void
     {
         $this->paid = $paid;

+ 80 - 0
src/ApiResources/Dolibarr/DolibarrContract.php

@@ -0,0 +1,80 @@
+<?php
+declare(strict_types=1);
+
+namespace App\ApiResources\Dolibarr;
+
+use ApiPlatform\Core\Annotation\ApiProperty;
+use ApiPlatform\Core\Annotation\ApiResource;
+use Symfony\Component\Serializer\Annotation\Groups;
+
+/**
+ * Contract of a society, retrieved from dolibarr
+ */
+#[ApiResource(
+    itemOperations: [
+        'get' => [
+            'method' => 'GET',
+            'path' => '/dolibarr/contract/{ref}',
+            'requirements' => ['socId' => '\d+'],
+            'normalization_context' => [
+                'groups' => ['dolibarr_get']
+            ]
+        ],
+    ]
+)]
+class DolibarrContract
+{
+    /**
+     * Reference of the dolibarr contract
+     */
+    #[ApiProperty(identifier: true)]
+    #[Groups('dolibarr_get')]
+    private string $ref;
+
+    /**
+     * Id of the society
+     */
+    #[Groups('dolibarr_get')]
+    private int $socId;
+
+    /**
+     * Lines (services) included in the current contract
+     */
+    #[Groups('dolibarr_get')]
+    private array $lines = [];
+
+    public function getRef(): string
+    {
+        return $this->ref;
+    }
+
+    public function setRef(string $ref): void
+    {
+        $this->ref = $ref;
+    }
+
+    public function getSocId(): int
+    {
+        return $this->socId;
+    }
+
+    public function setSocId(int $socId): void
+    {
+        $this->socId = $socId;
+    }
+
+    public function getLines(): array
+    {
+        return $this->lines;
+    }
+
+    public function setLines(array $lines): void
+    {
+        $this->lines = $lines;
+    }
+
+    public function addLine(object $line): void
+    {
+        $this->lines[] = $line;
+    }
+}

+ 120 - 0
src/ApiResources/Dolibarr/DolibarrContractLine.php

@@ -0,0 +1,120 @@
+<?php
+declare(strict_types=1);
+
+namespace App\ApiResources\Dolibarr;
+
+use ApiPlatform\Core\Annotation\ApiProperty;
+use ApiPlatform\Core\Annotation\ApiResource;
+use Symfony\Component\Serializer\Annotation\Groups;
+
+/**
+ *  Lines (services) included in a society contract, as retrieved from dolibarr
+ */
+#[ApiResource(
+    collectionOperations: [
+        'get' => [
+            'method' => 'GET',
+            'path' => '/dolibarr/contract-lines/{contractId}',
+            'requirements' => ['contractId' => '\d+'],
+            'normalization_context' => [
+                'groups' => ['dolibarr_get']
+            ]
+        ],
+    ]
+)]
+class DolibarrContractLine
+{
+    #[ApiProperty(identifier: true)]
+    #[Groups('dolibarr_get')]
+    private int $id;
+
+    /**
+     * Id of the contract's line
+     */
+    #[Groups('dolibarr_get')]
+    private int $contractId;
+
+    /**
+     * Reference of the contracted service ( = product's reference)
+     */
+    #[Groups('dolibarr_get')]
+    private string $serviceRef;
+
+    /**
+     * Label of the contracted service
+     */
+    #[Groups('dolibarr_get')]
+    private string $serviceLabel;
+
+    /**
+     * Service active from date ...
+     */
+    #[Groups('dolibarr_get')]
+    private \DateTime $dateStart;
+
+    /**
+     * Service active to date ...
+     */
+    #[Groups('dolibarr_get')]
+    private \DateTime $dateEnd;
+
+    public function getId(): int
+    {
+        return $this->id;
+    }
+
+    public function setId(int $id): void
+    {
+        $this->id = $id;
+    }
+
+    public function getContractId(): int
+    {
+        return $this->contractId;
+    }
+
+    public function setContractId(int $contractId): void
+    {
+        $this->contractId = $contractId;
+    }
+
+    public function getServiceRef(): string
+    {
+        return $this->serviceRef;
+    }
+
+    public function setServiceRef(string $serviceRef): void
+    {
+        $this->serviceRef = $serviceRef;
+    }
+
+    public function getServiceLabel(): string
+    {
+        return $this->serviceLabel;
+    }
+
+    public function setServiceLabel(string $serviceLabel): void
+    {
+        $this->serviceLabel = $serviceLabel;
+    }
+
+    public function getDateStart(): \DateTime
+    {
+        return $this->dateStart;
+    }
+
+    public function setDateStart(\DateTime $dateStart): void
+    {
+        $this->dateStart = $dateStart;
+    }
+
+    public function isDateEnd(): \DateTime
+    {
+        return $this->dateEnd;
+    }
+
+    public function setDateEnd(\DateTime $dateEnd): void
+    {
+        $this->dateEnd = $dateEnd;
+    }
+}

+ 45 - 8
src/DataProvider/Dolibarr/DolibarrAccountDataProvider.php

@@ -7,6 +7,8 @@ use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
 use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
 use App\ApiResources\Dolibarr\DolibarrAccount;
 use App\ApiResources\Dolibarr\DolibarrBill;
+use App\ApiResources\Dolibarr\DolibarrContract;
+use App\ApiResources\Dolibarr\DolibarrContractLine;
 use App\Service\Dolibarr\DolibarrService;
 
 /**
@@ -15,6 +17,13 @@ use App\Service\Dolibarr\DolibarrService;
  */
 final class DolibarrAccountDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
 {
+    const PRODUCT_MAPPING = [
+        1 => 'PRODUCT_ARTIST',   # OT Artist
+        2 => 'PRODUCT_ARTIST_PREMIUM',   # OT Artist Premium
+        3 => 'PRODUCT_SCHOOL',   # OT School Standard
+        4 => 'PRODUCT_SCHOOL_PREMIUM',   # OT School Premium
+        5 => 'PRODUCT_MANAGER',   # OT Manager
+    ];
     private DolibarrService $dolibarrService;
 
     public function __construct(
@@ -34,24 +43,52 @@ final class DolibarrAccountDataProvider implements ItemDataProviderInterface, Re
         $dolibarrAccount = new DolibarrAccount();
 
         $accountData = $this->dolibarrService->getSociety($id);
-        $billsData = $this->dolibarrService->getBills($accountData['id']);
 
         $dolibarrAccount->setOrganizationId($id);
-        $dolibarrAccount->setSocId($accountData['id']);
+        $dolibarrAccount->setSocId((int)$accountData['id']);
         $dolibarrAccount->setClientNumber($accountData['code_client']);
-        $dolibarrAccount->setProduct($accountData['array_options']['options_2iopen_software_used']);
-        // $dolibarrAccount->setSmsCredit();
-        // $dolibarrAccount->setServices($accountData['code_client']);
+        if ($accountData['array_options']['options_2iopen_software_used']) {
+            $dolibarrAccount->setProduct(
+                self::PRODUCT_MAPPING[(int)$accountData['array_options']['options_2iopen_software_used']]
+            );
+        }
+
+        // Get active contract and services
+        $contractData = $this->dolibarrService->getActiveContract($dolibarrAccount->getSocId());
+        if ($contractData !== null) {
+            $contract = new DolibarrContract();
+            $contract->setRef($contractData['ref']);
+            $contract->setSocId((int)$contractData['socid']);
 
+            foreach ($contractData['lines'] as $lineData) {
+                $line = new DolibarrContractLine();
+                $line->setId((int)$lineData['id']);
+                $line->setContractId((int)$lineData['fk_contrat']);
+                $line->setServiceRef($lineData['product_ref']);
+                $line->setServiceLabel($lineData['product_label']);
+                $line->setDateStart(new \DateTime(date('c', $lineData['date_start'])));
+                $line->setDateEnd(new \DateTime(date('c', $lineData['date_end'])));
+                $contract->addLine($line);
+            }
+
+            $dolibarrAccount->setContract($contract);
+        }
+
+        // get bills
+        $billsData = $this->dolibarrService->getBills($dolibarrAccount->getSocId());
         foreach ($billsData as $billData) {
             $bill = new DolibarrBill();
-            $bill->setBillId($billData['id']);
+            $bill->setId((int)$billData['id']);
             $bill->setSocId($dolibarrAccount->getSocId());
-            $bill->setAmount($billData['total_ttc']);
-            $bill->setDate($billData['date']);
+            $bill->setTaxExcludedAmount((float)$billData['total_ht']);
+            $bill->setTaxIncludedAmount((float)$billData['total_ttc']);
+            $bill->setDate(new \DateTime(date('c', $billData['date'])));
             $bill->setPaid((bool)$billData['paye']);
             $dolibarrAccount->addBill($bill);
         }
+
+        // $dolibarrAccount->setSmsCredit();
+
         return $dolibarrAccount;
     }
 }

+ 28 - 8
src/Service/Dolibarr/DolibarrService.php

@@ -7,13 +7,16 @@ use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
 use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
 
+/**
+ * Service d'appel à l'API dolibarr
+ */
 class DolibarrService
 {
     private HttpClientInterface $client;
 
-    function __construct(HttpClientInterface $client)
+    function __construct(HttpClientInterface $dolibarr_client)
     {
-        $this->client = $client;
+        $this->client = $dolibarr_client;
     }
 
     /**
@@ -23,7 +26,21 @@ class DolibarrService
      * @return array
      */
     public function getSociety(int $organizationId): array {
-        return $this->request("api/index.php/thirdparties?sqlfilters=ref_int%3D" . $organizationId);
+        return $this->request("thirdparties?sqlfilters=" . urlencode("ref_int=" . $organizationId))[0];
+    }
+
+    /**
+     * Get the first active contract for the given dolibarr society
+     *
+     * @param int $socId
+     * @return array|null
+     */
+    public function getActiveContract(int $socId): ?array {
+        try {
+            return $this->request("contracts?limit=1&sqlfilters=statut%3D1&thirdparty_ids%3D" . $socId)[0];
+        } catch (NotFoundHttpException) {
+            return null;
+        }
     }
 
     /**
@@ -33,7 +50,11 @@ class DolibarrService
      * @return array
      */
     public function getBills(int $socId): array {
-        return $this->request("invoices?sortfield=t.date&sortorder=DESC&limit=5&thirdparty_ids=" . $socId);
+        try {
+            return $this->request("invoices?sortfield=datef&sortorder=DESC&limit=5&thirdparty_ids=" . $socId);
+        } catch (NotFoundHttpException) {
+            return [];
+        }
     }
 
     /**
@@ -62,21 +83,20 @@ class DolibarrService
      * @return array
      * @throws NotFoundHttpException
      */
-    private function request(string $path, string $method = 'GET', string | null $body = null): array
+    private function request(string $path, string $method = 'GET', string $body = ''): array
     {
         try {
             $options = [
                 'headers' => [
                     'Accept'=> 'application/json',
-                    'DOLAPIKEY' => "Bocc4zC0J186v8J6QCqu7DnoIw4I7mCJ"
+                    'DOLAPIKEY' => 'Bocc4zC0J186v8J6QCqu7DnoIw4I7mCJ'
                 ]
             ];
 
             if ($body !== null) {
                 $options['body'] = $body;
             }
-
-            $uri = 'api/index.php/' . ltrim($path, '/');
+            $uri = ltrim($path, '/');
             $response = $this->client->request($method, $uri, $options);
             return json_decode($response->getContent(), true);
         } catch (HttpExceptionInterface | TransportExceptionInterface $e) {