浏览代码

Merge branch 'develop'

master
Guillaume Bourgeois 6 个月前
父节点
当前提交
8b3b23313f
共有 31 个文件被更改,包括 856 次插入125 次删除
  1. +1
    -1
      backend/controllers/AccessController.php
  2. +5
    -3
      backend/controllers/CommunicateController.php
  3. +99
    -0
      backend/controllers/UserAdminController.php
  4. +11
    -2
      backend/controllers/UserController.php
  5. +169
    -2
      backend/models/MailForm.php
  6. +6
    -0
      backend/views/layouts/header.php
  7. +19
    -8
      backend/views/layouts/left.php
  8. +3
    -1
      backend/views/producer-invoice/index.php
  9. +2
    -2
      backend/views/support/index.php
  10. +158
    -0
      backend/views/user-admin/index.php
  11. +17
    -1
      backend/views/user/_form.php
  12. +94
    -77
      backend/web/css/screen.css
  13. +8
    -1
      backend/web/js/backend.js
  14. +17
    -0
      backend/web/sass/_adminlte.scss
  15. +7
    -2
      common/config/main.php
  16. +1
    -1
      common/config/params.php
  17. +49
    -0
      common/mail/newTicketMessageAdmin-html.php
  18. +50
    -0
      common/mail/newTicketMessageAdmin-text.php
  19. +28
    -0
      common/versions/24.5.B.php
  20. +3
    -2
      common/versions/_macros.php
  21. +3
    -4
      domain/Ticket/Ticket/Event/TicketObserver.php
  22. +6
    -0
      domain/Ticket/Ticket/TicketModule.php
  23. +47
    -0
      domain/Ticket/Ticket/TicketNotifier.php
  24. +5
    -1
      domain/Ticket/Ticket/TicketSolver.php
  25. +15
    -0
      domain/Ticket/TicketMessage/Event/TicketMessageObserver.php
  26. +1
    -1
      domain/Ticket/TicketMessage/TicketMessageBuilder.php
  27. +13
    -1
      domain/Ticket/TicketMessage/TicketMessageRepository.php
  28. +6
    -0
      domain/Ticket/TicketMessage/TicketMessageRepositoryQuery.php
  29. +0
    -11
      domain/User/User/UserNotifier.php
  30. +6
    -4
      domain/User/User/UserSearch.php
  31. +7
    -0
      domain/User/UserProducer/UserProducerRepository.php

+ 1
- 1
backend/controllers/AccessController.php 查看文件

@@ -77,7 +77,7 @@ class AccessController extends BackendController
$userModule = $this->getUserModule();
$producer = $this->getProducerCurrent();
$userSearch = new UserSearch();
$usersArray = $userSearch->search()->query->all();
$usersArray = $userSearch->search([], $producer)->query->all();

$modelAccessUserProducerForm = new AccessUserProducerForm;
if ($modelAccessUserProducerForm->load(\Yii::$app->request->post()) && $modelAccessUserProducerForm->validate()) {

+ 5
- 3
backend/controllers/CommunicateController.php 查看文件

@@ -148,8 +148,10 @@ class CommunicateController extends BackendController


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

/*if ($responseSendMail->success()) {
$this->setFlash('success', 'Votre email a bien été envoyé.');
} else {
$bodyResponseSendMail = $responseSendMail->getBody();
@@ -168,7 +170,7 @@ class CommunicateController extends BackendController
$messageError .= '<br />Problème détecté : ' . implode(',', $emailsErrorArray);
}
$this->setFlash('error', $messageError);
}
}*/

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

+ 99
- 0
backend/controllers/UserAdminController.php 查看文件

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

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

namespace backend\controllers;

use domain\User\User\UserSearch;
use Yii;
use yii\filters\AccessControl;

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

/**
* Liste les utilisateurs.
*/
public function actionIndex()
{
$searchModel = new UserSearch();
$dataProvider = $searchModel->search([
'UserSearch' => isset(\Yii::$app->request->queryParams['UserSearch']) ?
Yii::$app->request->queryParams['UserSearch'] : []
]);

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

public function actionRedirectView(int $idUserProducer)
{
$userCurrent = $this->getUserCurrent();
$userProducer = $this->getUserProducerModule()->getRepository()->findOneUserProducerById($idUserProducer);
if($userProducer) {
$user = $userProducer->user;
$producer = $userProducer->producer;
$this->getUserModule()->getBuilder()->switchProducer($userCurrent, $producer);
return $this->redirect(['user/view', 'id' => $user->id]);
}
else {
$this->addFlash('error', "L'utilisateur n'a pas été trouvé.");
return $this->redirectReferer();
}
}
}

+ 11
- 2
backend/controllers/UserController.php 查看文件

@@ -88,7 +88,7 @@ class UserController extends BackendController
bool $sectionInactiveUsers = false)
{
$pointSaleModule = $this->getPointSaleModule();
$producer = $this->getProducerCurrent();
$searchModel = new UserSearch();
$dataProvider = $searchModel->search([
'UserSearch' => array_merge(
@@ -101,7 +101,7 @@ class UserController extends BackendController
Yii::$app->request->queryParams['UserSearch'] :
[]
)
]);
], $producer);

$producer = $this->getProducerCurrent();
$pointsSaleArray = $pointSaleModule->findPointSales();
@@ -235,6 +235,15 @@ class UserController extends BackendController
$userBelongToProducer->trust_alert_comment = $model->trust_alert_comment;
$userBelongToProducer->save();

// Mot de passe
if($this->getUserModule()->getAuthorizationChecker()->isGrantedAsAdministrator($this->getUserCurrent())
&& $model->password_new
&& strlen($model->password_new)) {

$this->getUserModule()->getBuilder()->initPassword($model, $model->password_new);
$model->save();
}

$this->setFlash('success', 'Utilisateur <strong>' . Html::encode($userModule->getUsername($model)) . '</strong> modifié.');
return $this->redirect(['view', 'id' => $model->id]);
}

+ 169
- 2
backend/models/MailForm.php 查看文件

@@ -47,6 +47,9 @@ use domain\Distribution\Distribution\DistributionModule;
use domain\Producer\Producer\ProducerModule;
use domain\Product\Product\Product;
use domain\Product\Product\ProductModule;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Yii;
use yii\base\Model;
use yii\helpers\Html;
@@ -92,11 +95,11 @@ class MailForm extends Model
* @param array $usersArray
* @param boolean $fromProducer
*/
public function sendEmail($usersArray, $fromProducer = true)
public function sendEmailMailjet($usersArray, $fromProducer = true)
{
$productModule = ProductModule::getInstance();
$producerModule = ProducerModule::getInstance();
$distributionModule =DistributionModule::getInstance();
$distributionModule = DistributionModule::getInstance();

$mj = new \Mailjet\Client(
Mailjet::getApiKey('public'),
@@ -248,4 +251,168 @@ Me désinscrire : ".$linkUnsubscribe;
return $response ;
}

public function sendEmail($usersArray, $fromProducer = true)
{
$productModule = ProductModule::getInstance();
$producerModule = ProducerModule::getInstance();
$distributionModule = DistributionModule::getInstance();

$messageAutoText = '' ;
$messageAutoHtml = '' ;

$messageAutoHtml .= ' <style type="text/css">
h1, h2, h3, h4, h5, h6 {
padding: 0px;
margin: 0px;
margin-bottom: 10px;
}
p {
margin: 0px;
padding: 0px;
margin-bottom: 5px;
}
</style>';

if($this->id_distribution) {

$messageAutoText = '

' ;
$messageAutoHtml .= '<br /><br />' ;

$distribution = Distribution::searchOne(['id' => $this->id_distribution]) ;

if($distribution) {

$linkOrder = $distributionModule->getLinkOrder($distribution);
$dateOrder = strftime('%A %d %B %Y', strtotime($distribution->date)) ;
$messageAutoHtml .= '<a href="'.$linkOrder.'">Passer ma commande du '.$dateOrder.'</a>' ;
$messageAutoText .= 'Suivez ce lien pour passer votre commande du '.$dateOrder.' :
'.$linkOrder ;

if($this->integrate_product_list) {
$productsArray = Product::find()
->where([
'id_producer' => GlobalParam::getCurrentProducerId(),
])
->andWhere('status >= :status')
->addParams(['status' => Product::STATUS_OFFLINE])
->innerJoinWith(['productDistribution' => function($query) use($distribution) {
$query->andOnCondition([
'product_distribution.id_distribution' => $distribution->id,
'product_distribution.active' => 1
]);
}])
->orderBy('product.name ASC')
->all();

if(count($productsArray) > 1) {
$messageAutoHtml .= '<br /><br />Produits disponibles : <br /><ul>' ;
$messageAutoText .= '

Produits disponibles :
' ;
foreach($productsArray as $product) {

$productDescription = $product->name ;
if(strlen($product->description)) {
$productDescription .= ' / '.$product->description ;
}
if($product->price) {
$productDescription .= ' / '.Price::format($productModule->getPriceWithTax($product)) ;
$productDescription .= ' ('. $productModule->getSolver()->strUnit($product, UnitDefinition::WORDING_UNIT).')' ;
}

$messageAutoText .= '- '.$productDescription.'
' ;
$messageAutoHtml .= '<li>'.Html::encode($productDescription).'</li>' ;
}
$messageAutoHtml .= '</ul>' ;
}
}
}
}

if($fromProducer) {
$producer = GlobalParam::getCurrentProducer() ;
$fromEmail = $producerModule->getProducerEmailPlatform($producer) ;
$fromName = $producer->name ;

$linkProducer = 'https://'.$producer->slug.'.souke.fr';
$linkUnsubscribe = Yii::$app->urlManagerProducer->createAbsoluteUrl(['newsletter/unsubscribe', 'slug_producer' => $producer->slug]);

// Message inscription newsletter
$messageAutoText .= "

--
Boutique : ".$linkProducer."
Me désinscrire : ".$linkUnsubscribe;

$messageAutoHtml .= "<br /><br />--<br>";
$messageAutoHtml .= "Boutique : <a href=\"".$linkProducer."\">".$linkProducer."</a><br>";
$messageAutoHtml .= "Me désinscrire : <a href=\"".$linkUnsubscribe."\">".$linkUnsubscribe."</a>";
}
else {
$fromEmail = 'contact@souke.fr' ;
$fromName = 'Souke' ;
}

$htmlContent = nl2br($this->message).$messageAutoHtml;

// Tests
/*$usersArray = [
['email' => 'contact@guillaumebourgeois.fr', 'name' => '', 'lastname' => '']
];*/

// Envoi via Brevo
$this->sendEmailsViaBrevoApi($usersArray, $fromName, $fromEmail, $htmlContent);

// Envoi via Mailjet
//$this->sendEmailsViaMailjetApi($usersArray, $fromName, $fromEmail, $htmlContent);
}

public function sendEmailsViaBrevoApi(array $usersArray, string $fromName, string $fromEmail, string $htmlContent)
{
$client = new Client();
$data = [
'sender' => [
'name' => $fromName,
'email' => $fromEmail
],
'to' => [],
'subject' => $this->subject,
'htmlContent' => $htmlContent
] ;

foreach($usersArray as $user) {

$data['to'][] = [
'name' => $user['name'].' '.$user['lastname'],
'email' => $user['email']
];

if(count($data['to']) == 50) {
$this->requestPostEmailViaBrevoApi($client, $data);
$data['to'] = [] ;
}
}

if(count($data['to']) > 0) {
$this->requestPostEmailViaBrevoApi($client, $data);
}
}

public function requestPostEmailViaBrevoApi(Client $client, array $data): ResponseInterface
{
return $client->request('POST', 'https://api.brevo.com/v3/smtp/email', [
'headers' => [
'accept' => 'application/json',
'content-type' => 'application/json',
'api-key' => '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',
],
'body' => json_encode($data)
]);
}
}

+ 6
- 0
backend/views/layouts/header.php 查看文件

@@ -82,6 +82,9 @@ $userCurrent = GlobalParam::getCurrentUser();
<?php endif; ?>
<div class="title">
<?= Html::encode($producer->name) ?>
<?php if ($userModule->getAuthorizationChecker()->isGrantedAsAdministrator($userCurrent)): ?>
<span class="producer-id">#<?= $producer->id ?></span>
<?php endif; ?>
<?php if (!$producer->active): ?>
<span class="label label-danger">Hors-ligne</span>
<?php endif; ?>
@@ -120,6 +123,7 @@ $userCurrent = GlobalParam::getCurrentUser();
<a href="<?= Yii::$app->urlManagerBackend->createUrl(['site/switch-producer', 'id' => $producer->id]); ?>">
<label class="label label-info">Nouveau</label>
<?= Html::encode($producer->name) ?>
<span class="producer-id">#<?= $producer->id ?></span>
</a>
</li>
<?php endif; ?>
@@ -130,6 +134,7 @@ $userCurrent = GlobalParam::getCurrentUser();
<a href="<?= Yii::$app->urlManagerBackend->createUrl(['site/switch-producer', 'id' => $producer->id]); ?>">
<?php if($producer->is_new): ?> <label class="label label-info">Nouveau</label> <?php endif; ?>
<?= Html::encode($producer->name) ?>
<span class="producer-id">#<?= $producer->id ?></span>
</a>
</li>
<?php endif; ?>
@@ -140,6 +145,7 @@ $userCurrent = GlobalParam::getCurrentUser();
<a href="<?= Yii::$app->urlManagerBackend->createUrl(['site/switch-producer', 'id' => $producer->id]); ?>">
<label class="label label-danger">Hors-ligne</label>
<?= Html::encode($producer->name) ?>
<span class="producer-id">#<?= $producer->id ?></span>
</a>
</li>
<?php endif; ?>

+ 19
- 8
backend/views/layouts/left.php 查看文件

@@ -63,10 +63,10 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
$versionOpendistribLabel = '';
if ($producer) {
$backgroundLabelVersionOpendistrib = 'black';
if(!$producerModule->isUpToDateWithOpendistribVersion($producer)) {
if (!$producerModule->isUpToDateWithOpendistribVersion($producer)) {
$backgroundLabelVersionOpendistrib = 'green';
}
$versionOpendistribLabel = '<span class="pull-right-container"><small class="label pull-right bg-'.$backgroundLabelVersionOpendistrib.'">' . GlobalParam::getSoukeVersion() . '</small></span>';
$versionOpendistribLabel = '<span class="pull-right-container"><small class="label pull-right bg-' . $backgroundLabelVersionOpendistrib . '">' . GlobalParam::getSoukeVersion() . '</small></span>';
}

$countTicketsProducerUnreadLabel = '';
@@ -81,11 +81,12 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
}

$countTicketsLabel = '';
$countTicketsAdminOpen = $ticketModule->getRepository()->countTicketsAdminStatusOpen();
$countTicketsAdminUnread = $ticketModule->getRepository()->countTicketsAdminUnreadByUser($this->getUserCurrent());

if ($countTicketsAdminUnread && $isUserCurrentGrantedAsAdministrator) {
$countTicketsLabel = '<span class="pull-right-container"><small class="label pull-right bg-green">' . $countTicketsAdminUnread . '</small></span>';
$countTicketsLabel = '<span class="pull-right-container"><small class="label pull-right bg-green">' . $countTicketsAdminOpen . '</small></span>';
} else {
$countTicketsAdminOpen = $ticketModule->getRepository()->countTicketsAdminStatusOpen();
if($countTicketsAdminOpen) {
$countTicketsLabel = '<span class="pull-right-container"><small class="label pull-right bg-blue">' . $countTicketsAdminOpen . '</small></span>';
}
@@ -95,7 +96,6 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
$sumUserProducerCreditsLabel = '';
//$sumUserProducerCreditsLabel = '<span class="pull-right-container"><small class="label pull-right '.($sumUserProducerCredits >= 0 ? 'bg-green' : 'bg-red') .'">'.number_format($sumUserProducerCredits, 2).' €</small></span>';


$countUsersWithStatusProducerOnline = $userModule->getRepository()->countUsersStatusProducerOnline();
$countUsersWithStatusUserOnline = $userModule->getRepository()->countUsersStatusUserOnline();
$countUsersProducersOnlineLabel = '';
@@ -106,9 +106,9 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
$countProducerInvoicesUnpaidLabel = '';
$countProducerInvoicesUnpaid = $this->getProducerModule()->getDolibarrUtils()
->countDolibarrProducerInvoicesUnpaid($producer);
if($countProducerInvoicesUnpaid > 1) {
if ($countProducerInvoicesUnpaid > 1) {
$countProducerInvoicesUnpaidLabelColor = ($countProducerInvoicesUnpaid > 2) ? 'red' : 'orange';
$countProducerInvoicesUnpaidLabel = '<span class="pull-right-container"><small class="label pull-right bg-'.$countProducerInvoicesUnpaidLabelColor.'">' . $countProducerInvoicesUnpaid . '</small></span>';
$countProducerInvoicesUnpaidLabel = '<span class="pull-right-container"><small class="label pull-right bg-' . $countProducerInvoicesUnpaidLabelColor . '">' . $countProducerInvoicesUnpaid . '</small></span>';
}

?>
@@ -133,7 +133,18 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
'visible' => $isUserCurrentGrantedAsAdministrator,
'template' => '<a href="{url}">{icon} {label}' . $countTicketsLabel . '</a>'
],
['label' => 'Producteurs', 'icon' => 'th-list', 'url' => ['/producer-admin/index'], 'visible' => $isUserCurrentGrantedAsAdministrator],
[
'label' => 'Producteurs',
'icon' => 'th-list',
'url' => ['/producer-admin/index'],
'visible' => $isUserCurrentGrantedAsAdministrator
],
[
'label' => 'Utilisateurs',
'icon' => 'users',
'url' => ['/user-admin/index'],
'visible' => $isUserCurrentGrantedAsAdministrator
],
[
'label' => 'Statistiques',
'icon' => 'line-chart',

+ 3
- 1
backend/views/producer-invoice/index.php 查看文件

@@ -46,7 +46,9 @@ $this->addBreadcrumb($this->getTitle()) ;

<?php if($invoicesArray && count($invoicesArray)): ?>
<div class="callout callout-info">
<span class="glyphicon glyphicon-info-sign"></span> Les factures et les réglements sont saisis en début de mois.
<span class="glyphicon glyphicon-pencil"></span> Les factures et les réglements sont saisis en début de mois.<br />
<span class="glyphicon glyphicon-euro"></span> Si votre chiffre d'affaire est stable et que vous souhaitez mettre en place un virement permanent,
<a href="<?= Yii::$app->urlManager->createUrl(['support/index']) ?>">prévenez-moi</a> et vous aurez tous les mois une facture avec un montant identique. Une régule sera réalisée en fin d'année.
</div>

<table class="table table-striped table-bordered">

+ 2
- 2
backend/views/support/index.php 查看文件

@@ -167,8 +167,8 @@ function ticketList($context, $searchTicket, $dataProviderTicket, $userCurrent)
'format' => 'raw',
'value' => function ($ticket) use ($ticketModule, $userCurrent) {

if ($ticketModule->isTicketUnread($ticket, $userCurrent)) {
$firstTicketMessageUnread = $ticketModule->getFirstTicketMessageUnread($ticket, $userCurrent);
$firstTicketMessageUnread = $ticketModule->getFirstTicketMessageUnread($ticket, $userCurrent);
if ($ticketModule->isTicketUnread($ticket, $userCurrent) && $firstTicketMessageUnread) {
$link = '<strong>' . Html::a($ticket->subject, ['view', 'id' => $ticket->id, '#' => $firstTicketMessageUnread->id]) . '</strong>';
} else {
$link = Html::a($ticket->subject, ['view', 'id' => $ticket->id]);

+ 158
- 0
backend/views/user-admin/index.php 查看文件

@@ -0,0 +1,158 @@
<?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('Utilisateurs');
$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;
}
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{switch} ',
'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'],
'buttons' => [
'view' => function ($url, $user) {
return Html::a('<span class="glyphicon glyphicon-eye-open"></span>',
Yii::$app->urlManager->createUrl(['user/view', 'id' => $user->id]),
[
'title' => 'Voir',
'class' => 'btn btn-default'
]);
},
'update' => function ($url, $user) {
return Html::a('<span class="glyphicon glyphicon-pencil"></span>',
Yii::$app->urlManager->createUrl(['user/update', 'id' => $user->id]),
[
'title' => 'Modifier',
'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>',
Yii::$app->urlManager->createUrl(['user/switch-identity', 'id' => $model->id]),
[
'title' => 'Prendre la main',
'class' => 'btn btn-default'
]);
}
}
],
],
],
]); ?>

+ 17
- 1
backend/views/user/_form.php 查看文件

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

use common\helpers\GlobalParam;
use domain\Distribution\Distribution\DistributionModule;
use domain\Distribution\Distribution\ExportManager;
use domain\Producer\Producer\ProducerModule;
@@ -45,6 +46,7 @@ use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\widgets\ActiveForm;

$userCurrent = GlobalParam::getCurrentUser();
$userModule = UserModule::getInstance();
$producerModule = ProducerModule::getInstance();
$distributionModule = DistributionModule::getInstance();
@@ -78,14 +80,28 @@ $distributionModule = DistributionModule::getInstance();
<?php if(!$model->email): ?>
<?= $form->field($model, 'send_mail_welcome')->checkbox() ?>
<?php endif; ?>
<?= $form->field($model, 'address')->textarea() ?>
<?= $form->field($model, 'email_sending_invoicing_documents')
->textInput()
->hint("Utilisé pour l'envoi des documents (devis, bons de livraisons et factures)")
?>
<?= $form->field($model, 'address')->textarea() ?>
</div>
</div>

<?php if($userModule->getAuthorizationChecker()->isGrantedAsAdministrator($userCurrent)): ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-lock"></i>
Mot de passe
</h3>
</div>
<div class="panel-body">
<?= $form->field($model, 'password_new')->passwordInput() ?>
</div>
</div>
<?php endif; ?>

<?php if($pointsSaleArray && count($pointsSaleArray) > 0): ?>
<div class="panel panel-default panel-point-sales">
<div class="panel-heading">

+ 94
- 77
backend/web/css/screen.css 查看文件

@@ -1621,201 +1621,218 @@ body.skin-black .main-header .navbar .producer-panel .title {
top: 2px;
text-transform: uppercase;
}
/* line 85, ../sass/_adminlte.scss */
/* line 83, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .producer-panel .title .producer-id {
color: gray;
font-size: 13px;
}
/* line 90, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .sidebar-toggle {
color: #333;
}
/* line 89, ../sass/_adminlte.scss */
/* line 94, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .link-support {
float: left;
padding: 15px 15px;
border-right: solid 1px #e0e0e0;
color: #333;
}
/* line 95, ../sass/_adminlte.scss */
/* line 100, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .link-support:hover {
text-decoration: none;
color: #F39C12;
}
/* line 101, ../sass/_adminlte.scss */
/* line 106, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .navbar-custom-menu .nav {
display: block;
}
/* line 105, ../sass/_adminlte.scss */
/* line 110, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .navbar-custom-menu .navbar-nav > li > a,
body.skin-black .main-header .navbar .navbar-right > li > a {
border-left: solid 1px #e0e0e0;
color: #333;
}
/* line 111, ../sass/_adminlte.scss */
/* line 116, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav > li > a:hover, body.skin-black .main-header .navbar .nav > li > a:active, body.skin-black .main-header .navbar .nav > li > a:focus,
body.skin-black .main-header .navbar .nav .open > a, body.skin-black .main-header .navbar .nav .open > a:hover, body.skin-black .main-header .navbar .nav .open > a:focus,
body.skin-black .main-header .navbar .nav > .active > a {
color: #F39C12;
}
/* line 117, ../sass/_adminlte.scss */
/* line 122, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .dropdown-menu {
-moz-box-shadow: 0px 0px 4px gray;
-webkit-box-shadow: 0px 0px 4px gray;
box-shadow: 0px 0px 4px gray;
}
/* line 122, ../sass/_adminlte.scss */
/* line 127, ../sass/_adminlte.scss */
body.skin-black .main-header .logo, body.skin-black .main-header .navbar .sidebar-toggle {
border-right: solid 1px #e0e0e0;
}
/* line 126, ../sass/_adminlte.scss */
/* line 131, ../sass/_adminlte.scss */
body.skin-black .main-header .link-control-sidebar {
display: none;
}
/* line 131, ../sass/_adminlte.scss */
/* line 136, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu {
max-height: 300px;
}
/* line 134, ../sass/_adminlte.scss */
/* line 139, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu li a {
padding-top: 4px;
padding-bottom: 4px;
}
/* line 138, ../sass/_adminlte.scss */
/* line 143, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu li a h5 {
margin-bottom: 2px;
}
/* line 141, ../sass/_adminlte.scss */
/* line 146, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu li a h5 small {
float: right;
}
/* line 146, ../sass/_adminlte.scss */
/* line 151, ../sass/_adminlte.scss */
body.skin-black .main-header .notifications-menu ul.menu li a p {
margin-left: 10px;
}
/* line 157, ../sass/_adminlte.scss */
/* line 162, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .dropdown-menu {
width: 400px;
}
/* line 161, ../sass/_adminlte.scss */
/* line 166, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .search-producer {
margin: 10px;
width: 94%;
}
/* line 166, ../sass/_adminlte.scss */
/* line 171, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .li-alert-no-results {
display: none;
}
/* line 169, ../sass/_adminlte.scss */
/* line 174, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .li-alert-no-results .alert {
margin-bottom: 0px;
margin-left: 10px;
margin-right: 10px;
padding: 15px 15px 10px 15px;
}
/* line 177, ../sass/_adminlte.scss */
/* line 182, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .label {
position: relative;
top: -2px;
left: 0px;
}
/* line 183, ../sass/_adminlte.scss */
/* line 188, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu #link-display-producers-offline {
color: #F39C12;
}
/* line 187, ../sass/_adminlte.scss */
/* line 192, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .offline {
display: none;
}
/* line 194, ../sass/_adminlte.scss */
/* line 196, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu a {
color: #333;
}
/* line 200, ../sass/_adminlte.scss */
body.skin-black .main-header .navbar .nav li.producer-menu .producer-id {
position: relative;
top: 4px;
color: gray;
font-size: 12px;
float: right;
}
/* line 211, ../sass/_adminlte.scss */
body.skin-black .sidebar .sidebar-menu > li.header {
color: #899397;
}
/* line 198, ../sass/_adminlte.scss */
/* line 215, ../sass/_adminlte.scss */
body.skin-black .sidebar .label {
padding-top: 5px;
position: relative;
top: -3px;
}
/* line 205, ../sass/_adminlte.scss */
/* line 222, ../sass/_adminlte.scss */
body.skin-black .sidebar-menu > li.active > a {
border-color: #F39C12;
}
/* line 210, ../sass/_adminlte.scss */
/* line 227, ../sass/_adminlte.scss */
body.skin-black section.sidebar .user-panel {
text-align: center;
}
/* line 213, ../sass/_adminlte.scss */
/* line 230, ../sass/_adminlte.scss */
body.skin-black section.sidebar .user-panel .image {
margin-bottom: 3px;
}
/* line 217, ../sass/_adminlte.scss */
/* line 234, ../sass/_adminlte.scss */
body.skin-black section.sidebar .user-panel .title {
font-weight: bold;
color: white;
}
/* line 224, ../sass/_adminlte.scss */
/* line 241, ../sass/_adminlte.scss */
body.skin-black .content-wrapper {
background-color: #f5f5f5;
}
/* line 227, ../sass/_adminlte.scss */
/* line 244, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .content-header {
background-color: #F5F5F5;
padding-bottom: 15px;
border-bottom: solid 1px #e0e0e0;
border-top: solid 1px #e0e0e0;
}
/* line 233, ../sass/_adminlte.scss */
/* line 250, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .content-header .btn {
padding: 3px 6px;
font-size: 10px;
font-family: Arial;
text-transform: uppercase;
}
/* line 240, ../sass/_adminlte.scss */
/* line 257, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .content-header h1 {
font-family: 'myriadpro-light';
font-size: 20px;
}
/* line 246, ../sass/_adminlte.scss */
/* line 263, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .col-no-padding-left {
padding-left: 0px;
}
/* line 250, ../sass/_adminlte.scss */
/* line 267, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .col-no-padding-right {
padding-right: 0px;
}
/* line 254, ../sass/_adminlte.scss */
/* line 271, ../sass/_adminlte.scss */
body.skin-black .content-wrapper a {
color: #e08e0b;
}
/* line 257, ../sass/_adminlte.scss */
/* line 274, ../sass/_adminlte.scss */
body.skin-black .content-wrapper a.disable {
pointer-events: none;
cursor: default;
}
/* line 263, ../sass/_adminlte.scss */
/* line 280, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .label {
padding-top: 4px;
padding-bottom: 1px;
}
/* line 268, ../sass/_adminlte.scss */
/* line 285, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .btn {
color: white;
}
/* line 272, ../sass/_adminlte.scss */
/* line 289, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .btn-default {
color: #333;
background-color: white;
}
/* line 277, ../sass/_adminlte.scss */
/* line 294, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .btn-primary {
background-color: #F39C12;
color: white;
border-color: #F39C12;
}
/* line 284, ../sass/_adminlte.scss */
/* line 301, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .nav.nav-tabs .badge {
margin-left: 4px;
background-color: #e0e0e0;
color: #444;
}
/* line 291, ../sass/_adminlte.scss */
/* line 308, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .tab-content {
border-left: solid 1px #ddd;
border-bottom: solid 1px #ddd;
@@ -1823,20 +1840,20 @@ body.skin-black .content-wrapper .tab-content {
padding: 30px 15px 15px 15px;
background-color: white;
}
/* line 299, ../sass/_adminlte.scss */
/* line 316, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert {
position: relative;
}
/* line 302, ../sass/_adminlte.scss */
/* line 319, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert a {
color: white;
}
/* line 305, ../sass/_adminlte.scss */
/* line 322, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert a.btn {
color: #333;
text-decoration: none;
}
/* line 310, ../sass/_adminlte.scss */
/* line 327, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert .close {
font-size: 30px;
position: absolute;
@@ -1846,83 +1863,83 @@ body.skin-black .content-wrapper .alert .close {
color: white;
opacity: 0.6;
}
/* line 319, ../sass/_adminlte.scss */
/* line 336, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert .close:hover {
opacity: 1;
}
/* line 324, ../sass/_adminlte.scss */
/* line 341, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .alert.alert-dark {
background-color: #ece4d8;
color: black;
}
/* line 331, ../sass/_adminlte.scss */
/* line 348, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .small-box h3 {
font-size: 28px;
font-family: 'Source Sans Pro',sans-serif;
}
/* line 336, ../sass/_adminlte.scss */
/* line 353, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .small-box .icon {
top: -2px;
}
/* line 340, ../sass/_adminlte.scss */
/* line 357, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .small-box .small-box-footer {
color: white;
padding-top: 6px;
padding-bottom: 2px;
}
/* line 349, ../sass/_adminlte.scss */
/* line 366, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .callout h4 .fa {
margin-right: 7px;
}
/* line 352, ../sass/_adminlte.scss */
/* line 369, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .callout a {
color: white;
}
/* line 355, ../sass/_adminlte.scss */
/* line 372, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .callout .btn {
color: #333;
text-decoration: none;
}
/* line 362, ../sass/_adminlte.scss */
/* line 379, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table th {
font-size: 13px;
}
/* line 365, ../sass/_adminlte.scss */
/* line 382, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table th.column-actions, body.skin-black .content-wrapper .table td.column-actions {
width: 172px;
text-align: right;
}
/* line 369, ../sass/_adminlte.scss */
/* line 386, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table td.text-small, body.skin-black .content-wrapper .table th.text-small {
font-size: 12px;
}
/* line 373, ../sass/_adminlte.scss */
/* line 390, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table.table-bordered > thead > tr > th, body.skin-black .content-wrapper .table.table-bordered > tbody > tr > th, body.skin-black .content-wrapper .table.table-bordered > tfoot > tr > th, body.skin-black .content-wrapper .table.table-bordered > thead > tr > td, body.skin-black .content-wrapper .table.table-bordered > tbody > tr > td, body.skin-black .content-wrapper .table.table-bordered > tfoot > tr > td {
border: 1px solid #ddd;
}
/* line 382, ../sass/_adminlte.scss */
/* line 399, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .table.table-bordered > thead > tr > th, body.skin-black .content-wrapper .table.table-bordered > thead > tr > td {
border-bottom-width: 2px;
}
/* line 388, ../sass/_adminlte.scss */
/* line 405, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .pagination > .active > a, body.skin-black .content-wrapper .pagination > .active > span, body.skin-black .content-wrapper .pagination > .active > a:hover, body.skin-black .content-wrapper .pagination > .active > span:hover, body.skin-black .content-wrapper .pagination > .active > a:focus, body.skin-black .content-wrapper .pagination > .active > span:focus {
background-color: #F39C12;
border: solid 1px #F39C12;
color: white;
}
/* line 394, ../sass/_adminlte.scss */
/* line 411, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .pagination > li > a, body.skin-black .content-wrapper .pagination > li > span {
color: #F39C12;
}
/* line 396, ../sass/_adminlte.scss */
/* line 413, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .pagination > li > a:hover, body.skin-black .content-wrapper .pagination > li > span:hover {
color: #c87f0a;
}
/* line 401, ../sass/_adminlte.scss */
/* line 418, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .submenu {
margin-bottom: 25px;
}
/* line 405, ../sass/_adminlte.scss */
/* line 422, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .form-actions {
position: fixed;
bottom: 0;
@@ -1936,71 +1953,71 @@ body.skin-black .content-wrapper .form-actions {
z-index: 10;
border-top: solid 1px #e0e0e0;
}
/* line 418, ../sass/_adminlte.scss */
/* line 435, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .form-actions a, body.skin-black .content-wrapper .form-actions button {
margin-left: 10px;
}
/* line 423, ../sass/_adminlte.scss */
/* line 440, ../sass/_adminlte.scss */
body.skin-black .content-wrapper .form-buttons {
margin-top: 25px;
text-align: right;
}
/* line 430, ../sass/_adminlte.scss */
/* line 447, ../sass/_adminlte.scss */
body.skin-black .main-footer a {
color: #F39C12;
}
/* line 435, ../sass/_adminlte.scss */
/* line 452, ../sass/_adminlte.scss */
body.skin-black .gridview-pagesize {
float: right;
margin-bottom: 8px;
}
/* line 440, ../sass/_adminlte.scss */
/* line 457, ../sass/_adminlte.scss */
body.skin-black #yii-debug-toolbar {
bottom: 64px;
}

/* line 445, ../sass/_adminlte.scss */
/* line 462, ../sass/_adminlte.scss */
body.login-page {
background: none;
background-color: white;
}
/* line 449, ../sass/_adminlte.scss */
/* line 466, ../sass/_adminlte.scss */
body.login-page .login-box .login-logo {
text-align: center;
font-family: 'worksans_bold';
}
/* line 453, ../sass/_adminlte.scss */
/* line 470, ../sass/_adminlte.scss */
body.login-page .login-box .login-logo img {
width: 150px;
}
/* line 459, ../sass/_adminlte.scss */
/* line 476, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body,
body.login-page .login-box .login-box-body input#loginform-email,
body.login-page .login-box .login-box-body input#loginform-password,
body.login-page .login-box .login-box-body .btn-primary {
font-size: 14px;
}
/* line 466, ../sass/_adminlte.scss */
/* line 483, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body .btn-primary {
background-color: #F39C12;
border-color: #F39C12;
padding: 5px 10px;
margin-bottom: 15px;
}
/* line 472, ../sass/_adminlte.scss */
/* line 489, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body .btn-primary:active {
background-color: #f4a62a;
border-color: #F39C12;
}
/* line 478, ../sass/_adminlte.scss */
/* line 495, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body a {
color: #F39C12;
}
/* line 480, ../sass/_adminlte.scss */
/* line 497, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body a:hover {
color: #f4a62a;
}
/* line 485, ../sass/_adminlte.scss */
/* line 502, ../sass/_adminlte.scss */
body.login-page .login-box .login-box-body .checkbox label input {
position: relative;
top: 0px;

+ 8
- 1
backend/web/js/backend.js 查看文件

@@ -177,7 +177,7 @@ function opendistrib_dropdown_producers() {
setTimeout(function() { $('.producer-menu .search-producer').focus(); }, 100);
});

$('.producer-menu .search-producer').keyup(function () {
$('.producer-menu .search-producer').keyup(function (event) {
var $alertNoResults = $('.producer-menu .li-alert-no-results');
var searchWords = $(this).val().toLowerCase();
var count = 0;
@@ -201,6 +201,13 @@ function opendistrib_dropdown_producers() {
$alertNoResults.hide();
$('.producer-menu li.producer').show();
}

if(event.key == 'Enter') {
$firstProducer = $('.producer-menu li.producer:visible:first');
if($firstProducer.length > 0) {
window.location = $firstProducer.find('a').attr('href');
}
}
});

$('#link-display-producers-offline').click(function () {

+ 17
- 0
backend/web/sass/_adminlte.scss 查看文件

@@ -79,6 +79,11 @@ body.skin-black {
position: relative;
top: 2px;
text-transform: uppercase;

.producer-id {
color: gray;
font-size: 13px;
}
}
}

@@ -187,6 +192,18 @@ body.skin-black {
.offline {
display: none;
}

a {
color: #333;
}

.producer-id {
position: relative;
top: 4px;
color: gray;
font-size: 12px;
float: right;
}
}
}


+ 7
- 2
common/config/main.php 查看文件

@@ -44,6 +44,7 @@ use domain\Document\DeliveryNote\DeliveryNote;
use domain\Order\Order\Order;
use domain\Payment\Payment;
use domain\Ticket\Ticket\Ticket;
use domain\Ticket\TicketMessage\TicketMessage;
use domain\User\User\User;

$serverName = isset($_SERVER['SERVER_NAME']) ?? '' ;
@@ -208,9 +209,13 @@ return [
domain\Document\DeliveryNote\Event\DeliveryNoteObserver::class
],
Ticket::class => [
// User : envoi email nouveau ticket à l'administrateur
domain\User\User\Event\TicketObserver::class,
// Envoi email nouveau ticket à l'administrateur
\domain\Ticket\Ticket\Event\TicketObserver::class,
],
TicketMessage::class => [
// Envoi email nouveau message ticket à l'administrateur
\domain\Ticket\TicketMessage\Event\TicketMessageObserver::class,
]
],
],
],

+ 1
- 1
common/config/params.php 查看文件

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

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

+ 49
- 0
common/mail/newTicketMessageAdmin-html.php 查看文件

@@ -0,0 +1,49 @@
<?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\helpers\Html;

$userModule = UserModule::getInstance();

?>

<p>Une réponse vient d'être apportée par <strong><?= Html::encode($userModule->getSolver()->getUsername($ticketMessage->user)) ?></strong> au ticket
<a href="<?= Yii::$app->urlManagerBackend->createAbsoluteUrl(['support/view', 'id' => $ticketMessage->ticket->id, '#' => $ticketMessage->id]) ?>"><?= Html::encode($ticketMessage->ticket->subject) ?></a>.</p>



+ 50
- 0
common/mail/newTicketMessageAdmin-text.php 查看文件

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

/**
Copyright Souke (2018)

contact@souke.fr

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

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

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

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

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

use domain\User\User\UserModule;
use yii\helpers\Html;

$userModule = UserModule::getInstance();

?>

Une réponse vient d'être apportée par <?= Html::encode($userModule->getSolver()->getUsername($ticketMessage->user)) ?> au ticket <?= Html::encode($ticketMessage->ticket->subject) ?>.

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



+ 28
- 0
common/versions/24.5.B.php 查看文件

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

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

version(
'07/05/2024',
[
[
],
[
"[Administration] Communiquer > Email : correctif envois emails en masse (envois via nouveau prestataire : Brevo)"
]
],
[
[
"[Administration] Vue générale des utilisateurs",
"[Administration] Menu déroulant producteurs : ajout identifiant + entrée rapide avec la touche Entrée",
"[Administration] Support > tickets : notification par email pour l'admin quand une réponse est apportée à un ticket",
"[Administration] Utilisateurs > modifier : possibilité de définir un mot de passe manuellement"
],
[
"[Administration] Support admin : correctif count tickets dans le menu"
]
],
$userCurrent
);

?>

+ 3
- 2
common/versions/_macros.php 查看文件

@@ -19,14 +19,15 @@ function release_date(string $date) {

function features(array $featuresArray, array $featuresAdminArray, User $userCurrent) {
$userModule = UserModule::getInstance();
if(count($featuresArray) > 0 || count($featuresAdminArray) > 0) {
$isGrantedAsUserCurrent = $userModule->getAuthorizationChecker()->isGrantedAsAdministrator($userCurrent);
if(count($featuresArray) > 0 || (count($featuresAdminArray) > 0 && $isGrantedAsUserCurrent)) {
$html = '<div class="block block-features">';
$html .= '<h4><span class="glyphicon glyphicon-flash"></span> Évolutions</h4>';
$html .= '<ul>';
foreach($featuresArray as $feature) {
$html .= '<li>'.$feature.'</li>';
}
if($userModule->getAuthorizationChecker()->isGrantedAsAdministrator($userCurrent)) {
if($isGrantedAsUserCurrent) {
foreach($featuresAdminArray as $feature) {
$html .= '<li class="admin">'.$feature.'</li>';
}

domain/User/User/Event/TicketObserver.php → domain/Ticket/Ticket/Event/TicketObserver.php 查看文件

@@ -1,15 +1,14 @@
<?php
namespace domain\User\User\Event;
namespace domain\Ticket\Ticket\Event;

use domain\Ticket\Ticket\TicketModule;
use justcoded\yii2\eventlistener\observers\ActiveRecordObserver;
use domain\User\User\UserModule;
use yii\db\AfterSaveEvent;

class TicketObserver extends ActiveRecordObserver
{
public function inserted(AfterSaveEvent $event)
{
UserModule::getInstance()->getNotifier()
->sendMailNewTicketAdmin($event->sender);
TicketModule::getInstance()->getNotifier()->sendEmailAdminNewTicket($event->sender);
}
}

+ 6
- 0
domain/Ticket/Ticket/TicketModule.php 查看文件

@@ -13,6 +13,7 @@ class TicketModule extends AbstractModule
TicketSolver::class,
TicketRepository::class,
TicketBuilder::class,
TicketNotifier::class,
];
}

@@ -35,4 +36,9 @@ class TicketModule extends AbstractModule
{
return TicketBuilder::getInstance();
}

public function getNotifier(): TicketNotifier
{
return TicketNotifier::getInstance();
}
}

+ 47
- 0
domain/Ticket/Ticket/TicketNotifier.php 查看文件

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

namespace domain\Ticket\Ticket;

use domain\_\AbstractNotifier;
use domain\Ticket\TicketMessage\TicketMessage;
use domain\Ticket\TicketMessage\TicketMessageRepository;
use domain\User\User\UserSolver;

class TicketNotifier extends AbstractNotifier
{
protected UserSolver $userSolver;
protected TicketMessageRepository $ticketMessageRepository;

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

public function sendEmailAdminNewTicket(Ticket $ticket)
{
$this->mailer->sendAdmin(
'Nouveau ticket de '.$ticket->producer->name.' : '.$ticket->subject,
'newTicketAdmin',
[
'ticket' => $ticket,
]
);
}

public function sendEmailAdminNewTicketMessage(TicketMessage $ticketMessage)
{
$countTicketMessages = $this->ticketMessageRepository->countTicketMessagesByTicketId($ticketMessage->ticket->id);

if($this->userSolver->isStatusProducer($ticketMessage->user) && $countTicketMessages > 1) {
$this->mailer->sendAdmin(
'Réponse au ticket : ' . $ticketMessage->ticket->subject.' ('.$ticketMessage->ticket->producer->name.')',
'newTicketMessageAdmin',
[
'ticketMessage' => $ticketMessage
]
);
}
}
}

+ 5
- 1
domain/Ticket/Ticket/TicketSolver.php 查看文件

@@ -98,7 +98,11 @@ class TicketSolver extends AbstractSolver
}
}

return $ticket->ticketMessages[0];
if(isset($ticket->ticketMessages[0])) {
return $ticket->ticketMessages[0];
}

return null;
}

public function countTicketsUnreadByUserFromArray(array $ticketsArray, User $user): int

+ 15
- 0
domain/Ticket/TicketMessage/Event/TicketMessageObserver.php 查看文件

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

namespace domain\Ticket\TicketMessage\Event;

use domain\Ticket\Ticket\TicketModule;
use justcoded\yii2\eventlistener\observers\ActiveRecordObserver;
use yii\db\AfterSaveEvent;

class TicketMessageObserver extends ActiveRecordObserver
{
public function inserted(AfterSaveEvent $event)
{
TicketModule::getInstance()->getNotifier()->sendEmailAdminNewTicketMessage($event->sender);
}
}

+ 1
- 1
domain/Ticket/TicketMessage/TicketMessageBuilder.php 查看文件

@@ -22,7 +22,7 @@ class TicketMessageBuilder extends AbstractBuilder
public function createTicketMessage(Ticket $ticket, User $user, string $message): TicketMessage
{
$ticketMessage = $this->instanciateTicketMessage($ticket, $user, $message);
$this->saveCreate($ticketMessage);
$this->create($ticketMessage);

return $ticketMessage;
}

+ 13
- 1
domain/Ticket/TicketMessage/TicketMessageRepository.php 查看文件

@@ -19,10 +19,22 @@ class TicketMessageRepository extends AbstractRepository
public function getDefaultOptionsSearch(): array
{
return [
self::WITH => ['user', 'producer', 'ticketMessages'],
self::WITH => ['user'],
self::JOIN_WITH => [],
self::ORDER_BY => '',
self::ATTRIBUTE_ID_PRODUCER => ''
];
}

public function findTicketMessagesByTicketId(int $ticketId)
{
return $this->createDefaultQuery()
->filterByTicketId($ticketId)
->find();
}

public function countTicketMessagesByTicketId(int $ticketId): int
{
return count($this->findTicketMessagesByTicketId($ticketId));
}
}

+ 6
- 0
domain/Ticket/TicketMessage/TicketMessageRepositoryQuery.php 查看文件

@@ -12,4 +12,10 @@ class TicketMessageRepositoryQuery extends AbstractRepositoryQuery
{
$this->loadDefinition(TicketMessageDefinition::class);
}

public function filterByTicketId(int $ticketId)
{
$this->andWhere(['ticket_message.id_ticket' => $ticketId]);
return $this;
}
}

+ 0
- 11
domain/User/User/UserNotifier.php 查看文件

@@ -52,17 +52,6 @@ class UserNotifier extends AbstractNotifier implements ManagerInterface
}
}

public function sendMailNewTicketAdmin(Ticket $ticket)
{
$this->mailer->sendAdmin(
'Nouveau ticket',
'newTicketAdmin',
[
'ticket' => $ticket,
]
);
}

public function sendMailNewPassword(User $user, string $password)
{
$producer = $this->getProducerContext();

+ 6
- 4
domain/User/User/UserSearch.php 查看文件

@@ -61,11 +61,11 @@ class UserSearch extends User
];
}

public function search($params = [])
public function search($params = [], $producer = null)
{
$userModule = UserModule::getInstance();
$producerModule = ProducerModule::getInstance();
$producer = GlobalParam::getCurrentProducer();
//$producer = GlobalParam::getCurrentProducer();

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

$query->innerJoin('user_producer', 'user.id = user_producer.id_user AND user_producer.id_producer = :id_producer AND user_producer.active = 1', [':id_producer' => $producer->id]);
if($producer) {
$query->innerJoin('user_producer', 'user.id = user_producer.id_user AND user_producer.id_producer = :id_producer AND user_producer.active = 1', [':id_producer' => $producer->id]);
}

$dataProvider = new ActiveDataProvider([
'query' => $query,
@@ -102,7 +104,7 @@ class UserSearch extends User
'defaultOrder' => ['created_at' => SORT_DESC]
],
'pagination' => [
'pageSize' => $producerModule->getConfig('option_pagesize_user', $producer),
'pageSize' => $producer ? $producerModule->getConfig('option_pagesize_user', $producer) : 20,
],
]);


+ 7
- 0
domain/User/UserProducer/UserProducerRepository.php 查看文件

@@ -31,6 +31,13 @@ class UserProducerRepository extends AbstractRepository
->findOne();
}

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

public function findUserProducersByUser(User $user, bool $active = true, bool $bookmark = true)
{
return $this->createQuery()

正在加载...
取消
保存