Explorar el Código

Merge branch 'develop'

master
Guillaume Bourgeois hace 1 año
padre
commit
5e8458554c
Se han modificado 95 ficheros con 2754 adiciones y 1355 borrados
  1. +1
    -1
      backend/controllers/CommunicateController.php
  2. +61
    -240
      backend/controllers/DistributionController.php
  3. +5
    -5
      backend/controllers/OrderController.php
  4. +16
    -1
      backend/controllers/ProducerAdminController.php
  5. +9
    -3
      backend/controllers/UserController.php
  6. +11
    -1
      backend/models/MailForm.php
  7. +8
    -13
      backend/views/development/index.php
  8. +19
    -22
      backend/views/distribution/index.php
  9. +0
    -257
      backend/views/distribution/report.php
  10. +14
    -6
      backend/views/layouts/header.php
  11. +4
    -4
      backend/views/order/report.php
  12. +3
    -0
      backend/views/producer-admin/_form.php
  13. +11
    -1
      backend/views/producer-admin/index.php
  14. +1
    -0
      backend/views/producer-price-range-admin/create.php
  15. +3
    -2
      backend/views/producer-price-range-admin/update.php
  16. +20
    -5
      backend/views/producer/update.php
  17. +16
    -4
      backend/views/support/index.php
  18. +9
    -0
      backend/views/support/view.php
  19. +1
    -0
      backend/views/user/_form.php
  20. +17
    -0
      backend/views/user/index.php
  21. +71
    -43
      backend/web/css/screen.css
  22. +34
    -0
      backend/web/js/backend.js
  23. +587
    -555
      backend/web/js/vuejs/distribution-index.js
  24. +12
    -1
      backend/web/js/vuejs/producer-update.js
  25. +21
    -0
      backend/web/sass/_adminlte.scss
  26. +1
    -1
      backend/web/sass/screen.scss
  27. +8
    -1
      backend/web/sass/support/_index.scss
  28. +62
    -0
      common/components/AbstractApi.php
  29. +6
    -0
      common/components/BusinessLogicTrait.php
  30. +51
    -0
      common/components/DolibarrApi.php
  31. +4
    -1
      common/components/MailerService.php
  32. +11
    -0
      common/config/main.php
  33. +45
    -0
      common/helpers/Ajax.php
  34. +8
    -0
      common/logic/AbstractUtils.php
  35. +1
    -1
      common/logic/ContainerInterface.php
  36. +6
    -1
      common/logic/Distribution/Distribution/Service/DistributionBuilder.php
  37. +1
    -8
      common/logic/Distribution/Distribution/Service/DistributionReportGridPdfGenerator.php
  38. +293
    -23
      common/logic/Distribution/Distribution/Service/DistributionReportPdfGenerator.php
  39. +12
    -0
      common/logic/Document/DeliveryNote/Event/DeliveryNoteCreateEvent.php
  40. +2
    -0
      common/logic/Document/DeliveryNote/Model/DeliveryNote.php
  41. +26
    -0
      common/logic/Document/DeliveryNote/Repository/DeliveryNoteRepository.php
  42. +108
    -0
      common/logic/Document/DeliveryNote/Service/DeliveryNoteBuilder.php
  43. +13
    -0
      common/logic/Document/Document/Service/DocumentBuilder.php
  44. +30
    -0
      common/logic/Opinion/Service/OpinionUtils.php
  45. +16
    -0
      common/logic/Opinion/Wrapper/OpinionContainer.php
  46. +17
    -0
      common/logic/Opinion/Wrapper/OpinionManager.php
  47. +24
    -0
      common/logic/Order/Order/Event/DeliveryNoteObserver.php
  48. +57
    -4
      common/logic/Order/Order/Service/OrderBuilder.php
  49. +24
    -4
      common/logic/Order/Order/Service/OrderSolver.php
  50. +10
    -2
      common/logic/Producer/Producer/Model/Producer.php
  51. +7
    -1
      common/logic/Producer/Producer/Repository/ProducerRepository.php
  52. +52
    -0
      common/logic/Producer/Producer/Service/DolibarrProducerUtils.php
  53. +4
    -4
      common/logic/Producer/Producer/Service/ProducerBuilder.php
  54. +3
    -1
      common/logic/Producer/Producer/Wrapper/ProducerContainer.php
  55. +2
    -0
      common/logic/Producer/Producer/Wrapper/ProducerManager.php
  56. +2
    -0
      common/logic/Producer/ProducerPriceRange/Model/ProducerPriceRange.php
  57. +12
    -0
      common/logic/Producer/ProducerPriceRange/Repository/ProducerPriceRangeRepository.php
  58. +1
    -1
      common/logic/Ticket/Ticket/Service/TicketSolver.php
  59. +2
    -2
      common/logic/User/CreditHistory/Service/CreditHistorySolver.php
  60. +4
    -2
      common/logic/User/User/Model/User.php
  61. +11
    -9
      common/logic/User/User/Model/UserSearch.php
  62. +1
    -1
      common/logic/User/User/Repository/UserRepository.php
  63. +49
    -0
      common/logic/User/User/Service/NewsletterUtils.php
  64. +5
    -0
      common/logic/User/User/Service/UserSolver.php
  65. +1
    -1
      common/logic/User/User/Service/UsersCreditCsvGenerator.php
  66. +2
    -0
      common/logic/User/User/Wrapper/UserContainer.php
  67. +2
    -0
      common/logic/User/User/Wrapper/UserManager.php
  68. +8
    -1
      common/logic/User/UserProducer/Model/UserProducer.php
  69. +13
    -6
      common/logic/User/UserProducer/Service/UserProducerBuilder.php
  70. +1
    -1
      common/logic/UtilsInterface.php
  71. +49
    -0
      common/mail/newOpinionAdmin-html.php
  72. +47
    -0
      common/mail/newOpinionAdmin-text.php
  73. +33
    -0
      common/versions/23.9.B.php
  74. +3
    -1
      composer.json
  75. +28
    -0
      console/commands/ActiveDistributionsInAdvanceController.php
  76. +27
    -0
      console/migrations/m230904_064216_add_column_user_producer_newsletter.php
  77. +30
    -0
      console/migrations/m230905_091112_add_columns_dolibarr.php
  78. +26
    -0
      console/migrations/m230906_060202_add_column_producer_option_export_display_column_delivery_note.php
  79. +26
    -0
      console/migrations/m230908_085432_add_column_producer_option_weeks_distributions_activated_in_advance.php
  80. +27
    -14
      frontend/controllers/SiteController.php
  81. +87
    -0
      frontend/forms/OpinionForm.php
  82. +4
    -2
      frontend/forms/SignupForm.php
  83. +1
    -0
      frontend/views/layouts/main.php
  84. +27
    -21
      frontend/views/site/contact.php
  85. +87
    -0
      frontend/views/site/opinion.php
  86. +1
    -0
      frontend/views/site/producer.php
  87. +3
    -1
      frontend/views/site/signup.php
  88. +17
    -3
      frontend/web/css/screen.css
  89. +14
    -0
      frontend/web/js/frontend.js
  90. +16
    -1
      frontend/web/sass/screen.scss
  91. +75
    -0
      producer/controllers/NewsletterController.php
  92. +8
    -6
      producer/views/layouts/main.php
  93. +71
    -0
      producer/views/newsletter/index.php
  94. +71
    -66
      producer/web/css/screen.css
  95. +4
    -0
      producer/web/sass/_layout.scss

+ 1
- 1
backend/controllers/CommunicateController.php Ver fichero

@@ -73,7 +73,7 @@ class CommunicateController extends BackendController
}

/**
* Affiche la page d'accueil de la section avec un aperçu du mpde d'emploi
* Affiche la page d'accueil de la section avec un aperçu du mode d'emploi
* à imprimer.
*/
public function actionIndex()

+ 61
- 240
backend/controllers/DistributionController.php Ver fichero

@@ -38,6 +38,7 @@

namespace backend\controllers;

use common\helpers\Ajax;
use common\helpers\CSV;
use common\helpers\GlobalParam;
use common\helpers\MeanPayment;
@@ -598,7 +599,7 @@ class DistributionController extends BackendController
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$productDistributionManager = $this->getProductDistributionManager();
$productDistribution = $this->getProductDistribution($idProduct, $idDistribution);
$productDistributionManager->updateProductDistributionQuantityMax($productDistribution, $quantityMax);
$productDistributionManager->updateProductDistributionQuantityMax($productDistribution, (float) $quantityMax);
return ['success'];
}

@@ -758,9 +759,13 @@ class DistributionController extends BackendController
*/
public function actionAjaxProcessAddSubscriptions($date)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$this->getOrderManager()->createAllOrdersFromSubscriptions($date, true);
return ['success'];
$ordersArray = $this->getOrderManager()->createAllOrdersFromSubscriptions($date, true);

if($ordersArray && count($ordersArray)) {
return Ajax::responseSuccess('Les abonnements ont bien été importés.');
}

return Ajax::responseError('Aucun abonnement à importer.');
}

/**
@@ -857,286 +862,102 @@ class DistributionController extends BackendController
return $return;
}

public function actionAjaxValidateDeliveryNotes($idOrders)
public function actionAjaxGenerateDeliveryNote(int $idOrder)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$this->generateDeliveryNote($idOrder);
return Ajax::responseSuccess('Bon de livraison généré');
}

public function actionAjaxGenerateDeliveryNotePointSale($idOrders)
{
$orderManager = $this->getOrderManager();
$deliveryNoteManager = $this->getDeliveryNoteManager();

if (strlen($idOrders)) {
$idOrders = json_decode($idOrders, true);

if (is_array($idOrders) && count($idOrders) > 0) {
foreach ($idOrders as $idOrder) {
$order = Order::searchOne([
'id' => (int)$idOrder
]);
reset($idOrders);
$firstOrder = $orderManager->findOneOrderById((int)$idOrders[key($idOrders)]);
$ordersArray = Order::searchAll(['id' => $idOrders,]);
$deliveryNote = $deliveryNoteManager->getOneDeliveryNoteExistingFromOrders($ordersArray);
$isUpdate = (bool) $deliveryNote;

if ($order && $order->distribution->id_producer == GlobalParam::getCurrentProducerId()) {
$deliveryNote = DeliveryNote::searchOne([
'id' => (int)$order->id_delivery_note
]);
if ($deliveryNote && $deliveryNoteManager->isStatusValid($deliveryNote)) {
return Ajax::responseError('Vous ne pouvez pas modifier un bon de livraison déjà validé.');
}

if ($deliveryNote && $deliveryNoteManager->isStatusDraft($deliveryNote)) {
$deliveryNoteManager->changeStatus($deliveryNote, Document::STATUS_VALID);
$deliveryNoteManager->saveUpdate($deliveryNote);
}
}
if(!$deliveryNote && $firstOrder && !$firstOrder->pointSale->id_user) {
return Ajax::responseError("Vous devez définir un contact de facturation pour ce point de vente.");
}

return [
'return' => 'success',
'alert' => [
'type' => 'success',
'message' => 'Bon(s) de livraison validé(s)'
]
];
if ($firstOrder) {
if (!$deliveryNote) {
$deliveryNoteManager->createDeliveryNoteForPointSale(
$firstOrder->pointSale,
$firstOrder->distribution,
$idOrders
);
}

return Ajax::responseSuccess('Bon de livraison ' . ($isUpdate ? 'modifié' : 'généré'));
}
}
}

return [
'return' => 'error',
'alert' => [
'type' => 'danger',
'message' => 'Une erreur est survenue lors de la validation des bons de livraison'
]
];
return Ajax::responseError('Une erreur est survenue lors de la génération du bon de livraison.');
}

public function actionAjaxGenerateDeliveryNoteEachUser($idOrders)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

$userManager = $this->getUserManager();
$userProducerManager = $this->getUserProducerManager();
$orderManager = $this->getOrderManager();
$deliveryNoteManager = $this->getDeliveryNoteManager();

$producerCurrent = $this->getProducerCurrent();


if (strlen($idOrders)) {
$idOrders = json_decode($idOrders, true);

if (is_array($idOrders) && count($idOrders) > 0) {
foreach ($idOrders as $idOrder) {
$order = Order::searchOne([
'id' => (int)$idOrder
]);

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

$deliveryNote = null;
$idDeliveryNote = $order->id_delivery_note;
if ($idDeliveryNote) {
$deliveryNote = DeliveryNote::searchOne([
'id' => (int)$idDeliveryNote
]);
}

// on regénére le document si c'est un brouillon
if ($deliveryNote && $deliveryNoteManager->isStatusDraft($deliveryNote)) {
$deliveryNote->delete();
$deliveryNote = null;
}

if (!$deliveryNote) {
$deliveryNote = new DeliveryNote();
$deliveryNoteManager->initTaxCalculationMethod($deliveryNote);
$deliveryNote->id_producer = GlobalParam::getCurrentProducerId();
$deliveryNote->id_user = $order->id_user;
$deliveryNote->name = 'Bon de livraison ' . $orderManager->getOrderUsername($order) . ' (' . date(
'd/m/Y',
strtotime(
$order->distribution->date
)
) . ')';
$deliveryNote->address = $userManager->getFullAddress($order->user);
$deliveryNote->save();
}

if ($deliveryNote) {
$order->id_delivery_note = $deliveryNote->id;
$order->save();

// init invoice prices
$user = $userManager->findOneUserById($deliveryNote->id_user);
$userProducer = $userProducerManager->findOneUserProducer($user);
$orderManager->updateOrderInvoicePrices($order, [
'user' => $user,
'user_producer' => $userProducer,
'point_sale' => $order->pointSale
]);
}
}
$this->generateDeliveryNote($idOrder);
}
}

return [
'return' => 'success',
'alert' => [
'type' => 'success',
'message' => 'Bon(s) de livraison généré(s)'
]
];
return Ajax::responseSuccess('Bon(s) de livraison généré(s)');
}

return [
'return' => 'error',
'alert' => [
'type' => 'danger',
'message' => 'Une erreur est survenue lors de la génération du bon de livraison.'
]
];
return Ajax::responseError('Une erreur est survenue lors de la génération du bon de livraison.');
}

public function actionAjaxGenerateDeliveryNote($idOrders)
public function generateDeliveryNote(int $idOrder)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

$userManager = $this->getUserManager();
$userProducerManager = $this->getUserProducerManager();
$orderManager = $this->getOrderManager();
$deliveryNoteManager = $this->getDeliveryNoteManager();

$producerCurrent = $this->getProducerCurrent();
$order = $orderManager->findOneOrderById($idOrder);
if ($orderManager->isOrderFromProducer($order) && $order->id_user) {
$deliveryNoteManager->createDeliveryNoteForOrder($order);
}
}

public function actionAjaxValidateDeliveryNotes($idOrders)
{
$orderManager = $this->getOrderManager();
$deliveryNoteManager = $this->getDeliveryNoteManager();

if (strlen($idOrders)) {
$idOrders = json_decode($idOrders, true);

if (is_array($idOrders) && count($idOrders) > 0) {
// récupération première commande pour obtenir des infos
reset($idOrders);
$firstOrder = Order::searchOne([
'id' => (int)$idOrders[key($idOrders)]
]);

// deliveryNote existant
$deliveryNote = null;
$isUpdate = false;
$i = 0;
$ordersArray = Order::searchAll([
'id' => $idOrders,
]);
do {
$order = $ordersArray[$i];
if ($order->distribution->id_producer == GlobalParam::getCurrentProducerId() && $order->id_delivery_note > 0) {
$deliveryNote = DeliveryNote::searchOne([
'id' => $order->id_delivery_note
]);
$isUpdate = true;
}
$i++;
} while ($deliveryNote == null && isset($ordersArray[$i]));

if ($deliveryNote && $deliveryNote->status == Document::STATUS_VALID) {
return [
'return' => 'error',
'alert' => [
'type' => 'danger',
'message' => 'Vous ne pouvez pas modifier un bon de livraison déjà validé.'
]
];
}

if ($firstOrder) {
// génération du BL
if (!$deliveryNote) {
$deliveryNote = new DeliveryNote;
$deliveryNoteManager->initTaxCalculationMethod($deliveryNote);
$deliveryNote->name = 'Bon de livraison ' . $firstOrder->pointSale->name . ' (' . date(
'd/m/Y',
strtotime(
$firstOrder->distribution->date
)
) . ')';
$deliveryNote->id_producer = GlobalParam::getCurrentProducerId();

if ($firstOrder->pointSale->id_user) {
$deliveryNote->id_user = $firstOrder->pointSale->id_user;
$user = $userManager->findOneUserById($deliveryNote->id_user);
$userProducer = $userProducerManager->findOneUserProducer($user);
} else {
$user = new User();
$user->type = User::TYPE_LEGAL_PERSON;
$user->name_legal_person = $firstOrder->pointSale->name;
$user->address = $firstOrder->pointSale->address;
$user->id_producer = 0;
$userManager->setPassword($user, Password::generate());
$userManager->generateAuthKey($user);
$user->email = '';
if (!strlen($user->email)) {
$user->username = 'inconnu@opendistrib.net';
}
$user->save();

$userProducer = new UserProducer();
$userProducer->id_user = $user->id;
$userProducer->id_producer = GlobalParam::getCurrentProducerId();
$userProducer->credit = 0;
$userProducer->active = 1;
$userProducer->save();

$firstOrder->pointSale->id_user = $user->id;
$firstOrder->pointSale->save();

$deliveryNote->id_user = $user->id;
}

$deliveryNote->address = $userManager->getFullAddress($user);
$deliveryNote->save();
} else {
// réinitialisation des order.id_delivery_note
Order::updateAll([
'id_delivery_note' => null
], [
'id_delivery_note' => $deliveryNote->id
]);
}

if (!isset($user) || !$user) {
$user = $userManager->findOneUserById($deliveryNote->id_user);
$userProducer = $userProducerManager->findOneUserProducer($user);
}

// affectation du BL aux commandes
foreach ($idOrders as $idOrder) {
$order = $orderManager->findOneOrderById((int)$idOrder);
if ($order && $order->distribution->id_producer == GlobalParam::getCurrentProducerId()) {
$order->id_delivery_note = $deliveryNote->id;
$order->save();
}

// init invoice price
$order = $orderManager->findOneOrderById((int)$idOrder);
if ($order) {
$orderManager->updateOrderInvoicePrices($order,
[
'user' => $user,
'user_producer' => $userProducer,
'point_sale' => $firstOrder->pointSale
]);
foreach ($idOrders as $idOrder) {
$order = $orderManager->findOneOrderById($idOrder);
if ($orderManager->isOrderFromProducer($order)) {
$deliveryNote = $deliveryNoteManager->findOneDeliveryNoteById((int) $order->id_delivery_note);
if($deliveryNote) {
$deliveryNoteManager->validateDocument($deliveryNote);
}
}

return [
'return' => 'success',
'alert' => [
'type' => 'success',
'message' => 'Bon de livraison ' . ($isUpdate ? 'modifié' : 'généré')
]
];
}

return Ajax::responseSuccess('Bon(s) de livraison validé(s)');
}
}

return [
'return' => 'error',
'alert' => [
'type' => 'danger',
'message' => 'Une erreur est survenue lors de la génération du bon de livraison.'
]
];
return Ajax::responseError('Une erreur est survenue lors de la validation des bons de livraison');
}

}

+ 5
- 5
backend/controllers/OrderController.php Ver fichero

@@ -1035,15 +1035,15 @@ class OrderController extends BackendController

if (abs($order->amount - $amountPaid) < 0.0001) {
$html .= '<span class="label label-success">Payé</span>';
$buttonsCredit = Html::a('Rembourser ' . $orderManager->getOrderAmountWithTax($order, Order::AMOUNT_TOTAL, true), 'javascript:void(0);', ['class' => 'btn btn-default btn-xs rembourser', 'data-montant' => $order->amount, 'data-type' => 'refund']);
$buttonsCredit = Html::a('Recréditer ' . $orderManager->getOrderAmountWithTax($order, Order::AMOUNT_TOTAL, true), 'javascript:void(0);', ['class' => 'btn btn-default btn-xs rembourser', 'data-montant' => $order->amount, 'data-type' => 'refund']);
} elseif ($order->amount > $amountPaid) {
$amountToPay = $order->amount - $amountPaid;
$html .= '<span class="label label-danger">Non payé</span> reste <strong>' . number_format($amountToPay, 2) . ' €</strong> à payer';
$buttonsCredit = Html::a('Payer ' . number_format($amountToPay, 2) . ' €', 'javascript:void(0);', ['class' => 'btn btn-default btn-xs payer', 'data-montant' => $amountToPay, 'data-type' => 'payment']);
$html .= '<span class="label label-danger">Non payé</span> reste <strong>' . number_format($amountToPay, 2) . ' €</strong> à débiter';
$buttonsCredit = Html::a('Débiter ' . number_format($amountToPay, 2) . ' €', 'javascript:void(0);', ['class' => 'btn btn-default btn-xs payer', 'data-montant' => $amountToPay, 'data-type' => 'payment']);
} elseif ($order->amount < $amountPaid) {
$amountToRefund = $amountPaid - $order->amount;
$html .= ' <span class="label label-success">Payé</span> <strong>' . number_format($amountToRefund, 2) . ' €</strong> à rembourser';
$buttonsCredit = Html::a('Rembourser ' . number_format($amountToRefund, 2) . ' €', 'javascript:void(0);', ['class' => 'btn btn-default btn-xs rembourser', 'data-montant' => $amountToRefund, 'data-type' => 'refund']);
$html .= ' <span class="label label-success">Payé</span> <strong>' . number_format($amountToRefund, 2) . ' €</strong> à recréditer';
$buttonsCredit = Html::a('Recréditer ' . number_format($amountToRefund, 2) . ' €', 'javascript:void(0);', ['class' => 'btn btn-default btn-xs rembourser', 'data-montant' => $amountToRefund, 'data-type' => 'refund']);
}

$html .= '<span class="buttons-credit">'

+ 16
- 1
backend/controllers/ProducerAdminController.php Ver fichero

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

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

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

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


+ 9
- 3
backend/controllers/UserController.php Ver fichero

@@ -157,6 +157,7 @@ class UserController extends BackendController
$useProducer->id_producer = GlobalParam::getCurrentProducerId();
$useProducer->credit = 0;
$useProducer->active = 1;
$useProducer->newsletter = $model->newsletter;
$useProducer->save();

$userManager->sendMailWelcome($model, $password);
@@ -178,16 +179,14 @@ class UserController extends BackendController
public function actionUpdate($id)
{
$userManager = $this->getUserManager();
$producerManager = $this->getProducerManager();
$pointSaleManager = $this->getPointSaleManager();

$model = $this->findModel($id);

// Moodification du profil
$previousMail = $model->email;
$user = User::find()->with('userProducer')->where(['id' => $model['id']])->one();
$userBelongToProducer = UserProducer::findOne(['id_user' => $id, 'id_producer' => GlobalParam::getCurrentProducerId()]);
if ($userBelongToProducer) {
$model->newsletter = $userBelongToProducer->newsletter;
if ($model->load(\Yii::$app->request->post()) && $model->save()) {

// on envoie le mail de bienvenue si le mail vient d'être défini
@@ -201,6 +200,13 @@ class UserController extends BackendController
$this->processLinkUserGroup($model);
$this->processProductPricePercent($model);

if($model->newsletter) {
$userManager->subscribeUserNewsletter($model);
}
else {
$userManager->unsubscribeUserNewsletter($model);
}

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

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

+ 11
- 1
backend/models/MailForm.php Ver fichero

@@ -163,11 +163,21 @@ Produits disponibles :
}
}
}
if($fromProducer) {
$producer = GlobalParam::getCurrentProducer() ;
$fromEmail = $producerManager->getEmailOpendistrib($producer) ;
$fromName = $producer->name ;

// Message inscription newsletter
$messageAutoText .= "

--

Me désinscrire de ce bulletin d'information :
".Yii::$app->urlManagerProducer->createAbsoluteUrl(['newsletter/index', 'slug_producer' => $producer->slug]);

$messageAutoHtml .= "<br /><br />--<br /><br /><a href=\"".Yii::$app->urlManagerProducer->createAbsoluteUrl(['newsletter/unsubscribe', 'slug_producer' => $producer->slug])."\">Me désinscrire</a> de ce bulletin d'information";
}
else {
$fromEmail = 'contact@opendistrib.net' ;

+ 8
- 13
backend/views/development/index.php Ver fichero

@@ -74,19 +74,14 @@ $this->addBreadcrumb($this->getTitle());
<h3 class="panel-title">Participer</h3>
</div>
<div class="panel-body">
<p>Le logiciel Opendistrib se construit pour et avec vous. Toutes vos suggestions et remontées
de bugs sont les bienvenues et forment le terreau des versions futures !</p>
<p>Pour me contacter :</p>
<ul class="contacts">
<li>
<span class="glyphicon glyphicon-earphone"></span>
<p><?= Html::a('Prendre rendez-vous', Yii::$app->parameterBag->get('appointmentUrl'), ['class' => '', 'target' => '_blank']); ?></p>
</li>
<li>
<span class="glyphicon glyphicon-envelope"></span>
<p><a href="mailto:contact@opendistrib.net">M'envoyer un message</a></p>
</li>
</ul>
<p>Le logiciel Opendistrib se construit pour et avec vous. Toutes vos remarques, suggestions et remontées
de bugs sont les bienvenues et forment le terreau des versions futures.</p>
<p>
<a class="btn btn-default" href="<?= $this->getUrlManagerBackend()->createUrl(['support/index']); ?>">
<span class="glyphicon glyphicon-comment"></span>
Me contacter
</a>
</p>
</div>
</div>
</div>

+ 19
- 22
backend/views/distribution/index.php Ver fichero

@@ -276,7 +276,7 @@ $this->setPageTitle('Distributions') ;
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a v-if="idActivePointSale > 0" @click="generateDeliveryNote" href="javascript:void(0);" >Générer un bon de livraison pour ce point de vente</a></li>
<li><a v-if="idActivePointSale > 0" @click="generateDeliveryNotePointSale" href="javascript:void(0);" >Générer un bon de livraison pour ce point de vente</a></li>
<li><a @click="generateDeliveryNoteEachUser" href="javascript:void(0);">Générer un bon de livraison pour chaque client</a></li>
<li><a @click="validateDeliveryNotes" href="javascript:void(0);">Valider les bons de livraisons</a></li>
</ul>
@@ -286,7 +286,7 @@ $this->setPageTitle('Distributions') ;
<button v-if="tillerIsSynchro" id="btn-tiller" class="btn btn-success btn-xs" disabled><span class="glyphicon glyphicon-refresh"></span> Synchronisé avec Tiller</button>
<button v-else id="btn-tiller" class="btn btn-xs btn-default" @click="synchroTiller"><span class="glyphicon glyphicon-refresh"></span> Synchroniser avec Tiller</button>
</template>
<button v-if="producer && producer.credit" id="btn-pay-orders" class="btn btn-default btn-xs" @click="payOrders"><span class="glyphicon glyphicon-euro"></span> Payer les commandes</button>
<button v-if="producer && producer.credit" id="btn-pay-orders" class="btn btn-default btn-xs" @click="payOrders"><span class="glyphicon glyphicon-euro"></span> Débiter les commandes</button>
<button id="btn-add-order" @click="openModalFormOrderCreate" class="btn btn-xs btn-primary"><span class="glyphicon glyphicon-plus"></span> Ajouter une commande</button>
</div>
<div class="left">
@@ -303,7 +303,6 @@ $this->setPageTitle('Distributions') ;
</div>

<div class="alert alert-danger" v-if="distribution && !distribution.active && orders && orders.length > 0">
{{ distribution }}
Attention, ce jour de distribution n'est pas activé et vous avez quand même des commandes enregistrées.
</div>

@@ -323,7 +322,7 @@ $this->setPageTitle('Distributions') ;
<th class="column-user">Utilisateur</th>
<th class="column-point-sale" v-if="idActivePointSale == 0">Point de vente</th>
<th class="column-amount">Montant</th>
<th class="column-state-payment">Paiement</th>
<th class="column-state-payment">Crédit</th>
<th class="column-payment"></th>
<th class="column-tiller" v-if="producer && producer.tiller">Tiller</th>
<th class="column-actions"></th>
@@ -382,16 +381,16 @@ $this->setPageTitle('Distributions') ;
<td class="column-payment" v-if="producer && producer.credit">
<div class="btn-group" v-if="order.user && !order.date_delete">
<button class="btn btn-xs btn-default" v-if="order.amount_paid == order.amount" @click="orderPaymentClick" :data-id-order="order.id" data-type="refund" :data-amount="order.amount">
<span class="glyphicon glyphicon-euro"></span> Rembourser
<span class="glyphicon glyphicon-euro"></span> Recréditer
</button>
<button class="btn btn-xs btn-default" v-else-if="order.amount_paid == 0" @click="orderPaymentClick" :data-id-order="order.id" data-type="payment" :data-amount="order.amount">
<span class="glyphicon glyphicon-euro"></span> Payer
<span class="glyphicon glyphicon-euro"></span> Débiter
</button>
<button class="btn btn-xs btn-default" v-else-if="order.amount_paid < order.amount" @click="orderPaymentClick" :data-id-order="order.id" data-type="payment" :data-amount="order.amount_remaining">
<span class="glyphicon glyphicon-euro"></span> Payer
<span class="glyphicon glyphicon-euro"></span> Débiter
</button>
<button class="btn btn-xs btn-default" v-else-if="order.amount_paid > order.amount" @click="orderPaymentClick" :data-id-order="order.id" data-type="refund" :data-amount="order.amount_surplus">
<span class="glyphicon glyphicon-euro"></span> Rembourser
<span class="glyphicon glyphicon-euro"></span> Recréditer
</button>

<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@@ -418,6 +417,7 @@ $this->setPageTitle('Distributions') ;
<li><a href="javascript:void(0);" class="" :data-id-order="order.id" @click="orderViewClick"><span :class="'glyphicon ' + ((showViewProduct && idOrderView == order.id) ? 'glyphicon-eye-close' : 'glyphicon-eye-open')"></span> Voir</a></li>
<li><a href="javascript:void(0);" class="" :data-id-order="order.id" @click="updateOrderClick"><span class="glyphicon glyphicon-pencil"></span> Modifier</a></li>
<li><a href="javascript:void(0);" class="" :data-id-order="order.id" @click="deleteOrderClick"><span class="glyphicon glyphicon-trash"></span> Supprimer</a></li>
<li><a href="javascript:void(0);" class="" :data-id-order="order.id" @click="generateDeliveryNote"><span class="glyphicon glyphicon-file"></span> Générer un bon de livraison</a></li>
<li v-if="order.id_subscription > 0"><a class="" :href="baseUrl+'/subscription/update?id='+order.id_subscription"><span class="glyphicon glyphicon-repeat"></span> Modifier l'abonnement associé</a></li>
<li v-else><a class="add-subscription" :href="baseUrl+'/subscription/create?idOrder='+order.id"><span class="glyphicon glyphicon-plus"></span><span class="glyphicon glyphicon-repeat"></span>Créer un abonnement sur cette base</a></li>
</ul>
@@ -455,10 +455,10 @@ $this->setPageTitle('Distributions') ;
<span class="info-box-number">{{ order.amount.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}</span>
<span class="info-box-text">
Statut<br />
<span class="label label-success" v-if="order.amount_paid == order.amount">payé</span>
<span class="label label-default" v-else-if="order.amount_paid == 0">non réglé</span>
<span class="label label-success" v-if="order.amount_paid == order.amount">débité</span>
<span class="label label-default" v-else-if="order.amount_paid == 0">non débité</span>
<span class="label label-default" v-else-if="order.amount_paid > order.amount">surplus</span>
<span class="label label-warning" v-else-if="order.amount_paid < order.amount">reste à payer</span>
<span class="label label-warning" v-else-if="order.amount_paid < order.amount">reste à débiter</span>
</span>
</div>
</div>
@@ -477,7 +477,7 @@ $this->setPageTitle('Distributions') ;
data-type="refund"
@click="orderPaymentClick" >
<span class="glyphicon glyphicon-chevron-right"></span>
Rembourser {{ order.amount.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}
Recréditer {{ order.amount.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}
</button>

<button v-else-if="order.amount_paid == 0"
@@ -486,7 +486,7 @@ $this->setPageTitle('Distributions') ;
data-type="payment"
@click="orderPaymentClick">
<span class="glyphicon glyphicon-chevron-right"></span>
Payer {{ order.amount.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}
Débiter {{ order.amount.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}
</button>

<button v-else-if="order.amount_paid > order.amount"
@@ -495,7 +495,7 @@ $this->setPageTitle('Distributions') ;
data-type="refund"
@click="orderPaymentClick">
<span class="glyphicon glyphicon-chevron-right"></span>
Rembourser {{ order.amount_surplus.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}
Recréditer {{ order.amount_surplus.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}
</button>

<button v-else-if="order.amount_paid < order.amount"
@@ -504,7 +504,7 @@ $this->setPageTitle('Distributions') ;
data-type="payment"
@click="orderPaymentClick">
<span class="glyphicon glyphicon-chevron-right"></span>
Payer le restant {{ order.amount_remaining.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}
Débiter le restant {{ order.amount_remaining.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}
</button>
</div>

@@ -581,10 +581,10 @@ $this->setPageTitle('Distributions') ;

<script type="text/x-template" id="order-state-payment">
<div class="input-group">
<span class="label label-success input-group-addon" v-if="order.amount_paid == order.amount">payé</span>
<span class="label label-default input-group-addon" v-else-if="order.amount_paid == 0">non réglé</span>
<span class="label label-success input-group-addon" v-if="order.amount_paid == order.amount">débité</span>
<span class="label label-default input-group-addon" v-else-if="order.amount_paid == 0">non débité</span>
<span class="label label-default input-group-addon" v-else-if="order.amount_paid > order.amount">surplus</span>
<span class="label label-warning input-group-addon" v-else-if="order.amount_paid < order.amount">reste à payer</span>
<span class="label label-warning input-group-addon" v-else-if="order.amount_paid < order.amount">reste à débiter</span>

<span class="glyphicon glyphicon-time" title="Paiement automatique" v-if="order.auto_payment && producer && producer.credit && (order.amount_paid == 0 || order.amount_paid < order.amount)"></span>
</div>
@@ -700,9 +700,6 @@ $this->setPageTitle('Distributions') ;
</div>
<div slot="footer">
<div class="actions-form">
<!--<button class="modal-default-button btn btn-primary" @click="submitFormCreate" v-if="!order.id && order.id_user > 0" data-process-credit="1">Créer et payer</button>
<button class="modal-default-button btn btn-primary" @click="submitFormUpdate" v-if="order.id && order.id_user > 0" data-process-credit="1">Modifier et payer</button>-->

<button class="modal-default-button btn btn-primary" @click="submitFormUpdate" v-if="order.id">Modifier</button>
<button class="modal-default-button btn btn-primary" @click="submitFormCreate" v-if="!order.id">Créer</button>

@@ -729,7 +726,7 @@ $this->setPageTitle('Distributions') ;
<span class="label label-success input-group-addon" v-if="order.amount_paid == order.amount">payé</span>
<span class="label label-default input-group-addon" v-else-if="order.amount_paid == 0">non réglé</span>
<span class="label label-default input-group-addon" v-else-if="order.amount_paid > order.amount">surplus</span>
<span class="label label-warning input-group-addon" v-else-if="order.amount_paid < order.amount">reste à payer</span>
<span class="label label-warning input-group-addon" v-else-if="order.amount_paid < order.amount">reste à débiter</span>

<span class="glyphicon glyphicon-time" title="Paiement automatique" v-if="order.auto_payment && producer && producer.credit && (order.amount_paid == 0 || order.amount_paid < order.amount)"></span>
</div>

+ 0
- 257
backend/views/distribution/report.php Ver fichero

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

/**
Copyright distrib (2018)

contact@opendistrib.net

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

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

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

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

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


use common\helpers\Price;
use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Wrapper\OrderManager;
use common\logic\Producer\Producer\Model\Producer;
use common\logic\Product\Product\Model\Product;
use common\logic\Product\Product\Wrapper\ProductManager;
use common\logic\User\UserProducer\Model\UserProducer;

$productManager = ProductManager::getInstance();
$orderManager = OrderManager::getInstance();

$dayWeek = date('w', strtotime($date));
$dayWeekArray = [0 => 'sunday', 1 => 'monday', 2 => 'tuesday', 3 => 'wednesday', 4 => 'thursday', 5 => 'friday', 6 => 'saturday'];
$fieldInfosPointSale = 'infos_' . $dayWeekArray[$dayWeek];
$html = '' ;
$count = count($productsArray) ;
$limit = 100 ;
$isBig = $count > $limit ;

// par point de vente
foreach ($pointsSaleArray as $pointSale) {
if (count($pointSale->orders)) {
$html .= '<h3>'.$pointSale->name.'</h3>' ;
$colCredit = ($pointSale->credit) ? '<th>Rappel crédit</th>' : '' ;
$html .= '<table class="">'
. '<thead>'
. '<tr>'
. '<th>Client</th>'
. '<th>Produits</th>'
. ($isBig ? '<th>Produits</th>' : '')
. '<th>Commentaire</th>'
. $colCredit
. '<th>Montant</th>'
. '</tr>'
. '<tbody>';
foreach ($pointSale->orders as $order) {
$html .= '<tr>' ;
$strUser = '';

// username
$strUser .= $orderManager->getOrderUsername($order) ;
if(strlen($order->comment_point_sale))
{
$strUser .= '<br /><em>'.$order->comment_point_sale.'</em>' ;
}
// téléphone
if (isset($order->user) && strlen($order->user->phone)) {
$strUser .= '<br />' . $order->user->phone . '';
}

// référence
if($producer->option_order_reference_type == Producer::ORDER_REFERENCE_TYPE_YEARLY && $order->reference && strlen($order->reference) > 0) {
$strUser .= '<br />'.$order->reference ;
}

$html .= '<td>'.$strUser.'</td>';
// produits
$strProducts = '';
foreach ($productsArray as $product) {
$add = false;
foreach ($order->productOrder as $productOrder) {
if($product->id == $productOrder->id_product) {
$unit = ( $productManager->strUnit($productOrder->unit, 'wording_short', true) == 'p.') ? '' : '&nbsp;'. $productManager->strUnit($productOrder->unit, 'wording_short', true) ;
$strProducts .= '('.$productOrder->quantity .$unit.') '.$productManager->getNameExport($product) . '<br />';
$add = true;
}
}
}
$html .= '<td>'.substr($strProducts, 0, strlen($strProducts) - 6).'</td>';
if($isBig) {
$html .= '<td></td>' ;
}
$html .= '<td>'.$orderManager->getCommentReport($order).'</td>';
if($pointSale->credit) {
$credit = '' ;

if(isset($order->user) && $order->user->id) {
$userProducer = UserProducer::searchOne([
'id_user' => $order->user->id
]);

if($userProducer) {
$credit = number_format($userProducer->credit,2).' €' ;
}
}

$html .= '<td>'.$credit.'</td>' ;
}
$html .= '<td><strong>'.number_format($order->amount_with_tax, 2) . ' € ';

if($orderManager->getPaymentStatus($order) == Order::PAYMENT_PAID)
{
$html .= '(payé)' ;
}
elseif($orderManager->getPaymentStatus($order) == Order::PAYMENT_UNPAID && $orderManager->getOrderAmount($order, Order::AMOUNT_PAID))
{
$html .= '(reste '.$orderManager->getOrderAmount($order, Order::AMOUNT_REMAINING, true).' à payer)' ;
}
elseif($orderManager->getPaymentStatus($order) == Order::PAYMENT_SURPLUS)
{
$html .= '(surplus : '.$orderManager->getOrderAmount($order, Order::PAYMENT_SURPLUS, true).' à rembourser)' ;
}
$html .= '</strong></td>' ;
$html .= '</tr>' ;
}

$html .= '<tr><td><strong>Total</strong></td>' ;
$strProducts = '';
$cpt = 0 ;
foreach ($productsArray as $product) {
foreach( Product::$unitsArray as $unit => $dataUnit) {
$quantity = $orderManager->getProductQuantity($product, $pointSale->orders, false, $unit);
if ($quantity) {
$theUnit = ( $productManager->strUnit($unit, 'wording_short', true) == 'p.') ? '' : '&nbsp;'. $productManager->strUnit($unit, 'wording_short', true) ;
$strProducts .= '(' .$quantity .$theUnit.') '.$productManager->getNameExport($product) . '<br />';
}
}

if($isBig && $cpt == $limit) {
$strProducts .= '</td><td>' ;
}

$cpt ++ ;
}

$html .= '<td>'.$strProducts.'</td><td></td>' ;
if($pointSale->credit) {
$html .= '<td></td>' ;
}
$html .= '<td><strong>'.Price::format($pointSale->revenues_with_tax) . '</strong></td>';
$html .= '</tbody></table><pagebreak>' ;
}
}

// par point de vente

$html .= '<h3>Points de vente</h3>' ;
$html .= '<table class="">'
. '<thead>'
. '<tr>'
. '<th>Point de vente</th>'
. '<th>Produits</th>'
. ( $isBig ? '<th>Produits</th>' : '')
. '<th>Montant</th>'
. '</tr>'
. '<tbody>';

$revenues = 0 ;
foreach ($pointsSaleArray as $pointSale)
{
if (count($pointSale->orders))
{
$html .= '<tr><td>'.$pointSale->name.'</td><td>' ;

$cpt = 0 ;
foreach ($productsArray as $product) {
foreach( Product::$unitsArray as $unit => $dataUnit) {
$quantity = $orderManager->getProductQuantity($product, $pointSale->orders, false, $unit);
if ($quantity) {
$theUnit = ( $productManager->strUnit($unit, 'wording_short', true) == 'p.') ? '' : '&nbsp;'. $productManager->strUnit($unit, 'wording_short', true) ;
$html .= '(' .$quantity .$theUnit.') '.$productManager->getNameExport($product) . '<br />';
}
}

if($isBig && $cpt == $limit) {
$html .= '</td><td>' ;
}

$cpt ++ ;
}
//$html = substr($html, 0, strlen($html) - 6) ;
$html .= '</td><td>'.Price::format($pointSale->revenues_with_tax, 2).'</td></tr>' ;
$revenues += $pointSale->revenues_with_tax ;
}
}

// total
$html .= '<tr><td><strong>Total</strong></td><td>' ;

$cpt = 0 ;
foreach ($productsArray as $product) {
foreach( Product::$unitsArray as $unit => $dataUnit) {
$quantity = $orderManager->getProductQuantity($product, $ordersArray, false, $unit);
if ($quantity) {
$theUnit = ( $productManager->strUnit($unit, 'wording_short', true) == 'p.') ? '' : '&nbsp;'. $productManager->strUnit($unit, 'wording_short', true) ;
$html .= '(' .$quantity .$theUnit.') '.$product->name . '<br />';
}
}
if($isBig && $cpt == $limit) {
$html .= '</td><td>' ;
}

$cpt ++ ;
}

$html .= '</td><td><strong>'.number_format($revenues, 2).' €</strong></td></tr>' ;

$html .= '</tbody></table>' ;

echo $html ;

?>

+ 14
- 6
backend/views/layouts/header.php Ver fichero

@@ -99,21 +99,29 @@ $producer = GlobalParam::getCurrentProducer();
<i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu">
<li class="header">&nbsp;<strong>Producteurs en ligne</strong></li>
<li>
<input type="text" class="search-producer form-control" placeholder="Rechercher" />
</li>
<li class="li-alert-no-results">
<div class="alert alert-warning">Aucun producteur trouvé</div>
</li>
<?php $producersArray = Producer::find()->orderBy('name ASC')->all(); ?>
<?php foreach ($producersArray as $producer): ?>
<?php if ($producer->active == 1): ?>
<li>
<li class="producer">
<a href="<?= Yii::$app->urlManagerBackend->createUrl(['site/change-producer', 'id' => $producer->id]); ?>"><?= Html::encode($producer->name) ?></a>
</li>
<?php endif; ?>
<?php endforeach; ?>
<li class="header"><a href="javascript:void(0);" id="link-display-producers-offline">Afficher
les producteurs hors-ligne</a></li>
<!--<li class="header"><a href="javascript:void(0);" id="link-display-producers-offline">Afficher
les producteurs hors-ligne</a></li>-->
<?php foreach ($producersArray as $producer): ?>
<?php if ($producer->active != 1): ?>
<li class="offline">
<a href="<?= Yii::$app->urlManagerBackend->createUrl(['site/change-producer', 'id' => $producer->id]); ?>"><?= Html::encode($producer->name) ?></a>
<li class="producer">
<a href="<?= Yii::$app->urlManagerBackend->createUrl(['site/change-producer', 'id' => $producer->id]); ?>">
<label class="label label-danger">Hors-ligne</label>
<?= Html::encode($producer->name) ?>
</a>
</li>
<?php endif; ?>
<?php endforeach; ?>

+ 4
- 4
backend/views/order/report.php Ver fichero

@@ -52,7 +52,7 @@ foreach ($pointsSaleArray as $pointSale) {
if (count($pointSale->orders) && strlen($pointSale->$fieldInfosPointSale)) {
$html .= '<h3>'.$pointSale->name.'</h3>' ;
$colCredit = ($pointSale->credit) ? '<th>Rappel crédit</th>' : '' ;
$colCredit = ($pointSale->credit) ? '<th>Crédit</th>' : '' ;
$html .= '<table class="table table-bordered">'
. '<thead>'
@@ -115,15 +115,15 @@ foreach ($pointsSaleArray as $pointSale) {

if($orderManager->getPaymentStatus($order) == Order::PAYMENT_PAID)
{
$html .= '(payé)' ;
$html .= '(débité)' ;
}
elseif($orderManager->getPaymentStatus($order) == Order::PAYMENT_UNPAID && $orderManager->getOrderAmount($order, Order::AMOUNT_PAID))
{
$html .= '(reste '.$orderManager->getOrderAmount($order, Order::AMOUNT_REMAINING, true).' à payer)' ;
$html .= '(reste '.$orderManager->getOrderAmount($order, Order::AMOUNT_REMAINING, true).' à débiter)' ;
}
elseif($orderManager->getPaymentStatus($order) == Order::PAYMENT_SURPLUS)
{
$html .= '(surplus : '.$orderManager->getOrderAmount($order, Order::PAYMENT_SURPLUS, true).' à rembourser)' ;
$html .= '(surplus : '.$orderManager->getOrderAmount($order, Order::PAYMENT_SURPLUS, true).' à recréditer)' ;
}
$html .= '</strong></td>' ;

+ 3
- 0
backend/views/producer-admin/_form.php Ver fichero

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

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

+ 11
- 1
backend/views/producer-admin/index.php Ver fichero

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

+ 1
- 0
backend/views/producer-price-range-admin/create.php Ver fichero

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

+ 3
- 2
backend/views/producer-price-range-admin/update.php Ver fichero

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

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

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

+ 20
- 5
backend/views/producer/update.php Ver fichero

@@ -60,12 +60,12 @@ $this->addBreadcrumb($this->getTitle());
<div class="user-update" id="app-producer-update">

<div id="nav-params">
<button v-for="section in sectionsArray" v-if="!section.isAdminSection || (section.isAdminSection && isAdmin)"
<a v-for="section in sectionsArray" v-if="!section.isAdminSection || (section.isAdminSection && isAdmin)"
:class="'btn '+((currentSection == section.name) ? 'btn-primary' : 'btn-default')"
@click="changeSection(section)">
@click="changeSection(section)" :href="'#'+section.name">
{{ section.nameDisplay }}
<span class="glyphicon glyphicon-triangle-bottom"></span>
</button>
</a>
</div>

<div class="user-form">
@@ -306,8 +306,22 @@ $this->addBreadcrumb($this->getTitle());
0 => 'Non',
1 => 'Oui'
], []); ?>
<?= $form->field($model, 'option_export_display_column_delivery_note')
->dropDownList([
0 => 'Non',
1 => 'Oui'
], []); ?>

<h4>Divers</h4>
<?php
$choicesWeeksDistributionsActivatedInAdvanceArray = [null => '--'];
for($i = 1; $i < 13; $i++) {
$choicesWeeksDistributionsActivatedInAdvanceArray[$i] = $i.' semaine'.(($i > 1) ? 's' : '');
}
?>
<?= $form->field($model, 'option_weeks_distributions_activated_in_advance')
->dropDownList($choicesWeeksDistributionsActivatedInAdvanceArray)
->hint("Attention, les premières semaines doivent être activées manuellement."); ?>
<?= $form->field($model, 'option_order_reference_type')
->dropDownList([
Producer::ORDER_REFERENCE_TYPE_NONE => '--',
@@ -481,9 +495,10 @@ $this->addBreadcrumb($this->getTitle());
<div v-show="currentSection == 'software'" class="panel panel-default">
<div class="panel-body">
<h4>Opendistrib</h4>
<?php $urlAboutPage = Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/about']); ?>
<?= $form->field($model, 'option_testimony')
->textarea(['rows' => 7])
->hint("Écrivez ici votre témoignage concernant l'utilisation du logiciel. Il sera publié sur la page 'À propos' du site.") ; ?>
->hint("Écrivez ici votre témoignage concernant l'utilisation du logiciel. Il sera publié sur la page <a href=\"".$urlAboutPage."\" target=\"_blanck\">À propos</a> du site.") ; ?>
<?= $form->field($model, 'option_time_saved')
->dropDownList([
null => '--',
@@ -497,7 +512,7 @@ $this->addBreadcrumb($this->getTitle());
7 => '7 heures',
8 => '8 heures',
])
->hint("Sélectionnez le temps que vous estimez gagner chaque semaine en utilisant ce logiciel. Cette donnée sera utilisée sur la page 'À propos' du site.") ; ?>
->hint("Sélectionnez le temps que vous estimez gagner chaque semaine en utilisant ce logiciel. Cette donnée sera utilisée sur la page <a href=\"".$urlAboutPage."\" target=\"_blanck\">À propos</a> du site.") ; ?>
<?= $form->field($model, 'option_display_message_new_opendistrib_version')
->dropDownList([
1 => 'Oui',

+ 16
- 4
backend/views/support/index.php Ver fichero

@@ -43,15 +43,19 @@ use yii\grid\GridView;

$ticketManager = TicketManager::getInstance();
$userCurrent = $this->getUserCurrent();
$this->setTitle('Support');
$this->setTitle('Support & contact');
$this->addBreadcrumb($this->getTitle());

?>

<div class="support-index">
<?php if($context == 'producer'): ?>

<div class="callout callout-info">
<p><i class="icon fa fa-info-circle"></i> Pour toutes vos remarques, suggestions et remontées de bugs.</p>
</div>
<div>
<div class="col-md-4">
<div class="col-md-6 col-left">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="fa fa-phone"></i></span>
<div class="info-box-content">
@@ -63,7 +67,7 @@ $this->addBreadcrumb($this->getTitle());
</div>
</div>
</div>
<div class="col-md-4">
<div class="col-md-6 col-right">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="fa fa-calendar"></i></span>
<div class="info-box-content">
@@ -73,7 +77,7 @@ $this->addBreadcrumb($this->getTitle());
</div>
</div>
</div>
<div class="col-md-4">
<div class="col-md-6 col-left">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="fa fa-comments"></i></span>
<div class="info-box-content">
@@ -81,6 +85,14 @@ $this->addBreadcrumb($this->getTitle());
</div>
</div>
</div>
<div class="col-md-6 col-right">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="fa fa-envelope"></i></span>
<div class="info-box-content">
<span class="info-box-text"><br/><?= Html::a("M'envoyer un email", 'mailto:'.Yii::$app->parameterBag->get('adminEmail'), ['class' => 'btn btn-sm btn-default']); ?></span>
</div>
</div>
</div>
</div>
<div class="clr"></div>
<?php endif; ?>

+ 9
- 0
backend/views/support/view.php Ver fichero

@@ -29,6 +29,15 @@ $this->addBreadcrumb('Voir un ticket');
<td><strong>Statut</strong></td>
<td><?= $ticketManager->getTicketStatusLabelAsHtml($ticket); ?></td>
</tr>
<?php if($userManager->isCurrentAdmin()): ?>
<tr>
<td><strong>Producteur</strong></td>
<td><?= $ticketManager->isTicketUnread($ticket, $ticket->user) ?
'<span class="label label-warning">Non lu</span>' :
'<span class="label label-success">Lu</span>'; ?>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>

+ 1
- 0
backend/views/user/_form.php Ver fichero

@@ -63,6 +63,7 @@ $producerManager = $this->getProducerManager();
<?= $form->field($model, 'name')->textInput() ?>
<?= $form->field($model, 'phone')->textInput() ?>
<?= $form->field($model, 'email')->textInput() ?>
<?= $form->field($model, 'newsletter')->checkbox() ?>
<?= $form->field($model, 'address')->textarea() ?>

<?php if ($producerManager->getConfig('option_export_evoliz')): ?>

+ 17
- 0
backend/views/user/index.php Ver fichero

@@ -109,6 +109,22 @@ $this->render('_menu', [
return $html;
}
],
[
'attribute' => 'newsletter',
'header' => "Inscrit au bulletin<br/>d'information",
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) {
$userManager = UserManager::getInstance();
if($userManager->isUserSubscribedNewsletter($model)) {
return '<span class="label label-success">Oui</span>';
}

return '<span class="label label-danger">Non</span>';
}
],
[
'class' => 'yii\grid\ActionColumn',
'header' => 'Commandes',
@@ -159,6 +175,7 @@ $this->render('_menu', [
) . '
</span>
</div>';

return $html;
}
],

+ 71
- 43
backend/web/css/screen.css Ver fichero

@@ -431,7 +431,7 @@ a.btn.btn-primary .glyphicon-triangle-bottom, button.btn.btn-primary .glyphicon-
margin-bottom: 30px;
}
/* line 347, ../sass/screen.scss */
#nav-params button {
#nav-params a {
margin-right: 10px;
}

@@ -1660,93 +1660,113 @@ body.skin-black .main-header .notifications-menu ul.menu li a h5 small {
body.skin-black .main-header .notifications-menu ul.menu li a p {
margin-left: 10px;
}
/* line 136, ../sass/_adminlte.scss */
/* line 137, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .dropdown-menu {
width: 400px;
}
/* line 141, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .search-producer {
margin: 10px;
width: 94%;
}
/* line 146, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .li-alert-no-results {
display: none;
}
/* line 149, ../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 157, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .label {
position: relative;
top: -2px;
left: 0px;
}
/* line 142, ../sass/_adminlte.scss */
/* line 163, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu #link-display-producers-offline {
color: #F39C12;
}
/* line 146, ../sass/_adminlte.scss */
/* line 167, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .offline {
display: none;
}
/* line 153, ../sass/_adminlte.scss */
/* line 174, ../sass/_adminlte.scss */
body.skin-black .sidebar .sidebar-menu > li.header {
color: #899397;
}
/* line 158, ../sass/_adminlte.scss */
/* line 179, ../sass/_adminlte.scss */
body.skin-black .sidebar-menu > li.active > a {
border-color: #F39C12;
}
/* line 163, ../sass/_adminlte.scss */
/* line 184, ../sass/_adminlte.scss */
body.skin-black section.sidebar .user-panel {
text-align: center;
}
/* line 166, ../sass/_adminlte.scss */
/* line 187, ../sass/_adminlte.scss */
body.skin-black section.sidebar .user-panel .image {
margin-bottom: 3px;
}
/* line 170, ../sass/_adminlte.scss */
/* line 191, ../sass/_adminlte.scss */
body.skin-black section.sidebar .user-panel .title {
font-weight: bold;
color: white;
}
/* line 177, ../sass/_adminlte.scss */
/* line 198, ../sass/_adminlte.scss */
body.skin-black .content-wrapper {
background-color: #f5f5f5;
}
/* line 180, ../sass/_adminlte.scss */
/* line 201, ../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 186, ../sass/_adminlte.scss */
/* line 207, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .content-header .btn {
padding: 3px 6px;
font-size: 10px;
font-family: Arial;
text-transform: uppercase;
}
/* line 193, ../sass/_adminlte.scss */
/* line 214, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .content-header h1 {
font-family: 'myriadpro-light';
font-size: 20px;
}
/* line 199, ../sass/_adminlte.scss */
/* line 220, ../sass/_adminlte.scss */
body.skin-black .content-wrapper a {
color: #e08e0b;
}
/* line 203, ../sass/_adminlte.scss */
/* line 224, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .btn {
color: white;
}
/* line 207, ../sass/_adminlte.scss */
/* line 228, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .btn-default {
color: #333;
background-color: white;
}
/* line 212, ../sass/_adminlte.scss */
/* line 233, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .btn-primary {
background-color: #F39C12;
color: white;
border-color: #F39C12;
}
/* line 219, ../sass/_adminlte.scss */
/* line 240, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert a {
color: white;
}
/* line 222, ../sass/_adminlte.scss */
/* line 243, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert a.btn {
color: #333;
text-decoration: none;
}
/* line 227, ../sass/_adminlte.scss */
/* line 248, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert .close {
font-size: 30px;
position: relative;
@@ -1755,89 +1775,89 @@ body.skin-black .content-wrapper .alert .close {
color: white;
opacity: 0.6;
}
/* line 235, ../sass/_adminlte.scss */
/* line 256, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert .close:hover {
opacity: 1;
}
/* line 242, ../sass/_adminlte.scss */
/* line 263, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .callout h4 .fa {
margin-right: 7px;
}
/* line 245, ../sass/_adminlte.scss */
/* line 266, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .callout a {
color: white;
}
/* line 248, ../sass/_adminlte.scss */
/* line 269, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .callout .btn {
color: #333;
text-decoration: none;
}
/* line 255, ../sass/_adminlte.scss */
/* line 276, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table th {
font-size: 13px;
}
/* line 258, ../sass/_adminlte.scss */
/* line 279, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table th.column-actions, body.skin-black .content-wrapper .table td.column-actions {
width: 150px;
text-align: right;
}
/* line 262, ../sass/_adminlte.scss */
/* line 283, ../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 267, ../sass/_adminlte.scss */
/* line 288, ../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 272, ../sass/_adminlte.scss */
/* line 293, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .pagination > li > a, body.skin-black .content-wrapper .pagination > li > span {
color: #F39C12;
}
/* line 274, ../sass/_adminlte.scss */
/* line 295, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .pagination > li > a:hover, body.skin-black .content-wrapper .pagination > li > span:hover {
color: #c87f0a;
}
/* line 279, ../sass/_adminlte.scss */
/* line 300, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .submenu {
margin-bottom: 25px;
}
/* line 285, ../sass/_adminlte.scss */
/* line 306, ../sass/_adminlte.scss */
body.skin-black .main-footer a {
color: #F39C12;
}

/* line 291, ../sass/_adminlte.scss */
/* line 312, ../sass/_adminlte.scss */
body.login-page {
background: none;
background-color: white;
}
/* line 295, ../sass/_adminlte.scss */
/* line 316, ../sass/_adminlte.scss */
body.login-page .login-box .login-logo {
text-align: center;
font-family: 'highvoltageregular';
}
/* line 299, ../sass/_adminlte.scss */
/* line 320, ../sass/_adminlte.scss */
body.login-page .login-box .login-logo img {
width: 50px;
}
/* line 304, ../sass/_adminlte.scss */
/* line 325, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body .btn-primary {
background-color: #F39C12;
border-color: #F39C12;
padding: 5px 10px;
}
/* line 309, ../sass/_adminlte.scss */
/* line 330, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body .btn-primary:active {
background-color: #f4a62a;
border-color: #F39C12;
}
/* line 315, ../sass/_adminlte.scss */
/* line 336, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body a {
color: #F39C12;
}
/* line 317, ../sass/_adminlte.scss */
/* line 338, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body a:hover {
color: #f4a62a;
}
@@ -2695,24 +2715,32 @@ termes.
padding-left: 25px;
}

/* line 6, ../sass/support/_index.scss */
/* line 4, ../sass/support/_index.scss */
.support-index .col-left {
padding-left: 0px;
}
/* line 7, ../sass/support/_index.scss */
.support-index .col-right {
padding-right: 0px;
}
/* line 13, ../sass/support/_index.scss */
.support-index .ticket-list .nav-tabs .label {
position: relative;
top: -2px;
left: 2px;
padding: 0.3em 0.6em 0.2em 0.6em;
}
/* line 15, ../sass/support/_index.scss */
/* line 22, ../sass/support/_index.scss */
.support-index .ticket-list .table .filters {
display: none;
}
/* line 19, ../sass/support/_index.scss */
/* line 26, ../sass/support/_index.scss */
.support-index .ticket-list .table .td-created-at,
.support-index .ticket-list .table .td-last-message,
.support-index .ticket-list .table .td-messages {
width: 100px;
}
/* line 24, ../sass/support/_index.scss */
/* line 31, ../sass/support/_index.scss */
.support-index .ticket-list .table .td-producer {
width: 200px;
}

+ 34
- 0
backend/web/js/backend.js Ver fichero

@@ -64,6 +64,40 @@ var UrlManager = {
};

function opendistrib_dropdown_producers() {

$('.producer-menu .dropdown-toggle').click(function() {
$('.producer-menu .search-producer').focus();
});

$('.producer-menu .search-producer').keyup(function() {
var $alertNoResults = $('.producer-menu .li-alert-no-results');
var searchWords = $(this).val().toLowerCase();
var count = 0;

if(searchWords && searchWords.length > 0) {
$('.producer-menu li.producer').each(function() {
if($(this).find('a').text().toLowerCase().indexOf(searchWords) >= 0 || !searchWords) {
$(this).show();
count ++;
}
else {
$(this).hide();
}
});

if(count) {
$alertNoResults.hide();
}
else {
$alertNoResults.show();
}
}
else {
$alertNoResults.hide();
$('.producer-menu li.producer').show();
}
});

$('#link-display-producers-offline').click(function() {
$(this).hide();
$('.producer-menu .offline').show();

+ 587
- 555
backend/web/js/vuejs/distribution-index.js
La diferencia del archivo ha sido suprimido porque es demasiado grande
Ver fichero


+ 12
- 1
backend/web/js/vuejs/producer-update.js Ver fichero

@@ -39,7 +39,7 @@ var app = new Vue({
el: '#app-producer-update',
data() {
return Object.assign({
currentSection: 'general',
currentSection: this.getInitialSection(),
sectionsArray: [
{
name: 'general',
@@ -92,7 +92,18 @@ var app = new Vue({
methods: {
changeSection: function(section) {
this.currentSection = section.name ;
},
getInitialSection: function() {
var hash = window.location.hash.substring(1);
if(hash && hash.length) {
return hash;
}

return 'general';
}
},
mounted: function() {

}
});


+ 21
- 0
backend/web/sass/_adminlte.scss Ver fichero

@@ -133,6 +133,27 @@ body.skin-black {
}
.navbar .nav li.producer-menu {

.dropdown-menu {
width: 400px;
}

.search-producer {
margin: 10px;
width: 94%;
}

.li-alert-no-results {
display: none;

.alert {
margin-bottom: 0px;
margin-left: 10px;
margin-right: 10px;
padding: 15px 15px 10px 15px;
}
}

.label {
position: relative ;
top: -2px ;

+ 1
- 1
backend/web/sass/screen.scss Ver fichero

@@ -344,7 +344,7 @@ a.btn, button.btn {
#nav-params {
margin-bottom: 30px ;

button {
a {
margin-right: 10px ;
}
}

+ 8
- 1
backend/web/sass/support/_index.scss Ver fichero

@@ -1,7 +1,14 @@

.support-index {
.ticket-list {

.col-left {
padding-left: 0px;
}
.col-right {
padding-right: 0px;
}

.ticket-list {
.nav-tabs {
.label {
position: relative;

+ 62
- 0
common/components/AbstractApi.php Ver fichero

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

namespace common\components;

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

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

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

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

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

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

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

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

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

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

+ 6
- 0
common/components/BusinessLogicTrait.php Ver fichero

@@ -18,6 +18,7 @@ use common\logic\Document\Invoice\Wrapper\InvoiceContainer;
use common\logic\Document\Invoice\Wrapper\InvoiceManager;
use common\logic\Document\Quotation\Wrapper\QuotationContainer;
use common\logic\Document\Quotation\Wrapper\QuotationManager;
use common\logic\Opinion\Wrapper\OpinionManager;
use common\logic\Order\Order\Wrapper\OrderContainer;
use common\logic\Order\Order\Wrapper\OrderManager;
use common\logic\Order\ProductOrder\Wrapper\ProductOrderContainer;
@@ -61,6 +62,11 @@ use common\logic\User\UserUserGroup\Wrapper\UserUserGroupManager;

trait BusinessLogicTrait
{
public function getOpinionManager(): OpinionManager
{
return OpinionManager::getInstance();
}

public function getUserProducerManager(): UserProducerManager
{
return UserProducerManager::getInstance();

+ 51
- 0
common/components/DolibarrApi.php Ver fichero

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

namespace common\components;

use Psr\Http\Message\ResponseInterface;

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

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

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

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

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

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

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

+ 4
- 1
common/components/MailerService.php Ver fichero

@@ -21,9 +21,12 @@ class MailerService
$message->send();
}

public function sendAdmin(string $subject, string $view, array $params = [])
public function sendAdmin(string $subject, string $view, array $params = [], string $replyTo = null)
{
$message = $this->composeBase(\Yii::$app->parameterBag->get('adminEmail'), $view, $params);
if($replyTo) {
$message->setReplyTo($replyTo);
}
$this->initMessageFromSite($message, $subject);
$message->send();
}

+ 11
- 0
common/config/main.php Ver fichero

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

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

@@ -128,6 +130,12 @@ return [
'enableStrictParsing' => false,
'rules' => [],
],
'dolibarrApi' => function() {
return new DolibarrApi(
Yii::$app->parameterBag->get('dolibarrApiUrl'),
['DOLAPIKEY', \Yii::$app->parameterBag->get('dolibarrApiKey')]
);
},
'logic' => function () {
return new BusinessLogic();
},
@@ -141,6 +149,9 @@ return [
Distribution::class => [
common\logic\Subscription\Subscription\Event\DistributionObserver::class
],
DeliveryNote::class => [
common\logic\Order\Order\Event\DeliveryNoteObserver::class
],
Ticket::class => [
common\logic\User\User\Event\TicketObserver::class,
],

+ 45
- 0
common/helpers/Ajax.php Ver fichero

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

namespace common\helpers;

class Ajax
{
const RESPONSE_TYPE_ERROR = 'error';
const RESPONSE_TYPE_SUCCESS = 'success';

public static function responseSuccess(string $message): array
{
return self::response(self::RESPONSE_TYPE_SUCCESS, $message);
}

public static function responseError(string $message): array
{
return self::response(self::RESPONSE_TYPE_ERROR, $message);
}

private static function response(string $responseType, string $message): array
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

return [
'return' => $responseType,
'alert' => [
'type' => self::getAlertClass($responseType),
'message' => $message
]
];
}

private static function getAlertClass(string $responseType)
{
$class = '';
if($responseType == self::RESPONSE_TYPE_SUCCESS) {
$class = 'success';
}
elseif($responseType == self::RESPONSE_TYPE_ERROR) {
$class = 'danger';
}

return $class;
}
}

+ 8
- 0
common/logic/AbstractUtils.php Ver fichero

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

namespace common\logic;

abstract class AbstractUtils extends AbstractService implements UtilsInterface
{

}

+ 1
- 1
common/logic/ContainerInterface.php Ver fichero

@@ -5,5 +5,5 @@ namespace common\logic;
interface ContainerInterface
{
public function getServices(): array;
public function getDefinition(): DefinitionInterface;
//public function getDefinition(): DefinitionInterface;
}

+ 6
- 1
common/logic/Distribution/Distribution/Service/DistributionBuilder.php Ver fichero

@@ -182,7 +182,6 @@ class DistributionBuilder extends AbstractBuilder
/**
* Active ou désactive la distribution.
*/
// active
public function activeDistribution(Distribution $distribution, bool $active = true): void
{
$distribution->active = (int) $active;
@@ -196,4 +195,10 @@ class DistributionBuilder extends AbstractBuilder
$distribution->trigger(Distribution::EVENT_ACTIVE, $distributionActiveEvent);
}
}

public function activeDistributionByDate(\DateTime $date): void
{
$distribution = $this->createDistributionIfNotExist($date->format('Y-m-d'));
$this->activeDistribution($distribution);
}
}

+ 1
- 8
common/logic/Distribution/Distribution/Service/DistributionReportGridPdfGenerator.php Ver fichero

@@ -78,7 +78,6 @@ class DistributionReportGridPdfGenerator extends AbstractGenerator
$orientationPdf = Pdf::ORIENT_LANDSCAPE;
}

// get your HTML raw content without any layouts or scripts
$content = \Yii::$app->getView()->render($viewPdf, [
'date' => $distribution->date,
'distribution' => $distribution,
@@ -92,17 +91,11 @@ class DistributionReportGridPdfGenerator extends AbstractGenerator

$dateStr = date('d/m/Y', strtotime($distribution->date));

if ($save) {
$destination = Pdf::DEST_FILE;
} else {
$destination = Pdf::DEST_BROWSER;
}

$pdf = new Pdf([
'mode' => Pdf::MODE_UTF8,
'format' => Pdf::FORMAT_A4,
'orientation' => $orientationPdf,
'destination' => $destination,
'destination' => $save ? Pdf::DEST_FILE : Pdf::DEST_BROWSER,
'filename' => \Yii::getAlias(
'@app/web/pdf/Commandes-' . $distribution->date . '-' . $producer->id . '.pdf'
),

+ 293
- 23
common/logic/Distribution/Distribution/Service/DistributionReportPdfGenerator.php Ver fichero

@@ -2,22 +2,36 @@

namespace common\logic\Distribution\Distribution\Service;

use common\helpers\Price;
use common\logic\AbstractGenerator;
use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Distribution\ProductDistribution\Repository\ProductDistributionRepository;
use common\logic\Document\Document\Service\DocumentSolver;
use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Repository\OrderRepository;
use common\logic\Order\Order\Service\OrderBuilder;
use common\logic\Order\Order\Service\OrderSolver;
use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\PointSale\PointSale\Repository\PointSaleRepository;
use common\logic\Producer\Producer\Model\Producer;
use common\logic\Product\Product\Model\Product;
use common\logic\Product\Product\Repository\ProductRepository;
use common\logic\Product\Product\Service\ProductSolver;
use common\logic\User\UserProducer\Model\UserProducer;
use kartik\mpdf\Pdf;

class DistributionReportPdfGenerator extends AbstractGenerator
{
const LIMIT_PRODUCTS = 100;

protected OrderRepository $orderRepository;
protected OrderBuilder $orderBuilder;
protected ProductRepository $productRepository;
protected ProductDistributionRepository $productDistributionRepository;
protected PointSaleRepository $pointSaleRepository;
protected OrderSolver $orderSolver;
protected ProductSolver $productSolver;
protected DocumentSolver $documentSolver;

public function loadDependencies(): void
{
@@ -26,6 +40,9 @@ class DistributionReportPdfGenerator extends AbstractGenerator
$this->productRepository = $this->loadService(ProductRepository::class);
$this->productDistributionRepository = $this->loadService(ProductDistributionRepository::class);
$this->pointSaleRepository = $this->loadService(PointSaleRepository::class);
$this->orderSolver = $this->loadService(OrderSolver::class);
$this->productSolver = $this->loadService(ProductSolver::class);
$this->documentSolver = $this->loadService(DocumentSolver::class);
}

public function generateDistributionReportPdf(Distribution $distribution, bool $save = false)
@@ -38,39 +55,31 @@ class DistributionReportPdfGenerator extends AbstractGenerator
foreach ($pointsSaleArray as $pointSale) {
$this->orderBuilder->initPointSaleOrders($pointSale, $ordersArray);
}

$viewPdf = '@backend/views/distribution/report';
$orientationPdf = Pdf::ORIENT_PORTRAIT;
$isBig = count($productsArray) > self::LIMIT_PRODUCTS;

if ($producer->slug == 'bourlinguepacotille') {
$viewPdf = '@backend/views/distribution/report-bourlingue';
$orientationPdf = Pdf::ORIENT_LANDSCAPE;
$content = \Yii::$app->getView()->render($viewPdf, [
'date' => $distribution->date,
'distribution' => $distribution,
'selectedProductsArray' => $selectedProductsArray,
'pointsSaleArray' => $pointsSaleArray,
'productsArray' => $productsArray,
'ordersArray' => $ordersArray,
'producer' => $producer
]);
}

// get your HTML raw content without any layouts or scripts
$content = \Yii::$app->getView()->render($viewPdf, [
'date' => $distribution->date,
'distribution' => $distribution,
'selectedProductsArray' => $selectedProductsArray,
'pointsSaleArray' => $pointsSaleArray,
'productsArray' => $productsArray,
'ordersArray' => $ordersArray,
'producer' => $producer
]);

$dateStr = date('d/m/Y', strtotime($distribution->date));

if ($save) {
$destination = Pdf::DEST_FILE;
} else {
$destination = Pdf::DEST_BROWSER;
else {
$orientationPdf = Pdf::ORIENT_PORTRAIT;
$content = $this->buildReportHtml($pointsSaleArray, $productsArray, $ordersArray, $isBig);
}

$pdf = new Pdf([
'mode' => Pdf::MODE_UTF8,
'format' => Pdf::FORMAT_A4,
'orientation' => $orientationPdf,
'destination' => $destination,
'destination' => $save ? Pdf::DEST_FILE : Pdf::DEST_BROWSER,
'filename' => \Yii::getAlias(
'@app/web/pdf/Commandes-' . $distribution->date . '-' . $this->getProducerContextId() . '.pdf'
),
@@ -103,11 +112,272 @@ class DistributionReportPdfGenerator extends AbstractGenerator
}
',
'methods' => [
'SetHeader' => ['Commandes du ' . $dateStr],
'SetHeader' => ['Commandes du ' . date('d/m/Y', strtotime($distribution->date))],
'SetFooter' => ['{PAGENO}'],
]
]);

return $pdf->render();
}

public function buildReportHtml(array $pointsSaleArray, array $productsArray, array $ordersArray, bool $isBig): string
{
$html = $this->buildReportPointsSaleHtml($pointsSaleArray, $productsArray, $isBig);
$html .= $this->buildReportPointsSaleTotalHtml($pointsSaleArray, $productsArray, $ordersArray, $isBig);
return $html;
}

public function buildReportPointsSaleHtml(array $pointsSaleArray, array $productsArray, bool $isBig): string
{
$producer = $this->getProducerContext();
$html = '' ;
foreach ($pointsSaleArray as $pointSale) {
if (count($pointSale->orders)) {

$html .= '<h3>'.$pointSale->name.'</h3>' ;
$columnDeliveryNote = ($producer->option_export_display_column_delivery_note) ? '<th>BL</th>' : '';
$colCredit = ($pointSale->credit) ? '<th>Crédit</th>' : '' ;

$html .= '<table class="">'
. '<thead>'
. '<tr>'
. '<th>Client</th>'
. '<th>Produits</th>'
. ($isBig ? '<th>Produits</th>' : '')
. '<th>Commentaire</th>'
. $columnDeliveryNote
. $colCredit
. '<th>Montant</th>'
. '</tr>'
. '</thead>'
. '<tbody>';

foreach ($pointSale->orders as $order) {
$html .= '<tr>' ;
$html .= $this->columnUsername($order);
$html .= $this->columnOrderProducts($order, $productsArray);
$html .= $this->columnIfIsBig($isBig);
$html .= $this->columnComment($order);
$html .= $this->columnDeliveryNote($order);
$html .= $this->columnCredit($order, $pointSale);
$html .= $this->columnOrderAmount($order);
$html .= '</tr>' ;
}

$html .= '<tr><td><strong>Total</strong></td>' ;

$strProducts = '';
$cpt = 0 ;
foreach ($productsArray as $product) {
foreach( Product::$unitsArray as $unit => $dataUnit) {
$quantity = $this->orderSolver->getProductQuantity($product, $pointSale->orders, false, $unit);
if ($quantity) {
$theUnit = ( $this->productSolver->strUnit($unit, 'wording_short', true) == 'p.') ? '' : '&nbsp;'. $this->productSolver->strUnit($unit, 'wording_short', true) ;
$strProducts .= '(' .$quantity .$theUnit.') '.$this->productSolver->getNameExport($product) . '<br />';
}
}

if($isBig && $cpt == self::LIMIT_PRODUCTS) {
$strProducts .= '</td><td>' ;
}

$cpt ++ ;
}

$html .= '<td>'.$strProducts.'</td><td></td>' ;
if($pointSale->credit) {
$html .= '<td></td>' ;
}
if($producer->option_export_display_column_delivery_note) {
$html .= '<td></td>' ;
}
$html .= '<td><strong>'.Price::format($pointSale->revenues_with_tax) . '</strong></td>';

$html .= '</tbody></table><pagebreak>' ;
}
}

return $html;
}

public function columnUsername(Order $order): string
{
$producer = $this->getProducerContext();

$strUser = $this->orderSolver->getOrderUsername($order) ;
if(strlen($order->comment_point_sale))
{
$strUser .= '<br /><em>'.$order->comment_point_sale.'</em>' ;
}

if (isset($order->user) && strlen($order->user->phone)) {
$strUser .= '<br />' . $order->user->phone . '';
}

if($producer->option_order_reference_type == Producer::ORDER_REFERENCE_TYPE_YEARLY && $order->reference && strlen($order->reference) > 0) {
$strUser .= '<br />'.$order->reference ;
}

return '<td>'.$strUser.'</td>';
}

public function columnOrderProducts(Order $order, array $productsArray): string
{
$strProducts = '';
foreach ($productsArray as $product) {
foreach ($order->productOrder as $productOrder) {
if($product->id == $productOrder->id_product) {
$unit = ( $this->productSolver->strUnit($productOrder->unit, 'wording_short', true) == 'p.') ? '' : '&nbsp;'. $this->productSolver->strUnit($productOrder->unit, 'wording_short', true) ;
$strProducts .= '('.$productOrder->quantity .$unit.') '.$this->productSolver->getNameExport($product) . '<br />';
}
}
}

return '<td>'.substr($strProducts, 0, strlen($strProducts) - 6).'</td>';
}

public function columnIfIsBig(bool $isBig): string
{
if($isBig) {
return '<td></td>' ;
}

return '';
}

public function columnComment(Order $order): string
{
return '<td>'.$this->orderSolver->getCommentReport($order).'</td>';;
}

public function columnDeliveryNote(Order $order): string
{
$producer = $this->getProducerContext();
if($producer->option_export_display_column_delivery_note) {
$contentColumnDeliveryNote = '';
if($order->deliveryNote) {
if($this->documentSolver->isStatusDraft($order->deliveryNote)) {
$contentColumnDeliveryNote = 'Brouillon';
}
elseif($this->documentSolver->isStatusValid($order->deliveryNote)) {
$contentColumnDeliveryNote = 'Oui';
}
}
return '<td>'.$contentColumnDeliveryNote.'</td>';
}

return '';
}

public function columnCredit(Order $order, PointSale $pointSale): string
{
if($pointSale->credit) {
$credit = '' ;

if(isset($order->user) && $order->user->id) {
$userProducer = UserProducer::searchOne([
'id_user' => $order->user->id
]);

if($userProducer) {
$credit = number_format($userProducer->credit,2).' €' ;
}
}

return '<td>'.$credit.'</td>' ;
}

return '';
}

public function columnOrderAmount(Order $order): string
{
$html = '<td><strong>'.number_format($order->amount_with_tax, 2) . ' € ';

if($this->orderSolver->getPaymentStatus($order) == Order::PAYMENT_PAID)
{
$html .= '(débité)' ;
}
elseif($this->orderSolver->getPaymentStatus($order) == Order::PAYMENT_UNPAID && $this->orderSolver->getOrderAmount($order, Order::AMOUNT_PAID))
{
$html .= '(reste '.$this->orderSolver->getOrderAmount($order, Order::AMOUNT_REMAINING, true).' à débiter)' ;
}
elseif($this->orderSolver->getPaymentStatus($order) == Order::PAYMENT_SURPLUS)
{
$html .= '(surplus : '.$this->orderSolver->getOrderAmount($order, Order::PAYMENT_SURPLUS, true).' à recréditer)' ;
}

$html .= '</strong></td>' ;

return $html;
}

public function buildReportPointsSaleTotalHtml(array $pointsSaleArray, array $productsArray, array $ordersArray, bool $isBig): string
{
$html = '';
$html .= '<h3>Points de vente</h3>' ;
$html .= '<table class="">'
. '<thead>'
. '<tr>'
. '<th>Point de vente</th>'
. '<th>Produits</th>'
. ( $isBig ? '<th>Produits</th>' : '')
. '<th>Montant</th>'
. '</tr>'
. '<tbody>';

$revenues = 0 ;
foreach ($pointsSaleArray as $pointSale)
{
if (count($pointSale->orders))
{
$html .= '<tr><td>'.$pointSale->name.'</td><td>' ;

$cpt = 0 ;
foreach ($productsArray as $product) {
foreach( Product::$unitsArray as $unit => $dataUnit) {
$quantity = $this->orderSolver->getProductQuantity($product, $pointSale->orders, false, $unit);
if ($quantity) {
$theUnit = ( $this->productSolver->strUnit($unit, 'wording_short', true) == 'p.') ? '' : '&nbsp;'. $this->productSolver->strUnit($unit, 'wording_short', true) ;
$html .= '(' .$quantity .$theUnit.') '.$this->productSolver->getNameExport($product) . '<br />';
}
}

if($isBig && $cpt == self::LIMIT_PRODUCTS) {
$html .= '</td><td>' ;
}

$cpt ++ ;
}

$html .= '</td><td>'.Price::format($pointSale->revenues_with_tax, 2).'</td></tr>' ;
$revenues += $pointSale->revenues_with_tax ;
}
}

// total
$html .= '<tr><td><strong>Total</strong></td><td>' ;

$cpt = 0 ;
foreach ($productsArray as $product) {
foreach( Product::$unitsArray as $unit => $dataUnit) {
$quantity = $this->orderSolver->getProductQuantity($product, $ordersArray, false, $unit);
if ($quantity) {
$theUnit = ( $this->productSolver->strUnit($unit, 'wording_short', true) == 'p.') ? '' : '&nbsp;'. $this->productSolver->strUnit($unit, 'wording_short', true) ;
$html .= '(' .$quantity .$theUnit.') '.$product->name . '<br />';
}
}
if($isBig && $cpt == self::LIMIT_PRODUCTS) {
$html .= '</td><td>' ;
}

$cpt ++ ;
}

$html .= '</td><td><strong>'.number_format($revenues, 2).' €</strong></td></tr>' ;

$html .= '</tbody></table>' ;

return $html;
}
}

+ 12
- 0
common/logic/Document/DeliveryNote/Event/DeliveryNoteCreateEvent.php Ver fichero

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

namespace common\logic\Document\DeliveryNote\Event;

use common\logic\Document\DeliveryNote\Model\DeliveryNote;
use yii\base\Event;

class DeliveryNoteCreateEvent extends Event
{
public DeliveryNote $deliveryNote;
public array $idOrders = [];
}

+ 2
- 0
common/logic/Document/DeliveryNote/Model/DeliveryNote.php Ver fichero

@@ -42,6 +42,8 @@ use common\logic\Document\Document\Model\Document;

class DeliveryNote extends Document
{
const EVENT_CREATE = 'deliverynote.event.create';

/**
* @inheritdoc
*/

+ 26
- 0
common/logic/Document/DeliveryNote/Repository/DeliveryNoteRepository.php Ver fichero

@@ -4,6 +4,7 @@ namespace common\logic\Document\DeliveryNote\Repository;

use common\logic\AbstractRepository;
use common\logic\Document\DeliveryNote\Model\DeliveryNote;
use common\logic\Order\Order\Model\Order;

class DeliveryNoteRepository extends AbstractRepository
{
@@ -30,4 +31,29 @@ class DeliveryNoteRepository extends AbstractRepository
->filterById($id)
->findOne();
}

public function getOneDeliveryNoteExistingFromOrders(array $ordersArray): ?DeliveryNote
{
$i = 0;
$deliveryNote = null;
do {
$order = $ordersArray[$i];
if ($order->distribution->id_producer == $this->getProducerContextId() && $order->id_delivery_note > 0) {
$deliveryNote = $this->findOneDeliveryNoteById($order->id_delivery_note);
}
$i++;
} while ($deliveryNote == null && isset($ordersArray[$i]));

return $deliveryNote;
}

public function findOneDeliveryNoteByOrder(Order $order): ?DeliveryNote
{
$deliveryNoteExist = null;
if ($order->id_delivery_note) {
$deliveryNoteExist = $this->findOneDeliveryNoteById($order->id_delivery_note);
}

return $deliveryNoteExist;
}
}

+ 108
- 0
common/logic/Document/DeliveryNote/Service/DeliveryNoteBuilder.php Ver fichero

@@ -2,15 +2,123 @@

namespace common\logic\Document\DeliveryNote\Service;

use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Document\DeliveryNote\Event\DeliveryNoteCreateEvent;
use common\logic\Document\DeliveryNote\Model\DeliveryNote;
use common\logic\Document\DeliveryNote\Repository\DeliveryNoteRepository;
use common\logic\Document\Document\Service\DocumentBuilder;
use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Service\OrderSolver;
use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\User\User\Repository\UserRepository;
use common\logic\User\User\Service\UserSolver;
use yii\base\ErrorException;

class DeliveryNoteBuilder extends DocumentBuilder
{
protected UserSolver $userSolver;
protected UserRepository $userRepository;
protected DeliveryNoteRepository $deliveryNoteRepository;
protected OrderSolver $orderSolver;

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

public function instanciateDeliveryNote(): DeliveryNote
{
$deliveryNote = new DeliveryNote();

$this->initDocumentProducer($deliveryNote);
$this->initTaxCalculationMethod($deliveryNote);

return $deliveryNote;
}

public function createDeliveryNoteForPointSale(PointSale $pointSale, Distribution $distribution, array $idOrders): DeliveryNote
{
$deliveryNote = $this->instanciateDeliveryNote();
$this->initDeliveryNoteNameByPointSale($deliveryNote, $distribution, $pointSale);
$this->initDeliveryNoteUserFromPointSale($deliveryNote, $pointSale);
$this->initDeliveryNoteAddress($deliveryNote);
$deliveryNote->save();

$this->triggerDeliveryNoteCreateEvent($deliveryNote, $idOrders);

return $deliveryNote;
}

public function createDeliveryNoteForOrder(Order $order): DeliveryNote
{
$deliveryNote = $this->deliveryNoteRepository->findOneDeliveryNoteByOrder($order);
$deliveryNote = $this->deleteDeliveryNoteIfStatusDraft($deliveryNote);

if(!$deliveryNote) {
$deliveryNote = $this->instanciateDeliveryNote();
$this->initDeliveryNoteNameByOrder($deliveryNote, $order);
$this->initDeliveryNoteUserFromOrder($deliveryNote, $order);
$this->initDeliveryNoteAddress($deliveryNote);
$deliveryNote->save();

$this->triggerDeliveryNoteCreateEvent($deliveryNote, [$order->id]);
}

return $deliveryNote;
}

public function triggerDeliveryNoteCreateEvent(DeliveryNote $deliveryNote, array $idOrders)
{
$deliveryNoteCreateEvent = new DeliveryNoteCreateEvent();
$deliveryNoteCreateEvent->deliveryNote = $deliveryNote;
$deliveryNoteCreateEvent->idOrders = $idOrders;
$deliveryNote->trigger(DeliveryNote::EVENT_CREATE, $deliveryNoteCreateEvent);
}

public function initDeliveryNoteUserFromPointSale(DeliveryNote $deliveryNote, PointSale $pointSale)
{
$deliveryNote->id_user = $pointSale->id_user;
}

public function initDeliveryNoteUserFromOrder(DeliveryNote $deliveryNote, Order $order)
{
$deliveryNote->id_user = $order->id_user;
}

public function initDeliveryNoteNameByPointSale(DeliveryNote $deliveryNote, Distribution $distribution, PointSale $pointSale)
{
$deliveryNote->name = 'Bon de livraison ' . $pointSale->name .
' (' . date('d/m/Y', strtotime($distribution->date)) . ')';
}

public function initDeliveryNoteNameByOrder(DeliveryNote $deliveryNote, Order $order)
{
$deliveryNote->name = 'Bon de livraison ' . $this->orderSolver->getOrderUsername($order) .
' (' . date('d/m/Y', strtotime($order->distribution->date)) . ')';
}

public function initDeliveryNoteAddress(DeliveryNote $deliveryNote)
{
$user = $this->userRepository->findOneUserById($deliveryNote->id_user);
if($user) {
$deliveryNote->address = $this->userSolver->getFullAddress($user);
}
else {
throw new ErrorException("L'utilisateur du bon de livraison n'est pas défini.");
}
}

public function deleteDeliveryNoteIfStatusDraft(DeliveryNote $deliveryNote = null): ?DeliveryNote
{
if ($deliveryNote && $this->documentSolver->isStatusDraft($deliveryNote)) {
$deliveryNote->delete();
$deliveryNote = null;
}

return $deliveryNote;
}
}

+ 13
- 0
common/logic/Document/Document/Service/DocumentBuilder.php Ver fichero

@@ -21,6 +21,11 @@ class DocumentBuilder extends AbstractBuilder
$this->producerRepository = $this->loadService(ProducerRepository::class);
}

public function initDocumentProducer(Document $document): void
{
$document->id_producer = $this->getProducerContextId();
}

public function generateReference(DocumentInterface $document): void
{
$class = $this->documentSolver->getClass($document);
@@ -64,6 +69,14 @@ class DocumentBuilder extends AbstractBuilder
}
}

public function validateDocument(Document $document): void
{
if($this->documentSolver->isStatusDraft($document)) {
$this->changeStatus($document, Document::STATUS_VALID);
$this->update($document);
}
}

public function initTaxCalculationMethod(DocumentInterface $document): void
{
$producerTaxCalculationMethod = $this->producerRepository->getConfig('option_tax_calculation_method');

+ 30
- 0
common/logic/Opinion/Service/OpinionUtils.php Ver fichero

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

namespace common\logic\Opinion\Service;

use common\logic\AbstractUtils;
use common\logic\User\User\Model\User;
use common\logic\User\User\Service\UserSolver;

class OpinionUtils extends AbstractUtils
{
protected UserSolver $userSolver;

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

public function sendOpinionEmailAdmin($opinionFormModel, User $userCurrent = null)
{
\Yii::$app->mailerService->sendAdmin(
'Nouvel avis',
'newOpinionAdmin',
[
'username' => $userCurrent ? $this->userSolver->getUsername($userCurrent) : $opinionFormModel->name,
'message' => $opinionFormModel->message,
],
$userCurrent ? $userCurrent->email : $opinionFormModel->email
);
}
}

+ 16
- 0
common/logic/Opinion/Wrapper/OpinionContainer.php Ver fichero

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

namespace common\logic\Opinion\Wrapper;

use common\logic\AbstractContainer;
use common\logic\Opinion\Service\OpinionUtils;

class OpinionContainer extends AbstractContainer
{
public function getServices(): array
{
return [
OpinionUtils::class
];
}
}

+ 17
- 0
common/logic/Opinion/Wrapper/OpinionManager.php Ver fichero

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

namespace common\logic\Opinion\Wrapper;

use common\logic\AbstractManager;
use common\logic\Opinion\Service\OpinionUtils;

/**
* @mixin OpinionUtils
*/
class OpinionManager extends AbstractManager
{
public function getContainerFqcn(): string
{
return OpinionContainer::class;
}
}

+ 24
- 0
common/logic/Order/Order/Event/DeliveryNoteObserver.php Ver fichero

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

namespace common\logic\Order\Order\Event;

use common\logic\Document\DeliveryNote\Event\DeliveryNoteCreateEvent;
use common\logic\Document\DeliveryNote\Model\DeliveryNote;
use common\logic\Order\Order\Wrapper\OrderManager;
use justcoded\yii2\eventlistener\observers\Observer;

class DeliveryNoteObserver extends Observer
{
public function events()
{
return [
DeliveryNote::EVENT_CREATE => 'onDeliveryNoteCreate'
];
}

public function onDeliveryNoteCreate(DeliveryNoteCreateEvent $event)
{
$orderManager = OrderManager::getInstance();
$orderManager->assignAllOrdersDeliveryNote($event->idOrders, $event->deliveryNote);
}
}

+ 57
- 4
common/logic/Order/Order/Service/OrderBuilder.php Ver fichero

@@ -10,6 +10,8 @@ use common\logic\Config\TaxRate\Model\TaxRate;
use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Distribution\Distribution\Repository\DistributionRepository;
use common\logic\Distribution\Distribution\Service\DistributionSolver;
use common\logic\Document\DeliveryNote\Model\DeliveryNote;
use common\logic\Document\DeliveryNote\Service\DeliveryNoteBuilder;
use common\logic\Document\Document\Model\Document;
use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Repository\OrderRepository;
@@ -30,6 +32,7 @@ use common\logic\Subscription\Subscription\Service\SubscriptionSolver;
use common\logic\User\CreditHistory\Model\CreditHistory;
use common\logic\User\CreditHistory\Service\CreditHistoryBuilder;
use common\logic\User\CreditHistory\Repository\CreditHistoryRepository;
use common\logic\User\User\Repository\UserRepository;
use common\logic\User\User\Service\UserSolver;
use common\logic\User\UserProducer\Repository\UserProducerRepository;
use yii\web\NotFoundHttpException;
@@ -54,6 +57,8 @@ class OrderBuilder extends AbstractBuilder
protected SubscriptionSolver $subscriptionSolver;
protected ProductSolver $productSolver;
protected DistributionSolver $distributionSolver;
protected UserRepository $userRepository;
protected DeliveryNoteBuilder $deliveryNoteBuilder;

public function loadDependencies(): void
{
@@ -75,6 +80,8 @@ class OrderBuilder extends AbstractBuilder
$this->subscriptionSolver = $this->loadService(SubscriptionSolver::class);
$this->productSolver = $this->loadService(ProductSolver::class);
$this->distributionSolver = $this->loadService(DistributionSolver::class);
$this->userRepository = $this->loadService(UserRepository::class);
$this->deliveryNoteBuilder = $this->loadService(DeliveryNoteBuilder::class);
}

public function instanciateOrder(Distribution $distribution): Order
@@ -130,7 +137,7 @@ class OrderBuilder extends AbstractBuilder
*/
public function createAllOrdersFromSubscriptions(string $date, bool $force = false): array
{
$orderArray = [];
$ordersSubscriptionsArray = [];
$distribution = $this->distributionRepository->findOneDistribution(date('Y-m-d', strtotime($date)));

if ($distribution) {
@@ -138,12 +145,15 @@ class OrderBuilder extends AbstractBuilder
$subscriptionArray = $this->subscriptionRepository->findSubscriptionsByDate($date);
foreach ($subscriptionArray as $subscription) {
if (!$this->subscriptionSolver->hasOrderAlreadyExist($subscription, $orderArray)) {
$this->createOrderFromSubscription($subscription, $date, $force);
$order = $this->createOrderFromSubscription($subscription, $date, $force);
if ($order) {
$ordersSubscriptionsArray[] = $order;
}
}
}
}

return $orderArray;
return $ordersSubscriptionsArray;
}

public function updateOrdersIncomingDistributionsFromSubscription(Subscription $subscription, $update = false): array
@@ -195,7 +205,7 @@ class OrderBuilder extends AbstractBuilder
$countOrdersDeleted = 0;
if ($ordersArray && count($ordersArray)) {
foreach ($ordersArray as $order) {
if($this->distributionSolver->isDistributionAvailable($order->distribution)) {
if ($this->distributionSolver->isDistributionAvailable($order->distribution)) {
$theOrder = $this->orderRepository->findOneOrderById($order->id);
$this->initOrder($theOrder);

@@ -601,4 +611,47 @@ class OrderBuilder extends AbstractBuilder
}
}

public function updateOrderDeliveryNote(Order $order, DeliveryNote $deliveryNote): bool
{
$order->id_delivery_note = $deliveryNote->id;
return $order->save();
}

public function assignAllOrdersDeliveryNote(array $idOrders, DeliveryNote $deliveryNote)
{
$this->unassignAllOrdersDeliveryNote($deliveryNote);

foreach ($idOrders as $idOrder) {
$order = $this->orderRepository->findOneOrderById((int)$idOrder);
if ($order) {
$this->assignOrderDeliveryNote($order, $deliveryNote);
}
}
}

public function assignOrderDeliveryNote(Order $order, DeliveryNote $deliveryNote)
{
if ($this->orderSolver->isOrderFromProducer($order)) {
$this->updateOrderDeliveryNote($order, $deliveryNote);

$order = $this->orderRepository->findOneOrderById($order->id);
$user = $this->userRepository->findOneUserById($deliveryNote->id_user);
$userProducer = $this->userProducerRepository->findOneUserProducer($user);
$this->updateOrderInvoicePrices($order,
[
'user' => $user,
'user_producer' => $userProducer,
'point_sale' => $order->pointSale
]);
}
}

public function unassignAllOrdersDeliveryNote(DeliveryNote $deliveryNote)
{
Order::updateAll([
'id_delivery_note' => null
], [
'id_delivery_note' => $deliveryNote->id
]);
}
}

+ 24
- 4
common/logic/Order/Order/Service/OrderSolver.php Ver fichero

@@ -6,6 +6,7 @@ use common\helpers\Price;
use common\logic\AbstractService;
use common\logic\Document\Document\Service\DocumentSolver;
use common\logic\Order\Order\Model\Order;
use common\logic\Producer\Producer\Model\Producer;
use common\logic\Product\Product\Model\Product;
use common\logic\SolverInterface;
use common\logic\User\CreditHistory\Model\CreditHistory;
@@ -123,9 +124,24 @@ class OrderSolver extends AbstractService implements SolverInterface

public function isLinkedToValidDocument(Order $order): bool
{
return ($order->deliveryNote && $this->documentSolver->isStatusValid($order->deliveryNote))
|| ($order->quotation && $this->documentSolver->isStatusValid($order->quotation))
|| ($order->invoice && $this->documentSolver->isStatusValid($order->invoice));
return ($this->isLinkedToValidDeliveryNote($order)
|| $this->isLinkedToValidQuotation($order)
|| $this->isLinkedToValidInvoice($order));
}

public function isLinkedToValidDeliveryNote(Order $order): bool
{
return $order->deliveryNote && $this->documentSolver->isStatusValid($order->deliveryNote);
}

public function isLinkedToValidQuotation(Order $order): bool
{
return $order->quotation && $this->documentSolver->isStatusValid($order->quotation);
}

public function isLinkedToValidInvoice(Order $order): bool
{
return $order->invoice && $this->documentSolver->isStatusValid($order->invoice);
}

public function getCommentReport(Order $order): string
@@ -361,7 +377,6 @@ class OrderSolver extends AbstractService implements SolverInterface
}
}

// belongsToUser
public function isOrderBelongsToUser(Order $order, User $user = null): bool
{
if($user) {
@@ -371,6 +386,11 @@ class OrderSolver extends AbstractService implements SolverInterface
return false;
}

public function isOrderFromProducer(Order $order = null): bool
{
return $order && $order->distribution->id_producer == $this->getProducerContextId();
}

/**
* Retourne les informations relatives à la commande au format JSON.
*/

+ 10
- 2
common/logic/Producer/Producer/Model/Producer.php Ver fichero

@@ -151,6 +151,9 @@ class Producer extends ActiveRecordCommon
'option_online_payment_minimum_amount',
'option_document_price_decimals',
'option_billing_reduction_percentage',
'dolibarr_socid',
'dolibarr_product_id',
'option_weeks_distributions_activated_in_advance'
],
'integer'
],
@@ -253,7 +256,8 @@ class Producer extends ActiveRecordCommon
'option_billing_reduction',
'option_export_evoliz',
'option_display_message_new_opendistrib_version',
'option_billing_permanent_transfer'
'option_billing_permanent_transfer',
'option_export_display_column_delivery_note'
],
'boolean'
],
@@ -415,7 +419,11 @@ class Producer extends ActiveRecordCommon
'option_testimony' => 'Témoignage',
'option_time_saved' => 'Temps gagné / semaine',
'contact_email' => 'Email de contact',
'admin_comment' => 'Commentaire'
'admin_comment' => 'Commentaire',
'dolibarr_socid' => 'Dolibarr : id user',
'dolibarr_product_id' => 'Dolibarr : id produit',
'option_export_display_column_delivery_note' => "Récapitulatif PDF : afficher une colonne bon de livraison",
'option_weeks_distributions_activated_in_advance' => "Semaines de distributions à activer à l'avance",
];
}


+ 7
- 1
common/logic/Producer/Producer/Repository/ProducerRepository.php Ver fichero

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

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

/**
* Retourne le CA du producteur pour un mois donné
*/
@@ -241,7 +247,7 @@ class ProducerRepository extends AbstractRepository
{
if (strlen($config)) {
if (!$idProducer) {
$idProducer = GlobalParam::getCurrentProducerId();
$idProducer = $this->getProducerContextId();
}

$producer = $this->findOneProducerById($idProducer);

+ 52
- 0
common/logic/Producer/Producer/Service/DolibarrProducerUtils.php Ver fichero

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

namespace common\logic\Producer\Producer\Service;

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

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

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

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

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

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

return $idProduct;
}
}

+ 4
- 4
common/logic/Producer/Producer/Service/ProducerBuilder.php Ver fichero

@@ -64,15 +64,15 @@ class ProducerBuilder extends AbstractBuilder
/**
* Lie un utilisateur à un producteur.
*/
public function addUser(User $user, Producer $producer, int $bookmark = 1): UserProducer
public function addUser(User $user, Producer $producer, bool $bookmark = true, bool $newsletter = true): UserProducer
{
$userProducer = $this->userProducerBuilder->createUserProducerIfNotExist($user, $producer, $bookmark);
$userProducer = $this->userProducerBuilder->createUserProducerIfNotExist($user, $producer, $bookmark, $newsletter);

if (!$userProducer->getActive()) {
$userProducer->setActive(1);
$userProducer->setActive(true);
}

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

return $userProducer;
}

+ 3
- 1
common/logic/Producer/Producer/Wrapper/ProducerContainer.php Ver fichero

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

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


+ 2
- 0
common/logic/Producer/Producer/Wrapper/ProducerManager.php Ver fichero

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

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

+ 2
- 0
common/logic/Producer/ProducerPriceRange/Model/ProducerPriceRange.php Ver fichero

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

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

+ 12
- 0
common/logic/Producer/ProducerPriceRange/Repository/ProducerPriceRangeRepository.php Ver fichero

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

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

return null;
}

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

+ 1
- 1
common/logic/Ticket/Ticket/Service/TicketSolver.php Ver fichero

@@ -71,7 +71,7 @@ class TicketSolver extends AbstractSolver
return false;
}

public function isTicketUnread(Ticket $ticket, User $user): int
public function isTicketUnread(Ticket $ticket, User $user): bool
{
$ticketUser = $this->getTicketUser($ticket, $user);


+ 2
- 2
common/logic/User/CreditHistory/Service/CreditHistorySolver.php Ver fichero

@@ -51,9 +51,9 @@ class CreditHistorySolver extends AbstractService implements SolverInterface
} elseif (CreditHistory::TYPE_CREDIT == $type) {
$str = 'Crédit';
} elseif (CreditHistory::TYPE_PAYMENT == $type) {
$str = 'Paiement';
$str = 'Débit';
} elseif (CreditHistory::TYPE_REFUND == $type) {
$str = 'Remboursement';
$str = 'Recrédit';
} elseif (CreditHistory::TYPE_DEBIT == $type) {
$str = 'Débit';
}

+ 4
- 2
common/logic/User/User/Model/User.php Ver fichero

@@ -70,6 +70,7 @@ class User extends ActiveRecordCommon implements IdentityInterface
var $user_groups = [];
var $one_name;
var $product_price_percent;
var $newsletter;

/**
* @inheritdoc
@@ -95,7 +96,7 @@ class User extends ActiveRecordCommon implements IdentityInterface
public function rules()
{
return [
[['no_mail', 'mail_distribution_monday', 'mail_distribution_tuesday', 'mail_distribution_wednesday', 'mail_distribution_thursday', 'mail_distribution_friday', 'mail_distribution_saturday', 'mail_distribution_sunday', 'is_main_contact'], 'boolean'],
[['no_mail', 'mail_distribution_monday', 'mail_distribution_tuesday', 'mail_distribution_wednesday', 'mail_distribution_thursday', 'mail_distribution_friday', 'mail_distribution_saturday', 'mail_distribution_sunday', 'is_main_contact', 'newsletter'], 'boolean'],
[['lastname', 'name', 'phone', 'address', 'type', 'name_legal_person', 'evoliz_code'], 'string'],
['lastname', 'verifyOneName', 'skipOnError' => false, 'skipOnEmpty' => false],
['email', 'email', 'message' => 'Cette adresse email n\'est pas valide'],
@@ -137,7 +138,8 @@ class User extends ActiveRecordCommon implements IdentityInterface
'is_main_contact' => 'Contact principal',
'product_price_percent' => 'Prix produits : pourcentage',
'user_groups' => "Groupes d'utilisateurs",
'evoliz_code' => 'Code client Evoliz'
'evoliz_code' => 'Code client Evoliz',
'newsletter' => "Inscrit au bulletin d'information"
];
}


+ 11
- 9
common/logic/User/User/Model/UserSearch.php Ver fichero

@@ -62,9 +62,6 @@ class UserSearch extends User

public function search($params = [])
{
$userRepository = UserRepository::getInstance();
$optionsSearch = $userRepository->getDefaultOptionsSearch();

$query = User::find()
->select(
'`user`.id, '
@@ -91,14 +88,24 @@ class UserSearch extends User
. '`user`.type, '
. '(SELECT COUNT(*) FROM `order` WHERE `user`.id = `order`.id_user) AS count_orders');

$query->innerJoin('user_producer', 'user.id = user_producer.id_user AND user_producer.id_producer = :id_producer AND user_producer.active = 1', [':id_producer' => GlobalParam::getCurrentProducerId()]);

$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => ['attributes' => ['username', 'credit', 'orders']],
'sort' => [
'attributes' => ['username', 'credit', 'orders'],
'defaultOrder' => ['created_at' => SORT_DESC]
],
'pagination' => [
'pageSize' => 20,
],
]);

$dataProvider->sort->attributes['created_at'] = [
'asc' => ['user.created_at' => SORT_ASC],
'desc' => ['user.created_at' => SORT_DESC],
];

$dataProvider->sort->attributes['username'] = [
'asc' => ['user.lastname' => SORT_ASC, 'user.name' => SORT_ASC],
'desc' => ['user.lastname' => SORT_DESC, 'user.name' => SORT_DESC],
@@ -114,10 +121,7 @@ class UserSearch extends User
return $dataProvider;
}

$query->innerJoin('user_producer', 'user.id = user_producer.id_user AND user_producer.id_producer = :id_producer AND user_producer.active = 1', [':id_producer' => GlobalParam::getCurrentProducerId()]);

if (isset($this->id_point_sale) && $this->id_point_sale) {
$pointSale = PointSale::findOne(['id' => $this->id_point_sale]);
$query->innerJoin('user_point_sale', 'user.id = user_point_sale.id_user AND user_point_sale.id_point_sale = :id_point_sale', [':id_point_sale' => $this->id_point_sale]);
}

@@ -142,8 +146,6 @@ class UserSearch extends User
['like', 'user.name_legal_person', $this->username],
]);

$query->orderBy('user.created_at DESC');

return $dataProvider;
}


+ 1
- 1
common/logic/User/User/Repository/UserRepository.php Ver fichero

@@ -91,7 +91,7 @@ class UserRepository extends AbstractRepository
->from('user');

$active = (isset($params['inactive']) && $params['inactive']) ? 0 : 1;
$query->innerJoin('user_producer', 'user.id = user_producer.id_user AND user_producer.active = ' . $active . ' AND user_producer.id_producer = :id_producer', [':id_producer' => $params['id_producer']]);
$query->innerJoin('user_producer', 'user.id = user_producer.id_user AND user_producer.active = ' . $active . ' AND user_producer.newsletter = 1 AND user_producer.id_producer = :id_producer', [':id_producer' => $params['id_producer']]);

if (isset($params['id_point_sale']) && $params['id_point_sale']) {
$point_sale = PointSale::findOne(['id' => $params['id_point_sale']]);

+ 49
- 0
common/logic/User/User/Service/NewsletterUtils.php Ver fichero

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

namespace common\logic\User\User\Service;

use common\logic\AbstractService;
use common\logic\User\User\Model\User;
use common\logic\User\UserProducer\Repository\UserProducerRepository;
use common\logic\User\UserProducer\Service\UserProducerBuilder;
use common\logic\UtilsInterface;

class NewsletterUtils extends AbstractService implements UtilsInterface
{
protected UserProducerRepository $userProducerRepository;
protected UserProducerBuilder $userProducerBuilder;

public function loadDependencies(): void
{
$this->userProducerRepository = $this->loadService(UserProducerRepository::class);
$this->userProducerBuilder = $this->loadService(UserProducerBuilder::class);
}

public function isUserSubscribedNewsletter(User $user = null): bool
{
if($user) {
$userProducer = $this->userProducerRepository->findOneUserProducer($user);
if($userProducer && $userProducer->newsletter) {
return true;
}
}

return false;
}

public function subscribeUserNewsletter(User $user): bool
{
$userProducer = $this->userProducerBuilder->createUserProducerIfNotExist($user, $this->getProducerContext());
return $this->userProducerBuilder->updateUserProducerNewsletter($userProducer, true);
}

public function unsubscribeUserNewsletter(User $user): bool
{
$userProducer = $this->userProducerRepository->findOneUserProducer($user);
if($userProducer) {
return $this->userProducerBuilder->updateUserProducerNewsletter($userProducer, false);
}

return false;
}
}

+ 5
- 0
common/logic/User/User/Service/UserSolver.php Ver fichero

@@ -137,6 +137,11 @@ class UserSolver extends AbstractService implements SolverInterface
return null;
}

public function isCurrentGuest(): bool
{
return \Yii::$app->user->isGuest;
}

/**
* Retourne si l'utilisateur courant est connecté ou non.
*

+ 1
- 1
common/logic/User/User/Service/UsersCreditCsvGenerator.php Ver fichero

@@ -41,7 +41,7 @@ class UsersCreditCsvGenerator extends AbstractGenerator
$this->userSolver->getUsernameFromArray($user, true),
$user['email'],
$user['phone'],
Price::format($user['credit']),
CSV::formatPrice($user['credit']),
];
}


+ 2
- 0
common/logic/User/User/Wrapper/UserContainer.php Ver fichero

@@ -5,6 +5,7 @@ namespace common\logic\User\User\Wrapper;
use common\logic\AbstractContainer;
use common\logic\User\User\Repository\UserRepository;
use common\logic\User\User\Repository\UserRepositoryQuery;
use common\logic\User\User\Service\NewsletterUtils;
use common\logic\User\User\Service\UserBuilder;
use common\logic\User\User\Service\UserDefinition;
use common\logic\User\User\Service\UsersCreditCsvGenerator;
@@ -23,6 +24,7 @@ class UserContainer extends AbstractContainer
UserBuilder::class,
UsersCreditCsvGenerator::class,
UserUtils::class,
NewsletterUtils::class,
];
}


+ 2
- 0
common/logic/User/User/Wrapper/UserManager.php Ver fichero

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

use common\logic\AbstractManager;
use common\logic\User\User\Repository\UserRepository;
use common\logic\User\User\Service\NewsletterUtils;
use common\logic\User\User\Service\UserBuilder;
use common\logic\User\User\Service\UserDefinition;
use common\logic\User\User\Service\UsersCreditCsvGenerator;
@@ -17,6 +18,7 @@ use common\logic\User\User\Service\UserUtils;
* @mixin UserBuilder
* @mixin UserUtils
* @mixin UsersCreditCsvGenerator
* @mixin NewsletterUtils
*/
class UserManager extends AbstractManager
{

+ 8
- 1
common/logic/User/UserProducer/Model/UserProducer.php Ver fichero

@@ -64,7 +64,7 @@ class UserProducer extends ActiveRecordCommon
return [
[['id_user', 'id_producer'], 'required'],
[['id_user', 'id_producer', 'product_price_percent'], 'integer'],
[['active', 'bookmark', 'credit_active'], 'boolean'],
[['active', 'bookmark', 'credit_active', 'newsletter'], 'boolean'],
[['credit', 'product_price_percent'], 'double'],
];
}
@@ -152,6 +152,13 @@ class UserProducer extends ActiveRecordCommon
return $this;
}

public function setNewsletter(bool $newsletter): self
{
$this->newsletter = $newsletter;

return $this;
}

public function getCredit(): float
{
return $this->credit;

+ 13
- 6
common/logic/User/UserProducer/Service/UserProducerBuilder.php Ver fichero

@@ -32,30 +32,31 @@ class UserProducerBuilder extends AbstractBuilder
$this->orderSolver = $this->loadService(OrderSolver::class);
}

public function instanciateUserProducer(User $user, Producer $producer, int $bookmark = 1)
public function instanciateUserProducer(User $user, Producer $producer, bool $bookmark = true, bool $newsletter = true)
{
$userProducer = new UserProducer();

$userProducer->populateUser($user);
$userProducer->populateproducer($producer);
$userProducer->setCredit(0);
$userProducer->setActive(1);
$userProducer->setActive(true);
$userProducer->setBookmark($bookmark);
$userProducer->setNewsletter($newsletter);

return $userProducer;
}

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

public function createUserProducerIfNotExist(User $user, Producer $producer, int $bookmark = 1): UserProducer
public function createUserProducerIfNotExist(User $user, Producer $producer, bool $bookmark = true, bool $newsletter = true): UserProducer
{
return $this->userProducerRepository->findOneUserProducer($user)
?? $this->createUserProducer($user, $producer, $bookmark);
?? $this->createUserProducer($user, $producer, $bookmark, $newsletter);
}

public function updateCredit(CreditHistory $creditHistory): void
@@ -176,4 +177,10 @@ class UserProducerBuilder extends AbstractBuilder
$userProducer->bookmark = 0;
return $this->update($userProducer);
}

public function updateUserProducerNewsletter(UserProducer $userProducer, bool $newsletter)
{
$userProducer->newsletter = $newsletter;
return $this->update($userProducer);
}
}

+ 1
- 1
common/logic/UtilsInterface.php Ver fichero

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

}
}

+ 49
- 0
common/mail/newOpinionAdmin-html.php Ver fichero

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

/**
Copyright distrib (2018)

contact@opendistrib.net

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

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

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

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

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

use yii\helpers\Html;

?>

<p>Un nouvel avis vient d'être envoyé par <em><?= Html::encode($username) ?></em> :</p><br />

<div>
<?= Html::encode($message) ?>
</div>



+ 47
- 0
common/mail/newOpinionAdmin-text.php Ver fichero

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

/**
Copyright distrib (2018)

contact@opendistrib.net

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

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

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

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

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

use yii\helpers\Html;

?>

Un nouvel avis vient d'être envoyé par <?= Html::encode($username) ?> :

<?= Html::encode($message) ?>



+ 33
- 0
common/versions/23.9.B.php Ver fichero

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

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

version(
'11/09/2023',
[
[
"[Site & espace producteur] Avis & suggestions : possibilité pour les clients d'envoyer des avis et suggestions à l'administrateur",
"[Administration et espace producteur] Bulletins d'informations : gestion inscription / désinscription",
"[Administration] Distributions > Commandes : possibilité de générer un BL pour une commande via le bouton 'Action'",
"[Administration] Crédit : statut 'Payé' remplacé par 'Débité'",
"[Administration] Distributions > Récapitulatif commandes : ajout d'une colonne BL (paramétrable dans Paramètres > Commandes > Exports)",
"[Administration] Distributions : activation automatique de X semaines à l'avance (paramétrable dans Paramètres > Commandes > Divers)"
],
[
"[Administration] Utilisateurs > Crédit : formatage du montant du crédit dans les exports CSV",
"[Administration] Utilisateurs > Liste : correctif tri par crédit"
]
],
[
[
"[Administration] Header > liste producteurs : champs de recherche rapide",
"[Administration] Dolibarr : génération automatique des factures producteurs"
],
[
"[Administration] Distributions : refactoring gestion des bons de livraisons",
"[Administration] Tickets admin : flag pour savoir si un ticket a été lu par le producteur"
]
],
);

?>

+ 3
- 1
composer.json Ver fichero

@@ -34,7 +34,9 @@
"loveorigami/yii2-bootstrap-toggle": "*",
"justcoded/yii2-event-listener": "*",
"ext-pdo": "*",
"weluse/yii2-mailjet": "^0.2.0"
"weluse/yii2-mailjet": "^0.2.0",
"ext-json": "*",
"ext-curl": "*"
},
"require-dev": {
"yiisoft/yii2-codeception": "*",

+ 28
- 0
console/commands/ActiveDistributionsInAdvanceController.php Ver fichero

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

namespace console\commands;

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

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

$producersArray = $producerManager->findProducersActive();
foreach($producersArray as $producer) {
\Yii::$app->logic->setProducerContext($producer);
$weeksDistributionsActivatedInAdvance = $producerManager->getConfig('option_weeks_distributions_activated_in_advance');
if($weeksDistributionsActivatedInAdvance) {
$date = new \DateTime('+'.$weeksDistributionsActivatedInAdvance.' weeks');
$distributionManager->activeDistributionByDate($date);
}
}
}
}

?>

+ 27
- 0
console/migrations/m230904_064216_add_column_user_producer_newsletter.php Ver fichero

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

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

/**
* Class m230904_064216_add_column_user_producer_newsletter
*/
class m230904_064216_add_column_user_producer_newsletter extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('user_producer', 'newsletter', Schema::TYPE_BOOLEAN);
$this->execute('UPDATE user_producer SET newsletter = 1;');
}

/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropColumn('user_producer', 'newsletter');
}
}

+ 30
- 0
console/migrations/m230905_091112_add_columns_dolibarr.php Ver fichero

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

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

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

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

+ 26
- 0
console/migrations/m230906_060202_add_column_producer_option_export_display_column_delivery_note.php Ver fichero

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

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

/**
* Class m230906_060202_add_column_producer_option_export_display_column_delivery_note
*/
class m230906_060202_add_column_producer_option_export_display_column_delivery_note extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('producer', 'option_export_display_column_delivery_note', Schema::TYPE_BOOLEAN);
}

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

+ 26
- 0
console/migrations/m230908_085432_add_column_producer_option_weeks_distributions_activated_in_advance.php Ver fichero

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

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

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

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

+ 27
- 14
frontend/controllers/SiteController.php Ver fichero

@@ -39,6 +39,7 @@
namespace frontend\controllers;

use common\helpers\GlobalParam;
use frontend\forms\OpinionForm;
use frontend\forms\ProducerCodeForm;
use GuzzleHttp\Client;
use Yii;
@@ -82,6 +83,9 @@ class SiteController extends FrontendController
'roles' => ['@'],
],
],
'denyCallback' => function($rule, $action) {
return $this->redirect('index');
}
],
'verbs' => [
'class' => VerbFilter::class,
@@ -294,22 +298,16 @@ class SiteController extends FrontendController
public function actionContact()
{
$model = new ContactForm();
$messageSent = false;
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
if ($model->sendEmail(Yii::$app->parameterBag->get('adminEmail'))) {
$this->setFlash('success', 'Votre message a bien été envoyé. Nous vous répondrons dès que possible.');
}
else {
$this->setFlash('error', 'Il y a eu une erreur lors de l\'envoi de votre message.');
}

return $this->refresh();
}
else {
return $this->render('contact', [
'model' => $model,
]);
$model->sendEmail(Yii::$app->parameterBag->get('adminEmail'));
$messageSent = true;
}

return $this->render('contact', [
'model' => $model,
'messageSent' => $messageSent,
]);
}

/**
@@ -501,6 +499,21 @@ class SiteController extends FrontendController
]);
}

public function actionOpinion()
{
$opinionFormModel = new OpinionForm();
$opinionSent = false;
if ($opinionFormModel->load(Yii::$app->request->post()) && $opinionFormModel->validate()) {
$this->getOpinionManager()->sendOpinionEmailAdmin($opinionFormModel, $this->getUserCurrent());
$opinionSent = true;
}

return $this->render('opinion', [
'model' => $opinionFormModel,
'opinionSent' => $opinionSent
]);
}

/**
* Affiche les mentions légales.
*/

+ 87
- 0
frontend/forms/OpinionForm.php Ver fichero

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

/**
Copyright distrib (2018)

contact@opendistrib.net

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

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

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

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

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

namespace frontend\forms;

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

/**
* ContactForm is the model behind the contact form.
*/
class OpinionForm extends Model
{
public $name;
public $email;
public $message;
public $verifyCode;
public $isTest;

/**
* @inheritdoc
*/
public function rules()
{
$userManager = UserManager::getInstance();
return [
[['message'], 'required', 'message' => 'Champs obligatoire'],
[['name', 'email'], 'required', 'message' => 'Champs obligatoire', 'when' => function($model) use($userManager) {
return $userManager->isCurrentGuest();
}],
['email', 'email', 'message' => 'Email incorrect'],
['isTest', 'string'],
['verifyCode', 'captcha', 'message' => 'Veuillez recopier le code de vérification', 'when' => function($model) use($userManager) {
return $model->isTest != 'isTest' && $userManager->isCurrentGuest();
}],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'name' => 'Nom',
'email' => 'Email',
'message' => 'Message',
'verifyCode' => 'Code de vérification',
];
}
}

+ 4
- 2
frontend/forms/SignupForm.php Ver fichero

@@ -70,6 +70,7 @@ class SignupForm extends Model
public $id_tax_rate_default;
public $verifyCode;
public $is_test;
public $newsletter = true;

/**
* @inheritdoc
@@ -96,7 +97,7 @@ class SignupForm extends Model
[['name', 'lastname', 'phone', 'option_user_producer'], 'string', 'min' => 2, 'max' => 255],
['password', 'required', 'message' => 'Champs obligatoire'],
['password', 'string', 'min' => 6, 'tooShort' => 'Votre mot de passe doit contenir au moins 6 caractères'],
['is_producer', 'boolean'],
[['is_producer', 'newsletter'], 'boolean'],
['cgv', 'boolean'],
['cgv', function ($attribute, $params) {
$cgv = $this->$attribute;
@@ -222,6 +223,7 @@ class SignupForm extends Model
// 'free_price' => 'Prix libre',
'id_tax_rate_default' => 'TVA par défaut',
'verifyCode' => 'Code de vérification',
'newsletter' => "S'abonner au bulletin d'information de ce producteur"
];
}

@@ -253,7 +255,7 @@ class SignupForm extends Model

\Yii::$app->logic->setProducerContext($producer);

$producerManager->addUser($user, $producer);
$producerManager->addUser($user, $producer, true, $this->newsletter);
$userManager->sendEmailSignup($user, $producer);

return $user;

+ 1
- 0
frontend/views/layouts/main.php Ver fichero

@@ -169,6 +169,7 @@ if ($userManager->isCurrentProducer()) {
<footer id="footer">
<div class="container">
<a href="<?php echo $this->getUrlManager()->createUrl('site/service'); ?>">Fonctionnalités, services & tarifs</a> <span class="bull">&bull;</span>
<a href="<?php echo $this->getUrlManager()->createUrl('site/opinion'); ?>">Avis & suggestions</a> <span class="bull">&bull;</span>
<a href="<?php echo $this->getUrlManager()->createUrl('site/mentions'); ?>">Mentions légales</a> <span class="bull">&bull;</span>
<a href="<?php echo $this->getUrlManager()->createUrl('site/cgv'); ?>">Conditions générales de service</a> <span class="bull">&bull;</span>
<a href="<?php echo $this->getUrlManager()->createUrl('site/source-code'); ?>">Code source</a>

+ 27
- 21
frontend/views/site/contact.php Ver fichero

@@ -45,34 +45,40 @@ use yii\captcha\Captcha;

$this->setTitle('Contact');
$this->setIcon('envelope');
$this->setMeta('description', 'Pour toute remarque ou demande d\'information, nous vous proposons d\'utiliser ce formulaire de contact.') ;
$this->setMeta('description', 'Pour toute demande d\'information, nous vous proposons d\'utiliser ce formulaire de contact.') ;

$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-contact">
<div class="row">
<div class="col-lg-5">
<div class="alert alert-info">
Ce formulaire de contact vous permet de joindre le développeur de la plateforme Opendistrib.
Si vous souhaitez joindre un producteur, merci de le faire directement depuis son espace producteur.
</div>
<div class="panel panel-default">
<div class="panel-body">
<?php $form = ActiveForm::begin(['id' => 'contact-form']); ?>
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'email') ?>
<?= $form->field($model, 'subject') ?>
<?= $form->field($model, 'body')->textArea(['rows' => 6]) ?>
<?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
]) ?>
<?= $form->field($model, 'isTest')->hiddenInput() ?>
<div class="form-group submit">
<?= Html::submitButton('Envoyer', ['class' => 'btn btn-primary', 'name' => 'contact-button']) ?>
<div class="col-lg-6">
<?php if($messageSent): ?>
<div class="alert alert-success text-center">
Merci pour votre message, je vous réponds dès que possible.
</div>
<?php else: ?>
<div class="alert alert-warning">
Ce formulaire de contact vous permet de joindre le développeur de la plateforme Opendistrib.
Si vous souhaitez joindre un producteur, merci de le faire directement depuis son espace producteur.
</div>
<div class="panel panel-default">
<div class="panel-body">
<?php $form = ActiveForm::begin(['id' => 'contact-form']); ?>
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'email') ?>
<?= $form->field($model, 'subject') ?>
<?= $form->field($model, 'body')->textArea(['rows' => 6]) ?>
<?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
]) ?>
<?= $form->field($model, 'isTest')->hiddenInput() ?>
<div class="form-group submit">
<?= Html::submitButton('Envoyer', ['class' => 'btn btn-primary', 'name' => 'contact-button']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
<?php endif; ?>
</div>
</div>


+ 87
- 0
frontend/views/site/opinion.php Ver fichero

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

/**
Copyright distrib (2018)

contact@opendistrib.net

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

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

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

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

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

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\captcha\Captcha;

/* @var $this yii\web\View */
/* @var $form yii\bootstrap\ActiveForm */

$this->setTitle('Avis & suggestions');
$this->setIcon('star');
//$this->setMeta('description', '') ;

$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-opinion">
<div class="row">
<div class="col-lg-6">
<?php if($opinionSent): ?>
<div class="alert alert-success text-center">
Merci pour votre participation, je vous fais un retour dès que possible.
</div>
<?php else: ?>
<div class="alert alert-warning">
Vous pouvez utiliser ce formulaire pour m'envoyer toutes vos remarques et suggestions d'amélioration.
</div>
<div class="panel panel-default">
<div class="panel-body">
<?php $form = ActiveForm::begin(['id' => 'opinion-form']); ?>
<?php if (Yii::$app->user->isGuest): ?>
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'email') ?>
<?php endif; ?>
<?= $form->field($model, 'message')->textArea(['rows' => 6]) ?>
<?php if (Yii::$app->user->isGuest): ?>
<?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
]) ?>
<?php endif; ?>
<?= $form->field($model, 'isTest')->hiddenInput() ?>
<div class="form-group submit">
<?= Html::submitButton('Envoyer', ['class' => 'btn btn-primary', 'name' => 'opinion-button']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
<?php endif; ?>
</div>
</div>

</div>

+ 1
- 0
frontend/views/site/producer.php Ver fichero

@@ -100,6 +100,7 @@ $this->setMeta('description', 'Veuillez vous connecter pour réserver les produi
<?= $form->field($signupForm, 'lastname') ?>
<?= $form->field($signupForm, 'name') ?>
<?= $form->field($signupForm, 'phone') ?>
<?= $form->field($signupForm, 'newsletter')->checkbox() ?>
<?php if(strlen($producer->code)): ?>
<?= $form->field($signupForm, 'code',[
'inputTemplate' => '<div class="input-group"><span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>{input}</div>',

+ 3
- 1
frontend/views/site/signup.php Ver fichero

@@ -87,7 +87,9 @@ $this->params['breadcrumbs'][] = $this->title;
<?= $form->field($model, 'cgv')->checkbox()->label('J\'accepte les <button type="button" class="btn btn-xs btn-default btn-modal-cgv" data-toggle="modal" data-target="#modal-cgv">conditions générales de service</button> et les <button type="button" class="btn btn-xs btn-default btn-modal-prices" data-toggle="modal" data-target="#modal-prices">conditions tarifaires</button>.') ?>
</div>
<div id="fields-user">
<?= $form->field($model, 'id_producer')->dropDownList($dataProducers, ['prompt' => '--','encode' => false,'options' => $optionsProducers]) ?>
<?= $form->field($model, 'id_producer')
->dropDownList($dataProducers, ['prompt' => '--','encode' => false,'options' => $optionsProducers]) ?>
<?= $form->field($model, 'newsletter')->checkbox() ?>
<div id="bloc-code-acces">
<?= $form->field($model, 'code',[
'inputTemplate' => '<div class="input-group"><span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>{input}</div>',

+ 17
- 3
frontend/web/css/screen.css Ver fichero

@@ -1326,7 +1326,7 @@ nav#menu-producer ul li a:hover {
}

/* line 1395, ../sass/screen.scss */
.site-contact .col-lg-5 {
.site-contact .col-lg-6 {
margin: 0px auto;
float: none;
}
@@ -1335,12 +1335,26 @@ nav#menu-producer ul li a:hover {
text-align: center;
}

/* line 1407, ../sass/screen.scss */
/* line 1406, ../sass/screen.scss */
.site-opinion .col-lg-6 {
margin: 0px auto;
float: none;
}
/* line 1411, ../sass/screen.scss */
.site-opinion .field-opinionform-istest {
display: none;
}
/* line 1415, ../sass/screen.scss */
.site-opinion .form-group.submit {
text-align: center;
}

/* line 1422, ../sass/screen.scss */
#site-prices .panel p {
padding-bottom: 0px;
}

/* line 1414, ../sass/screen.scss */
/* line 1429, ../sass/screen.scss */
#contact-form .field-contactform-istest {
display: none;
}

+ 14
- 0
frontend/web/js/frontend.js Ver fichero

@@ -197,8 +197,10 @@ function opendistrib_signup() {
});

opendistrib_signup_code_producer();
opendistrib_signup_newsletter();
$('#signupform-id_producer').change(function () {
opendistrib_signup_code_producer();
opendistrib_signup_newsletter();
});

// modals
@@ -231,4 +233,16 @@ function opendistrib_signup_code_producer() {
}
}

function opendistrib_signup_newsletter() {
if($('#signupform-id_producer').length) {
var $fieldNewsletter = $('.field-signupform-newsletter');
if($('#signupform-id_producer').val()) {
$fieldNewsletter.show();
}
else {
$fieldNewsletter.hide();
}
}
}



+ 16
- 1
frontend/web/sass/screen.scss Ver fichero

@@ -1392,7 +1392,7 @@ nav#menu-producer {
}

.site-contact {
.col-lg-5 {
.col-lg-6 {
margin: 0px auto;
float: none;
}
@@ -1402,6 +1402,21 @@ nav#menu-producer {
}
}

.site-opinion {
.col-lg-6 {
margin: 0px auto;
float: none;
}

.field-opinionform-istest {
display: none;
}

.form-group.submit {
text-align: center;
}
}

#site-prices {
.panel {
p {

+ 75
- 0
producer/controllers/NewsletterController.php Ver fichero

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

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

namespace producer\controllers;

class NewsletterController extends ProducerBaseController
{
public function behaviors()
{
return [];
}

public function actionIndex()
{
return $this->render('index', [
'user' => $this->getUserCurrent(),
'producer' => $this->getProducerCurrent()
]);
}

public function actionSubscribe()
{
$userManager = $this->getUserManager();
$userCurrent = $this->getUserCurrent();
$userManager->subscribeUserNewsletter($userCurrent);
$this->setFlash('success', "Votre inscription au bulletin d'information a bien été prise en compte.");
return $this->redirect('index');
}

public function actionUnsubscribe()
{
$userManager = $this->getUserManager();
$userCurrent = $this->getUserCurrent();
$userManager->unsubscribeUserNewsletter($userCurrent);
$this->setFlash('success', "À partir de maintenant, vous ne recevrez plus d'email de la part de ce producteur.");
return $this->redirect('index');
}
}

?>

+ 8
- 6
producer/views/layouts/main.php Ver fichero

@@ -128,6 +128,7 @@ if (!Yii::$app->user->isGuest) {
->count();
$labelOrders = $countOrders > 0 ? 'success' : 'default';

$isUserSubscribedNewsletter = $userManager->isUserSubscribedNewsletter($userCurrent);

echo Nav::widget([
'encodeLabels' => false,
@@ -168,17 +169,17 @@ if (!Yii::$app->user->isGuest) {
'visible' => !Yii::$app->user->isGuest && $producer->credit,
'active' => $this->getControllerAction() == 'credit/history',
],
[
'label' => '<span class="glyphicon glyphicon-bullhorn"></span> Bulletin d\'information <span class="label label-'.($isUserSubscribedNewsletter ? 'success' : 'danger').'">'.($isUserSubscribedNewsletter ? 'Oui' : 'Non').'</span>',
'url' => $this->getUrlManagerProducer()->createUrl(['newsletter/index']),
'visible' => !Yii::$app->user->isGuest,
'active' => $this->getControllerAction() == 'newsletter/index',
],
[
'label' => '<span class="glyphicon glyphicon-envelope"></span> Contact',
'url' => $this->getUrlManagerProducer()->createUrl(['site/contact']),
'active' => $this->getControllerAction() == 'site/contact',
],
/*[
'label' => '<span class="glyphicon glyphicon-cog"></span> Administration',
'url' => $this->getUrlManagerBackend()->createAbsoluteUrl(['site/index']),
'visible' => isset(Yii::$app->user->identity) && $this->getUserManager()->isProducer(\Yii::$app->user->identity),
'options' => ['id' => 'btn-administration']
],*/
],
]);
?>
@@ -276,6 +277,7 @@ if (!Yii::$app->user->isGuest) {
<footer id="footer" class="container">
<div class="content">
<a href="<?php echo \Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/index']); ?>">Opendistrib</a> &bull;
<a href="<?php echo \Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/opinion']); ?>">Avis & suggestions</a> &bull;
<a href="<?php echo \Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/mentions']); ?>">Mentions
légales</a> &bull;
<a href="<?php echo \Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/cgv']); ?>">CGS</a> &bull;

+ 71
- 0
producer/views/newsletter/index.php Ver fichero

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

/**
Copyright distrib (2018)

contact@opendistrib.net

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

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

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

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

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

use common\logic\User\User\Wrapper\UserManager;
use yii\helpers\Html;

$userManager = UserManager::getInstance();

$this->setTitle("Bulletin d'information");

?>
<div class="newsletter-index">
<?php if($userManager->isUserSubscribedNewsletter($user)): ?>
<div class="panel panel-default">
<div class="panel-body">
Vous êtes inscrit au bulletin d'information <strong><?= Html::encode($producer->name) ?></strong>.
</div>
</div>
<p>
<a class="btn btn-danger" href="<?= $this->getUrlManagerProducer()->createUrl(['newsletter/unsubscribe']) ?>">
Me désinscrire
</a>
</p>
<?php else: ?>
<div class="panel panel-default">
<div class="panel-body">
Vous n'êtes pas inscrit au bulletin d'information <strong><?= Html::encode($producer->name) ?></strong>.
</div>
</div>
<p>
<a class="btn btn-success" href="<?= $this->getUrlManagerProducer()->createUrl(['newsletter/subscribe']) ?>">
M'inscrire
</a>
</p>
<?php endif; ?>
</div>

+ 71
- 66
producer/web/css/screen.css Ver fichero

@@ -148,79 +148,84 @@ body {
clear: both;
}

/* line 64, ../sass/_layout.scss */
/* line 63, ../sass/_layout.scss */
.panel strong {
font-weight: bold;
}

/* line 68, ../sass/_layout.scss */
.modal-backdrop.in {
z-index: 10;
}

/* line 69, ../sass/_layout.scss */
/* line 73, ../sass/_layout.scss */
#section-user-top .navbar-default {
background-color: white;
}

/* line 74, ../sass/_layout.scss */
/* line 78, ../sass/_layout.scss */
#main {
position: relative;
}
/* line 76, ../sass/_layout.scss */
/* line 80, ../sass/_layout.scss */
#main .btn-primary {
background-color: #F39C12;
border: solid 1px #F39C12;
color: white;
}
/* line 81, ../sass/_layout.scss */
/* line 85, ../sass/_layout.scss */
#main .btn-primary:hover, #main .btn-primary:active, #main .btn-primary:focus {
background-color: #e08e0b;
border: solid 1px #F39C12;
color: white;
}

/* line 90, ../sass/_layout.scss */
/* line 94, ../sass/_layout.scss */
.btn {
background-image: none;
}

/* line 94, ../sass/_layout.scss */
/* line 98, ../sass/_layout.scss */
#main .alert {
background-image: none;
background-color: white;
border-bottom-width: 3px;
}

/* line 102, ../sass/_layout.scss */
/* line 106, ../sass/_layout.scss */
.alert.alert-warning a {
color: #8a6d3b;
text-decoration: underline;
}
/* line 109, ../sass/_layout.scss */
/* line 113, ../sass/_layout.scss */
.alert.alert-danger a {
color: #a94442;
text-decoration: underline;
}

/* line 119, ../sass/_layout.scss */
/* line 123, ../sass/_layout.scss */
ul.pagination li.active a {
background-color: #F39C12;
border: solid 1px #F39C12;
}
/* line 123, ../sass/_layout.scss */
/* line 127, ../sass/_layout.scss */
ul.pagination li.active a:hover {
background-color: white;
border: solid 1px white;
color: #F39C12;
}
/* line 130, ../sass/_layout.scss */
/* line 134, ../sass/_layout.scss */
ul.pagination li a {
color: #F39C12;
}
/* line 133, ../sass/_layout.scss */
/* line 137, ../sass/_layout.scss */
ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
background-color: white;
border: solid 1px white;
color: #F39C12;
}

/* line 143, ../sass/_layout.scss */
/* line 147, ../sass/_layout.scss */
.product-name-description-block .name {
font-family: "capsuularegular";
color: black;
@@ -228,28 +233,28 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
line-height: 25px;
font-weight: bold;
}
/* line 151, ../sass/_layout.scss */
/* line 155, ../sass/_layout.scss */
.product-name-description-block .other {
font-family: "capsuularegular";
color: black;
font-weight: bold;
font-size: 17px;
}
/* line 158, ../sass/_layout.scss */
/* line 162, ../sass/_layout.scss */
.product-name-description-block .description,
.product-name-description-block .description-long {
color: gray;
}
/* line 164, ../sass/_layout.scss */
/* line 168, ../sass/_layout.scss */
.product-name-description-block .description-long a {
color: #F39C12;
}
/* line 167, ../sass/_layout.scss */
/* line 171, ../sass/_layout.scss */
.product-name-description-block .description-long .content {
display: none;
}

/* line 173, ../sass/_layout.scss */
/* line 177, ../sass/_layout.scss */
#left {
background-color: #FFF8DC;
text-align: center;
@@ -257,12 +262,12 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
padding: 0px;
position: relative;
}
/* line 180, ../sass/_layout.scss */
/* line 184, ../sass/_layout.scss */
#left .fixed {
position: fixed;
display: none;
}
/* line 186, ../sass/_layout.scss */
/* line 190, ../sass/_layout.scss */
#left #logo {
position: relative;
background-color: white;
@@ -277,7 +282,7 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
text-align: center;
overflow: hidden;
}
/* line 198, ../sass/_layout.scss */
/* line 202, ../sass/_layout.scss */
#left #logo img {
position: absolute;
top: 50%;
@@ -286,11 +291,11 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
max-width: 90px;
max-height: 90px;
}
/* line 208, ../sass/_layout.scss */
/* line 212, ../sass/_layout.scss */
#left h1, #left h2, #left #infos, #left #infos a {
color: #323232;
}
/* line 212, ../sass/_layout.scss */
/* line 216, ../sass/_layout.scss */
#left h1 {
text-transform: uppercase;
font-family: "highvoltageregular";
@@ -301,37 +306,37 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
text-align: center;
font-weight: normal;
}
/* line 223, ../sass/_layout.scss */
/* line 227, ../sass/_layout.scss */
#left h2 {
font-family: "capsuularegular";
font-size: 15px;
font-weight: normal;
text-align: center;
}
/* line 229, ../sass/_layout.scss */
/* line 233, ../sass/_layout.scss */
#left h2 .favorite {
padding-left: 0px;
}
/* line 232, ../sass/_layout.scss */
/* line 236, ../sass/_layout.scss */
#left h2 .favorite .glyphicon {
font-size: 14px;
}
/* line 237, ../sass/_layout.scss */
/* line 241, ../sass/_layout.scss */
#left h2 a {
color: #323232;
}
/* line 243, ../sass/_layout.scss */
/* line 247, ../sass/_layout.scss */
#left nav#main-nav {
background-color: white;
border: solid 1px #e0e0e0;
border-bottom: 0px none;
margin-top: 20px;
}
/* line 250, ../sass/_layout.scss */
/* line 254, ../sass/_layout.scss */
#left nav#main-nav ul li {
display: block;
}
/* line 253, ../sass/_layout.scss */
/* line 257, ../sass/_layout.scss */
#left nav#main-nav ul li a {
color: #323232;
color: black;
@@ -341,23 +346,23 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
display: block;
text-align: left;
}
/* line 262, ../sass/_layout.scss */
/* line 266, ../sass/_layout.scss */
#left nav#main-nav ul li a .glyphicon {
font-size: 15px;
margin-right: 3px;
}
/* line 267, ../sass/_layout.scss */
/* line 271, ../sass/_layout.scss */
#left nav#main-nav ul li a span.label {
padding-bottom: 3px;
font-family: "Arial";
float: right;
}
/* line 275, ../sass/_layout.scss */
/* line 279, ../sass/_layout.scss */
#left nav#main-nav ul li.active span.label, #left nav#main-nav ul li a:hover span.label {
background-color: #e08e0b;
color: white;
}
/* line 281, ../sass/_layout.scss */
/* line 285, ../sass/_layout.scss */
#left nav#main-nav ul li a:hover, #left nav#main-nav ul li.active a {
background: #F39C12;
color: white;
@@ -365,22 +370,22 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
-webkit-border-radius: 0px;
border-radius: 0px;
}
/* line 290, ../sass/_layout.scss */
/* line 294, ../sass/_layout.scss */
#left nav#main-nav ul li#btn-administration a {
color: #F39C12;
}
/* line 293, ../sass/_layout.scss */
/* line 297, ../sass/_layout.scss */
#left nav#main-nav ul li#btn-administration a:hover {
color: white;
}
/* line 301, ../sass/_layout.scss */
/* line 305, ../sass/_layout.scss */
#left nav#main-nav #user {
color: #F39C12;
float: right;
padding: 10px;
}

/* line 309, ../sass/_layout.scss */
/* line 313, ../sass/_layout.scss */
#main {
background-color: #FFF8DC;
border: solid 1px #e0e0e0;
@@ -388,13 +393,13 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
padding: 0px;
background-color: white;
}
/* line 316, ../sass/_layout.scss */
/* line 320, ../sass/_layout.scss */
#main #img-big {
height: 130px;
overflow: hidden;
position: relative;
}
/* line 321, ../sass/_layout.scss */
/* line 325, ../sass/_layout.scss */
#main #img-big img.img-photo {
width: 100%;
position: absolute;
@@ -402,7 +407,7 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
left: 50%;
transform: translate(-50%, -50%);
}
/* line 331, ../sass/_layout.scss */
/* line 335, ../sass/_layout.scss */
#main #infos-producer {
padding: 5px 10px;
margin-bottom: 0px;
@@ -412,20 +417,20 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
border-bottom: solid 1px #e0e0e0;
color: gray;
}
/* line 340, ../sass/_layout.scss */
/* line 344, ../sass/_layout.scss */
#main #infos-producer strong {
font-weight: bold;
}
/* line 344, ../sass/_layout.scss */
/* line 348, ../sass/_layout.scss */
#main #infos-producer .favorite {
float: right;
color: gray;
}
/* line 347, ../sass/_layout.scss */
/* line 351, ../sass/_layout.scss */
#main #infos-producer .favorite a {
color: black;
}
/* line 353, ../sass/_layout.scss */
/* line 357, ../sass/_layout.scss */
#main h2#page-title {
padding-left: 15px;
padding-right: 15px;
@@ -440,36 +445,36 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
top: -10px;
text-align: left;
}
/* line 367, ../sass/_layout.scss */
/* line 371, ../sass/_layout.scss */
#main h2#page-title #buttons {
margin-bottom: 15px;
font-family: "Arial";
}
/* line 374, ../sass/_layout.scss */
/* line 378, ../sass/_layout.scss */
#main #content {
padding: 0px 20px 20px 20px;
padding-bottom: 40px;
min-height: 300px;
}
/* line 379, ../sass/_layout.scss */
/* line 383, ../sass/_layout.scss */
#main #content h1, #main #content h2, #main #content h3, #main #content h4, #main #content h5, #main #content h6 {
font-family: "highvoltageregular";
margin-top: 30px;
margin-bottom: 20px;
}
/* line 384, ../sass/_layout.scss */
/* line 388, ../sass/_layout.scss */
#main #content h1.first, #main #content h2.first, #main #content h3.first, #main #content h4.first, #main #content h5.first, #main #content h6.first {
margin-top: 0px;
}
/* line 389, ../sass/_layout.scss */
/* line 393, ../sass/_layout.scss */
#main #content h1 {
font-size: 30px;
}
/* line 393, ../sass/_layout.scss */
/* line 397, ../sass/_layout.scss */
#main #content h2 {
font-size: 25px;
}
/* line 398, ../sass/_layout.scss */
/* line 402, ../sass/_layout.scss */
#main #content h3 {
font-family: "capsuularegular";
text-transform: uppercase;
@@ -478,29 +483,29 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
margin-bottom: 30px;
margin-top: 45px;
}
/* line 406, ../sass/_layout.scss */
/* line 410, ../sass/_layout.scss */
#main #content h3 span {
padding-top: 14px;
color: #323232;
}
/* line 412, ../sass/_layout.scss */
/* line 416, ../sass/_layout.scss */
#main #content h4 {
font-size: 20px;
}
/* line 416, ../sass/_layout.scss */
/* line 420, ../sass/_layout.scss */
#main #content h5 {
font-size: 18px;
}
/* line 420, ../sass/_layout.scss */
/* line 424, ../sass/_layout.scss */
#main #content h6 {
font-size: 16px;
}
/* line 426, ../sass/_layout.scss */
/* line 430, ../sass/_layout.scss */
#main #content form .form-group .hint-block {
color: gray;
}

/* line 434, ../sass/_layout.scss */
/* line 438, ../sass/_layout.scss */
#footer-producer {
text-align: center;
position: absolute;
@@ -508,28 +513,28 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
left: 0px;
width: 100%;
}
/* line 441, ../sass/_layout.scss */
/* line 445, ../sass/_layout.scss */
#footer-producer a {
color: #F39C12;
}
/* line 443, ../sass/_layout.scss */
/* line 447, ../sass/_layout.scss */
#footer-producer a:active {
text-decoration: underline;
}

/* line 449, ../sass/_layout.scss */
/* line 453, ../sass/_layout.scss */
#footer {
background-color: #FFF8DC;
height: 100px;
float: right;
text-align: center;
}
/* line 455, ../sass/_layout.scss */
/* line 459, ../sass/_layout.scss */
#footer .content {
padding-top: 20px;
color: black;
}
/* line 459, ../sass/_layout.scss */
/* line 463, ../sass/_layout.scss */
#footer .content a {
color: black;
font-family: "capsuularegular";
@@ -537,11 +542,11 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
padding-left: 10px;
padding-right: 10px;
}
/* line 466, ../sass/_layout.scss */
/* line 470, ../sass/_layout.scss */
#footer .content a:hover {
text-decoration: underline;
}
/* line 473, ../sass/_layout.scss */
/* line 477, ../sass/_layout.scss */
#footer #code-source img {
height: 20px;
}

+ 4
- 0
producer/web/sass/_layout.scss Ver fichero

@@ -59,6 +59,10 @@ body {
a {
//color: $color1;
}

strong {
font-weight: bold;
}
}

.modal-backdrop.in {

Cargando…
Cancelar
Guardar