Bläddra i källkod

Merge branch 'develop'

master
Guillaume Bourgeois 5 månader sedan
förälder
incheckning
4b1a5de1ee
74 ändrade filer med 1838 tillägg och 196 borttagningar
  1. +1
    -1
      backend/controllers/InvoiceController.php
  2. +1
    -0
      backend/controllers/ProducerInvoiceController.php
  3. +42
    -0
      backend/controllers/SponsorshipController.php
  4. +3
    -7
      backend/controllers/TaxRateAdminController.php
  5. +39
    -0
      backend/controllers/UserAdminController.php
  6. +91
    -5
      backend/controllers/UserController.php
  7. +29
    -12
      backend/views/dashboard-admin/index.php
  8. +23
    -0
      backend/views/delivery-note/index.php
  9. +1
    -1
      backend/views/distribution/index.php
  10. +1
    -1
      backend/views/document/download.php
  11. +19
    -8
      backend/views/invoice/index.php
  12. +13
    -0
      backend/views/layouts/left.php
  13. +68
    -33
      backend/views/producer-admin/_form.php
  14. +9
    -0
      backend/views/producer-admin/index.php
  15. +10
    -0
      backend/views/producer-invoice/index.php
  16. +129
    -0
      backend/views/sponsorship/index.php
  17. +2
    -1
      backend/views/subscription/index.php
  18. +124
    -0
      backend/views/user-admin/email_deliverability.php
  19. +11
    -1
      backend/views/user-admin/index.php
  20. +18
    -2
      backend/views/user/_form.php
  21. +6
    -0
      backend/views/user/_menu_navigation.php
  22. +15
    -1
      backend/views/user/index.php
  23. +124
    -0
      backend/views/user/messages.php
  24. +9
    -0
      backend/views/user/view.php
  25. +9
    -0
      backend/web/js/backend.js
  26. +1
    -1
      backend/web/js/vuejs/distribution-index.js
  27. +1
    -0
      common/components/BusinessLogic.php
  28. +6
    -0
      common/components/BusinessLogicTrait.php
  29. +1
    -1
      common/config/params.php
  30. +30
    -0
      common/versions/24.6.C.php
  31. +26
    -0
      console/migrations/m240611_091617_add_column_user_problem_receiving_emails.php
  32. +37
    -0
      console/migrations/m240611_125313_create_table_user_message.php
  33. +26
    -0
      console/migrations/m240612_062929_add_column_user_note_email.php
  34. +41
    -0
      console/migrations/m240613_070747_add_columns_producer_sponsorship.php
  35. +29
    -9
      domain/Config/TaxRate/TaxRate.php
  36. +0
    -9
      domain/Config/TaxRate/TaxRateBuilder.php
  37. +24
    -0
      domain/Config/TaxRate/TaxRateManager.php
  38. +26
    -1
      domain/Document/DeliveryNote/DeliveryNoteSearch.php
  39. +55
    -7
      domain/Document/Invoice/InvoiceSearch.php
  40. +2
    -0
      domain/Feature/Feature/Feature.php
  41. +2
    -0
      domain/Feature/Feature/FeatureDefinition.php
  42. +1
    -1
      domain/Feature/Feature/FeatureRepository.php
  43. +56
    -2
      domain/Producer/Producer/Producer.php
  44. +8
    -0
      domain/Producer/Producer/ProducerBuilder.php
  45. +14
    -0
      domain/Producer/Producer/ProducerRepository.php
  46. +13
    -0
      domain/Producer/Producer/ProducerRepositoryQuery.php
  47. +30
    -0
      domain/Producer/Producer/ProducerSolver.php
  48. +18
    -3
      domain/User/User/User.php
  49. +6
    -1
      domain/User/User/UserManager.php
  50. +12
    -0
      domain/User/User/UserRepository.php
  51. +6
    -0
      domain/User/User/UserRepositoryQuery.php
  52. +10
    -1
      domain/User/User/UserSearch.php
  53. +113
    -0
      domain/User/UserMessage/UserMessage.php
  54. +20
    -0
      domain/User/UserMessage/UserMessageBuilder.php
  55. +13
    -0
      domain/User/UserMessage/UserMessageDefinition.php
  56. +35
    -0
      domain/User/UserMessage/UserMessageManager.php
  57. +38
    -0
      domain/User/UserMessage/UserMessageModule.php
  58. +61
    -0
      domain/User/UserMessage/UserMessageRepository.php
  59. +28
    -0
      domain/User/UserMessage/UserMessageRepositoryQuery.php
  60. +30
    -3
      frontend/controllers/SiteController.php
  61. +11
    -0
      frontend/forms/SignupForm.php
  62. +13
    -0
      frontend/views/site/_signup_sponsorship_message.php
  63. +5
    -0
      frontend/views/site/signup.php
  64. +10
    -5
      frontend/views/site/signup_producer.php
  65. +13
    -0
      producer/controllers/NewsletterController.php
  66. +1
    -1
      producer/controllers/OrderController.php
  67. +10
    -0
      producer/controllers/SiteController.php
  68. +24
    -0
      producer/views/layouts/main.php
  69. +33
    -18
      producer/views/newsletter/index.php
  70. +0
    -1
      producer/views/subscription/_form.php
  71. +74
    -55
      producer/web/css/screen.css
  72. +2
    -1
      producer/web/js/vuejs/order-order.js
  73. +22
    -1
      producer/web/sass/_responsive.scss
  74. +4
    -2
      producer/web/sass/order/_order.scss

+ 1
- 1
backend/controllers/InvoiceController.php Visa fil

@@ -60,7 +60,7 @@ class InvoiceController extends DocumentController
public function actionAjaxDeleteDeliveryNote($idInvoice, $idDeliveryNote)
{
$orderModule = $this->getOrderModule();
$invoiceModule = $this-> getInvoiceModule();
$invoiceModule = $this-> getInvoiceModule();
$deliveryNoteModule = $this->getDeliveryNoteModule();
$invoice = $invoiceModule->findOneInvoiceById($idInvoice);
$deliveryNote = $deliveryNoteModule->findOneDeliveryNoteById($idDeliveryNote);

+ 1
- 0
backend/controllers/ProducerInvoiceController.php Visa fil

@@ -31,6 +31,7 @@ class ProducerInvoiceController extends BackendController
public function actionIndex()
{
return $this->render('index', [
'producer' => $this->getProducerCurrent(),
'invoicesArray' => $this->getProducerModule()
->getDolibarrUtils()
->getDolibarrProducerInvoices($this->getProducerCurrent())

+ 42
- 0
backend/controllers/SponsorshipController.php Visa fil

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

namespace backend\controllers;

use backend\controllers\BackendController;
use domain\Feature\Feature\Feature;
use yii\filters\AccessControl;

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

public function actionIndex()
{
$producerCurrent = $this->getProducerCurrent();

return $this->render('index', [
'producer' => $producerCurrent,
'producersGodsonsArray' => $this->getProducerModule()->getRepository()->findProducersSponsorshipGodsons($producerCurrent)
]);
}
}

+ 3
- 7
backend/controllers/TaxRateAdminController.php Visa fil

@@ -88,7 +88,7 @@ class TaxRateAdminController extends BackendController

public function actionCreate()
{
$model = $this-> getTaxRateModule()->instanciateTaxRate();
$model = $this->getTaxRateModule()->getBuilder()->instanciateTaxRate();

if ($model->load(\Yii::$app->request->post()) && $model->save()) {
$this->setFlash('success', 'Taxe créée.');
@@ -116,19 +116,15 @@ class TaxRateAdminController extends BackendController

public function actionDelete(int $id)
{
$taxRateModule = $this-> getTaxRateModule();
$taxRate = $this->findModel($id);
$taxRateModule->delete($taxRate);

$taxRate->delete();
$this->setFlash('success', 'Taxe supprimé');

return $this->redirect(['tax-rate-admin/index']);
}

protected function findModel($id)
{
$taxRateModule = $this-> getTaxRateModule();
if (($taxRate = $taxRateModule->findOneTaxRateById($id)) !== null) {
if (($taxRate = $this->getTaxRateModule()->getRepository()->findOneTaxRateById($id)) !== null) {
return $taxRate;
} else {
throw new NotFoundHttpException('The requested page does not exist.');

+ 39
- 0
backend/controllers/UserAdminController.php Visa fil

@@ -41,6 +41,7 @@ namespace backend\controllers;
use domain\User\User\UserSearch;
use Yii;
use yii\filters\AccessControl;
use yii\web\NotFoundHttpException;

class UserAdminController extends BackendController
{
@@ -81,6 +82,35 @@ class UserAdminController extends BackendController
]);
}

public function actionEmailDeliverability()
{
$searchModel = new UserSearch();
$searchModel->problem_receiving_emails = true;
$dataProvider = $searchModel->search([
'UserSearch' => isset(\Yii::$app->request->queryParams['UserSearch']) ?
Yii::$app->request->queryParams['UserSearch'] : []
]);

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

public function actionReportProblemReceivingEmails(int $id)
{
$user = $this->findModel($id);

if($this->getUserModule()->getManager()->reportProblemReceivingEmails($user)) {
$this->setFlash('success', "L'utilisateur <strong>".$this->getUserModule()->getSolver()->getUsername($user)."</strong> a bien été signalé comme ayant des problèmes dans la réception de vos emails. L'administrateur débloquera la situation dès que possible et préviendra l'utilisateur.");
}
else {
$this->setFlash('error', "Une erreur est survenue.");
}

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

public function actionRedirectView(int $idUserProducer)
{
$userCurrent = $this->getUserCurrent();
@@ -96,4 +126,13 @@ class UserAdminController extends BackendController
return $this->redirectReferer();
}
}

protected function findModel($id)
{
if (($user = $this->getUserModule()->findOneUserById($id)) !== null) {
return $user;
} else {
throw new NotFoundHttpException("Utilisateur introuvable");
}
}
}

+ 91
- 5
backend/controllers/UserController.php Visa fil

@@ -69,11 +69,16 @@ class UserController extends BackendController
'allow' => true,
'roles' => ['@'],
'matchCallback' => function ($rule, $action) {
return $this->getUserModule()
->getAuthorizationChecker()
->isGrantedAsProducer($this->getUserCurrent());
$userCurrent = $this->getUserCurrent();
$authorizationChecker = $this->getUserModule()->getAuthorizationChecker();
if(in_array($action->id, ['messages', 'message-delete'])) {
return $authorizationChecker->isGrantedAsAdministrator($userCurrent);
}
else {
return $authorizationChecker->isGrantedAsProducer($userCurrent);
}
}
]
],
],
],
];
@@ -246,7 +251,7 @@ class UserController extends BackendController
}

$this->setFlash('success', 'Utilisateur <strong>' . Html::encode($userModule->getUsername($model)) . '</strong> modifié.');
return $this->redirect(['view', 'id' => $model->id]);
return $this->redirect(['update', 'id' => $model->id]);
}
} else {
throw new UserException("Vous ne pouvez pas modifier cet utilisateur.");
@@ -258,6 +263,87 @@ class UserController extends BackendController
]));
}

public function actionMessages(int $id, int $idUserMessage = null)
{
$userMessageModule = $this->getUserMessageModule();
$user = $this->findModel($id);
$isUpdate = false;

if($idUserMessage) {
$isUpdate = true;
$userMessageModel = $this->findUserMessage($idUserMessage);
}
else {
$userMessageModel = $userMessageModule->getBuilder()->instanciateUserMessage(
$user,
$this->getUserCurrent()
);
}

if($userMessageModel->load(\Yii::$app->request->post()) && $userMessageModel->validate()) {
if($isUpdate) {
$userMessageModel->save();
$this->setFlash('success', "Le message a bien été modifié.");
}
else {
$userMessageModule->getManager()->createUserMessage(
$user,
$userMessageModel->getMessage(),
$this->getUserCurrent()
);
$this->setFlash('success', "Le message a bien été envoyé à l'utilisateur.");
}

return $this->redirect(['messages', 'id' => $id]);
}

return $this->render('messages', [
'user' => $user,
'userMessageModel' => $userMessageModel,
'userMessagesDataProvider' => $userMessageModule->getRepository()
->queryUserMessagesByUser($user)
->getDataProvider(20)
]);
}

public function actionMessageDelete(int $idUser, int $idUserMessage)
{
$userMessageModule = $this->getUserMessageModule();
$userMessage = $this->findUserMessage($idUserMessage);
if($userMessageModule->getManager()->deleteUserMessage($userMessage)) {
$this->setFlash('success', "Le message a bien été supprimé.");
}
else {
$this->setFlash('error', "Une erreur est survenue pendant la suppression du message.");
}
return $this->redirect(['messages', 'id' => $idUser]);
}

public function findUserMessage(int $idUserMessage)
{
$userMessage = $this->getUserMessageModule()->getRepository()->findOneUserMessageById($idUserMessage);

if(!$userMessage) {
throw new NotFoundHttpException("Le message utilisateur n'a pas été trouvé.");
}

return $userMessage;
}

public function actionReportProblemReceivingEmails(int $id)
{
$user = $this->findModel($id);

if($this->getUserModule()->getManager()->reportProblemReceivingEmails($user)) {
$this->setFlash('success', "L'utilisateur <strong>".$this->getUserModule()->getSolver()->getUsername($user)."</strong> a bien été signalé comme ayant des problèmes dans la réception de vos emails. L'administrateur débloquera la situation dès que possible et préviendra l'utilisateur.");
}
else {
$this->setFlash('error', "Une erreur est survenue.");
}

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

public function initForm($model)
{
$userPointSaleModule = $this->getUserPointSaleModule();

+ 29
- 12
backend/views/dashboard-admin/index.php Visa fil

@@ -10,18 +10,13 @@ $this->setMetaRefresh(true);
?>

<div class="dashboard-admin-index">
<div class="row">
<div class="col-lg-6 col-xs-6">
<?= AdminLTE::smallBox(
$countUsersOnline,
'En ligne',
$countUsersOnline ? 'green' : 'blue',
'wifi',
Yii::$app->urlManager->createUrl('online-admin/index')
) ?>

<div id="producers-online" class="box box-solid">
<div class="box-header with-border">
<i class="fa fa-bookmark"></i>
<h3 class="box-title">Producteurs en ligne</h3>
</div>
<div class="col-lg-6 col-xs-6" id="producers-online">
<!--<h3>Producteurs en ligne :</h3>-->
<div class="box-body">
<?php if($usersWithStatusProducerOnlineArray && count($usersWithStatusProducerOnlineArray) > 0): ?>
<?php foreach ($usersWithStatusProducerOnlineArray as $userWithStatusProducerOnline): ?>
<?php $producer = $userWithStatusProducerOnline->producer; ?>
@@ -33,10 +28,32 @@ $this->setMetaRefresh(true);
<?php endforeach; ?>
<div class="clr"></div>
<?php else: ?>
<div class="alert alert-info">Aucun producteur en ligne actuellement.</div>
<p><em>Aucun producteur en ligne actuellement.</em></p>
<?php endif; ?>
</div>
</div>

<div class="row">
<div class="col-lg-6 col-xs-6">
<?= AdminLTE::smallBox(
$countUsersOnline,
'Utilisateurs en ligne',
$countUsersOnline ? 'green' : 'blue',
'wifi',
Yii::$app->urlManager->createUrl('online-admin/index')
) ?>
</div>
<div class="col-lg-6 col-xs-6">
<?php $countUsersWithProblemReceivingEmails = $this->getUserModule()->getRepository()->countUsersWithProblemReceivingEmails(); ?>
<?= AdminLTE::smallBox(
$countUsersWithProblemReceivingEmails,
'Problèmes réception emails',
$countUsersWithProblemReceivingEmails ? 'red' : 'green',
'send',
Yii::$app->urlManager->createUrl('user-admin/email-deliverability')
) ?>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-xs-6">
<?= AdminLTE::smallBox(

+ 23
- 0
backend/views/delivery-note/index.php Visa fil

@@ -117,9 +117,32 @@ $this->addButton(['label' => 'Nouveau bon de livraison <span class="glyphicon gl
return $deliveryNoteModule->getAmountWithTax($deliveryNote, Order::INVOICE_AMOUNT_TOTAL, true);
}
],
[
'attribute' => 'with_invoice',
'header' => 'Facture',
'filter' => [
0 => 'Non',
1 => 'Oui',
],
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($deliveryNote) use ($deliveryNoteModule) {
$invoice = $deliveryNoteModule->getSolver()->getInvoice($deliveryNote);
if($invoice) {
return Html::a($invoice->reference, ['invoice/update', 'id' => $invoice->id], ['class' => 'btn btn-xs btn-default']);
}
return '';
}
],
[
'attribute' => 'is_sent',
'header' => 'Envoyé',
'filter' => [
0 => 'Non',
1 => 'Oui',
],
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],

+ 1
- 1
backend/views/distribution/index.php Visa fil

@@ -91,7 +91,7 @@ $this->setPageTitle('Distributions') ;
<h4>
Distribution du <strong>{{ dateFormat }}</strong>
<a v-if="distribution.active" class="btn btn-default" :href="distribution.url_order" @click="copyLinkOrder($event, distribution.url_order)"><span class="glyphicon glyphicon-link"></span></a>
<span v-if="distribution.is_leave_period" class="label label-info">
<span v-if="distribution.is_leave_period" class="label label-default">
<span class="glyphicon glyphicon-info-sign"></span>
Congés
</span>

+ 1
- 1
backend/views/document/download.php Visa fil

@@ -173,7 +173,7 @@ $documentPriceDecimals = (int) $producerModule->getConfig('option_document_price
</tr>

<?php
$taxRateArray = $this-> getTaxRateModule()->findTaxRatesAsArray();
$taxRateArray = $this-> getTaxRateModule()->getRepository()->findTaxRatesAsArray();
foreach ($documentModule->getTotalVatArray($document, $typeAmount) as $idTaxRate => $totalVat): ?>
<tr>
<td class="align-right" colspan="4">

+ 19
- 8
backend/views/invoice/index.php Visa fil

@@ -52,7 +52,6 @@ $this->addButton(['label' => 'Nouvelle facture <span class="glyphicon glyphicon-
?>

<div class="invoice-index">

<?php if (Invoice::searchCount()): ?>
<?= GridView::widget([
'filterModel' => $searchModel,
@@ -82,7 +81,7 @@ $this->addButton(['label' => 'Nouvelle facture <span class="glyphicon glyphicon-
'name',
[
'attribute' => 'username',
'header' => 'Utilisateur',
'label' => 'Utilisateur',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
@@ -93,6 +92,13 @@ $this->addButton(['label' => 'Nouvelle facture <span class="glyphicon glyphicon-
[
'attribute' => 'date',
'header' => 'Date',
'filter' => \yii\jui\DatePicker::widget([
'language' => 'fr',
'dateFormat' => 'dd/MM/yyyy',
'model' => $searchModel,
'attribute' => 'date',
'options' => ['class' => 'form-control']
]),
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
@@ -105,28 +111,34 @@ $this->addButton(['label' => 'Nouvelle facture <span class="glyphicon glyphicon-
'header' => 'Montant',
'format' => 'raw',
'value' => function ($invoice) use ( $invoiceModule) {
$amountWithTax = $invoiceModule->getAmountWithTax($invoice, Order::INVOICE_AMOUNT_TOTAL);
return $invoiceModule->getAmountWithTax($invoice, Order::INVOICE_AMOUNT_TOTAL, true);
}
],
[
'header' => 'Payée',
'attribute' => 'paid',
'label' => 'Payée',
'filter' => [
0 => 'Non',
1 => 'Oui',
],
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($invoice) use ( $invoiceModule) {
$amountWithTax = $invoiceModule->getAmountWithTax($invoice, Order::INVOICE_AMOUNT_TOTAL);
if($amountWithTax && $invoiceModule->isInvoicePaid($invoice)) {
if($invoiceModule->isInvoicePaid($invoice)) {
return '<span class="label label-success">Oui</span>';
}

return '<span class="label label-default">Non</span>';
}
],
[
'attribute' => 'is_sent',
'header' => 'Envoyée',
'filter' => [
0 => 'Non',
1 => 'Oui',
],
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
@@ -166,7 +178,6 @@ $this->addButton(['label' => 'Nouvelle facture <span class="glyphicon glyphicon-
'title' => 'Export CSV Evoliz', 'class' => 'btn btn-default'
]);
}

return '';
},
'update' => function ($url, $invoice) {

+ 13
- 0
backend/views/layouts/left.php Visa fil

@@ -145,6 +145,12 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
'url' => ['/user-admin/index'],
'visible' => $isUserCurrentGrantedAsAdministrator
],
[
'label' => 'Deliverabilité emails',
'icon' => 'paper-plane',
'url' => ['/user-admin/email-deliverability'],
'visible' => $isUserCurrentGrantedAsAdministrator
],
[
'label' => 'Statistiques',
'icon' => 'line-chart',
@@ -273,6 +279,13 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
'template' => '<a href="{url}">{icon} {label}' . $countProducerInvoicesUnpaidLabel . '</a>'
],
['label' => 'Tarifs & modules', 'icon' => 'euro', 'url' => ['/producer/billing'], 'visible' => $isUserCurrentGrantedAsProducer],
[
'label' => 'Parrainage',
'icon' => 'users',
'url' => ['/sponsorship/index'],
'visible' => $isUserCurrentGrantedAsProducer && $featureChecker->isEnabled(Feature::ALIAS_SPONSORSHIP),
'active' => Yii::$app->controller->id == 'sponsorship'
],
[
'label' => 'Développement',
'icon' => 'code',

+ 68
- 33
backend/views/producer-admin/_form.php Visa fil

@@ -44,40 +44,75 @@ use yii\widgets\ActiveForm;

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

<h3>Général</h3>
<?= $form->field($model, 'slug') ?>
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'type')->textInput(['placeholder' => 'Boulangerie, brasserie, ferme ...']); ?>
<?= $form->field($model, 'postcode') ?>
<?= $form->field($model, 'city') ?>
<?= $form->field($model, 'contact_email') ?>
<?= $form->field($model, 'latitude') ?>
<?= $form->field($model, 'longitude') ?>
<?= $form->field($model, 'code')->label('Code d\'accès') ?>
<?= $form->field($model, 'admin_comment')->textarea(['rows' => 7]) ?>
<?= $form->field($model, 'is_new')->checkbox() ?>
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-th-list"></i>
Général
</h3>
</div>
<div class="panel-body">
<?= $form->field($model, 'slug') ?>
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'type')->textInput(['placeholder' => 'Boulangerie, brasserie, ferme ...']); ?>
<?= $form->field($model, 'postcode') ?>
<?= $form->field($model, 'city') ?>
<?= $form->field($model, 'contact_email') ?>
<?= $form->field($model, 'latitude') ?>
<?= $form->field($model, 'longitude') ?>
<?= $form->field($model, 'code')->label('Code d\'accès') ?>
<?= $form->field($model, 'admin_comment')->textarea(['rows' => 7]) ?>
<?= $form->field($model, 'is_new')->checkbox() ?>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-euro"></i>
Facturation
</h3>
</div>
<div class="panel-body">
<?= $form->field($model, 'option_billing_type')
->dropDownList(Producer::getBillingTypePopulateDropdown()); ?>
<?= $form->field($model, 'option_billing_frequency')
->dropDownList(Producer::getBillingFrequencyPopulateDropdown()); ?>
<?= $form->field($model, 'option_billing_reduction')
->dropDownList([
0 => 'Non',
1 => 'Oui'
]); ?>
<?= $form->field($model, 'option_billing_reduction_percentage') ?>
<?= $form->field($model, 'option_billing_permanent_transfer')
->dropDownList([
0 => 'Non',
1 => 'Oui'
]); ?>
<?= $form->field($model, 'option_billing_permanent_transfer_amount') ?>
<?= $form->field($model, 'dolibarr_socid') ?>
<?= $form->field($model, 'dolibarr_product_id') ?>
</div>
</div>

<h3>Facturation</h3>
<?= $form->field($model, 'option_billing_type')
->dropDownList(Producer::getBillingTypePopulateDropdown()); ?>
<?= $form->field($model, 'option_billing_frequency')
->dropDownList(Producer::getBillingFrequencyPopulateDropdown()); ?>
<?= $form->field($model, 'option_billing_reduction')
->dropDownList([
0 => 'Non',
1 => 'Oui'
]); ?>
<?= $form->field($model, 'option_billing_reduction_percentage') ?>
<?= $form->field($model, 'option_billing_permanent_transfer')
->dropDownList([
0 => 'Non',
1 => 'Oui'
]); ?>
<?= $form->field($model, 'option_billing_permanent_transfer_amount') ?>
<?= $form->field($model, 'dolibarr_socid') ?>
<?= $form->field($model, 'dolibarr_product_id') ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-users"></i>
Parrainage
</h3>
</div>
<div class="panel-body">
<?= $form->field($model, 'sponsorship_sponsor_reward')->checkbox() ?>
</div>
</div>
</div>
</div>

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

+ 9
- 0
backend/views/producer-admin/index.php Visa fil

@@ -122,11 +122,13 @@ $this->addButton(['label' => 'Nouveau producteur <span class="glyphicon glyphico
$summaryQuaterly = $producerModule->getSummaryAmountsToBeBilled($producer, '3 derniers mois', 3);
$isBillingFrequencyBiannual = $producerModule->isBillingFrequencyBiannual($producer);
$summaryBiannual = $producerModule->getSummaryAmountsToBeBilled($producer, '6 derniers mois', 6);
$isBilled = false;

if(($isBillingFrequencyMonthly && $summaryMonthly)
|| ($isBillingFrequencyQuaterly && $summaryQuaterly)
|| ($isBillingFrequencyBiannual && $summaryBiannual)) {

$isBilled = true;
$str .= '<li>';
if ($isBillingFrequencyMonthly && $summaryMonthly) {
$str .= $summaryMonthly;
@@ -155,6 +157,13 @@ $this->addButton(['label' => 'Nouveau producteur <span class="glyphicon glyphico

$str .= '</ul>';

if($isBilled && $producerModule->getSolver()->isFreeBillingPeriodSponsorship($producer)) {
$str .= "<br /><p><span class=\"glyphicon glyphicon-warning-sign\"></span> <strong>Pas de facturation, offre de parrainage jusqu'au ".$producerModule->getSolver()->getDateEndFreeBillingPeriodSponsorship($producer)->format('d/m/Y')."</strong></p>";
if(!$producer->getSponsorshipSponsorReward()) {
$str .= '<p><i class="fa fa-gift"></i> Créer un avoir de 30€ pour le parrain <strong>'.Html::encode($producer->getSponsoredBy()->getName()).'</strong> sur Dolibarr et valider la récompense parrain.</p>';
}
}

return $str;
}
],

+ 10
- 0
backend/views/producer-invoice/index.php Visa fil

@@ -42,6 +42,8 @@ use yii\helpers\Html;
$this->setTitle('Mes factures') ;
$this->addBreadcrumb($this->getTitle()) ;

$producerModule = $this->getProducerModule();

?>

<?php if($invoicesArray && count($invoicesArray)): ?>
@@ -81,4 +83,12 @@ $this->addBreadcrumb($this->getTitle()) ;
<div class="callout callout-info">
<span class="glyphicon glyphicon-info-sign"></span> Vous n'avez encore aucune facture.
</div>

<?php if($producerModule->getSolver()->isFreeBillingPeriodSponsorship($producer)): ?>
<div class="callout callout-info">
<i class="fa fa-gift"></i>
Et comme vous avez été parrainé au moment de votre inscription, vous n'aurez pas de facture <em>Souke</em>
avant le <?= $producerModule->getSolver()->getDateEndFreeBillingPeriodSponsorship($producer)->format('d/m/Y'); ?>.
</div>
<?php endif; ?>
<?php endif; ?>

+ 129
- 0
backend/views/sponsorship/index.php Visa fil

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

/**
Copyright La boîte à pain (2018)

contact@souke.fr

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

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

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

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

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

use common\helpers\Price;
use yii\helpers\Html;

$this->setTitle('Parrainage') ;
$this->addBreadcrumb($this->getTitle()) ;

$producerModule = $this->getProducerModule();
$sponsorshipLink = $producerModule->getSolver()->getSponsorshipLink($producer);

?>

<?php if($producer->getSponsoredBy()): ?>
<div class="callout callout-info">
<i class="fa fa-users"></i>
Vous avez été parrainé par le producteur <strong><?= Html::encode($producer->getSponsoredBy()->getName()) ?></strong>.
<?php if($producerModule->getSolver()->isFreeBillingPeriodSponsorship($producer)): ?>
<br /><i class="fa fa-gift"></i>
Vous bénéficiez donc de 3 mois offerts et n'aurez pas de facture <em>Souke</em> avant le <?= $producerModule->getSolver()->getDateEndFreeBillingPeriodSponsorship($producer)->format('d/m/Y'); ?>.
<?php endif; ?>
</div>
<?php endif; ?>

<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<span class="glyphicon glyphicon-link"></span>
Votre lien de partage
</h3>
</div>
<div class="panel-body">
<strong><?= $sponsorshipLink ?></strong>
<a class="btn btn-xs btn-default" id="sponsorship-link-copy" href="<?= $sponsorshipLink ?>" title="Copier le lien dans le presse-papier">
<span class="glyphicon glyphicon-copy"></span>
</a>
</div>
</div>

<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-info"></i>
Comment ça marche ?
</h3>
</div>
<div class="panel-body">
<p>
Partagez votre lien de parrainage avec les producteurs que vous souhaitez parrainer. Quand un de ces
producteurs s'inscrit en suivant ce lien, il devient votre filleul et obtenez tous les deux une récompense :
</p>
<ul>
<li>
Votre filleul démarre sur le logiciel avec <strong>3 mois offerts</strong>.
</li>
<li>
Vous obtenez <strong>30€ de réduction</strong> sur vos prochaines factures dès lors que votre filleul
utilise le logiciel en production.
</li>
</ul>
</div>
</div>

<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-users"></i>
Vos filleuls
</h3>
</div>
<div class="panel-body">
<?php if($producersGodsonsArray && count($producersGodsonsArray)): ?>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Producteur</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<?php foreach($producersGodsonsArray as $producerGodson): ?>
<tr>
<td><?= Html::encode($producerGodson->getName()); ?></td>
<td><?= date('d/m/Y', strtotime($producerGodson->date_creation)); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<p>Vous n'avez encore parrainé aucun producteur.</p>
<?php endif; ?>
</div>
</div>

+ 2
- 1
backend/views/subscription/index.php Visa fil

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

use common\helpers\GlobalParam;
use domain\_\StatusInterface;
use domain\PointSale\PointSale\PointSale;
use domain\Product\Product\Product;
use domain\Product\Product\ProductModule;
@@ -110,7 +111,7 @@ $subscriptionsArray = Subscription::searchAll() ;
'attribute' => 'id_point_sale',
'label' => 'Point de vente',
'format' => 'raw',
'filter' => ArrayHelper::map(PointSale::find()->where(['id_producer' => GlobalParam::getCurrentProducerId()])->asArray()->all(), 'id', 'name'),
'filter' => ArrayHelper::map(PointSale::find()->where(['id_producer' => GlobalParam::getCurrentProducerId(), 'status' => StatusInterface::STATUS_ONLINE])->orderBy('is_bread_box ASC, name ASC')->asArray()->all(), 'id', 'name'),
'value' => function($model) {
if($model->pointSale) {
return Html::encode($model->pointSale->name) ;

+ 124
- 0
backend/views/user-admin/email_deliverability.php Visa fil

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

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

use common\helpers\GlobalParam;
use common\helpers\Price;
use domain\Order\Order\Order;
use domain\Producer\Producer\ProducerModule;
use domain\User\User\User;
use domain\User\User\UserModule;
use domain\User\UserProducer\UserProducer;
use domain\User\UserProducer\UserProducerModule;
use yii\grid\GridView;
use yii\helpers\Html;
use domain\User\UserGroup\UserGroupModule;

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

$this->setTitle('Déliverabilité des emails');
$this->addBreadcrumb($this->getTitle());

?>

<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'summary' =>
'Affichage de <b>{begin, number}-{end, number}</b> sur <b>{totalCount, number}</b> {totalCount, plural, one{élément} other{éléments}}.',
'columns' => [
[
'attribute' => 'username',
'label' => 'Nom',
'value' => function ($user) use ($userModule) {
return $userModule->getUsername($user);
}
],
[
'attribute' => 'type',
'label' => 'Type',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'filter' => $userModule->getTypeChoicesArray(),
'value' => function ($user) use ($userModule) {
return $userModule->getTypeLabel($user['type']);
}
],
[
'attribute' => 'contacts',
'header' => 'Contacts',
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($user) {
$html = '';
if (strlen($user['phone'])) {
$html .= $user['phone'];
}
if (strlen($user['phone']) && strlen($user['email'])) {
$html .= '<br />';
}
if (strlen($user['email'])) {
$html .= $user['email'];
}
return $html;
}
],
[
'attribute' => 'producers',
'label' => 'Producteurs',
'format' => 'raw',
'contentOptions' => ['class' => 'column-hide-on-mobile align-center'],
'value' => function ($user) use ($userProducerModule) {
$html = '';
$userProducersArray = $userProducerModule->getRepository()->findUserProducersByUser($user);

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

return $html;
}
]
],
]); ?>

+ 11
- 1
backend/views/user-admin/index.php Visa fil

@@ -122,7 +122,7 @@ $this->addBreadcrumb($this->getTitle());
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{switch} ',
'template' => '{problemReceivingEmails} {switch}',
'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'],
'buttons' => [
@@ -142,6 +142,16 @@ $this->addBreadcrumb($this->getTitle());
'class' => 'btn btn-default'
]);
},
'problemReceivingEmails' => function($url, $model) use ($userModule, $userCurrent) {
if(!$model->getProblemReceivingEmails()) {
return Html::a('<i class="fa fa-life-ring"></i>',
Yii::$app->urlManager->createUrl(['user-admin/report-problem-receiving-emails', 'id' => $model->id]),
[
'title' => 'Signaler comme ayant des problèmes de réception des emails',
'class' => 'btn btn-default',
]);
}
},
'switch' => function($url, $model) use ($userModule, $userCurrent) {
if($userModule->getAuthorizationChecker()->isGrantedAsAdministrator($userCurrent)) {
return Html::a('<i class="fa fa-fw fa-user-secret"></i>',

+ 18
- 2
backend/views/user/_form.php Visa fil

@@ -56,7 +56,7 @@ $distributionModule = DistributionModule::getInstance();
<div class="user-form" id="app-user-form">

<?php $form = ActiveForm::begin([
'enableClientValidation' => false
'enableClientValidation' => false,
]); ?>

<div class="col-md-8 col-no-padding-left">
@@ -97,7 +97,7 @@ $distributionModule = DistributionModule::getInstance();
</h3>
</div>
<div class="panel-body">
<?= $form->field($model, 'password_new')->passwordInput() ?>
<?= $form->field($model, 'password_new')->passwordInput(['autocomplete' => 'new-password']) ?>
</div>
</div>
<?php endif; ?>
@@ -184,6 +184,20 @@ $distributionModule = DistributionModule::getInstance();
]
); ?>
<?php endif; ?>
<?= $form->field($model, 'problem_receiving_emails')->widget(Toggle::class,
[
'options' => [
'data-id' => $model->id,
'data-on' => 'Oui',
'data-off' => 'Non',
'data-onstyle' => 'danger',
'data-offstyle' => 'default',
],
]
); ?>
<?php if($userModule->getAuthorizationChecker()->isGrantedAsAdministrator($userCurrent)): ?>
<?= $form->field($model, 'note_emails')->textarea(['rows' => 7]); ?>
<?php endif; ?>
</div>
</div>

@@ -201,6 +215,8 @@ $distributionModule = DistributionModule::getInstance();
'data-id' => $model->id,
'data-on' => 'Oui',
'data-off' => 'Non',
'data-onstyle' => 'danger',
'data-offstyle' => 'default',
],
]
)->hint('Si activé, le nom du client sera mis en avant dans la liste des commandes'); ?>

+ 6
- 0
backend/views/user/_menu_navigation.php Visa fil

@@ -1,5 +1,6 @@
<?php

use common\helpers\GlobalParam;
use domain\Order\Order\OrderModule;
use domain\User\User\User;
use domain\User\User\UserModule;
@@ -8,8 +9,10 @@ use common\helpers\Price;
$userModule = UserModule::getInstance();
$orderModule = OrderModule::getInstance();

$userCurrent = GlobalParam::getCurrentUser();
$credit = $userModule->getRepository()->getCredit($user);
$countOrders = $orderModule->getRepository()->countOrdersByUser($user);
$countUserMessages = $this->getUserMessageModule()->getRepository()->countUserMessagesByUser($user);

?>

@@ -18,6 +21,9 @@ $countOrders = $orderModule->getRepository()->countOrdersByUser($user);
<?= menu_navigation_item('update', 'Profil', $action, $user) ?>
<?= menu_navigation_item('credit', 'Cagnotte <span class="label label-default badge">'.Price::format($credit).'</span>', $action, $user) ?>
<?= menu_navigation_item('orders', 'Commandes <span class="label label-default badge">'.$countOrders.'</span>', $action, $user) ?>
<?php if($userModule->getAuthorizationChecker()->isGrantedAsAdministrator($userCurrent)): ?>
<?= menu_navigation_item('messages', 'Messages <span class="label label-default badge">'.$countUserMessages.'</span>', $action, $user) ?>
<?php endif; ?>
</ul>



+ 15
- 1
backend/views/user/index.php Visa fil

@@ -115,6 +115,9 @@ $this->render('_menu_filter', [
}
if (strlen($user['email'])) {
$html .= $user['email'];
if($user['problem_receiving_emails']) {
$html .= ' <span class="fa fa-life-ring"></span>';
}
}
return $html;
}
@@ -199,10 +202,11 @@ $this->render('_menu_filter', [
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{view} {update}
'template' => '{view} {update}
<div class="wrapper-button-dropdown">
<button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-default dropdown-toggle"><span class="caret"></span></button>
<ul class="dropdown-menu">
<li>{problemReceivingEmails}</li>
<li>{delete}</li>
<li>{switch}</li>
</ul></div>',
@@ -225,6 +229,16 @@ $this->render('_menu_filter', [
'class' => 'btn btn-default'
]);
},
'problemReceivingEmails' => function($url, $model) use ($userModule, $userCurrent) {
if(!$model->getProblemReceivingEmails()) {
return Html::a('<i class="fa fa-life-ring"></i> Réception emails',
Yii::$app->urlManager->createUrl(['user/report-problem-receiving-emails', 'id' => $model->id]),
[
'title' => 'Signaler comme ayant des problèmes de réception des emails',
'class' => '',
]);
}
},
'delete' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-minus"></span> Enlever',
Yii::$app->urlManager->createUrl(array_merge(['user/delete', 'id' => $model->id], Yii::$app->getRequest()->getQueryParams())),

+ 124
- 0
backend/views/user/messages.php Visa fil

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

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

use domain\User\User\UserModule;
use yii\grid\GridView;
use yii\helpers\Html;
use yii\widgets\ActiveForm;

$userModule = $this->getUserModule();
$orderModule = $this->getOrderModule();
$userModule = $this->getUserModule();
$username = Html::encode($userModule->getSolver()->getUsername($user));
$this->setTitle($username.' (#'.$user->id.')') ;
$this->addBreadcrumb(['label' => 'Utilisateurs', 'url' => ['index']]) ;
$this->addBreadcrumb(['label' => $username]) ;
$this->addBreadcrumb('Messages') ;

?>

<?= $this->render('_menu_navigation', [
'action' => 'messages',
'user' => $user
]); ?>

<div class="user-messages tab-content">

<div class="alert alert-dark">
<i class="bi bi-info-circle"></i>
Les messages envoyés ici sont affichés à l'utilisateur directement sur la boutique.
</div>

<?php $form = ActiveForm::begin([
'enableClientValidation' => false
]); ?>
<?= $form->field($userMessageModel, 'message')->textarea(['rows' => 4]) ?>
<?= Html::submitButton($userMessageModel->isNewRecord ? 'Envoyer' : 'Modifier', ['class' => 'btn btn-primary', 'name' => 'save']) ?>
<?php ActiveForm::end(); ?>
<br />

<?= GridView::widget([
'dataProvider' => $userMessagesDataProvider,
'columns' => [
[
'label' => 'Message',
'format' => 'raw',
'value' => function ($userMessage) {
return nl2br(Html::encode($userMessage->getMessage())).'<br /><br /><em>'.$userMessage->getCreatedAt()->format('\L\e d/m/Y à H:i').'</em>';
}
],
[
'label' => 'Lu',
'format' => 'raw',
'value' => function ($userMessage) {
if($userMessage->getReadAt()) {
//return '<span class="label label-success" title="'.$userMessage->getReadAt()->format('\L\e d/m/Y à H:i').'">Oui</span>';
return '<span class="label label-success">Oui</span><br />'.$userMessage->getReadAt()->format('\L\e d/m/Y à H:i');
}
else {
return '<span class="label label-default">Non</span>';
}
}
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{update} {delete}',
'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'],
'buttons' => [
'update' => function ($url, $userMessage) {
return Html::a('<span class="glyphicon glyphicon-pencil"></span>',
Yii::$app->urlManager->createUrl(['user/messages', 'id' => $userMessage->getUser()->id, 'idUserMessage' => $userMessage->id]),
[
'title' => 'Modifier',
'class' => 'btn btn-default'
]);
},
'delete' => function ($url, $userMessage) {
return Html::a('<span class="glyphicon glyphicon-trash"></span>',
Yii::$app->urlManager->createUrl(['user/message-delete', 'idUser' => $userMessage->getUser()->getId(), 'idUserMessage' => $userMessage->getId()]),
[
'title' => 'Supprimer',
'class' => 'btn btn-default'
]);
},
],
],
],
]); ?>
</div>

+ 9
- 0
backend/views/user/view.php Visa fil

@@ -139,6 +139,15 @@ $this->addBreadcrumb('Récapitulatif') ;
</span>
</li>
<?php endif; ?>
<li class="list-group-item">
<strong>Problème réception emails</strong>
<span class="pull-right">
<?php $hasProblemReceivingEmails = $model->problem_receiving_emails; ?>
<span class="label label-<?= $hasProblemReceivingEmails ? 'danger' : 'default' ?>">
<?= $hasProblemReceivingEmails ? 'Oui' : 'Non' ?>
</span>
</span>
</li>
<?php if($model->userPointSale): ?>
<li class="list-group-item">
<strong>Points de vente</strong>

+ 9
- 0
backend/web/js/backend.js Visa fil

@@ -59,8 +59,17 @@ $(document).ready(function () {
opendistrib_check_all_checkboxes();
opendistrib_dashboard_admin_statistics();
opendistrib_tinymce_responsive();
opendistrib_sponsorship();
});

function opendistrib_sponsorship() {
$('#sponsorship-link-copy').click(function() {
navigator.clipboard.writeText($(this).attr('href'));
appAlerts.alert('success', 'Lien de parrainage copié');
return false;
});
}

function saveData (data, fileName) {
var a = document.createElement("a");
document.body.appendChild(a);

+ 1
- 1
backend/web/js/vuejs/distribution-index.js Visa fil

@@ -252,7 +252,7 @@ if($(selector).length) {
key: 'leave_period',
dates: leave_period_dates,
highlight: {
color: 'blue',
color: 'gray',
fillMode: 'solid'
}
});

+ 1
- 0
common/components/BusinessLogic.php Visa fil

@@ -26,6 +26,7 @@ class BusinessLogic
$this->getUserProducerModule(),
$this->getUserPointSaleModule(),
$this->getUserModule(),
$this->getUserMessageModule(),
$this->getPointSaleDistributionModule(),
$this->getProductDistributionModule(),
$this->getProductCategoryModule(),

+ 6
- 0
common/components/BusinessLogicTrait.php Visa fil

@@ -36,6 +36,7 @@ use domain\Ticket\TicketMessage\TicketMessageModule;
use domain\Ticket\TicketUser\TicketUserModule;
use domain\User\User\UserModule;
use domain\User\UserGroup\UserGroupModule;
use domain\User\UserMessage\UserMessageModule;
use domain\User\UserProducer\UserProducerModule;
use domain\User\UserUserGroup\UserUserGroupModule;

@@ -181,6 +182,11 @@ trait BusinessLogicTrait
return UserModule::getInstance();
}

public function getUserMessageModule(): UserMessageModule
{
return UserMessageModule::getInstance();
}

public function getUserGroupModule(): UserGroupModule
{
return UserGroupModule::getInstance();

+ 1
- 1
common/config/params.php Visa fil

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

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

+ 30
- 0
common/versions/24.6.C.php Visa fil

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

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

version(
'17/06/2024',
[
[
"Points de vente partagés : possibilité de distributions en commun avec d'autres producteurs (Points de vente > Partages)",
"[Boutique & administration] Gestion des utilisateurs qui ne reçoivent pas les emails :
possibilité d'informer facilement le développeur via la boutique (onglet 'Infolettre') pour les utilisateurs
et la section 'Utilisateurs' de l'administration pour les producteurs",
],
[
"[Administration] Factures & bons de livraisons > Liste : amélioration des filtres de recherche",
"[Administration] Abonnements > liste : ajustement de l'ordre des points de vente dans le champs de recherche",
"[Boutique & administration] Congés : couleur en gris dans les calendrier",
"[Boutique] Abonnements > formulaire création/modification : amélioration responsive tableau produit",
]
],
[
[
],
[
]
],
$userCurrent
);

?>

+ 26
- 0
console/migrations/m240611_091617_add_column_user_problem_receiving_emails.php Visa fil

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

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

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

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

+ 37
- 0
console/migrations/m240611_125313_create_table_user_message.php Visa fil

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

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

/**
* Class m240611_125313_create_table_user_message
*/
class m240611_125313_create_table_user_message extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->createTable('user_message', [
'id' => 'pk',
'id_user' => Schema::TYPE_INTEGER,
'message' => Schema::TYPE_TEXT,
'created_at' => Schema::TYPE_DATETIME,
'created_by' => Schema::TYPE_INTEGER,
'read_at' => Schema::TYPE_DATETIME,
]);
$this->addForeignKey('fk_user_message_id_user', 'user_message', 'id_user', 'user', 'id');
$this->addForeignKey('fk_user_message_created_by', 'user_message', 'created_by', 'user', 'id');
}

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

+ 26
- 0
console/migrations/m240612_062929_add_column_user_note_email.php Visa fil

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

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

/**
* Class m240612_062929_add_column_user_note_email
*/
class m240612_062929_add_column_user_note_email extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('user', 'note_emails', Schema::TYPE_TEXT);
}

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

+ 41
- 0
console/migrations/m240613_070747_add_columns_producer_sponsorship.php Visa fil

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

use common\helpers\Password;
use domain\Producer\Producer\ProducerBuilder;
use domain\Producer\Producer\ProducerRepository;
use yii\db\Migration;
use yii\db\Schema;

/**
* Class m240613_070747_add_columns_producer_sponsorship
*/
class m240613_070747_add_columns_producer_sponsorship extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('producer', 'sponsorship_code', Schema::TYPE_STRING);
$this->addColumn('producer', 'sponsored_by', Schema::TYPE_INTEGER);
$this->addColumn('producer', 'sponsorship_sponsor_reward', Schema::TYPE_BOOLEAN);
$this->addColumn('producer', 'sponsorship_godson_reward', Schema::TYPE_BOOLEAN);

$producersArray = ProducerRepository::getInstance()->findAll();
foreach($producersArray as $producer) {
ProducerBuilder::getInstance()->initSponsorshipCode($producer);
$producer->save();
}
}

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

+ 29
- 9
domain/Config/TaxRate/TaxRate.php Visa fil

@@ -6,17 +6,11 @@ use common\components\ActiveRecordCommon;

class TaxRate extends ActiveRecordCommon
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'tax_rate';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
@@ -25,9 +19,6 @@ class TaxRate extends ActiveRecordCommon
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
@@ -36,4 +27,33 @@ class TaxRate extends ActiveRecordCommon
'value' => 'Valeur (0.2 pour 20%)',
];
}

/* Getters / Setters */

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

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

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

public function getValue(): ?float
{
return $this->value;
}

public function setValue(?float $value): self
{
$this->value = $value;
return $this;
}
}

+ 0
- 9
domain/Config/TaxRate/TaxRateBuilder.php Visa fil

@@ -12,13 +12,4 @@ class TaxRateBuilder extends AbstractBuilder

return $taxRate;
}

public function createTaxRate(): TaxRate
{
$taxRate = $this->instanciateTaxRate();

$this->saveCreate($taxRate);

return $taxRate;
}
}

+ 24
- 0
domain/Config/TaxRate/TaxRateManager.php Visa fil

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

namespace domain\Config\TaxRate;

use domain\_\AbstractManager;

class TaxRateManager extends AbstractManager
{
protected TaxRateBuilder $taxRateBuilder;

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

public function createTaxRate(string $name, float $value): TaxRate
{
$taxRate = $this->taxRateBuilder->instanciateTaxRate();
$taxRate->setName($name);
$taxRate->setValue($value);
$taxRate->save();
return $taxRate;
}
}

+ 26
- 1
domain/Document/DeliveryNote/DeliveryNoteSearch.php Visa fil

@@ -43,6 +43,7 @@ use yii\data\ActiveDataProvider;

class DeliveryNoteSearch extends DeliveryNote
{
public $with_invoice;
public $id_point_sale;
public $date_distribution;

@@ -50,6 +51,7 @@ class DeliveryNoteSearch extends DeliveryNote
{
return [
[[], 'safe'],
[['is_sent', 'with_invoice'], 'boolean'],
[['comment', 'address', 'status', 'date_distribution'], 'string'],
[['id_user', 'id_point_sale'], 'integer'],
[['name', 'reference'], 'string', 'max' => 255],
@@ -58,7 +60,8 @@ class DeliveryNoteSearch extends DeliveryNote

public function search($params)
{
$deliveryNoteRepository = DeliveryNoteRepository::getInstance();
$deliveryNoteModule = DeliveryNoteModule::getInstance();
$deliveryNoteRepository = $deliveryNoteModule->getRepository();
$optionsSearch = $deliveryNoteRepository->getDefaultOptionsSearch();

if(isset($params['DeliveryNoteSearch']['id_point_sale'])) {
@@ -93,10 +96,32 @@ class DeliveryNoteSearch extends DeliveryNote
$query->andWhere(['order.id_point_sale' => $this->id_point_sale]);
}

if(!is_null($this->is_sent) && is_numeric($this->is_sent)) {
if($this->is_sent) {
$query->andWhere(['delivery_note.is_sent' => 1]);
}
else {
$query->andWhere('delivery_note.is_sent IS NULL OR delivery_note.is_sent = 0');
}
}

if ($this->date_distribution && strlen($this->date_distribution)) {
$query->andFilterWhere(['like', 'distribution.date', date('Y-m-d', strtotime(str_replace('/', '-', $this->date_distribution)))]);
}

// filtre facture (oui / non)
$models = $dataProvider->getModels();
foreach($models as $index => $deliveryNote) {
if(!is_null($this->with_invoice) && is_numeric($this->with_invoice)) {
$invoice = $deliveryNoteModule->getSolver()->getInvoice($deliveryNote);
if(($this->with_invoice && !$invoice) || (!$this->with_invoice && $invoice)) {
unset($models[$index]);
}
}
}
$dataProvider->setModels($models);


return $dataProvider;
}
}

+ 55
- 7
domain/Document/Invoice/InvoiceSearch.php Visa fil

@@ -40,35 +40,57 @@ namespace domain\Document\Invoice;

use common\helpers\GlobalParam;
use yii\data\ActiveDataProvider;
use yii\data\Sort;

class InvoiceSearch extends Invoice
{
var $paid = null;
var $username;

public function rules()
{
return [
[[], 'safe'],
[['comment', 'address', 'status', 'username'], 'string'],
[['name', 'reference'], 'string', 'max' => 255],
[['paid'], 'safe'],
[['is_sent'], 'boolean'],
[['comment', 'address', 'status', 'username', 'date'], 'string'],
[['name', 'reference', 'username'], 'string', 'max' => 255],
];
}

public function search($params)
{
$invoiceRepository = InvoiceRepository::getInstance();
$invoiceModule = InvoiceModule::getInstance();
$invoiceRepository = $invoiceModule->getRepository();
$optionsSearch = $invoiceRepository->getDefaultOptionsSearch();

$sort = new Sort([
'attributes' => [
'status',
'reference',
'name',
'date',
'username' => [
'asc' => ['user_invoice.lastname' => SORT_ASC, 'user_invoice.name' => SORT_ASC],
'desc' => ['user_invoice.lastname' => SORT_DESC, 'user_invoice.name' => SORT_DESC],
]
],
'defaultOrder' => [
'status' => SORT_ASC,
'reference' => SORT_DESC
]
]);

$query = Invoice::find()
->with($optionsSearch['with'])
->joinWith($optionsSearch['join_with'])
->where(['invoice.id_producer' => GlobalParam::getCurrentProducerId()])
->orderBy('invoice.status ASC, invoice.reference DESC')
//->orderBy('invoice.status ASC, invoice.reference DESC')
->orderBy($sort->orders)
->groupBy('invoice.id');

$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => ['attributes' => ['name', 'reference', 'date']],
'sort' => $sort,
'pagination' => [
'pageSize' => 20,
],
@@ -82,7 +104,6 @@ class InvoiceSearch extends Invoice
$query->andFilterWhere(['like', 'invoice.name', $this->name]);
$query->andFilterWhere(['like', 'invoice.reference', $this->reference]);
$query->andFilterWhere(['like', 'invoice.status', $this->status]);

$query->andFilterWhere([
'or',
['like', 'user_invoice.lastname', $this->username],
@@ -90,6 +111,33 @@ class InvoiceSearch extends Invoice
['like', 'user_invoice.name_legal_person', $this->username],
]);

if ($this->date && strlen($this->date)) {
$query->andFilterWhere(['like', 'invoice.date', date('Y-m-d', strtotime(str_replace('/', '-', $this->date)))]);
}

// filtre envoyé
if(!is_null($this->is_sent) && is_numeric($this->is_sent)) {
if($this->is_sent) {
$query->andWhere(['invoice.is_sent' => 1]);
}
else {
$query->andWhere('invoice.is_sent IS NULL OR invoice.is_sent = 0');
}
}

// filter payé / non payé
// @TODO : comprendre pourquoi la pagination ne suit pas
$models = $dataProvider->getModels();
foreach($models as $index => $invoice) {
if(!is_null($this->paid) && is_numeric($this->paid)) {
$isInvoicePaid = $invoiceModule->getSolver()->isInvoicePaid($invoice);
if(($this->paid && !$isInvoicePaid) || (!$this->paid && $isInvoicePaid)) {
unset($models[$index]);
}
}
}
$dataProvider->setModels($models);

return $dataProvider;
}
}

+ 2
- 0
domain/Feature/Feature/Feature.php Visa fil

@@ -51,6 +51,8 @@ class Feature extends ActiveRecordCommon
const ALIAS_SETTINGS = 'settings';
const ALIAS_SHOP_SUPPORT = 'shop_support';
const ALIAS_SHARED_POINT_SALE = 'shared_point_sale';
const ALIAS_SUMUP_SYNCHRONIZATION = 'sumup_synchronization';
const ALIAS_SPONSORSHIP = 'sponsorship';

/**
* @inheritdoc

+ 2
- 0
domain/Feature/Feature/FeatureDefinition.php Visa fil

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

+ 1
- 1
domain/Feature/Feature/FeatureRepository.php Visa fil

@@ -39,7 +39,7 @@ class FeatureRepository extends AbstractRepository

public function findPaidFeatures(): array
{
return $this->createQuery()
return $this->createDefaultQuery()
->filterIsPaidFeature()
->find();
}

+ 56
- 2
domain/Producer/Producer/Producer.php Visa fil

@@ -173,7 +173,8 @@ class Producer extends ActiveRecordCommon
'option_weeks_distributions_activated_in_advance',
'option_document_width_logo',
'export_shopping_cart_labels_number_per_column',
'id_user_group_default'
'id_user_group_default',
'sponsored_by'
],
'integer'
],
@@ -261,6 +262,7 @@ class Producer extends ActiveRecordCommon
'option_leave_period_message_title',
'option_leave_period_message',
'option_credit_description',
'sponsorship_code'
],
'string'
],
@@ -304,7 +306,9 @@ class Producer extends ActiveRecordCommon
'delivery_note_automatic_validation',
'is_new',
'agree_contact_about_software_development',
'option_leave_period_message_display'
'option_leave_period_message_display',
'sponsorship_sponsor_reward',
'sponsorship_godson_reward',
],
'boolean'
],
@@ -542,6 +546,7 @@ class Producer extends ActiveRecordCommon
'option_leave_period_message_title' => 'Titre du message des congés',
'option_leave_period_message' => 'Message des congés',
'option_credit_description' => "Description Cagnotte",
'sponsorship_sponsor_reward' => 'Récompense parrain',
];
}

@@ -550,6 +555,50 @@ class Producer extends ActiveRecordCommon
return $this->name;
}

public function getSponsorshipCode(): string
{
return $this->sponsorship_code;
}

public function setSponsorshipCode(string $sponsorshipCode): self
{
$this->sponsorship_code = $sponsorshipCode;
return $this;
}

public function getSponsoredBy(): ?Producer
{
return $this->sponsoredByRelation;
}

public function setSponsoredBy(Producer $producer): self
{
$this->populateFieldObject('sponsored_by', 'sponsoredByRelation', $producer);
return $this;
}

public function getSponsorshipSponsorReward(): ?bool
{
return $this->sponsorship_sponsor_reward;
}

public function setSponsorshipSponsorReward(bool $sponsorshipSponsorReward = null): self
{
$this->sponsorship_sponsor_reward = $sponsorshipSponsorReward;
return $this;
}

public function getSponsorshipGodsonReward(): ?bool
{
return $this->sponsorship_godson_reward;
}

public function setSponsorshipGodsonReward(bool $sponsorshipGodsonReward = null): self
{
$this->sponsorship_godson_reward = $sponsorshipGodsonReward;
return $this;
}

/*
* Relations
*/
@@ -590,6 +639,11 @@ class Producer extends ActiveRecordCommon
$this->populateFieldObject('id_user_group_default', 'userGroupDefault', $userGroup);
}

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

// ---

public static function getBillingTypePopulateDropdown()

+ 8
- 0
domain/Producer/Producer/ProducerBuilder.php Visa fil

@@ -30,8 +30,10 @@ class ProducerBuilder extends AbstractBuilder
public function instanciateProducer(): Producer
{
$producer = new Producer();

$producer->order_deadline = Producer::ORDER_DEADLINE_DEFAULT;
$producer->order_delay = Producer::ORDER_DELAY_DEFAULT;
$this->initSponsorshipCode($producer);

return $producer;
}
@@ -161,4 +163,10 @@ class ProducerBuilder extends AbstractBuilder
$producer->save();
}
}

public function initSponsorshipCode(Producer $producer): self
{
$producer->setSponsorshipCode(Password::generate());
return $this;
}
}

+ 14
- 0
domain/Producer/Producer/ProducerRepository.php Visa fil

@@ -445,4 +445,18 @@ class ProducerRepository extends AbstractRepository

return 0;
}

public function findOneProducerBySponsorshipCode(string $sponsorshipCode): ?Producer
{
return $this->createQuery()
->filterBySponsorshipCode($sponsorshipCode)
->findOne();
}

public function findProducersSponsorshipGodsons(Producer $producer): array
{
return $this->createQuery()
->filterBySponsoredBy($producer)
->find();
}
}

+ 13
- 0
domain/Producer/Producer/ProducerRepositoryQuery.php Visa fil

@@ -42,4 +42,17 @@ class ProducerRepositoryQuery extends AbstractRepositoryQuery
$this->andWhere('producer.option_time_saved > 0');
return $this;
}

public function filterBySponsorshipCode(string $sponsorshipCode): self
{
$this->andWhere('producer.sponsorship_code LIKE :sponsorship_code')
->addParams(['sponsorship_code' => $sponsorshipCode]);
return $this;
}

public function filterBySponsoredBy(Producer $producer): self
{
$this->andWhere(['producer.sponsored_by' => $producer->id]);
return $this;
}
}

+ 30
- 0
domain/Producer/Producer/ProducerSolver.php Visa fil

@@ -307,4 +307,34 @@ class ProducerSolver extends AbstractService implements SolverInterface

return false;
}

public function getSponsorshipLink(Producer $producer): string
{
return \Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/signup', 'from' => $producer->getSponsorshipCode()]);
}

public function getDateEndFreeBillingPeriodSponsorship(Producer $producer): ?\DateTime
{
if($producer->getSponsoredBy()) {
$dateStart = new \DateTime($producer->date_creation);
return $dateStart
->modify('+4 months')
->modify('first day of this month');
}

return null;
}

public function isFreeBillingPeriodSponsorship(Producer $producer): bool
{
if($producer->getSponsoredBy()) {
$dateNow = new \DateTime();
$dateEndFreeBillingPeriodSponsorship = $this->getDateEndFreeBillingPeriodSponsorship($producer);
if($dateNow < $dateEndFreeBillingPeriodSponsorship) {
return true;
}
}

return false;
}
}

+ 18
- 3
domain/User/User/User.php Visa fil

@@ -108,8 +108,8 @@ class User extends ActiveRecordCommon implements IdentityInterface
[['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', 'exclude_export_shopping_cart_labels',
'send_mail_welcome', 'trust_alert', 'newsletter_souke'], 'boolean'],
[['lastname', 'name', 'phone', 'address', 'type', 'name_legal_person', 'evoliz_code', 'trust_alert_comment'], 'string'],
'send_mail_welcome', 'trust_alert', 'newsletter_souke', 'problem_receiving_emails'], 'boolean'],
[['lastname', 'name', 'phone', 'address', 'type', 'name_legal_person', 'evoliz_code', 'trust_alert_comment', 'note_emails'], 'string'],
['lastname', 'verifyOneName', 'skipOnError' => false, 'skipOnEmpty' => false],
[['email', 'email_sending_invoicing_documents'], 'email', 'message' => 'Cette adresse email n\'est pas valide'],
['email', 'verifyEmail'],
@@ -157,7 +157,9 @@ class User extends ActiveRecordCommon implements IdentityInterface
'email_sending_invoicing_documents' => 'Email facturation',
'trust_alert' => 'Alerte confiance',
'trust_alert_comment' => 'Commentaire',
'newsletter_souke' => "S'abonner à l'infolettre de Souke"
'newsletter_souke' => "S'abonner à l'infolettre de Souke",
'problem_receiving_emails' => "Rencontre des problèmes pour recevoir les emails",
'note_emails' => "Note emails"
];
}

@@ -247,6 +249,19 @@ class User extends ActiveRecordCommon implements IdentityInterface
}
}

/* Getters / Setters */

public function getProblemReceivingEmails(): ?bool
{
return $this->problem_receiving_emails;
}

public function setProblemReceivingEmails(bool $problemReceivingEmails = null): self
{
$this->problem_receiving_emails = $problemReceivingEmails;
return $this;
}

/*
* Relations
*/

+ 6
- 1
domain/User/User/UserManager.php Visa fil

@@ -19,7 +19,6 @@ class UserManager extends AbstractManager
{
$password = $this->userBuilder->generatePassword($user);
$this->userNotifier->sendMailWelcome($user, $password);

}

public function newPassword(User $user)
@@ -27,4 +26,10 @@ class UserManager extends AbstractManager
$password = $this->userBuilder->generatePassword($user);
$this->userNotifier->sendMailNewPassword($user, $password);
}

public function reportProblemReceivingEmails(User $user): bool
{
$user->setProblemReceivingEmails(true);
return $this->userBuilder->update($user);
}
}

+ 12
- 0
domain/User/User/UserRepository.php Visa fil

@@ -312,4 +312,16 @@ class UserRepository extends AbstractRepository

return $userSystem;
}

public function findUsersWithProblemReceivingEmails()
{
return $this->createQuery()
->filterHasProblemReceivingEmails()
->find();
}

public function countUsersWithProblemReceivingEmails(): int
{
return count($this->findUsersWithProblemReceivingEmails());
}
}

+ 6
- 0
domain/User/User/UserRepositoryQuery.php Visa fil

@@ -61,4 +61,10 @@ class UserRepositoryQuery extends AbstractRepositoryQuery
->addParams(['date' => $date->format('Y-m-d H:i:s')]);
return $this;
}

public function filterHasProblemReceivingEmails(): self
{
$this->andWhere(['problem_receiving_emails' => true]);
return $this;
}
}

+ 10
- 1
domain/User/User/UserSearch.php Visa fil

@@ -54,7 +54,9 @@ class UserSearch extends User
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'], 'boolean'],
[['no_mail', 'mail_distribution_monday', 'mail_distribution_tuesday', 'mail_distribution_wednesday',
'mail_distribution_thursday', 'mail_distribution_friday', 'mail_distribution_saturday',
'mail_distribution_sunday', 'problem_receiving_emails'], 'boolean'],
[['lastname', 'name', 'phone', 'address', 'type', 'newsletter', 'contacts'], 'string'],
[['id_point_sale', 'inactive', 'subscribers', 'id_user_user_group'], 'integer'],
[['date_last_connection', 'id_point_sale', 'username'], 'safe'],
@@ -91,6 +93,7 @@ class UserSearch extends User
. '`user`.date_last_connection, '
. '`user`.name_legal_person, '
. '`user`.type, '
. '`user`.problem_receiving_emails, '
. '(SELECT COUNT(*) FROM `order` WHERE `user`.id = `order`.id_user) AS count_orders');

if($producer) {
@@ -181,6 +184,12 @@ class UserSearch extends User
]);
}

if(isset($this->problem_receiving_emails)) {
$query->andWhere([
'user.problem_receiving_emails' => (bool) $this->problem_receiving_emails
]);
}

return $dataProvider;
}
}

+ 113
- 0
domain/User/UserMessage/UserMessage.php Visa fil

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

namespace domain\User\UserMessage;

use common\components\ActiveRecordCommon;
use domain\User\User\User;

class UserMessage extends ActiveRecordCommon
{
public static function tableName()
{
return 'user_message';
}

public function rules()
{
return [
[['id_user', 'message', 'created_at', 'created_by'], 'required'],
[['message'], 'string'],
[['id_user', 'created_by'], 'integer'],
[['created_at', 'read_at'], 'safe']
];
}

public function attributeLabels()
{
return [
'id_user' => 'Utilisateur',
'message' => 'Message',
'created_at' => 'Date de création',
'created_by' => 'Créé par',
'read_at', 'Date de lecture'
];
}

/* Getters / Setters */

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

public function getUser(): User
{
return $this->userRelation;
}

public function setUser(User $user): self
{
$this->populateFieldObject('id_user', 'userRelation', $user);
return $this;
}

public function getMessage(): string
{
return $this->message;
}

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

public function getCreatedAt(): \DateTime
{
return new \DateTime($this->created_at);
}

public function setCreatedAt(\DateTime $createdAt): self
{
$this->created_at = $createdAt->format('Y-m-d H:i:s');
return $this;
}

public function getCreatedBy(): User
{
return $this->createdByRelation;
}

public function setCreatedBy(User $createdBy): self
{
$this->populateFieldObject('created_by', 'createdByRelation', $createdBy);
return $this;
}

public function getReadAt(): ?\DateTime
{
if($this->read_at) {
return new \DateTime($this->read_at);
}

return null;
}

public function setReadAt(\DateTime $readAt): self
{
$this->read_at = $readAt->format('Y-m-d H:i:s');
return $this;
}

/* Relations */

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

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

+ 20
- 0
domain/User/UserMessage/UserMessageBuilder.php Visa fil

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

namespace domain\User\UserMessage;

use domain\_\AbstractBuilder;
use domain\User\User\User;

class UserMessageBuilder extends AbstractBuilder
{
public function instanciateUserMessage(User $user, User $createdBy): UserMessage
{
$userMessage = new UserMessage();

$userMessage->setUser($user);
$userMessage->setCreatedAt(new \DateTime());
$userMessage->setCreatedBy($createdBy);

return $userMessage;
}
}

+ 13
- 0
domain/User/UserMessage/UserMessageDefinition.php Visa fil

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

namespace domain\User\UserMessage;

use domain\_\AbstractDefinition;

class UserMessageDefinition extends AbstractDefinition
{
public function getEntityFqcn(): string
{
return UserMessage::class;
}
}

+ 35
- 0
domain/User/UserMessage/UserMessageManager.php Visa fil

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

namespace domain\User\UserMessage;

use domain\_\AbstractManager;
use domain\User\User\User;

class UserMessageManager extends AbstractManager
{
protected UserMessageBuilder $userMessageBuilder;

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

public function createUserMessage(User $user, string $message, User $createdBy): UserMessage
{
$userMessage = $this->userMessageBuilder->instanciateUserMessage($user, $createdBy);
$userMessage->setMessage($message);
$userMessage->save();
return $userMessage;
}

public function deleteUserMessage(UserMessage $userMessage): bool
{
return $userMessage->delete();
}

public function readUserMessage(UserMessage $userMessage): bool
{
$userMessage->setReadAt(new \DateTime());
return $userMessage->save();
}
}

+ 38
- 0
domain/User/UserMessage/UserMessageModule.php Visa fil

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

namespace domain\User\UserMessage;

use domain\_\AbstractModule;

class UserMessageModule extends AbstractModule
{
public function getServices(): array
{
return [
UserMessageDefinition::class,
UserMessageBuilder::class,
UserMessageRepository::class,
UserMessageManager::class
];
}

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

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

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

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

+ 61
- 0
domain/User/UserMessage/UserMessageRepository.php Visa fil

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

namespace domain\User\UserMessage;

use domain\_\AbstractRepository;
use domain\User\User\User;

class UserMessageRepository extends AbstractRepository
{
protected UserMessageRepositoryQuery $query;

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

public function getDefaultOptionsSearch(): array
{
return [
self::WITH => [],
self::JOIN_WITH => [],
self::ORDER_BY => 'created_at DESC',
self::ATTRIBUTE_ID_PRODUCER => ''
];
}

public function findOneUserMessageById(int $id): ?UserMessage
{
return $this->createQuery()
->filterById($id)
->findOne();
}

public function queryUserMessagesByUser(User $user)
{
return $this->createDefaultQuery()
->filterByUser($user);
}

public function findUserMessagesByUser(User $user): array
{
return $this->queryUserMessagesByUser($user)->find();
}

public function countUserMessagesByUser(User $user): int
{
return count($this->findUserMessagesByUser($user));
}

public function findUserMessagesUnreadByUser(User $user)
{
return $this->queryUserMessagesByUser($user)
->filterIsUnread()
->find();
}

public function countUserMessagesUnreadByUser(User $user): int
{
return count($this->findUserMessagesUnreadByUser($user));
}
}

+ 28
- 0
domain/User/UserMessage/UserMessageRepositoryQuery.php Visa fil

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

namespace domain\User\UserMessage;

use domain\_\AbstractRepositoryQuery;
use domain\User\User\User;

class UserMessageRepositoryQuery extends AbstractRepositoryQuery
{
protected UserMessageDefinition $definition;

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

public function filterByUser(User $user): self
{
$this->andWhere(['user_message.id_user' => $user->id]);
return $this;
}

public function filterIsUnread(): self
{
$this->andWhere('user_message.read_at IS NULL');
return $this;
}
}

+ 30
- 3
frontend/controllers/SiteController.php Visa fil

@@ -80,7 +80,6 @@ class SiteController extends FrontendController
[
'actions' => ['signup-producer'],
'allow' => true,
'roles' => ['@'],
],
[
'actions' => ['logout'],
@@ -354,8 +353,12 @@ class SiteController extends FrontendController
*/
public function actionSignup(string $type = 'user')
{
$sponsorshipFromCode = Yii::$app->request->get('from');
$sponsorshipProducerFrom = $this->findProducerSponsorshipByCode($sponsorshipFromCode);

$model = new SignupForm();
$model->option_user_producer = $type;
$model->sponsored_by = $sponsorshipProducerFrom ? $sponsorshipProducerFrom->id : false;
$producerModule = $this->getProducerModule();

if ($model->load(Yii::$app->request->post())) {
@@ -382,11 +385,11 @@ class SiteController extends FrontendController
$dataProducers = $producersArray['data'];
$optionsProducers = $producersArray['options'];


$paidFeaturesArray = $this->getFeatureModule()->getRepository()->findPaidFeatures();

return $this->render('signup', [
'model' => $model,
'sponsorshipProducerFrom' => $sponsorshipProducerFrom,
'dataProducers' => $dataProducers,
'dataProviderPrices' => $this->getDataProviderPrices(),
'paidFeaturesArray' => $paidFeaturesArray,
@@ -396,12 +399,26 @@ class SiteController extends FrontendController

public function actionSignupProducer()
{
$userCurrent = $this->getUserCurrent();
$sponsorshipFromCode = Yii::$app->request->get('from');
$sponsorshipProducerFrom = $this->findProducerSponsorshipByCode($sponsorshipFromCode);
if(!$userCurrent) {
// Lien parrainage
if($sponsorshipFromCode && strlen($sponsorshipFromCode)) {
$this->redirect(['site/signup', 'from' => $sponsorshipFromCode]);
}
else {
$this->redirect(['site/signup']);
}
}

$model = new SignupForm();
$model->signup_producer_only = 'producer';
$model->option_user_producer = 'producer';
$model->sponsored_by = $sponsorshipProducerFrom ? $sponsorshipProducerFrom->id : false;

if ($model->load(Yii::$app->request->post())) {
$user = $model->signup($this->getUserCurrent());
$user = $model->signup($userCurrent);
if($user) {
$this->redirect(['site/signup-confirm']);
}
@@ -409,11 +426,21 @@ class SiteController extends FrontendController

return $this->render('signup_producer', [
'model' => $model,
'sponsorshipProducerFrom' => $sponsorshipProducerFrom,
'dataProviderPrices' => $this->getDataProviderPrices(),
'paidFeaturesArray' => $this->getFeatureModule()->getRepository()->findPaidFeatures()
]);
}

public function findProducerSponsorshipByCode($sponsorshipFromCode)
{
$sponsorshipProducerFrom = null;
if($sponsorshipFromCode && strlen($sponsorshipFromCode)) {
$sponsorshipProducerFrom = $this->getProducerModule()->getRepository()->findOneProducerBySponsorshipCode($sponsorshipFromCode);
}
return $sponsorshipProducerFrom;
}

public function actionSignupConfirm($idProducerRedirect = null)
{
$producerModule = $this->getProducerModule();

+ 11
- 0
frontend/forms/SignupForm.php Visa fil

@@ -74,6 +74,7 @@ class SignupForm extends Model
public $is_test;
public $newsletter = false;
public $newsletter_souke = false;
public $sponsored_by = false;

/**
* @inheritdoc
@@ -176,6 +177,7 @@ class SignupForm extends Model
['id_producer', 'required', 'message' => 'Champs obligatoire', 'when' => function ($model) {
return $this->option_user_producer == 'user';
}],
['sponsored_by', 'safe'],
['code', 'required', 'message' => 'Champs obligatoire', 'when' => function ($model) {
$producer = Producer::findOne($this->id_producer);
if ($producer) {
@@ -297,6 +299,15 @@ class SignupForm extends Model
$producerModule->initProducer($producer);
$producer->save();

// Parrainage
if($this->sponsored_by) {
$sponsorshipProducerSponsor = $producerModule->getRepository()->findOneProducerById($this->sponsored_by);
if($sponsorshipProducerSponsor) {
$producer->sponsored_by = $this->sponsored_by;
$producer->save();
}
}

/*
* Envoi d'un email à l'administrateur pour le prévenir
* qu'un nouveau producteur s'est inscrit

+ 13
- 0
frontend/views/site/_signup_sponsorship_message.php Visa fil

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

use yii\helpers\Html;

?>

<?php if($sponsorshipProducerFrom): ?>
<div class="alert alert-dark">
<i class="bi bi-people-fill"></i>
Le producteur <strong><?= Html::encode($sponsorshipProducerFrom->getName()) ?></strong> vous propose de vous parrainer.
En vous inscrivant, profitez de <strong>3 mois offerts</strong> d'utilisation du logiciel !
</div>
<?php endif; ?>

+ 5
- 0
frontend/views/site/signup.php Visa fil

@@ -57,6 +57,11 @@ $this->params['breadcrumbs'][] = $this->title;
les identifiants indiqués sur la page de <?= Html::a('connexion', \Yii::$app->urlManager->createUrl(['site/login'])); ?> pour vous identifier.
</div>
<?php else: ?>

<?= $this->render('_signup_sponsorship_message.php', [
'sponsorshipProducerFrom' => $sponsorshipProducerFrom
]); ?>

<?php $form = ActiveForm::begin(['id' => 'form-signup', 'enableClientValidation'=> false]); ?>
<?= $form->field($model, 'email') ?>
<?= $form->field($model, 'password')->passwordInput() ?>

+ 10
- 5
frontend/views/site/signup_producer.php Visa fil

@@ -52,6 +52,11 @@ $this->params['breadcrumbs'][] = $this->title;

<div class="row">
<div class="col-lg-5">

<?= $this->render('_signup_sponsorship_message.php', [
'sponsorshipProducerFrom' => $sponsorshipProducerFrom
]); ?>

<?php $form = ActiveForm::begin(['id' => 'form-signup','enableClientValidation'=> false]); ?>
<?= $form->field($model, 'name_producer') ?>
<?= $form->field($model, 'type')->textInput(['placeholder' => 'Boulangerie, brasserie, ferme ...']); ?>
@@ -62,7 +67,7 @@ $this->params['breadcrumbs'][] = $this->title;
'prompt' => '--',
])
->label('TVA à appliquer par défaut'); ?>
<?= $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>.') ?>
<?= $form->field($model, 'cgv')->checkbox()->label('J\'accepte les <button type="button" class="btn btn-sm btn-secondary btn-modal-cgv" data-bs-toggle="modal" data-bs-target="#modal-cgv">conditions générales de service</button> et les <button type="button" class="btn btn-sm btn-secondary btn-modal-prices" data-bs-toggle="modal" data-bs-target="#modal-prices">conditions tarifaires</button>.') ?>

<?= $form->field($model, 'verifyCode')->widget(\yii\captcha\Captcha::className(), [
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
@@ -82,14 +87,14 @@ $this->params['breadcrumbs'][] = $this->title;
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">Conditions générales de service</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<?= $this->render('_cgv_content.php'); ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Fermer</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
</div>
</div>
</div>
@@ -100,14 +105,14 @@ $this->params['breadcrumbs'][] = $this->title;
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">Tarifs</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<?= $this->render('../site/_prices_producer', ['dataProviderPrices' => $dataProviderPrices, 'paidFeaturesArray' => $paidFeaturesArray]); ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Fermer</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
</div>
</div>
</div>

+ 13
- 0
producer/controllers/NewsletterController.php Visa fil

@@ -85,6 +85,19 @@ class NewsletterController extends ProducerBaseController
return $this->redirect('index');
}

public function actionReportProblemReceivingEmails()
{
if(!$this->getUserCurrent()) {
return $this->redirectProducerLoginFrontend('index');
}

if(!$this->getUserModule()->getManager()->reportProblemReceivingEmails($this->getUserCurrent())) {
$this->setFlash('error', "Une erreur est survenue.");
}

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

public function redirectProducerLoginFrontend(string $actionNewsletter)
{
return $this->redirect($this->getUrlManagerFrontend()->createAbsoluteUrl(['site/producer', 'id' => $this->getProducerCurrent()->id, 'return_url' => \Yii::$app->urlManagerProducer->createAbsoluteUrl(['newsletter/'.$actionNewsletter, 'slug_producer' => $this->getProducerCurrent()->slug])]));

+ 1
- 1
producer/controllers/OrderController.php Visa fil

@@ -719,7 +719,7 @@ class OrderController extends ProducerBaseController
$distributionsArrayFilterPointSale = [];
for ($i = 0; $i < count($distributionsArray); $i++) {
$distribution = $distributionsArray[$i];
if ($distributionModule->isPointSaleActive($distribution, $pointSaleCurrent)) {
if ($distribution && $distributionModule->isPointSaleActive($distribution, $pointSaleCurrent)) {
$countOrders = Order::searchCount([
'id_distribution' => $distribution->id,
'id_point_sale' => $pointSaleCurrent->id

+ 10
- 0
producer/controllers/SiteController.php Visa fil

@@ -314,6 +314,16 @@ class SiteController extends ProducerBaseController
'producer' => $producer
]);
}

public function actionUserMessageRead(int $idUserMessage)
{
$userMessageModule = $this->getUserMessageModule();
$userMessage = $userMessageModule->getRepository()->findOneUserMessageById($idUserMessage);
if($userMessage) {
$userMessageModule->getManager()->readUserMessage($userMessage);
}
return $this->redirectReferer();
}
}

?>

+ 24
- 0
producer/views/layouts/main.php Visa fil

@@ -60,6 +60,7 @@ $producerModule = ProducerModule::getInstance();
$featureModule = FeatureModule::getInstance();
$productModule = ProductModule::getInstance();
$pointSaleModule = PointSaleModule::getInstance();
$userMessageModule = $this->getUserMessageModule();
$producerUser = null;
if ($userModule->getAuthorizationChecker()->isGrantedAsProducer($userCurrent)) {
$producerUser = $producerModule->findOneProducerById($userCurrent->id_producer);
@@ -326,6 +327,29 @@ $mainColor = $producer->option_main_color ?: '#ee6f42' ;

<section id="content">

<?php
// Message utilisateur
$userMessagesArray = $userMessageModule->getRepository()->findUserMessagesUnreadByUser($userCurrent);
if($userMessagesArray && count($userMessagesArray)):
foreach($userMessagesArray as $userMessage): ?>
<div class="alert alert-info">
<h4 class="alert-heading">
<i class="bi bi-envelope"></i>
Nouveau message
</h4>
<p><?= nl2br(Html::encode($userMessage->getMessage())) ?></p>
<p>
<a class="alert-link" href="<?= Yii::$app->urlManager->createUrl(['site/'.($userModule->getAuthorizationChecker()->isGrantedAsAdministrator($userMessage->getCreatedBy()) ? 'support' : 'contact')]); ?>">
Répondre</a>
&bull;
<a class="alert-link" href="<?= Yii::$app->urlManager->createUrl(['site/user-message-read', 'idUserMessage' => $userMessage->getId()]); ?>">
Fermer
</a>
</p>
</div>
<?php endforeach;
endif; ?>

<?php
// Message congés
$leavePeriodMessageDisplay = $producerModule->getSolver()->getConfig('option_leave_period_message_display', $producer);

+ 33
- 18
producer/views/newsletter/index.php Visa fil

@@ -66,24 +66,39 @@ else {
?>
<div class="newsletter-index">

<div class="alert alert-info">
<i class="bi bi-info-circle"></i>
<?php if($producer->option_newsletter_description): ?>
<?= nl2br(Html::encode($producer->option_newsletter_description)); ?>
<?php else: ?>
L'infolettre vous permet de recevoir les emails de prise de commande et les actualités de ce producteur.
<?php endif; ?>
</div>

<?php if($userModule->isUserSubscribedNewsletter($user)): ?>
<div class="alert alert-success">
<i class="bi bi-megaphone"></i>
Vous êtes inscrit à l'infolettre <strong><?= Html::encode($producer->name) ?></strong>.
<div class="row">
<div class="col-md-8">
<div class="alert alert-info">
<i class="bi bi-info-circle"></i>
<?php if($producer->option_newsletter_description): ?>
<?= nl2br(Html::encode($producer->option_newsletter_description)); ?>
<?php else: ?>
L'infolettre vous permet de recevoir les emails de prise de commande et les actualités de ce producteur.
<?php endif; ?>
</div>
<?php if($userModule->isUserSubscribedNewsletter($user)): ?>
<div class="alert alert-success">
<i class="bi bi-megaphone"></i>
Vous êtes inscrit à l'infolettre <strong><?= Html::encode($producer->name) ?></strong>.
</div>
<?php else: ?>
<div class="alert alert-danger">
<i class="bi bi-x-circle"></i>
Vous n'êtes pas inscrit à l'infolettre <strong><?= Html::encode($producer->name) ?></strong>.
</div>
<?php endif; ?>
</div>
<?php else: ?>
<div class="alert alert-danger">
<i class="bi bi-x-circle"></i>
Vous n'êtes pas inscrit à l'infolettre <strong><?= Html::encode($producer->name) ?></strong>.
<div class="col-md-4">
<div class="alert alert-dark">
<i class="bi bi-life-preserver"></i>
<?php if(!$user->getProblemReceivingEmails()): ?>
Vous rencontrez des problèmes pour recevoir les emails de ce producteur ?
<a href="<?= Yii::$app->urlManager->createUrl('newsletter/report-problem-receiving-emails') ?>">Cliquez ici</a> pour nous prévenir.
<?php else: ?>
Nous avons bien été prévenu de vos difficultés à recevoir les emails de ce producteur,
nous reviendrons vers vous dès que possible.
<?php endif; ?>
</div>
</div>
<?php endif; ?>
</div>
</div>

+ 0
- 1
producer/views/subscription/_form.php Visa fil

@@ -233,7 +233,6 @@ $orderModule = OrderModule::getInstance();
<td class="price-unit">
{{ formatPrice(product.price_with_tax) }}<br/><span
class="unit">{{ product.wording_unit }}</span>

</td>
<td class="quantity">
<div class="input-group">

+ 74
- 55
producer/web/css/screen.css Visa fil

@@ -1366,117 +1366,117 @@ termes.
}
/* line 152, ../sass/order/_order.scss */
.order-order #main #app-order-order #legend #leave-period-date-color {
background-color: #E09F3E;
border: solid 2px #E09F3E;
background-color: gray;
border: solid 2px gray;
}
/* line 158, ../sass/order/_order.scss */
/* line 160, ../sass/order/_order.scss */
.order-order #main #app-order-order #calendar {
margin-bottom: 15px;
}
/* line 160, ../sass/order/_order.scss */
/* line 162, ../sass/order/_order.scss */
.order-order #main #app-order-order #calendar .c-header .c-title-layout .c-title-popover .c-title-anchor .c-title[data-v-2083cb72] {
font-size: 2rem;
}
/* line 163, ../sass/order/_order.scss */
/* line 165, ../sass/order/_order.scss */
.order-order #main #app-order-order #calendar .c-day-background {
padding: 20px;
}
/* line 168, ../sass/order/_order.scss */
/* line 170, ../sass/order/_order.scss */
.order-order #main #app-order-order #calendar .c-day:hover .c-day-background {
background-color: #ee6f42 !important;
color: white !important;
}
/* line 174, ../sass/order/_order.scss */
/* line 176, ../sass/order/_order.scss */
.order-order #main #app-order-order #calendar .c-day-popover-content {
font-size: 1.3rem;
}
/* line 182, ../sass/order/_order.scss */
/* line 184, ../sass/order/_order.scss */
.order-order #main #app-order-order #credit-online-payment .panel .panel-heading .btn-default {
float: right;
position: relative;
top: -5px;
}
/* line 193, ../sass/order/_order.scss */
/* line 195, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-date #distributions-list .card {
margin-bottom: 20px;
}
/* line 196, ../sass/order/_order.scss */
/* line 198, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-date #distributions-list .card .btn-primary {
float: right;
}
/* line 200, ../sass/order/_order.scss */
/* line 202, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-date #distributions-list .card .date {
font-size: 1.2rem;
line-height: 1.4rem;
text-transform: uppercase;
font-family: 'worksans_semibold';
}
/* line 207, ../sass/order/_order.scss */
/* line 209, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-date #distributions-list .card .point-sales {
color: gray;
font-size: 14px;
margin-top: 8px;
}
/* line 216, ../sass/order/_order.scss */
/* line 218, ../sass/order/_order.scss */
.order-order #main #app-order-order .block-actions {
text-align: center;
margin-top: 40px;
}
/* line 223, ../sass/order/_order.scss */
/* line 225, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.name .the-name {
color: black;
font-size: 1.2em;
line-height: 1.4em;
font-family: 'worksans_semibold';
}
/* line 230, ../sass/order/_order.scss */
/* line 232, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.name .locality {
display: none;
}
/* line 234, ../sass/order/_order.scss */
/* line 236, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.name .comment,
.order-order #main #app-order-order table#points-sale td.name .minimum-order-amount,
.order-order #main #app-order-order table#points-sale td.name .shared-point-sale-producers {
color: gray;
}
/* line 239, ../sass/order/_order.scss */
/* line 241, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.name .comment a,
.order-order #main #app-order-order table#points-sale td.name .minimum-order-amount a,
.order-order #main #app-order-order table#points-sale td.name .shared-point-sale-producers a {
color: #ee6f42;
}
/* line 245, ../sass/order/_order.scss */
/* line 247, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.actions {
width: 150px;
}
/* line 247, ../sass/order/_order.scss */
/* line 249, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.actions button {
width: 100%;
}
/* line 259, ../sass/order/_order.scss */
/* line 261, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products {
margin-bottom: 40px;
border-top: solid 1px #b7ab9b;
border-left: solid 1px #b7ab9b;
border-right: solid 1px #b7ab9b;
}
/* line 265, ../sass/order/_order.scss */
/* line 267, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products thead {
display: none;
}
/* line 269, ../sass/order/_order.scss */
/* line 271, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td {
border-bottom: solid 1px #b7ab9b;
border-left: 0px none;
border-right: 0px none;
}
/* line 277, ../sass/order/_order.scss */
/* line 279, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.category-closed:hover td.category-name,
.order-order #main #app-order-order table#products tr.category-open td.category-name {
padding-left: 30px;
background-color: #f4efe8;
}
/* line 284, ../sass/order/_order.scss */
/* line 286, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name {
transition: all 0.1s linear;
background-color: #f4efe8;
@@ -1488,12 +1488,12 @@ termes.
padding-top: 13px;
padding-left: 20px;
}
/* line 295, ../sass/order/_order.scss */
/* line 297, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name .bi-caret-down-fill,
.order-order #main #app-order-order table#products td.category-name .bi-caret-right-fill {
font-size: 15px;
}
/* line 300, ../sass/order/_order.scss */
/* line 302, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name span.badge {
font-family: "worksans_bold";
text-transform: uppercase;
@@ -1502,21 +1502,21 @@ termes.
position: relative;
top: -3px;
}
/* line 308, ../sass/order/_order.scss */
/* line 310, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name span.badge.bg-primary {
float: right;
top: 2px;
}
/* line 314, ../sass/order/_order.scss */
/* line 316, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name:hover {
cursor: pointer;
background-color: white;
}
/* line 321, ../sass/order/_order.scss */
/* line 323, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.photo img {
width: 75px;
}
/* line 331, ../sass/order/_order.scss */
/* line 333, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices {
margin-top: 10px;
font-size: 10px;
@@ -1524,74 +1524,74 @@ termes.
padding-bottom: 2px;
margin-bottom: 0px;
}
/* line 339, ../sass/order/_order.scss */
/* line 341, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li {
margin-bottom: 5px;
}
/* line 341, ../sass/order/_order.scss */
/* line 343, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li strong {
font-weight: bold;
}
/* line 349, ../sass/order/_order.scss */
/* line 351, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit, .order-order #main #app-order-order table#products .price-total {
width: 135px;
text-align: center;
}
/* line 353, ../sass/order/_order.scss */
/* line 355, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .price-infos, .order-order #main #app-order-order table#products .price-total .price-infos {
color: gray;
font-size: 13px;
line-height: 15px;
}
/* line 360, ../sass/order/_order.scss */
/* line 362, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.product-open td.price-total {
font-size: 1.1rem;
font-family: 'worksans_bold';
padding-top: 19px;
}
/* line 366, ../sass/order/_order.scss */
/* line 368, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity {
width: 175px;
}
/* line 369, ../sass/order/_order.scss */
/* line 371, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity input.quantity,
.order-order #main #app-order-order table#products .td-quantity .input-group-text {
background-color: white;
}
/* line 374, ../sass/order/_order.scss */
/* line 376, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity input.quantity {
text-align: center;
border: 0px none;
}
/* line 378, ../sass/order/_order.scss */
/* line 380, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity .input-group-text {
border: 0px none;
padding-right: 10px;
padding-left: 0px;
margin: 0px;
}
/* line 386, ../sass/order/_order.scss */
/* line 388, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity .input-group-btn button {
padding: 4px 5px 0px 5px;
}
/* line 388, ../sass/order/_order.scss */
/* line 390, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity .input-group-btn button .bi {
font-size: 1.5em;
font-weight: bold;
margin: 0px;
}
/* line 399, ../sass/order/_order.scss */
/* line 401, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary {
padding: 25px;
}
/* line 402, ../sass/order/_order.scss */
/* line 404, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary h3 {
font-family: 'worksans_bold';
margin-top: 0px;
text-transform: uppercase;
margin-bottom: 5px;
}
/* line 409, ../sass/order/_order.scss */
/* line 411, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul {
margin-bottom: 15px;
padding-left: 20px;
@@ -1599,17 +1599,17 @@ termes.
line-height: 1.4rem;
list-style-type: disc;
}
/* line 417, ../sass/order/_order.scss */
/* line 419, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul li .quantity {
font-weight: bold;
}
/* line 424, ../sass/order/_order.scss */
/* line 426, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .price-total {
padding-top: 25px;
font-size: 1.5rem;
font-family: 'worksans_bold';
}
/* line 429, ../sass/order/_order.scss */
/* line 431, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .price-total span {
display: inline-block;
padding: 7px 15px;
@@ -1619,30 +1619,30 @@ termes.
color: white;
font-size: 1.2rem;
}
/* line 441, ../sass/order/_order.scss */
/* line 443, ../sass/order/_order.scss */
.order-order #main #app-order-order #payment-methods .infos {
margin-top: 10px;
color: gray;
}
/* line 448, ../sass/order/_order.scss */
/* line 450, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .delivery {
margin-bottom: 20px;
}
/* line 452, ../sass/order/_order.scss */
/* line 454, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .comment {
margin-bottom: 20px;
}
/* line 456, ../sass/order/_order.scss */
/* line 458, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment #payment-methods {
margin-bottom: 20px;
}
/* line 461, ../sass/order/_order.scss */
/* line 463, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .credit .info {
margin-left: 20px;
color: gray;
}

/* line 474, ../sass/order/_order.scss */
/* line 476, ../sass/order/_order.scss */
#main #content .panel h3 {
font-family: "worksans_bold";
margin: 0px;
@@ -2216,13 +2216,32 @@ termes.
text-align: center;
}

/* line 291, ../sass/_responsive.scss */
/* line 292, ../sass/_responsive.scss */
.subscription-form #main #content .block.products .table td {
padding: 5px;
}
/* line 295, ../sass/_responsive.scss */
.subscription-form #main #content .block.products .table .recipe {
display: none;
}
/* line 298, ../sass/_responsive.scss */
.subscription-form #main #content .block.products .table .input-group-btn {
display: block;
width: 1000%;
}
/* line 301, ../sass/_responsive.scss */
.subscription-form #main #content .block.products .table .input-group-btn .btn {
display: block;
width: 100%;
}

/* line 312, ../sass/_responsive.scss */
#footer .content {
text-align: center;
}
}
@media screen and (max-width: 991px) {
/* line 303, ../sass/_responsive.scss */
/* line 324, ../sass/_responsive.scss */
#main {
padding-top: 0px;
}

+ 2
- 1
producer/web/js/vuejs/order-order.js Visa fil

@@ -179,7 +179,8 @@ var app = new Vue({
app.calendar.attrs.push({
highlight: {
style: {
background: '#E09F3E'
//background: '#E09F3E'
background: 'gray'
},
contentStyle: {
color: 'white'

+ 22
- 1
producer/web/sass/_responsive.scss Visa fil

@@ -284,7 +284,28 @@ termes.
}
}
}
}

.subscription-form {
#main #content .block.products {
.table {
td {
padding: 5px;
}
.recipe {
display: none;
}
.input-group-btn {
display: block;
width: 1000%;
.btn {
display: block;
width: 100%;
}
}
}

}
}
#footer {

+ 4
- 2
producer/web/sass/order/_order.scss Visa fil

@@ -150,8 +150,10 @@
border: solid 2px #198754;
}
#leave-period-date-color {
background-color: #E09F3E;
border: solid 2px #E09F3E;
//background-color: #E09F3E;
//border: solid 2px #E09F3E;
background-color: gray;
border: solid 2px gray;
}
}

Laddar…
Avbryt
Spara