Преглед на файлове

Merge branch 'develop'

master
Guillaume Bourgeois преди 3 месеца
родител
ревизия
f75ba6219d
променени са 93 файла, в които са добавени 2050 реда и са изтрити 343 реда
  1. +13
    -0
      backend/config/main.php
  2. +162
    -0
      backend/controllers/AccessoryController.php
  3. +7
    -2
      backend/controllers/BackendController.php
  4. +15
    -23
      backend/controllers/CommunicateController.php
  5. +22
    -9
      backend/controllers/DistributionController.php
  6. +5
    -0
      backend/controllers/DocumentController.php
  7. +1
    -1
      backend/controllers/OrderController.php
  8. +3
    -0
      backend/controllers/ReportController.php
  9. +9
    -4
      backend/controllers/UserController.php
  10. +2
    -1
      backend/controllers/admin/CommunicateAdminController.php
  11. +2
    -3
      backend/controllers/admin/DashboardAdminController.php
  12. +2
    -1
      backend/controllers/admin/FeatureAdminController.php
  13. +3
    -2
      backend/controllers/admin/OnlineAdminController.php
  14. +77
    -0
      backend/controllers/admin/OrderAdminController.php
  15. +2
    -2
      backend/controllers/admin/ProducerAdminController.php
  16. +2
    -4
      backend/controllers/admin/SettingAdminController.php
  17. +5
    -4
      backend/controllers/admin/StatsAdminController.php
  18. +2
    -1
      backend/controllers/admin/SupportAdminController.php
  19. +2
    -1
      backend/controllers/admin/TaxRateAdminController.php
  20. +4
    -3
      backend/controllers/admin/UserAdminController.php
  21. +3
    -0
      backend/views/_include/form_actions.php
  22. +1
    -1
      backend/views/access/index.php
  23. +78
    -0
      backend/views/accessory/_form.php
  24. +50
    -0
      backend/views/accessory/create.php
  25. +91
    -0
      backend/views/accessory/index.php
  26. +53
    -0
      backend/views/accessory/update.php
  27. +1
    -1
      backend/views/dashboard-admin/index.php
  28. +1
    -7
      backend/views/dashboard/index.php
  29. +11
    -22
      backend/views/distribution/index.php
  30. +6
    -3
      backend/views/invoice/index.php
  31. +8
    -1
      backend/views/layouts/left.php
  32. +111
    -0
      backend/views/order-admin/index.php
  33. +19
    -6
      backend/views/producer/update.php
  34. +29
    -2
      backend/views/product/_form.php
  35. +1
    -1
      backend/views/report/index.php
  36. +4
    -3
      backend/views/subscription/index.php
  37. +2
    -2
      backend/views/user-admin/email_deliverability.php
  38. +2
    -2
      backend/views/user-admin/index.php
  39. +1
    -0
      backend/views/user/_form.php
  40. +2
    -2
      backend/views/user/credit.php
  41. +22
    -12
      backend/views/user/index.php
  42. +4
    -11
      backend/views/user/orders.php
  43. +3
    -3
      backend/views/user/view.php
  44. +108
    -94
      backend/web/css/screen.css
  45. +24
    -10
      backend/web/js/vuejs/distribution-index.js
  46. +5
    -0
      backend/web/js/vuejs/producer-update.js
  47. +9
    -0
      backend/web/sass/_adminlte.scss
  48. +11
    -0
      backend/web/sass/accessory/_form.scss
  49. +1
    -0
      backend/web/sass/screen.scss
  50. +5
    -1
      common/components/ActiveRecordCommon.php
  51. +2
    -0
      common/components/BusinessLogic.php
  52. +12
    -0
      common/components/BusinessLogicTrait.php
  53. +42
    -0
      common/components/Faker.php
  54. +3
    -0
      common/config/main.php
  55. +1
    -1
      common/config/params.php
  56. +28
    -0
      common/versions/24.6.D.php
  57. +34
    -0
      console/migrations/m240619_195454_create_table_accessory.php
  58. +28
    -0
      console/migrations/m240620_070618_add_columns_producer_communicate_email_defaults.php
  59. +31
    -0
      console/migrations/m240620_074924_create_table_product_accessory.php
  60. +3
    -0
      domain/Distribution/Distribution/Export/DistributionReportPdfGenerator.php
  61. +2
    -2
      domain/Document/Invoice/InvoiceSearch.php
  62. +3
    -1
      domain/Feature/Feature/Feature.php
  63. +4
    -2
      domain/Feature/Feature/FeatureDefinition.php
  64. +1
    -1
      domain/Order/Order/OrderBuilder.php
  65. +6
    -0
      domain/Order/Order/OrderModule.php
  66. +119
    -0
      domain/Order/Order/OrderResolver.php
  67. +1
    -0
      domain/Order/Order/OrderSearch.php
  68. +10
    -46
      domain/Order/Order/OrderSolver.php
  69. +1
    -11
      domain/Payment/PaymentSolver.php
  70. +14
    -1
      domain/Producer/Producer/Producer.php
  71. +0
    -12
      domain/Producer/Producer/ProducerSolver.php
  72. +106
    -0
      domain/Product/Accessory/Accessory.php
  73. +35
    -0
      domain/Product/Accessory/AccessoryBuilder.php
  74. +18
    -0
      domain/Product/Accessory/AccessoryDefinition.php
  75. +45
    -0
      domain/Product/Accessory/AccessoryManager.php
  76. +38
    -0
      domain/Product/Accessory/AccessoryModule.php
  77. +39
    -0
      domain/Product/Accessory/AccessoryRepository.php
  78. +15
    -0
      domain/Product/Accessory/AccessoryRepositoryQuery.php
  79. +24
    -0
      domain/Product/Product/Product.php
  80. +22
    -0
      domain/Product/Product/ProductManager.php
  81. +9
    -3
      domain/Product/Product/ProductModule.php
  82. +86
    -0
      domain/Product/ProductAccessory/ProductAccessory.php
  83. +15
    -0
      domain/Product/ProductAccessory/ProductAccessoryBuilder.php
  84. +13
    -0
      domain/Product/ProductAccessory/ProductAccessoryDefinition.php
  85. +51
    -0
      domain/Product/ProductAccessory/ProductAccessoryManager.php
  86. +38
    -0
      domain/Product/ProductAccessory/ProductAccessoryModule.php
  87. +42
    -0
      domain/Product/ProductAccessory/ProductAccessoryRepository.php
  88. +29
    -0
      domain/Product/ProductAccessory/ProductAccessoryRepositoryQuery.php
  89. +1
    -1
      domain/User/User/User.php
  90. +70
    -14
      domain/User/User/UserSolver.php
  91. +1
    -1
      frontend/views/site/producer.php
  92. +1
    -1
      frontend/views/site/service.php
  93. +1
    -1
      producer/views/order/confirm.php

+ 13
- 0
backend/config/main.php Целия файл

@@ -49,6 +49,19 @@ return [
'basePath' => dirname(__DIR__),
'name' => 'distrib',
'controllerNamespace' => 'backend\controllers',
'controllerMap' => [
'dashboard-admin' => 'backend\controllers\admin\DashboardAdminController',
'communicate-admin' => 'backend\controllers\admin\CommunicatedAdminController',
'feature-admin' => 'backend\controllers\admin\FeatureAdminController',
'online-admin' => 'backend\controllers\admin\OnlineAdminController',
'producer-admin' => 'backend\controllers\admin\ProducerAdminController',
'setting-admin' => 'backend\controllers\admin\SettingAdminController',
'stats-admin' => 'backend\controllers\admin\StatsAdminController',
'support-admin' => 'backend\controllers\admin\SupportAdminController',
'tax-rate-admin' => 'backend\controllers\admin\TaxRateAdminController',
'user-admin' => 'backend\controllers\admin\UserAdminController',
'order-admin' => 'backend\controllers\admin\OrderAdminController',
],
'defaultRoute' => 'dashboard/index',
'bootstrap' => ['log'],
'modules' => [],

+ 162
- 0
backend/controllers/AccessoryController.php Целия файл

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

/**
* Copyright Souke (2018)
*
* contact@souke.fr
*
* 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 domain\Product\Accessory\Accessory;
use yii\base\Response;
use yii\db\StaleObjectException;
use yii\filters\AccessControl;
use yii\web\NotFoundHttpException;

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

public function actionIndex()
{
return $this->render('index', [
'dataProvider' => $this->getAccessoryModule()->getRepository()
->queryAccessories()->getDataProvider(20),
]);
}

public function actionCreate()
{
$accessoryModule = $this->getAccessoryModule();
$accessoryModel = $accessoryModule->getBuilder()->instanciateAccessory($this->getProducerCurrent());

if ($accessoryModel->load(\Yii::$app->request->post()) && $accessoryModel->validate()) {
$accessory = $accessoryModule->getManager()->createAccessory(
$this->getProducerCurrent(),
$accessoryModel->getName(),
$accessoryModel->getQuantity()
);
$this->afterSave($accessory, $accessoryModel->getSelectedProductsIds());
$this->setFlash('success', "Accessoire ajouté");
return $this->redirectAfterSave('accessory', $accessory->getId());
}

return $this->render('create', [
'accessory' => $this->initFormModel($accessoryModel),
'productsArray' => $this->findProducts()
]);
}

/**
* @throws NotFoundHttpException
*/
public function actionUpdate(int $id)
{
$accessory = $this->findAccessory($id);

if ($accessory->load(\Yii::$app->request->post()) && $accessory->validate() && $accessory->save()) {
$this->afterSave($accessory, $accessory->getSelectedProductsIds());
return $this->redirectAfterSave('accessory', $accessory->getId());
}

return $this->render('update', [
'accessory' => $this->initFormModel($accessory),
'productsArray' => $this->findProducts()
]);
}

/**
* @throws \Throwable
* @throws StaleObjectException
* @throws NotFoundHttpException
*/
public function actionDelete(int $id): Response
{
$accessory = $this->findAccessory($id);
if($accessory->delete()) {
$this->setFlash('success', "Accessoire supprimé");
}

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

public function afterSave(Accessory $accessory, $selectedProductsIdsArray): void
{
if(!is_array($selectedProductsIdsArray)) {
$selectedProductsIdsArray = [];
}
$this->getAccessoryModule()->getManager()->manageProducts($accessory, $selectedProductsIdsArray);
}

public function findProducts(): array
{
return $this->getProductModule()->getRepository()->findProducts(true);
}

/**
* @throws NotFoundHttpException
*/
protected function findAccessory($id): Accessory
{
if (($accessory = $this->getAccessoryModule()->getRepository()->findOneAccessoryById($id)) !== null) {
return $accessory;
} else {
throw new NotFoundHttpException("L'accessoire n'a pas été trouvé.");
}
}

public function initFormModel(Accessory $accessoryModel)
{
$this->getAccessoryModule()->getBuilder()->initSelectedProductsIds($accessoryModel);
return $accessoryModel;
}
}

+ 7
- 2
backend/controllers/BackendController.php Целия файл

@@ -82,14 +82,19 @@ class BackendController extends CommonController
return $this->redirect(['dashboard/index']);
}

public function redirectAfterSave(string $baseRoute, int $id)
public function redirectAfterSave(string $baseRoute, int $id, string $redirectUrl = null)
{
$postParams = \Yii::$app->request->post();
if(isset($postParams['save-stay'])) {
return $this->redirect([$baseRoute.'/update', 'id' => $id]);
}
else {
return $this->redirect(['index']);
if($redirectUrl) {
return $this->redirect($redirectUrl);
}
else {
return $this->redirect(['index']);
}
}
}
}

+ 15
- 23
backend/controllers/CommunicateController.php Целия файл

@@ -88,6 +88,9 @@ class CommunicateController extends BackendController
$userModule = $this->getUserModule();
$distributionModule = $this->getDistributionModule();
$mailForm = new MailForm();
// Sujet et message par défaut
$mailForm->subject = $this->getProducerModule()->getSolver()->getConfig('option_communicate_email_default_subject');
$mailForm->message = $this->getProducerModule()->getSolver()->getConfig('option_communicate_email_default_message');

if ($idPointSale && !$usersPointSaleLink && !$usersPointSaleHasOrder) {
$usersPointSaleLink = 1;
@@ -133,7 +136,12 @@ class CommunicateController extends BackendController
$usersArray = [];
foreach ($users as $key => $user) {
if (isset($user['email']) && strlen($user['email']) > 0) {
$usersArray[] = $user['email'];
if($this->getProducerCurrent()->isDemoAccount()) {
$usersArray[] = \Yii::$app->faker->email();
}
else {
$usersArray[] = $user['email'];
}
} else {
unset($users[$key]);
}
@@ -148,30 +156,14 @@ class CommunicateController extends BackendController


if ($mailForm->load(\Yii::$app->request->post()) && $mailForm->validate()) {
$mailForm->sendEmail($users);
$this->setFlash('success', 'Votre email a bien été envoyé.');

// @TODO : traiter les erreurs
/*if ($responseSendMail->success()) {
if($this->getProducerCurrent()->isDemoAccount()) {
$this->setFlash('error', "Fonctionnalité désactivée sur le compte de démo.");
}
else {
$mailForm->sendEmail($users);
$this->setFlash('success', 'Votre email a bien été envoyé.');
} else {
$bodyResponseSendMail = $responseSendMail->getBody();
$emailsErrorArray = [];

if (isset($bodyResponseSendMail['Messages'])) {
foreach ($bodyResponseSendMail['Messages'] as $message) {
if ($message['Status'] != 'success') {
$emailsErrorArray[] = $message['Errors'][0]['ErrorMessage'];
}
}
}

$messageError = 'Un problème est survenu lors de l\'envoi de votre email.';
if (count($emailsErrorArray) > 0) {
$messageError .= '<br />Problème détecté : ' . implode(',', $emailsErrorArray);
}
$this->setFlash('error', $messageError);
}*/
}

return $this->redirect(['email', 'idPointSale' => $idPointSale]);
}

+ 22
- 9
backend/controllers/DistributionController.php Целия файл

@@ -131,7 +131,7 @@ class DistributionController extends BackendController
$json['points_sale'] = $this->buildAjaxInfosResponsePointsSale($distribution);
$json['delivery_notes'] = $this->buildAjaxInfosResponseDeliveryNotes($date);
$json['order_create'] = $this->buildAjaxInfosResponseOrderCreate($distribution, $productsArray);
$json['users'] = $userModule->findUsers();
$json['users'] = $this->buildAjaxInfosResponseUsers();
$json['one_distribution_week_active'] = $distributionModule->isOneDistributionWeekActive($date);
$json['tiller_is_synchro'] = $this->buildAjaxInfosResponseTiller($producer, $date);
$json['tiller_is_authenticated'] = $this->getOrderModule()->getTillerManager()->isAuthenticated();
@@ -142,6 +142,15 @@ class DistributionController extends BackendController
return $json;
}

public function buildAjaxInfosResponseUsers()
{
$usersArray = $this->getUserModule()->getRepository()->findUsers();
foreach($usersArray as $key => $user) {
$usersArray[$key]['username'] = $this->getUserModule()->getSolver()->getUsernameFromArray($user, true);
}
return $usersArray;
}

public function buildAjaxInfosResponseLeavePeriod(Producer $producer)
{
$producerModule = $this->getProducerModule();
@@ -217,12 +226,7 @@ class DistributionController extends BackendController
}
}

if (!isset($product->productDistribution[0]) || !is_numeric($product->productDistribution[0]->quantity_max)) {
$jsonProduct['quantity_remaining'] = null;
} else {
$jsonProduct['quantity_remaining'] = $product->productDistribution[0]->quantity_max - $quantityOrder;
}

$jsonProduct['quantity_max'] = $orderModule->getResolver()->getProductQuantityMax($product, $distribution);
$jsonProduct['quantity_form'] = 0;

if ($product->taxRate) {
@@ -314,6 +318,14 @@ class DistributionController extends BackendController
$distributionJsonData['potential_revenues'] = Price::format($productModule->getProductDistributionPotentialRevenues($productsArray));
$distributionJsonData['potential_revenues_with_tax'] = Price::format($productModule->getProductDistributionPotentialRevenues($productsArray, true));
$distributionJsonData['potential_weight'] = number_format($productModule->getProductDistributionPotentialWeight($productsArray), 2);
$distributionJsonData['user_create_href'] = \Yii::$app->urlManager->createUrl([
'user/create',
'redirectUrl' => \Yii::$app->urlManager->createAbsoluteUrl([
'distribution/index',
'date' => $distribution->date,
'displayFormOrderCreate' => 1
])
]);

return $distributionJsonData;
}
@@ -362,8 +374,8 @@ class DistributionController extends BackendController
'mean_payment' => $payment->mean_payment,
'wording_mean_payment' => $paymentManager->getStrMeanPayment($payment),
'date' => date('d/m/Y H:i:s', strtotime($payment->date)),
'user' => $payment->getUserObject() ? $userModule->getUsername($payment->getUserObject()) : '',
'user_action' => $paymentManager->getStrUserAction($payment),
'user' => $payment->getUserObject() ? $userModule->getSolver()->getUsername($payment->getUserObject()) : '',
'user_action' => $userModule->getSolver()->getPaymentUsernameUserAction($payment),
'wording' => $paymentManager->getStrWording($payment, $order),
'amount' => $paymentManager->getAmount($payment, Order::AMOUNT_TOTAL, true),
];
@@ -399,6 +411,7 @@ class DistributionController extends BackendController
$order->user->getAttributes(),
$arrayDatasUser
) : null,
'username_user' => (isset($order->user)) ? $userModule->getSolver()->getUsername($order->user) : '',
'pointSale' => $order->pointSale ? ['id' => $order->pointSale->id, 'name' => $order->pointSale->name] : null,
'productOrder' => $productOrderArray,
'paymentsArray' => $paymentArray,

+ 5
- 0
backend/controllers/DocumentController.php Целия файл

@@ -47,6 +47,7 @@ use domain\Document\DeliveryNote\DeliveryNote;
use domain\Document\Document\Document;
use domain\Document\Invoice\Invoice;
use domain\Document\Quotation\Quotation;
use domain\Feature\Feature\Feature;
use domain\Order\Order\Order;
use domain\Order\OrderStatus\OrderStatus;
use domain\Order\ProductOrder\ProductOrder;
@@ -261,6 +262,10 @@ class DocumentController extends BackendController

public function actionExportCsvEvoliz(int $id)
{
if(!$this->getFeatureModule()->getChecker()->isEnabled(Feature::ALIAS_BRIDGE_EVOLIZ)) {
throw new yii\web\UnauthorizedHttpException("Vous n'êtes pas autorisé à effectuer cette action.");
}

$documentModule = $this->getDocumentModule();
$productOrderModule = $this->getProductOrderModule();


+ 1
- 1
backend/controllers/OrderController.php Целия файл

@@ -1069,7 +1069,7 @@ class OrderController extends BackendController
foreach ($history as $creditHistory) {
$html .= '<tr>'
. '<td>' . date('d/m/Y H:i:s', strtotime($paymentManager->getDate($creditHistory))) . '</td>'
. '<td>' . Html::encode($paymentManager->getStrUserAction($creditHistory)) . '</td>'
. '<td>' . Html::encode($this->getUserModule()->getSolver()->getPaymentUsernameUserAction($creditHistory)) . '</td>'
. '<td>' . $paymentManager->getStrWording($creditHistory) . '</td>'
. '<td>' . ($paymentManager->isTypeDebit($creditHistory) ? '- ' . Price::getPriceWithTax($creditHistory->amount) : '') . '</td>'
. '<td>' . ($paymentManager->isTypeCredit($creditHistory) ? '+ ' . Price::getPriceWithTax($creditHistory->amount) : '') . '</td>'

+ 3
- 0
backend/controllers/ReportController.php Целия файл

@@ -86,6 +86,9 @@ class ReportController extends BackendController
$distributionModule = $this-> getDistributionModule();

$usersArray = $userModule->findUsers();
foreach($usersArray as $key => $user) {
$usersArray[$key]['username'] = $userModule->getSolver()->getUsernameFromArray($user, true);
}
$pointsSaleArray = $pointSaleModule->findPointSales();
$firstDistribution = $distributionModule->findOneFirstDistribution();
$lastDistribution = $distributionModule->findOneLastDistribution();

+ 9
- 4
backend/controllers/UserController.php Целия файл

@@ -122,12 +122,13 @@ class UserController extends BackendController
]);
}

public function actionCreate()
public function actionCreate(string $redirectUrl = null)
{
$userModule = $this->getUserModule();
$producerModule = $this->getProducerModule();
$producerCurrent = $this->getProducerCurrent();
$model = $userModule->instanciateUser();
$model->redirect_url = $redirectUrl;
$posts = Yii::$app->request->post();
$userExist = false;

@@ -165,7 +166,7 @@ class UserController extends BackendController

$this->setFlash('success', 'Utilisateur créé.');

return $this->redirectAfterSave('user', $userCreate->id);
return $this->redirectAfterSave('user', $userCreate->id, $model->redirect_url);
}
}

@@ -205,9 +206,13 @@ class UserController extends BackendController

public function actionUpdate($id)
{
if($this->getProducerCurrent()->isDemoAccount()) {
$this->addFlash('error', "Fonctionnalité non disponible sur le compte de démo.");
return $this->redirect(['view', 'id' => $id]);
}

$userModule = $this->getUserModule();
$pointSaleModule = $this->getPointSaleModule();

$model = $this->findModel($id);
$previousMail = $model->email;
$userBelongToProducer = UserProducer::findOne(['id_user' => $id, 'id_producer' => GlobalParam::getCurrentProducerId()]);
@@ -518,7 +523,7 @@ class UserController extends BackendController
$dateTransaction
);

if ($creditForm->send_mail) {
if ($creditForm->send_mail && !$this->getProducerCurrent()->isDemoAccount()) {
$paymentModule->getNotifier()
->notifyUserCreditMovement(
$user,

backend/controllers/CommunicateAdminController.php → backend/controllers/admin/CommunicateAdminController.php Целия файл

@@ -36,8 +36,9 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use backend\controllers\BackendController;
use backend\models\MailForm;
use domain\User\User\User;
use yii\filters\AccessControl;

backend/controllers/DashboardAdminController.php → backend/controllers/admin/DashboardAdminController.php Целия файл

@@ -36,11 +36,10 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use common\helpers\Price;
use backend\controllers\BackendController;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;

class DashboardAdminController extends BackendController
{

backend/controllers/FeatureAdminController.php → backend/controllers/admin/FeatureAdminController.php Целия файл

@@ -36,8 +36,9 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use backend\controllers\BackendController;
use common\helpers\Ajax;
use yii\filters\AccessControl;
use yii\helpers\Html;

backend/controllers/OnlineAdminController.php → backend/controllers/admin/OnlineAdminController.php Целия файл

@@ -36,10 +36,11 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use yii\filters\VerbFilter;
use backend\controllers\BackendController;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;

class OnlineAdminController extends BackendController
{

+ 77
- 0
backend/controllers/admin/OrderAdminController.php Целия файл

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

/**
* Copyright Souke (2018)
*
* contact@souke.fr
*
* 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\admin;

use backend\controllers\BackendController;
use domain\Order\Order\OrderSearch;
use yii\filters\AccessControl;

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

public function actionIndex()
{
$searchModel = new OrderSearch();
$dataProvider = $searchModel->search(array_merge(\Yii::$app->request->queryParams));

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

backend/controllers/ProducerAdminController.php → backend/controllers/admin/ProducerAdminController.php Целия файл

@@ -36,13 +36,13 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use backend\controllers\BackendController;
use common\helpers\Ajax;
use common\helpers\Alwaysdata;
use domain\Order\Order\Order;
use domain\Order\Order\OrderRepositoryQuery;
use domain\Order\OrderStatus\OrderStatus;
use domain\Producer\Producer\Producer;
use domain\Product\Product\Product;
use Yii;

backend/controllers/SettingAdminController.php → backend/controllers/admin/SettingAdminController.php Целия файл

@@ -36,13 +36,11 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use backend\controllers\BackendController;
use backend\forms\AdminSettingsForm;
use common\helpers\Ajax;
use yii\filters\AccessControl;
use yii\helpers\Html;
use yii\web\NotFoundHttpException;

/**
* UserController implements the CRUD actions for User model.

backend/controllers/StatsAdminController.php → backend/controllers/admin/StatsAdminController.php Целия файл

@@ -36,13 +36,14 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use yii\filters\AccessControl;
use Yii;
use DateTime;
use backend\controllers\BackendController;
use DateInterval;
use DatePeriod;
use DateTime;
use Yii;
use yii\filters\AccessControl;

class StatsAdminController extends BackendController
{

backend/controllers/SupportAdminController.php → backend/controllers/admin/SupportAdminController.php Целия файл

@@ -36,8 +36,9 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use backend\controllers\SupportController;
use domain\Ticket\Ticket\Ticket;
use domain\Ticket\Ticket\TicketSearch;
use yii\filters\AccessControl;

backend/controllers/TaxRateAdminController.php → backend/controllers/admin/TaxRateAdminController.php Целия файл

@@ -36,8 +36,9 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use backend\controllers\BackendController;
use domain\Config\TaxRate\TaxRate;
use yii\data\ActiveDataProvider;
use yii\filters\AccessControl;

backend/controllers/UserAdminController.php → backend/controllers/admin/UserAdminController.php Целия файл

@@ -36,8 +36,9 @@
* termes.
*/

namespace backend\controllers;
namespace backend\controllers\admin;

use backend\controllers\BackendController;
use domain\User\User\UserSearch;
use Yii;
use yii\filters\AccessControl;
@@ -111,7 +112,7 @@ class UserAdminController extends BackendController
return $this->redirect('index');
}

public function actionRedirectView(int $idUserProducer)
public function actionRedirectUpdate(int $idUserProducer)
{
$userCurrent = $this->getUserCurrent();
$userProducer = $this->getUserProducerModule()->getRepository()->findOneUserProducerById($idUserProducer);
@@ -119,7 +120,7 @@ class UserAdminController extends BackendController
$user = $userProducer->user;
$producer = $userProducer->producer;
$this->getUserModule()->getBuilder()->switchProducer($userCurrent, $producer);
return $this->redirect(['user/view', 'id' => $user->id]);
return $this->redirect(['user/update', 'id' => $user->id]);
}
else {
$this->addFlash('error', "L'utilisateur n'a pas été trouvé.");

+ 3
- 0
backend/views/_include/form_actions.php Целия файл

@@ -5,6 +5,9 @@ use yii\helpers\Html;
?>

<div class="form-group form-actions">
<?php if(isset($form)): ?>
<?= $form->field($model, 'redirect_url', ['options' => ['class' => 'field-redirect-url']])->hiddenInput() ?>
<?php endif; ?>
<?= Html::a('Retour', ['index'], ['class' => 'btn btn-default']) ?>
<?= Html::submitButton($model->isNewRecord ? 'Créer' : 'Modifier', ['class' => 'btn btn-primary', 'name' => 'save']) ?>
<?= Html::submitButton($model->isNewRecord ? 'Créer et rester' : 'Modifier et rester', ['class' => 'btn btn-primary', 'name' => 'save-stay']) ?>

+ 1
- 1
backend/views/access/index.php Целия файл

@@ -73,7 +73,7 @@ $this->setTitle('Accès') ;
</tr>
<?php foreach($usersAccessArray as $user): ?>
<tr>
<td><?= Html::encode($user->lastname.' '.$user->name) ?></td>
<td><?= Html::encode($userModule->getSolver()->getUsername($user)) ?></td>
<td><?= Html::a('<span class="glyphicon glyphicon-trash"></span>',['access/delete','idUser' => $user->id], ['class' => 'btn btn-default']); ?></td>
</tr>
<?php endforeach; ?>

+ 78
- 0
backend/views/accessory/_form.php Целия файл

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

/**
* Copyright Souke (2018)
*
* contact@souke.fr
*
* 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\ArrayHelper;
use yii\helpers\Html;
use yii\widgets\ActiveForm;

?>

<div class="accessory-form">
<?php $form = ActiveForm::begin(); ?>
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-th-list"></i>
Général
</h3>
</div>
<div class="panel-body">
<?= $form->field($accessory, 'name')->textInput() ?>
<?= $form->field($accessory, 'quantity')->textInput() ?>
</div>
</div>
<div class="panel panel-default" id="panel-products">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-clone"></i>
Produits
</h3>
</div>
<div class="panel-body">
<?= Html::activeCheckboxList($accessory, 'selected_products_ids', ArrayHelper::map($productsArray, 'id', function ($product, $defaultValue) {
return Html::encode($product->name);
}), ['encode' => false, 'class' => '']) ?>
</div>
</div>
</div>
<?= $this->render('@backend/views/_include/form_actions.php',[
'model' => $accessory,
]); ?>
<?php ActiveForm::end(); ?>
</div>

+ 50
- 0
backend/views/accessory/create.php Целия файл

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

/**
Copyright Souke (2018)

contact@souke.fr

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.
*/

$this->setTitle("Ajouter un accessoire") ;
$this->addBreadcrumb(['label' => "Accessoires", 'url' => ['index']]) ;
$this->addBreadcrumb('Ajouter') ;

?>

<div class="accessory-create">
<?= $this->render('_form', [
'accessory' => $accessory,
'productsArray' => $productsArray
]) ?>
</div>

+ 91
- 0
backend/views/accessory/index.php Целия файл

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

/**
* Copyright Souke (2018)
*
* contact@souke.fr
*
* 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 common\components\View;
use yii\helpers\Html;
use yii\grid\GridView;

/**
* @var View $this
*/

$this->setTitle('Accessoires');
$this->addBreadcrumb($this->getTitle());
$this->addButton(['label' => 'Nouvel accessoire <span class="glyphicon glyphicon-plus"></span>', 'url' => 'accessory/create', 'class' => 'btn btn-primary']);

?>

<div class="accessory-index">
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'name',
'quantity',
[
'label' => 'Produits',
'format' => 'raw',
'value' => function($accessory) {
$html = '';
foreach($accessory->getProductAccessories() as $productAccessory) {
$html .= '<span class="label label-default">'.Html::encode($productAccessory->getProduct()->name).'</span>&nbsp;';
}

return $html;
}
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{update} {delete}',
'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'],
'buttons' => [
'update' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, [
'title' => 'Modifier', 'class' => 'btn btn-default'
]);
},
'delete' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-trash"></span>', $url, [
'title' => 'Supprimer', 'class' => 'btn btn-default'
]);
}
],
],
],
]); ?>
</div>

+ 53
- 0
backend/views/accessory/update.php Целия файл

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

/**
Copyright Souke (2018)

contact@souke.fr

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;

$this->setTitle("Modifier un accessoire") ;
$this->addBreadcrumb(['label' => "Accessoires", 'url' => ['index']]) ;
$this->addBreadcrumb(['label' => Html::encode($accessory->getName()), 'url' => ['update', 'id' => $accessory->getId()]]) ;
$this->addBreadcrumb('Modifier') ;

?>

<div class="accessory-update">
<?= $this->render('_form', [
'accessory' => $accessory,
'productsArray' => $productsArray
]) ?>
</div>

+ 1
- 1
backend/views/dashboard-admin/index.php Целия файл

@@ -69,7 +69,7 @@ $this->setMetaRefresh(true);
<?= AdminLTE::smallBox(
$countTicketsAdminOpen,
'Tickets',
$countTicketsAdminUnread ? 'green' : 'blue',
$countTicketsAdminUnread ? 'red' : 'blue',
'comments',
Yii::$app->urlManager->createUrl('support-admin/index')
) ?>

+ 1
- 7
backend/views/dashboard/index.php Целия файл

@@ -253,13 +253,7 @@ $this->setTitle('Tableau de bord');

<tr class="<?= $orderModule->getHistoryClass($order) ; ?>">
<td class="history">
<?= $orderModule->getSolver()->getLabelOrderStatus($order); ?>
<?php
$lastOrderStatusHistory = $orderModule->getSolver()->getLastOrderStatusHistory($order);
if($lastOrderStatusHistory) {
echo '<br /><span class="small gray">'.$lastOrderStatusHistory->getDate()->format('d/m/Y à H:i').'</span>';
}
?>
<?= $orderModule->getSolver()->getLabelOrderStatus($order, true); ?>
</td>
<td class="infos">
<?= $orderModule->getSolver()->getLabelOrigin($order, true); ?>

+ 11
- 22
backend/views/distribution/index.php Целия файл

@@ -151,6 +151,10 @@ $this->setPageTitle('Distributions') ;
<input type="text" class="form-control quantity-max" placeholder="&infin;" :data-id-product="product.id" v-model="getProductDistribution(product).quantity_max" @keyup="productQuantityMaxChange" />
<span class="input-group-addon">{{ (product.unit == 'piece') ? 'p.' : ' '+((product.unit == 'g' || product.unit == 'kg') ? 'kg' : 'litre(s)') }}</span>
</div>
<div v-if=" false && getProductDistribution(product).quantity_max != product.quantity_max">
Limitation accessoires : <br />
{{ product.quantity_max }}
</div>
</td>
</tr>
</tbody>
@@ -334,8 +338,8 @@ $this->setPageTitle('Distributions') ;
Attention, ce jour de distribution n'est pas activé et vous avez quand même des commandes enregistrées.
</div>

<div v-if="idActivePointSale > 0 && (totalActivePointSale() > 0 || weightActivePointSale() > 0)" class="point-sale-totals">
<div>
<div v-if="idActivePointSale > 0 && (totalActivePointSale() > 0 || weightActivePointSale() > 0 || pointSaleActive.producers_sharing_point_sale_as_string)" class="point-sale-totals">
<div v-if="totalActivePointSale() > 0 || weightActivePointSale() > 0">
<span class="title">Totaux</span>
CA TTC : <strong>{{ totalActivePointSale() }} €</strong> / Poids : <strong>{{ weightActivePointSale() }} kg</strong>
</div>
@@ -385,17 +389,7 @@ $this->setPageTitle('Distributions') ;
<td class="column-origin" v-html="order.labelOrigin"></td>
<td class="column-user">
<a v-if="order.user" :href="baseUrl+'/user/view?id='+order.id_user" target="_blank" :class="order.user.trust_alert ? 'user-trust-alert' : ''" :title="order.user.trust_alert ? order.user.trust_alert_comment : ''">
<template v-if="order.user.name_legal_person && order.user.name_legal_person.length">
{{ order.user.name_legal_person }}
</template>
<template v-else>
{{ order.user.lastname+' '+order.user.name }}
</template>
<!--<span class="shortcuts btn-group" role="group">
<a :class="order.user.credit_active ? 'btn btn-success btn-sm' : 'btn btn-default btn-sm'" :href="baseUrl+'/user/credit?id='+order.id_user" data-toggle="popover" data-trigger="hover" data-placement="bottom" :data-content="order.user.credit.toFixed(2)+' €'"><span class="glyphicon glyphicon-euro"></span></a>
<a class="btn btn-default btn-sm" :href="baseUrl+'/user/update?id='+order.id_user" data-toggle="popover" data-trigger="hover" data-placement="bottom" data-content="Modifier"><span class="glyphicon glyphicon-user"></span></a>
<a class="btn btn-default btn-sm" :href="baseUrl+'/user/orders?id='+order.id_user" data-toggle="popover" data-trigger="hover" data-placement="bottom" data-content="Voir les commandes"><span class="glyphicon glyphicon-eye-open"></span></a>
</span>-->
{{ order.username_user }}
</a>
<span v-else class="user-without-account">{{ order.username }}</span>
<span v-if="order.comment && order.comment.length > 0" class="glyphicon glyphicon-comment"></span>
@@ -548,7 +542,7 @@ $this->setPageTitle('Distributions') ;
<modal v-if="showModalPayment && idOrderPayment == order.id" class="modal-payment" @close="showModalPayment = false">
<h3 slot="header">
Commande du <strong>{{ dateFormat }}</strong> &gt;
<strong><span v-if="order.user">{{ order.user.name +' '+order.user.lastname }}</span>
<strong><span v-if="order.user">{{ order.username_user }}</span>
<span v-else>{{ order.username }}</span></strong>
</h3>
<div slot="body">
@@ -671,7 +665,7 @@ $this->setPageTitle('Distributions') ;
<a v-if="producer && producer.credit && order.id_user > 0 && user.id_user == order.id_user" class="btn btn-xs btn-primary btn-credit" :href="baseUrl+'/user/credit?id='+user.id_user" v-for="user in users">{{ parseFloat(user.credit).toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+'&nbsp;€' }}</a>
<label class="control-label" for="select-id-user">
Utilisateur
<a v-if="!order.id_user || order.id_user == 0" class="btn btn-default btn-xs" href="<?= Yii::$app->urlManager->createUrl('user/create'); ?>">
<a v-if="!order.id_user || order.id_user == 0" class="btn btn-default btn-xs" :href="distribution.user_create_href">
<span class="glyphicon glyphicon-plus"></span>
Créer un utilisateur
</a>
@@ -679,12 +673,7 @@ $this->setPageTitle('Distributions') ;
<select class="form-control select2-order-form" v-model="order.id_user" @change="userChange">
<option value="0">--</option>
<option v-for="user in users" :value="user.id_user">
<template v-if="user.type == 'legal-person' && user.name_legal_person && user.name_legal_person.length">
{{ user.name_legal_person }} (personne morale)
</template>
<template v-else>
{{ user.lastname +' '+ user.name }}
</template>
{{ user.username }}
</option>
</select>
<input v-model="order.username" type="text" class="form-control" placeholder="Ou saisissez ici le nom de l'utilisateur" />
@@ -756,7 +745,7 @@ $this->setPageTitle('Distributions') ;
</span>
</div>
</td>
<td class="quantity-remaining infinite" v-if="product.quantity_remaining === null || order.productOrder[product.id].unit != product.unit">&infin;</td>
<td class="quantity-remaining infinite" v-if="(getProductQuantityRemaining(product) === null) || order.productOrder[product.id].unit != product.unit">&infin;</td>
<td class="quantity-remaining negative" v-else-if="getProductQuantityRemaining(product) <= 0">
{{ getProductQuantityRemaining(product) }} {{ order.productOrder[product.id].unit == 'piece' ? ' p.' : ' '+(order.productOrder[product.id].unit == 'g' || order.productOrder[product.id].unit == 'kg') ? 'kg' : 'litre(s)' }}
<span class="glyphicon glyphicon-alert" v-if="getProductQuantityRemaining(product) < 0"></span>

+ 6
- 3
backend/views/invoice/index.php Целия файл

@@ -37,13 +37,15 @@
*/

use domain\Document\Invoice\Invoice;
use domain\Feature\Feature\Feature;
use domain\Order\Order\Order;
use yii\grid\GridView;
use yii\helpers\Html;

$producerModule = $this->getProducerModule();
$invoiceModule = $this-> getInvoiceModule();
$invoiceModule = $this-> getInvoiceModule();
$userModule = $this->getUserModule();
$featureChecker = $this->getFeatureModule()->getChecker();

$this->setTitle('Factures');
$this->addBreadcrumb($this->getTitle());
@@ -172,8 +174,9 @@ $this->addButton(['label' => 'Nouvelle facture <span class="glyphicon glyphicon-
'title' => 'Télécharger', 'class' => 'btn btn-default'
]);
},
'export-csv-evoliz' => function ($url, $invoice) use ($producerModule) {
if ($producerModule->getConfig('option_export_evoliz')) {
'export-csv-evoliz' => function ($url, $invoice) use ($producerModule, $featureChecker) {
if($featureChecker->isEnabled(Feature::ALIAS_BRIDGE_EVOLIZ)
&& $producerModule->getConfig('option_export_evoliz')) {
return Html::a('<span class="glyphicon glyphicon-save-file"></span> Evoliz', $url, [
'title' => 'Export CSV Evoliz', 'class' => 'btn btn-default'
]);

+ 8
- 1
backend/views/layouts/left.php Целия файл

@@ -151,6 +151,12 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
'url' => ['/user-admin/email-deliverability'],
'visible' => $isUserCurrentGrantedAsAdministrator
],
[
'label' => 'Commandes',
'icon' => 'calendar',
'url' => ['order-admin/index'],
'visible' => $isUserCurrentGrantedAsAdministrator,
],
[
'label' => 'Statistiques',
'icon' => 'line-chart',
@@ -201,10 +207,11 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
'icon' => 'clone',
'url' => ['/product/index'],
'visible' => $isUserCurrentGrantedAsProducer,
'active' => Yii::$app->controller->id == 'product' || Yii::$app->controller->id == 'product-category',
'active' => Yii::$app->controller->id == 'product' || Yii::$app->controller->id == 'product-category' || Yii::$app->controller->id == 'accessory',
'items' => [
['label' => 'Liste', 'icon' => 'th-list', 'url' => ['/product/index'], 'visible' => $isUserCurrentGrantedAsProducer],
['label' => 'Catégories', 'icon' => 'book', 'url' => ['/product-category/index'], 'visible' => $isUserCurrentGrantedAsProducer],
['label' => 'Accessoires', 'icon' => 'cutlery', 'url' => ['/accessory/index'], 'visible' => $isUserCurrentGrantedAsProducer && $featureChecker->isEnabled(Feature::ALIAS_PRODUCT_ACCESSORY)],
['label' => 'Import prix', 'icon' => 'upload', 'url' => ['/product/price-import'], 'visible' => $isUserCurrentGrantedAsProducer && $featureChecker->isEnabled(Feature::ALIAS_PRODUCT_PRICE_IMPORT)],
]
],

+ 111
- 0
backend/views/order-admin/index.php Целия файл

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

/**
* Copyright Souke (2018)
*
* contact@souke.fr
*
* 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 common\components\View;
use yii\grid\GridView;
use yii\helpers\Html;

/**
* @var View $this
*/

$userModule = $this->getUserModule();
$orderModule = $this->getOrderModule();

$this->setTitle('Commandes') ;
$this->addBreadcrumb('Commandes') ;

?>

<div class="order-admin-index">
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'label' => 'Statut',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
return $orderModule->getSolver()->getLabelOrderStatus($order, true);
}
],
[
'label' => 'Producteur',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
return Html::encode($order->distribution->producer->name);
}
],
[
'label' => 'Origine',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
return $orderModule->getSolver()->getLabelOrigin($order, true);;
}
],
[
'attribute' => 'distribution.date',
'label' => 'Distribution',
'value' => function ($order) {
return date('d/m/Y',strtotime($order->distribution->date));
}
],
[
'label' => 'Point de vente',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
return $orderModule->getSolver()->getPointSaleSummary($order);
}
],
[
'label' => 'Produits',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
return $orderModule->getRepository()->getCartSummary($order);
}
],
[
'label' => 'Montant',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
$orderModule->initOrder($order);
return $orderModule->getRepository()->getAmountSummary($order);
}
]
],
]); ?>
</div>

+ 19
- 6
backend/views/producer/update.php Целия файл

@@ -153,11 +153,6 @@ $this->addBreadcrumb($this->getTitle());
<?= $form->field($model, 'option_leave_period_message_title')->textInput(); ?>
<?= $form->field($model, 'option_leave_period_message')->textarea(); ?>

<h4>Communication</h4>
<?= $form->field($model, 'option_newsletter_description')
->hint('Description affichée sur la page "Infolettre" de la boutique')
->textarea(); ?>

<h4>Groupes utilisateurs</h4>
<?= $form->field($model, 'id_user_group_default')
->dropDownList($userGroupModule->getRepository()->populateUserGroupDropdownList()); ?>
@@ -356,6 +351,22 @@ $this->addBreadcrumb($this->getTitle());
</div>
</div>

<div v-show="currentSection == 'communication'" class="panel panel-default">
<div class="panel-body">
<h4>Boutique</h4>
<?= $form->field($model, 'option_newsletter_description')
->hint('Description affichée sur la page "Infolettre" de la boutique')
->textarea(); ?>
<h4>Envoi d'emails</h4>
<?= $form->field($model, 'option_communicate_email_default_subject')->textInput(); ?>
<?= $form->field($model, 'option_communicate_email_default_message')->widget(letyii\tinymce\Tinymce::class, [
'configs' => [
'plugins' => Yii::$app->parameterBag->get('tinyMcePlugins'),
]
]); ?>
</div>
</div>

<div v-show="currentSection == 'credit-payment'" class="panel panel-default">
<div class="panel-body">
<h4>Cagnotte</h4>
@@ -456,7 +467,9 @@ $this->addBreadcrumb($this->getTitle());
->label('TVA à appliquer par défaut'); ?>
<?= $form->field($model, 'option_tax_calculation_method')
->dropDownList(Document::$taxCalculationMethodArray); ?>
<?= $form->field($model, 'option_export_evoliz')->dropDownList(Dropdown::noYesChoices()); ?>
<?php if($featureChecker->isEnabled(Feature::ALIAS_BRIDGE_EVOLIZ)): ?>
<?= $form->field($model, 'option_export_evoliz')->dropDownList(Dropdown::noYesChoices()); ?>
<?php endif; ?>
<?php $hintKeywordsPrefix = "Saisissez [ANNEE] pour intégrer l'année courante"; ?>
<?= $form->field($model, 'document_quotation_prefix')->hint($hintKeywordsPrefix); ?>
<?= $form->field($model, 'document_quotation_first_reference'); ?>

+ 29
- 2
backend/views/product/_form.php Целия файл

@@ -1,7 +1,9 @@
<?php

use common\components\View;
use common\helpers\GlobalParam;
use common\helpers\Image;
use domain\Feature\Feature\Feature;
use domain\PointSale\PointSale\PointSale;
use lo\widgets\Toggle;
use domain\Product\Product\Product;
@@ -9,9 +11,15 @@ use yii\bootstrap\ActiveForm;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

/**
* @var View $this
*/

$producerModule = $this->getProducerModule();
$productCategoryModule = $this->getProductCategoryModule();
$taxRateModule = $this->getTaxRateModule();
$featureChecker = $this->getFeatureModule()->getChecker();
$accessoryModule = $this->getAccessoryModule();

?>

@@ -113,6 +121,27 @@ $taxRateModule = $this->getTaxRateModule();
</div>
</div>

<?php if($featureChecker->isEnabled(Feature::ALIAS_PRODUCT_ACCESSORY)): ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-<?= $accessoryModule->getDefinition()->getIcon() ?>"></i>
Accessoires
<a class="btn btn-default btn-xs" href="<?= Yii::$app->urlManager->createUrl(['accessory/index']) ?>">Gérer</a>
</h3>
</div>
<div class="panel-body">
<?php if($model->hasAccessory()): ?>
<?php foreach($model->getProductAccessories() as $productAccessory): ?>
<a class="btn btn-default" href="<?= Yii::$app->urlManager->createUrl(['accessory/update', 'id' => $productAccessory->getAccessory()->getId()]) ?>"><?= Html::encode($productAccessory->getAccessory()->getName()) ?></a>
<?php endforeach; ?>
<?php else: ?>
<p><em>Aucun accessoire n'est associé à ce produit.</em></p>
<?php endif; ?>
</div>
</div>
<?php endif; ?>

<?php if (!$model->isNewRecord): ?>
<div class="panel panel-default">
<div class="panel-heading">
@@ -236,7 +265,6 @@ $taxRateModule = $this->getTaxRateModule();
</div>
</div>
</div>

</div>
<div class="clr"></div>
</div>
@@ -248,5 +276,4 @@ $taxRateModule = $this->getTaxRateModule();
]); ?>

<?php ActiveForm::end(); ?>

</div>

+ 1
- 1
backend/views/report/index.php Целия файл

@@ -59,7 +59,7 @@ $this->addBreadcrumb('Rapports') ;
<ul id="list-users">
<li v-for="user in usersArray" v-if="!termSearchUser.length || (termSearchUser.length && (user.lastname.toLowerCase().indexOf(termSearchUser.toLowerCase()) != -1 || user.name.toLowerCase().indexOf(termSearchUser.toLowerCase()) != -1 ))">
<input type="checkbox" :id="'user_'+user.user_id" v-model="user.checked" @change="reportChange()" />
<label :for="'user_'+user.user_id" v-html="(user.name_legal_person && user.name_legal_person.length) ? user.name_legal_person : user.lastname+' '+user.name"></label>
<label :for="'user_'+user.user_id" v-html="user.username"></label>
</li>
</ul>
</div>

+ 4
- 3
backend/views/subscription/index.php Целия файл

@@ -43,11 +43,13 @@ use domain\Product\Product\Product;
use domain\Product\Product\ProductModule;
use domain\Subscription\Subscription\Subscription;
use domain\Subscription\Subscription\SubscriptionModule;
use domain\User\User\UserModule;
use yii\grid\GridView;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

$subscriptionModule = SubscriptionModule::getInstance();
$userModule = UserModule::getInstance();

$this->setTitle('Abonnements') ;
$this->addBreadcrumb($this->getTitle()) ;
@@ -57,7 +59,6 @@ $subscriptionsArray = Subscription::searchAll() ;

?>
<div class="subscription-index">
<?= GridView::widget([
'filterModel' => $searchModel,
'dataProvider' => $dataProvider,
@@ -66,14 +67,14 @@ $subscriptionsArray = Subscription::searchAll() ;
'attribute' => 'username',
'label' => 'Utilisateur',
'format' => 'raw',
'value' => function($model) {
'value' => function($model) use ($userModule) {
if(strlen($model->username))
{
return Html::encode($model->username) ;
}
else {
if(isset($model->user)) {
return Html::encode($model->user->lastname.' '.$model->user->name) ;
return Html::encode($userModule->getSolver()->getUsername($model->user)) ;
}
}
}

+ 2
- 2
backend/views/user-admin/email_deliverability.php Целия файл

@@ -106,7 +106,7 @@ $this->addBreadcrumb($this->getTitle());
],
[
'attribute' => 'producers',
'label' => 'Producteurs',
'label' => 'Profils',
'format' => 'raw',
'contentOptions' => ['class' => 'column-hide-on-mobile align-center'],
'value' => function ($user) use ($userProducerModule) {
@@ -114,7 +114,7 @@ $this->addBreadcrumb($this->getTitle());
$userProducersArray = $userProducerModule->getRepository()->findUserProducersByUser($user);

foreach($userProducersArray as $userProducer) {
$html .= '<a href="'.Yii::$app->urlManager->createUrl(['user-admin/redirect-view', 'idUserProducer' => $userProducer->id]).'" class="btn btn-default"><span class="glyphicon glyphicon-eye-open"></span> '.$userProducer->producer->name.'</a> ';
$html .= '<a href="'.Yii::$app->urlManager->createUrl(['user-admin/redirect-update', 'idUserProducer' => $userProducer->id]).'" class="btn btn-default"><span class="glyphicon glyphicon-user"></span> '.$userProducer->producer->name.'</a> ';
}

return $html;

+ 2
- 2
backend/views/user-admin/index.php Целия файл

@@ -106,7 +106,7 @@ $this->addBreadcrumb($this->getTitle());
],
[
'attribute' => 'producers',
'label' => 'Producteurs',
'label' => 'Profils',
'format' => 'raw',
'contentOptions' => ['class' => 'column-hide-on-mobile align-center'],
'value' => function ($user) use ($userProducerModule) {
@@ -114,7 +114,7 @@ $this->addBreadcrumb($this->getTitle());
$userProducersArray = $userProducerModule->getRepository()->findUserProducersByUser($user);

foreach($userProducersArray as $userProducer) {
$html .= '<a href="'.Yii::$app->urlManager->createUrl(['user-admin/redirect-view', 'idUserProducer' => $userProducer->id]).'" class="btn btn-default"><span class="glyphicon glyphicon-eye-open"></span> '.$userProducer->producer->name.'</a> ';
$html .= '<a href="'.Yii::$app->urlManager->createUrl(['user-admin/redirect-update', 'idUserProducer' => $userProducer->id]).'" class="btn btn-default"><span class="glyphicon glyphicon-user"></span> '.$userProducer->producer->name.'</a> ';
}

return $html;

+ 1
- 0
backend/views/user/_form.php Целия файл

@@ -151,6 +151,7 @@ $distributionModule = DistributionModule::getInstance();
->dropDownList( ProductPrice::percentValues(), [])->hint('Pourcentage appliqué aux prix de chaque produit pour cet utilisateur.');*/ ?>

<?= $this->render('@backend/views/_include/form_actions.php',[
'form' => $form,
'model' => $model,
]); ?>
</div>

+ 2
- 2
backend/views/user/credit.php Целия файл

@@ -172,8 +172,8 @@ $this->addBreadcrumb('Cagnotte') ;
],
[
'attribute' => 'id_user_action',
'value' => function ($model) use ($paymentManager) {
return $paymentManager->getStrUserAction($model);
'value' => function ($model) use ($userModule) {
return $userModule->getSolver()->getPaymentUsernameUserAction($model);
}
],
[

+ 22
- 12
backend/views/user/index.php Целия файл

@@ -44,14 +44,16 @@ use domain\Order\OrderStatus\OrderStatus;
use domain\Producer\Producer\ProducerModule;
use domain\User\User\UserModule;
use domain\User\UserProducer\UserProducer;
use Faker\Factory;
use yii\grid\GridView;
use yii\helpers\Html;
use domain\User\UserGroup\UserGroupModule;

$userModule = UserModule::getInstance();
$producerModule = ProducerModule::getInstance();
$userCurrent = GlobalParam::getCurrentUser();
$userGroupModule = UserGroupModule::getInstance();
$userCurrent = GlobalParam::getCurrentUser();
$producerCurrent = GlobalParam::getCurrentProducer();

$this->setTitle('Utilisateurs');
$this->addBreadcrumb($this->getTitle());
@@ -84,7 +86,7 @@ $this->render('_menu_filter', [
'attribute' => 'username',
'label' => 'Nom',
'value' => function ($user) use ($userModule) {
return $userModule->getUsername($user);
return $userModule->getSolver()->getUsername($user);
}
],
[
@@ -105,20 +107,28 @@ $this->render('_menu_filter', [
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($user) {
'value' => function ($user) use ($producerCurrent) {

$html = '';
if (strlen($user['phone'])) {
$html .= $user['phone'];
if($producerCurrent->isDemoAccount()) {
$faker = Yii::$app->faker;
$html .= $faker->email().'<br />'.$faker->phoneNumber();
}
if (strlen($user['phone']) && strlen($user['email'])) {
$html .= '<br />';
}
if (strlen($user['email'])) {
$html .= $user['email'];
if($user['problem_receiving_emails']) {
$html .= ' <span class="fa fa-life-ring"></span>';
else {
if (strlen($user['phone'])) {
$html .= $user['phone'];
}
if (strlen($user['phone']) && strlen($user['email'])) {
$html .= '<br />';
}
if (strlen($user['email'])) {
$html .= $user['email'];
if($user['problem_receiving_emails']) {
$html .= ' <span class="fa fa-life-ring"></span>';
}
}
}

return $html;
}
],

+ 4
- 11
backend/views/user/orders.php Целия файл

@@ -73,7 +73,7 @@ $this->addBreadcrumb('Commandes') ;
'label' => 'Origine',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
return $orderModule->getSolver()->getLabelOrigin($order);;
return $orderModule->getSolver()->getLabelOrigin($order, true);;
}
],
[
@@ -87,21 +87,14 @@ $this->addBreadcrumb('Commandes') ;
'label' => 'Point de vente',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
return $orderModule->getPointSaleSummary($order);
return $orderModule->getSolver()->getPointSaleSummary($order);
}
],
/*[
'label' => 'Historique',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
return $orderModule->getHistorySummary($order);
}
],*/
[
'label' => 'Produits',
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
return $orderModule->getCartSummary($order);
return $orderModule->getRepository()->getCartSummary($order);
}
],
[
@@ -109,7 +102,7 @@ $this->addBreadcrumb('Commandes') ;
'format' => 'raw',
'value' => function ($order) use ($orderModule) {
$orderModule->initOrder($order);
return $orderModule->getAmountSummary($order);
return $orderModule->getRepository()->getAmountSummary($order);
}
],
[

+ 3
- 3
backend/views/user/view.php Целия файл

@@ -97,7 +97,7 @@ $this->addBreadcrumb('Récapitulatif') ;
<strong>Téléphone</strong>
<span class="pull-right">
<span class="glyphicon glyphicon-phone"></span>
<?= $model->phone ?>
<?= $userModule->getSolver()->getPhone($model); ?>
</span>
</li>
<?php endif; ?>
@@ -106,7 +106,7 @@ $this->addBreadcrumb('Récapitulatif') ;
<strong>Email</strong>
<span class="pull-right">
<span class="glyphicon glyphicon-envelope"></span>
<a href="mailto:<?= $model->email ?>"><?= $model->email ?></a>
<a href="mailto:<?= $userModule->getSolver()->getEmail($model) ?>"><?= $userModule->getSolver()->getEmail($model) ?></a>
</span>
</li>
<?php endif; ?>
@@ -114,7 +114,7 @@ $this->addBreadcrumb('Récapitulatif') ;
<li class="list-group-item list-group-item-address">
<strong>Adresse</strong>
<span class="pull-right">
<?= nl2br($model->address) ?>
<?= nl2br($userModule->getSolver()->getAddress($model)) ?>
</span>
<div class="clr"></div>
</li>

+ 108
- 94
backend/web/css/screen.css Целия файл

@@ -1580,45 +1580,49 @@ body.skin-black .user-without-account {
color: gray;
font-style: italic;
}
/* line 50, ../sass/_adminlte.scss */
/* line 49, ../sass/_adminlte.scss */
body.skin-black .locality {
color: gray;
}
/* line 55, ../sass/_adminlte.scss */
body.skin-black .main-header .dropdown-toggle::after {
display: none;
}
/* line 54, ../sass/_adminlte.scss */
/* line 59, ../sass/_adminlte.scss */
body.skin-black .main-header .logo {
background-color: white;
font-family: 'highvoltageregular';
font-size: 23px;
position: relative;
}
/* line 60, ../sass/_adminlte.scss */
/* line 65, ../sass/_adminlte.scss */
body.skin-black .main-header .logo:hover, body.skin-black .main-header .logo:focus {
background-color: white;
text-decoration: none;
}
/* line 65, ../sass/_adminlte.scss */
/* line 70, ../sass/_adminlte.scss */
body.skin-black .main-header .logo img {
position: relative;
max-width: 300px;
max-height: 300px;
height: auto;
}
/* line 73, ../sass/_adminlte.scss */
/* line 78, ../sass/_adminlte.scss */
body.skin-black .main-header .logo .logo-lg img {
width: 90px;
top: -2px;
}
/* line 79, ../sass/_adminlte.scss */
/* line 84, ../sass/_adminlte.scss */
body.skin-black .main-header .logo .logo-mini img {
width: 50px;
}
/* line 84, ../sass/_adminlte.scss */
/* line 89, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar {
display: block;
background-color: white;
padding: 0px;
}
/* line 89, ../sass/_adminlte.scss */
/* line 94, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .producer-panel {
position: relative;
float: left;
@@ -1626,11 +1630,11 @@ body.skin-black .main-header .navbar .producer-panel {
padding-left: 50px;
margin-left: 7px;
}
/* line 96, ../sass/_adminlte.scss */
/* line 101, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .producer-panel.without-logo {
padding-left: 10px;
}
/* line 100, ../sass/_adminlte.scss */
/* line 105, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .producer-panel .logo {
position: absolute;
top: 5px;
@@ -1645,7 +1649,7 @@ body.skin-black .main-header .navbar .producer-panel .logo {
text-align: center;
overflow: hidden;
}
/* line 112, ../sass/_adminlte.scss */
/* line 117, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .producer-panel .logo .img-logo {
position: absolute;
top: 50%;
@@ -1654,131 +1658,131 @@ body.skin-black .main-header .navbar .producer-panel .logo .img-logo {
max-width: 35px;
max-height: 35px;
}
/* line 122, ../sass/_adminlte.scss */
/* line 127, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .producer-panel .title {
position: relative;
top: 2px;
text-transform: uppercase;
}
/* line 127, ../sass/_adminlte.scss */
/* line 132, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .producer-panel .title a {
color: #333;
}
/* line 130, ../sass/_adminlte.scss */
/* line 135, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .producer-panel .title a:hover {
text-decoration: underline;
}
/* line 135, ../sass/_adminlte.scss */
/* line 140, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .producer-panel .title .producer-id {
color: gray;
font-size: 13px;
}
/* line 142, ../sass/_adminlte.scss */
/* line 147, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .sidebar-toggle {
color: #333;
}
/* line 146, ../sass/_adminlte.scss */
/* line 151, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .link-support {
float: left;
padding: 15px 15px;
border-right: solid 1px #e0e0e0;
color: #333;
}
/* line 152, ../sass/_adminlte.scss */
/* line 157, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .link-support:hover {
text-decoration: none;
color: #F39C12;
}
/* line 158, ../sass/_adminlte.scss */
/* line 163, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .navbar-custom-menu .nav {
display: block;
}
/* line 162, ../sass/_adminlte.scss */
/* line 167, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .navbar-custom-menu .navbar-nav > li > a,
body.skin-black .main-header .navbar .navbar-right > li > a {
border-left: solid 1px #e0e0e0;
color: #333;
}
/* line 168, ../sass/_adminlte.scss */
/* line 173, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav > li > a:hover, body.skin-black .main-header .navbar .nav > li > a:active, body.skin-black .main-header .navbar .nav > li > a:focus,
body.skin-black .main-header .navbar .nav .open > a, body.skin-black .main-header .navbar .nav .open > a:hover, body.skin-black .main-header .navbar .nav .open > a:focus,
body.skin-black .main-header .navbar .nav > .active > a {
color: #F39C12;
}
/* line 174, ../sass/_adminlte.scss */
/* line 179, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .dropdown-menu {
-moz-box-shadow: 0px 0px 4px gray;
-webkit-box-shadow: 0px 0px 4px gray;
box-shadow: 0px 0px 4px gray;
}
/* line 179, ../sass/_adminlte.scss */
/* line 184, ../sass/_adminlte.scss */
body.skin-black .main-header .logo, body.skin-black .main-header .navbar .sidebar-toggle {
border-right: solid 1px #e0e0e0;
}
/* line 183, ../sass/_adminlte.scss */
/* line 188, ../sass/_adminlte.scss */
body.skin-black .main-header .link-control-sidebar {
display: none;
}
/* line 188, ../sass/_adminlte.scss */
/* line 193, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu {
max-height: 300px;
}
/* line 191, ../sass/_adminlte.scss */
/* line 196, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu li a {
padding-top: 4px;
padding-bottom: 4px;
}
/* line 195, ../sass/_adminlte.scss */
/* line 200, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu li a h5 {
margin-bottom: 2px;
}
/* line 198, ../sass/_adminlte.scss */
/* line 203, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu li a h5 small {
float: right;
}
/* line 203, ../sass/_adminlte.scss */
/* line 208, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu li a p {
margin-left: 10px;
}
/* line 214, ../sass/_adminlte.scss */
/* line 219, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .dropdown-menu {
width: 400px;
}
/* line 218, ../sass/_adminlte.scss */
/* line 223, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .search-producer {
margin: 10px;
width: 94%;
}
/* line 223, ../sass/_adminlte.scss */
/* line 228, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .li-alert-no-results {
display: none;
}
/* line 226, ../sass/_adminlte.scss */
/* line 231, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .li-alert-no-results .alert {
margin-bottom: 0px;
margin-left: 10px;
margin-right: 10px;
padding: 15px 15px 10px 15px;
}
/* line 234, ../sass/_adminlte.scss */
/* line 239, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .label {
position: relative;
top: -2px;
left: 0px;
}
/* line 240, ../sass/_adminlte.scss */
/* line 245, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu #link-display-producers-offline {
color: #F39C12;
}
/* line 244, ../sass/_adminlte.scss */
/* line 249, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .offline {
display: none;
}
/* line 248, ../sass/_adminlte.scss */
/* line 253, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu a {
color: #333;
}
/* line 252, ../sass/_adminlte.scss */
/* line 257, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .producer-id {
position: relative;
top: 4px;
@@ -1786,100 +1790,100 @@ body.skin-black .main-header .navbar .nav li.producer-menu .producer-id {
font-size: 12px;
float: right;
}
/* line 263, ../sass/_adminlte.scss */
/* line 268, ../sass/_adminlte.scss */
body.skin-black .sidebar .sidebar-menu > li.header {
color: #899397;
}
/* line 267, ../sass/_adminlte.scss */
/* line 272, ../sass/_adminlte.scss */
body.skin-black .sidebar .label {
padding-top: 5px;
position: relative;
top: -3px;
}
/* line 274, ../sass/_adminlte.scss */
/* line 279, ../sass/_adminlte.scss */
body.skin-black .sidebar-menu > li.active > a {
border-color: #F39C12;
}
/* line 279, ../sass/_adminlte.scss */
/* line 284, ../sass/_adminlte.scss */
body.skin-black section.sidebar .user-panel {
text-align: center;
}
/* line 282, ../sass/_adminlte.scss */
/* line 287, ../sass/_adminlte.scss */
body.skin-black section.sidebar .user-panel .image {
margin-bottom: 3px;
}
/* line 286, ../sass/_adminlte.scss */
/* line 291, ../sass/_adminlte.scss */
body.skin-black section.sidebar .user-panel .title {
font-weight: bold;
color: white;
}
/* line 293, ../sass/_adminlte.scss */
/* line 298, ../sass/_adminlte.scss */
body.skin-black .content-wrapper {
background-color: #f5f5f5;
}
/* line 296, ../sass/_adminlte.scss */
/* line 301, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .content-header {
background-color: #F5F5F5;
padding-bottom: 15px;
border-bottom: solid 1px #e0e0e0;
border-top: solid 1px #e0e0e0;
}
/* line 302, ../sass/_adminlte.scss */
/* line 307, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .content-header .btn {
padding: 3px 6px;
font-size: 10px;
font-family: Arial;
text-transform: uppercase;
}
/* line 309, ../sass/_adminlte.scss */
/* line 314, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .content-header h1 {
font-family: 'myriadpro-light';
font-size: 20px;
}
/* line 315, ../sass/_adminlte.scss */
/* line 320, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .col-no-padding-left {
padding-left: 0px;
}
/* line 319, ../sass/_adminlte.scss */
/* line 324, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .col-no-padding-right {
padding-right: 0px;
}
/* line 323, ../sass/_adminlte.scss */
/* line 328, ../sass/_adminlte.scss */
body.skin-black .content-wrapper a {
color: #e08e0b;
}
/* line 326, ../sass/_adminlte.scss */
/* line 331, ../sass/_adminlte.scss */
body.skin-black .content-wrapper a.disable {
pointer-events: none;
cursor: default;
}
/* line 332, ../sass/_adminlte.scss */
/* line 337, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .label {
padding-top: 4px;
padding-bottom: 1px;
}
/* line 337, ../sass/_adminlte.scss */
/* line 342, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .btn {
color: white;
}
/* line 341, ../sass/_adminlte.scss */
/* line 346, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .btn-default {
color: #333;
background-color: white;
}
/* line 346, ../sass/_adminlte.scss */
/* line 351, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .btn-primary {
background-color: #F39C12;
color: white;
border-color: #F39C12;
}
/* line 353, ../sass/_adminlte.scss */
/* line 358, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .nav.nav-tabs .badge {
margin-left: 4px;
background-color: #e0e0e0;
color: #444;
}
/* line 360, ../sass/_adminlte.scss */
/* line 365, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .tab-content {
border-left: solid 1px #ddd;
border-bottom: solid 1px #ddd;
@@ -1887,20 +1891,20 @@ body.skin-black .content-wrapper .tab-content {
padding: 30px 15px 15px 15px;
background-color: white;
}
/* line 368, ../sass/_adminlte.scss */
/* line 373, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert {
position: relative;
}
/* line 371, ../sass/_adminlte.scss */
/* line 376, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert a {
color: white;
}
/* line 374, ../sass/_adminlte.scss */
/* line 379, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert a.btn {
color: #333;
text-decoration: none;
}
/* line 379, ../sass/_adminlte.scss */
/* line 384, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert .close {
font-size: 30px;
position: absolute;
@@ -1910,83 +1914,83 @@ body.skin-black .content-wrapper .alert .close {
color: white;
opacity: 0.6;
}
/* line 388, ../sass/_adminlte.scss */
/* line 393, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert .close:hover {
opacity: 1;
}
/* line 393, ../sass/_adminlte.scss */
/* line 398, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert.alert-dark {
background-color: #ece4d8;
color: black;
}
/* line 400, ../sass/_adminlte.scss */
/* line 405, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .small-box h3 {
font-size: 28px;
font-family: 'Source Sans Pro',sans-serif;
}
/* line 405, ../sass/_adminlte.scss */
/* line 410, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .small-box .icon {
top: -2px;
}
/* line 409, ../sass/_adminlte.scss */
/* line 414, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .small-box .small-box-footer {
color: white;
padding-top: 6px;
padding-bottom: 2px;
}
/* line 418, ../sass/_adminlte.scss */
/* line 423, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .callout h4 .fa {
margin-right: 7px;
}
/* line 421, ../sass/_adminlte.scss */
/* line 426, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .callout a {
color: white;
}
/* line 424, ../sass/_adminlte.scss */
/* line 429, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .callout .btn {
color: #333;
text-decoration: none;
}
/* line 431, ../sass/_adminlte.scss */
/* line 436, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table th {
font-size: 13px;
}
/* line 434, ../sass/_adminlte.scss */
/* line 439, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table th.column-actions, body.skin-black .content-wrapper .table td.column-actions {
width: 172px;
text-align: right;
}
/* line 438, ../sass/_adminlte.scss */
/* line 443, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table td.text-small, body.skin-black .content-wrapper .table th.text-small {
font-size: 12px;
}
/* line 442, ../sass/_adminlte.scss */
/* line 447, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table.table-bordered > thead > tr > th, body.skin-black .content-wrapper .table.table-bordered > tbody > tr > th, body.skin-black .content-wrapper .table.table-bordered > tfoot > tr > th, body.skin-black .content-wrapper .table.table-bordered > thead > tr > td, body.skin-black .content-wrapper .table.table-bordered > tbody > tr > td, body.skin-black .content-wrapper .table.table-bordered > tfoot > tr > td {
border: 1px solid #ddd;
}
/* line 451, ../sass/_adminlte.scss */
/* line 456, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table.table-bordered > thead > tr > th, body.skin-black .content-wrapper .table.table-bordered > thead > tr > td {
border-bottom-width: 2px;
}
/* line 457, ../sass/_adminlte.scss */
/* line 462, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .pagination > .active > a, body.skin-black .content-wrapper .pagination > .active > span, body.skin-black .content-wrapper .pagination > .active > a:hover, body.skin-black .content-wrapper .pagination > .active > span:hover, body.skin-black .content-wrapper .pagination > .active > a:focus, body.skin-black .content-wrapper .pagination > .active > span:focus {
background-color: #F39C12;
border: solid 1px #F39C12;
color: white;
}
/* line 463, ../sass/_adminlte.scss */
/* line 468, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .pagination > li > a, body.skin-black .content-wrapper .pagination > li > span {
color: #F39C12;
}
/* line 465, ../sass/_adminlte.scss */
/* line 470, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .pagination > li > a:hover, body.skin-black .content-wrapper .pagination > li > span:hover {
color: #c87f0a;
}
/* line 470, ../sass/_adminlte.scss */
/* line 475, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .submenu {
margin-bottom: 25px;
}
/* line 474, ../sass/_adminlte.scss */
/* line 479, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .form-actions {
position: fixed;
bottom: 0;
@@ -2000,71 +2004,75 @@ body.skin-black .content-wrapper .form-actions {
z-index: 10;
border-top: solid 1px #e0e0e0;
}
/* line 487, ../sass/_adminlte.scss */
/* line 492, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .form-actions a, body.skin-black .content-wrapper .form-actions button {
margin-left: 10px;
}
/* line 492, ../sass/_adminlte.scss */
/* line 496, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .form-actions .field-redirect-url {
display: none;
}
/* line 501, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .form-buttons {
margin-top: 25px;
text-align: right;
}
/* line 499, ../sass/_adminlte.scss */
/* line 508, ../sass/_adminlte.scss */
body.skin-black .main-footer a {
color: #F39C12;
}
/* line 504, ../sass/_adminlte.scss */
/* line 513, ../sass/_adminlte.scss */
body.skin-black .gridview-pagesize {
float: right;
margin-bottom: 8px;
}
/* line 509, ../sass/_adminlte.scss */
/* line 518, ../sass/_adminlte.scss */
body.skin-black #yii-debug-toolbar {
bottom: 64px;
}

/* line 514, ../sass/_adminlte.scss */
/* line 523, ../sass/_adminlte.scss */
body.login-page {
background: none;
background-color: white;
}
/* line 518, ../sass/_adminlte.scss */
/* line 527, ../sass/_adminlte.scss */
body.login-page .login-box .login-logo {
text-align: center;
font-family: 'worksans_bold';
}
/* line 522, ../sass/_adminlte.scss */
/* line 531, ../sass/_adminlte.scss */
body.login-page .login-box .login-logo img {
width: 150px;
}
/* line 528, ../sass/_adminlte.scss */
/* line 537, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body,
body.login-page .login-box .login-box-body input#loginform-email,
body.login-page .login-box .login-box-body input#loginform-password,
body.login-page .login-box .login-box-body .btn-primary {
font-size: 14px;
}
/* line 535, ../sass/_adminlte.scss */
/* line 544, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body .btn-primary {
background-color: #F39C12;
border-color: #F39C12;
padding: 5px 10px;
margin-bottom: 15px;
}
/* line 541, ../sass/_adminlte.scss */
/* line 550, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body .btn-primary:active {
background-color: #f4a62a;
border-color: #F39C12;
}
/* line 547, ../sass/_adminlte.scss */
/* line 556, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body a {
color: #F39C12;
}
/* line 549, ../sass/_adminlte.scss */
/* line 558, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body a:hover {
color: #f4a62a;
}
/* line 554, ../sass/_adminlte.scss */
/* line 563, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body .checkbox label input {
position: relative;
top: 0px;
@@ -2300,6 +2308,12 @@ body.login-page .login-box .login-box-body .checkbox label input {
font-weight: normal;
}

/* line 5, ../sass/accessory/_form.scss */
.accessory-form #panel-products .panel-body label {
display: block;
font-weight: normal;
}

/**
Copyright Souke (2018)


+ 24
- 10
backend/web/js/vuejs/distribution-index.js Целия файл

@@ -135,7 +135,7 @@ if($(selector).length) {
+ ('0' + (this.date.getMonth() + 1)).slice(-2) + '/'
+ this.date.getFullYear();
}
this.init();
this.init(false, true);
this.loading = false;
},
methods: {
@@ -157,7 +157,7 @@ if($(selector).length) {
&& today.getMonth() == this.date.getMonth()
&& today.getDay() == this.date.getDay();
},
init: function (idActivePointSale) {
init: function (idActivePointSale, displayFormOrderCreate) {
var app = this;
this.showLoading = true;

@@ -288,6 +288,10 @@ if($(selector).length) {
highlight: highlightStyle,
dates: app.date
});

if(displayFormOrderCreate && searchParams.has('displayFormOrderCreate')) {
app.openModalFormOrderCreate();
}
});
},
initCountActiveProducts: function () {
@@ -1230,24 +1234,34 @@ if($(selector).length) {
this.vatMode = 'all';
}
},
getProductQuantityRemaining: function (product) {
var quantityRemaining = 0;
getProductQuantityMax: function(product) {
return product.quantity_max;
},
getProductQuantityOrder: function(product) {
var productQuantityOrder = 0;
var unit = product.unit;

for (key in this.orders) {
productQuantityOrder += this.getProductQuantityProductOrder(this.orders[key], product);
}
if (this.create == 1) {
productQuantityOrder += this.getProductQuantityProductOrder(this.order, product);
}
return productQuantityOrder;
},
getProductQuantityRemaining: function (product) {
var productQuantityRemaining = null;
var productQuantityMax = this.getProductQuantityMax(product);
var productQuantityOrder = this.getProductQuantityOrder(product);

if(productQuantityMax) {
productQuantityRemaining = productQuantityMax - productQuantityOrder;
}

quantityRemaining = this.getProductDistribution(product).quantity_max - productQuantityOrder;
if (unit != 'piece') {
quantityRemaining = quantityRemaining.toFixed(2);
// format
if (productQuantityRemaining && product.unit != 'piece') {
productQuantityRemaining = productQuantityRemaining.toFixed(2);
}

return quantityRemaining;
return productQuantityRemaining;
},
getProductQuantityProductOrder: function (order, product) {
var productOrder = order.productOrder[product.id];

+ 5
- 0
backend/web/js/vuejs/producer-update.js Целия файл

@@ -73,6 +73,11 @@ if($(selector).length) {
nameDisplay: 'Abonnements',
isAdminSection: 0
},
{
name: 'communication',
nameDisplay: 'Communication',
isAdminSection: 0
},
{
name: 'tableau-bord',
nameDisplay: 'Tableau de bord',

+ 9
- 0
backend/web/sass/_adminlte.scss Целия файл

@@ -45,6 +45,11 @@ body.skin-black {
font-style: italic;
}

// Points de vente
.locality {
color: gray;
}

.main-header {

.dropdown-toggle::after {
@@ -487,6 +492,10 @@ body.skin-black {
a, button {
margin-left: 10px;
}

.field-redirect-url {
display: none;
}
}

.form-buttons {

+ 11
- 0
backend/web/sass/accessory/_form.scss Целия файл

@@ -0,0 +1,11 @@

.accessory-form {
#panel-products {
.panel-body {
label {
display: block;
font-weight: normal;
}
}
}
}

+ 1
- 0
backend/web/sass/screen.scss Целия файл

@@ -1533,6 +1533,7 @@ a.btn, button.btn {
@import "subscription/_form.scss" ;
@import "product/_index.scss" ;
@import "product/_form.scss" ;
@import "accessory/_form.scss" ;
@import "stats/_products.scss" ;
@import "distribution/_index.scss" ;
@import "user/_emails.scss" ;

+ 5
- 1
common/components/ActiveRecordCommon.php Целия файл

@@ -47,6 +47,8 @@ class ActiveRecordCommon extends \yii\db\ActiveRecord
const SEARCH_ONE = 'one';
const SEARCH_COUNT = 'count';

public ?string $redirect_url = '';

public function populateFieldObject($fieldIdentifier, $fieldObject, $object)
{
$this->{$fieldIdentifier} = $object->id;
@@ -92,7 +94,9 @@ class ActiveRecordCommon extends \yii\db\ActiveRecord
$pk = $class::tableName() . '.' . $pk[0];

if (isset($options['attribute_id_producer']) && strlen($options['attribute_id_producer'])
&& !isset($params[$options['attribute_id_producer']]) && !\Yii::$app->user->isGuest
&& !isset($params[$options['attribute_id_producer']])
&& !\Yii::$app->user->isGuest
&& !isset($options['ignore_id_producer'])
) {
$params[$options['attribute_id_producer']] = GlobalParam::getCurrentProducerId();
}

+ 2
- 0
common/components/BusinessLogic.php Целия файл

@@ -28,6 +28,8 @@ class BusinessLogic
$this->getUserModule(),
$this->getUserMessageModule(),
$this->getPointSaleDistributionModule(),
$this->getProductAccessoryModule(),
$this->getAccessoryModule(),
$this->getProductDistributionModule(),
$this->getProductCategoryModule(),
$this->getProductPointSaleModule(),

+ 12
- 0
common/components/BusinessLogicTrait.php Целия файл

@@ -24,7 +24,9 @@ use domain\PointSale\SharedPointSale\SharedPointSaleModule;
use domain\PointSale\UserPointSale\UserPointSaleModule;
use domain\Producer\Producer\ProducerModule;
use domain\Producer\ProducerPriceRange\ProducerPriceRangeModule;
use domain\Product\Accessory\AccessoryModule;
use domain\Product\Product\ProductModule;
use domain\Product\ProductAccessory\ProductAccessoryModule;
use domain\Product\ProductCategory\ProductCategoryModule;
use domain\Product\ProductPointSale\ProductPointSaleModule;
use domain\Product\ProductPrice\Module\ProductPriceModule;
@@ -42,6 +44,16 @@ use domain\User\UserUserGroup\UserUserGroupModule;

trait BusinessLogicTrait
{
public function getProductAccessoryModule(): ProductAccessoryModule
{
return ProductAccessoryModule::getInstance();
}

public function getAccessoryModule(): AccessoryModule
{
return AccessoryModule::getInstance();
}

public function getOrderStatusModule(): OrderStatusModule
{
return OrderStatusModule::getInstance();

+ 42
- 0
common/components/Faker.php Целия файл

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

namespace common\components;

use Faker\Factory;
use Faker\Generator;
use Faker\Provider\fr_FR\Address;
use Faker\Provider\fr_FR\Person;
use Faker\Provider\fr_FR\PhoneNumber;

class Faker
{
protected Generator $faker;

public function __construct()
{
$this->faker = Factory::create();
$this->faker->addProvider(new Person($this->faker));
$this->faker->addProvider(new PhoneNumber($this->faker));
$this->faker->addProvider(new Address($this->faker));
}

public function name(): string
{
return $this->faker->name;
}

public function email(): string
{
return $this->faker->email;
}

public function phoneNumber(): string
{
return $this->faker->mobileNumber;
}

public function address(): string
{
return $this->faker->address;
}
}

+ 3
- 0
common/config/main.php Целия файл

@@ -78,6 +78,9 @@ return [
}
},
'components' => [
'faker' => [
'class' => 'common\components\Faker'
],
'parameterBag' => [
'class' => 'common\components\ParameterBag'
],

+ 1
- 1
common/config/params.php Целия файл

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

return [
'version' => '24.6.C',
'version' => '24.6.D',
'maintenanceMode' => false,
'siteName' => 'Souke',
'tinyMcePlugins' => 'preview searchreplace autolink autosave save directionality code visualblocks visualchars fullscreen image link lists wordcount help',

+ 28
- 0
common/versions/24.6.D.php Целия файл

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

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

version(
'24/06/2024',
[
[
"[Administration] Communiquer > Email : possibilité de configurer un message et un sujet par défaut (Paramètres > Communication)",
"[Administration] Utilisateur > Créer (en arrivant de la création d'une commande) : retour automatique à la création de la commande",
],
[
"[Administration] Tableau de bord : corectif affichage des commandes modifiées issues des abonnements"
]
],
[
[
"[Administration] Commandes admin : page générale des dernières commandes passées sur Souke",
"[Administration] Compte démo : anonymisation des données personnelles",
],
[
"[Administration] Utilisateurs admin : lien vers la modification du profil"
]
],
$userCurrent
);

?>

+ 34
- 0
console/migrations/m240619_195454_create_table_accessory.php Целия файл

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

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

/**
* Class m240619_195454_create_table_accessory
*/
class m240619_195454_create_table_accessory extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->createTable('accessory', [
'id' => 'pk',
'id_producer' => Schema::TYPE_INTEGER.' NOT NULl',
'name' => Schema::TYPE_STRING.' NOT NULl',
'quantity' => Schema::TYPE_INTEGER
]);

$this->addForeignKey('fk_accessory_id_producer', 'accessory', 'id_producer', 'producer', 'id');
}

/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropTable('accessory');
$this->dropForeignKey('fk_accessory_id_producer', 'accessory');
}
}

+ 28
- 0
console/migrations/m240620_070618_add_columns_producer_communicate_email_defaults.php Целия файл

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

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

/**
* Class m240620_070618_add_columns_producer_communicate_email_defaults
*/
class m240620_070618_add_columns_producer_communicate_email_defaults extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('producer', 'option_communicate_email_default_subject', Schema::TYPE_STRING);
$this->addColumn('producer', 'option_communicate_email_default_message', Schema::TYPE_TEXT);
}

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

+ 31
- 0
console/migrations/m240620_074924_create_table_product_accessory.php Целия файл

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

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

/**
* Class m240620_074924_create_table_product_accessory
*/
class m240620_074924_create_table_product_accessory extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->createTable('product_accessory', [
'id' => 'pk',
'id_product' => Schema::TYPE_INTEGER.' NOT NULl',
'id_accessory' => Schema::TYPE_INTEGER.' NOT NULl',
'quantity' => Schema::TYPE_INTEGER.' NOT NULL'
]);
}

/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropTable('product_accessory');
}
}

+ 3
- 0
domain/Distribution/Distribution/Export/DistributionReportPdfGenerator.php Целия файл

@@ -18,6 +18,7 @@ use domain\Product\Product\Product;
use domain\Product\Product\ProductRepository;
use domain\Product\Product\ProductSolver;
use domain\User\User\UserRepository;
use domain\User\User\UserSolver;
use kartik\mpdf\Pdf;
use domain\_\AbstractGenerator;

@@ -35,6 +36,7 @@ class DistributionReportPdfGenerator extends AbstractGenerator implements Distri
protected ProductSolver $productSolver;
protected DocumentSolver $documentSolver;
protected UserRepository $userRepository;
protected UserSolver $userSolver;

public function loadDependencies(): void
{
@@ -48,6 +50,7 @@ class DistributionReportPdfGenerator extends AbstractGenerator implements Distri
$this->productSolver = $this->loadService(ProductSolver::class);
$this->documentSolver = $this->loadService(DocumentSolver::class);
$this->userRepository = $this->loadService(UserRepository::class);
$this->userSolver = $this->loadService(UserSolver::class);
}

public function generate(Distribution $distribution, bool $save = false)

+ 2
- 2
domain/Document/Invoice/InvoiceSearch.php Целия файл

@@ -70,8 +70,8 @@ class InvoiceSearch extends Invoice
'name',
'date',
'username' => [
'asc' => ['user_invoice.lastname' => SORT_ASC, 'user_invoice.name' => SORT_ASC],
'desc' => ['user_invoice.lastname' => SORT_DESC, 'user_invoice.name' => SORT_DESC],
'asc' => ['IF(ISNULL(user_invoice.name_legal_person), user_invoice.lastname, user_invoice.name_legal_person)' => SORT_ASC],
'desc' => ['IF(ISNULL(user_invoice.name_legal_person), user_invoice.lastname, user_invoice.name_legal_person)' => SORT_DESC],
]
],
'defaultOrder' => [

+ 3
- 1
domain/Feature/Feature/Feature.php Целия файл

@@ -51,8 +51,10 @@ class Feature extends ActiveRecordCommon
const ALIAS_SETTINGS = 'settings';
const ALIAS_SHOP_SUPPORT = 'shop_support';
const ALIAS_SHARED_POINT_SALE = 'shared_point_sale';
const ALIAS_SUMUP_SYNCHRONIZATION = 'sumup_synchronization';
const ALIAS_BRIDGE_SUMUP = 'sumup_synchronization';
const ALIAS_SPONSORSHIP = 'sponsorship';
const ALIAS_BRIDGE_EVOLIZ = 'bridge_evoliz';
const ALIAS_PRODUCT_ACCESSORY = 'product_accessory';

/**
* @inheritdoc

+ 4
- 2
domain/Feature/Feature/FeatureDefinition.php Целия файл

@@ -21,8 +21,10 @@ class FeatureDefinition extends AbstractDefinition
Feature::ALIAS_SETTINGS => 'Système de paramètres',
Feature::ALIAS_SHOP_SUPPORT => 'Support boutique',
Feature::ALIAS_SHARED_POINT_SALE => 'Points de vente partagés',
Feature::ALIAS_SUMUP_SYNCHRONIZATION => "Synchronisation de commandes avec Sumup / Tiller",
Feature::ALIAS_SPONSORSHIP => "Parrainage producteurs"
Feature::ALIAS_SPONSORSHIP => "Parrainage producteurs",
Feature::ALIAS_BRIDGE_SUMUP => "Pont vers SumUp",
Feature::ALIAS_BRIDGE_EVOLIZ => "Pont vers Evoliz",
Feature::ALIAS_PRODUCT_ACCESSORY => 'Accessoires produits',
];
}
}

+ 1
- 1
domain/Order/Order/OrderBuilder.php Целия файл

@@ -120,7 +120,7 @@ class OrderBuilder extends AbstractBuilder

public function initDateUpdate(Order $order)
{
$this->date_update = date('Y-m-d H:i:s');;
$order->date_update = date('Y-m-d H:i:s');;
}

public function addProductOrdersFromSubscription(Order $order, Subscription $subscription): bool

+ 6
- 0
domain/Order/Order/OrderModule.php Целия файл

@@ -13,6 +13,7 @@ class OrderModule extends AbstractModule
OrderSolver::class,
OrderRepository::class,
OrderBuilder::class,
OrderResolver::class,
OrderManager::class,
OrderDocumentManager::class,
TillerManager::class,
@@ -39,6 +40,11 @@ class OrderModule extends AbstractModule
return OrderBuilder::getInstance();
}

public function getResolver(): OrderResolver
{
return OrderResolver::getInstance();
}

public function getManager(): OrderManager
{
return OrderManager::getInstance();

+ 119
- 0
domain/Order/Order/OrderResolver.php Целия файл

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

namespace domain\Order\Order;

use domain\_\AbstractResolver;
use domain\Distribution\Distribution\Distribution;
use domain\Distribution\ProductDistribution\ProductDistributionRepository;
use domain\Feature\Feature\Feature;
use domain\Feature\Feature\FeatureChecker;
use domain\Product\Accessory\Accessory;
use domain\Product\Product\Product;
use yii\base\ErrorException;

class OrderResolver extends AbstractResolver
{
protected OrderSolver $orderSolver;
protected OrderRepository $orderRepository;
protected ProductDistributionRepository $productDistributionRepository;
protected FeatureChecker $featureChecker;

public function loadDependencies(): void
{
$this->orderSolver = $this->loadService(OrderSolver::class);
$this->orderRepository = $this->loadService(OrderRepository::class);
$this->productDistributionRepository = $this->loadService(ProductDistributionRepository::class);
$this->featureChecker = $this->loadService(FeatureChecker::class);
}

public function getProductQuantityByDistribution(Product $product, Distribution $distribution): float
{
$ordersArray = $this->orderRepository->findOrdersByDistribution($distribution);
return $this->orderSolver->getProductQuantity($product, $ordersArray);
}

public function getSmallestQuantityAccessory(Product $product): ?int
{
$smallestQuantity = null;

foreach ($product->getProductAccessories() as $productAccessory) {
$quantityAccessory = $productAccessory->getAccessory()->getQuantity();
$smallestQuantity = is_null($smallestQuantity) ? $quantityAccessory
: min($smallestQuantity, $quantityAccessory);
}

return $smallestQuantity;
}

public function getProductQuantityMax(Product $product, Distribution $distribution): ?float
{
$productDistribution = $this->productDistributionRepository->findOneProductDistribution($distribution, $product);
// @TODO : gérer via une exception
if(!$productDistribution) {
return null;
}

$quantityMax = $productDistribution->quantity_max;

if($this->featureChecker->isEnabled(Feature::ALIAS_PRODUCT_ACCESSORY)) {
$smallestQuantityAccessory = $this->getSmallestQuantityAccessory($product);
if (!is_null($smallestQuantityAccessory)) {
$quantityMax = is_null($quantityMax) ? $smallestQuantityAccessory : min($quantityMax, $smallestQuantityAccessory);
}
}

return $quantityMax;
}

public function getQuantityOfAccessoryAvailableInDistribution(Accessory $accessory, Distribution $distribution): int
{
$quantityOfAccessoryUsed = 0;

foreach($accessory->getProductAccessories() as $productAccessory) {
$quantityOfAccessoryUsed += $this->getProductQuantityByDistribution($productAccessory->getProduct(), $distribution);
}

return $accessory->getQuantity() - $quantityOfAccessoryUsed;
}

public function getSmallestQuantityAccessoryAvailable(Product $product, Distribution $distribution): ?int
{
$smallestQuantity = null;

if($this->featureChecker->isEnabled(Feature::ALIAS_PRODUCT_ACCESSORY)) {
foreach ($product->getProductAccessories() as $productAccessory) {
$quantityAccessoryAvailableInDistribution = $this->getQuantityOfAccessoryAvailableInDistribution(
$productAccessory->getAccessory(),
$distribution
);
$smallestQuantity = is_null($smallestQuantity) ? $quantityAccessoryAvailableInDistribution
: min($smallestQuantity, $quantityAccessoryAvailableInDistribution);
}
}

return $smallestQuantity;
}

public function getProductQuantityRemaining(Product $product, Distribution $distribution): ?float
{
$productDistribution = $this->productDistributionRepository->findOneProductDistribution($distribution, $product);
if(!$productDistribution) {
return null;
}

$quantityOrder = $this->getProductQuantityByDistribution($product, $distribution);
$quantityRemaining = is_null($productDistribution->quantity_max) ? null
: ($productDistribution->quantity_max - $quantityOrder);

// Limitation par nombre d'accessoires disponibles
if($this->featureChecker->isEnabled(Feature::ALIAS_PRODUCT_ACCESSORY)) {
$smallestQuantityAccessoryAvailable = $this->getSmallestQuantityAccessoryAvailable($product, $distribution);
if (!is_null($smallestQuantityAccessoryAvailable)) {
$quantityRemaining = is_null($quantityRemaining) ? $smallestQuantityAccessoryAvailable
: min($quantityRemaining, $smallestQuantityAccessoryAvailable);
}
}

return $quantityRemaining;
}
}

+ 1
- 0
domain/Order/Order/OrderSearch.php Целия файл

@@ -53,6 +53,7 @@ class OrderSearch extends Order
}

$query = Order::searchQuery($paramsSearch, [
'ignore_id_producer' => true,
'orderby' => 'distribution.date DESC'
]);

+ 10
- 46
domain/Order/Order/OrderSolver.php Целия файл

@@ -127,11 +127,7 @@ class OrderSolver extends AbstractService implements SolverInterface
public function getOrderUsername(Order $order): string
{
if (isset($order->user)) {
if (isset($order->user->name_legal_person) && strlen($order->user->name_legal_person)) {
return Html::encode($order->user->name_legal_person);
} else {
return Html::encode($this->userSolver->getUsername($order->user));
}
return Html::encode($this->userSolver->getUsername($order->user));
} elseif (strlen($order->username)) {
return Html::encode($order->username);
} else {
@@ -268,45 +264,6 @@ class OrderSolver extends AbstractService implements SolverInterface
return 'commande-create';
}

/**
* Retourne l'historique de la commande (ajoutée, modifiée, supprimée) au format HTML.
*/
//getStrHistory
public function getHistorySummary(Order $order): string
{
$arr = [
'class' => 'create',
'glyphicon' => 'plus',
'str' => 'Ajoutée',
'date' => $order->date
];

if (!is_null($order->date_update)) {
$arr = [
'class' => 'update',
'glyphicon' => 'pencil',
'str' => 'Modifiée',
'date' => $order->date_update
];
}
if ($this->isOrderStatusCanceled($order)) {
$arr = [
'class' => 'delete',
'glyphicon' => 'remove',
'str' => 'Annulée',
'date' => $this->getOrderStatusHistoryByOrderStatusAlias($order,OrderStatus::ALIAS_CANCELED)
->getDate()->format('Y-m-d H:i:s')
];
}

$html = '<div class="small"><span class="' . $arr['class'] . '">'
. '<span class="glyphicon glyphicon-' . $arr['glyphicon'] . '"></span> '
. $arr['str'] . '</span> le <strong>'
. date('d/m/Y à G\hi', strtotime($arr['date'])) . '</strong></div>';

return $html;
}

public function getPaymentLabelAmountRemainingSurplus(Order $order): string
{
$amountPaid = $this->getOrderAmountPaid($order);
@@ -331,12 +288,19 @@ class OrderSolver extends AbstractService implements SolverInterface
return '<br><span class="payment-detail-remaining-surplus">'.$text.'</span>';
}

public function getLabelOrderStatus(Order $order): string
public function getLabelOrderStatus(Order $order, bool $withDateLastOrderStatus = false): string
{
$orderStatusCssClass = $this->getOrderStatusCssClass($order);
$orderStatusLabel = $this->getOrderStatusLabel($order);
$orderStatusHistorySummaryTitleTag = $this->getOrderStatusHistorySummaryTitleTag($order);
return '<span class="label label-'.$orderStatusCssClass.'" title="'.$orderStatusHistorySummaryTitleTag.'">'.$orderStatusLabel.'</span>';
$html = '<span class="label label-'.$orderStatusCssClass.'" title="'.$orderStatusHistorySummaryTitleTag.'">'.$orderStatusLabel.'</span>';

$lastOrderStatusHistory = $this->getLastOrderStatusHistory($order);
if($withDateLastOrderStatus && $lastOrderStatusHistory) {
$html .= '<br /><span class="small gray">'.$lastOrderStatusHistory->getDate()->format('d/m/Y à H:i').'</span>';
}

return $html;
}

/**

+ 1
- 11
domain/Payment/PaymentSolver.php Целия файл

@@ -6,6 +6,7 @@ use common\helpers\MeanPayment;
use domain\Order\Order\Order;
use domain\_\AbstractService;
use domain\_\SolverInterface;
use domain\User\User\UserSolver;

class PaymentSolver extends AbstractService implements SolverInterface
{
@@ -130,15 +131,4 @@ class PaymentSolver extends AbstractService implements SolverInterface

return 'Type de paiement inconnu';
}

public function getStrUserAction(Payment $payment): string
{
$userAction = $payment->getUserActionObject();

if ($userAction) {
return $userAction->getName() . ' ' . $userAction->getlastname();
} else {
return 'Système';
}
}
}

+ 14
- 1
domain/Producer/Producer/Producer.php Целия файл

@@ -262,7 +262,9 @@ class Producer extends ActiveRecordCommon
'option_leave_period_message_title',
'option_leave_period_message',
'option_credit_description',
'sponsorship_code'
'sponsorship_code',
'option_communicate_email_default_subject',
'option_communicate_email_default_message',
],
'string'
],
@@ -548,6 +550,8 @@ class Producer extends ActiveRecordCommon
'option_leave_period_message' => 'Message des congés',
'option_credit_description' => "Description Cagnotte",
'sponsorship_sponsor_reward' => 'Récompense parrain',
'option_communicate_email_default_subject' => 'Sujet par défaut',
'option_communicate_email_default_message' => 'Message par défaut',
];
}

@@ -671,5 +675,14 @@ class Producer extends ActiveRecordCommon
{
return self::$billingFrequencyArray;
}

public function isDemoAccount(): bool
{
if (strpos($this->getName(), 'Démo') !== false) {
return true;
}

return false;
}
}

+ 0
- 12
domain/Producer/Producer/ProducerSolver.php Целия файл

@@ -10,18 +10,6 @@ use yii\helpers\Html;

class ProducerSolver extends AbstractService implements SolverInterface
{
/**
* Retourne true si le compte est un compte de démo.
*/
public function isDemo(Producer $producer): bool
{
if (strpos($producer->name, 'Démo') !== false) {
return true;
}

return false;
}

public function getFullAddressAsHtml(Producer $producer): string
{
$address = '<div class="name">'.$producer->name . '</div>';

+ 106
- 0
domain/Product/Accessory/Accessory.php Целия файл

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

namespace domain\Product\Accessory;

use common\components\ActiveRecordCommon;
use domain\Producer\Producer\Producer;
use domain\Product\ProductAccessory\ProductAccessory;
use yii\db\ActiveQuery;

class Accessory extends ActiveRecordCommon
{
// Produits sélectionnés dans le formulaire d'édition
public $selected_products_ids;

public static function tableName()
{
return 'accessory';
}

public function rules()
{
return [
[['name', 'id_producer'], 'required'],
[['name'], 'string', 'max' => 255],
[['quantity', 'id_producer'], 'integer'],
[['selected_products_ids'], 'safe'],
];
}

public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Nom',
'quantity' => 'Quantité',
];
}

/* Getters / Setters */

public function getId(): ?int
{
return $this->id;
}

public function getProducer(): Producer
{
return $this->producerRelation;
}

public function setProducer(Producer $producer): self
{
$this->populateFieldObject('id_producer', 'producerRelation', $producer);
return $this;
}

public function getName(): string
{
return $this->name;
}

public function setName(string $name): self
{
$this->name = $name;
return $this;
}

public function getQuantity(): ?int
{
return $this->quantity;
}

public function setQuantity(?int $quantity): self
{
$this->quantity = $quantity;
return $this;
}

public function getProductAccessories(): array
{
return $this->productAccessoriesRelation;
}

public function getSelectedProductsIds()
{
return $this->selected_products_ids;
}

public function setSelectedProductsIds(array $selectedProductsIdsArray): self
{
$this->selected_products_ids = $selectedProductsIdsArray;
return $this;
}

/* Relations */

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

public function getProductAccessoriesRelation(): ActiveQuery
{
return $this->hasMany(ProductAccessory::class, ['id_accessory' => 'id']);
}
}

+ 35
- 0
domain/Product/Accessory/AccessoryBuilder.php Целия файл

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

namespace domain\Product\Accessory;

use domain\_\AbstractBuilder;
use domain\Producer\Producer\Producer;
use domain\Product\ProductAccessory\ProductAccessoryRepository;

class AccessoryBuilder extends AbstractBuilder
{
protected ProductAccessoryRepository $productAccessoryRepository;

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

public function instanciateAccessory(Producer $producer): Accessory
{
$accessory = new Accessory();
$accessory->setProducer($producer);

return $accessory;
}

public function initSelectedProductsIds(Accessory $accessory): void
{
$selectedProductsIdsArray = [];
$productAccessoriesArray = $this->productAccessoryRepository->findProductAccessoriesByAccessory($accessory);
foreach($productAccessoriesArray as $productAccessory) {
$selectedProductsIdsArray[] = $productAccessory->getProduct()->id;
}
$accessory->setSelectedProductsIds($selectedProductsIdsArray);
}
}

+ 18
- 0
domain/Product/Accessory/AccessoryDefinition.php Целия файл

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

namespace domain\Product\Accessory;

use domain\_\AbstractDefinition;

class AccessoryDefinition extends AbstractDefinition
{
public function getEntityFqcn(): string
{
return Accessory::class;
}

public function getIcon(): string
{
return 'cutlery';
}
}

+ 45
- 0
domain/Product/Accessory/AccessoryManager.php Целия файл

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

namespace domain\Product\Accessory;

use domain\_\AbstractManager;
use domain\Producer\Producer\Producer;
use domain\Product\Product\ProductRepository;
use domain\Product\ProductAccessory\ProductAccessoryManager;
use domain\Product\ProductAccessory\ProductAccessoryRepository;
use yii\base\ErrorException;

class AccessoryManager extends AbstractManager
{
protected AccessoryBuilder $accessoryBuilder;
protected ProductAccessoryManager $productAccessoryManager;
protected ProductRepository $productRepository;

public function loadDependencies(): void
{
$this->accessoryBuilder = $this->loadService(AccessoryBuilder::class);
$this->productAccessoryManager = $this->loadService(ProductAccessoryManager::class);
$this->productRepository = $this->loadService(ProductRepository::class);
}

public function createAccessory(Producer $producer, string $name, ?int $quantity): Accessory
{
$accessory = $this->accessoryBuilder->instanciateAccessory($producer);
$accessory->setName($name);
$accessory->setQuantity($quantity);
$accessory->save();
return $accessory;
}

public function manageProducts(Accessory $accessory, array $selectedProductsIds = []): void
{
$this->productAccessoryManager->deleteAllProductAccessoriesByAccessory($accessory);

foreach($selectedProductsIds as $selectedProductId) {
$product = $this->productRepository->findOneProductById($selectedProductId);
if($product) {
$this->productAccessoryManager->createProductAccessory($product, $accessory, 1);
}
}
}
}

+ 38
- 0
domain/Product/Accessory/AccessoryModule.php Целия файл

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

namespace domain\Product\Accessory;

use domain\_\AbstractModule;

class AccessoryModule extends AbstractModule
{
public function getServices(): array
{
return [
AccessoryDefinition::class,
AccessoryBuilder::class,
AccessoryRepository::class,
AccessoryManager::class
];
}

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

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

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

public function getManager(): AccessoryManager
{
return AccessoryManager::getInstance();
}
}

+ 39
- 0
domain/Product/Accessory/AccessoryRepository.php Целия файл

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

namespace domain\Product\Accessory;

use domain\_\AbstractRepository;
use domain\_\RepositoryQueryInterface;
use yii\db\ActiveQuery;

class AccessoryRepository extends AbstractRepository
{
protected AccessoryRepositoryQuery $query;

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

public function getDefaultOptionsSearch(): array
{
return [
self::WITH => [],
self::JOIN_WITH => [],
self::ORDER_BY => 'accessory.name ASC',
self::ATTRIBUTE_ID_PRODUCER => 'accessory.id_producer'
];
}

public function queryAccessories(): RepositoryQueryInterface
{
return $this->createDefaultQuery();
}

public function findOneAccessoryById(int $id): ?Accessory
{
return $this->createDefaultQuery()
->filterById($id)
->findOne();
}
}

+ 15
- 0
domain/Product/Accessory/AccessoryRepositoryQuery.php Целия файл

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

namespace domain\Product\Accessory;

use domain\_\AbstractRepositoryQuery;

class AccessoryRepositoryQuery extends AbstractRepositoryQuery
{
protected AccessoryDefinition $definition;

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

+ 24
- 0
domain/Product/Product/Product.php Целия файл

@@ -43,11 +43,14 @@ use common\helpers\GlobalParam;
use domain\Config\TaxRate\TaxRate;
use domain\Distribution\ProductDistribution\ProductDistribution;
use domain\Producer\Producer\Producer;
use domain\Product\Accessory\Accessory;
use domain\Product\ProductAccessory\ProductAccessory;
use domain\Product\ProductCategory\ProductCategory;
use domain\Product\ProductPointSale\ProductPointSale;
use domain\Product\ProductPrice\Model\ProductPrice;
use domain\Subscription\ProductSubscription\ProductSubscription;
use domain\_\StatusInterface;
use yii\db\ActiveQuery;
use yii\web\UploadedFile;

/**
@@ -204,6 +207,15 @@ class Product extends ActiveRecordCommon implements StatusInterface
$this->price_with_tax = $productSolver->getPriceWithTax($this);
}

/* Getters / Setters */

public function getProductAccessories(): array
{
return $this->productAccessoriesRelation;
}

/* Relations */

public function getProductDistribution()
{
return $this->hasMany(ProductDistribution::class, ['id_product' => 'id']);
@@ -244,6 +256,18 @@ class Product extends ActiveRecordCommon implements StatusInterface
return $this->hasMany(ProductPointSale::class, ['id_product' => 'id']);
}

public function getProductAccessoriesRelation(): ActiveQuery
{
return $this->hasMany(ProductAccessory::class, ['id_product' => 'id']);
}

/* Méthodes */

public function hasAccessory(): bool
{
return $this->getProductAccessories() && count($this->getProductAccessories());
}

/**
* Enregistre le produit.
*/

+ 22
- 0
domain/Product/Product/ProductManager.php Целия файл

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

namespace domain\Product\Product;

use domain\_\AbstractManager;
use domain\Product\Accessory\Accessory;
use domain\Product\ProductAccessory\ProductAccessoryManager;

class ProductManager extends AbstractManager
{
protected ProductAccessoryManager $productAccessoryManager;

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

public function needAccessory(Product $product, Accessory $accessory, int $quantity): void
{
$this->productAccessoryManager->createProductAccessoryIfNotExist($product, $accessory, $quantity);
}
}

+ 9
- 3
domain/Product/Product/ProductModule.php Целия файл

@@ -12,8 +12,9 @@ class ProductModule extends AbstractModule
return [
ProductDefinition::class,
ProductSolver::class,
ProductRepository::class,
ProductBuilder::class,
ProductRepository::class,
ProductManager::class
];
}

@@ -27,13 +28,18 @@ class ProductModule extends AbstractModule
return ProductSolver::getInstance();
}

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

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

public function getBuilder(): ProductBuilder
public function getManager(): ProductManager
{
return ProductBuilder::getInstance();
return ProductManager::getInstance();
}
}

+ 86
- 0
domain/Product/ProductAccessory/ProductAccessory.php Целия файл

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

namespace domain\Product\ProductAccessory;

use common\components\ActiveRecordCommon;
use domain\Product\Accessory\Accessory;
use domain\Product\Product\Product;
use yii\db\ActiveQuery;

class ProductAccessory extends ActiveRecordCommon
{
public static function tableName()
{
return 'product_accessory';
}

public function rules()
{
return [
[['id_product', 'id_accessory', 'quantity'], 'required'],
[['id_product', 'id_accessory', 'quantity'], 'integer'],
];
}

public function attributeLabels()
{
return [
'id' => 'ID',
'id_product' => 'Produit',
'id_accessory' => 'Accessoire',
'quantity' => 'Quantité',
];
}

/* Getters / Setters */

public function getId(): ?int
{
return $this->id;
}

public function getProduct(): Product
{
return $this->productRelation;
}

public function setProduct(Product $product): self
{
$this->populateFieldObject('id_product', 'productRelation', $product);
return $this;
}

public function getAccessory(): Accessory
{
return $this->accessoryRelation;
}

public function setAccessory(Accessory $accessory): self
{
$this->populateFieldObject('id_accessory', 'accessoryRelation', $accessory);
return $this;
}

public function getQuantity(): ?int
{
return $this->quantity;
}

public function setQuantity(?int $quantity): self
{
$this->quantity = $quantity;
return $this;
}

/* Relations */

public function getProductRelation(): ActiveQuery
{
return $this->hasOne(Product::class, ['id' => 'id_product']);
}

public function getAccessoryRelation(): ActiveQuery
{
return $this->hasOne(Accessory::class, ['id' => 'id_accessory']);
}
}

+ 15
- 0
domain/Product/ProductAccessory/ProductAccessoryBuilder.php Целия файл

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

namespace domain\Product\ProductAccessory;

use domain\_\AbstractBuilder;
use domain\Product\Product\Product;

class ProductAccessoryBuilder extends AbstractBuilder
{
public function instanciateProductAccessory(): ProductAccessory
{
$productAccessory = new ProductAccessory();
return $productAccessory;
}
}

+ 13
- 0
domain/Product/ProductAccessory/ProductAccessoryDefinition.php Целия файл

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

namespace domain\Product\ProductAccessory;

use domain\_\AbstractDefinition;

class ProductAccessoryDefinition extends AbstractDefinition
{
public function getEntityFqcn(): string
{
return ProductAccessory::class;
}
}

+ 51
- 0
domain/Product/ProductAccessory/ProductAccessoryManager.php Целия файл

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

namespace domain\Product\ProductAccessory;

use domain\_\AbstractManager;
use domain\Product\Accessory\Accessory;
use domain\Product\Product\Product;

class ProductAccessoryManager extends AbstractManager
{
protected ProductAccessoryBuilder $productAccessoryBuilder;
protected ProductAccessoryRepository $productAccessoryRepository;

public function loadDependencies(): void
{
$this->productAccessoryBuilder = $this->loadService(ProductAccessoryBuilder::class);
$this->productAccessoryRepository = $this->loadService(ProductAccessoryRepository::class);
}

public function createProductAccessory(Product $product, Accessory $accessory, int $quantity): ProductAccessory
{
$productAccessory = $this->productAccessoryBuilder->instanciateProductAccessory();
$productAccessory->setProduct($product);
$productAccessory->setAccessory($accessory);
$productAccessory->setQuantity($quantity);
$productAccessory->save();
return $productAccessory;
}

public function createProductAccessoryIfNotExist(Product $product, Accessory $accessory, int $quantity): ProductAccessory
{
$productAccessory = $this->productAccessoryRepository->findOneProductAccessory($product, $accessory);
if($productAccessory) {
$productAccessory->setQuantity($quantity);
$productAccessory->save();
}
else {
$productAccessory = $this->createProductAccessory($product, $accessory, $quantity);
}

return $productAccessory;
}

public function deleteAllProductAccessoriesByAccessory(Accessory $accessory): void
{
$productAccessoriesArray = $this->productAccessoryRepository->findProductAccessoriesByAccessory($accessory);
foreach($productAccessoriesArray as $productAccessory) {
$productAccessory->delete();
}
}
}

+ 38
- 0
domain/Product/ProductAccessory/ProductAccessoryModule.php Целия файл

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

namespace domain\Product\ProductAccessory;

use domain\_\AbstractModule;

class ProductAccessoryModule extends AbstractModule
{
public function getServices(): array
{
return [
ProductAccessoryDefinition::class,
ProductAccessoryBuilder::class,
ProductAccessoryRepository::class,
ProductAccessoryManager::class,
];
}

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

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

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

public function getManager(): ProductAccessoryManager
{
return ProductAccessoryManager::getInstance();
}
}

+ 42
- 0
domain/Product/ProductAccessory/ProductAccessoryRepository.php Целия файл

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

namespace domain\Product\ProductAccessory;

use domain\_\AbstractRepository;
use domain\Product\Accessory\Accessory;
use domain\Product\Product\Product;

class ProductAccessoryRepository extends AbstractRepository
{
protected ProductAccessoryRepositoryQuery $query;

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

public function getDefaultOptionsSearch(): array
{
return [
self::WITH => [],
self::JOIN_WITH => ['accessoryRelation'],
self::ORDER_BY => 'accessory.name ASC',
self::ATTRIBUTE_ID_PRODUCER => ''
];
}

public function findOneProductAccessory(Product $product, Accessory $accessory): ?ProductAccessory
{
return $this->createDefaultQuery()
->filterByProduct($product)
->filterByAccessory($accessory)
->findOne();
}

public function findProductAccessoriesByAccessory(Accessory $accessory): array
{
return $this->createDefaultQuery()
->filterByAccessory($accessory)
->find();
}
}

+ 29
- 0
domain/Product/ProductAccessory/ProductAccessoryRepositoryQuery.php Целия файл

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

namespace domain\Product\ProductAccessory;

use domain\_\AbstractRepositoryQuery;
use domain\Product\Accessory\Accessory;
use domain\Product\Product\Product;

class ProductAccessoryRepositoryQuery extends AbstractRepositoryQuery
{
protected ProductAccessoryDefinition $definition;

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

public function filterByProduct(Product $product): self
{
$this->andWhere(['product_accessory.id_product' => $product->id]);
return $this;
}

public function filterByAccessory(Accessory $accessory): self
{
$this->andWhere(['product_accessory.id_accessory' => $accessory->id]);
return $this;
}
}

+ 1
- 1
domain/User/User/User.php Целия файл

@@ -118,7 +118,7 @@ class User extends ActiveRecordCommon implements IdentityInterface
['password_old', 'verifyPasswordOld'],
['password_new', 'verifyPasswordNew'],
['password_new_confirm', 'verifyPasswordNewConfirm'],
[['date_last_connection', 'password_old', 'password_new', 'password_new_confirm', 'password_hash', 'points_sale', 'product_price_percent', 'user_groups'], 'safe'],
[['date_last_connection', 'password_old', 'password_new', 'password_new_confirm', 'password_hash', 'points_sale', 'product_price_percent', 'user_groups', 'redirect_url'], 'safe'],
];
}


+ 70
- 14
domain/User/User/UserSolver.php Целия файл

@@ -2,11 +2,15 @@

namespace domain\User\User;

use domain\Payment\Payment;
use domain\Producer\Producer\ProducerSolver;
use domain\User\UserGroup\UserGroup;
use domain\User\UserProducer\UserProducer;
use domain\User\UserUserGroup\UserUserGroup;
use domain\_\AbstractService;
use domain\_\SolverInterface;
use Faker\Factory;
use yii\base\ErrorException;

class UserSolver extends AbstractService implements SolverInterface
{
@@ -79,15 +83,62 @@ class UserSolver extends AbstractService implements SolverInterface
return $html;
}

public function getUsername(User $user, $withType = false): string
// getStrUserAction
public function getPaymentUsernameUserAction(Payment $payment): string
{
if ($this->isTypeLegalPerson($user)
&& isset($user->name_legal_person)
&& strlen($user->name_legal_person)) {
$userAction = $payment->getUserActionObject();

$username = $user->name_legal_person;
if ($userAction) {
return $this->getUsername($userAction);
} else {
$username = $user->lastname . ' ' . $user->name;
return 'Système';
}
}

public function getPhone(User $user)
{
if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
return \Yii::$app->faker->phoneNumber();
}

return $user->phone;
}

public function getEmail(User $user)
{
if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
return \Yii::$app->faker->email();
}

return $user->email;
}

public function getAddress(User $user): string
{
if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
return \Yii::$app->faker->address();
}

return $user->address;
}

/**
* @throws ErrorException
*/
public function getUsername(User $user, $withType = false): string
{
if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
$username = \Yii::$app->faker->name();
}
else {
if ($this->isTypeLegalPerson($user)
&& isset($user->name_legal_person)
&& strlen($user->name_legal_person)) {

$username = $user->name_legal_person;
} else {
$username = $user->lastname . ' ' . $user->name;
}
}

if ($withType && $this->isTypeLegalPerson($user)) {
@@ -99,14 +150,19 @@ class UserSolver extends AbstractService implements SolverInterface

public function getUsernameFromArray(array $modelArray, $withType = false): string
{
$username = 'Nom indéfini';
if ($modelArray['type'] == User::TYPE_LEGAL_PERSON
&& isset($modelArray['name_legal_person'])
&& strlen($modelArray['name_legal_person'])) {
$username = $modelArray['name_legal_person'];
} elseif((isset($modelArray['lastname']) && $modelArray['lastname'])
|| (isset($modelArray['name']) && $modelArray['name'])) {
$username = $modelArray['lastname'] . ' ' . $modelArray['name'];
if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
$username = \Yii::$app->faker->name();
}
else {
$username = 'Nom indéfini';
if ($modelArray['type'] == User::TYPE_LEGAL_PERSON
&& isset($modelArray['name_legal_person'])
&& strlen($modelArray['name_legal_person'])) {
$username = $modelArray['name_legal_person'];
} elseif((isset($modelArray['lastname']) && $modelArray['lastname'])
|| (isset($modelArray['name']) && $modelArray['name'])) {
$username = $modelArray['lastname'] . ' ' . $modelArray['name'];
}
}

if ($withType && $modelArray['type'] == User::TYPE_LEGAL_PERSON) {

+ 1
- 1
frontend/views/site/producer.php Целия файл

@@ -72,7 +72,7 @@ $this->setMeta('description', 'Connectez-vous pour passer commande auprès du pr
<h2 class="panel-title">Connexion</h2>
</div>
<div class="panel-body">
<?php if(isset($producer) && $producerModule->isDemo($producer)) : ?>
<?php if(isset($producer) && $producer->isDemoAccount()) : ?>
<div class="alert alert-warning">
<p>Merci d'utiliser les identifiants suivants pour vous connecter à l'espace de démonstration :</p>
Identifiant : <strong>demo@souke.fr</strong><br>

+ 1
- 1
frontend/views/site/service.php Целия файл

@@ -85,7 +85,7 @@ $this->setMeta('description', "Découvrez les fonctionnalités du logiciel, les
</div>
<div class="row">
<?= block_feature("graph-up", "Statistiques et rapports de vente"); ?>
<?= block_feature("cloud-arrow-up", "Exports vers les logiciels <strong>Evoliz</strong> (comptabilité) et <strong>Tiller</strong> (caisse)"); ?>
<?= block_feature("cloud-arrow-up", "Exports vers les logiciels <strong>Evoliz</strong> (comptabilité) et <strong>SumUp</strong> (caisse)"); ?>
</div>
</div>
</div>

+ 1
- 1
producer/views/order/confirm.php Целия файл

@@ -85,7 +85,7 @@ $this->setPageTitle('Confirmation de commande');
<?php if($pointsSaleSharedWithPointSaleArray && count($pointsSaleSharedWithPointSaleArray)): ?>
<div class="alert alert-info">
<h4 class="alert-heading">
<i class="bi bi-share"></i>
<i class="bi bi-shop"></i>
Commander chez d'autres producteurs présents à cette distribution<br />
</h4>
<?php foreach($pointsSaleSharedWithPointSaleArray as $pointSaleSharedWithPointSale): ?>

Loading…
Отказ
Запис