Browse Source

Merge branch 'develop'

master
Guillaume Bourgeois 6 months ago
parent
commit
0d8839ebbb
51 changed files with 1393 additions and 250 deletions
  1. +15
    -0
      backend/controllers/DistributionController.php
  2. +7
    -0
      backend/controllers/DocumentController.php
  3. +147
    -0
      backend/controllers/SharedPointSaleController.php
  4. +1
    -1
      backend/views/development/index.php
  5. +5
    -0
      backend/views/distribution/index.php
  6. +15
    -1
      backend/views/layouts/content.php
  7. +12
    -2
      backend/views/layouts/left.php
  8. +28
    -1
      backend/views/point-sale/index.php
  9. +5
    -2
      backend/views/producer/update.php
  10. +72
    -0
      backend/views/shared-point-sale/create.php
  11. +187
    -0
      backend/views/shared-point-sale/index.php
  12. +4
    -0
      backend/web/css/screen.css
  13. +4
    -2
      backend/web/js/backend.js
  14. +12
    -0
      backend/web/js/vuejs/distribution-index.js
  15. +5
    -0
      backend/web/sass/point_sale/_index.scss
  16. +5
    -6
      common/components/Tiller/TillerClientV2.php
  17. +1
    -1
      common/config/main.php
  18. +1
    -1
      common/config/params.php
  19. +3
    -0
      common/helpers/Upload.php
  20. +29
    -0
      common/versions/24.6.B.php
  21. +2
    -2
      common/views/alert_message.php
  22. +2
    -2
      common/views/nav_user_top.php
  23. +42
    -26
      common/web/css/screen.css
  24. +18
    -4
      common/web/sass/_common.scss
  25. +38
    -0
      console/migrations/m240603_131331_create_table_shared_point_sale.php
  26. +42
    -0
      console/migrations/m240604_093627_add_columns_shared_point_sale_created_confirmed_declined.php
  27. +9
    -4
      domain/Distribution/PointSaleDistribution/PointSaleDistributionRepository.php
  28. +6
    -0
      domain/Distribution/PointSaleDistribution/PointSaleDistributionRepositoryQuery.php
  29. +1
    -0
      domain/Feature/Feature/Feature.php
  30. +2
    -1
      domain/Feature/Feature/FeatureDefinition.php
  31. +0
    -1
      domain/Order/Order/OrderBuilder.php
  32. +123
    -113
      domain/Order/Order/TillerManager.php
  33. +1
    -1
      domain/Order/OrderStatus/OrderStatusDefinition.php
  34. +16
    -0
      domain/PointSale/PointSale/PointSale.php
  35. +114
    -14
      domain/PointSale/SharedPointSale/SharedPointSale.php
  36. +29
    -3
      domain/PointSale/SharedPointSale/SharedPointSaleBuilder.php
  37. +16
    -2
      domain/PointSale/SharedPointSale/SharedPointSaleManager.php
  38. +12
    -0
      domain/PointSale/SharedPointSale/SharedPointSaleModule.php
  39. +57
    -0
      domain/PointSale/SharedPointSale/SharedPointSaleRepository.php
  40. +63
    -0
      domain/PointSale/SharedPointSale/SharedPointSaleRepositoryQuery.php
  41. +119
    -0
      domain/PointSale/SharedPointSale/SharedPointSaleResolver.php
  42. +5
    -0
      domain/Producer/Producer/Producer.php
  43. +16
    -13
      domain/Producer/Producer/ProducerRepository.php
  44. +1
    -1
      frontend/views/site/index.php
  45. +8
    -1
      producer/controllers/OrderController.php
  46. +20
    -0
      producer/views/order/confirm.php
  47. +4
    -1
      producer/views/order/order.php
  48. +13
    -1
      producer/views/site/points-sale.php
  49. +49
    -42
      producer/web/css/screen.css
  50. +2
    -1
      producer/web/sass/order/_order.scss
  51. +5
    -0
      producer/web/sass/site/_points_sale.scss

+ 15
- 0
backend/controllers/DistributionController.php View File

@@ -44,6 +44,7 @@ use common\helpers\MeanPayment;
use common\helpers\Price;
use domain\Distribution\Distribution\Distribution;
use domain\Document\DeliveryNote\DeliveryNote;
use domain\Feature\Feature\Feature;
use domain\Order\Order\Order;
use domain\Producer\Producer\Producer;
use DateTime;
@@ -161,6 +162,8 @@ class DistributionController extends BackendController
$producerModule = $this->getProducerModule();
$pointSaleModule = $this->getPointSaleModule();
$pointSaleDistributionModule = $this->getPointSaleDistributionModule();
$sharedPointSaleModule = $this->getSharedPointSaleModule();
$featureModule = $this->getFeatureModule();

$pointsSaleArray = $pointSaleModule->findPointSalesByDistributionAsArray($distribution);

@@ -180,6 +183,11 @@ class DistributionController extends BackendController
}

$pointSaleArray['credit_functioning'] = $producerModule->getPointSaleCreditFunctioning($pointSale);

$pointSaleArray['producers_sharing_point_sale_as_string'] = false;
if($featureModule->getChecker()->isEnabled(Feature::ALIAS_SHARED_POINT_SALE)) {
$pointSaleArray['producers_sharing_point_sale_as_string'] = $sharedPointSaleModule->getResolver()->getProducersSharingPointSaleAsString($pointSale, $distribution);
}
}

return $pointsSaleArray;
@@ -725,6 +733,13 @@ class DistributionController extends BackendController
return $this->getOrderModule()->getTillerManager()->synchronizeDistribution($date);
}

public function actionAjaxForceSynchronizeOrderTiller(int $idOrder)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$order = $this->getOrderModule()->getRepository()->findOneOrderById($idOrder);
return $this->getOrderModule()->getTillerManager()->synchronizeOrder($order, true);
}

public function actionAjaxGenerateDeliveryNotePointSale(string $idOrders)
{
if (strlen($idOrders)) {

+ 7
- 0
backend/controllers/DocumentController.php View File

@@ -153,6 +153,13 @@ class DocumentController extends BackendController
foreach ($model->ordersOnCreate as $key => $idOrder) {
$order = $orderModule->findOneOrderById($idOrder);
$orderModule->updateOrderInvoice($order, $model);
$orderModule->getBuilder()->updateOrderInvoicePrices($order,
[
'user' => $model->user,
'user_producer' => $this->getUserProducerModule()->getRepository()
->findOneUserProducer($model->user),
'point_sale' => $order->pointSale
]);
}
}
}

+ 147
- 0
backend/controllers/SharedPointSaleController.php View File

@@ -0,0 +1,147 @@
<?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\PointSale\SharedPointSale\SharedPointSale;
use domain\Feature\Feature\Feature;
use yii\filters\AccessControl;
use yii\web\NotFoundHttpException;

/**
* UserController implements the CRUD actions for User model.
*/
class SharedPointSaleController extends BackendController
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::class,
'rules' => [
[
'allow' => true,
'roles' => ['@'],
'matchCallback' => function ($rule, $action) {
$authorizationChecker = $this->getUserModule()->getAuthorizationChecker();
$featureChecker = $this->getFeatureModule()->getChecker();

return $authorizationChecker->isGrantedAsProducer($this->getUserCurrent())
&& $featureChecker->isEnabled(Feature::ALIAS_SHARED_POINT_SALE);
}
]
],
],
];
}

public function actionIndex()
{
$sharedPointSaleRepository = $this->getSharedPointSaleModule()->getRepository();

return $this->render('index', [
'sharedPointsSaleRequestOfMe' => $sharedPointSaleRepository->findSharedPointsSaleRequestsOfMe(),
'sharedPointsSaleRequestOthers' => $sharedPointSaleRepository->findSharedPointsSaleRequestsOthers(),
'pointsSaleArray' => $this->getPointSaleModule()->getRepository()->findPointSales()
]);
}

public function actionCreate()
{
$sharedPointSaleModule = $this->getSharedPointSaleModule();
$sharedPointSaleModel = $sharedPointSaleModule->getBuilder()->instanciateSharedPointSale(null, null, $this->getUserCurrent());

if($sharedPointSaleModel->load(\Yii::$app->request->post()) && $sharedPointSaleModel->validate()) {
$sharedPointSaleModule->getManager()->createSharedPointSale(
$sharedPointSaleModel->getPointSale(),
$sharedPointSaleModel->getProducerWithSharing(),
$this->getUserCurrent()
);
$this->setFlash('success', "La demande de partage a bien été créée");
return $this->redirect(['index']);
}

return $this->render('create', [
'sharedPointSaleModel' => $sharedPointSaleModel
]);
}

public function actionConfirm(int $id)
{
$sharedPointSale = $this->findSharedPointSale($id);
$sharedPointSale->scenario = SharedPointSale::SCENARIO_CONFIRM;
if($sharedPointSale->load(\Yii::$app->request->post()) && $sharedPointSale->validate()) {
$pointSaleWithSharing = $sharedPointSale->getPointSaleWithSharing();
if($this->getSharedPointSaleModule()->getManager()->confirmSharedPointSale($sharedPointSale, $pointSaleWithSharing, $this->getUserCurrent())) {
$this->addFlash('success', "Le partage de point de vente a bien été confirmé");
}
else {
$this->addFlash('error', "Une erreur est survenue lors de la confirmation du partage");
}
}
else {
$this->addFlash('error', "Veuillez sélectionner un point de vente pour confirmer le partage");
}

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

public function actionDecline(int $id)
{
$sharedPointSale = $this->findSharedPointSale($id);
if($this->getSharedPointSaleModule()->getManager()->declineSharedPointSale($sharedPointSale, $this->getUserCurrent())) {
$this->addFlash('success', "La demande de partage de point de vente a bien été annulée.");
}
else {
$this->addFlash('error', "Une erreur est survenue lors de l'annulation de la demande de partage.");
}

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

public function findSharedPointSale(int $id)
{
$sharedPointSale = $this->getSharedPointSaleModule()->getRepository()->findOneSharedPointSaleById($id);

if(!$sharedPointSale) {
throw new NotFoundHttpException("La demande de point de vente partagé n'a pas été trouvée.");
}

return $sharedPointSale;
}
}

+ 1
- 1
backend/views/development/index.php View File

@@ -74,7 +74,7 @@ $this->addBreadcrumb($this->getTitle());
<h3 class="panel-title">Participer</h3>
</div>
<div class="panel-body">
<p>Le logiciel Opendistrib se construit pour et avec vous. Toutes vos remarques, suggestions et remontées
<p>Le logiciel Souke se construit pour et avec vous. Toutes vos remarques, suggestions et remontées
de bugs sont les bienvenues et forment le terreau des versions futures.</p>
<p>
<a class="btn btn-default" href="<?= $this->getUrlManagerBackend()->createUrl(['support/index']); ?>">

+ 5
- 0
backend/views/distribution/index.php View File

@@ -348,6 +348,10 @@ $this->setPageTitle('Distributions') ;
</template>
<template v-else>Désactivé</template>
</div>
<div v-if="pointSaleActive.producers_sharing_point_sale_as_string">
<span class="title">Point de vente partagé</span>
<i class="fa fa-share-alt"></i> {{ pointSaleActive.producers_sharing_point_sale_as_string }}
</div>
</div>

<table class="table table-condensed table-bordered table-hover" v-if="countOrdersByPointSale[idActivePointSale] > 0 || (idActivePointSale == 0 && orders.length > 0)">
@@ -513,6 +517,7 @@ $this->setPageTitle('Distributions') ;
</button>
<ul class="dropdown-menu">
<li><a href="javascript:void(0);" class="" :data-id-order="order.id" @click="deleteOrderClick"><span class="glyphicon glyphicon-trash"></span> {{ order.labelDeleteAction }}</a></li>
<li v-if="producer && producer.tiller"><a href="javascript:void(0);" @click="forceSynchronizeOrderTiller(order.id)"><span class="glyphicon glyphicon-transfer"></span> Synchroniser avec Tiller</a></li>
<li v-if="order.id_subscription > 0"><a class="" :href="baseUrl+'/subscription/update?id='+order.id_subscription"><span class="glyphicon glyphicon-repeat"></span> Modifier l'abonnement lié</a></li>
<li v-else><a class="add-subscription" :href="baseUrl+'/subscription/create?idOrder='+order.id"><span class="glyphicon glyphicon-plus"></span><span class="glyphicon glyphicon-repeat"></span>Créer un abonnement</a></li>
</ul>

+ 15
- 1
backend/views/layouts/content.php View File

@@ -43,6 +43,7 @@ use common\helpers\GlobalParam;

$producerModule = $this->getProducerModule();
$adminSettingBag = $this->getSettingModule()->getAdminSettingBag();
$sharedPointSaleModule = $this->getSharedPointSaleModule();

?>
<div class="content-wrapper">
@@ -92,11 +93,24 @@ $adminSettingBag = $this->getSettingModule()->getAdminSettingBag();
<?php $producer = GlobalParam::getCurrentProducer(); ?>
<?php if($producer && !$producerModule->isUpToDateWithOpendistribVersion($producer) && $producer->option_display_message_new_opendistrib_version): ?>
<div class="alert alert-success">
<p>Souke a été mis à jour vers la version <?= GlobalParam::getSoukeVersion() ?> ! <a class="alert-link" href="<?= Yii::$app->urlManager->createUrl(['development/index']) ?>">Découvrir les nouveautés</a></p>
<p>
<i class="icon fa fa-cogs"></i>
Souke a été mis à jour vers la version <?= GlobalParam::getSoukeVersion() ?> ! <a class="alert-link" href="<?= Yii::$app->urlManager->createUrl(['development/index']) ?>">Découvrir les nouveautés</a>
</p>
<a href="<?= Yii::$app->urlManager->createUrl(['producer/update-opendistrib-version']) ?>" class="close"><span aria-hidden="true">&times;</span></a>
</div>
<?php endif; ?>

<?php $countSharedPointsSaleRequestsOthers = $sharedPointSaleModule->getResolver()->countSharedPointsSaleRequestsOthers(); ?>
<?php if($countSharedPointsSaleRequestsOthers && Yii::$app->controller->id != 'shared-point-sale'): ?>
<div class="alert alert-info">
<p>
<i class="icon fa fa-share-alt"></i>
Vous avez une demande de partage de point de vente en attente. <a class="alert-link" href="<?= Yii::$app->urlManager->createUrl(['shared-point-sale/index']) ?>">Voir</a>
</p>
</div>
<?php endif; ?>

<?php
$flashTypeArray = ['error' => 'ban', 'danger' => 'ban', 'warning' => 'warning', 'info' => 'info', 'success' => 'check'];
foreach($flashTypeArray as $flashType => $icon) {

+ 12
- 2
backend/views/layouts/left.php View File

@@ -202,7 +202,17 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
['label' => 'Import prix', 'icon' => 'upload', 'url' => ['/product/price-import'], 'visible' => $isUserCurrentGrantedAsProducer && $featureChecker->isEnabled(Feature::ALIAS_PRODUCT_PRICE_IMPORT)],
]
],
['label' => 'Points de vente', 'icon' => 'map-marker', 'url' => ['/point-sale/index'], 'visible' => $isUserCurrentGrantedAsProducer, 'active' => Yii::$app->controller->id == 'point-sale'],
[
'label' => 'Points de vente',
'icon' => 'map-marker',
'url' => ['/point-sale/index'],
'visible' => $isUserCurrentGrantedAsProducer,
'active' => Yii::$app->controller->id == 'point-sale' || Yii::$app->controller->id == 'shared-point-sale',
'items' => [
['label' => 'Liste', 'icon' => 'th-list', 'url' => ['/point-sale/index'], 'visible' => $isUserCurrentGrantedAsProducer],
['label' => 'Partages', 'icon' => 'share-alt', 'url' => ['/shared-point-sale/index'], 'visible' => $isUserCurrentGrantedAsProducer && $featureChecker->isEnabled(Feature::ALIAS_SHARED_POINT_SALE)],
]
],
[
'label' => 'Utilisateurs',
'icon' => 'users',
@@ -253,7 +263,7 @@ $isUserCurrentGrantedAsProducer = $userModule->getAuthorizationChecker()->isGran
],
['label' => 'Paramètres', 'icon' => 'cog', 'url' => ['/producer/update'], 'visible' => $isUserCurrentGrantedAsProducer],
['label' => 'Accès', 'icon' => 'lock', 'url' => ['/access/index'], 'visible' => $isUserCurrentGrantedAsProducer],
['label' => "Opendistrib", 'options' => ['class' => 'header'], 'visible' => $isUserCurrentGrantedAsProducer],
['label' => "Souke", 'options' => ['class' => 'header'], 'visible' => $isUserCurrentGrantedAsProducer],
[
'label' => 'Mes factures',
'icon' => 'clone',

+ 28
- 1
backend/views/point-sale/index.php View File

@@ -36,12 +36,15 @@
* termes.
*/

use domain\Feature\Feature\Feature;
use domain\PointSale\UserPointSale\UserPointSale;
use domain\Producer\Producer\Producer;
use yii\grid\GridView;
use yii\helpers\Html;

$pointSaleModule = $this->getPointSaleModule();
$sharedPointSaleModule = $this->getSharedPointSaleModule();
$featureChecker = $this->getFeatureModule()->getChecker();

$this->setTitle('Points de vente');
$this->addBreadcrumb($this->getTitle());
@@ -64,12 +67,23 @@ $this->addButton(
'attribute' => 'name',
'label' => 'Nom',
'format' => 'raw',
'value' => function ($model) {
'contentOptions' => ['class' => 'column-name'],
'value' => function ($model) use ($featureChecker, $sharedPointSaleModule) {
$html = '';
$html .= '<div class="name">';
$html .= $model->name;
if ($model->is_bread_box) {
$html .= ' <span class="label label-default">Boîte à pain</span> ';
}
$html .= '</div>';

if($featureChecker->isEnabled(Feature::ALIAS_SHARED_POINT_SALE)) {
if($sharedPointSaleModule->getResolver()->countPointsSaleSharedWithPointSale($model)) {
$html .= '<div class="shared-point-sale-producers"><small><span class="fa fa-share-alt"></span> ';
$html .= $sharedPointSaleModule->getResolver()->getProducersSharingPointSaleAsString($model);
$html .= '</small></div>';
}
}

return $html;
}
@@ -184,6 +198,19 @@ $this->addButton(
}
}
],
[
//'visible' => $featureChecker->isEnabled(Feature::ALIAS_SHARED_POINT_SALE),
'visible' => false,
'label' => 'Partages',
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'td-shared-point-sale column-hide-on-mobile'],
'value' => function ($pointSale) use ($sharedPointSaleModule) {
$countPointsSaleSharedWithPointSale = $sharedPointSaleModule->getResolver()->countPointsSaleSharedWithPointSale($pointSale);
return '<a class="btn btn-'.($countPointsSaleSharedWithPointSale ? 'success' : 'default').'" href="'.Yii::$app->urlManager->createUrl(['shared-point-sale/index']).'" title="'.$sharedPointSaleModule->getResolver()->getProducersSharingPointSaleAsString($pointSale, null, '&#013;').'">'.$countPointsSaleSharedWithPointSale.' <span class="fa fa-share-alt"></span></a>';
}
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{update} {delete}',

+ 5
- 2
backend/views/producer/update.php View File

@@ -303,11 +303,14 @@ $this->addBreadcrumb($this->getTitle());
<?= $form->field($model, 'option_weeks_distributions_activated_in_advance')
->dropDownList($choicesWeeksDistributionsActivatedInAdvanceArray)
->hint("Attention, les premières semaines doivent être activées manuellement."); ?>
<?= $form->field($model, 'option_order_reference_type')
<?php
// Fonctionnalité désactivée car elle crée des bugs
// @TODO : à réactiver quand tous les problèmes seront résolus
/*$form->field($model, 'option_order_reference_type')
->dropDownList([
Producer::ORDER_REFERENCE_TYPE_NONE => '--',
Producer::ORDER_REFERENCE_TYPE_YEARLY => 'Annuelle',
], []); ?>
], []);*/ ?>
<?= $form->field($model, 'option_behavior_cancel_order')
->dropDownList([
Producer::BEHAVIOR_DELETE_ORDER_DELETE => 'Suppression de la commande',

+ 72
- 0
backend/views/shared-point-sale/create.php View File

@@ -0,0 +1,72 @@
<?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\PointSale\PointSale\PointSaleRepository;
use yii\helpers\Html;
use yii\widgets\ActiveForm;

$pointSaleModule = $this->getPointSaleModule();
$producerModule = $this->getProducerModule();

$this->setTitle('Partager un point de vente') ;
$this->addBreadcrumb(['label' => 'Points de vente partagés', 'url' => ['index']]) ;
$this->addBreadcrumb('Partager') ;

?>

<div class="shared-point-sale-create">
<?php $form = ActiveForm::begin([
'enableClientValidation' => false
]); ?>
<div class="panel panel-default">
<div class="panel-body">
<?= $form->field($sharedPointSaleModel, 'id_point_sale')
->dropDownList($pointSaleModule->getRepository()->populatePointSaleDropdownList())
->label('Point de vente'); ?>
<?php $producerPopulateDropdownArray = $producerModule->getRepository()->populateProducerDropdown(true); ?>
<?= $form->field($sharedPointSaleModel, 'id_producer_with_sharing')
->dropDownList($producerPopulateDropdownArray['data'], ['prompt' => '--','encode' => false,'options' => $producerPopulateDropdownArray['options']])
->label('Producteur avec qui vous souhaitez le partager');?>
</div>
</div>
<div class="form-group form-actions">
<?= Html::a('Retour', ['index'], ['class' => 'btn btn-default']) ?>
<?= Html::submitButton($sharedPointSaleModel->isNewRecord ? 'Créer' : 'Modifier', ['class' => 'btn btn-primary', 'name' => 'save']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>

+ 187
- 0
backend/views/shared-point-sale/index.php View File

@@ -0,0 +1,187 @@
<?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\PointSale\UserPointSale\UserPointSale;
use domain\Producer\Producer\Producer;
use yii\grid\GridView;
use yii\helpers\Html;
use yii\widgets\ActiveForm;

$sharedPointSaleModule = $this->getSharedPointSaleModule();
$pointSaleModule = $this->getPointSaleModule();

$this->setTitle('Points de vente partagés');
$this->addBreadcrumb($this->getTitle());
$this->addButton(
[
'label' => 'Partager un point de vente <span class="glyphicon glyphicon-plus"></span>',
'url' => 'shared-point-sale/create',
'class' => 'btn btn-primary'
]
);
?>



<div class="shared-point-sale-index">
<div class="row">
<div class="col-md-8">
<?php if(count($sharedPointsSaleRequestOfMe)): ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
Mes demandes de partages en attente
</h3>
</div>
<div class="panel-body">
<table class="table table-striped table-bordered">
<tbody>
<?php foreach($sharedPointsSaleRequestOfMe as $sharedPointSale): ?>
<tr>
<td>
Vous souhaitez partager votre point de vente <strong><?= Html::encode($sharedPointSale->getPointSale()->getName()); ?></strong>
avec le producteur <strong><?= Html::encode($sharedPointSale->getProducerWithSharing()->getName()); ?></strong>
</td>
<td>
<a href="<?= Yii::$app->urlManager->createUrl(['shared-point-sale/decline', 'id' => $sharedPointSale->getId()]) ?>" class="btn btn-default">Annuler</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>

<?php if(count($sharedPointsSaleRequestOthers)): ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
Demandes de partage des autres producteurs
</h3>
</div>
<div class="panel-body">
<table class="table table-striped table-bordered">
<tbody>
<?php foreach($sharedPointsSaleRequestOthers as $sharedPointSale): ?>
<tr>
<td>Le producteur <strong><?= Html::encode($sharedPointSale->getPointSale()->getProducer()->getName()); ?></strong>
souhaite partager son point de vente <strong><?= Html::encode($sharedPointSale->getPointSale()->getName()); ?></strong>
avec vous.
</td>
<td>
<?php $form = ActiveForm::begin([
'enableClientValidation' => false,
'action' => Yii::$app->urlManager->createUrl(['shared-point-sale/confirm', 'id' => $sharedPointSale->getId()])
]); ?>
<?= $form->field($sharedPointSale, 'id_point_sale_with_sharing')
->dropDownList($pointSaleModule->getRepository()->populatePointSaleDropdownList())
->label('Votre point de vente correspondant')
->hint('Absent de la liste ? <a href="'.Yii::$app->urlManager->createUrl(['point-sale/create']).'">Créer le point de vente</a>'); ?>

<?= Html::submitButton('Confirmer', ['class' => 'btn btn-success', 'name' => 'save']) ?>
<?php ActiveForm::end(); ?>
</td>
<td>
<br />
<a href="<?= Yii::$app->urlManager->createUrl(['shared-point-sale/decline', 'id' => $sharedPointSale->getId()]) ?>" class="btn btn-danger">
Refuser
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>

<?php if($sharedPointSaleModule->getResolver()->countPointsSaleShared()): ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
Partages confirmés
</h3>
</div>
<div class="panel-body">
<table class="table table-striped table-bordered">
<thead>
<tr>
<td>Point de vente</td>
<td>Partagé avec</td>
</tr>
</thead>
<tbody>
<?php foreach($pointsSaleArray as $pointSale): ?>
<?php
$pointsSaleSharedWithPointSaleArray = $sharedPointSaleModule->getResolver()->getPointsSaleSharedWithPointSale($pointSale);
if(count($pointsSaleSharedWithPointSaleArray)):
?>
<tr>
<td><?= Html::encode($pointSale->getName()); ?></td>
<td>
<?php foreach($pointsSaleSharedWithPointSaleArray as $pointSaleSharedWithPointSale): ?>
<div>
<?= Html::encode($pointSaleSharedWithPointSale->getProducer()->getName()); ?>
- <?= Html::encode($pointSaleSharedWithPointSale->getName()); ?>
<!--<a href="<?= Yii::$app->urlManager->createUrl(['shared-point-sale/decline']) ?>" class="btn btn-xs btn-default">
<span class="glyphicon glyphicon-remove"></span>
</a>-->
</div>
<?php endforeach; ?>
</td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
</div>
<div class="col-md-4">
<div class="callout callout-info">
<span class="glyphicon glyphicon-info-sign"></span>
Cette fonctionnalité vous permet de partager des points de vente avec d'autres producteurs inscrits sur Souke
et avec qui vous avez des distributions en commun.<br />
Quand vous partagez un point de vente avec un autre producteur, un lien vers votre boutique est
proposé aux clients de ce producteur quand ils passent commande sur le point de vente en partage.
</div>
</div>
</div>
</div>

+ 4
- 0
backend/web/css/screen.css View File

@@ -2847,6 +2847,10 @@ termes.
text-align: center;
}
/* line 8, ../sass/point_sale/_index.scss */
.point-sale-index table .column-name .shared-point-sale-producers {
margin-top: 5px;
}
/* line 13, ../sass/point_sale/_index.scss */
.point-sale-index table .column-payment-method ul {
list-style-type: none;
padding: 0px;

+ 4
- 2
backend/web/js/backend.js View File

@@ -322,7 +322,11 @@ function opendistrib_products_event_price_with_tax() {

function opendistrib_products_event_price() {
taxRateSelected = $('#product-id_tax_rate').find('option:selected').data('tax-rate-value');
if (typeof taxRateSelected == 'undefined') {
taxRateSelected = 0;
}
var priceWithTax = $('#product-price-with-tax').val();

if (priceWithTax) {
$('#product-price').val(getPrice(priceWithTax, taxRateSelected));
// formattage
@@ -391,7 +395,6 @@ function opendistrib_product_prices_event_price_with_tax() {
$('#productprice-price-with-tax').val(getPriceWithTax(price, taxRateValue));
// formattage
$('#productprice-price').val(parseFloat(price).toFixed(5));

opendistrib_product_prices_update_reduction_increase();
}
}
@@ -403,7 +406,6 @@ function opendistrib_product_prices_event_price() {
$('#productprice-price').val(getPrice(priceWithTax, taxRateValue));
// formattage
$('#productprice-price-with-tax').val(parseFloat(priceWithTax).toFixed(2));

opendistrib_product_prices_update_reduction_increase();
}
}

+ 12
- 0
backend/web/js/vuejs/distribution-index.js View File

@@ -643,6 +643,18 @@ if($(selector).length) {
app.init(app.idActivePointSale);
});
},
forceSynchronizeOrderTiller: function(idOrder) {
var app = this;
this.showLoading = true;
axios.get(UrlManager.getBaseUrlAbsolute() + "distribution/ajax-force-synchronize-order-tiller", {
params: {
idOrder: idOrder
}
})
.then(function (response) {
app.init(app.idActivePointSale);
});
},
authTiller: function () {

},

+ 5
- 0
backend/web/sass/point_sale/_index.scss View File

@@ -4,6 +4,11 @@
.td-default {
text-align: center ;
}
.column-name {
.shared-point-sale-producers {
margin-top: 5px;
}
}
.column-payment-method {
ul {
list-style-type: none;

+ 5
- 6
common/components/Tiller/TillerClientV2.php View File

@@ -83,11 +83,10 @@ class TillerClientV2 implements TillerClientInterface
public function postOrder($params)
{
return $this->curl->setPostParams(
array_merge([
'provider_token' => $this->providerToken,
'restaurant_token' => $this->restaurantToken,
], $params)
)
->post($this->urlApi . 'orders');
array_merge([
'provider_token' => $this->providerToken,
'restaurant_token' => $this->restaurantToken,
], $params)
)->post($this->urlApi . 'orders');
}
}

+ 1
- 1
common/config/main.php View File

@@ -67,7 +67,7 @@ return [
}
}

if (Yii::$app->params['maintenanceMode']) {
if (Yii::$app->params['maintenanceMode'] && Yii::$app instanceof \yii\web\Application) {
if(isset($_GET['letMeIn'])) {
Yii::$app->session->set('letMeIn', (int) $_GET['letMeIn']);
}

+ 1
- 1
common/config/params.php View File

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

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

+ 3
- 0
common/helpers/Upload.php View File

@@ -58,6 +58,9 @@ class Upload
if ($width > 500) {
$image = Yii::$app->image->load($path_file);

// fix exif orientation
$image->rotate(array_values([0, 0, 0, 180, 0, 0, 90, 0, -90])[@exif_read_data($path_file)['Orientation'] ?: 0]);

// big
if ($width > 1600) {
$image->resize(1600)->save($dir_file . $file_name . '-big.' . $file->extension);

+ 29
- 0
common/versions/24.6.B.php View File

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

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

version(
'10/06/2024',
[
[
"[Administration] Distributions > Tiller : possibilité de forcer la synchronisation d'une commande"
],
[
"[Administration] Produits > photo : correctif orientation image (données EXIF non prises en compte)",
"[Administration] Produits : correctif problème saisie prix via champs TTC (NaN)",
"[Administration] Factures : correctif initialisation prix facturés lors de la création d'une facture sur base de commandes",
"[Site & boutique] Menu haut : affichage du nom de l'utilisateur en entier"
]
],
[
[

],
[
"Mode maintenance : correctif lancement de commandes via la console"
]
],
$userCurrent
);

?>

+ 2
- 2
common/views/alert_message.php View File

@@ -6,7 +6,7 @@ use yii\helpers\Html;

<?php if($display && $message): ?>
<div class="alert alert-<?= $type ?>">
<?php if($title): ?>
<?php if(isset($title) && $title): ?>
<h4>
<?php if($icon): ?>
<i class="icon fa fa-<?= $icon ?>"></i>
@@ -15,7 +15,7 @@ use yii\helpers\Html;
</h4>
<?php endif; ?>
<p>
<?php if(!$title && $icon): ?>
<?php if((!isset($title) || !$title) && $icon): ?>
<i class="icon fa fa-<?= $icon ?>"></i>
<?php endif; ?>
<?php if(is_array($message)): ?>

+ 2
- 2
common/views/nav_user_top.php View File

@@ -107,9 +107,9 @@ if ($isUserCurrentGrantedAsProducer && $userCurrent->id_producer) {

$itemUser = [
'label' => '<i class="bi bi-person"></i> <span class="link-text">' .
((!Yii::$app->user->isGuest) ? Html::encode(Yii::$app->user->identity->name . ' ' . strtoupper(substr(Yii::$app->user->identity->lastname, 0, 1)) . '.') : '') .
((!Yii::$app->user->isGuest) ? Html::encode(Yii::$app->user->identity->name . ' ' . Yii::$app->user->identity->lastname) : '') .
'</span>',
'options' => ['id' => 'label1'],
'options' => ['id' => 'label1', 'class' => 'nav-item-user'],
'url' => '#',
'linkOptions' => ['class' => ''],
'items' => $itemsUserArray,

+ 42
- 26
common/web/css/screen.css View File

@@ -432,48 +432,64 @@ termes.
position: relative;
top: 1px;
}
/* line 281, ../sass/_common.scss */
/* line 280, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar ul li.nav-item-producers .dropdown-menu {
right: -75px;
left: -75px;
}
/* line 285, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar ul li.nav-item-user .dropdown-menu {
right: -22px;
left: 9px;
}
/* line 291, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar ul li .dropdown-menu a {
padding: 2px 20px;
}
/* line 284, ../sass/_common.scss */
/* line 294, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar ul li .dropdown-menu a:hover, .container-nav-user-top .nav-user-top .navbar ul li .dropdown-menu a:focus {
background-color: #ece4d8;
}
/* line 293, ../sass/_common.scss */
/* line 303, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .dropdown-menu {
z-index: 9999;
}
/* line 295, ../sass/_common.scss */
/* line 305, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .dropdown-menu .divider.dropdown-header {
padding: 0px;
}

@media screen and (max-width: 991px) {
/* line 306, ../sass/_common.scss */
/* line 316, ../sass/_common.scss */
.container-nav-user-top .nav-user-top {
position: relative;
}
/* line 310, ../sass/_common.scss */
/* line 320, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar ul {
width: 100%;
display: block;
margin-right: 0px;
text-align: center;
}
/* line 316, ../sass/_common.scss */
/* line 326, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar ul li {
display: inline-block;
}
/* line 320, ../sass/_common.scss */
/* line 329, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar ul li.nav-item-producers .dropdown-menu {
right: -95px;
left: -115px;
width: 300px;
}
/* line 327, ../sass/_common.scss */
/* line 334, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar ul li.nav-item-user .dropdown-menu {
left: -40px;
width: 150px;
}
/* line 341, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar .link-text {
display: none;
}
/* line 331, ../sass/_common.scss */
/* line 345, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar .dropdown-menu {
position: absolute;
right: 5%;
@@ -484,32 +500,32 @@ termes.
-webkit-box-shadow: 0px 0px 4px gray;
box-shadow: 0px 0px 4px gray;
}
/* line 340, ../sass/_common.scss */
/* line 354, ../sass/_common.scss */
.container-nav-user-top .nav-user-top .navbar .dropdown-menu li a {
padding-left: 15px;
}
}
/* Block de date */
/* line 353, ../sass/_common.scss */
/* line 367, ../sass/_common.scss */
.block-date {
margin: 0px auto;
padding-top: 0px;
text-align: center;
}
/* line 358, ../sass/_common.scss */
/* line 372, ../sass/_common.scss */
.block-date .day {
text-transform: capitalize;
line-height: 15px;
font-size: 15px;
text-transform: uppercase;
}
/* line 365, ../sass/_common.scss */
/* line 379, ../sass/_common.scss */
.block-date .num {
font-size: 30px;
line-height: 35px;
font-weight: bold;
}
/* line 371, ../sass/_common.scss */
/* line 385, ../sass/_common.scss */
.block-date .month {
text-transform: uppercase;
line-height: 15px;
@@ -518,52 +534,52 @@ termes.
}

/* Page d'erreur */
/* line 381, ../sass/_common.scss */
/* line 395, ../sass/_common.scss */
#main #content .site-error .col-lg-6 {
margin: 0px auto;
float: none;
}
/* line 391, ../sass/_common.scss */
/* line 405, ../sass/_common.scss */
#main #content .site-error .panel h2 {
text-transform: none;
font-size: 25px;
margin-top: 0px;
margin-bottom: 20px;
}
/* line 398, ../sass/_common.scss */
/* line 412, ../sass/_common.scss */
#main #content .site-error .panel p:last-child {
margin-bottom: 0px;
padding-bottom: 0px;
}
/* line 404, ../sass/_common.scss */
/* line 418, ../sass/_common.scss */
#main #content .site-error .alert {
padding-bottom: 5px;
}
/* line 407, ../sass/_common.scss */
/* line 421, ../sass/_common.scss */
#main #content .site-error .alert h3 {
margin-top: 5px;
margin-bottom: 18px;
}
/* line 412, ../sass/_common.scss */
/* line 426, ../sass/_common.scss */
#main #content .site-error .alert p {
margin-bottom: 15px;
}
/* line 416, ../sass/_common.scss */
/* line 430, ../sass/_common.scss */
#main #content .site-error .alert .btn {
text-decoration: none;
}
/* line 421, ../sass/_common.scss */
/* line 435, ../sass/_common.scss */
#main #content .site-error p.error-message {
font-weight: bold;
}

/* Paiement */
/* line 427, ../sass/_common.scss */
/* line 441, ../sass/_common.scss */
.payment-detail-remaining-surplus {
font-size: 13px;
color: gray;
}
/* line 431, ../sass/_common.scss */
/* line 445, ../sass/_common.scss */
.payment-detail-remaining-surplus strong {
font-weight: bold;
}

+ 18
- 4
common/web/sass/_common.scss View File

@@ -277,6 +277,16 @@
}
}

&.nav-item-producers .dropdown-menu {
right: -75px;
left: -75px;
}

&.nav-item-user .dropdown-menu {
right: -22px;
left: 9px;
}

.dropdown-menu {
a {
padding: 2px 20px;
@@ -316,10 +326,14 @@
li {
display: inline-block;

&.nav-item-producers {
.dropdown-menu {
right: -95px;
}
&.nav-item-producers .dropdown-menu {
left: -115px;
width: 300px;
}

&.nav-item-user .dropdown-menu {
left: -40px;
width: 150px;
}
}
}

+ 38
- 0
console/migrations/m240603_131331_create_table_shared_point_sale.php View File

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

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

/**
* Class m240603_131331_create_table_shared_point_sale
*/
class m240603_131331_create_table_shared_point_sale extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->createTable('shared_point_sale', [
'id' => 'pk',
'id_point_sale' => Schema::TYPE_INTEGER,
'id_producer_with_sharing' => Schema::TYPE_INTEGER,
'id_point_sale_with_sharing' => Schema::TYPE_INTEGER,
'status' => Schema::TYPE_INTEGER,
]);
$this->addForeignKey('fk_id_point_sale', 'shared_point_sale', 'id_point_sale', 'point_sale', 'id');
$this->addForeignKey('fk_id_producer', 'shared_point_sale', 'id_producer_with_sharing', 'producer', 'id');
$this->addForeignKey('fk_id_point_sale_with_sharing', 'shared_point_sale', 'id_point_sale_with_sharing', 'point_sale', 'id');
}

/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropTable('shared_point_sale');
$this->dropForeignKey('fk_id_point_sale', 'shared_point_sale');
$this->dropForeignKey('fk_id_producer', 'shared_point_sale');
$this->dropForeignKey('fk_id_point_sale_with_sharing', 'shared_point_sale');
}
}

+ 42
- 0
console/migrations/m240604_093627_add_columns_shared_point_sale_created_confirmed_declined.php View File

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

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

/**
* Class m240604_093627_add_columns_shared_point_sale_created_confirmed_declined
*/
class m240604_093627_add_columns_shared_point_sale_created_confirmed_declined extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('shared_point_sale', 'created_at', Schema::TYPE_DATETIME);
$this->addColumn('shared_point_sale', 'created_by', Schema::TYPE_INTEGER);
$this->addColumn('shared_point_sale', 'confirmed_at', Schema::TYPE_DATETIME);
$this->addColumn('shared_point_sale', 'confirmed_by', Schema::TYPE_INTEGER);
$this->addColumn('shared_point_sale', 'declined_at', Schema::TYPE_DATETIME);
$this->addColumn('shared_point_sale', 'declined_by', Schema::TYPE_INTEGER);
$this->addForeignKey('fk_created_by', 'shared_point_sale', 'created_by', 'user', 'id');
$this->addForeignKey('fk_confirmed_by', 'shared_point_sale', 'confirmed_by', 'user', 'id');
$this->addForeignKey('fk_declined_by', 'shared_point_sale', 'declined_by', 'user', 'id');
}

/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropColumn('shared_point_sale', 'created_at');
$this->dropColumn('shared_point_sale', 'created_by');
$this->dropColumn('shared_point_sale', 'confirmed_at');
$this->dropColumn('shared_point_sale', 'confirmed_by');
$this->dropColumn('shared_point_sale', 'declined_at');
$this->dropColumn('shared_point_sale', 'declined_by');
$this->dropForeignKey('fk_created_by', 'shared_point_sale');
$this->dropForeignKey('fk_confirmed_by', 'shared_point_sale');
$this->dropForeignKey('fk_declined_by', 'shared_point_sale');
}
}

+ 9
- 4
domain/Distribution/PointSaleDistribution/PointSaleDistributionRepository.php View File

@@ -25,12 +25,17 @@ class PointSaleDistributionRepository extends AbstractRepository
];
}

public function findOnePointSaleDistribution(Distribution $distribution, PointSale $pointSale): ?PointSaleDistribution
public function findOnePointSaleDistribution(Distribution $distribution, PointSale $pointSale, bool $delivery = null): ?PointSaleDistribution
{
return $this->createDefaultQuery()
$query = $this->createDefaultQuery()
->filterByDistribution($distribution)
->filterByPointSale($pointSale)
->findOne();
->filterByPointSale($pointSale);

if(!is_null($delivery)) {
$query->filterIsDelivery($delivery);
}

return $query->findOne();
}

public function findPointSaleDistributionsByDistribution(Distribution $distribution): array

+ 6
- 0
domain/Distribution/PointSaleDistribution/PointSaleDistributionRepositoryQuery.php View File

@@ -28,4 +28,10 @@ class PointSaleDistributionRepositoryQuery extends AbstractRepositoryQuery

return $this;
}

public function filterIsDelivery(bool $delivery)
{
$this->andWhere(['delivery' => $delivery ? 1 : 0]);
return $this;
}
}

+ 1
- 0
domain/Feature/Feature/Feature.php View File

@@ -50,6 +50,7 @@ class Feature extends ActiveRecordCommon
const ALIAS_EXPORT_SHOPPING_CART_LABELS_ADVANCED = 'export_shopping_cart_labels_advanced';
const ALIAS_SETTINGS = 'settings';
const ALIAS_SHOP_SUPPORT = 'shop_support';
const ALIAS_SHARED_POINT_SALE = 'shared_point_sale';

/**
* @inheritdoc

+ 2
- 1
domain/Feature/Feature/FeatureDefinition.php View File

@@ -19,7 +19,8 @@ class FeatureDefinition extends AbstractDefinition
Feature::ALIAS_ONLINE_PAYMENT => 'Paiement en ligne',
Feature::ALIAS_EXPORT_SHOPPING_CART_LABELS_ADVANCED => "Génération d'étiquettes avec un format spécifique",
Feature::ALIAS_SETTINGS => 'Système de paramètres',
Feature::ALIAS_SHOP_SUPPORT => 'Support boutique'
Feature::ALIAS_SHOP_SUPPORT => 'Support boutique',
Feature::ALIAS_SHARED_POINT_SALE => 'Points de vente partagés',
];
}
}

+ 0
- 1
domain/Order/Order/OrderBuilder.php View File

@@ -449,7 +449,6 @@ class OrderBuilder extends AbstractBuilder
{
if ($this->orderSolver->isOrderFromProducer($order)) {
$this->updateOrderDeliveryNote($order, $deliveryNote);

$order = $this->orderRepository->findOneOrderById($order->id);
$user = $this->userRepository->findOneUserById($deliveryNote->id_user);
$userProducer = $this->userProducerRepository->findOneUserProducer($user);

+ 123
- 113
domain/Order/Order/TillerManager.php View File

@@ -66,7 +66,6 @@ class TillerManager extends AbstractManager

public function synchronizeDistribution(string $date): array
{
$apiVersion = $this->producerSolver->getConfig('tiller_api_version');
$return = [];

if($this->tillerActivated) {
@@ -80,130 +79,141 @@ class TillerManager extends AbstractManager
'conditions' => OrderRepositoryQuery::getSqlFilterIsValid()
]);

$strDate = date('Y-m-d\T12:i:s+0000', strtotime($date) + 1);
$datetime = new \DateTime(date('Y-m-d 12:i:s', strtotime($date)));

if ($orders && count($orders)) {
foreach ($orders as $order) {
$this->orderBuilder->initOrder($order);
$lines = [];
foreach ($order->productOrder as $productOrder) {
// v3
if($apiVersion == 'v3') {
$amount = round($this->productOrderSolver->getPriceWithTax($productOrder) * 100);

// classique
if(is_int($productOrder->quantity)) {
$quantity = $productOrder->quantity;
}
// vrac
else {
$amount = $amount * $productOrder->quantity;
$quantity = 1;
}

$lines[] = [
'name' => $productOrder->product->name,
'unitPrice' => [
'amount' => $amount,
],
'taxRate' => $productOrder->taxRate->value * 100,
'quantity' => $quantity
];
}
// v2
else {
$lines[] = [
'name' => $productOrder->product->name,
'price' => $this->productOrderSolver->getPriceWithTax($productOrder) * 100 * $productOrder->quantity,
'tax' => $productOrder->taxRate->value * 100,
'date' => $strDate,
'quantity' => $productOrder->quantity
];
}
$res = $this->synchronizeOrder($order);
if($res) {
$return[] = $res;
}
}
}
}
}

$typePaymentTiller = '';
if ($order->mean_payment == MeanPayment::MONEY) {
$typePaymentTiller = 'CASH';
}
if ($order->mean_payment == MeanPayment::CREDIT_CARD
|| $order->mean_payment == MeanPayment::CREDIT
|| $order->mean_payment == MeanPayment::TRANSFER
|| $order->mean_payment == MeanPayment::OTHER) {
$typePaymentTiller = 'CARD';
}
if ($order->mean_payment == MeanPayment::CHEQUE) {
$typePaymentTiller = 'BANK_CHECK';
}
if (!strlen($typePaymentTiller) || !$order->mean_payment) {
$typePaymentTiller = 'CASH';
}
return $return;
}

if (!$this->isSynchronized($date, $order->id)) {
// v3
if($apiVersion == 'v3') {

$payments = [];
$amountPayment = round($this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_PAID) * 100);
if($amountPayment) {
$payments[] = [
'externalId' => ''.$order->id,
'amount' => $amountPayment
];
}
public function synchronizeOrder(Order $order, bool $force = false)
{
$apiVersion = $this->producerSolver->getConfig('tiller_api_version');
$date = $order->distribution->date;
$strDate = date('Y-m-d\T12:i:s+0000', strtotime($date) + 1);
$datetime = new \DateTime(date('Y-m-d 12:i:s', strtotime($date)));
$this->orderBuilder->initOrder($order);
$lines = [];

$returnTiller = $this->tillerClient->postOrder([
'externalId' => ''.$order->id,
'purchaseRequestType' => 'clickAndCollect',
'date' => $datetime->format(\DateTime::ATOM),
'order' => [
'currencyCode' => 'EUR',
'itemLines' => $lines,
'payments' => $payments
]
]);
}
// v2
else {
$returnTiller = $this->tillerClient->postOrder([
'externalId' => $order->id,
'type' => 1,
'status' => 'IN_PROGRESS',
'openDate' => $strDate,
'closeDate' => $strDate,
'lines' => $lines,
'payments' => [
[
'type' => $typePaymentTiller,
'amount' => $this->orderSolver->getOrderAmountWithTax(
$order,
Order::AMOUNT_PAID
) * 100,
'status' => 'ACCEPTED',
'date' => $strDate
]
]
]);
}
foreach ($order->productOrder as $productOrder) {
// v3
if($apiVersion == 'v3') {
$amount = round($this->productOrderSolver->getPriceWithTax($productOrder) * 100);

$returnTillerObject = json_decode($returnTiller);
if($apiVersion == 'v3') {
$order->tiller_external_id = '' . $returnTillerObject->referenceId;
}
else {
$order->tiller_external_id = '' . $returnTillerObject->id;
}
$order->save();
// classique
if(is_int($productOrder->quantity)) {
$quantity = $productOrder->quantity;
}
// vrac
else {
$amount = $amount * $productOrder->quantity;
$quantity = 1;
}

$return[] = $returnTiller;
}
}
$lines[] = [
'name' => $productOrder->product->name,
'unitPrice' => [
'amount' => $amount,
],
'taxRate' => $productOrder->taxRate->value * 100,
'quantity' => $quantity
];
}
// v2
else {
$lines[] = [
'name' => $productOrder->product->name,
'price' => $this->productOrderSolver->getPriceWithTax($productOrder) * 100 * $productOrder->quantity,
'tax' => $productOrder->taxRate->value * 100,
'date' => $strDate,
'quantity' => $productOrder->quantity
];
}
}

$typePaymentTiller = '';
if ($order->mean_payment == MeanPayment::MONEY) {
$typePaymentTiller = 'CASH';
}
if ($order->mean_payment == MeanPayment::CREDIT_CARD
|| $order->mean_payment == MeanPayment::CREDIT
|| $order->mean_payment == MeanPayment::TRANSFER
|| $order->mean_payment == MeanPayment::OTHER) {
$typePaymentTiller = 'CARD';
}
if ($order->mean_payment == MeanPayment::CHEQUE) {
$typePaymentTiller = 'BANK_CHECK';
}
if (!strlen($typePaymentTiller) || !$order->mean_payment) {
$typePaymentTiller = 'CASH';
}

if (!$this->isSynchronized($date, $order->id) || $force) {
// v3
if($apiVersion == 'v3') {
$payments = [];
$amountPayment = round($this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_PAID) * 100);
if($amountPayment) {
$payments[] = [
'externalId' => ''.$order->id,
'amount' => $amountPayment
];
}

$returnTiller = $this->tillerClient->postOrder([
'externalId' => ''.$order->id,
'purchaseRequestType' => 'clickAndCollect',
'date' => $datetime->format(\DateTime::ATOM),
'order' => [
'currencyCode' => 'EUR',
'itemLines' => $lines,
'payments' => $payments
]
]);
}
// v2
else {
$returnTiller = $this->tillerClient->postOrder([
'externalId' => $order->id,
'type' => 1,
'status' => 'IN_PROGRESS',
'openDate' => $strDate,
'closeDate' => $strDate,
'lines' => $lines,
'payments' => [
[
'type' => $typePaymentTiller,
'amount' => $this->orderSolver->getOrderAmountWithTax(
$order,
Order::AMOUNT_PAID
) * 100,
'status' => 'ACCEPTED',
'date' => $strDate
]
]
]);
}

$returnTillerObject = json_decode($returnTiller);
if($apiVersion == 'v3') {
$order->tiller_external_id = '' . $returnTillerObject->referenceId;
}
else {
$order->tiller_external_id = '' . $returnTillerObject->id;
}
$order->save();

return $returnTiller;
}

return $return;
return null;
}

public function isSynchronized($date, $idOrder = null): bool

+ 1
- 1
domain/Order/OrderStatus/OrderStatusDefinition.php View File

@@ -15,7 +15,7 @@ class OrderStatusDefinition extends AbstractDefinition
{
return [
OrderStatus::ALIAS_ORDERED => [
'label' => 'Créée'
'label' => 'Ajoutée'
],
OrderStatus::ALIAS_UPDATED => [
'label' => 'Modifiée'

+ 16
- 0
domain/PointSale/PointSale/PointSale.php View File

@@ -42,6 +42,7 @@ use common\components\ActiveRecordCommon;
use common\helpers\GlobalParam;
use domain\Distribution\PointSaleDistribution\PointSaleDistribution;
use domain\PointSale\UserPointSale\UserPointSale;
use domain\Producer\Producer\Producer;
use domain\User\User\User;

/**
@@ -136,10 +137,25 @@ class PointSale extends ActiveRecordCommon
];
}

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

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

/*
* Relations
*/

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

public function getUserPointSale()
{
return $this->hasMany(UserPointSale::class, ['id_point_sale' => 'id']);

+ 114
- 14
domain/PointSale/SharedPointSale/SharedPointSale.php View File

@@ -5,9 +5,50 @@ namespace domain\PointSale\SharedPointSale;
use common\components\ActiveRecordCommon;
use domain\PointSale\PointSale\PointSale;
use domain\Producer\Producer\Producer;
use domain\User\User\User;

class SharedPointSale extends ActiveRecordCommon
{
/* Yii */

public const SCENARIO_CONFIRM = 'confirm';

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

public function rules()
{
return [
[['id_point_sale', 'id_producer_with_sharing', 'created_at', 'created_by'], 'required'],
['id_point_sale_with_sharing', 'required', 'on' => self::SCENARIO_CONFIRM],
[['id_point_sale', 'id_producer_with_sharing', 'id_point_sale_with_sharing', 'status',
'created_by', 'confirmed_by', 'declined_by'], 'integer'],
[['created_at', 'confirmed_at', 'declined_at'], 'safe'],
['id_point_sale', 'exist', 'targetClass' => PointSale::class, 'targetAttribute' => 'id'],
['id_point_sale_with_sharing', 'exist', 'targetClass' => PointSale::class, 'targetAttribute' => 'id'],
['id_producer_with_sharing', 'exist', 'targetClass' => Producer::class, 'targetAttribute' => 'id'],
[['created_by', 'confirmed_by', 'declined_by'], 'exist', 'targetClass' => User::class, 'targetAttribute' => 'id'],
];
}

public function attributeLabels()
{
return [
'id_point_sale' => 'Point de vente',
'id_producer_with_sharing' => 'Producteur',
'id_point_sale_with_sharing' => 'Point de vente partagé',
];
}

/* Get / Set */

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

public function getPointSale(): PointSale
{
return $this->pointSaleRelation;
@@ -33,7 +74,7 @@ class SharedPointSale extends ActiveRecordCommon

public function getPointSaleWithSharing(): ?PointSale
{
return $this->pointSaleWithSharing;
return $this->pointSaleWithSharingRelation;
}

public function setPointSaleWithSharing(PointSale $pointSaleWithSharing = null): self
@@ -56,26 +97,70 @@ class SharedPointSale extends ActiveRecordCommon
return $this;
}

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

public function rules()
public function setCreatedAt(\DateTime $createdAt): self
{
return [
[['id_point_sale', 'id_producer_with_sharing'], 'required'],
[['id_point_sale', 'id_producer_with_sharing', 'id_point_sale_with_sharing', 'status'], 'integer'],
];
$this->created_at = $createdAt->format('Y-m-d H:i:s');
return $this;
}

public function attributeLabels()
public function getConfirmedAt(): \DateTime
{
return [
'id_point_sale' => 'Point de vente que vous souhaitez partager',
'id_producer_with_sharing' => 'Producteur avec qui vous souhaitez partager un point de vente',
'id_point_sale_with_sharing' => 'Point de vente du producteur avec qui vous souhaitez partager un point de vente',
];
return new \DateTime($this->confirmed_at);
}

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

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

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

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

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

public function getConfirmedBy(): User
{
return $this->confirmedByRelation;
}

public function setConfirmedBy(User $confirmedBy): SharedPointSale
{
$this->populateFieldObject('confirmed_by', 'confirmedByRelation', $confirmedBy);
return $this;
}

public function getDeclinedBy(): User
{
return $this->declinedByRelation;
}

public function setDeclinedBy(User $declinedBy): SharedPointSale
{
$this->populateFieldObject('declined_by', 'declinedByRelation', $declinedBy);
return $this;
}

/* Relations */
@@ -94,4 +179,19 @@ class SharedPointSale extends ActiveRecordCommon
{
return $this->hasOne(PointSale::class, ['id' => 'id_point_sale_with_sharing']);
}

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

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

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

+ 29
- 3
domain/PointSale/SharedPointSale/SharedPointSaleBuilder.php View File

@@ -6,17 +6,43 @@ use domain\_\AbstractBuilder;
use domain\_\StatusInterface;
use domain\PointSale\PointSale\PointSale;
use domain\Producer\Producer\Producer;
use domain\User\User\User;

class SharedPointSaleBuilder extends AbstractBuilder
{
public function instanciateSharedPointSale(PointSale $pointSale, Producer $producerWithSharing): SharedPointSale
public function instanciateSharedPointSale(PointSale $pointSale = null, Producer $producerWithSharing = null, User $createdBy = null): SharedPointSale
{
$sharedPointSale = new SharedPointSale();

$sharedPointSale->setPointSale($pointSale);
$sharedPointSale->setProducerWithSharing($producerWithSharing);
if($pointSale) {
$sharedPointSale->setPointSale($pointSale);
}

if($producerWithSharing) {
$sharedPointSale->setProducerWithSharing($producerWithSharing);
}

if($createdBy) {
$sharedPointSale->setCreatedBy($createdBy);
}

$sharedPointSale->setCreatedAt(new \DateTime());
$sharedPointSale->setStatus(StatusInterface::STATUS_ONLINE);

return $sharedPointSale;
}

public function initConfirmSharedPointSale(SharedPointSale $sharedPointSale, PointSale $pointSaleWithSharing, User $confirmedBy)
{
$sharedPointSale->setPointSaleWithSharing($pointSaleWithSharing);
$sharedPointSale->setConfirmedBy($confirmedBy);
$sharedPointSale->setConfirmedAt(new \DateTime());
}

public function initDeclineSharedPointSale(SharedPointSale $sharedPointSale, User $declinedBy)
{
$sharedPointSale->setStatus(StatusInterface::STATUS_OFFLINE);
$sharedPointSale->setDeclinedBy($declinedBy);
$sharedPointSale->setDeclinedAt(new \DateTime());
}
}

+ 16
- 2
domain/PointSale/SharedPointSale/SharedPointSaleManager.php View File

@@ -5,6 +5,7 @@ namespace domain\PointSale\SharedPointSale;
use domain\_\AbstractManager;
use domain\PointSale\PointSale\PointSale;
use domain\Producer\Producer\Producer;
use domain\User\User\User;

class SharedPointSaleManager extends AbstractManager
{
@@ -15,9 +16,22 @@ class SharedPointSaleManager extends AbstractManager
$this->sharedPointSaleBuilder = $this->loadService(SharedPointSaleBuilder::class);
}

public function createSharedPointSale(PointSale $pointSale, Producer $producerWithSharing)
public function createSharedPointSale(PointSale $pointSale, Producer $producerWithSharing, User $createdBy): SharedPointSale
{
$sharedPointSale = $this->sharedPointSaleBuilder->instanciateSharedPointSale($pointSale, $producerWithSharing);
$sharedPointSale = $this->sharedPointSaleBuilder->instanciateSharedPointSale($pointSale, $producerWithSharing, $createdBy);
$this->sharedPointSaleBuilder->create($sharedPointSale);
return $sharedPointSale;
}

public function confirmSharedPointSale(SharedPointSale $sharedPointSale, PointSale $pointSaleWithSharing, User $confirmedBy): bool
{
$this->sharedPointSaleBuilder->initConfirmSharedPointSale($sharedPointSale, $pointSaleWithSharing, $confirmedBy);
return $this->sharedPointSaleBuilder->update($sharedPointSale);
}

public function declineSharedPointSale(SharedPointSale $sharedPointSale, User $declinedBy): bool
{
$this->sharedPointSaleBuilder->initDeclineSharedPointSale($sharedPointSale, $declinedBy);
return $this->sharedPointSaleBuilder->update($sharedPointSale);
}
}

+ 12
- 0
domain/PointSale/SharedPointSale/SharedPointSaleModule.php View File

@@ -11,6 +11,8 @@ class SharedPointSaleModule extends AbstractModule
return [
SharedPointSaleDefinition::class,
SharedPointSaleBuilder::class,
SharedPointSaleRepository::class,
SharedPointSaleResolver::class,
SharedPointSaleManager::class
];
}
@@ -25,6 +27,16 @@ class SharedPointSaleModule extends AbstractModule
return SharedPointSaleBuilder::getInstance();
}

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

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

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

+ 57
- 0
domain/PointSale/SharedPointSale/SharedPointSaleRepository.php View File

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

namespace domain\PointSale\SharedPointSale;

use domain\_\AbstractRepository;
use domain\PointSale\PointSale\PointSale;

class SharedPointSaleRepository extends AbstractRepository
{
protected SharedPointSaleRepositoryQuery $sharedPointSaleRepositoryQuery;

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

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

public function findOneSharedPointSaleById(int $id)
{
return $this->createQuery()
->filterById($id)
->findOne();
}

public function findSharedPointsSaleRequestsOfMe()
{
return $this->createQuery()
->filterByProducerOfPointSale($this->getProducerContext())
->filterIsRequest()
->find();
}

public function findSharedPointsSaleRequestsOthers()
{
return $this->createQuery()
->filterByProducerWithSharing($this->getProducerContext())
->filterIsRequest()
->find();
}

public function findSharedPointsSaleConfirmedByPointSale(PointSale $pointSale)
{
return $this->createQuery()
->filterByPointSale($pointSale)
->filterIsConfirmed()
->find();
}
}

+ 63
- 0
domain/PointSale/SharedPointSale/SharedPointSaleRepositoryQuery.php View File

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

namespace domain\PointSale\SharedPointSale;

use domain\_\AbstractRepositoryQuery;
use domain\_\StatusInterface;
use domain\PointSale\PointSale\PointSale;
use domain\Producer\Producer\Producer;

class SharedPointSaleRepositoryQuery extends AbstractRepositoryQuery
{
protected SharedPointSaleDefinition $sharedPointSaleDefinition;

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

public function filterIsStatusOnline()
{
$this->andWhere(['shared_point_sale.status' => StatusInterface::STATUS_ONLINE]);
return $this;
}

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

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

public function filterByPointSale(PointSale $pointSale)
{
$this->andWhere('id_point_sale = :id_point_sale OR id_point_sale_with_sharing = :id_point_sale')
->addParams(['id_point_sale' => $pointSale->id]);
return $this;
}

public function filterIsRequest()
{
$this->filterIsPointSaleWithSharingIsNull()
->filterIsStatusOnline();
return $this;
}

public function filterIsConfirmed()
{
$this->filterIsStatusOnline();
$this->andWhere('id_point_sale_with_sharing IS NOT NULL AND confirmed_at IS NOT NULL');
return $this;
}

public function filterIsPointSaleWithSharingIsNull(): self
{
$this->andWhere('id_point_sale_with_sharing IS NULL');
return $this;
}
}

+ 119
- 0
domain/PointSale/SharedPointSale/SharedPointSaleResolver.php View File

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

namespace domain\PointSale\SharedPointSale;

use common\helpers\GlobalParam;
use domain\_\AbstractResolver;
use domain\Distribution\Distribution\Distribution;
use domain\Distribution\Distribution\DistributionRepository;
use domain\Distribution\PointSaleDistribution\PointSaleDistributionRepository;
use domain\PointSale\PointSale\PointSale;
use domain\PointSale\PointSale\PointSaleRepository;
use yii\helpers\Html;

class SharedPointSaleResolver extends AbstractResolver
{
protected PointSaleRepository $pointSaleRepository;
protected SharedPointSaleRepository $sharedPointSaleRepository;
protected PointSaleDistributionRepository $pointSaleDistributionRepository;
protected DistributionRepository $distributionRepository;

public function loadDependencies(): void
{
$this->pointSaleRepository = $this->loadService(PointSaleRepository::class);
$this->sharedPointSaleRepository = $this->loadService(SharedPointSaleRepository::class);
$this->distributionRepository = $this->loadService(DistributionRepository::class);
$this->pointSaleDistributionRepository = $this->loadService(PointSaleDistributionRepository::class);
}

public function getPointsSaleSharedWithPointSale(PointSale $pointSale, Distribution $distribution = null, array &$pointsSaleSharedWithPointSaleArray = []): array
{
$idProducerContext = $this->getProducerContextId();
$sharedPointsSaleConfirmedArray = $this->sharedPointSaleRepository->findSharedPointsSaleConfirmedByPointSale($pointSale);

foreach($sharedPointsSaleConfirmedArray as $sharedPointSaleConfirmed) {
if ($sharedPointSaleConfirmed->getPointSale()->id != $pointSale->id
&& !in_array($sharedPointSaleConfirmed->getPointSale(), $pointsSaleSharedWithPointSaleArray)
&& $sharedPointSaleConfirmed->getPointSale()->getProducer()->id != $idProducerContext) {

$distributionProducer = null;
if($distribution) {
$distributionProducer = $this->distributionRepository
->setProducerContext($sharedPointSaleConfirmed->getPointSale()->getProducer())
->findOneDistribution($distribution->date, true);
}

if(!$distribution || ($distributionProducer && $this->pointSaleDistributionRepository->findOnePointSaleDistribution($distributionProducer, $sharedPointSaleConfirmed->getPointSale(), true))) {
$pointsSaleSharedWithPointSaleArray[] = $sharedPointSaleConfirmed->getPointSale();
$this->getPointsSaleSharedWithPointSale($sharedPointSaleConfirmed->getPointSale(), $distribution, $pointsSaleSharedWithPointSaleArray);
}
}
if ($sharedPointSaleConfirmed->getPointSaleWithSharing()->id != $pointSale->id
&& !in_array($sharedPointSaleConfirmed->getPointSaleWithSharing(), $pointsSaleSharedWithPointSaleArray)
&& $sharedPointSaleConfirmed->getProducerWithSharing()->id != $idProducerContext) {

$distributionProducer = null;
if($distribution) {
$distributionProducer = $this->distributionRepository
->setProducerContext($sharedPointSaleConfirmed->getProducerWithSharing())
->findOneDistribution($distribution->date, true);
}

if(!$distribution || ($distributionProducer && $this->pointSaleDistributionRepository->findOnePointSaleDistribution($distributionProducer, $sharedPointSaleConfirmed->getPointSaleWithSharing(), true))) {
$pointsSaleSharedWithPointSaleArray[] = $sharedPointSaleConfirmed->getPointSaleWithSharing();
$this->getPointsSaleSharedWithPointSale($sharedPointSaleConfirmed->getPointSaleWithSharing(), $distribution, $pointsSaleSharedWithPointSaleArray);
}
}
}

return array_unique($pointsSaleSharedWithPointSaleArray, SORT_REGULAR);
}

public function getProducersSharingPointSaleAsString(PointSale $pointSale, Distribution $distribution = null, string $separator = ', ', bool $withLink = false): string
{
$pointsSaleSharedWithPointSaleArray = $this->getPointsSaleSharedWithPointSale($pointSale, $distribution);
return implode($separator, array_map(
function($pointSale) use ($withLink) {
$return = '';
if($withLink) {
$return .= '<a href="'.\Yii::$app->urlManagerProducer->createUrl(['site/index', 'slug_producer' => $pointSale->getProducer()->slug]).'">';
}
$return .= $pointSale->getProducer()->getName();
if($withLink) {
$return .= '</a>';
}
return $return;
},
$pointsSaleSharedWithPointSaleArray)
);
}

public function countPointsSaleSharedWithPointSale(PointSale $pointSale): int
{
return count($this->getPointsSaleSharedWithPointSale($pointSale));
}

public function hasPointSaleSharedWithPointSale(PointSale $pointSale): bool
{
return (bool) $this->countPointsSaleSharedWithPointSale($pointSale);
}

public function countPointsSaleShared(): int
{
$count = 0;
$pointsSaleArray = $this->pointSaleRepository->findPointSales();

foreach($pointsSaleArray as $pointSale) {
if($this->hasPointSaleSharedWithPointSale($pointSale)) {
$count ++;
}
}

return $count;
}

public function countSharedPointsSaleRequestsOthers(): int
{
return count($this->sharedPointSaleRepository->findSharedPointsSaleRequestsOthers());
}
}

+ 5
- 0
domain/Producer/Producer/Producer.php View File

@@ -545,6 +545,11 @@ class Producer extends ActiveRecordCommon
];
}

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

/*
* Relations
*/

+ 16
- 13
domain/Producer/Producer/ProducerRepository.php View File

@@ -77,8 +77,9 @@ class ProducerRepository extends AbstractRepository
/**
* Retourne la liste des établissements pour l'initialisation d'une listesélective.
*/
public function populateProducerDropdown(): array
public function populateProducerDropdown(bool $excludeProducerContext = false): array
{
$producerContext = $this->getProducerContext(false);
$producers = $this->createQuery()
->filterIsActive()
->orderBy('postcode, city ASC')
@@ -89,20 +90,22 @@ class ProducerRepository extends AbstractRepository
$optionsProducers = [];

foreach ($producers as $p) {
$departmentCode = substr($p->postcode, 0, 2);
if (!key_exists('d' . $departmentCode, $dataProducers) && isset($departments[$departmentCode])) {
$dataProducers['d' . $departmentCode] = '<strong>' . $departments[$departmentCode] . '</strong>';
$optionsProducers['d' . $departmentCode] = ['disabled' => true];
}
if($excludeProducerContext && $producerContext && $producerContext->id != $p->id || !$excludeProducerContext) {
$departmentCode = substr($p->postcode, 0, 2);
if (!key_exists('d' . $departmentCode, $dataProducers) && isset($departments[$departmentCode])) {
$dataProducers['d' . $departmentCode] = '<strong>' . $departments[$departmentCode] . '</strong>';
$optionsProducers['d' . $departmentCode] = ['disabled' => true];
}

$dataProducers[$p->id] = '<span class="glyphicon glyphicon-lock"></span> ' . Html::encode(
$p->name
) . ' - ' . Html::encode($p->postcode) . ' ' . Html::encode(
$p->city
) . ' <span class="glyphicon glyphicon-lock"></span>';
$dataProducers[$p->id] = '<span class="glyphicon glyphicon-lock"></span> ' . Html::encode(
$p->name
) . ' - ' . Html::encode($p->postcode) . ' ' . Html::encode(
$p->city
) . ' <span class="glyphicon glyphicon-lock"></span>';

if (strlen($p->code)) {
$optionsProducers[$p->id] = ['class' => 'lock'];
if (strlen($p->code)) {
$optionsProducers[$p->id] = ['class' => 'lock'];
}
}
}


+ 1
- 1
frontend/views/site/index.php View File

@@ -43,7 +43,7 @@ use yii\helpers\Html;
$userProducerModule = UserProducerModule::getInstance();
$userCurrent = GlobalParam::getCurrentUser();

$this->setTitle('Passez commande auprès de producteurs locaux') ;
$this->setTitle('Passer commande auprès de producteurs locaux') ;
$this->setMeta('description', 'Trouvez des producteurs proches de chez vous et passez commande pour un jour et un lieu donné.') ;

?>

+ 8
- 1
producer/controllers/OrderController.php View File

@@ -43,6 +43,7 @@ use common\helpers\Image;
use common\helpers\Password;
use domain\Config\Unit\UnitDefinition;
use domain\Distribution\Distribution\Distribution;
use domain\Feature\Feature\Feature;
use domain\Order\Order\Order;
use domain\Order\Order\OrderRepositoryQuery;
use domain\Order\OrderStatus\OrderStatus;
@@ -805,7 +806,7 @@ class OrderController extends ProducerBaseController
return $jsonUser;
}

private function ajaxInfosPointsSale($producer, $distribution = false)
private function ajaxInfosPointsSale($producer, $distribution = null)
{
$pointSaleModule = $this->getPointSaleModule();
$producerModule = $this->getProducerModule();
@@ -876,6 +877,12 @@ class OrderController extends ProducerBaseController
$pointSale['infos'] = $pointSaleModule->getSolver()->getStrInfosByDistribution($pointSaleObject, $distribution);
}

$pointSale['producers_sharing_point_sale_as_string'] = false;
if($this->getFeatureModule()->getChecker()->isEnabled(Feature::ALIAS_SHARED_POINT_SALE)) {
$pointSale['producers_sharing_point_sale_as_string'] = $this->getSharedPointSaleModule()->getResolver()
->getProducersSharingPointSaleAsString($pointSaleObject, $distribution, ', ', true);
}

$pointSale['position'] = $position;
$position++;
}

+ 20
- 0
producer/views/order/confirm.php View File

@@ -37,9 +37,12 @@ termes.
*/

use common\helpers\GlobalParam;
use domain\Feature\Feature\Feature;
use domain\Feature\Feature\FeatureModule;
use domain\Order\Order\Order;
use domain\Order\Order\OrderModule;
use domain\PointSale\PointSale\PointSaleModule;
use domain\PointSale\SharedPointSale\SharedPointSaleModule;
use domain\Producer\Producer\ProducerModule;
use yii\helpers\Html;

@@ -47,6 +50,8 @@ $producerModule = ProducerModule::getInstance();
$orderModule = OrderModule::getInstance();
$pointSaleModule = PointSaleModule::getInstance();
$producer = GlobalParam::getCurrentProducer() ;
$featureModule = FeatureModule::getInstance();
$sharedPointSaleModule = SharedPointSaleModule::getInstance();

$this->setPageTitle('Confirmation de commande');

@@ -75,6 +80,21 @@ $this->setPageTitle('Confirmation de commande');
</div>
<?php endif; ?>

<?php if($featureModule->getChecker()->isEnabled(Feature::ALIAS_SHARED_POINT_SALE)): ?>
<?php $pointsSaleSharedWithPointSaleArray = $sharedPointSaleModule->getResolver()->getPointsSaleSharedWithPointSale($order->pointSale, $order->distribution); ?>
<?php if($pointsSaleSharedWithPointSaleArray && count($pointsSaleSharedWithPointSaleArray)): ?>
<div class="alert alert-info">
<h4 class="alert-heading">
<i class="bi bi-share"></i>
Commander chez d'autres producteurs présents à cette distribution<br />
</h4>
<?php foreach($pointsSaleSharedWithPointSaleArray as $pointSaleSharedWithPointSale): ?>
<a href="<?= Yii::$app->urlManagerProducer->createAbsoluteUrl(['order/order', 'date' => date('Y-m-d', strtotime($order->distribution->date)), 'idPointSale' => $pointSaleSharedWithPointSale->id, 'slug_producer' => $pointSaleSharedWithPointSale->getProducer()->slug]) ?>"><?= Html::encode($pointSaleSharedWithPointSale->getProducer()->getName()) ?></a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php endif; ?>

<div class="alert alert-info alert-order-summary">
<h4 class="alert-heading">
<i class="bi bi-list-check"></i>

+ 4
- 1
producer/views/order/order.php View File

@@ -233,7 +233,7 @@ $this->setMeta('description', $producerModule->getSeoGenerator()->generateMetaDe
<table id="points-sale" class="table table-striped" v-if="pointsSale.length">
<thead>
<tr>
<th>Point de vente</th>
<th><?= $producerModule->getPointSaleWording($producer); ?></th>
<th class="column-locality">Localité</th>
<th></th>
</tr>
@@ -253,6 +253,9 @@ $this->setMeta('description', $producerModule->getSeoGenerator()->generateMetaDe
<div class="minimum-order-amount" v-if="pointSale.minimum_order_amount">
Montant minimum de commande : {{ formatPrice(pointSale.minimum_order_amount) }}
</div>
<div class="shared-point-sale-producers" v-if="pointSale.producers_sharing_point_sale_as_string">
Autres producteurs présents : <span v-html="pointSale.producers_sharing_point_sale_as_string"></span>
</div>
</td>
<td class="column-locality">{{ pointSale.locality }}</td>
<td class="actions">

+ 13
- 1
producer/views/site/points-sale.php View File

@@ -40,6 +40,7 @@ use common\helpers\Image;
use common\helpers\Price;
use domain\Distribution\Distribution\DistributionModule;
use domain\Distribution\PointSaleDistribution\PointSaleDistribution;
use domain\Feature\Feature\Feature;
use domain\PointSale\PointSale\PointSaleModule;
use domain\Producer\Producer\Producer;
use domain\Producer\Producer\ProducerModule;
@@ -51,6 +52,8 @@ $productModule = ProductModule::getInstance();
$producerModule = ProducerModule::getInstance();
$distributionModule = DistributionModule::getInstance();
$pointSaleModule = PointSaleModule::getInstance();
$sharedPointSaleModule = $this->getSharedPointSaleModule();
$featureChecker = $this->getFeatureModule()->getChecker();

$producer = $this->context->getProducerCurrent();

@@ -69,11 +72,20 @@ $this->setMeta('description', $producerModule->getSeoGenerator()->generateMetaDe
'attribute' => 'name',
'format' => 'raw',
'contentOptions' => ['class' => 'name'],
'value' => function ($model) use ($pointSaleModule) {
'value' => function ($model) use ($pointSaleModule, $sharedPointSaleModule, $featureChecker) {
$html = '<span class="the-name">' . Html::encode($model->name) . '</span>';
if (strlen($model->locality)) {
$html .= '<br />' . $pointSaleModule->getSolver()->getLocalityWithAddressTooltip($model);
}

if($featureChecker->isEnabled(Feature::ALIAS_SHARED_POINT_SALE)) {
if($sharedPointSaleModule->getResolver()->countPointsSaleSharedWithPointSale($model)) {
$html .= '<div class="shared-point-sale-producers">Autres producteurs présents :<br />';
$html .= $sharedPointSaleModule->getResolver()->getProducersSharingPointSaleAsString($model, null, ', ', true);
$html .= '</div>';
}
}

return $html;
}
],

+ 49
- 42
producer/web/css/screen.css View File

@@ -575,15 +575,20 @@ termes.
.site-points-sale #points-sale .name .locality {
color: gray;
}
/* line 17, ../sass/site/_points_sale.scss */
/* line 15, ../sass/site/_points_sale.scss */
.site-points-sale #points-sale .name .shared-point-sale-producers {
color: gray;
margin-top: 10px;
}
/* line 22, ../sass/site/_points_sale.scss */
.site-points-sale #points-sale .days .block-day:not(:last-child) {
margin-bottom: 15px;
}
/* line 20, ../sass/site/_points_sale.scss */
/* line 25, ../sass/site/_points_sale.scss */
.site-points-sale #points-sale .days .block-day strong {
font-family: 'worksans_medium';
}
/* line 23, ../sass/site/_points_sale.scss */
/* line 28, ../sass/site/_points_sale.scss */
.site-points-sale #points-sale .days .block-day small {
color: gray;
}
@@ -1430,46 +1435,48 @@ termes.
}
/* line 234, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.name .comment,
.order-order #main #app-order-order table#points-sale td.name .minimum-order-amount {
.order-order #main #app-order-order table#points-sale td.name .minimum-order-amount,
.order-order #main #app-order-order table#points-sale td.name .shared-point-sale-producers {
color: gray;
}
/* line 238, ../sass/order/_order.scss */
/* line 239, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.name .comment a,
.order-order #main #app-order-order table#points-sale td.name .minimum-order-amount a {
.order-order #main #app-order-order table#points-sale td.name .minimum-order-amount a,
.order-order #main #app-order-order table#points-sale td.name .shared-point-sale-producers a {
color: #ee6f42;
}
/* line 244, ../sass/order/_order.scss */
/* line 245, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.actions {
width: 150px;
}
/* line 246, ../sass/order/_order.scss */
/* line 247, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.actions button {
width: 100%;
}
/* line 258, ../sass/order/_order.scss */
/* line 259, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products {
margin-bottom: 40px;
border-top: solid 1px #b7ab9b;
border-left: solid 1px #b7ab9b;
border-right: solid 1px #b7ab9b;
}
/* line 264, ../sass/order/_order.scss */
/* line 265, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products thead {
display: none;
}
/* line 268, ../sass/order/_order.scss */
/* line 269, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td {
border-bottom: solid 1px #b7ab9b;
border-left: 0px none;
border-right: 0px none;
}
/* line 276, ../sass/order/_order.scss */
/* line 277, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.category-closed:hover td.category-name,
.order-order #main #app-order-order table#products tr.category-open td.category-name {
padding-left: 30px;
background-color: #f4efe8;
}
/* line 283, ../sass/order/_order.scss */
/* line 284, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name {
transition: all 0.1s linear;
background-color: #f4efe8;
@@ -1481,12 +1488,12 @@ termes.
padding-top: 13px;
padding-left: 20px;
}
/* line 294, ../sass/order/_order.scss */
/* line 295, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name .bi-caret-down-fill,
.order-order #main #app-order-order table#products td.category-name .bi-caret-right-fill {
font-size: 15px;
}
/* line 299, ../sass/order/_order.scss */
/* line 300, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name span.badge {
font-family: "worksans_bold";
text-transform: uppercase;
@@ -1495,21 +1502,21 @@ termes.
position: relative;
top: -3px;
}
/* line 307, ../sass/order/_order.scss */
/* line 308, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name span.badge.bg-primary {
float: right;
top: 2px;
}
/* line 313, ../sass/order/_order.scss */
/* line 314, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name:hover {
cursor: pointer;
background-color: white;
}
/* line 320, ../sass/order/_order.scss */
/* line 321, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.photo img {
width: 75px;
}
/* line 330, ../sass/order/_order.scss */
/* line 331, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices {
margin-top: 10px;
font-size: 10px;
@@ -1517,74 +1524,74 @@ termes.
padding-bottom: 2px;
margin-bottom: 0px;
}
/* line 338, ../sass/order/_order.scss */
/* line 339, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li {
margin-bottom: 5px;
}
/* line 340, ../sass/order/_order.scss */
/* line 341, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li strong {
font-weight: bold;
}
/* line 348, ../sass/order/_order.scss */
/* line 349, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit, .order-order #main #app-order-order table#products .price-total {
width: 135px;
text-align: center;
}
/* line 352, ../sass/order/_order.scss */
/* line 353, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .price-infos, .order-order #main #app-order-order table#products .price-total .price-infos {
color: gray;
font-size: 13px;
line-height: 15px;
}
/* line 359, ../sass/order/_order.scss */
/* line 360, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.product-open td.price-total {
font-size: 1.1rem;
font-family: 'worksans_bold';
padding-top: 19px;
}
/* line 365, ../sass/order/_order.scss */
/* line 366, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity {
width: 175px;
}
/* line 368, ../sass/order/_order.scss */
/* line 369, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity input.quantity,
.order-order #main #app-order-order table#products .td-quantity .input-group-text {
background-color: white;
}
/* line 373, ../sass/order/_order.scss */
/* line 374, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity input.quantity {
text-align: center;
border: 0px none;
}
/* line 377, ../sass/order/_order.scss */
/* line 378, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity .input-group-text {
border: 0px none;
padding-right: 10px;
padding-left: 0px;
margin: 0px;
}
/* line 385, ../sass/order/_order.scss */
/* line 386, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity .input-group-btn button {
padding: 4px 5px 0px 5px;
}
/* line 387, ../sass/order/_order.scss */
/* line 388, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity .input-group-btn button .bi {
font-size: 1.5em;
font-weight: bold;
margin: 0px;
}
/* line 398, ../sass/order/_order.scss */
/* line 399, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary {
padding: 25px;
}
/* line 401, ../sass/order/_order.scss */
/* line 402, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary h3 {
font-family: 'worksans_bold';
margin-top: 0px;
text-transform: uppercase;
margin-bottom: 5px;
}
/* line 408, ../sass/order/_order.scss */
/* line 409, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul {
margin-bottom: 15px;
padding-left: 20px;
@@ -1592,17 +1599,17 @@ termes.
line-height: 1.4rem;
list-style-type: disc;
}
/* line 416, ../sass/order/_order.scss */
/* line 417, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul li .quantity {
font-weight: bold;
}
/* line 423, ../sass/order/_order.scss */
/* line 424, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .price-total {
padding-top: 25px;
font-size: 1.5rem;
font-family: 'worksans_bold';
}
/* line 428, ../sass/order/_order.scss */
/* line 429, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .price-total span {
display: inline-block;
padding: 7px 15px;
@@ -1612,30 +1619,30 @@ termes.
color: white;
font-size: 1.2rem;
}
/* line 440, ../sass/order/_order.scss */
/* line 441, ../sass/order/_order.scss */
.order-order #main #app-order-order #payment-methods .infos {
margin-top: 10px;
color: gray;
}
/* line 447, ../sass/order/_order.scss */
/* line 448, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .delivery {
margin-bottom: 20px;
}
/* line 451, ../sass/order/_order.scss */
/* line 452, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .comment {
margin-bottom: 20px;
}
/* line 455, ../sass/order/_order.scss */
/* line 456, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment #payment-methods {
margin-bottom: 20px;
}
/* line 460, ../sass/order/_order.scss */
/* line 461, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .credit .info {
margin-left: 20px;
color: gray;
}

/* line 473, ../sass/order/_order.scss */
/* line 474, ../sass/order/_order.scss */
#main #content .panel h3 {
font-family: "worksans_bold";
margin: 0px;

+ 2
- 1
producer/web/sass/order/_order.scss View File

@@ -232,7 +232,8 @@
}

.comment,
.minimum-order-amount {
.minimum-order-amount,
.shared-point-sale-producers{
color: gray;

a {

+ 5
- 0
producer/web/sass/site/_points_sale.scss View File

@@ -11,6 +11,11 @@
.locality {
color: gray;
}

.shared-point-sale-producers {
color: gray;
margin-top: 10px;
}
}
.days {
.block-day {

Loading…
Cancel
Save