@@ -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()) { |
@@ -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]); | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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]); | |||
} |
@@ -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) | |||
]); | |||
} | |||
} |
@@ -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; ?> |
@@ -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', |
@@ -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"> |
@@ -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]); |
@@ -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' | |||
]); | |||
} | |||
} | |||
], | |||
], | |||
], | |||
]); ?> |
@@ -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"> |
@@ -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; |
@@ -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 () { |
@@ -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; | |||
} | |||
} | |||
} | |||
@@ -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, | |||
] | |||
], | |||
], | |||
], |
@@ -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', |
@@ -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> | |||
@@ -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]) ?> | |||
@@ -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 | |||
); | |||
?> |
@@ -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>'; | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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 | |||
] | |||
); | |||
} | |||
} | |||
} |
@@ -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 |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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(); |
@@ -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, | |||
], | |||
]); | |||
@@ -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() |