Переглянути джерело

[Administration] Dolibarr : génération automatique des factures producteurs #1182

feature/souke
Guillaume Bourgeois 1 рік тому
джерело
коміт
9fb4aa0545
19 змінених файлів з 277 додано та 8 видалено
  1. +16
    -1
      backend/controllers/ProducerAdminController.php
  2. +3
    -0
      backend/views/producer-admin/_form.php
  3. +11
    -1
      backend/views/producer-admin/index.php
  4. +1
    -0
      backend/views/producer-price-range-admin/create.php
  5. +3
    -2
      backend/views/producer-price-range-admin/update.php
  6. +62
    -0
      common/components/AbstractApi.php
  7. +51
    -0
      common/components/DolibarrApi.php
  8. +7
    -0
      common/config/main.php
  9. +8
    -0
      common/logic/AbstractUtils.php
  10. +5
    -1
      common/logic/Producer/Producer/Model/Producer.php
  11. +6
    -0
      common/logic/Producer/Producer/Repository/ProducerRepository.php
  12. +52
    -0
      common/logic/Producer/Producer/Service/DolibarrProducerUtils.php
  13. +3
    -1
      common/logic/Producer/Producer/Wrapper/ProducerContainer.php
  14. +2
    -0
      common/logic/Producer/Producer/Wrapper/ProducerManager.php
  15. +2
    -0
      common/logic/Producer/ProducerPriceRange/Model/ProducerPriceRange.php
  16. +12
    -0
      common/logic/Producer/ProducerPriceRange/Repository/ProducerPriceRangeRepository.php
  17. +1
    -1
      common/logic/UtilsInterface.php
  18. +2
    -1
      composer.json
  19. +30
    -0
      console/migrations/m230905_091112_add_columns_dolibarr.php

+ 16
- 1
backend/controllers/ProducerAdminController.php Переглянути файл

@@ -170,6 +170,21 @@ class ProducerAdminController extends BackendController
return $this->redirect(['index']);
}

public function actionDolibarr(int $id)
{
$producerManager = $this->getProducerManager();
$producer = $this->findProducer($id);
if($producer->dolibarr_socid) {
$producerManager->generateDolibarrProducerInvoice($producer);
$this->setFlash('success', "Facture générée sur Dolibarr pour le producteur <strong>".$producer->name."</strong>");
}
else {
$this->setFlash('error', "Dolibarr : l'id user du producteur doit être défini");
}

return $this->redirect(['index']);
}

public function actionUserTransfer($fromProducerId, $toProducerId, $withOrders = 1)
{
$producerManager = $this->getProducerManager();
@@ -248,7 +263,7 @@ class ProducerAdminController extends BackendController
if (($model = $producerManager->findOneProducerById($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
throw new NotFoundHttpException('Producteur introuvable.');
}
}


+ 3
- 0
backend/views/producer-admin/_form.php Переглянути файл

@@ -73,6 +73,9 @@ use common\logic\Producer\Producer\Model\Producer;
1 => 'Oui'
]); ?>
<?= $form->field($model, 'option_billing_permanent_transfer_amount') ?>
<?= $form->field($model, 'dolibarr_socid') ?>
<?= $form->field($model, 'dolibarr_product_id') ?>

<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Ajouter' : 'Modifier', ['class' => 'btn btn-success']) ?>
</div>

+ 11
- 1
backend/views/producer-admin/index.php Переглянути файл

@@ -218,7 +218,7 @@ $this->addButton(['label' => 'Nouveau producteur <span class="glyphicon glyphico
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{update} {billing} {alwaysdata}',
'template' => '{update} {dolibarr} {billing} {alwaysdata}',
'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'],
'buttons' => [
@@ -232,6 +232,16 @@ $this->addButton(['label' => 'Nouveau producteur <span class="glyphicon glyphico
]
);
},
'dolibarr' => function ($url, $model) {
return Html::a(
'<span class="glyphicon glyphicon-paste"></span>',
$url,
[
'title' => 'Générer la facture sur Dolibarr',
'class' => 'btn btn-default'
]
);
},
'billing' => function ($url, $model) {
return Html::a(
'<span class="glyphicon glyphicon-euro"></span>',

+ 1
- 0
backend/views/producer-price-range-admin/create.php Переглянути файл

@@ -50,6 +50,7 @@ $this->addBreadcrumb('Ajouter') ;
<?= $form->field($model, 'range_begin') ?>
<?= $form->field($model, 'range_end') ?>
<?= $form->field($model, 'price') ?>
<?= $form->field($model, 'dolibarr_product_id') ?>
<div class="form-group">
<?= Html::submitButton('Ajouter', ['class' => 'btn btn-success']) ?>
</div>

+ 3
- 2
backend/views/producer-price-range-admin/update.php Переглянути файл

@@ -39,8 +39,8 @@ termes.
use yii\helpers\Html;
use yii\widgets\ActiveForm;

$this->setTitle('Éditer une taxe') ;
$this->addBreadcrumb(['label' => 'taxe', 'url' => ['index']]) ;
$this->setTitle('Éditer une tranche de prix') ;
$this->addBreadcrumb(['label' => 'tranche de prix', 'url' => ['index']]) ;
$this->addBreadcrumb('Éditer') ;

?>
@@ -50,6 +50,7 @@ $this->addBreadcrumb('Éditer') ;
<?= $form->field($model, 'range_begin') ?>
<?= $form->field($model, 'range_end') ?>
<?= $form->field($model, 'price') ?>
<?= $form->field($model, 'dolibarr_product_id') ?>
<div class="form-group">
<?= Html::submitButton('Ajouter', ['class' => 'btn btn-success']) ?>
</div>

+ 62
- 0
common/components/AbstractApi.php Переглянути файл

@@ -0,0 +1,62 @@
<?php

namespace common\components;

use GuzzleHttp\Client;
use linslin\yii2\curl\Curl;
use Psr\Http\Message\ResponseInterface;

abstract class AbstractApi
{
public string $url;
public array $auth;

public function __construct(string $url, array $auth)
{
$this->url = $url;
$this->auth = $auth;
}

protected function get(string $resource, array $data = [], bool $raw = false)
{
$client = $this->getClient();
$client->setGetParams($data);
return $client->get($this->buildUrl($resource), $raw);
}

protected function post(string $resource, array $data = [], bool $raw = true)
{
$client = $this->getClient();
$client->setPostParams($data);
return $client->post($this->buildUrl($resource), $raw);
}

protected function put(string $resource, array $data = [], bool $raw = true)
{
$client = $this->getClient();
$client->setPostParams($data);
return $client->put($this->buildUrl($resource), $raw);
}

private function getClient()
{
$curl = new Curl();
$curl->setHeader($this->auth[0], $this->auth[1]);
return $curl;
}

public function buildUrl(string $resource): string
{
return $this->url.$resource;
}

protected function getUrl(): string
{
return $this->url;
}

private function getAuth(): array
{
return $this->auth;
}
}

+ 51
- 0
common/components/DolibarrApi.php Переглянути файл

@@ -0,0 +1,51 @@
<?php

namespace common\components;

use Psr\Http\Message\ResponseInterface;

class DolibarrApi extends AbstractApi
{
const RESOURCE_INVOICES = 'invoices';
const RESOURCE_PRODUCTS = 'products';
const RESOURCE_DOCUMENTS = 'documents';

public function createInvoice(int $idUser)
{
return $this->post(self::RESOURCE_INVOICES, [
'socid' => $idUser
]);
}

public function addInvoiceLine(int $idInvoice, int $idProduct)
{
$productArray = $this->getProduct($idProduct);

return $this->post(self::RESOURCE_INVOICES . '/' . $idInvoice . '/lines', [
'fk_product' => $idProduct,
'subprice' => $productArray['price'],
'qty' => 1,
'desc' => $productArray['description']
]);
}

public function validateInvoice(int $idInvoice)
{
return $this->post(self::RESOURCE_INVOICES . '/' . $idInvoice . '/validate', [], false);
}

public function generateInvoicePdf(string $reference)
{
return $this->put(self::RESOURCE_DOCUMENTS . '/builddoc', [
'modulepart' => 'invoice',
'doctemplate' => 'crabe',
'langcode' => 'fr_FR',
'original_file' => $reference.'/'.$reference.'.pdf'
]);
}

public function getProduct(int $idProduct)
{
return $this->get(self::RESOURCE_PRODUCTS . '/' . $idProduct);
}
}

+ 7
- 0
common/config/main.php Переглянути файл

@@ -37,6 +37,7 @@
*/

use common\components\BusinessLogic;
use common\components\DolibarrApi;
use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Document\DeliveryNote\Model\DeliveryNote;
use common\logic\Ticket\Ticket\Model\Ticket;
@@ -129,6 +130,12 @@ return [
'enableStrictParsing' => false,
'rules' => [],
],
'dolibarrApi' => function() {
return new DolibarrApi(
Yii::$app->parameterBag->get('dolibarrApiUrl'),
['DOLAPIKEY', \Yii::$app->parameterBag->get('dolibarrApiKey')]
);
},
'logic' => function () {
return new BusinessLogic();
},

+ 8
- 0
common/logic/AbstractUtils.php Переглянути файл

@@ -0,0 +1,8 @@
<?php

namespace common\logic;

abstract class AbstractUtils extends AbstractService implements UtilsInterface
{

}

+ 5
- 1
common/logic/Producer/Producer/Model/Producer.php Переглянути файл

@@ -151,6 +151,8 @@ class Producer extends ActiveRecordCommon
'option_online_payment_minimum_amount',
'option_document_price_decimals',
'option_billing_reduction_percentage',
'dolibarr_socid',
'dolibarr_product_id'
],
'integer'
],
@@ -415,7 +417,9 @@ class Producer extends ActiveRecordCommon
'option_testimony' => 'Témoignage',
'option_time_saved' => 'Temps gagné / semaine',
'contact_email' => 'Email de contact',
'admin_comment' => 'Commentaire'
'admin_comment' => 'Commentaire',
'dolibarr_socid' => 'Dolibarr : id user',
'dolibarr_product_id' => 'Dolibarr : id produit'
];
}


+ 6
- 0
common/logic/Producer/Producer/Repository/ProducerRepository.php Переглянути файл

@@ -113,6 +113,12 @@ class ProducerRepository extends AbstractRepository
];
}

public function getTurnoverLastMonth(Producer $producer, bool $format = false)
{
$period = date('Y-m', strtotime('-1 month'));
return $this->getTurnover($producer, $period, $format);
}

/**
* Retourne le CA du producteur pour un mois donné
*/

+ 52
- 0
common/logic/Producer/Producer/Service/DolibarrProducerUtils.php Переглянути файл

@@ -0,0 +1,52 @@
<?php

namespace common\logic\Producer\Producer\Service;

use common\components\DolibarrApi;
use common\logic\AbstractUtils;
use common\logic\Producer\Producer\Model\Producer;
use common\logic\Producer\Producer\Repository\ProducerRepository;
use common\logic\Producer\ProducerPriceRange\Repository\ProducerPriceRangeRepository;
use yii\base\ErrorException;

class DolibarrProducerUtils extends AbstractUtils
{
protected DolibarrApi $dolibarrApi;
protected ProducerPriceRangeRepository $producerPriceRangeRepository;
protected ProducerRepository $producerRepository;

public function loadDependencies(): void
{
$this->dolibarrApi = \Yii::$app->dolibarrApi;
$this->producerPriceRangeRepository = $this->loadService(ProducerPriceRangeRepository::class);
$this->producerRepository = $this->loadService(ProducerRepository::class);
}

public function generateDolibarrProducerInvoice(Producer $producer)
{
$idProduct = $this->getDolibarrProductId($producer);
if(!$idProduct) {
throw new ErrorException("Dolibarr : pas d'id product trouvé pour le producteur ".$producer->name);
}

$idInvoice = $this->dolibarrApi->createInvoice($producer->dolibarr_socid);
$this->dolibarrApi->addInvoiceLine($idInvoice, $idProduct);
$responseValidate = $this->dolibarrApi->validateInvoice($idInvoice);
$this->dolibarrApi->generateInvoicePdf($responseValidate['ref']);
}

private function getDolibarrProductId(Producer $producer)
{
if($producer->dolibarr_product_id) {
$idProduct = $producer->dolibarr_product_id;
}
else {
$producerPriceRange = $this->producerPriceRangeRepository->getProducerPriceRangeByTurnover($this->producerRepository->getTurnoverLastMonth($producer));
if($producerPriceRange && $producerPriceRange->dolibarr_product_id) {
$idProduct = $producerPriceRange->dolibarr_product_id;
}
}

return $idProduct;
}
}

+ 3
- 1
common/logic/Producer/Producer/Wrapper/ProducerContainer.php Переглянути файл

@@ -4,6 +4,7 @@ namespace common\logic\Producer\Producer\Wrapper;

use common\logic\AbstractContainer;
use common\logic\Producer\Producer\Repository\ProducerRepository;
use common\logic\Producer\Producer\Service\DolibarrProducerUtils;
use common\logic\Producer\Producer\Service\ProducerBuilder;
use common\logic\Producer\Producer\Service\ProducerDefinition;
use common\logic\Producer\Producer\Service\ProducerSolver;
@@ -18,7 +19,8 @@ class ProducerContainer extends AbstractContainer
ProducerSolver::class,
ProducerRepository::class,
ProducerBuilder::class,
ProducerUtils::class
ProducerUtils::class,
DolibarrProducerUtils::class,
];
}


+ 2
- 0
common/logic/Producer/Producer/Wrapper/ProducerManager.php Переглянути файл

@@ -4,6 +4,7 @@ namespace common\logic\Producer\Producer\Wrapper;

use common\logic\AbstractManager;
use common\logic\Producer\Producer\Repository\ProducerRepository;
use common\logic\Producer\Producer\Service\DolibarrProducerUtils;
use common\logic\Producer\Producer\Service\ProducerBuilder;
use common\logic\Producer\Producer\Service\ProducerDefinition;
use common\logic\Producer\Producer\Service\ProducerSolver;
@@ -15,6 +16,7 @@ use common\logic\Producer\Producer\Service\ProducerUtils;
* @mixin ProducerRepository
* @mixin ProducerBuilder
* @mixin ProducerUtils
* @mixin DolibarrProducerUtils
*/
class ProducerManager extends AbstractManager
{

+ 2
- 0
common/logic/Producer/ProducerPriceRange/Model/ProducerPriceRange.php Переглянути файл

@@ -62,6 +62,7 @@ class ProducerPriceRange extends ActiveRecordCommon
{
return [
[['range_begin', 'range_end', 'price'], 'double'],
[['dolibarr_product_id'], 'integer']
];
}

@@ -75,6 +76,7 @@ class ProducerPriceRange extends ActiveRecordCommon
'range_begin' => 'Début',
'range_end' => 'Fin',
'price' => 'Tarif (HT)',
'dolibarr_product_id' => 'Dolibarr : id produit'
];
}
}

+ 12
- 0
common/logic/Producer/ProducerPriceRange/Repository/ProducerPriceRangeRepository.php Переглянути файл

@@ -45,6 +45,18 @@ class ProducerPriceRangeRepository extends AbstractRepository
return $this->queryProducerPriceRanges()->find();
}

public function getProducerPriceRangeByTurnover(float $turnover = null): ?ProducerPriceRange
{
$producerPriceRangeArray = $this->findProducerPriceRanges();
foreach ($producerPriceRangeArray as $producerPriceRange) {
if ($turnover >= $producerPriceRange->range_begin && $turnover < $producerPriceRange->range_end) {
return $producerPriceRange;
}
}

return null;
}

public function getAmountToBeBilledByTurnover(float $turnover = null, $format = false)
{
$amountToBeBilled = 0;

+ 1
- 1
common/logic/UtilsInterface.php Переглянути файл

@@ -5,4 +5,4 @@ namespace common\logic;
interface UtilsInterface
{

}
}

+ 2
- 1
composer.json Переглянути файл

@@ -35,7 +35,8 @@
"justcoded/yii2-event-listener": "*",
"ext-pdo": "*",
"weluse/yii2-mailjet": "^0.2.0",
"ext-json": "*"
"ext-json": "*",
"ext-curl": "*"
},
"require-dev": {
"yiisoft/yii2-codeception": "*",

+ 30
- 0
console/migrations/m230905_091112_add_columns_dolibarr.php Переглянути файл

@@ -0,0 +1,30 @@
<?php

use yii\db\Migration;
use yii\db\Schema;

/**
* Class m230905_091112_add_columns_dolibarr
*/
class m230905_091112_add_columns_dolibarr extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('producer', 'dolibarr_socid', Schema::TYPE_INTEGER);
$this->addColumn('producer', 'dolibarr_product_id', Schema::TYPE_INTEGER);
$this->addColumn('producer_price_range', 'dolibarr_product_id', Schema::TYPE_INTEGER);
}

/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropColumn('producer', 'dolibarr_socid');
$this->dropColumn('producer', 'dolibarr_product_id');
$this->dropColumn('producer_price_range', 'dolibarr_product_id');
}
}

Завантаження…
Відмінити
Зберегти