Browse Source

Merge branch 'develop'

master
Guillaume Bourgeois 1 year ago
parent
commit
6350a0fed2
100 changed files with 1770 additions and 1393 deletions
  1. +16
    -11
      backend/controllers/AccessController.php
  2. +90
    -0
      backend/controllers/CreditController.php
  3. +1
    -46
      backend/controllers/CronController.php
  4. +2
    -137
      backend/controllers/DevelopmentController.php
  5. +12
    -25
      backend/controllers/OrderController.php
  6. +22
    -5
      backend/controllers/ProducerAdminController.php
  7. +1
    -0
      backend/controllers/SiteController.php
  8. +2
    -2
      backend/controllers/SupportController.php
  9. +155
    -167
      backend/controllers/UserController.php
  10. +4
    -12
      backend/models/CreditForm.php
  11. +79
    -0
      backend/views/credit/index.php
  12. +13
    -11
      backend/views/development/index.php
  13. +1
    -1
      backend/views/distribution/index.php
  14. +2
    -5
      backend/views/layouts/header.php
  15. +11
    -0
      backend/views/layouts/left.php
  16. +3
    -0
      backend/views/producer-admin/_form.php
  17. +53
    -27
      backend/views/producer-admin/index.php
  18. +29
    -7
      backend/views/producer/update.php
  19. +2
    -3
      backend/views/product/_form.php
  20. +2
    -3
      backend/views/product/index.php
  21. +4
    -0
      backend/views/user/_form.php
  22. +24
    -4
      backend/web/css/screen.css
  23. +5
    -0
      backend/web/js/vuejs/producer-update.js
  24. +29
    -0
      backend/web/sass/development/_index.scss
  25. +0
    -1
      common/components/BusinessLogic.php
  26. +0
    -12
      common/components/BusinessLogicTrait.php
  27. +21
    -3
      common/config/main.php
  28. +1
    -1
      common/config/params.php
  29. +18
    -0
      common/events/EntityManagerEvent.php
  30. +62
    -0
      common/helpers/Alwaysdata.php
  31. +7
    -0
      common/helpers/CSV.php
  32. +58
    -0
      common/helpers/Image.php
  33. +1
    -1
      common/helpers/Opendistrib.php
  34. +55
    -66
      common/helpers/Upload.php
  35. +20
    -3
      common/logic/AbstractBuilder.php
  36. +8
    -0
      common/logic/AbstractGenerator.php
  37. +1
    -0
      common/logic/AbstractService.php
  38. +0
    -148
      common/logic/Development/Development/Development.php
  39. +0
    -149
      common/logic/Development/DevelopmentPriority/DevelopmentPriority.php
  40. +2
    -11
      common/logic/Distribution/Distribution/Model/Distribution.php
  41. +3
    -2
      common/logic/Distribution/Distribution/Service/DistributionBuilder.php
  42. +8
    -0
      common/logic/GeneratorInterface.php
  43. +0
    -17
      common/logic/Order/Order/Service/OrderBuilder.php
  44. +0
    -72
      common/logic/Order/OrderStatusHistory/Model/OrderStatusHistory.php
  45. +0
    -25
      common/logic/Order/OrderStatusHistory/Repository/OrderStatusHistoryRepository.php
  46. +0
    -18
      common/logic/Order/OrderStatusHistory/Repository/OrderStatusHistoryRepositoryQuery.php
  47. +0
    -39
      common/logic/Order/OrderStatusHistory/Service/OrderStatusHistoryBuilder.php
  48. +0
    -14
      common/logic/Order/OrderStatusHistory/Service/OrderStatusHistoryDefinition.php
  49. +0
    -35
      common/logic/Order/OrderStatusHistory/Wrapper/OrderStatusHistoryContainer.php
  50. +0
    -21
      common/logic/Order/OrderStatusHistory/Wrapper/OrderStatusHistoryManager.php
  51. +11
    -3
      common/logic/Producer/Producer/Model/Producer.php
  52. +38
    -2
      common/logic/Producer/Producer/Repository/ProducerRepository.php
  53. +12
    -0
      common/logic/Producer/Producer/Repository/ProducerRepositoryQuery.php
  54. +1
    -1
      common/logic/Product/Product/Model/Product.php
  55. +26
    -0
      common/logic/Subscription/Subscription/Event/DistributionObserver.php
  56. +0
    -15
      common/logic/Subscription/Subscription/Event/SubscriptionEventSubscriber.php
  57. +3
    -0
      common/logic/Ticket/Ticket/Model/Ticket.php
  58. +4
    -4
      common/logic/Ticket/Ticket/Service/TicketBuilder.php
  59. +0
    -12
      common/logic/User/CreditHistory/Event/CreditHistoryCreateEvent.php
  60. +0
    -11
      common/logic/User/CreditHistory/Model/CreditHistory.php
  61. +1
    -6
      common/logic/User/CreditHistory/Service/CreditHistoryBuilder.php
  62. +132
    -0
      common/logic/User/CreditHistory/Service/CreditUtils.php
  63. +7
    -0
      common/logic/User/CreditHistory/Wrapper/CreditHistoryContainer.php
  64. +2
    -0
      common/logic/User/CreditHistory/Wrapper/CreditHistoryManager.php
  65. +17
    -0
      common/logic/User/User/Event/TicketObserver.php
  66. +32
    -2
      common/logic/User/User/Repository/UserRepository.php
  67. +18
    -3
      common/logic/User/User/Service/UserBuilder.php
  68. +27
    -8
      common/logic/User/User/Service/UserSolver.php
  69. +19
    -1
      common/logic/User/User/Service/UserUtils.php
  70. +50
    -0
      common/logic/User/User/Service/UsersCreditCsvGenerator.php
  71. +4
    -0
      common/logic/User/User/Wrapper/UserContainer.php
  72. +2
    -0
      common/logic/User/User/Wrapper/UserManager.php
  73. +18
    -0
      common/logic/User/UserProducer/Event/CreditHistoryObserver.php
  74. +0
    -14
      common/logic/User/UserProducer/Event/UserProducerEventSubscriber.php
  75. +19
    -0
      common/logic/User/UserProducer/Repository/UserProducerRepository.php
  76. +7
    -0
      common/logic/User/UserProducer/Repository/UserProducerRepositoryQuery.php
  77. +29
    -20
      common/logic/User/UserProducer/Service/UserProducerBuilder.php
  78. +14
    -0
      common/logic/User/UserProducer/Service/UserProducerSolver.php
  79. +2
    -0
      common/logic/User/UserProducer/Wrapper/UserProducerContainer.php
  80. +46
    -0
      common/mail/newTicketAdmin-html.php
  81. +47
    -0
      common/mail/newTicketAdmin-text.php
  82. +31
    -42
      common/versions/22.10.A.php
  83. +14
    -14
      common/versions/22.11.A.php
  84. +15
    -12
      common/versions/22.11.B.php
  85. +12
    -9
      common/versions/22.12.A.php
  86. +13
    -13
      common/versions/23.1.A.php
  87. +16
    -18
      common/versions/23.3.A.php
  88. +14
    -19
      common/versions/23.4.A.php
  89. +17
    -13
      common/versions/23.6.A.php
  90. +23
    -22
      common/versions/23.6.B.php
  91. +14
    -10
      common/versions/23.7.A.php
  92. +15
    -11
      common/versions/23.8.A.php
  93. +19
    -0
      common/versions/23.8.B.php
  94. +43
    -0
      common/versions/_macros.php
  95. +3
    -1
      composer.json
  96. +50
    -2
      composer.lock
  97. +27
    -0
      console/commands/DemoAccountController.php
  98. +1
    -1
      console/config/main.php
  99. +0
    -0
      console/controllers/.gitkeep
  100. +28
    -0
      console/migrations/m230821_061757_producer_add_option_testimony.php

+ 16
- 11
backend/controllers/AccessController.php View File

/** /**
* Affiche les utilisateurs ayant accès à l'administration de ce producteur. * Affiche les utilisateurs ayant accès à l'administration de ce producteur.
* Gestion du formulaire permettant d'en ajouter de nouveaux. * Gestion du formulaire permettant d'en ajouter de nouveaux.
*
* @return string
*/ */
public function actionIndex() public function actionIndex()
{ {
$userManager = $this->getUserManager();
$producer = $this->getProducerCurrent();
$userSearch = new UserSearch(); $userSearch = new UserSearch();
$usersArray = $userSearch->search()->query->all(); $usersArray = $userSearch->search()->query->all();


$modelAccessUserProducerForm = new AccessUserProducerForm; $modelAccessUserProducerForm = new AccessUserProducerForm;
if ($modelAccessUserProducerForm->load(\Yii::$app->request->post()) && $modelAccessUserProducerForm->save()) {
$this->setFlash('success', 'Droits ajoutés à l\'utilisateur');
if ($modelAccessUserProducerForm->load(\Yii::$app->request->post()) && $modelAccessUserProducerForm->validate()) {
$user = $userManager->findOneUserById($modelAccessUserProducerForm->id_user);
if($user && $userManager->grantAccess($user)) {
$this->setFlash('success', 'Droits ajoutés à l\'utilisateur');
}
else {
$this->addFlash('error', "Une erreur est survenue.");
}
} }


$producer = $this->getProducerCurrent();
$usersAccessArray = $this->getUserManager()->findUsersByProducer($producer);

return $this->render('index', [ return $this->render('index', [
'usersArray' => $usersArray, 'usersArray' => $usersArray,
'usersAccessArray' => $usersAccessArray,
'usersAccessArray' => $userManager->findUsersByProducer($producer),
'producer' => $producer, 'producer' => $producer,
'modelAccessUserProducerForm' => $modelAccessUserProducerForm, 'modelAccessUserProducerForm' => $modelAccessUserProducerForm,
]); ]);
$userManager = $this->getUserManager(); $userManager = $this->getUserManager();
$user = $userManager->findOneUserById($idUser); $user = $userManager->findOneUserById($idUser);


if ($user) {
$userManager->deleteAccess($user);
$this->setFlash('success', 'Droits de l\'utilisateur supprimé.');
if ($user && $userManager->deleteAccess($user)) {
$this->addFlash('success', 'Droits de l\'utilisateur supprimé.');
}
else {
$this->addFlash('error', "Une erreur est survenue.");
} }


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

+ 90
- 0
backend/controllers/CreditController.php View File

<?php

/**
* Copyright distrib (2018)
*
* contact@opendistrib.net
*
* Ce logiciel est un programme informatique servant à aider les producteurs
* à distribuer leur production en circuits courts.
*
* Ce logiciel est régi par la licence CeCILL soumise au droit français et
* respectant les principes de diffusion des logiciels libres. Vous pouvez
* utiliser, modifier et/ou redistribuer ce programme sous les conditions
* de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
* sur le site "http://www.cecill.info".
*
* En contrepartie de l'accessibilité au code source et des droits de copie,
* de modification et de redistribution accordés par cette licence, il n'est
* offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
* seule une responsabilité restreinte pèse sur l'auteur du programme, le
* titulaire des droits patrimoniaux et les concédants successifs.
*
* A cet égard l'attention de l'utilisateur est attirée sur les risques
* associés au chargement, à l'utilisation, à la modification et/ou au
* développement et à la reproduction du logiciel par l'utilisateur étant
* donné sa spécificité de logiciel libre, qui peut le rendre complexe à
* manipuler et qui le réserve donc à des développeurs et des professionnels
* avertis possédant des connaissances informatiques approfondies. Les
* utilisateurs sont donc invités à charger et tester l'adéquation du
* logiciel à leurs besoins dans des conditions permettant d'assurer la
* sécurité de leurs systèmes et ou de leurs données et, plus généralement,
* à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
*
* Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
* pris connaissance de la licence CeCILL, et que vous en avez accepté les
* termes.
*/

namespace backend\controllers;

use common\helpers\CSV;
use common\helpers\Price;
use http\Exception\InvalidArgumentException;
use yii\data\ActiveDataProvider;
use yii\filters\AccessControl;

class CreditController extends BackendController
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::class,
'rules' => [
[
'allow' => true,
'roles' => ['@'],
'matchCallback' => function ($rule, $action) {
return $this->getUserManager()->hasAccessBackend();
}
]
],
],
];
}

public function actionIndex()
{
$userManager = $this->getUserManager();
$userProducerManager = $this->getUserProducerManager();

$dataProviderUsersWithNegativeCredit = new ActiveDataProvider([
'query' => $userManager->queryUsersWithNegativeCredit(),
'sort' => false,
'pagination' => [
'pageSize' => 30,
],
]);

return $this->render('index', [
'sumUserProducerCredits' => $userProducerManager->sumUserProducerCredits(),
'dataProviderUsersWithNegativeCredit' => $dataProviderUsersWithNegativeCredit
]);
}

public function actionExportUsers(string $type)
{
$this->getUserManager()->exportUsersCreditAsCsv($type);
}
}

+ 1
- 46
backend/controllers/CronController.php View File

]; ];
} }


/**
* Initialise le compte de démonstration.
*
* @param string $key
*/
public function actionInitDemo($key = '')
{
if ($key == '45432df6e842ac71aa0b5bb6b9f25d44') {

$producerManager = $this->getProducerManager();
$distributionManager = $this->getDistributionManager();

$producer = $producerManager->findOneProducerDemoAccount();
$producerManager->setProducerContext($producer);
$distributionManager->setProducerContext($producer);

if ($producer) {
// initialisation de la distribution à J+7
$dateTime = strtotime("+7 day");
$dayStr = strtolower(date('l', $dateTime));
$fieldDeliveryDay = 'delivery_' . $dayStr;
$pointsSaleArray = PointSale::searchAll(['point_sale.id_producer' => $producer->id]);
$activeDistribution = false;
foreach ($pointsSaleArray as $pointSale) {
if ($pointSale->$fieldDeliveryDay) {
$activeDistribution = true;
}
}

if ($activeDistribution) {
$distribution = $distributionManager->createDistributionIfNotExist(date('Y-m-d', $dateTime));
$distributionManager->activeDistribution($distribution);
}
}
}
}

public function actionPayOrders($date) public function actionPayOrders($date)
{ {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$orderManager->initOrder($order); $orderManager->initOrder($order);
if ($order->auto_payment && $configCredit) { if ($order->auto_payment && $configCredit) {
if ($orderManager->getOrderAmount($order, Order::AMOUNT_REMAINING) > 0) { if ($orderManager->getOrderAmount($order, Order::AMOUNT_REMAINING) > 0) {
$creditHistoryManager->createCreditHistory(
CreditHistory::TYPE_PAYMENT,
$orderManager->getOrderAmount($order, Order::AMOUNT_REMAINING),
$order->distribution->producer,
$order->user,
$userManager->findOneUserById(User::ID_USER_SYSTEM),
MeanPayment::CREDIT,
$order
);
$creditHistoryManager->payOrder($order, $userManager->findOneUserById(User::ID_USER_SYSTEM), false);
$countOrders++; $countOrders++;
} }
} }

+ 2
- 137
backend/controllers/DevelopmentController.php View File



namespace backend\controllers; namespace backend\controllers;


use common\helpers\GlobalParam;
use common\helpers\Opendistrib; use common\helpers\Opendistrib;
use common\logic\Development\Development\Development;
use common\logic\Development\DevelopmentPriority\DevelopmentPriority;
use Yii;
use yii\data\ActiveDataProvider;
use yii\web\NotFoundHttpException;
use yii\filters\AccessControl; use yii\filters\AccessControl;


/** /**
} }


/** /**
* Liste les développements.
*
* @return mixed
* Liste les versions d'Opendistrib
*/ */
public function actionIndex() public function actionIndex()
{ {
]; ];
} }


$producer = $this->getProducerCurrent();
$producerManager->updateOpendistribVersion($producer);
$producerManager->updateOpendistribVersion($this->getProducerCurrent());


return $this->render('index', [ return $this->render('index', [
'versionsArray' => $versionsRenderArray 'versionsArray' => $versionsRenderArray
]); ]);
} }


public function actionDevelopment($status = Development::STATUS_OPEN)
{
$dataProvider = new ActiveDataProvider([
'query' => Development::find()
->with(['developmentPriority', 'developmentPriorityCurrentProducer'])
->where(['status' => $status])
->orderBy('date DESC'),
]);

return $this->render('development', [
'dataProvider' => $dataProvider,
'status' => $status
]);
}

/**
* Creates a new Developpement model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$model = new Development();

if ($model->load(\Yii::$app->request->post())) {
$model->date = date('Y-m-d H:i:s');
$model->setDateDelivery();
if ($model->save()) {
$this->setFlash('success', 'Développement ajouté');
return $this->redirect(['index']);
}
} else {
return $this->render('create', [
'model' => $model,
]);
}
}

/**
* Updates an existing Developpement model.
* If update is successful, the browser will be redirected to the 'view' page.
*
* @param integer $id
* @return mixed
*/
public function actionUpdate($id)
{
$model = $this->findModel($id);

if ($model->load(\Yii::$app->request->post())) {
$model->setDateDelivery();
if ($model->save()) {
$this->setFlash('success', 'Développement modifié');
return $this->redirect(['index']);
}
} else {
return $this->render('update', [
'model' => $model,
]);
}
}

/**
* Deletes an existing Developpement model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* @param integer $id
* @return mixed
*/
public function actionDelete($id)
{
$this->findModel($id)->delete();
$this->setFlash('success', 'Développement supprimé');

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

/**
* Définit une priorité pour un développement.
*
* @param integer $idDevelopment
* @param string $priorite
*/
public function actionPriority($idDevelopment, $priority = null)
{
$develpmentPriority = DevelopmentPriority::searchOne([
'id_development' => $idDevelopment,
]);

if (in_array($priority, [DevelopmentPriority::PRIORITY_HIGH,
DevelopmentPriority::PRIORITY_NORMAL,
DevelopmentPriority::PRIORITY_LOW])) {

if ($develpmentPriority) {
$develpmentPriority->priority = $priority;
$develpmentPriority->id_producer = GlobalParam::getCurrentProducerId();
} else {
$develpmentPriority = new DevelopmentPriority;
$develpmentPriority->id_development = $idDevelopment;
$develpmentPriority->priority = $priority;
$develpmentPriority->id_producer = GlobalParam::getCurrentProducerId();
}

$develpmentPriority->save();
} else {
if ($develpmentPriority) {
$develpmentPriority->delete();
}
}

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

/**
* Finds the Developpement model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
*/
protected function findModel($id)
{
if (($model = Development::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}

} }

+ 12
- 25
backend/controllers/OrderController.php View File

$comment = $request->post('comment'); $comment = $request->post('comment');


$order = $orderManager->findOneOrderById($idOrder); $order = $orderManager->findOneOrderById($idOrder);
$orderManager->initOrder($order);

$user = $userManager->findOneUserById($idUser); $user = $userManager->findOneUserById($idUser);
$pointSale = $pointSaleManager->findOnePointSaleById($idPointSale); $pointSale = $pointSaleManager->findOnePointSaleById($idPointSale);


if ($order if ($order
&& $order->distribution->id_producer == GlobalParam::getCurrentProducerId()) { && $order->distribution->id_producer == GlobalParam::getCurrentProducerId()) {


// Si changement d'user : on rembourse l'ancien user
$oldIdUser = $order->id_user; $oldIdUser = $order->id_user;
$oldUser = $userManager->findOneUserById($oldIdUser);
$amountPaid = $orderManager->getOrderAmountWithTax($order, Order::AMOUNT_PAID);
if ($oldIdUser != $idUser && $amountPaid > 0) {
$creditHistoryManager->refundOrder($order, $this->getUserCurrent());
$order = $orderManager->findOneOrderById($idOrder);
$orderManager->initOrder($order);
}

if ($idUser) { if ($idUser) {
$order->username = ''; $order->username = '';
$order->id_user = $idUser; $order->id_user = $idUser;
$order = Order::searchOne(['id' => $order->id]); $order = Order::searchOne(['id' => $order->id]);
$orderManager->initOrder($order); $orderManager->initOrder($order);
if ($order && $orderManager->isCreditAutoPayment($order)) { if ($order && $orderManager->isCreditAutoPayment($order)) {
// Si changement d'user : on rembourse l'ancien user
$amountPaid = $orderManager->getOrderAmount($order, Order::AMOUNT_PAID);
if ($oldIdUser != $idUser && $amountPaid > 0) {
$creditHistoryManager->createCreditHistory(
CreditHistory::TYPE_REFUND,
$amountPaid,
$this->getProducerCurrent(),
$oldUser,
$this->getUserCurrent()
);
$order = Order::searchOne(['id' => $order->id]);
$orderManager->initOrder($order);
}

$orderManager->processCredit($order); $orderManager->processCredit($order);
} }
} }


$orderManager = $this->getOrderManager(); $orderManager = $this->getOrderManager();
$creditHistoryManager = $this->getCreditHistoryManager(); $creditHistoryManager = $this->getCreditHistoryManager();

$order = $orderManager->findOneOrderById($idOrder); $order = $orderManager->findOneOrderById($idOrder);
$orderManager->initOrder($order);


if ($order) { if ($order) {
$creditHistoryManager->createCreditHistory(
$type,
$amount,
GlobalParam::getCurrentProducer(),
$order->user,
GlobalParam::getCurrentUser(),
MeanPayment::CREDIT,
$order
);
$creditHistoryManager->payOrRefundOrder($type, $order, $this->getUserCurrent());
} }


return ['success']; return ['success'];

+ 22
- 5
backend/controllers/ProducerAdminController.php View File



namespace backend\controllers; namespace backend\controllers;


use common\helpers\Alwaysdata;
use common\logic\Order\Order\Model\Order; use common\logic\Order\Order\Model\Order;
use common\logic\Producer\Producer\Model\Producer; use common\logic\Producer\Producer\Model\Producer;
use common\logic\Product\Product\Model\Product; use common\logic\Product\Product\Model\Product;
public function actionUpdate(int $id) public function actionUpdate(int $id)
{ {
$producerManager = $this->getProducerManager(); $producerManager = $this->getProducerManager();
$producer = $this->findModel($id);
$producer = $this->findProducer($id);


if ($producer->load(\Yii::$app->request->post()) && $producerManager->saveCreate($producer)) { if ($producer->load(\Yii::$app->request->post()) && $producerManager->saveCreate($producer)) {
$this->setFlash('success', 'Producteur modifié.'); $this->setFlash('success', 'Producteur modifié.');
*/ */
public function actionBilling(int $id) public function actionBilling(int $id)
{ {
$producerManager = $this->getProducerManager();
$producer = $this->findModel($id);
$producer = $this->findProducer($id);


return $this->render('billing', [ return $this->render('billing', [
'producer' => $producer, 'producer' => $producer,
]); ]);
} }


public function actionAlwaysdata(int $id)
{
$producer = $this->findProducer($id);

if($producer->contact_email) {
Alwaysdata::createProducerSiteShortUrlRedirection($producer);
Alwaysdata::createProducerEmailRedirection($producer);
}
else {
$this->addFlash('error', "L'adresse email de contact du producteur n'est pas définie.");
}

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

public function actionUserTransfer($fromProducerId, $toProducerId, $withOrders = 1) public function actionUserTransfer($fromProducerId, $toProducerId, $withOrders = 1)
{ {
$producerManager = $this->getProducerManager(); $producerManager = $this->getProducerManager();
/** /**
* Recherche un producteur. * Recherche un producteur.
*/ */
protected function findModel(int $id)
protected function findProducer(int $id)
{ {
if (($model = Producer::findOne($id)) !== null) {
$producerManager = $this->getProducerManager();

if (($model = $producerManager->findOneProducerById($id)) !== null) {
return $model; return $model;
} else { } else {
throw new NotFoundHttpException('The requested page does not exist.'); throw new NotFoundHttpException('The requested page does not exist.');

+ 1
- 0
backend/controllers/SiteController.php View File



namespace backend\controllers; namespace backend\controllers;


use common\helpers\Alwaysdata;
use common\helpers\GlobalParam; use common\helpers\GlobalParam;
use common\logic\Distribution\Distribution\Model\Distribution; use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Order\Order\Model\Order; use common\logic\Order\Order\Model\Order;

+ 2
- 2
backend/controllers/SupportController.php View File

$ticketMessageManager = $this->getTicketMessageManager(); $ticketMessageManager = $this->getTicketMessageManager();
$ticket = $ticketManager->instanciateTicket($this->getProducerCurrent(), $userCurrent); $ticket = $ticketManager->instanciateTicket($this->getProducerCurrent(), $userCurrent);


if ($ticket->load(\Yii::$app->request->post()) && $ticketManager->saveCreate($ticket)) {
if ($ticket->load(\Yii::$app->request->post()) && $ticket->validate() && $ticketManager->create($ticket)) {
$ticketMessageManager->createTicketMessage($ticket, $userCurrent, $ticket->message); $ticketMessageManager->createTicketMessage($ticket, $userCurrent, $ticket->message);
$this->setFlash('success', 'Le ticket a bien été créé.'); $this->setFlash('success', 'Le ticket a bien été créé.');
return $this->redirect(['view', 'id' => $ticket->id]); return $this->redirect(['view', 'id' => $ticket->id]);
} else { } else {
return $this->render('@backend/views/support/create', [ return $this->render('@backend/views/support/create', [
'ticket' => $ticket,
'ticket' => $ticket
]); ]);
} }
} }

+ 155
- 167
backend/controllers/UserController.php View File

use common\logic\User\User\Model\UserSearch; use common\logic\User\User\Model\UserSearch;
use common\logic\User\UserProducer\Model\UserProducer; use common\logic\User\UserProducer\Model\UserProducer;
use common\logic\User\UserUserGroup\Model\UserUserGroup; use common\logic\User\UserUserGroup\Model\UserUserGroup;
use Faker\Provider\HtmlLorem;
use yii\base\UserException; use yii\base\UserException;
use yii\filters\AccessControl; use yii\filters\AccessControl;
use yii\filters\VerbFilter; use yii\filters\VerbFilter;
use \Yii; use \Yii;
use yii\helpers\Html;
use yii\web\NotFoundHttpException; use yii\web\NotFoundHttpException;


/** /**
public function behaviors() public function behaviors()
{ {
return [ return [
'verbs' => [
'class' => VerbFilter::class,
'actions' => [
],
],
'access' => [ 'access' => [
'class' => AccessControl::class, 'class' => AccessControl::class,
'rules' => [ 'rules' => [
]); ]);
} }


public function initForm($model)
{
$userPointSaleManager = $this->getUserPointSaleManager();
$userUserGroupManager = $this->getUserUserGroupManager();
$userProducerManager = $this->getUserProducerManager();
$userGroupManager = $this->getUserGroupManager();

$producerCurrent = $this->getProducerCurrent();

if ($model->id) {
$userPointSaleArray = $userPointSaleManager->findUserPointSalesByUser($model);
if ($userPointSaleArray && count($userPointSaleArray) > 0) {
foreach ($userPointSaleArray as $userPointSale) {
$model->points_sale[] = $userPointSale->id_point_sale;
}
}

$userUserGroupsArray = $userUserGroupManager->findUserUserGroupsByUser($model);
if ($userUserGroupsArray && count($userUserGroupsArray) > 0) {
foreach ($userUserGroupsArray as $userUserGroup) {
$model->user_groups[] = $userUserGroup->id_user_group;
}
}
$userProducer = $userProducerManager->findOneUserProducer($model);
$model->product_price_percent = $userProducer->product_price_percent;
}

$pointsSaleArray = PointSale::find()
->where([
'id_producer' => GlobalParam::getCurrentProducerId(),
'status' => 1
])
->joinWith(['userPointSale' => function ($query) use ($model) {
if ($model->id) {
$query->andOnCondition('user_point_sale.id_user = ' . $model->id);
}
}])
->all();

$userGroupsArray = $userGroupManager->findUserGroups();

return [
'pointsSaleArray' => $pointsSaleArray,
'userGroupsArray' => $userGroupsArray,
];
}

/**
* Creates a new User model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate() public function actionCreate()
{ {
$userManager = $this->getUserManager(); $userManager = $this->getUserManager();
$producerManager = $this->getProducerManager(); $producerManager = $this->getProducerManager();
$pointSaleManager = $this->getPointSaleManager();

$producerCurrent = $this->getProducerCurrent(); $producerCurrent = $this->getProducerCurrent();
$model = $userManager->instanciateUser(); $model = $userManager->instanciateUser();

$userExist = false;
$posts = Yii::$app->request->post(); $posts = Yii::$app->request->post();
$userExist = false;


if ($posts && isset($posts['User']['email']) && strlen($posts['User']['email']) > 0) { if ($posts && isset($posts['User']['email']) && strlen($posts['User']['email']) > 0) {
$userExist = $userManager->findOneUserByEmail($posts['User']['email']); $userExist = $userManager->findOneUserByEmail($posts['User']['email']);


} }


/**
* Updates an existing User model.
* If update is successful, the browser will be redirected to the 'view' page.
*/
public function actionUpdate($id) public function actionUpdate($id)
{ {
$userManager = $this->getUserManager(); $userManager = $this->getUserManager();
$this->processLinkUserGroup($model); $this->processLinkUserGroup($model);
$this->processProductPricePercent($model); $this->processProductPricePercent($model);


$this->setFlash('success', 'Utilisateur modifié.');
$this->setFlash('success', 'Utilisateur <strong>'.Html::encode($userManager->getUsername($model)).'</strong> modifié.');

return $this->redirect(['index']);
} }
} else { } else {
throw new UserException("Vous ne pouvez pas modifier cet utilisateur."); throw new UserException("Vous ne pouvez pas modifier cet utilisateur.");
] ]
]); ]);


$this->setFlash('success', 'Nouveau mot de passe envoyé.');
$this->setFlash('success', 'Nouveau mot de passe envoyé à <strong>'.Html::encode($userManager->getUsername($model)).'</strong>.');

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


return $this->render('update', array_merge($this->initForm($model), [ return $this->render('update', array_merge($this->initForm($model), [
])); ]));
} }


public function initForm($model)
{
$userPointSaleManager = $this->getUserPointSaleManager();
$userUserGroupManager = $this->getUserUserGroupManager();
$userProducerManager = $this->getUserProducerManager();
$userGroupManager = $this->getUserGroupManager();

if ($model->id) {
$userPointSaleArray = $userPointSaleManager->findUserPointSalesByUser($model);
if ($userPointSaleArray && count($userPointSaleArray) > 0) {
foreach ($userPointSaleArray as $userPointSale) {
$model->points_sale[] = $userPointSale->id_point_sale;
}
}

$userUserGroupsArray = $userUserGroupManager->findUserUserGroupsByUser($model);
if ($userUserGroupsArray && count($userUserGroupsArray) > 0) {
foreach ($userUserGroupsArray as $userUserGroup) {
$model->user_groups[] = $userUserGroup->id_user_group;
}
}
$userProducer = $userProducerManager->findOneUserProducer($model);
$model->product_price_percent = $userProducer->product_price_percent;
}

$pointsSaleArray = PointSale::find()
->where([
'id_producer' => GlobalParam::getCurrentProducerId(),
'status' => 1
])
->joinWith(['userPointSale' => function ($query) use ($model) {
if ($model->id) {
$query->andOnCondition('user_point_sale.id_user = ' . $model->id);
}
}])
->all();

$userGroupsArray = $userGroupManager->findUserGroups();

return [
'pointsSaleArray' => $pointsSaleArray,
'userGroupsArray' => $userGroupsArray,
];
}

/** /**
* Lie un utilisateur aux points de vente sélectionnés. * Lie un utilisateur aux points de vente sélectionnés.
*/ */
$userProducerManager = $this->getUserProducerManager(); $userProducerManager = $this->getUserProducerManager();


$user = $userManager->findOneUserById($id); $user = $userManager->findOneUserById($id);
$producer = $this->getProducerCurrent();
$userProducer = $userProducerManager->findOneUserProducer($user); $userProducer = $userProducerManager->findOneUserProducer($user);


if ($userProducer) { if ($userProducer) {
$userProducer->active = 0;
$userProducer->bookmark = 0;
$userProducer->save();

$this->setFlash('success', 'L\'utilisateur a bien été supprimé de votre établissement.');
if($userProducerManager->hasOutstandingCredit($userProducer)) {
$this->setFlash('error', "Vous ne pouvez pas supprimer cet utilisateur car il a toujours du crédit en cours.");
}
else {
$userProducerManager->unlinkUserProducer($userProducer);
$this->setFlash('success', 'L\'utilisateur a bien été supprimé de votre établissement.');
}
} else { } else {
throw new \yii\web\NotFoundHttpException('L\'enregistrement UserProducer est introuvable', 404); throw new \yii\web\NotFoundHttpException('L\'enregistrement UserProducer est introuvable', 404);
} }
$this->redirect(array_merge(['index'], $params)); $this->redirect(array_merge(['index'], $params));
} }


/**
* Affiche les données liées au crédit d'un utilisateur (formulaire, historique).
*/
public function actionCredit(int $id)
{
$user = User::find()->with('userProducer')->where(['id' => $id])->one();
$userProducer = UserProducer::findOne(['id_user' => $id, 'id_producer' => GlobalParam::getCurrentProducerId()]);

if (($userProducer) || $this->isUserCurrentAdmin()) {

$creditForm = new CreditForm();
if ($creditForm->load(\Yii::$app->request->post()) && $creditForm->validate()) {
$creditForm->id_user = $id;
$creditForm->save();

$creditForm = new CreditForm;
}

$history = CreditHistory::find()
->with(['order', 'userAction'])
->where([
'id_user' => $user->id,
'id_producer' => GlobalParam::getCurrentProducerId(),
])
->orderBy('date DESC')
->all();

return $this->render('credit', [
'user' => $user,
'userProducer' => $userProducer,
'creditForm' => $creditForm,
'history' => $history
]);
} else {
throw new UserException("Vous ne pouvez pas créditer un utilisateur qui n'est pas associé à votre établissement.");
}
}

/**
* Modifie l'option "credit_active" d'un utilisateur pour le producteur courant.
* Redirige vers la page de crédit de l'utilisateur.
*/
public function actionStateCredit($idUser, $state)
{
$userManager = $this->getUserManager();
$userProducerManager = $this->getUserProducerManager();

$user = $userManager->findOneUserById($idUser);
$userProducer = $userProducerManager->findOneUserProducer($user);

if ($userProducer) {
$userProducer->credit_active = $state;
$userProducer->save();
}

return $this->redirect(['user/credit', 'id' => $idUser]);
}

/**
* Affiche les commandes d'un utilisateur.
*
* @param integer $id
* @return mixed
*/
public function actionOrders($id)
{
$userManager = $this->getUserManager();

$user = $userManager->findOneUserById($id);
$searchModel = new OrderSearch();
$dataProvider = $searchModel->search(array_merge(\Yii::$app->request->queryParams, ['id_user' => $id]));

return $this->render('orders', [
'user' => $user,
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}

/**
* Finds the User model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
*/
protected function findModel($id)
{
$userManager = $this->getUserManager();

if (($user = $userManager->findOneUserById($id)) !== null) {
return $user;
} else {
throw new NotFoundHttpException("Utilisateur introuvable");
}
}

/** /**
* Affiche la liste des emails des utilisateurs liés à un point de vente donné. * Affiche la liste des emails des utilisateurs liés à un point de vente donné.
*/ */
'usersPointSaleHasOrder' => $usersPointSaleHasOrder, 'usersPointSaleHasOrder' => $usersPointSaleHasOrder,
]); ]);
} }

/**
* Affiche les données liées au crédit d'un utilisateur (formulaire, historique).
*/
public function actionCredit(int $id)
{
$user = User::find()->with('userProducer')->where(['id' => $id])->one();
$userProducer = UserProducer::findOne(['id_user' => $id, 'id_producer' => GlobalParam::getCurrentProducerId()]);

if (($userProducer) || $this->isUserCurrentAdmin()) {

$creditForm = new CreditForm();
if ($creditForm->load(\Yii::$app->request->post()) && $creditForm->validate()) {
$creditForm->id_user = $id;
$creditForm->save();

$creditForm = new CreditForm;
}

$history = CreditHistory::find()
->with(['order', 'userAction'])
->where([
'id_user' => $user->id,
'id_producer' => GlobalParam::getCurrentProducerId(),
])
->orderBy('date DESC')
->all();

return $this->render('credit', [
'user' => $user,
'userProducer' => $userProducer,
'creditForm' => $creditForm,
'history' => $history
]);
} else {
throw new UserException("Vous ne pouvez pas créditer un utilisateur qui n'est pas associé à votre établissement.");
}
}

/**
* Affiche les commandes d'un utilisateur.
*
* @param integer $id
* @return mixed
*/
public function actionOrders($id)
{
$userManager = $this->getUserManager();

$user = $userManager->findOneUserById($id);
$searchModel = new OrderSearch();
$dataProvider = $searchModel->search(array_merge(\Yii::$app->request->queryParams, ['id_user' => $id]));

return $this->render('orders', [
'user' => $user,
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}

/**
* Modifie l'option "credit_active" d'un utilisateur pour le producteur courant.
* Redirige vers la page de crédit de l'utilisateur.
*/
public function actionStateCredit($idUser, $state)
{
$userManager = $this->getUserManager();
$userProducerManager = $this->getUserProducerManager();

$user = $userManager->findOneUserById($idUser);
$producerCurrent = $this->getproducerCurrent();
$userProducer = $userProducerManager->findOneUserProducer($user);

if ($userProducer) {
$userProducer->credit_active = $state;
$userProducer->save();
}

return $this->redirect(['user/credit', 'id' => $idUser]);
}

/**
* Finds the User model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
*/
protected function findModel($id)
{
$userManager = $this->getUserManager();

if (($user = $userManager->findOneUserById($id)) !== null) {
return $user;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
} }

+ 4
- 12
backend/models/CreditForm.php View File

use common\logic\User\User\Model\User; use common\logic\User\User\Model\User;
use common\logic\User\User\Wrapper\UserManager; use common\logic\User\User\Wrapper\UserManager;
use common\logic\User\UserProducer\Model\UserProducer; use common\logic\User\UserProducer\Model\UserProducer;
use common\logic\User\UserProducer\Wrapper\UserProducerManager;
use Yii; use Yii;
use yii\base\Model; use yii\base\Model;


public function save() public function save()
{ {
$userManager = UserManager::getInstance(); $userManager = UserManager::getInstance();
$userProducerManager = UserProducerManager::getInstance();
$creditHistoryManager = CreditHistoryManager::getInstance(); $creditHistoryManager = CreditHistoryManager::getInstance();
$producerManager = ProducerManager::getInstance(); $producerManager = ProducerManager::getInstance();


if ($this->validate()) { if ($this->validate()) {
$user = $userManager->findOneUserById($this->id_user); $user = $userManager->findOneUserById($this->id_user);
$creditHistoryManager->createCreditHistory(
$this->type,
$this->amount,
GlobalParam::getCurrentProducer(),
$user,
Yii::$app->user->identity,
$this->mean_payment
);
$creditHistoryManager->creditOrDebitUser($this->type, $user, $this->amount, $this->mean_payment, $userManager->getCurrent());
// on prévient l'utilisateur que son compte vient d'être crédité // on prévient l'utilisateur que son compte vient d'être crédité
if($this->send_mail) { if($this->send_mail) {
$user = User::findOne($this->id_user) ;
$producer = GlobalParam::getCurrentProducer() ; $producer = GlobalParam::getCurrentProducer() ;
$userProducer = UserProducer::searchOne([
'id_user' => $this->id_user
]);
$userProducer = $userProducerManager->findOneUserProducer($user);


$paramsEmail = [ $paramsEmail = [
'from_email' => $producerManager->getEmailOpendistrib($producer), 'from_email' => $producerManager->getEmailOpendistrib($producer),

+ 79
- 0
backend/views/credit/index.php View File

<?php

use common\helpers\Price;
use yii\grid\GridView;

$userManager = $this->getUserManager();

$this->setTitle('Crédit');

?>

<div class="row">
<div class="col-md-6">
<div class="info-box">
<span class="info-box-icon <?= $sumUserProducerCredits >= 0 ? 'bg-green' : 'bg-red' ?>"><i
class="fa fa-euro"></i></span>
<div class="info-box-content">
<span class="info-box-text">Somme totale en crédit</span>
<span class="info-box-number"><?= Price::format($sumUserProducerCredits); ?></span>
</div>
</div>
</div>
<div class="col-md-6">
<div class="info-box">
<span class="info-box-icon bg-orange"><i class="fa fa-download"></i></span>
<div class="info-box-content">
<span class="info-box-text">Exports<br />
<a class="btn btn-default btn-sm" href="<?= Yii::$app->urlManager->createUrl(['credit/export-users', 'type' => 'negative']); ?>">Clients au crédit négatif (CSV)</a>
<a class="btn btn-default btn-sm" href="<?= Yii::$app->urlManager->createUrl(['credit/export-users', 'type' => 'positive']); ?>">Clients au crédit positif (CSV)</a>
</span>
</div>
</div>
</div>
</div>

<h3>Clients avec un crédit négatif</h3>

<?=

GridView::widget([
'dataProvider' => $dataProviderUsersWithNegativeCredit,
'summary' => '',
'columns' => [
[
'label' => 'Client',
'value' => function ($user) use ($userManager) {
return $userManager->getUsernameFromArray($user, true);
}
],
[
'label' => 'Email',
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($user) {
return $user['email'];
}
],
[
'label' => 'Téléphone',
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($user) {
return $user['phone'];
}
],
[
'label' => 'Crédit',
'format' => 'raw',
'value' => function ($user) {
return Price::format($user['credit']);
}
]
]
]);
?>

+ 13
- 11
backend/views/development/index.php View File

<div class="container-fluidd"> <div class="container-fluidd">
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<?php foreach($versionsArray as $version): ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<?= $version['version'] ?>
</h3>
<div id="versions-list">
<?php foreach($versionsArray as $version): ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<?= $version['version'] ?>
</h3>
</div>
<div class="panel-body">
<?= $version['content'] ?>
</div>
</div> </div>
<div class="panel-body">
<?= $version['content'] ?>
</div>
</div>
<?php endforeach; ?>
<?php endforeach; ?>
</div>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<div id="panel-participate" class="panel panel-default"> <div id="panel-participate" class="panel panel-default">

+ 1
- 1
backend/views/distribution/index.php View File

<option value="0">--</option> <option value="0">--</option>
<option v-for="user in users" :value="user.id_user"> <option v-for="user in users" :value="user.id_user">
<template v-if="user.name_legal_person && user.name_legal_person.length"> <template v-if="user.name_legal_person && user.name_legal_person.length">
Personne morale / {{ user.name_legal_person }}
{{ user.name_legal_person }} (personne morale)
</template> </template>
<template v-else> <template v-else>
{{ user.lastname +' '+ user.name }} {{ user.lastname +' '+ user.name }}

+ 2
- 5
backend/views/layouts/header.php View File



<?php <?php


$usersNegativeCreditArray = $userManager->queryUsersBy(['id_producer' => GlobalParam::getCurrentProducerId()])
->andWhere('user_producer.credit < 0')
->orderBy('lastname, name ASC')
->all();
$usersNegativeCreditArray = $userManager->findUsersWithNegativeCredit();


?> ?>




<ul class="dropdown-menu"> <ul class="dropdown-menu">
<?php if (count($usersNegativeCreditArray)): ?> <?php if (count($usersNegativeCreditArray)): ?>
<li class="header">Utilisateurs au crédit négatif</li>
<li class="header"><a href="<?= Yii::$app->urlManager->createUrl(['credit/index']); ?>">Utilisateurs au crédit négatif</a></li>
<li> <li>
<ul class="menu"> <ul class="menu">
<?php foreach ($usersNegativeCreditArray as $user): ?> <?php foreach ($usersNegativeCreditArray as $user): ?>

+ 11
- 0
backend/views/layouts/left.php View File



$producerManager = $this->getProducerManager(); $producerManager = $this->getProducerManager();
$userManager = $this->getUserManager(); $userManager = $this->getUserManager();
$userProducerManager = $this->getUserProducerManager();
$ticketManager = $this->getTicketManager(); $ticketManager = $this->getTicketManager();
$producer = GlobalParam::getCurrentProducer(); $producer = GlobalParam::getCurrentProducer();


$countTicketsAdminUnreadLabel = '<span class="pull-right-container"><small class="label pull-right bg-green">'.$countTicketsAdminUnread.'</small></span>'; $countTicketsAdminUnreadLabel = '<span class="pull-right-container"><small class="label pull-right bg-green">'.$countTicketsAdminUnread.'</small></span>';
} }


$sumUserProducerCredits = $userProducerManager->sumUserProducerCredits();
$sumUserProducerCreditsLabel = '<span class="pull-right-container"><small class="label pull-right '.($sumUserProducerCredits >= 0 ? 'bg-green' : 'bg-red') .'">'.number_format($sumUserProducerCredits, 2).' €</small></span>';

?> ?>


<?= dmstr\widgets\Menu::widget( <?= dmstr\widgets\Menu::widget(
'url' => ['/user/index'], 'url' => ['/user/index'],
'items' => [ 'items' => [
['label' => 'Liste', 'icon' => 'th-list', 'url' => ['/user/index'], 'visible' => $userManager->isCurrentProducer()], ['label' => 'Liste', 'icon' => 'th-list', 'url' => ['/user/index'], 'visible' => $userManager->isCurrentProducer()],
[
'label' => 'Crédit',
'icon' => 'euro',
'url' => ['/credit/index'],
'template' => '<a href="{url}">{icon} {label}' . $sumUserProducerCreditsLabel . '</a>',
'visible' => $userManager->isCurrentProducer() && $producerManager->getConfig('credit')
],
['label' => 'Groupes', 'icon' => 'users', 'url' => ['/user-group/index'], 'visible' => $userManager->isCurrentProducer()], ['label' => 'Groupes', 'icon' => 'users', 'url' => ['/user-group/index'], 'visible' => $userManager->isCurrentProducer()],
], ],
], ],

+ 3
- 0
backend/views/producer-admin/_form.php View File

<?php $form = ActiveForm::begin(); ?> <?php $form = ActiveForm::begin(); ?>


<h3>Général</h3> <h3>Général</h3>
<?= $form->field($model, 'slug') ?>
<?= $form->field($model, 'name') ?> <?= $form->field($model, 'name') ?>
<?= $form->field($model, 'type')->textInput(['placeholder' => 'Boulangerie, brasserie, ferme ...']); ?> <?= $form->field($model, 'type')->textInput(['placeholder' => 'Boulangerie, brasserie, ferme ...']); ?>
<?= $form->field($model, 'postcode') ?> <?= $form->field($model, 'postcode') ?>
<?= $form->field($model, 'city') ?> <?= $form->field($model, 'city') ?>
<?= $form->field($model, 'contact_email') ?>
<?= $form->field($model, 'latitude') ?> <?= $form->field($model, 'latitude') ?>
<?= $form->field($model, 'longitude') ?> <?= $form->field($model, 'longitude') ?>
<?= $form->field($model, 'code')->label('Code d\'accès') ?> <?= $form->field($model, 'code')->label('Code d\'accès') ?>
<?= $form->field($model, 'admin_comment')->textarea(['rows' => 7]) ?>


<h3>Facturation</h3> <h3>Facturation</h3>
<?= $form->field($model, 'option_billing_type') <?= $form->field($model, 'option_billing_type')

+ 53
- 27
backend/views/producer-admin/index.php View File

} }
],*/ ],*/
[ [
'attribute' => 'À facturer / chiffre d\'affaire',
'label' => 'À facturer / chiffre d\'affaire',
'label' => 'Facturation',
'format' => 'raw', 'format' => 'raw',
'value' => function($producer) use ($producerManager) { 'value' => function($producer) use ($producerManager) {


$str = ''; $str = '';
if($producerManager->isBillingFrequencyMonthly($producer)) {
$str .= $producerManager->getSummaryAmountsToBeBilled($producer, 'Mois dernier', 1);
}
elseif($producerManager->isBillingFrequencyQuarterly($producer)) {
$str .= $producerManager->getSummaryAmountsToBeBilled($producer, '3 derniers mois', 3);
}
elseif($producerManager->isBillingFrequencyBiannual($producer)) {
$str .= $producerManager->getSummaryAmountsToBeBilled($producer, '6 derniers mois', 6);
}
$str .= '<ul style="margin: 0px;padding-left: 15px;">';

$isBillingFrequencyMonthly = $producerManager->isBillingFrequencyMonthly($producer);
$summaryMonthly = $producerManager->getSummaryAmountsToBeBilled($producer, 'Mois dernier', 1);
$isBillingFrequencyQuaterly = $producerManager->isBillingFrequencyQuarterly($producer);
$summaryQuaterly = $producerManager->getSummaryAmountsToBeBilled($producer, '3 derniers mois', 3);
$isBillingFrequencyBiannual = $producerManager->isBillingFrequencyBiannual($producer);
$summaryBiannual = $producerManager->getSummaryAmountsToBeBilled($producer, '6 derniers mois', 6);


if($producer->option_billing_reduction && strlen($str)) {
$str .= '<br /><u>Avec réduction</u> : ';
if($producer->option_billing_reduction_percentage) {
$str .= ' '.$producer->option_billing_reduction_percentage.'&nbsp;%';
if(($isBillingFrequencyMonthly && $summaryMonthly)
|| ($isBillingFrequencyQuaterly && $summaryQuaterly)
|| ($isBillingFrequencyBiannual && $summaryBiannual)) {

$str .= '<li>';
if ($isBillingFrequencyMonthly && $summaryMonthly) {
$str .= $summaryMonthly;
} elseif ($isBillingFrequencyQuaterly && $summaryQuaterly) {
$str .= $summaryQuaterly;
} elseif ($isBillingFrequencyBiannual && $summaryBiannual) {
$str .= $summaryBiannual;
} }

if ($producer->option_billing_reduction && strlen($str)) {
$str .= '<br /><u>Avec réduction</u> : ';
if ($producer->option_billing_reduction_percentage) {
$str .= ' ' . $producer->option_billing_reduction_percentage . '&nbsp;%';
}
}
$str .= '</li>';

$str .= '<li>Facturation '.strtolower(Producer::$billingFrequencyArray[$producer->option_billing_frequency]).'</li>';
}

if($producer->option_billing_permanent_transfer) {
$str .= '<li>Virement permanent : <strong>'.Price::format($producer->option_billing_permanent_transfer_amount).'</strong></li>';
} }


$str .= '</ul>';

return $str; return $str;
} }
], ],
[ [
'attribute' => 'Facturation',
'label' => 'Détails facturation',
'attribute' => 'admin_comment',
'label' => 'Commentaire',
'format' => 'raw', 'format' => 'raw',
'value' => function($model) {
$str = '<ul style="margin: 0px;padding-left: 15px;">';
$str .= '<li>'.Producer::$billingFrequencyArray[$model->option_billing_frequency].'</li>';

if($model->option_billing_permanent_transfer) {
$str .= '<li>Virement permanent : <strong>'.Price::format($model->option_billing_permanent_transfer_amount).'</strong></li>';
'value' => function($producer) {
if($producer->admin_comment) {
return $producer->admin_comment;
} }


$str .= '</ul>';

return $str;
return '';
} }
], ],
[ [
'class' => 'yii\grid\ActionColumn', 'class' => 'yii\grid\ActionColumn',
'template' => '{update} {billing}',
'template' => '{update} {billing} {alwaysdata}',
'headerOptions' => ['class' => 'column-actions'], 'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'], 'contentOptions' => ['class' => 'column-actions'],
'buttons' => [ 'buttons' => [
] ]
); );
}, },
'alwaysdata' => function ($url, $model) {
return Html::a(
'<span class="glyphicon glyphicon-road"></span>',
$url,
[
'title' => 'Redirections Alwaysdata (email et url courte)',
'class' => 'btn btn-default'
]
);
},
], ],
], ],
], ],

+ 29
- 7
backend/views/producer/update.php View File

Producer::BEHAVIOR_HOME_POINT_SALE_DAY_LIST_INCOMING_DISTRIBUTIONS => 'Distributions à venir', Producer::BEHAVIOR_HOME_POINT_SALE_DAY_LIST_INCOMING_DISTRIBUTIONS => 'Distributions à venir',
]); ?> ]); ?>
<?= $form->field($model, 'option_point_sale_wording') ?> <?= $form->field($model, 'option_point_sale_wording') ?>

<h4>Logiciel</h4>
<?= $form->field($model, 'option_display_message_new_opendistrib_version')
->dropDownList([
1 => 'Oui',
0 => 'Non'
], []); ?>
</div> </div>
</div> </div>


->textarea(['rows' => 15]) ?> ->textarea(['rows' => 15]) ?>
</div> </div>
</div> </div>

<div v-show="currentSection == 'software'" class="panel panel-default">
<div class="panel-body">
<h4>Opendistrib</h4>
<?= $form->field($model, 'option_testimony')
->textarea(['rows' => 7])
->hint("Écrivez ici votre témoignage concernant l'utilisation du logiciel. Il sera publié sur la page 'À propos' du site.") ; ?>
<?= $form->field($model, 'option_time_saved')
->dropDownList([
null => '--',
0.5 => '30 minutes',
1 => '1 heure',
2 => '2 heures',
3 => '3 heures',
4 => '4 heures',
5 => '5 heures',
6 => '6 heures',
7 => '7 heures',
8 => '8 heures',
])
->hint("Sélectionnez le temps que vous estimez gagner chaque semaine en utilisant ce logiciel. Cette donnée sera utilisée sur la page 'À propos' du site.") ; ?>
<?= $form->field($model, 'option_display_message_new_opendistrib_version')
->dropDownList([
1 => 'Oui',
0 => 'Non'
], []); ?>
</div>
</div>

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

+ 2
- 3
backend/views/product/_form.php View File

<?php <?php


use common\helpers\Image;
use yii\helpers\Html; use yii\helpers\Html;
use yii\bootstrap\ActiveForm; use yii\bootstrap\ActiveForm;
use yii\helpers\ArrayHelper; use yii\helpers\ArrayHelper;
<?= $form->field($model, 'photo')->fileInput() ?> <?= $form->field($model, 'photo')->fileInput() ?>
<?php <?php
if (strlen($model->photo)) { if (strlen($model->photo)) {
$url = Yii::$app->urlManagerProducer->getHostInfo() . '/' . Yii::$app->urlManagerProducer->baseUrl . '/uploads/' . $model->photo;
$url = str_replace('//uploads','/uploads', $url) ;
echo '<img class="photo-product" src="' . $url . '" width="200px" /><br />';
echo '<img class="photo-product" src="' . Image::getThumbnailSmall($model->photo, true). '" width="200px" /><br />';
echo '<input type="checkbox" name="delete_photo" id="delete_photo" /> <label for="delete_photo">Supprimer la photo</label>'; echo '<input type="checkbox" name="delete_photo" id="delete_photo" /> <label for="delete_photo">Supprimer la photo</label>';
} }
?> ?>

+ 2
- 3
backend/views/product/index.php View File

* termes. * termes.
*/ */


use common\helpers\Image;
use yii\helpers\Html; use yii\helpers\Html;
use yii\grid\GridView; use yii\grid\GridView;
use common\helpers\GlobalParam; use common\helpers\GlobalParam;
'filter' => '', 'filter' => '',
'value' => function ($model) { 'value' => function ($model) {
if (strlen($model->photo)) { if (strlen($model->photo)) {
$url = Yii::$app->urlManagerProducer->getHostInfo() . '/' . Yii::$app->urlManagerProducer->baseUrl . '/uploads/' . $model->photo;
$url = str_replace('//uploads', '/uploads', $url);
return '<img class="photo-product" src="' . $url . '" />';
return '<img class="photo-product" src="' . Image::getThumbnailSmall($model->photo, true) . '" />';
} }
return ''; return '';
} }

+ 4
- 0
backend/views/user/_form.php View File

<?= $form->field($model, 'evoliz_code')->textInput() ?> <?= $form->field($model, 'evoliz_code')->textInput() ?>
<?php endif; ?> <?php endif; ?>


<?php if($pointsSaleArray && count($pointsSaleArray) > 0): ?>
<?= $form->field($model, 'points_sale')->checkboxlist( <?= $form->field($model, 'points_sale')->checkboxlist(
ArrayHelper::map($pointsSaleArray, 'id', function ($pointSale) use ($model) { ArrayHelper::map($pointsSaleArray, 'id', function ($pointSale) use ($model) {
$commentUserPointSale = isset($pointSale->userPointSale[0]) ? $pointSale->userPointSale[0]->comment : ''; $commentUserPointSale = isset($pointSale->userPointSale[0]) ? $pointSale->userPointSale[0]->comment : '';
'encode' => false 'encode' => false
]); ]);
?> ?>
<?php endif; ?>


<?php if($userGroupsArray && count($userGroupsArray) > 0): ?>
<?= $form->field($model, 'user_groups')->checkboxlist( <?= $form->field($model, 'user_groups')->checkboxlist(
ArrayHelper::map($userGroupsArray, 'id', function ($userGroup) use ($model) { ArrayHelper::map($userGroupsArray, 'id', function ($userGroup) use ($model) {
return Html::encode($userGroup->name); return Html::encode($userGroup->name);
'encode' => false 'encode' => false
]); ]);
?> ?>
<?php endif; ?>


<?php /* $form->field($model, 'product_price_percent') <?php /* $form->field($model, 'product_price_percent')
->dropDownList( ProductPrice::percentValues(), [])->hint('Pourcentage appliqué aux prix de chaque produit pour cet utilisateur.');*/ ?> ->dropDownList( ProductPrice::percentValues(), [])->hint('Pourcentage appliqué aux prix de chaque produit pour cet utilisateur.');*/ ?>

+ 24
- 4
backend/web/css/screen.css View File

width: 200px; width: 200px;
} }


/* line 4, ../sass/development/_index.scss */
/* line 6, ../sass/development/_index.scss */
.development-index #versions-list .panel .block {
margin-bottom: 15px;
}
/* line 9, ../sass/development/_index.scss */
.development-index #versions-list .panel .block .glyphicon {
font-size: 15px;
margin-right: 3px;
}
/* line 14, ../sass/development/_index.scss */
.development-index #versions-list .panel .block h4 {
font-size: 16px;
border-bottom: solid 1px #e0e0e0;
padding-bottom: 4px;
}
/* line 20, ../sass/development/_index.scss */
.development-index #versions-list .panel .block ul {
padding: 0px;
list-style-type: none;
}
/* line 33, ../sass/development/_index.scss */
.development-index #panel-participate ul.contacts { .development-index #panel-participate ul.contacts {
padding: 0px; padding: 0px;
padding-left: 10px; padding-left: 10px;
margin: 0px; margin: 0px;
list-style-type: none; list-style-type: none;
} }
/* line 10, ../sass/development/_index.scss */
/* line 39, ../sass/development/_index.scss */
.development-index #panel-participate ul.contacts li { .development-index #panel-participate ul.contacts li {
padding-bottom: 10px; padding-bottom: 10px;
} }
/* line 13, ../sass/development/_index.scss */
/* line 42, ../sass/development/_index.scss */
.development-index #panel-participate ul.contacts li .glyphicon { .development-index #panel-participate ul.contacts li .glyphicon {
float: left; float: left;
} }
/* line 17, ../sass/development/_index.scss */
/* line 46, ../sass/development/_index.scss */
.development-index #panel-participate ul.contacts li p { .development-index #panel-participate ul.contacts li p {
padding-left: 25px; padding-left: 25px;
} }

+ 5
- 0
backend/web/js/vuejs/producer-update.js View File

name: 'logiciels-caisse', name: 'logiciels-caisse',
nameDisplay: 'Logiciels de caisse', nameDisplay: 'Logiciels de caisse',
isAdminSection: 0 isAdminSection: 0
},
{
name: 'software',
nameDisplay: 'Opendistrib',
isAdminSection: 0
} }
] ]
}, window.appInitValues); }, window.appInitValues);

+ 29
- 0
backend/web/sass/development/_index.scss View File



.development-index { .development-index {

#versions-list {
.panel {
.block {
margin-bottom: 15px;

.glyphicon {
font-size: 15px;
margin-right: 3px;
}

h4 {
font-size: 16px;
border-bottom: solid 1px #e0e0e0;
padding-bottom: 4px;
}

ul {
padding: 0px;
list-style-type: none;

li {

}
}
}
}
}

#panel-participate { #panel-participate {
ul.contacts { ul.contacts {
padding: 0px; padding: 0px;

+ 0
- 1
common/components/BusinessLogic.php View File

$this->getUserProducerContainer(), $this->getUserProducerContainer(),
$this->getUserPointSaleContainer(), $this->getUserPointSaleContainer(),
$this->getUserContainer(), $this->getUserContainer(),
$this->getOrderSatusHistoryContainer(),
$this->getPointSaleDistributionContainer(), $this->getPointSaleDistributionContainer(),
$this->getProductDistributionContainer(), $this->getProductDistributionContainer(),
$this->getProductCategoryContainer(), $this->getProductCategoryContainer(),

+ 0
- 12
common/components/BusinessLogicTrait.php View File

use common\logic\Document\Quotation\Wrapper\QuotationManager; use common\logic\Document\Quotation\Wrapper\QuotationManager;
use common\logic\Order\Order\Wrapper\OrderContainer; use common\logic\Order\Order\Wrapper\OrderContainer;
use common\logic\Order\Order\Wrapper\OrderManager; use common\logic\Order\Order\Wrapper\OrderManager;
use common\logic\Order\OrderStatusHistory\Wrapper\OrderStatusHistoryContainer;
use common\logic\Order\OrderStatusHistory\Wrapper\OrderStatusHistoryManager;
use common\logic\Order\ProductOrder\Wrapper\ProductOrderContainer; use common\logic\Order\ProductOrder\Wrapper\ProductOrderContainer;
use common\logic\Order\ProductOrder\Wrapper\ProductOrderManager; use common\logic\Order\ProductOrder\Wrapper\ProductOrderManager;
use common\logic\PointSale\PointSale\Wrapper\PointSaleContainer; use common\logic\PointSale\PointSale\Wrapper\PointSaleContainer;
return QuotationManager::getInstance(); return QuotationManager::getInstance();
} }


public function getOrderStatusHistoryManager(): OrderStatusHistoryManager
{
return OrderStatusHistoryManager::getInstance();
}

public function getProductOrderManager(): ProductOrderManager public function getProductOrderManager(): ProductOrderManager
{ {
return ProductOrderManager::getInstance(); return ProductOrderManager::getInstance();
return OrderContainer::getInstance(); return OrderContainer::getInstance();
} }


public function getOrderSatusHistoryContainer(): OrderStatusHistoryContainer
{
return OrderStatusHistoryContainer::getInstance();
}

public function getUserPointSaleContainer(): UserPointSaleContainer public function getUserPointSaleContainer(): UserPointSaleContainer
{ {
return UserPointSaleContainer::getInstance(); return UserPointSaleContainer::getInstance();

+ 21
- 3
common/config/main.php View File

*/ */


use common\components\BusinessLogic; use common\components\BusinessLogic;
use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Ticket\Ticket\Model\Ticket;
use common\logic\User\CreditHistory\Model\CreditHistory;


$serverName = isset($_SERVER['SERVER_NAME']) ?? ''; $serverName = isset($_SERVER['SERVER_NAME']) ?? '';


return [ return [
'bootstrap' => ['listener'],
'aliases' => [ 'aliases' => [
'@bower' => '@vendor/bower-asset', '@bower' => '@vendor/bower-asset',
], ],
'enablePrettyUrl' => true, 'enablePrettyUrl' => true,
'showScriptName' => false, 'showScriptName' => false,
'enableStrictParsing' => false, 'enableStrictParsing' => false,
'rules' => [
],
'rules' => [],
], ],
'logic' => function () { 'logic' => function () {
return new BusinessLogic(); return new BusinessLogic();
}
},
'listener' => [
'class' => \justcoded\yii2\eventlistener\components\EventListener::class,
'listeners' => [],
'observers' => [
CreditHistory::class => [
common\logic\User\UserProducer\Event\CreditHistoryObserver::class
],
Distribution::class => [
common\logic\Subscription\Subscription\Event\DistributionObserver::class
],
Ticket::class => [
common\logic\User\User\Event\TicketObserver::class,
],
],
],
], ],
'language' => 'fr-FR', 'language' => 'fr-FR',
'timeZone' => 'Europe/Paris', 'timeZone' => 'Europe/Paris',

+ 1
- 1
common/config/params.php View File

*/ */


return [ return [
'version' => '23.8.A',
'version' => '23.8.B',
'adminEmail' => 'contact@opendistrib.net', 'adminEmail' => 'contact@opendistrib.net',
'supportEmail' => 'contact@opendistrib.net', 'supportEmail' => 'contact@opendistrib.net',
'user.passwordResetTokenExpire' => 3600, 'user.passwordResetTokenExpire' => 3600,

+ 18
- 0
common/events/EntityManagerEvent.php View File

<?php

namespace common\events;

use yii\base\Event;
use yii\base\Model;

class EntityManagerEvent extends Event
{
const PRE_CREATE_EVENT = 'entity_manager_event.pre_create';
const POST_CREATE_EVENT = 'entity_manager_event.post_create';
const PRE_UPDATE_EVENT = 'entity_manager_event.pre_update';
const POST_UPDATE_EVENT = 'entity_manager_event.post_update';
const PRE_DELETE_EVENT = 'entity_manager_event.pre_delete';
const POST_DELETE_EVENT = 'entity_manager_event.post_delete';

public Model $model;
}

+ 62
- 0
common/helpers/Alwaysdata.php View File

<?php

namespace common\helpers;

use common\logic\Producer\Producer\Model\Producer;
use GuzzleHttp\Client;
use yii\base\ErrorException;

class Alwaysdata
{
public static function createProducerEmailRedirection(Producer $producer)
{
return self::post('mailbox',[
'domain' => \Yii::$app->params['alwaysdataDomainOpendistribId'],
'name' => $producer->slug,
'password' => Password::generate(13),
'redirect_enabled' => true,
'redirect_to' => $producer->contact_email
]);
}

public static function createProducerSiteShortUrlRedirection(Producer $producer)
{
return self::post('site', [
'addresses' => [$producer->slug.'.opendistrib.net'],
'type' => 'redirect',
'url' => 'https://producteurs.opendistrib.net/'.$producer->slug,
'redirect_type' => 'PERMANENT',
'annotation' => 'Opendistrib / '.$producer->name
]);
}

private static function post(string $resource, array $data)
{
$client = self::getClient($resource);

return $client->request('POST', '', [
'body' => json_encode($data)
]);
}

private static function getClient(string $resource)
{
self::checkConfiguration();

return new Client([
'base_uri' => \Yii::$app->params['alwaysdataApiUrl'].$resource.'/',
'auth' => [\Yii::$app->params['alwaysdataApiKey'].' account='.\Yii::$app->params['alwaysdataAccount'], ''],
]);
}

private static function checkConfiguration()
{
if(!isset(\Yii::$app->params['alwaysdataApiUrl'])
|| !isset(\Yii::$app->params['alwaysdataAccount'])
|| !isset(\Yii::$app->params['alwaysdataApiKey'])
|| !isset(\Yii::$app->params['alwaysdataDomainOpendistribId'])) {

throw new ErrorException('Configuration API Alwaysdata absente ou incomplète dans params-local.php');
}
}
}

+ 7
- 0
common/helpers/CSV.php View File



class CSV class CSV
{ {
public static function send(string $filename, array $data)
{
CSV::downloadSendHeaders($filename);
echo CSV::array2csv($data);
die();
}

public static function array2csv(array &$array) public static function array2csv(array &$array)
{ {
$producerManager = ProducerManager::getInstance(); $producerManager = ProducerManager::getInstance();

+ 58
- 0
common/helpers/Image.php View File

<?php

namespace common\helpers;

class Image
{
const DIR_UPLOADS = 'uploads';

const THUMBNAIL_SMALL = 'small';
const THUMBNAIL_MEDIUM = 'medium';
const THUMBNAIL_BIG = 'big';

public static function getThumbnailSmall(string $filenameOriginal, bool $absoluteUrl = false)
{
return self::getThumbnail($filenameOriginal, self::THUMBNAIL_SMALL, $absoluteUrl);
}

public static function getThumbnailMedium(string $filenameOriginal, bool $absoluteUrl = false)
{
return self::getThumbnail($filenameOriginal, self::THUMBNAIL_MEDIUM, $absoluteUrl);
}

public static function getThumbnailBig(string $filenameOriginal, bool $absoluteUrl = false)
{
return self::getThumbnail($filenameOriginal, self::THUMBNAIL_BIG, $absoluteUrl);
}

public static function getThumbnail(string $filenameOriginal, string $thumbnail = self::THUMBNAIL_MEDIUM, bool $absoluteUrl = false)
{
$basePath = self::getBasePath($absoluteUrl);
$thumbnailFilename = self::getThumbnailFilename($filenameOriginal, $thumbnail);
$thumbnailPath = $basePath . $thumbnailFilename;
$originalPath = $basePath . $filenameOriginal;

return self::isThumbnailExist($thumbnailFilename) ? $thumbnailPath : $originalPath;
}

public static function getBasePath(bool $absoluteUrl = false): string
{
$absoluteUrlPrepend = '';
if($absoluteUrl) {
$absoluteUrlPrepend = \Yii::$app->urlManagerProducer->getHostInfo();
}

return $absoluteUrlPrepend . \Yii::$app->urlManagerProducer->baseUrl.'/'.self::DIR_UPLOADS.'/';
}

public static function getThumbnailFilename(string $filename, string $thumbnail = self::THUMBNAIL_MEDIUM)
{
$filenameArray = explode('.', $filename);
return $filenameArray[0].'-'.$thumbnail.'.'.$filenameArray[1];
}

public static function isThumbnailExist(string $thumbnailFilename): bool
{
return file_exists(\Yii::getAlias('@producer').'/web/'.self::DIR_UPLOADS.'/'.$thumbnailFilename);
}
}

+ 1
- 1
common/helpers/Opendistrib.php View File

{ {
$directory = opendir($pathVersions); $directory = opendir($pathVersions);
while( $child = readdir($directory) ){ while( $child = readdir($directory) ){
if($child != '.' && $child != '..'){
if($child != '.' && $child != '..' && $child != '_macros.php'){
$version = str_replace('.php', '', $child); $version = str_replace('.php', '', $child);
$versionsArray[] = $version; $versionsArray[] = $version;
} }

+ 55
- 66
common/helpers/Upload.php View File

<?php <?php


/**
Copyright distrib (2018)
contact@opendistrib.net
Ce logiciel est un programme informatique servant à aider les producteurs
à distribuer leur production en circuits courts.
Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".
En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.
A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/
/**
* Copyright distrib (2018)
*
* contact@opendistrib.net
*
* Ce logiciel est un programme informatique servant à aider les producteurs
* à distribuer leur production en circuits courts.
*
* Ce logiciel est régi par la licence CeCILL soumise au droit français et
* respectant les principes de diffusion des logiciels libres. Vous pouvez
* utiliser, modifier et/ou redistribuer ce programme sous les conditions
* de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
* sur le site "http://www.cecill.info".
*
* En contrepartie de l'accessibilité au code source et des droits de copie,
* de modification et de redistribution accordés par cette licence, il n'est
* offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
* seule une responsabilité restreinte pèse sur l'auteur du programme, le
* titulaire des droits patrimoniaux et les concédants successifs.
*
* A cet égard l'attention de l'utilisateur est attirée sur les risques
* associés au chargement, à l'utilisation, à la modification et/ou au
* développement et à la reproduction du logiciel par l'utilisateur étant
* donné sa spécificité de logiciel libre, qui peut le rendre complexe à
* manipuler et qui le réserve donc à des développeurs et des professionnels
* avertis possédant des connaissances informatiques approfondies. Les
* utilisateurs sont donc invités à charger et tester l'adéquation du
* logiciel à leurs besoins dans des conditions permettant d'assurer la
* sécurité de leurs systèmes et ou de leurs données et, plus généralement,
* à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
*
* Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
* pris connaissance de la licence CeCILL, et que vous en avez accepté les
* termes.
*/


namespace common\helpers; namespace common\helpers;


use yii\web\UploadedFile; use yii\web\UploadedFile;
use Yii ;
use Yii;


class Upload
class Upload
{ {

public static function uploadFile($model, $champs, $filename_old = '')
public static function uploadFile($model, $champs, $filename_old = '')
{ {
$file = UploadedFile::getInstance($model, $champs); $file = UploadedFile::getInstance($model, $champs);
if ($file) { if ($file) {
$file_name = $file->baseName . '-' . uniqid() ;
$file_name_extension = $file_name .'.'.$file->extension ;
$dir_file = '../../producer/web/uploads/' ;
$path_file = $dir_file . $file_name_extension ;
$file_name = $file->baseName . '-' . uniqid();
$file_name_extension = $file_name . '.' . $file->extension;
$dir_file = '../../producer/web/uploads/';
$path_file = $dir_file . $file_name_extension;
$file->saveAs($path_file); $file->saveAs($path_file);
// resize image // resize image
list($width, $height, $type, $attr) = getimagesize($path_file); list($width, $height, $type, $attr) = getimagesize($path_file);
if($width > 500)
{
if ($width > 500) {
$image = Yii::$app->image->load($path_file); $image = Yii::$app->image->load($path_file);
// big // big
if($width > 1600)
{
$image->resize(1600)
->save($dir_file . $file_name . '-big.'.$file->extension);
if ($width > 1600) {
$image->resize(1600)->save($dir_file . $file_name . '-big.' . $file->extension);
} }

// medium // medium
if($width > 1024)
{
$image->resize(1024)->save($dir_file . $file_name_extension) ;
$image->save($dir_file . $file_name . '-medium.'.$file->extension);
if ($width > 1024) {
$image->resize(1024)->save($dir_file . $file_name . '-medium.' . $file->extension);
} }

// small // small
if($width > 500)
{
$image->resize(500)
->save($dir_file . $file_name . '-small.'.$file->extension);
if ($width > 500) {
$image->resize(500)->save($dir_file . $file_name . '-small.' . $file->extension);
} }
} }
$model->$champs = $file_name_extension ;
$model->$champs = $file_name_extension;
} else { } else {
$model->$champs = $filename_old; $model->$champs = $filename_old;
} }


$model->save(); $model->save();
} }

} }

+ 20
- 3
common/logic/AbstractBuilder.php View File



namespace common\logic; namespace common\logic;


use yii\base\Model;
use yii\db\ActiveRecord; use yii\db\ActiveRecord;


abstract class AbstractBuilder extends AbstractService implements BuilderInterface abstract class AbstractBuilder extends AbstractService implements BuilderInterface
{ {
public function saveCreate(ActiveRecord $model): bool
public function create(Model $model): bool
{ {
return $model->save(); return $model->save();
} }


public function saveUpdate(ActiveRecord $model): bool
public function update(Model $model): bool
{ {
return $model->save(); return $model->save();
} }


public function delete(ActiveRecord $model): bool
public function delete(Model $model): bool
{ {
return $model->delete(); return $model->delete();
} }

/**
* @deprecated
*/
public function saveCreate(ActiveRecord $model): bool
{
return $model->save();
}

/**
* @deprecated
*/
public function saveUpdate(ActiveRecord $model): bool
{
return $model->save();
}
} }

+ 8
- 0
common/logic/AbstractGenerator.php View File

<?php

namespace common\logic;

abstract class AbstractGenerator extends AbstractService implements GeneratorInterface
{

}

+ 1
- 0
common/logic/AbstractService.php View File

RepositoryInterface::class, RepositoryInterface::class,
BuilderInterface::class, BuilderInterface::class,
ResolverInterface::class, ResolverInterface::class,
GeneratorInterface::class,
UtilsInterface::class, UtilsInterface::class,
]; ];
} }

+ 0
- 148
common/logic/Development/Development/Development.php View File

<?php

/**
Copyright distrib (2018)

contact@opendistrib.net

Ce logiciel est un programme informatique servant à aider les producteurs
à distribuer leur production en circuits courts.

Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".

En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.

A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.

Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/

namespace common\logic\Development\Development;

use common\helpers\GlobalParam;
use Yii;
use common\components\ActiveRecordCommon ;

/**
* This is the model class for table "development".
*/
class Development extends ActiveRecordCommon
{
const STATUS_OPEN = 'open';
const STATUS_CLOSED = 'closed';
const TYPE_EVOLUTION = 'evolution';
const TYPE_BUG = 'bug';

/**
* @inheritdoc
*/
public static function tableName()
{
return 'development';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['subject', 'date'], 'required'],
[['id', 'progress'], 'integer'],
[['description'], 'string'],
[['date', 'date_delivery'], 'safe'],
[['time_estimate'], 'number'],
[['subject', 'status', 'type'], 'string', 'max' => 255],
];
}

/*
* Relations
*/
public function getDevelopmentPriority()
{
return $this->hasMany(
DevelopmentPriorityModel::className(),
['id_development' => 'id'])
->with('producer');
}

public function getDevelopmentPriorityCurrentProducer()
{
return $this->hasOne(
DevelopmentPriorityModel::className(),
['id_development' => 'id'])
->where(['id_producer' => GlobalParam::getCurrentProducerId()])
->with('producer');
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'subject' => 'Sujet',
'description' => 'Description',
'date' => 'Date',
'progress' => 'Avancement',
'status' => 'Statut',
'time_estimate' => 'Estimation temps',
'type' => 'Type',
'date_delivery' => 'Date de livraison'
];
}
/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function getDefaultOptionsSearch() {
return [
'with' => ['developmentPriority', 'developmentPriorityCurrentProducer'],
'join_with' => [],
'orderby' => 'date DESC',
'attribute_id_producer' => ''
] ;
}
/**
* Définit une date de livraison.
*
* @param string $date
*/
public function setDateDelivery($date = '')
{
if (strlen($date)) {
$this->date_delivery = $date;
}
if (strlen($this->date_delivery)) {
$this->date_delivery = date('Y-m-d', strtotime($this->date_delivery));
}
}

}

+ 0
- 149
common/logic/Development/DevelopmentPriority/DevelopmentPriority.php View File

<?php

/**
Copyright distrib (2018)

contact@opendistrib.net

Ce logiciel est un programme informatique servant à aider les producteurs
à distribuer leur production en circuits courts.

Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".

En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.

A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.

Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/

namespace common\logic\Development\DevelopmentPriority;

use common\logic\Producer\Producer\Producer;
use common\components\ActiveRecordCommon ;

/**
* This is the model class for table "development_priority".
*/
class DevelopmentPriority extends ActiveRecordCommon
{

const PRIORITY_HIGH = 'high';
const PRIORITY_NORMAL = 'normal';
const PRIORITY_LOW = 'low';

/**
* @inheritdoc
*/
public static function tableName()
{
return 'development_priority';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['id_producer', 'id_development'], 'required'],
[['id_producer', 'id_development'], 'integer'],
[['priority'], 'string'],
];
}
/*
* Relations
*/

public function getProducer()
{
return $this->hasOne(Producer::class, ['id' => 'id_producer']);
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id_producer' => 'Producteur',
'id_development' => 'Développement',
'priority' => 'Priorité'
];
}
/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function getDefaultOptionsSearch() {
return [
'with' => [],
'join_with' => [],
'orderby' => '',
'attribute_id_producer' => 'development_priority.id_producer'
] ;
}

/**
* Retourne la priorité.
*
* @return string
*/
public function getStrPriority()
{
switch ($this->priority) {
case self::PRIORITY_LOW : return 'Basse';
break;
case self::PRIORITY_NORMAL : return 'Normale';
break;
case self::PRIORITY_HIGH : return 'Haute';
break;
default: return 'Non définie';
break;
}
}

/**
* Retourne la classe CSS du bouton servant à définir la priorité.
*
* @return string
*/
public function getClassCssStyleButton()
{
$styleButton = 'default';
if ($this->priority == DevelopmentPriorityModel::PRIORITY_LOW) {
$styleButton = 'info';
}
elseif ($this->priority == DevelopmentPriorityModel::PRIORITY_NORMAL) {
$styleButton = 'warning';
}
elseif ($this->priority == DevelopmentPriorityModel::PRIORITY_HIGH) {
$styleButton = 'danger';
}
return $styleButton;
}

}

+ 2
- 11
common/logic/Distribution/Distribution/Model/Distribution.php View File

use common\logic\Distribution\ProductDistribution\Model\ProductDistribution; use common\logic\Distribution\ProductDistribution\Model\ProductDistribution;
use common\logic\Order\Order\Model\Order; use common\logic\Order\Order\Model\Order;
use common\logic\Producer\Producer\Model\Producer; use common\logic\Producer\Producer\Model\Producer;
use common\logic\Subscription\Subscription\Event\SubscriptionEventSubscriber;
use common\logic\Subscription\Subscription\Event\DistributionObserver;


class Distribution extends ActiveRecordCommon class Distribution extends ActiveRecordCommon
{ {
const EVENT_ACTIVE = 'distribution.active';
const EVENT_ACTIVE = 'distribution.event.active';


/** /**
* @inheritdoc * @inheritdoc
]; ];
} }


public function init()
{
parent::init();

$this->on(Distribution::EVENT_ACTIVE, function($event) {
SubscriptionEventSubscriber::onActiveDistribution($event->distribution);
});
}

/* /*
* Relations * Relations
*/ */

+ 3
- 2
common/logic/Distribution/Distribution/Service/DistributionBuilder.php View File

// active // active
public function activeDistribution(Distribution $distribution, bool $active = true): void public function activeDistribution(Distribution $distribution, bool $active = true): void
{ {
$this->pointSaleDistributionBuilder->createAllPointSaleDistributions($distribution, true);
$distribution->active = (int) $active; $distribution->active = (int) $active;
$this->saveUpdate($distribution);
$this->update($distribution);

$this->pointSaleDistributionBuilder->createAllPointSaleDistributions($distribution, true);


if ($active) { if ($active) {
$distributionActiveEvent = new DistributionActiveEvent(); $distributionActiveEvent = new DistributionActiveEvent();

+ 8
- 0
common/logic/GeneratorInterface.php View File

<?php

namespace common\logic;

interface GeneratorInterface
{

}

+ 0
- 17
common/logic/Order/Order/Service/OrderBuilder.php View File

use common\logic\Document\Document\Model\Document; use common\logic\Document\Document\Model\Document;
use common\logic\Order\Order\Model\Order; use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Repository\OrderRepository; use common\logic\Order\Order\Repository\OrderRepository;
use common\logic\Order\OrderStatusHistory\Service\OrderStatusHistoryBuilder;
use common\logic\Order\ProductOrder\Model\ProductOrder; use common\logic\Order\ProductOrder\Model\ProductOrder;
use common\logic\Order\ProductOrder\Service\ProductOrderBuilder; use common\logic\Order\ProductOrder\Service\ProductOrderBuilder;
use common\logic\Order\ProductOrder\Service\ProductOrderSolver; use common\logic\Order\ProductOrder\Service\ProductOrderSolver;
protected ProducerRepository $producerRepository; protected ProducerRepository $producerRepository;
protected CreditHistoryBuilder $creditHistoryBuilder; protected CreditHistoryBuilder $creditHistoryBuilder;
protected ProductOrderBuilder $productOrderBuilder; protected ProductOrderBuilder $productOrderBuilder;
protected OrderStatusHistoryBuilder $orderStatusHistoryBuilder;
protected OrderRepository $orderRepository; protected OrderRepository $orderRepository;
protected DistributionRepository $distributionRepository; protected DistributionRepository $distributionRepository;
protected SubscriptionBuilder $subscriptionBuilder; protected SubscriptionBuilder $subscriptionBuilder;
$this->producerRepository = $this->loadService(ProducerRepository::class); $this->producerRepository = $this->loadService(ProducerRepository::class);
$this->creditHistoryBuilder = $this->loadService(CreditHistoryBuilder::class); $this->creditHistoryBuilder = $this->loadService(CreditHistoryBuilder::class);
$this->productOrderBuilder = $this->loadService(ProductOrderBuilder::class); $this->productOrderBuilder = $this->loadService(ProductOrderBuilder::class);
$this->orderStatusHistoryBuilder = $this->loadService(OrderStatusHistoryBuilder::class);
$this->orderRepository = $this->loadService(OrderRepository::class); $this->orderRepository = $this->loadService(OrderRepository::class);
$this->distributionRepository = $this->loadService(DistributionRepository::class); $this->distributionRepository = $this->loadService(DistributionRepository::class);
$this->subscriptionBuilder = $this->loadService(SubscriptionBuilder::class); $this->subscriptionBuilder = $this->loadService(SubscriptionBuilder::class);
/** /**
* Ajoute l'abonnement' pour une date donnée. * Ajoute l'abonnement' pour une date donnée.
*/ */
// add
public function createOrderFromSubscription(Subscription $subscription, string $date, bool $force = false): ?Order public function createOrderFromSubscription(Subscription $subscription, string $date, bool $force = false): ?Order
{ {
$now = date('Y-m-d'); $now = date('Y-m-d');
/** /**
* Ajoute les commandes pour une date donnée à partir des abonnements. * Ajoute les commandes pour une date donnée à partir des abonnements.
*/ */
// addAll
// createAllFromSubscriptions
public function createAllOrdersFromSubscriptions(string $date, bool $force = false): array public function createAllOrdersFromSubscriptions(string $date, bool $force = false): array
{ {
$orderArray = []; $orderArray = [];
return $orderArray; return $orderArray;
} }


// updateIncomingDistributions
public function updateOrdersIncomingDistributionsFromSubscription(Subscription $subscription, $update = false): array public function updateOrdersIncomingDistributionsFromSubscription(Subscription $subscription, $update = false): array
{ {
$orderArray = []; $orderArray = [];
return $productsAdd; return $productsAdd;
} }


// updateFromSubscription
public function updateOrderFromSubscription(Order $order, Subscription $subscription): void public function updateOrderFromSubscription(Order $order, Subscription $subscription): void
{ {
$this->initOrderBaseFromSubscription($order, $subscription); $this->initOrderBaseFromSubscription($order, $subscription);
$order->tiller_synchronization = $order->auto_payment; $order->tiller_synchronization = $order->auto_payment;
} }


// addUserPointSale
public function createUserPointSale(Order $order): void public function createUserPointSale(Order $order): void
{ {
if ($order->user) { if ($order->user) {
} }
} }


// initCommentPointSale
public function initOrderCommentPointSale(Order $order): void public function initOrderCommentPointSale(Order $order): void
{ {
if ($order->user && $order->pointSale) { if ($order->user && $order->pointSale) {
$this->addProductOrderVat($order, $typeTotal, $price * $productOrder->quantity, $productOrder->taxRate, $taxCalculationMethod); $this->addProductOrderVat($order, $typeTotal, $price * $productOrder->quantity, $productOrder->taxRate, $taxCalculationMethod);
} }


// addVat
public function addProductOrderVat( public function addProductOrderVat(
Order $order, Order $order,
string $typeTotal, string $typeTotal,
} }
} }


// delete
public function deleteOrder(Order $order, bool $force = false): bool public function deleteOrder(Order $order, bool $force = false): bool
{ {
$this->initOrder($order); $this->initOrder($order);
} }
} }


// setTillerSynchronization
// updateTillerSynchronization
public function updateOrderTillerSynchronization(Order $order, int $synchroTiller = null): void public function updateOrderTillerSynchronization(Order $order, int $synchroTiller = null): void
{ {
if (!is_null($synchroTiller)) { if (!is_null($synchroTiller)) {
/** /**
* Changement de statut d'une commande. * Changement de statut d'une commande.
*/ */
// changeOrderStatus
public function updateOrderStatus(Order $order, string $newStatus, string $origin): void public function updateOrderStatus(Order $order, string $newStatus, string $origin): void
{ {
$orderStatusArray = GlobalParam::get('orderStatus'); $orderStatusArray = GlobalParam::get('orderStatus');


switch ($newStatus) { switch ($newStatus) {
case 'new-order' : case 'new-order' :
//$this->orderStatusHistoryBuilder->createOrderStatusHistory($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus; $order->status = $newStatus;
$order->save(); $order->save();
break; break;
case 'refunded': case 'refunded':
case 'cancel': case 'cancel':
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) { if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) {
//$this->orderStatusHistoryBuilder->createOrderStatusHistory($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus; $order->status = $newStatus;
$order->save(); $order->save();
} }

+ 0
- 72
common/logic/Order/OrderStatusHistory/Model/OrderStatusHistory.php View File

<?php

namespace common\logic\Order\OrderStatusHistory\Model;

use common\components\ActiveRecordCommon;
use common\logic\Order\Order\Model\Order;
use common\logic\User\User\Model\User;

/**
* This is the model class for table "order_status_history".
*/
class OrderStatusHistory extends ActiveRecordCommon
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'order_status_history';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['id_order', 'status', 'id_user', 'date', 'origin'], 'required'],
[['id_order', 'id_user',], 'integer'],
[['date'], 'safe'],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_order' => 'Commande',
'id_user' => 'Utilisateur',
'status' => 'Statut',
'origin' => 'Origine',
'date' => 'Date',
];
}

/*
* Relations
*/

public function getOrder()
{
return $this->hasOne(Order::class, ['id' => 'id_order']);
}

public function populateOrder(Order $order): void
{
$this->populateFieldObject('id_order', 'order', $order);
}

public function getUser()
{
return $this->hasOne(User::class, ['id' => 'id_user']);
}

public function populateUser(User $user): void
{
$this->populateFieldObject('id_user', 'user', $user);
}
}

+ 0
- 25
common/logic/Order/OrderStatusHistory/Repository/OrderStatusHistoryRepository.php View File

<?php

namespace common\logic\Order\OrderStatusHistory\Repository;

use common\logic\AbstractRepository;

class OrderStatusHistoryRepository extends AbstractRepository
{
protected OrderStatusHistoryRepositoryQuery $query;

public function loadDependencies(): void
{
$this->loadQuery(OrderStatusHistoryRepositoryQuery::class);
}

public function getDefaultOptionsSearch(): array
{
return [
self::WITH => [],
self::JOIN_WITH => ['order', 'orderStatus'],
self::ORDER_BY => 'date ASC',
self::ATTRIBUTE_ID_PRODUCER => ''
];
}
}

+ 0
- 18
common/logic/Order/OrderStatusHistory/Repository/OrderStatusHistoryRepositoryQuery.php View File

<?php

namespace common\logic\Order\OrderStatusHistory\Repository;

use common\logic\AbstractRepositoryQuery;
use common\logic\Order\OrderStatusHistory\Model\OrderStatusHistory;
use common\logic\Order\OrderStatusHistory\Service\OrderStatusHistoryDefinition;
use yii\db\ActiveQuery;

class OrderStatusHistoryRepositoryQuery extends AbstractRepositoryQuery
{
protected OrderStatusHistoryDefinition $definition;

public function loadDependencies(): void
{
$this->loadDefinition(OrderStatusHistoryDefinition::class);
}
}

+ 0
- 39
common/logic/Order/OrderStatusHistory/Service/OrderStatusHistoryBuilder.php View File

<?php

namespace common\logic\Order\OrderStatusHistory\Service;

use common\logic\AbstractBuilder;
use common\logic\Order\Order\Model\Order;
use common\logic\Order\OrderStatusHistory\Model\OrderStatusHistory;
use common\logic\User\User\Model\User;
use common\logic\User\User\Service\UserSolver;

class OrderStatusHistoryBuilder extends AbstractBuilder
{
protected UserSolver $userSolver;

public function loadDependencies(): void
{
$this->userSolver = $this->loadService(UserSolver::class);
}

public function instanciateOrderStatusHistory(Order $order, User $user, string $status, string $origin): OrderStatusHistory
{
$orderStatusHistory = new OrderStatusHistory();
$orderStatusHistory->populateOrder($order);
$orderStatusHistory->populateUser($user);
$orderStatusHistory->status = $status;
$orderStatusHistory->origin = $origin;
$orderStatusHistory->date = date('Y-m-d H:i:s');

return $orderStatusHistory;
}

public function createOrderStatusHistory(Order $order, User $user, string $status, string $origin): OrderStatusHistory
{
$orderStatusHistory = $this->instanciateOrderStatusHistory($order, $user, $status, $origin);
$this->saveCreate($orderStatusHistory);

return $orderStatusHistory;
}
}

+ 0
- 14
common/logic/Order/OrderStatusHistory/Service/OrderStatusHistoryDefinition.php View File

<?php

namespace common\logic\Order\OrderStatusHistory\Service;

use common\logic\AbstractDefinition;
use common\logic\Order\OrderStatusHistory\Model\OrderStatusHistory;

class OrderStatusHistoryDefinition extends AbstractDefinition
{
public function getEntityFqcn(): string
{
return OrderStatusHistory::class;
}
}

+ 0
- 35
common/logic/Order/OrderStatusHistory/Wrapper/OrderStatusHistoryContainer.php View File

<?php

namespace common\logic\Order\OrderStatusHistory\Wrapper;

use common\logic\AbstractContainer;
use common\logic\Order\OrderStatusHistory\Repository\OrderStatusHistoryRepository;
use common\logic\Order\OrderStatusHistory\Service\OrderStatusHistoryBuilder;
use common\logic\Order\OrderStatusHistory\Service\OrderStatusHistoryDefinition;

class OrderStatusHistoryContainer extends AbstractContainer
{
public function getServices(): array
{
return [
OrderStatusHistoryDefinition::class,
OrderStatusHistoryRepository::class,
OrderStatusHistoryBuilder::class
];
}

public function getDefinition(): OrderStatusHistoryDefinition
{
return OrderStatusHistoryDefinition::getInstance();
}

public function getRepository(): OrderStatusHistoryRepository
{
return OrderStatusHistoryRepository::getInstance();
}

public function getBuilder(): OrderStatusHistoryBuilder
{
return OrderStatusHistoryBuilder::getInstance();
}
}

+ 0
- 21
common/logic/Order/OrderStatusHistory/Wrapper/OrderStatusHistoryManager.php View File

<?php

namespace common\logic\Order\OrderStatusHistory\Wrapper;

use common\logic\AbstractManager;
use common\logic\Order\OrderStatusHistory\Repository\OrderStatusHistoryRepository;
use common\logic\Order\OrderStatusHistory\Service\OrderStatusHistoryBuilder;
use common\logic\Order\OrderStatusHistory\Service\OrderStatusHistoryDefinition;

/**
* @mixin OrderStatusHistoryDefinition
* @mixin OrderStatusHistoryRepository
* @mixin OrderStatusHistoryBuilder
*/
class OrderStatusHistoryManager extends AbstractManager
{
public function getContainerFqcn(): string
{
return OrderStatusHistoryContainer::class;
}
}

+ 11
- 3
common/logic/Producer/Producer/Model/Producer.php View File

'option_tax_calculation_method', 'option_tax_calculation_method',
'latest_version_opendistrib', 'latest_version_opendistrib',
'option_csv_separator', 'option_csv_separator',
'option_point_sale_wording'
'option_point_sale_wording',
'option_testimony',
'contact_email',
'admin_comment',
], ],
'string' 'string'
], ],
'credit_limit', 'credit_limit',
'option_billing_permanent_transfer_amount', 'option_billing_permanent_transfer_amount',
'latitude', 'latitude',
'longitude'
'longitude',
'option_time_saved'
], 'double'], ], 'double'],
[ [
'free_price', 'free_price',
'option_billing_permanent_transfer_amount' => 'Virement permanent : montant', 'option_billing_permanent_transfer_amount' => 'Virement permanent : montant',
'option_point_sale_wording' => 'Libellé points de vente', 'option_point_sale_wording' => 'Libellé points de vente',
'latitude' => 'Latitude', 'latitude' => 'Latitude',
'longitude' => 'Longitude'
'longitude' => 'Longitude',
'option_testimony' => 'Témoignage',
'option_time_saved' => 'Temps gagné / semaine',
'contact_email' => 'Email de contact',
'admin_comment' => 'Commentaire'
]; ];
} }



+ 38
- 2
common/logic/Producer/Producer/Repository/ProducerRepository.php View File

if ($isBold) $text .= '<strong>'; if ($isBold) $text .= '<strong>';
$text .= $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, true); $text .= $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, true);
if ($isBold) $text .= '</strong>'; if ($isBold) $text .= '</strong>';
$text .= ' / ' . Price::format($turnover, 0);
$text .= ' (' . Price::format($turnover, 0). ' CA)';
$text .= '<br />'; $text .= '<br />';


$sumInvoicePrice += $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, false); $sumInvoicePrice += $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, false);
} }
} }


if($numberOfMonths > 1) {
if($numberOfMonths > 1 && $sumInvoicePrice > 0) {
$text .= '<br />Total : <strong>'.Price::format($sumInvoicePrice, 0).'</strong>'; $text .= '<br />Total : <strong>'.Price::format($sumInvoicePrice, 0).'</strong>';
} }


{ {
return $this->createQuery()->find(); return $this->createQuery()->find();
} }

public function findProducersWithTestimonials(): array
{
return $this->queryProducersActive()
->filterHasOptionTestimony()
->find();
}

public function findProducersWithTimeSaved(): array
{
return $this->queryProducersActive()
->filterHasOptionTimeSaved()
->find();
}

public function countProducersWithTimeSaved(): int
{
return count($this->findProducersWithTimeSaved());
}

public function getTimeSavedByProducersAverage(): int
{
$producersWithTimeSavedArray = $this->findProducersWithTimeSaved();
$countProducersWithOptionTimeSaved = count($producersWithTimeSavedArray);

if($countProducersWithOptionTimeSaved) {
$sumTimeSaved = 0;
foreach($producersWithTimeSavedArray as $producerWithTimeSaved) {
$sumTimeSaved += $producerWithTimeSaved->option_time_saved;
}

return round($sumTimeSaved / $countProducersWithOptionTimeSaved);
}

return 0;
}
} }

+ 12
- 0
common/logic/Producer/Producer/Repository/ProducerRepositoryQuery.php View File

$this->andWhere('name LIKE \'Démo\''); $this->andWhere('name LIKE \'Démo\'');
return $this; return $this;
} }

public function filterHasOptionTestimony(): self
{
$this->andWhere('option_testimony IS NOT NULL AND option_testimony != ""');
return $this;
}

public function filterHasOptionTimeSaved(): self
{
$this->andWhere('producer.option_time_saved > 0');
return $this;
}
} }

+ 1
- 1
common/logic/Product/Product/Model/Product.php View File

public function afterFind() public function afterFind()
{ {
if ($this->taxRate == null) { if ($this->taxRate == null) {
$producer = Producer::searchOne(['id' => GlobalParam::getCurrentProducerId()]);
$producer = Producer::searchOne(['id' => $this->id_producer]);
if ($producer) { if ($producer) {
$this->populateRelation('taxRate', $producer->taxRate); $this->populateRelation('taxRate', $producer->taxRate);
} }

+ 26
- 0
common/logic/Subscription/Subscription/Event/DistributionObserver.php View File

<?php

namespace common\logic\Subscription\Subscription\Event;

use common\logic\Distribution\Distribution\Event\DistributionActiveEvent;
use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Order\Order\Wrapper\OrderManager;
use justcoded\yii2\eventlistener\observers\Observer;

class DistributionObserver extends Observer
{
public function events()
{
return [
Distribution::EVENT_ACTIVE => 'onDistributionActive'
];
}

public static function onDistributionActive(DistributionActiveEvent $event): void
{
$distribution = $event->distribution;
$orderManager = OrderManager::getInstance();

$orderManager->createAllOrdersFromSubscriptions($distribution->date);
}
}

+ 0
- 15
common/logic/Subscription/Subscription/Event/SubscriptionEventSubscriber.php View File

<?php

namespace common\logic\Subscription\Subscription\Event;

use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Order\Order\Wrapper\OrderManager;

class SubscriptionEventSubscriber
{
public static function onActiveDistribution(Distribution $distribution): void
{
$orderManager = OrderManager::getInstance();
$orderManager->createAllOrdersFromSubscriptions($distribution->date);
}
}

+ 3
- 0
common/logic/Ticket/Ticket/Model/Ticket.php View File

namespace common\logic\Ticket\Ticket\Model; namespace common\logic\Ticket\Ticket\Model;


use common\components\ActiveRecordCommon; use common\components\ActiveRecordCommon;
use common\events\EntityManagerEvent;
use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Producer\Producer\Model\Producer; use common\logic\Producer\Producer\Model\Producer;
use common\logic\Subscription\Subscription\Event\DistributionObserver;
use common\logic\Ticket\TicketMessage\Model\TicketMessage; use common\logic\Ticket\TicketMessage\Model\TicketMessage;
use common\logic\Ticket\TicketUser\Model\TicketUser; use common\logic\Ticket\TicketUser\Model\TicketUser;
use common\logic\User\User\Model\User; use common\logic\User\User\Model\User;

+ 4
- 4
common/logic/Ticket/Ticket/Service/TicketBuilder.php View File

public function createTicket(Producer $producer, User $user): Ticket public function createTicket(Producer $producer, User $user): Ticket
{ {
$ticket = $this->instanciateTicket($producer, $user); $ticket = $this->instanciateTicket($producer, $user);
$this->saveCreate($ticket);
$this->create($ticket);


return $ticket; return $ticket;
} }
public function updateTicketStatus(Ticket $ticket, string $status) public function updateTicketStatus(Ticket $ticket, string $status)
{ {
$ticket->status = $status; $ticket->status = $status;
$this->saveUpdate($ticket);
$this->update($ticket);


$this->updateTicketUpdatedAt($ticket); $this->updateTicketUpdatedAt($ticket);
} }
public function updateTicketUpdatedAt(Ticket $ticket) public function updateTicketUpdatedAt(Ticket $ticket)
{ {
$ticket->updated_at = date('Y-m-d H:i:s'); $ticket->updated_at = date('Y-m-d H:i:s');
$this->saveUpdate($ticket);
$this->update($ticket);
} }


public function createTicketMessage(TicketMessage $ticketMessage) public function createTicketMessage(TicketMessage $ticketMessage)
{ {
$this->updateTicketUpdatedAt($ticketMessage->ticket); $this->updateTicketUpdatedAt($ticketMessage->ticket);
return $this->saveCreate($ticketMessage);
return $this->create($ticketMessage);
} }


public function viewTicket(Ticket $ticket, User $user) public function viewTicket(Ticket $ticket, User $user)

+ 0
- 12
common/logic/User/CreditHistory/Event/CreditHistoryCreateEvent.php View File

<?php

namespace common\logic\User\CreditHistory\Event;

use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\User\CreditHistory\Model\CreditHistory;
use yii\base\Event;

class CreditHistoryCreateEvent extends Event
{
public CreditHistory $creditHistory;
}

+ 0
- 11
common/logic/User/CreditHistory/Model/CreditHistory.php View File



class CreditHistory extends ActiveRecordCommon class CreditHistory extends ActiveRecordCommon
{ {
const EVENT_CREATE = 'creditHistory.create';

const TYPE_INITIAL_CREDIT = 'initial-credit'; const TYPE_INITIAL_CREDIT = 'initial-credit';
const TYPE_CREDIT = 'credit'; const TYPE_CREDIT = 'credit';
const TYPE_PAYMENT = 'payment'; const TYPE_PAYMENT = 'payment';
]; ];
} }


public function init()
{
$this->on(CreditHistory::EVENT_CREATE, function($event) {
UserProducerEventSubscriber::onCreateCreditHistory($event);
});

parent::init();
}

/* /*
* Relations * Relations
*/ */

+ 1
- 6
common/logic/User/CreditHistory/Service/CreditHistoryBuilder.php View File

use common\logic\Order\Order\Model\Order; use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Service\OrderSolver; use common\logic\Order\Order\Service\OrderSolver;
use common\logic\Producer\Producer\Model\Producer; use common\logic\Producer\Producer\Model\Producer;
use common\logic\User\CreditHistory\Event\CreditHistoryCreateEvent;
use common\logic\User\CreditHistory\Model\CreditHistory; use common\logic\User\CreditHistory\Model\CreditHistory;
use common\logic\User\User\Model\User; use common\logic\User\User\Model\User;
use yii\base\Event; use yii\base\Event;


$creditHistory = $this->instanciateCreditHistory($type, $amount, $producer, $user, $userAction, $meanPayment, $order); $creditHistory = $this->instanciateCreditHistory($type, $amount, $producer, $user, $userAction, $meanPayment, $order);
$creditHistory->setComment($creditHistory->getComment() . $this->orderSolver->getCreditHistoryComment($creditHistory)); $creditHistory->setComment($creditHistory->getComment() . $this->orderSolver->getCreditHistoryComment($creditHistory));
$this->saveCreate($creditHistory);

$creditHistoryCreateEvent = new CreditHistoryCreateEvent();
$creditHistoryCreateEvent->creditHistory = $creditHistory;
$creditHistory->trigger(CreditHistory::EVENT_CREATE, $creditHistoryCreateEvent);
$this->create($creditHistory);


return $creditHistory; return $creditHistory;
} }

+ 132
- 0
common/logic/User/CreditHistory/Service/CreditUtils.php View File

<?php

namespace common\logic\User\CreditHistory\Service;

use common\helpers\MeanPayment;
use common\logic\AbstractService;
use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Service\OrderSolver;
use common\logic\Producer\Producer\Repository\ProducerRepository;
use common\logic\User\CreditHistory\Model\CreditHistory;
use common\logic\User\User\Model\User;
use common\logic\User\User\Repository\UserRepository;
use common\logic\UtilsInterface;
use yii\base\ErrorException;

class CreditUtils extends AbstractService implements UtilsInterface
{
protected CreditHistoryBuilder $creditHistoryBuilder;
protected OrderSolver $orderSolver;
protected ProducerRepository $producerRepository;
protected UserRepository $userRepository;

public function loadDependencies(): void
{
$this->creditHistoryBuilder = $this->loadService(CreditHistoryBuilder::class);
$this->orderSolver = $this->loadService(OrderSolver::class);
$this->producerRepository = $this->loadService(ProducerRepository::class);
$this->userRepository = $this->loadService(UserRepository::class);
}

public function creditUser(User $user, float $amount, string $meanPayment, User $userAction): void
{
$this->creditHistoryBuilder->createCreditHistory(
CreditHistory::TYPE_CREDIT,
$amount,
$this->getProducerContext(),
$user,
$userAction,
$meanPayment
);
}

public function debitUser(User $user, float $amount, string $meanPayment, User $userAction): void
{
$this->creditHistoryBuilder->createCreditHistory(
CreditHistory::TYPE_DEBIT,
$amount,
$this->getProducerContext(),
$user,
$userAction,
$meanPayment
);
}

public function creditOrDebitUser(string $type, User $user, float $amount, string $meanPayment, User $userAction): void
{
if($type == CreditHistory::TYPE_CREDIT) {
$this->creditUser($user, $amount, $meanPayment, $userAction);
}
elseif($type == CreditHistory::TYPE_DEBIT) {
$this->debitUser($user, $amount, $meanPayment, $userAction);
}
else {
throw new ErrorException('$type a une valeur incorrect');
}
}

public function payOrder(Order $order, User $userAction, bool $checkCreditLimit): void
{
$amountRemaining = $this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_REMAINING);

if($checkCreditLimit) {
$creditLimit = $this->producerRepository->getConfig('credit_limit');
$creditUser = $this->userRepository->getCredit($order->user);

if (!is_null($creditLimit) && $amountRemaining > $creditUser - $creditLimit) {
$amountRemaining = $creditUser - $creditLimit;
}
}

if($amountRemaining > 0) {
$this->creditHistoryBuilder->createCreditHistory(
CreditHistory::TYPE_PAYMENT,
$amountRemaining,
$this->getProducerContext(),
$order->user,
$userAction,
MeanPayment::CREDIT,
$order
);
}
}

public function refundOrder(Order $order, User $userAction): void
{
$this->creditHistoryBuilder->createCreditHistory(
CreditHistory::TYPE_REFUND,
$this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_PAID),
$this->getProducerContext(),
$order->user,
$userAction,
MeanPayment::CREDIT,
$order
);
}

public function refundSurplusOrder(Order $order, User $userAction): void
{
$this->creditHistoryBuilder->createCreditHistory(
CreditHistory::TYPE_REFUND,
$this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_SURPLUS),
$this->getProducerContext(),
$order->user,
$userAction,
MeanPayment::CREDIT,
$order
);
}

public function payOrRefundOrder(string $type, Order $order, User $userAction, bool $checkCreditLimit = false): void
{
if($type == CreditHistory::TYPE_PAYMENT) {
$this->payOrder($order, $userAction, $checkCreditLimit);
}
elseif($type == CreditHistory::TYPE_REFUND) {
$this->refundOrder($order, $userAction);
}
else {
throw new ErrorException('$type a une valeur incorrect');
}
}
}

+ 7
- 0
common/logic/User/CreditHistory/Wrapper/CreditHistoryContainer.php View File

use common\logic\User\CreditHistory\Service\CreditHistoryBuilder; use common\logic\User\CreditHistory\Service\CreditHistoryBuilder;
use common\logic\User\CreditHistory\Service\CreditHistoryDefinition; use common\logic\User\CreditHistory\Service\CreditHistoryDefinition;
use common\logic\User\CreditHistory\Service\CreditHistorySolver; use common\logic\User\CreditHistory\Service\CreditHistorySolver;
use common\logic\User\CreditHistory\Service\CreditUtils;


class CreditHistoryContainer extends AbstractContainer class CreditHistoryContainer extends AbstractContainer
{ {
CreditHistorySolver::class, CreditHistorySolver::class,
CreditHistoryBuilder::class, CreditHistoryBuilder::class,
CreditHistoryRepository::class, CreditHistoryRepository::class,
CreditUtils::class,
]; ];
} }


{ {
return CreditHistoryRepository::getInstance(); return CreditHistoryRepository::getInstance();
} }

public function getCreditUtils(): CreditUtils
{
return CreditUtils::getInstance();
}
} }

+ 2
- 0
common/logic/User/CreditHistory/Wrapper/CreditHistoryManager.php View File

use common\logic\User\CreditHistory\Service\CreditHistoryBuilder; use common\logic\User\CreditHistory\Service\CreditHistoryBuilder;
use common\logic\User\CreditHistory\Service\CreditHistoryDefinition; use common\logic\User\CreditHistory\Service\CreditHistoryDefinition;
use common\logic\User\CreditHistory\Service\CreditHistorySolver; use common\logic\User\CreditHistory\Service\CreditHistorySolver;
use common\logic\User\CreditHistory\Service\CreditUtils;


/** /**
* @mixin CreditHistoryDefinition * @mixin CreditHistoryDefinition
* @mixin CreditHistorySolver * @mixin CreditHistorySolver
* @mixin CreditHistoryRepository * @mixin CreditHistoryRepository
* @mixin CreditHistoryBuilder * @mixin CreditHistoryBuilder
* @mixin CreditUtils
*/ */
class CreditHistoryManager extends AbstractManager class CreditHistoryManager extends AbstractManager
{ {

+ 17
- 0
common/logic/User/User/Event/TicketObserver.php View File

<?php
namespace common\logic\User\User\Event;

use common\logic\User\User\Wrapper\UserManager;
use justcoded\yii2\eventlistener\observers\ActiveRecordObserver;
use yii\db\AfterSaveEvent;

class TicketObserver extends ActiveRecordObserver
{
public function inserted(AfterSaveEvent $event)
{
$ticket = $event->sender;
$userManager = UserManager::getInstance();

$userManager->sendMailNewTicketAdmin($ticket);
}
}

+ 32
- 2
common/logic/User/User/Repository/UserRepository.php View File

public function queryUsersBy(array $params = []) public function queryUsersBy(array $params = [])
{ {
if (!isset($params['id_producer'])) { if (!isset($params['id_producer'])) {
$params['id_producer'] = GlobalParam::getCurrentProducerId();
$params['id_producer'] = $this->getProducerContextId();
} }


$query = (new Query()) $query = (new Query())
->select(['user.id AS user_id', 'user.name', 'user.lastname', 'user.phone', 'user.email', 'user.created_at', 'user.date_last_connection', 'user_producer.*', 'user.address', 'user.name_legal_person'])
->select(['user.id AS user_id', 'user.type', 'user.name', 'user.lastname', 'user.phone', 'user.email', 'user.created_at', 'user.date_last_connection', 'user_producer.*', 'user.address', 'user.name_legal_person'])
->from('user'); ->from('user');


$active = (isset($params['inactive']) && $params['inactive']) ? 0 : 1; $active = (isset($params['inactive']) && $params['inactive']) ? 0 : 1;
return $query; return $query;
} }


public function queryUsersWithNegativeCredit()
{
return $this->queryUsersBy()
->andWhere('user_producer.credit < 0')
->orderBy('credit ASC');
}

public function findUsersWithNegativeCredit()
{
return $this->queryUsersWithNegativeCredit()->all();
}

public function queryUsersWithPositiveCredit()
{
return $this->queryUsersBy()
->andWhere('user_producer.credit > 0')
->orderBy('lastname, name ASC');
}

public function findUsersWithPositiveCredit()
{
return $this->queryUsersWithPositiveCredit()->all();
}

/** /**
* Finds user by password reset token * Finds user by password reset token
*/ */


return count($results); return count($results);
} }

public function isActive(User $user)
{
$userProducer = $this->userProducerRepository->findOneUserProducer($user);
return $userProducer ? $userProducer->active : false;
}
} }

+ 18
- 3
common/logic/User/User/Service/UserBuilder.php View File

$user->password_reset_token = null; $user->password_reset_token = null;
} }


public function grantAccess(User $user): bool
{
if($this->userRepository->isActive($user)) {
$user->id_producer = $this->getProducerContextId();
$user->status = User::STATUS_PRODUCER;
return $user->save();
}

return false;
}

public function deleteAccess(User $user): bool public function deleteAccess(User $user): bool
{ {
$user->id_producer = 0;
$user->status = User::STATUS_ACTIVE;
return $user->save();
if($this->userRepository->isActive($user)) {
$user->id_producer = null;
$user->status = User::STATUS_ACTIVE;
return $user->save();
}

return false;
} }
} }

+ 27
- 8
common/logic/User/User/Service/UserSolver.php View File

$username = ''; $username = '';
if (isset($modelArray['name_legal_person']) && strlen($modelArray['name_legal_person'])) { if (isset($modelArray['name_legal_person']) && strlen($modelArray['name_legal_person'])) {
$username = $modelArray['name_legal_person']; $username = $modelArray['name_legal_person'];

if ($withType) {
$username = 'Personne morale / ' . $username;
}
} else { } else {
$username = $modelArray['lastname'] . ' ' . $modelArray['name']; $username = $modelArray['lastname'] . ' ' . $modelArray['name'];
} }


if ($withType && $modelArray['type'] == User::TYPE_LEGAL_PERSON) {
$username = $username . ' (personne morale)';
}

return $username; return $username;
} }


public function getContactSummaryFromArrayAsHtml(array $user): string
{
$html = '';

if (strlen($user['phone'])) {
$html .= $user['phone'];
}

if (strlen($user['phone']) && strlen($user['email'])) {
$html .= '<br />';
}

if (strlen($user['email'])) {
$html .= $user['email'];
}

return $html;
}

public function getUsername(User $user, $withType = false): string public function getUsername(User $user, $withType = false): string
{ {
$username = ''; $username = '';
if (isset($user->name_legal_person) && strlen($user->name_legal_person)) { if (isset($user->name_legal_person) && strlen($user->name_legal_person)) {
$username = $user->name_legal_person; $username = $user->name_legal_person;

if ($withType) {
$username = 'Personne morale / ' . $username;
}
} else { } else {
$username = $user->lastname . ' ' . $user->name; $username = $user->lastname . ' ' . $user->name;
} }


if ($withType) {
$username = $username . ' (personne morale)';
}

return $username; return $username;
} }



+ 19
- 1
common/logic/User/User/Service/UserUtils.php View File

use common\helpers\Mailjet; use common\helpers\Mailjet;
use common\logic\AbstractService; use common\logic\AbstractService;
use common\logic\Producer\Producer\Model\Producer; use common\logic\Producer\Producer\Model\Producer;
use common\logic\Ticket\Ticket\Model\Ticket;
use common\logic\User\User\Model\User; use common\logic\User\User\Model\User;
use common\logic\UtilsInterface; use common\logic\UtilsInterface;


/** /**
* Envoie un email de bienvenue à l'utilisateur lors de son inscription * Envoie un email de bienvenue à l'utilisateur lors de son inscription
* via le backend du site. * via le backend du site.
*
*/ */
public function sendMailWelcome(User $user, string $password): void public function sendMailWelcome(User $user, string $password): void
{ {
->send(); ->send();
} }
} }

public function sendMailNewTicketAdmin(Ticket $ticket)
{
$adminEmail = \Yii::$app->params['adminEmail'];

Mailjet::sendMail([
'from_email' => $adminEmail,
'from_name' => 'Opendistrib',
'to_email' => $adminEmail,
'to_name' => 'Opendistrib',
'subject' => '[Opendistrib] Nouveau ticket',
'content_view_text' => '@common/mail/newTicketAdmin-text.php',
'content_view_html' => '@common/mail/newTicketAdmin-html.php',
'content_params' => [
'ticket' => $ticket,
]
]);
}
} }

+ 50
- 0
common/logic/User/User/Service/UsersCreditCsvGenerator.php View File

<?php

namespace common\logic\User\User\Service;

use common\helpers\CSV;
use common\helpers\Price;
use common\logic\User\User\Repository\UserRepository;
use common\logic\AbstractGenerator;
use yii\base\ErrorException;

class UsersCreditCsvGenerator extends AbstractGenerator
{
protected UserSolver $userSolver;
protected UserRepository $userRepository;

public function loadDependencies(): void
{
$this->userSolver = $this->loadService(UserSolver::class);
$this->userRepository = $this->loadService(UserRepository::class);
}

public function exportUsersCreditAsCsv(string $type)
{
if($type == 'negative') {
$filename = 'Utilisateurs_credit_negatif.csv';
$usersArray = $this->userRepository->findUsersWithNegativeCredit();
}
elseif($type == 'positive') {
$filename = 'Utilisateurs_credit_positif.csv';
$usersArray = $this->userRepository->findUsersWithPositiveCredit();
}
else {
throw new ErrorException('Le paramètre $type est invalide.');
}

$data = [
['Client', 'Email', 'Téléphone', 'Crédit']
];
foreach($usersArray as $user) {
$data[] = [
$this->userSolver->getUsernameFromArray($user, true),
$user['email'],
$user['phone'],
Price::format($user['credit']),
];
}

CSV::send($filename, $data);
}
}

+ 4
- 0
common/logic/User/User/Wrapper/UserContainer.php View File



use common\logic\AbstractContainer; use common\logic\AbstractContainer;
use common\logic\User\User\Repository\UserRepository; use common\logic\User\User\Repository\UserRepository;
use common\logic\User\User\Repository\UserRepositoryQuery;
use common\logic\User\User\Service\UserBuilder; use common\logic\User\User\Service\UserBuilder;
use common\logic\User\User\Service\UserDefinition; use common\logic\User\User\Service\UserDefinition;
use common\logic\User\User\Service\UsersCreditCsvGenerator;
use common\logic\User\User\Service\UserSolver; use common\logic\User\User\Service\UserSolver;
use common\logic\User\User\Service\UserUtils; use common\logic\User\User\Service\UserUtils;


return [ return [
UserDefinition::class, UserDefinition::class,
UserSolver::class, UserSolver::class,
UserRepositoryQuery::class,
UserRepository::class, UserRepository::class,
UserBuilder::class, UserBuilder::class,
UsersCreditCsvGenerator::class,
UserUtils::class, UserUtils::class,
]; ];
} }

+ 2
- 0
common/logic/User/User/Wrapper/UserManager.php View File

use common\logic\User\User\Repository\UserRepository; use common\logic\User\User\Repository\UserRepository;
use common\logic\User\User\Service\UserBuilder; use common\logic\User\User\Service\UserBuilder;
use common\logic\User\User\Service\UserDefinition; use common\logic\User\User\Service\UserDefinition;
use common\logic\User\User\Service\UsersCreditCsvGenerator;
use common\logic\User\User\Service\UserSolver; use common\logic\User\User\Service\UserSolver;
use common\logic\User\User\Service\UserUtils; use common\logic\User\User\Service\UserUtils;


* @mixin UserRepository * @mixin UserRepository
* @mixin UserBuilder * @mixin UserBuilder
* @mixin UserUtils * @mixin UserUtils
* @mixin UsersCreditCsvGenerator
*/ */
class UserManager extends AbstractManager class UserManager extends AbstractManager
{ {

+ 18
- 0
common/logic/User/UserProducer/Event/CreditHistoryObserver.php View File

<?php

namespace common\logic\User\UserProducer\Event;

use common\logic\User\UserProducer\Wrapper\UserProducerManager;
use justcoded\yii2\eventlistener\observers\ActiveRecordObserver;
use yii\db\AfterSaveEvent;

class CreditHistoryObserver extends ActiveRecordObserver
{
public function inserted(AfterSaveEvent $event)
{
$creditHistory = $event->sender;
$userProducerManager = UserProducerManager::getInstance();

$userProducerManager->updateCredit($creditHistory);
}
}

+ 0
- 14
common/logic/User/UserProducer/Event/UserProducerEventSubscriber.php View File

<?php

namespace common\logic\User\UserProducer\Event;

use common\logic\User\UserProducer\Wrapper\UserProducerManager;

class UserProducerEventSubscriber
{
public static function onCreateCreditHistory($event)
{
$userProducerManager = UserProducerManager::getInstance();
$userProducerManager->updateCredit($event->creditHistory);
}
}

+ 19
- 0
common/logic/User/UserProducer/Repository/UserProducerRepository.php View File

$userProducer = $this->findOneUserProducer($user); $userProducer = $this->findOneUserProducer($user);
return $userProducer ? $userProducer->bookmark : false; return $userProducer ? $userProducer->bookmark : false;
} }

public function findUserProducersWithNegativeOrPositiveCredit()
{
return $this->createDefaultQuery()
->filterHasNegativeOrPositiveCredit()
->find();
}

public function sumUserProducerCredits()
{
$sumUserProducersCredits = 0;
$userProducersWithNegativeOrPositiveCreditArray = $this->findUserProducersWithNegativeOrPositiveCredit();

foreach ($userProducersWithNegativeOrPositiveCreditArray as $userProducerWithNegativeOrPositiveCredit) {
$sumUserProducersCredits += $userProducerWithNegativeOrPositiveCredit->credit;
}

return $sumUserProducersCredits;
}
} }

+ 7
- 0
common/logic/User/UserProducer/Repository/UserProducerRepositoryQuery.php View File

$this->andWhere(['bookmark' => $bookmark]); $this->andWhere(['bookmark' => $bookmark]);
return $this; return $this;
} }

public function filterHasNegativeOrPositiveCredit(): self
{
$this->andWhere('user_producer.credit IS NOT NULL AND user_producer.credit != 0');

return $this;
}
} }

+ 29
- 20
common/logic/User/UserProducer/Service/UserProducerBuilder.php View File

public function createUserProducer(User $user, Producer $producer, int $bookmark = 1): UserProducer public function createUserProducer(User $user, Producer $producer, int $bookmark = 1): UserProducer
{ {
$userProducer = $this->instanciateUserProducer($user, $producer, $bookmark); $userProducer = $this->instanciateUserProducer($user, $producer, $bookmark);
$this->saveCreate($userProducer);
$this->create($userProducer);
return $userProducer; return $userProducer;
} }


$userProducer->setCredit($userProducer->getCredit() - $creditHistory->getAmount()); $userProducer->setCredit($userProducer->getCredit() - $creditHistory->getAmount());
} }


$this->saveUpdate($userProducer);
$this->update($userProducer);
} }


public function initMeanPaymentOrder($creditHistory) public function initMeanPaymentOrder($creditHistory)


$order->mean_payment = MeanPayment::CREDIT; $order->mean_payment = MeanPayment::CREDIT;


$this->saveUpdate($order);
$this->update($order);
} }
} }
} }
$user = $userRepository->findOneUserById($creditHistory->id_user); $user = $userRepository->findOneUserById($creditHistory->id_user);
$producer = $producerRepository->findOneProducerById($creditHistory->id_producer); $producer = $producerRepository->findOneProducerById($creditHistory->id_producer);


\Yii::$app->mailer->compose(
[
'html' => 'creditLimitReminder-html',
'text' => 'creditLimitReminder-text'
],
[
'user' => $user,
'producer' => $producer,
'credit' => $newCredit
]
)
->setTo($user->email)
->setFrom(['contact@opendistrib.net' => 'Opendistrib'])
->setSubject('[Opendistrib] Seuil limite de crédit dépassé')
->send();
if($user && $user->email && strlen($user->email) > 0) {
\Yii::$app->mailer->compose(
[
'html' => 'creditLimitReminder-html',
'text' => 'creditLimitReminder-text'
],
[
'user' => $user,
'producer' => $producer,
'credit' => $newCredit
]
)
->setTo($user->email)
->setFrom(['contact@opendistrib.net' => 'Opendistrib'])
->setSubject('[Opendistrib] Seuil limite de crédit dépassé')
->send();
}
} }
} }




$userProducer->active = $active; $userProducer->active = $active;


return $this->saveUpdate($userProducer);
return $this->update($userProducer);
} }


public function updateBookmark(UserProducer $userProducer, bool $bookmark) public function updateBookmark(UserProducer $userProducer, bool $bookmark)
{ {
$userProducer->bookmark = $bookmark; $userProducer->bookmark = $bookmark;
return $this->saveUpdate($userProducer);
return $this->update($userProducer);
} }


public function addProducerBookmark(User $user) public function addProducerBookmark(User $user)
$userProducer = $this->createUserProducerIfNotExist($user, $this->getProducerContext()); $userProducer = $this->createUserProducerIfNotExist($user, $this->getProducerContext());
return $this->updateBookmark($userProducer, false); return $this->updateBookmark($userProducer, false);
} }

public function unlinkUserProducer(UserProducer $userProducer)
{
$userProducer->active = 0;
$userProducer->bookmark = 0;
return $this->update($userProducer);
}
} }

+ 14
- 0
common/logic/User/UserProducer/Service/UserProducerSolver.php View File

<?php

namespace common\logic\User\UserProducer\Service;

use common\logic\AbstractSolver;
use common\logic\User\UserProducer\Model\UserProducer;

class UserProducerSolver extends AbstractSolver
{
public function hasOutstandingCredit(UserProducer $userProducer): bool
{
return $userProducer->credit < 0 || $userProducer->credit > 0;
}
}

+ 2
- 0
common/logic/User/UserProducer/Wrapper/UserProducerContainer.php View File

use common\logic\User\UserProducer\Repository\UserProducerRepository; use common\logic\User\UserProducer\Repository\UserProducerRepository;
use common\logic\User\UserProducer\Service\UserProducerBuilder; use common\logic\User\UserProducer\Service\UserProducerBuilder;
use common\logic\User\UserProducer\Service\UserProducerDefinition; use common\logic\User\UserProducer\Service\UserProducerDefinition;
use common\logic\User\UserProducer\Service\UserProducerSolver;


class UserProducerContainer extends AbstractContainer class UserProducerContainer extends AbstractContainer
{ {
{ {
return [ return [
UserProducerDefinition::class, UserProducerDefinition::class,
UserProducerSolver::class,
UserProducerRepository::class, UserProducerRepository::class,
UserProducerBuilder::class, UserProducerBuilder::class,
]; ];

+ 46
- 0
common/mail/newTicketAdmin-html.php View File

<?php

/**
Copyright distrib (2018)

contact@opendistrib.net

Ce logiciel est un programme informatique servant à aider les producteurs
à distribuer leur production en circuits courts.

Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".

En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.

A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.

Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/

use yii\helpers\Html;

?>

<p>Un nouveau ticket vient d'être ouvert par <strong><?= Html::encode($ticket->producer->name) ?></strong> :
<a href="<?= Yii::$app->urlManagerBackend->createAbsoluteUrl(['support/view', 'id' => $ticket->id]) ?>"><?= Html::encode($ticket->subject) ?></a>.</p>



+ 47
- 0
common/mail/newTicketAdmin-text.php View File

<?php

/**
Copyright distrib (2018)

contact@opendistrib.net

Ce logiciel est un programme informatique servant à aider les producteurs
à distribuer leur production en circuits courts.

Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".

En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.

A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.

Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/

use yii\helpers\Html;

?>

Un nouveau ticket vient d'être ouvert par <?= Html::encode($ticket->producer->name) ?> : <?= Html::encode($ticket->subject) ?>.

<?= Yii::$app->urlManagerBackend->createAbsoluteUrl(['support/view', 'id' => $ticket->id]) ?>



+ 31
- 42
common/versions/22.10.A.php View File

<?php


<h4>Date de sortie</h4>
<ul>
<li>25/10/2022</li>
</ul>
require_once dirname(__FILE__).'/_macros.php';


<h4>Évolutions</h4>
<ul>
<li>[Administration] Distributions > commandes : ajout ligne avec montant total et poids par point de vente</li>
<li>[Administration] Distributions > formulaire commande : ajout champs prix HT</li>
<li>[Administration] Produits, Utilisateurs, Statistiques et Documents : accès rapide en un clic</li>
<li>[Administration] Produits > liste : possibilité de modifier directement le champs "actif"</li>
<li>[Administration] Utilisateurs > commandes : ajout lien vers modification</li>
<li>
[Administration] Documents > modification : mise en évidence des prix incohérents par rapport à ceux définis au
niveau des produits
</li>
<li>[Administration] Documents > liste : ajout champs "Envoyé"</li>
<li>[Administration] Documents > factures > liste : filtre par utilisateur</li>
<li>[Administration] Paramètres : tri et réagencement</li>
<li>[Administration] Développement : page de suivi des versions du logiciel (liste des évolutions et correctifs)</li>
<li>[Espace producteur] Formulaire de contact avec protection par captcha</li>
</ul>
version(
'25/10/2022',
[
"[Administration] Distributions > commandes : ajout ligne avec montant total et poids par point de vente",
"[Administration] Distributions > formulaire commande : ajout champs prix HT",
"[Administration] Produits, Utilisateurs, Statistiques et Documents : accès rapide en un clic",
"[Administration] Produits > liste : possibilité de modifier directement le champs 'actif'",
"[Administration] Utilisateurs > commandes : ajout lien vers modification",
"[Administration] Documents > modification : mise en évidence des prix incohérents par rapport à ceux définis au niveau des produits",
"[Administration] Documents > liste : ajout champs 'Envoyé'",
"[Administration] Documents > factures > liste : filtre par utilisateur",
"[Administration] Paramètres : tri et réagencement",
"[Administration] Développement : page de suivi des versions du logiciel (liste des évolutions et correctifs)",
"[Espace producteur] Formulaire de contact avec protection par captcha"
],
[
"[Administration] Produits > modification : prise en compte des prix spécifiques lors de la mise à jour automatique des commandes des distributions futures",
"[Administration] Produits > prix spécifiques : prise en compte des prix par groupe d'utilisateur et point de vente",
"[Administration] Utilisateurs > crédit : correctif champs 'Commentaire' trop long",
"[Administration] Utilisateurs > liste : correctif nombre de commandes",
"[Administration] Distributions > modification commande : correctif modification prix",
"[Administration] Distributions > modification commande : adaptation changement du point de vente lors de la sélection d'un utilisateur",
"[Administration] Haut de page : utilisateurs vides dans le bloc 'Utilisateurs au crédit négatif'",
"[Administration] Abonnements : ne pas générer de commandes pour le jour même",
"[Backend] Facture > créer : tri des utilisateurs par ordre alphabétique",
"Correctif connexion personnes morales"
]
);


<h4>Correctifs</h4>
<ul>
<li>
[Administration] Produits > modification : prise en compte des prix spécifiques lors de la mise à jour automatique
des commandes des distributions futures
</li>
<li>
[Administration] Produits > prix spécifiques : prise en compte des prix par groupe d'utilisateur et point de vente
</li>
<li>[Administration] Utilisateurs > crédit : correctif champs "Commentaire" trop long</li>
<li>[Administration] Utilisateurs > liste : correctif nombre de commandes</li>
<li>[Administration] Distributions > modification commande : correctif modification prix</li>
<li>
[Administration] Distributions > modification commande : adaptation changement du point de vente lors de la
sélection d'un utilisateur
</li>
<li>[Administration] Haut de page : utilisateurs vides dans le bloc "Utilisateurs au crédit négatif"</li>
<li>[Administration] Abonnements : ne pas générer de commandes pour le jour même</li>
<li>[Backend] Facture > créer : tri des utilisateurs par ordre alphabétique</li>
<li>Correctif connexion personnes morales</li>
</ul>
?>

+ 14
- 14
common/versions/22.11.A.php View File

<?php


<h4>Date de sortie</h4>
<ul>
<li>08/11/2022</li>
</ul>
require_once dirname(__FILE__) . '/_macros.php';


<h4>Évolutions</h4>
<ul>
<li>[Administration] Documents > édition : liens vers les commandes associées</li>
<li>[Administration] Distributions > édition commande : bouton de réinitialisation des prix facturés</li>
</ul>
version(
'08/11/2022',
[
"[Administration] Documents > édition : liens vers les commandes associées",
"[Administration] Distributions > édition commande : bouton de réinitialisation des prix facturés"
],
[
"[Administration] Abonnements : suppression des commandes après la date de fin lors de l'arrêt d'un abonnement",
"[Administration] Distributions > calendrier : amélioration chargement automatique des distributions (affichage pastilles vertes)"
]
);


<h4>Maintenance</h4>
<ul>
<li>[Administration] Abonnements : suppression des commandes après la date de fin lors de l'arrêt d'un abonnement</li>
<li>[Administration] Distributions > calendrier : amélioration chargement automatique des distributions (affichage pastilles vertes)</li>
</ul>
?>

+ 15
- 12
common/versions/22.11.B.php View File

<?php


<h4>Date de sortie</h4>
<ul>
<li>22/11/2022</li>
</ul>
require_once dirname(__FILE__) . '/_macros.php';


<h4>Évolutions</h4>
<ul>
<li>[Administration] Documents > factures : gestion des bons de livraison associés</li>
<li>[Administration] Communiquer : possibilité de ne pas inclure la liste des produits dans le message</li>
<li>[Administration] Paramètres : possibilité de configurer le séparateur CSV</li>
<li>[Administration] Paramètres > paiement en ligne : montant minimum configurable</li>
<li>[Administration] Développement : mise en avant des nouvelles versions et des informations de contact</li>
</ul>
version(
'22/11/2022',
[
"[Administration] Documents > factures : gestion des bons de livraison associés",
"[Administration] Communiquer : possibilité de ne pas inclure la liste des produits dans le message",
"[Administration] Paramètres : possibilité de configurer le séparateur CSV",
"[Administration] Paramètres > paiement en ligne : montant minimum configurable",
"[Administration] Développement : mise en avant des nouvelles versions et des informations de contact"
],
[]
);

?>

+ 12
- 9
common/versions/22.12.A.php View File

<?php


<h4>Date de sortie</h4>
<ul>
<li>06/12/2022</li>
</ul>
require_once dirname(__FILE__) . '/_macros.php';


<h4>Évolutions</h4>
<ul>
<li>[Administration] Listes d'utilisateurs : ordre alphabétique + champs de recherche rapide (commandes, abonnements, documents, points de vente)</li>
<li>[Administration] Abonnements : comportement paiement automatique (déduit, oui, non)</li>
</ul>
version(
'06/12/2022',
[
"[Administration] Listes d'utilisateurs : ordre alphabétique + champs de recherche rapide (commandes, abonnements, documents, points de vente)",
"[Administration] Abonnements : comportement paiement automatique (déduit, oui, non)"
],
[]
);

?>

+ 13
- 13
common/versions/23.1.A.php View File

<?php


<h4>Date de sortie</h4>
<ul>
<li>23/01/2023</li>
</ul>
require_once dirname(__FILE__) . '/_macros.php';


<h4>Évolutions</h4>
<ul>
<li>[Administration] Documents : possibilité de regénérer les PDF</li>
</ul>
version(
'23/01/2023',
[
"[Administration] Documents : possibilité de regénérer les PDF"
],
[
"[Administration] Documents > listes : optimisation chargement",
"[Espace producteur] Commander : ajustement ordre des points de vente"
]
);


<h4>Maintenance</h4>
<ul>
<li>[Administration] Documents > listes : optimisation chargement</li>
<li>[Espace producteur] Commander : ajustement ordre des points de vente</li>
</ul>
?>

+ 16
- 18
common/versions/23.3.A.php View File

<h4>Date de sortie</h4>
<ul>
<li>27/03/2023</li>
</ul>
<?php


<h4>Évolutions</h4>
<ul>
<li>
[Administration] Distributions > édition/création commande : bouton unique "Créer" ou "Modifier".
La gestion du crédit est désormais automatiquement déduite du contexte (utilisateur, point de vente).
</li>
<li>
[Administration] Paramètres : ajout d'une option pour configurer le libellé "Points de vente" affiché sur l'accueil
et le tunnel de commande de l'espace producteur.
</li>
<li>
[Administration] Export vers le logiciel Evoliz : ajout de la TVA + code classification vente
</li>
</ul>
require_once dirname(__FILE__) . '/_macros.php';

version(
'27/03/2023',
[
"[Administration] Distributions > édition/création commande : bouton unique 'Créer' ou 'Modifier'.
La gestion du crédit est désormais automatiquement déduite du contexte (utilisateur, point de vente).",
"[Administration] Paramètres : ajout d'une option pour configurer le libellé 'Points de vente' affiché sur l'accueil
et le tunnel de commande de l'espace producteur.",
"[Administration] Export vers le logiciel Evoliz : ajout de la TVA + code classification vente"
],
[]
);

?>

+ 14
- 19
common/versions/23.4.A.php View File

<h4>Date de sortie</h4>
<ul>
<li>27/04/2023</li>
</ul>
<?php


<h4>Évolutions</h4>
<ul>
<li>
[Administration] Distributions > édition commande : possibilité de modifier les prix facturés
</li>
<li>
[Administration] Produits > import prix : possibilité d'importer des prix sur base d'un fichier CSV
</li>
</ul>
require_once dirname(__FILE__) . '/_macros.php';


<h4>Maintenance</h4>
<ul>
<li>
Logiciel de caisse Tiller : synchronisation des commandes partiellement payées
</li>
</ul>
version(
'27/04/2023',
[
"[Administration] Distributions > édition commande : possibilité de modifier les prix facturés",
"[Administration] Produits > import prix : possibilité d'importer des prix sur base d'un fichier CSV"
],
[
"Logiciel de caisse Tiller : synchronisation des commandes partiellement payées"
]
);

?>

+ 17
- 13
common/versions/23.6.A.php View File

<h4>Date de sortie</h4>
<ul>
<li>12/06/2023</li>
</ul>
<?php


<h4>Maintenance</h4>
<ul>
<li>[Administration] Logiciel de caisse Tiller : synchroniser automatiquement les commandes payées avec le crédit</li>
<li>[Administration] Correction affichage des points de vente supprimés</li>
<li>[Administration] Distribution > ajout commande : gestion de 5 chiffres après la virgule pour les prix HT</li>
<li>[Administration] Produits > liste : amélioration responsive</li>
<li>[Espace producteur] Produits : mise en évidence des noms de produit</li>
<li>[Site] Profil utilisateur : permettre édition adresse email</li>
</ul>
require_once dirname(__FILE__) . '/_macros.php';

version(
'12/06/2023',
[],
[
"[Administration] Logiciel de caisse Tiller : synchroniser automatiquement les commandes payées avec le crédit",
"[Administration] Correction affichage des points de vente supprimés",
"[Administration] Distribution > ajout commande : gestion de 5 chiffres après la virgule pour les prix HT",
"[Administration] Produits > liste : amélioration responsive",
"[Espace producteur] Produits : mise en évidence des noms de produit",
"[Site] Profil utilisateur : permettre édition adresse email"
],
);

?>

+ 23
- 22
common/versions/23.6.B.php View File

<h4>Date de sortie</h4>
<ul>
<li>22/06/2023</li>
</ul>
<?php


<h4>Évolutions</h4>
<ul>
<li>[Administration et Espace producteur] Calendrier pour le choix du jour de distribution : affichage du lundi en premier</li>
<li>[Administration] Distribution : alerte remboursement commandes lors de la désactivation d'une distribution</li>
<li>[Administration] Distribution > édition commande : alerte si quantité max d'un produit dépassée</li>
<li>[Administration] Distributions > liste commandes : ajout lien vers fiche client (crédit, profil, commandes)</li>
<li>[Administration] Documents > Bons de livraison : alerte suppression produits</li>
<li>[Administration] Distributions > formulaire commande : raccourci "Entrée" pour passer à la ligne du dessous</li>
<li>[Administration] Utilisateur > édition : ajout info contact facturation</li>
<li>[Administration] Responsive > listes : accès facilité aux boutons d'action</li>
<li>[Espace producteur] Accueil : gestion visibilité produits présents uniquement sur un point de vente à accès restreint</li>
<li>[Espace producteur] Commande > choix du point de vente : ajout informations en fonction du jour choisi</li>
</ul>
require_once dirname(__FILE__) . '/_macros.php';


<h4>Maintenance</h4>
<ul>
<li>[Espace producteur] Abonnements : correctif disponibilité produits par point de vente</li>
<li>Abonnements > ajout/modification : prise en compte des contraintes de délai et d'heure limite de commande dans la génération des commandes des distributions à venir</li>
</ul>
version(
'22/06/2023',
[
"[Administration et Espace producteur] Calendrier pour le choix du jour de distribution : affichage du lundi en premier",
"[Administration] Distribution : alerte remboursement commandes lors de la désactivation d'une distribution",
"[Administration] Distribution > édition commande : alerte si quantité max d'un produit dépassée",
"[Administration] Distributions > liste commandes : ajout lien vers fiche client (crédit, profil, commandes)",
"[Administration] Documents > Bons de livraison : alerte suppression produits",
"[Administration] Distributions > formulaire commande : raccourci 'Entrée' pour passer à la ligne du dessous",
"[Administration] Utilisateur > édition : ajout info contact facturation",
"[Administration] Responsive > listes : accès facilité aux boutons d'action",
"[Espace producteur] Accueil : gestion visibilité produits présents uniquement sur un point de vente à accès restreint",
"[Espace producteur] Commande > choix du point de vente : ajout informations en fonction du jour choisi"
],
[
"[Espace producteur] Abonnements : correctif disponibilité produits par point de vente",
"Abonnements > ajout/modification : prise en compte des contraintes de délai et d'heure limite de commande dans la génération des commandes des distributions à venir"
]
);

?>

+ 14
- 10
common/versions/23.7.A.php View File

<h4>Date de sortie</h4>
<ul>
<li>03/07/2023</li>
</ul>
<?php


<h4>Maintenance</h4>
<ul>
<li>[Administration] Calendrier : couleur du jour sélectionné plus prononcée</li>
<li>[Administration] Distributions > Produits : possibilité de définir une quantité maximum à 0</li>
<li>[Technique] Réécriture requêtes bases de données</li>
</ul>
require_once dirname(__FILE__) . '/_macros.php';

version(
'03/07/2023',
[],
[
'[Administration] Calendrier : couleur du jour sélectionné plus prononcée',
'[Administration] Distributions > Produits : possibilité de définir une quantité maximum à 0',
'[Technique] Réécriture requêtes bases de données'
]
);

?>

+ 15
- 11
common/versions/23.8.A.php View File

<h4>Date de sortie</h4>
<ul>
<li>17/08/2023</li>
</ul>
<?php


<h4>Évolutions</h4>
<ul>
<li>[Administration] Système de support</li>
<li>[Site] Évolution du contenu et mise en page : carte et liste des producteurs, à propos, fonctionnalités, code source.</li>
<li>[Site] Lien "Je demande une démo"</li>
<li>[Site & espace producteur] Barre de navigation en haut du site</li>
</ul>
require_once dirname(__FILE__).'/_macros.php';

version(
'17/08/2023',
[
'[Administration] Système de support',
'[Site] Évolution du contenu et mise en page : carte et liste des producteurs, à propos, fonctionnalités, code source.',
'[Site] Lien "Je demande une démo"',
'[Site & espace producteur] Barre de navigation en haut du site'
],
[]
);

?>

+ 19
- 0
common/versions/23.8.B.php View File

<?php

require_once dirname(__FILE__).'/_macros.php';

version(
'28/08/2023',
[
"[Administration] Utilisateurs : page crédit (somme totale en crédit, liste des clients à relancer, exports CSV)",
"[Administration et espace producteur] Témoignages producteurs : possibilité de saisir un témoignage sur l'utilisation du logiciel dans 'Paramètres > Opendistrib' puis affichage des témoignages sur la page 'À propos'.",
"[Administration] Utilisateur : retour à la liste après modification",
'[Espace producteur] Produits : lien "En savoir plus" pour afficher la description longue',
"[Espace producteur] Commande : affichage d'un message s'il n'y a aucune distributions à venir",
],
[
"[Administration et espace producteur] Produits : optimisation de l'affichage des images"
]
);

?>

+ 43
- 0
common/versions/_macros.php View File

<?php

function version(string $date, array $featuresArray, array $maintenanceArray) {
release_date($date);
features($featuresArray);
maintenance($maintenanceArray);
}

function release_date(string $date) {
$html = '<div class="block">';
$html .= '<h4><span class="glyphicon glyphicon-calendar"></span> Date de sortie</h4>';
$html .= '<ul><li>'.$date.'</li></ul>';
$html .= '</div>';
echo $html;
}

function features(array $featuresArray) {
if(count($featuresArray) > 0) {
$html = '<div class="block">';
$html .= '<h4><span class="glyphicon glyphicon-flash"></span> Évolutions</h4>';
$html .= '<ul>';
foreach($featuresArray as $feature) {
$html .= '<li>'.$feature.'</li>';
}
$html .= '</ul>';
$html .= '</div>';
echo $html;
}
}

function maintenance(array $maintenanceArray) {
if(count($maintenanceArray) > 0) {
$html = '<div class="block">';
$html .= '<h4><span class="glyphicon glyphicon-wrench"></span> Maintenance</h4>';
$html .= '<ul>';
foreach($maintenanceArray as $maintenance) {
$html .= '<li>'.$maintenance.'</li>';
}
$html .= '</ul>';
$html .= '</div>';
echo $html;
}
}

+ 3
- 1
composer.json View File

"bower-asset/jquery": "^3.6", "bower-asset/jquery": "^3.6",
"yidas/yii2-bower-asset": "2.0.13.1", "yidas/yii2-bower-asset": "2.0.13.1",
"stripe/stripe-php": "^7.95", "stripe/stripe-php": "^7.95",
"loveorigami/yii2-bootstrap-toggle": "*"
"loveorigami/yii2-bootstrap-toggle": "*",
"justcoded/yii2-event-listener": "*",
"ext-pdo": "*"
}, },
"require-dev": { "require-dev": {
"yiisoft/yii2-codeception": "*", "yiisoft/yii2-codeception": "*",

+ 50
- 2
composer.lock View File

"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "85c783330a1d88a3ed3c4674e84d10ba",
"content-hash": "7da17be4685def1e9635cc5ab5e5a7d9",
"packages": [ "packages": [
{ {
"name": "2amigos/yii2-chartjs-widget", "name": "2amigos/yii2-chartjs-widget",
], ],
"time": "2022-06-20T21:43:03+00:00" "time": "2022-06-20T21:43:03+00:00"
}, },
{
"name": "justcoded/yii2-event-listener",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/justcoded/yii2-event-listener.git",
"reference": "7407899c71241a92b6508561cf1527e5f097ca57"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/justcoded/yii2-event-listener/zipball/7407899c71241a92b6508561cf1527e5f097ca57",
"reference": "7407899c71241a92b6508561cf1527e5f097ca57",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
"yiisoft/yii2": "~2.0.11"
},
"type": "yii2-extension",
"autoload": {
"psr-4": {
"justcoded\\yii2\\eventlistener\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Alex Prokopenko",
"email": "aprokopenko@justcoded.com"
}
],
"description": "Yii2 Event Listener",
"keywords": [
"event listener",
"events",
"listeners",
"yii2"
],
"support": {
"issues": "https://github.com/justcoded/yii2-event-listener/issues",
"source": "https://github.com/justcoded/yii2-event-listener/tree/1.0.2"
},
"time": "2019-06-24T17:11:24+00:00"
},
{ {
"name": "kartik-v/yii2-mpdf", "name": "kartik-v/yii2-mpdf",
"version": "dev-master", "version": "dev-master",
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": ">=7.4"
"php": ">=7.4",
"ext-pdo": "*"
}, },
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "2.3.0" "plugin-api-version": "2.3.0"

+ 27
- 0
console/commands/DemoAccountController.php View File

<?php

namespace console\commands;

use common\logic\Distribution\Distribution\Wrapper\DistributionManager;
use common\logic\Producer\Producer\Wrapper\ProducerManager;
use yii\console\Controller;

class DemoAccountController extends Controller
{
public function actionIndex()
{
$producerManager = ProducerManager::getInstance();
$distributionManager = DistributionManager::getInstance();

$producerDemo = $producerManager->findOneProducerDemoAccount();
\Yii::$app->logic->setProducerContext($producerDemo);

if ($producerDemo) {
$dateTime = strtotime("+7 day");
$distribution = $distributionManager->createDistributionIfNotExist(date('Y-m-d', $dateTime));
$distributionManager->activeDistribution($distribution);
}
}
}

?>

+ 1
- 1
console/config/main.php View File

'id' => 'app-console', 'id' => 'app-console',
'basePath' => dirname(__DIR__), 'basePath' => dirname(__DIR__),
'bootstrap' => ['log'], 'bootstrap' => ['log'],
'controllerNamespace' => 'console\controllers',
'controllerNamespace' => 'console\commands',
'components' => [ 'components' => [
'log' => [ 'log' => [
'targets' => [ 'targets' => [

+ 0
- 0
console/controllers/.gitkeep View File


+ 28
- 0
console/migrations/m230821_061757_producer_add_option_testimony.php View File

<?php

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

/**
* Class m230821_061757_producer_add_option_testimony
*/
class m230821_061757_producer_add_option_testimony extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('producer', 'option_testimony', Schema::TYPE_TEXT);
$this->addColumn('producer', 'option_time_saved', Schema::TYPE_FLOAT);
}

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

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save