Browse Source

Merge branch 'develop'

master
Guillaume Bourgeois 1 year ago
parent
commit
fce8e45b06
40 changed files with 717 additions and 432 deletions
  1. +7
    -3
      backend/controllers/DistributionController.php
  2. +1
    -1
      backend/controllers/PointSaleController.php
  3. +13
    -0
      backend/controllers/ProducerAdminController.php
  4. +2
    -0
      backend/controllers/UserController.php
  5. +9
    -0
      backend/views/delivery-note/index.php
  6. +16
    -8
      backend/views/distribution/index.php
  7. +12
    -0
      backend/views/invoice/index.php
  8. +152
    -139
      backend/views/point-sale/index.php
  9. +10
    -49
      backend/views/producer-admin/billing.php
  10. +11
    -1
      backend/views/producer-admin/index.php
  11. +9
    -0
      backend/views/quotation/index.php
  12. +17
    -4
      backend/views/subscription/index.php
  13. +62
    -55
      backend/views/user/_form.php
  14. +9
    -1
      backend/views/user/index.php
  15. +1
    -0
      backend/views/user/update.php
  16. +54
    -38
      backend/web/css/screen.css
  17. +5
    -1
      backend/web/js/backend.js
  18. +52
    -9
      backend/web/js/vuejs/distribution-index.js
  19. +13
    -9
      backend/web/js/vuejs/document-form.js
  20. +16
    -0
      backend/web/sass/distribution/_index.scss
  21. +4
    -1
      common/assets/CommonAsset.php
  22. +1
    -1
      common/config/params.php
  23. +15
    -6
      common/logic/Distribution/Distribution/Repository/DistributionRepository.php
  24. +2
    -2
      common/logic/Distribution/Distribution/Service/DistributionBuilder.php
  25. +22
    -27
      common/logic/Order/Order/Service/OrderBuilder.php
  26. +13
    -0
      common/logic/PointSale/PointSale/Repository/PointSaleRepository.php
  27. +7
    -0
      common/logic/PointSale/PointSale/Service/PointSaleSolver.php
  28. +15
    -4
      common/logic/Producer/Producer/Repository/ProducerRepository.php
  29. +38
    -6
      common/logic/Product/Product/Service/ProductSolver.php
  30. +1
    -1
      common/versions/23.4.A.php
  31. +24
    -0
      common/versions/23.6.B.php
  32. +2
    -0
      common/web/js/vuejs/vcalendar/v-calendar.umd.min.js
  33. +10
    -11
      producer/controllers/OrderController.php
  34. +15
    -3
      producer/controllers/SiteController.php
  35. +6
    -0
      producer/controllers/SubscriptionController.php
  36. +6
    -5
      producer/views/order/order.php
  37. +38
    -33
      producer/web/css/screen.css
  38. +13
    -10
      producer/web/js/vuejs/order-order.js
  39. +9
    -4
      producer/web/js/vuejs/subscription-form.js
  40. +5
    -0
      producer/web/sass/order/_order.scss

+ 7
- 3
backend/controllers/DistributionController.php View File

{ {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$userManager = $this->getUserManager(); $userManager = $this->getUserManager();

$user = $userManager->findOneUserById($idUser); $user = $userManager->findOneUserById($idUser);
$favoritePointSale = $userManager->getUserFavoritePointSale($user);
$idFavoritePointSale = 0; $idFavoritePointSale = 0;
if ($favoritePointSale) {
$idFavoritePointSale = $favoritePointSale->id;

if($user) {
$favoritePointSale = $userManager->getUserFavoritePointSale($user);
if ($favoritePointSale) {
$idFavoritePointSale = $favoritePointSale->id;
}
} }


return [ return [

+ 1
- 1
backend/controllers/PointSaleController.php View File

UserPointSale::deleteAll(['id_point_sale' => $id]); UserPointSale::deleteAll(['id_point_sale' => $id]);


// Suppression du lien PointSaleDistribution pour toutes les distributions à venir // Suppression du lien PointSaleDistribution pour toutes les distributions à venir
$incomingDistributions = $distributionManager->findDistributionsIncoming();
$incomingDistributions = $distributionManager->findDistributionsIncoming(true);
foreach ($incomingDistributions as $distribution) { foreach ($incomingDistributions as $distribution) {
PointSaleDistribution::deleteAll(['id_point_sale' => $id, 'id_distribution' => $distribution->id]); PointSaleDistribution::deleteAll(['id_point_sale' => $id, 'id_distribution' => $distribution->id]);
} }

+ 13
- 0
backend/controllers/ProducerAdminController.php View File

} }
} }


/**
* Facturation producteur.
*/
public function actionBilling(int $id)
{
$producerManager = $this->getProducerManager();
$producer = $this->findModel($id);

return $this->render('billing', [
'producer' => $producer,
]);
}

public function actionUserTransfer($fromProducerId, $toProducerId, $withOrders = 1) public function actionUserTransfer($fromProducerId, $toProducerId, $withOrders = 1)
{ {
$producerManager = $this->getProducerManager(); $producerManager = $this->getProducerManager();

+ 2
- 0
backend/controllers/UserController.php View File

{ {
$userManager = $this->getUserManager(); $userManager = $this->getUserManager();
$producerManager = $this->getProducerManager(); $producerManager = $this->getProducerManager();
$pointSaleManager = $this->getPointSaleManager();


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




return $this->render('update', array_merge($this->initForm($model), [ return $this->render('update', array_merge($this->initForm($model), [
'model' => $model, 'model' => $model,
'pointSaleBillingArray' => $pointSaleManager->findByBillingUser($model)
])); ]));
} }



+ 9
- 0
backend/views/delivery-note/index.php View File

], ],
[ [
'attribute' => 'reference', 'attribute' => 'reference',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) { 'value' => function ($model) {
return (strlen($model->reference) > 0) ? $model->reference : ''; return (strlen($model->reference) > 0) ? $model->reference : '';
} }
'attribute' => 'date_distribution', 'attribute' => 'date_distribution',
'options' => ['class' => 'form-control'] 'options' => ['class' => 'form-control']
]), ]),
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) use ($deliveryNoteManager) { 'value' => function ($model) use ($deliveryNoteManager) {
$distribution = $deliveryNoteManager->getDistribution($model); $distribution = $deliveryNoteManager->getDistribution($model);
return $distribution ? date('d/m/Y', strtotime($distribution->date)) : ''; return $distribution ? date('d/m/Y', strtotime($distribution->date)) : '';
'header' => 'Point de vente', 'header' => 'Point de vente',
'filter' => ArrayHelper::map(PointSale::searchAll([], ['as_array' => true]), 'id', 'name'), 'filter' => ArrayHelper::map(PointSale::searchAll([], ['as_array' => true]), 'id', 'name'),
'format' => 'html', 'format' => 'html',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) use ($deliveryNoteManager) { 'value' => function ($model) use ($deliveryNoteManager) {
$pointSale = $deliveryNoteManager->getPointSale($model); $pointSale = $deliveryNoteManager->getPointSale($model);
return $pointSale ? Html::encode($pointSale->name) : ''; return $pointSale ? Html::encode($pointSale->name) : '';

+ 16
- 8
backend/views/distribution/index.php View File

<div id="wrapper-app-distribution-index" :class="'wrapper-app-vuejs '+(loading ? '' : 'loaded')"> <div id="wrapper-app-distribution-index" :class="'wrapper-app-vuejs '+(loading ? '' : 'loaded')">
<div class="col-md-4"> <div class="col-md-4">
<div id="calendar"> <div id="calendar">
<v-date-picker
<v-calendar
is-inline is-inline
is-expanded is-expanded
v-model="date" v-model="date"
popover-visibility="hidden" popover-visibility="hidden"
firstDayOfWeek="1"
color="green"
:mode="calendar.mode" :mode="calendar.mode"
:formats="calendar.formats" :formats="calendar.formats"
:theme-styles="calendar.themeStyles" :theme-styles="calendar.themeStyles"
:attributes="calendar.attrs" :attributes="calendar.attrs"
@dayclick='dayClicked'> @dayclick='dayClicked'>
></v-date-picker>
></v-calendar>
</div> </div>
<div class="clr"></div> <div class="clr"></div>
</div> </div>
<span class="info-box-icon bg-yellow"><i class="fa fa-clone"></i></span> <span class="info-box-icon bg-yellow"><i class="fa fa-clone"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text"> <span class="info-box-text">
{{ countActiveProducts }} Produits<br /><br />
{{ countActiveProducts }} Produits<br />
<template v-if="isOneProductMaximumQuantityExceeded()"><span class="glyphicon glyphicon-alert"></span> Quantités max dépassées<br /></template>
<br />
<button class="btn btn-default" @click="showModalProducts = true">Configurer</button> <button class="btn btn-default" @click="showModalProducts = true">Configurer</button>
</span> </span>
</div> </div>
<button class="btn btn-default" v-else data-active-product="0" :data-id-product="product.id" @click="productActiveClick"><span class="glyphicon glyphicon-remove"></span></button> <button class="btn btn-default" v-else data-active-product="0" :data-id-product="product.id" @click="productActiveClick"><span class="glyphicon glyphicon-remove"></span></button>
</td> </td>
<td>{{ product.name }}</td> <td>{{ product.name }}</td>
<td class="quantity-ordered">{{ product.quantity_ordered ? product.quantity_ordered + ' '+ ((product.unit == 'piece') ? ' p.' : ' '+(product.unit == 'g' || product.unit == 'kg') ? 'kg' : 'litre(s)') : '&empty;' }}</td>
<td class="quantity-ordered">
<span v-if="isProductMaximumQuantityExceeded(product)" class="glyphicon glyphicon-alert"></span>
{{ product.quantity_ordered ? product.quantity_ordered + ' '+ ((product.unit == 'piece') ? ' p.' : ' '+(product.unit == 'g' || product.unit == 'kg') ? 'kg' : 'litre(s)') : '&empty;' }}
</td>
<td class="quantity-max"> <td class="quantity-max">
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control quantity-max" placeholder="&infin;" :data-id-product="product.id" v-model="product.productDistribution[0].quantity_max" @keyup="productQuantityMaxChange" /> <input type="text" class="form-control quantity-max" placeholder="&infin;" :data-id-product="product.id" v-model="product.productDistribution[0].quantity_max" @keyup="productQuantityMaxChange" />
<span class="input-group-addon">{{ (product.unit == 'piece') ? 'p.' : ' '+((product.unit == 'g' || product.unit == 'kg') ? 'kg' : 'litre(s)') }}</span> <span class="input-group-addon">{{ (product.unit == 'piece') ? 'p.' : ' '+((product.unit == 'g' || product.unit == 'kg') ? 'kg' : 'litre(s)') }}</span>
</div> </div>

</td> </td>
</tr> </tr>
</tbody> </tbody>
<template v-else> <template v-else>
{{ order.user.lastname+' '+order.user.name }} {{ order.user.lastname+' '+order.user.name }}
</template> </template>

<span class="shortcuts btn-group" role="group">
<a class="btn btn-default btn-sm" :href="baseUrl+'/user/credit?id='+order.id_user" data-toggle="popover" data-trigger="hover" data-placement="bottom" :data-content="order.user.credit.toFixed(2)+' €'"><span class="glyphicon glyphicon-euro"></span></a>
<a class="btn btn-default btn-sm" :href="baseUrl+'/user/update?id='+order.id_user" data-toggle="popover" data-trigger="hover" data-placement="bottom" data-content="Modifier"><span class="glyphicon glyphicon-user"></span></a>
<a class="btn btn-default btn-sm" :href="baseUrl+'/user/orders?id='+order.id_user" data-toggle="popover" data-trigger="hover" data-placement="bottom" data-content="Voir les commandes"><span class="glyphicon glyphicon-eye-open"></span></a>
</span>
</span> </span>
<span v-else>{{ order.username }}</span> <span v-else>{{ order.username }}</span>
<span v-if="order.comment && order.comment.length > 0" class="glyphicon glyphicon-comment"></span> <span v-if="order.comment && order.comment.length > 0" class="glyphicon glyphicon-comment"></span>
<span :class="'info-box-icon ' +((order.user.credit > 0) ? 'bg-green' : 'bg-red')"><i class="fa fa-user"></i></span> <span :class="'info-box-icon ' +((order.user.credit > 0) ? 'bg-green' : 'bg-red')"><i class="fa fa-user"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text">Crédit utilisateur</span> <span class="info-box-text">Crédit utilisateur</span>
<span class="info-box-number">{{ order.user.credit.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}</span>
<span class="info-box-number">{{ order.user.credit.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}</span>
</div> </div>
</div> </div>



+ 12
- 0
backend/views/invoice/index.php View File

], ],
[ [
'attribute' => 'reference', 'attribute' => 'reference',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($invoice) { 'value' => function ($invoice) {
return (strlen($invoice->reference) > 0) ? $invoice->reference : ''; return (strlen($invoice->reference) > 0) ? $invoice->reference : '';
} }
[ [
'attribute' => 'username', 'attribute' => 'username',
'header' => 'Utilisateur', 'header' => 'Utilisateur',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($invoice) use ($userManager) { 'value' => function ($invoice) use ($userManager) {
return $userManager->getUsername($invoice->user); return $userManager->getUsername($invoice->user);
} }
[ [
'attribute' => 'date', 'attribute' => 'date',
'header' => 'Date', 'header' => 'Date',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($invoice) { 'value' => function ($invoice) {
return date('d/m/Y', strtotime($invoice->date)); return date('d/m/Y', strtotime($invoice->date));
} }
'attribute' => 'is_sent', 'attribute' => 'is_sent',
'header' => 'Envoyé', 'header' => 'Envoyé',
'format' => 'raw', 'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) { 'value' => function ($model) {
if ($model->is_sent) { if ($model->is_sent) {
return '<span class="label label-success">Oui</span>'; return '<span class="label label-success">Oui</span>';

+ 152
- 139
backend/views/point-sale/index.php View File

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


?> ?>


<div class="point-sale-index"> <div class="point-sale-index">
<?= GridView::widget([ <?= GridView::widget([
'filterModel' => $searchModel,
'dataProvider' => $dataProvider,
'columns' => [
[
'attribute' => 'name',
'label' => 'Nom',
'format' => 'raw',
'value' => function ($model) {
$html = '';
$html .= $model->name;
if ($model->is_bread_box) {
$html .= ' <span class="label label-default">Boîte à pain</span> ';
}
'filterModel' => $searchModel,
'dataProvider' => $dataProvider,
'columns' => [
[
'attribute' => 'name',
'label' => 'Nom',
'format' => 'raw',
'value' => function ($model) {
$html = '';
$html .= $model->name;
if ($model->is_bread_box) {
$html .= ' <span class="label label-default">Boîte à pain</span> ';
}


return $html;
}
],
'locality',
[
'attribute' => 'delivery',
'label' => 'Livraison',
'filter' => [
'monday' => 'Lundi',
'tuesday' => 'Mardi',
'wednesday' => 'Mercredi',
'thursday' => 'Jeudi',
'friday' => 'Vendredi',
'saterday' => 'Samedi',
'sunday' => 'Dimanche',
],
'value' => function ($model) use ($pointSaleManager) {
return $pointSaleManager->getStrDeliveryDays($model);
}
],
[
'attribute' => 'access_type',
'label' => 'Accès',
'filter' => [
'open' => 'Ouvert',
'code' => 'Code',
'restricted_access' => 'Accès restreint'
],
'format' => 'raw',
'value' => function ($model) {
$count = UserPointSale::find()->where(
['id_point_sale' => $model->id]
)->count();
$html = '';
if ($model->restricted_access) {
$html .= '<span class="glyphicon glyphicon-lock"></span> ';
if ($count == 1) {
$html .= '1 utilisateur';
} else {
$html .= $count . ' utilisateurs';
}
}
return $html;
}
],
[
'attribute' => 'locality',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
],
[
'attribute' => 'delivery',
'label' => 'Livraison',
'filter' => [
'monday' => 'Lundi',
'tuesday' => 'Mardi',
'wednesday' => 'Mercredi',
'thursday' => 'Jeudi',
'friday' => 'Vendredi',
'saterday' => 'Samedi',
'sunday' => 'Dimanche',
],
'value' => function ($model) use ($pointSaleManager) {
return $pointSaleManager->getStrDeliveryDays($model);
}
],
[
'attribute' => 'access_type',
'label' => 'Accès',
'filter' => [
'open' => 'Ouvert',
'code' => 'Code',
'restricted_access' => 'Accès restreint'
],
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) {
$count = UserPointSale::find()->where(
['id_point_sale' => $model->id]
)->count();
$html = '';
if ($model->restricted_access) {
$html .= '<span class="glyphicon glyphicon-lock"></span> ';
if ($count == 1) {
$html .= '1 utilisateur';
} else {
$html .= $count . ' utilisateurs';
}
}


if (strlen($model->code)) {
if (strlen($html)) {
$html .= '<br />';
}
$html .= 'Code : <strong>' . Html::encode(
$model->code
) . '</strong>';
}
if (strlen($model->code)) {
if (strlen($html)) {
$html .= '<br />';
}
$html .= 'Code : <strong>' . Html::encode(
$model->code
) . '</strong>';
}


return $html;
}
],
[
'attribute' => 'credit',
'label' => 'Crédit',
'format' => 'raw',
'value' => function ($model) {
if ($model->credit && isset(Producer::$creditFunctioningArray[$model->credit_functioning])) {
return '<span class="glyphicon glyphicon-euro"></span> ' . Producer::$creditFunctioningArray[$model->credit_functioning];
}
return $html;
}
],
[
'attribute' => 'credit',
'label' => 'Crédit',
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) {
if ($model->credit && isset(Producer::$creditFunctioningArray[$model->credit_functioning])) {
return '<span class="glyphicon glyphicon-euro"></span> ' . Producer::$creditFunctioningArray[$model->credit_functioning];
}


return '';
}
],
[
'attribute' => 'default',
'label' => 'Par défaut',
'format' => 'raw',
'contentOptions' => ['class' => 'td-default'],
'value' => function ($model) {
if ($model->default) {
return Html::a(
'<span class="glyphicon glyphicon-star"></span>',
['point-sale/default', 'id' => $model->id],
[
'title' => 'Point de vente par défaut',
'class' => 'btn btn-default'
]
);
} else {
return Html::a(
'<span class="glyphicon glyphicon-star-empty"></span>',
['point-sale/default', 'id' => $model->id],
[
'title' => 'Point de vente par défaut',
'class' => 'btn btn-default'
]
);
}
}
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{update} {delete}',
'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'],
'buttons' => [
'update' => function ($url, $model) {
return Html::a(
'<span class="glyphicon glyphicon-pencil"></span>',
$url,
[
'title' => 'Modifier',
'class' => 'btn btn-default'
]
);
},
'delete' => function ($url, $model) {
return Html::a(
'<span class="glyphicon glyphicon-trash"></span>',
$url,
[
'title' => 'Supprimer',
'class' => 'btn btn-default'
]
);
}
],
],
],
]); ?>
return '';
}
],
[
'attribute' => 'default',
'label' => 'Par défaut',
'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'td-default column-hide-on-mobile'],
'value' => function ($model) {
if ($model->default) {
return Html::a(
'<span class="glyphicon glyphicon-star"></span>',
['point-sale/default', 'id' => $model->id],
[
'title' => 'Point de vente par défaut',
'class' => 'btn btn-default'
]
);
} else {
return Html::a(
'<span class="glyphicon glyphicon-star-empty"></span>',
['point-sale/default', 'id' => $model->id],
[
'title' => 'Point de vente par défaut',
'class' => 'btn btn-default'
]
);
}
}
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{update} {delete}',
'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'],
'buttons' => [
'update' => function ($url, $model) {
return Html::a(
'<span class="glyphicon glyphicon-pencil"></span>',
$url,
[
'title' => 'Modifier',
'class' => 'btn btn-default'
]
);
},
'delete' => function ($url, $model) {
return Html::a(
'<span class="glyphicon glyphicon-trash"></span>',
$url,
[
'title' => 'Supprimer',
'class' => 'btn btn-default'
]
);
}
],
],
],
]); ?>
</div> </div>

+ 10
- 49
backend/views/producer-admin/billing.php View File

<?php <?php


/**
/**
Copyright distrib (2018) Copyright distrib (2018)


contact@opendistrib.net contact@opendistrib.net
Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 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 pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes. termes.
*/
*/


use yii\helpers\Html;
use yii\grid\GridView;
use common\models\ User ;
use common\models\Etablissement ;
use common\logic\Producer\Producer\Wrapper\ProducerManager;


$this->title = 'Facturation';
$this->params['breadcrumbs'][] = 'Administration' ;
$this->params['breadcrumbs'][] = $this->title;
$this->setTitle('Facturation producteur ('.$producer->name.')') ;
$this->addBreadcrumb(['label' => 'Producteurs', 'url' => ['index']]) ;
$this->addBreadcrumb('Facturation') ;


$producerManager = ProducerManager::getInstance();
?> ?>


<h1>Facturation</h1>

<?= GridView::widget([
'dataProvider' => $datas_factures,
'columns' => [
[
'attribute' => 'reference',
'label' => 'Référence',
],
[
'attribute' => 'id_producer',
'label' => 'Producteur',
'value' => function($model) {
return Html::encode($model->producer->name) ;
}
],
'libelle',
[
'attribute' => 'amount_ht',
'label' => 'Montant',
'value' => function($model) {
return number_format($model->amount_ht,2).' €' ;
}
],
[
'attribute' => 'paid',
'label' => 'Payé',
'format' => 'raw',
'value' => function($model) {
if($model->paid)
{
return '<span class="label label-success">Oui</span>' ;
}
else {
return '<span class="label label-danger">Non</span>' ;
}
}
]
],
]); ?>
<div class="producer-billing">
<?= $producerManager->getSummaryAmountsToBeBilled($producer, '12 derniers mois', 12, 'billing'); ?>
</div>

+ 11
- 1
backend/views/producer-admin/index.php View File

], ],
[ [
'class' => 'yii\grid\ActionColumn', 'class' => 'yii\grid\ActionColumn',
'template' => '{update}',
'template' => '{update} {billing}',
'headerOptions' => ['class' => 'column-actions'], 'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'], 'contentOptions' => ['class' => 'column-actions'],
'buttons' => [ 'buttons' => [
] ]
); );
}, },
'billing' => function ($url, $model) {
return Html::a(
'<span class="glyphicon glyphicon-euro"></span>',
$url,
[
'title' => 'Facturation',
'class' => 'btn btn-default'
]
);
},
], ],
], ],
], ],

+ 9
- 0
backend/views/quotation/index.php View File

], ],
[ [
'attribute' => 'reference', 'attribute' => 'reference',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) { 'value' => function ($model) {
return (strlen($model->reference) > 0) ? $model->reference : ''; return (strlen($model->reference) > 0) ? $model->reference : '';
} }
[ [
'attribute' => 'id_user', 'attribute' => 'id_user',
'header' => 'Utilisateur', 'header' => 'Utilisateur',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($quotation) use ($userManager) { 'value' => function ($quotation) use ($userManager) {
return $userManager->getUsername($quotation->user); return $userManager->getUsername($quotation->user);
} }
[ [
'attribute' => 'date', 'attribute' => 'date',
'header' => 'Date', 'header' => 'Date',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($quotation) { 'value' => function ($quotation) {
return date('d/m/Y', strtotime($quotation->date)); return date('d/m/Y', strtotime($quotation->date));
} }

+ 17
- 4
backend/views/subscription/index.php View File

'attribute' => 'product_name', 'attribute' => 'product_name',
'label' => 'Produits', 'label' => 'Produits',
'format' => 'raw', 'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function($model) { 'value' => function($model) {
$productManager = ProductManager::getInstance(); $productManager = ProductManager::getInstance();
$html = '' ; $html = '' ;
'attribute' => 'date_begin', 'attribute' => 'date_begin',
'label' => 'Période', 'label' => 'Période',
'format' => 'raw', 'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function($model) { 'value' => function($model) {
$html = '<small>' ; $html = '<small>' ;
if($model->date_end) { if($model->date_end) {
'saterday' => 'Samedi', 'saterday' => 'Samedi',
'sunday' => 'Dimanche', 'sunday' => 'Dimanche',
], ],
'contentOptions' => ['class' => 'text-small'],
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'text-small column-hide-on-mobile'],
'value' => function($model) { 'value' => function($model) {
$html = '' ; $html = '' ;
if($model->monday) { if($model->monday) {
1 => 'Toutes les semaines', 1 => 'Toutes les semaines',
2 => 'Toutes les 2 semaines', 2 => 'Toutes les 2 semaines',
3 => 'Toutes les 3 semaines', 3 => 'Toutes les 3 semaines',
4 => 'Tous les mois'],
4 => 'Tous les mois'
],
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function($model) { 'value' => function($model) {
if($model->week_frequency == 1) { if($model->week_frequency == 1) {
return 'Toutes les semaines' ; return 'Toutes les semaines' ;
'attribute' => 'auto_payment', 'attribute' => 'auto_payment',
'format' => 'raw', 'format' => 'raw',
'label' => 'Paiement automatique', 'label' => 'Paiement automatique',
'headerOptions' => ['class' => 'column-auto-payment'],
'contentOptions' => ['class' => 'column-auto-payment'],
'headerOptions' => ['class' => 'column-auto-payment column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-auto-payment column-hide-on-mobile'],
'filter' => [0 => 'Non', 1 => 'Oui'], 'filter' => [0 => 'Non', 1 => 'Oui'],
'value' => function($model) { 'value' => function($model) {
if($model->auto_payment) { if($model->auto_payment) {

+ 62
- 55
backend/views/user/_form.php View File



<div class="user-form" id="app-user-form"> <div class="user-form" id="app-user-form">


<div class="col-md-8">
<?php $form = ActiveForm::begin([
'enableClientValidation' => false
]); ?>
<?= $form->field($model, 'type')
->dropDownList( $userManager->getTypeChoicesArray(), [
'v-model' => 'type'
]) ; ?>
<?= $form->field($model, 'name_legal_person', ['options' => ['v-show' => "type == 'legal-person'"]])->textInput() ?>
<?= $form->field($model, 'lastname')->textInput() ?>
<?= $form->field($model, 'name')->textInput() ?>
<?= $form->field($model, 'phone')->textInput() ?>
<?= $form->field($model, 'email')->textInput() ?>
<?= $form->field($model, 'address')->textarea() ?>
<?php if($producerManager->getConfig('option_export_evoliz')): ?>
<?= $form->field($model, 'evoliz_code')->textInput() ?>
<?php endif; ?>
<?= $form->field($model, 'points_sale')->checkboxlist(
ArrayHelper::map($pointsSaleArray, 'id', function ($pointSale) use ($model) {
$commentUserPointSale = isset($pointSale->userPointSale[0]) ? $pointSale->userPointSale[0]->comment : '';
$html = Html::encode($pointSale->name);
if ($pointSale->restricted_access) {
$html .= '<input type="text" placeholder="Commentaire" class="form-control" name="User[comment_point_sale_' . $pointSale->id . ']" value="' . (($model->id) ? Html::encode($commentUserPointSale) : '') . '" />';
}
return $html;
}), [
'encode' => false
]);
?>
<?= $form->field($model, 'user_groups')->checkboxlist(
ArrayHelper::map($userGroupsArray, 'id', function ($userGroup) use ($model) {
return Html::encode($userGroup->name);
}), [
'encode' => false
]);
?>
<?php /* $form->field($model, 'product_price_percent')
<div class="col-md-8">
<?php $form = ActiveForm::begin([
'enableClientValidation' => false
]); ?>
<?= $form->field($model, 'type')
->dropDownList($userManager->getTypeChoicesArray(), [
'v-model' => 'type'
]); ?>
<?= $form->field($model, 'name_legal_person', ['options' => ['v-show' => "type == 'legal-person'"]])->textInput() ?>
<?= $form->field($model, 'lastname')->textInput() ?>
<?= $form->field($model, 'name')->textInput() ?>
<?= $form->field($model, 'phone')->textInput() ?>
<?= $form->field($model, 'email')->textInput() ?>
<?= $form->field($model, 'address')->textarea() ?>
<?php if ($producerManager->getConfig('option_export_evoliz')): ?>
<?= $form->field($model, 'evoliz_code')->textInput() ?>
<?php endif; ?>
<?= $form->field($model, 'points_sale')->checkboxlist(
ArrayHelper::map($pointsSaleArray, 'id', function ($pointSale) use ($model) {
$commentUserPointSale = isset($pointSale->userPointSale[0]) ? $pointSale->userPointSale[0]->comment : '';
$html = Html::encode($pointSale->name);
if ($pointSale->restricted_access) {
$html .= '<input type="text" placeholder="Commentaire" class="form-control" name="User[comment_point_sale_' . $pointSale->id . ']" value="' . (($model->id) ? Html::encode($commentUserPointSale) : '') . '" />';
}
return $html;
}), [
'encode' => false
]);
?>
<?= $form->field($model, 'user_groups')->checkboxlist(
ArrayHelper::map($userGroupsArray, 'id', function ($userGroup) use ($model) {
return Html::encode($userGroup->name);
}), [
'encode' => false
]);
?>
<?php /* $form->field($model, 'product_price_percent')
->dropDownList( ProductPrice::percentValues(), [])->hint('Pourcentage appliqué aux prix de chaque produit pour cet utilisateur.');*/ ?> ->dropDownList( ProductPrice::percentValues(), [])->hint('Pourcentage appliqué aux prix de chaque produit pour cet utilisateur.');*/ ?>


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

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


<div class="col-md-4">
<h2>Mot de passe</h2>
<?php $form = ActiveForm::begin(); ?>
<div class="form-group">
<?= Html::submitButton('Envoyer un nouveau mot de passe', ['class' => 'btn btn-primary', 'name' => 'submit_new_password', 'value' => 1]) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
<?php ActiveForm::end(); ?>
</div>

<div class="col-md-4">


<?php if($pointSaleBillingArray && count($pointSaleBillingArray) > 0): ?>
<h3>Facturation</h3>
<?php foreach($pointSaleBillingArray as $pointSale): ?>
<a href="<?= Yii::$app->urlManager->createUrl(['point-sale/update', 'id' => $pointSale->id]) ?>"><?= $pointSale->name ?></a><br />
<?php endforeach; ?>
<?php endif; ?>

<h3>Mot de passe</h3>
<?php $form = ActiveForm::begin(); ?>
<div class="form-group">
<?= Html::submitButton('Envoyer un nouveau mot de passe', ['class' => 'btn btn-primary', 'name' => 'submit_new_password', 'value' => 1]) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div> </div>

+ 9
- 1
backend/views/user/index.php View File

[ [
'attribute' => 'type', 'attribute' => 'type',
'label' => 'Type', 'label' => 'Type',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) { 'value' => function ($model) {
$userManager = UserManager::getInstance(); $userManager = UserManager::getInstance();
$typeArray = $userManager->getTypeChoicesArray(); $typeArray = $userManager->getTypeChoicesArray();
'attribute' => 'contacts', 'attribute' => 'contacts',
'header' => 'Contacts', 'header' => 'Contacts',
'format' => 'raw', 'format' => 'raw',
'headerOptions' => ['class' => 'column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'value' => function ($model) { 'value' => function ($model) {
$html = ''; $html = '';
if (strlen($model['phone'])) { if (strlen($model['phone'])) {
'class' => 'yii\grid\ActionColumn', 'class' => 'yii\grid\ActionColumn',
'header' => 'Commandes', 'header' => 'Commandes',
'template' => '{orders}', 'template' => '{orders}',
'headerOptions' => ['class' => 'actions'],
'headerOptions' => ['class' => 'actions column-hide-on-mobile'],
'filterOptions' => ['class' => 'column-hide-on-mobile'],
'contentOptions' => ['class' => 'column-hide-on-mobile'],
'buttons' => [ 'buttons' => [
'orders' => function ($url, $model) { 'orders' => function ($url, $model) {
$url = Yii::$app->urlManager->createUrl(['user/orders', 'id' => $model['id']]); $url = Yii::$app->urlManager->createUrl(['user/orders', 'id' => $model['id']]);

+ 1
- 0
backend/views/user/update.php View File

'model' => $model, 'model' => $model,
'pointsSaleArray' => $pointsSaleArray, 'pointsSaleArray' => $pointsSaleArray,
'userGroupsArray' => $userGroupsArray, 'userGroupsArray' => $userGroupsArray,
'pointSaleBillingArray' => $pointSaleBillingArray
]) ?> ]) ?>
</div> </div>

+ 54
- 38
backend/web/css/screen.css View File

text-transform: uppercase; text-transform: uppercase;
} }
/* line 257, ../sass/distribution/_index.scss */ /* line 257, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-user {
position: relative;
}
/* line 260, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-user:hover .shortcuts {
display: block;
}
/* line 264, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-user .shortcuts {
display: none;
float: right;
position: absolute;
top: 1px;
right: 1px;
}
/* line 273, ../sass/distribution/_index.scss */
.distribution-index #orders table td.tiller { .distribution-index #orders table td.tiller {
width: 60px; width: 60px;
} }
/* line 260, ../sass/distribution/_index.scss */
/* line 276, ../sass/distribution/_index.scss */
.distribution-index #orders table td.tiller label { .distribution-index #orders table td.tiller label {
font-size: 12px; font-size: 12px;
cursor: pointer; cursor: pointer;
top: -2px; top: -2px;
font-weight: normal; font-weight: normal;
} }
/* line 269, ../sass/distribution/_index.scss */
/* line 285, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-actions { .distribution-index #orders table td.column-actions {
position: relative; position: relative;
text-align: right; text-align: right;
} }
/* line 273, ../sass/distribution/_index.scss */
/* line 289, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-actions .dropdown-menu { .distribution-index #orders table td.column-actions .dropdown-menu {
top: 0px; top: 0px;
right: 0px; right: 0px;
} }
/* line 278, ../sass/distribution/_index.scss */
/* line 294, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-actions .modal-form-order, .distribution-index #orders table td.column-actions .modal-form-order,
.distribution-index #orders table td.column-actions .modal-payment { .distribution-index #orders table td.column-actions .modal-payment {
text-align: left; text-align: left;
} }
/* line 283, ../sass/distribution/_index.scss */
/* line 299, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-actions .add-subscription { .distribution-index #orders table td.column-actions .add-subscription {
position: relative; position: relative;
} }
/* line 286, ../sass/distribution/_index.scss */
/* line 302, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-actions .add-subscription .glyphicon-plus { .distribution-index #orders table td.column-actions .add-subscription .glyphicon-plus {
position: absolute; position: absolute;
top: 4px; top: 4px;
right: 4px; right: 4px;
font-size: 7px; font-size: 7px;
} }
/* line 295, ../sass/distribution/_index.scss */
/* line 311, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-state-payment { .distribution-index #orders table td.column-state-payment {
width: 120px; width: 120px;
} }
/* line 299, ../sass/distribution/_index.scss */
/* line 315, ../sass/distribution/_index.scss */
.distribution-index #orders table .state-payment-mobile { .distribution-index #orders table .state-payment-mobile {
display: none; display: none;
} }
/* line 304, ../sass/distribution/_index.scss */
/* line 320, ../sass/distribution/_index.scss */
.distribution-index #orders table td.column-payment div.btn-group { .distribution-index #orders table td.column-payment div.btn-group {
width: 125px; width: 125px;
} }
/* line 310, ../sass/distribution/_index.scss */
/* line 326, ../sass/distribution/_index.scss */
.distribution-index #orders table tr.view ul { .distribution-index #orders table tr.view ul {
list-style-type: none; list-style-type: none;
margin-left: 0px; margin-left: 0px;
padding-left: 15px; padding-left: 15px;
} }
/* line 320, ../sass/distribution/_index.scss */
/* line 336, ../sass/distribution/_index.scss */
.distribution-index #orders table tr.view .comment { .distribution-index #orders table tr.view .comment {
margin-top: 20px; margin-top: 20px;
} }
/* line 324, ../sass/distribution/_index.scss */
/* line 340, ../sass/distribution/_index.scss */
.distribution-index #orders table tr.view .delivery { .distribution-index #orders table tr.view .delivery {
margin-top: 20px; margin-top: 20px;
} }
/* line 333, ../sass/distribution/_index.scss */
/* line 349, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order .modal-container { .distribution-index .modal-form-order .modal-container {
width: 100%; width: 100%;
padding: 0px; padding: 0px;
} }
/* line 337, ../sass/distribution/_index.scss */
/* line 353, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order .modal-container .modal-body { .distribution-index .modal-form-order .modal-container .modal-body {
padding-right: 15px; padding-right: 15px;
} }
/* line 340, ../sass/distribution/_index.scss */
/* line 356, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order .modal-container .modal-body table { .distribution-index .modal-form-order .modal-container .modal-body table {
margin-bottom: 150px; margin-bottom: 150px;
} }
/* line 345, ../sass/distribution/_index.scss */
/* line 361, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order .modal-container .modal-footer { .distribution-index .modal-form-order .modal-container .modal-footer {
border-top-color: #f4f4f4; border-top-color: #f4f4f4;
position: fixed; position: fixed;
text-align: center; text-align: center;
border-top: solid 1px #e0e0e0; border-top: solid 1px #e0e0e0;
} }
/* line 357, ../sass/distribution/_index.scss */
/* line 373, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order .modal-container .modal-footer .actions-form button { .distribution-index .modal-form-order .modal-container .modal-footer .actions-form button {
float: none; float: none;
} }
/* line 361, ../sass/distribution/_index.scss */
/* line 377, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order .modal-container .modal-footer .actions-form div.right { .distribution-index .modal-form-order .modal-container .modal-footer .actions-form div.right {
float: right; float: right;
} }
/* line 368, ../sass/distribution/_index.scss */
/* line 384, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order .btn-credit { .distribution-index .modal-form-order .btn-credit {
float: right; float: right;
} }
/* line 374, ../sass/distribution/_index.scss */
/* line 390, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products .product-ordered td { .distribution-index .modal-form-order table.table-products .product-ordered td {
background-color: #e9e9e9; background-color: #e9e9e9;
} }
/* line 378, ../sass/distribution/_index.scss */
/* line 394, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products .product-ordered input.input-quantity { .distribution-index .modal-form-order table.table-products .product-ordered input.input-quantity {
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
} }
/* line 384, ../sass/distribution/_index.scss */
/* line 400, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.price { .distribution-index .modal-form-order table.table-products td.price {
width: 150px; width: 150px;
} }
/* line 387, ../sass/distribution/_index.scss */
/* line 403, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.price input { .distribution-index .modal-form-order table.table-products td.price input {
text-align: center; text-align: center;
} }
/* line 391, ../sass/distribution/_index.scss */
/* line 407, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.price .input-group-addon { .distribution-index .modal-form-order table.table-products td.price .input-group-addon {
background-color: #eee; background-color: #eee;
} }
/* line 395, ../sass/distribution/_index.scss */
/* line 411, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.price .invoice-price { .distribution-index .modal-form-order table.table-products td.price .invoice-price {
margin-top: 8px; margin-top: 8px;
} }
/* line 397, ../sass/distribution/_index.scss */
/* line 413, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.price .invoice-price .label-invoice-price { .distribution-index .modal-form-order table.table-products td.price .invoice-price .label-invoice-price {
font-size: 11px; font-size: 11px;
font-weight: bold; font-weight: bold;
color: gray; color: gray;
} }
/* line 405, ../sass/distribution/_index.scss */
/* line 421, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.quantity { .distribution-index .modal-form-order table.table-products td.quantity {
width: 165px; width: 165px;
} }
/* line 408, ../sass/distribution/_index.scss */
/* line 424, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.quantity input { .distribution-index .modal-form-order table.table-products td.quantity input {
text-align: center; text-align: center;
color: black; color: black;
} }
/* line 413, ../sass/distribution/_index.scss */
/* line 429, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.quantity .form-control { .distribution-index .modal-form-order table.table-products td.quantity .form-control {
border-right: 0px none; border-right: 0px none;
padding-right: 4px; padding-right: 4px;
} }
/* line 418, ../sass/distribution/_index.scss */
/* line 434, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.quantity .input-group-addon { .distribution-index .modal-form-order table.table-products td.quantity .input-group-addon {
padding: 5px; padding: 5px;
padding-left: 0px; padding-left: 0px;
border-left: 0px none; border-left: 0px none;
border-right: 0px none; border-right: 0px none;
} }
/* line 427, ../sass/distribution/_index.scss */
/* line 443, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.quantity-remaining { .distribution-index .modal-form-order table.table-products td.quantity-remaining {
text-align: right; text-align: right;
} }
/* line 430, ../sass/distribution/_index.scss */
/* line 446, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.quantity-remaining.quantity-remaining, .distribution-index .modal-form-order table.table-products td.quantity-remaining.infinite { .distribution-index .modal-form-order table.table-products td.quantity-remaining.quantity-remaining, .distribution-index .modal-form-order table.table-products td.quantity-remaining.infinite {
color: #00A65A; color: #00A65A;
} }
/* line 434, ../sass/distribution/_index.scss */
/* line 450, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.quantity-remaining.negative { .distribution-index .modal-form-order table.table-products td.quantity-remaining.negative {
color: #DD4B39; color: #DD4B39;
} }
/* line 438, ../sass/distribution/_index.scss */
/* line 454, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order table.table-products td.quantity-remaining.infinite, .distribution-index .modal-form-order table.table-products td.quantity-remaining.empty { .distribution-index .modal-form-order table.table-products td.quantity-remaining.infinite, .distribution-index .modal-form-order table.table-products td.quantity-remaining.empty {
font-size: 18px; font-size: 18px;
} }
/* line 445, ../sass/distribution/_index.scss */
/* line 461, ../sass/distribution/_index.scss */
.distribution-index .modal-form-order .actions-form button { .distribution-index .modal-form-order .actions-form button {
margin-left: 15px; margin-left: 15px;
} }
/* line 453, ../sass/distribution/_index.scss */
/* line 469, ../sass/distribution/_index.scss */
.distribution-index .modal-payment .info-box .info-box-icon { .distribution-index .modal-payment .info-box .info-box-icon {
width: 50px; width: 50px;
} }
/* line 456, ../sass/distribution/_index.scss */
/* line 472, ../sass/distribution/_index.scss */
.distribution-index .modal-payment .info-box .info-box-icon i { .distribution-index .modal-payment .info-box .info-box-icon i {
font-size: 30px; font-size: 30px;
} }
/* line 461, ../sass/distribution/_index.scss */
/* line 477, ../sass/distribution/_index.scss */
.distribution-index .modal-payment .info-box .info-box-content { .distribution-index .modal-payment .info-box .info-box-content {
margin-left: 50px; margin-left: 50px;
} }

+ 5
- 1
backend/web/js/backend.js View File



$(document).ready(function () { $(document).ready(function () {
opendistrib_datepicker(); opendistrib_datepicker();
$('button[data-toggle=popover]').popover();
opendistrib_popover();
opendistrib_commandeauto(); opendistrib_commandeauto();
opendistrib_points_vente_acces(); opendistrib_points_vente_acces();
opendistrib_tooltip(); opendistrib_tooltip();
} }
}; };


function opendistrib_popover() {
$('button[data-toggle=popover], a[data-toggle=popover]').popover();
}

function opendistrib_select2() { function opendistrib_select2() {
$('.select2').select2({ $('.select2').select2({
width: 'resolve' width: 'resolve'

+ 52
- 9
backend/web/js/vuejs/distribution-index.js View File

if(distributions.length) { if(distributions.length) {
for(var i= 0; i < distributions.length; i++) { for(var i= 0; i < distributions.length; i++) {
app.calendar.attrs.push({ app.calendar.attrs.push({
highlight: {
backgroundColor: '#5cb85c',
},
contentStyle: {
color: 'white',
},
highlight: true,
dates: distributions[i].date dates: distributions[i].date
}) ; }) ;
} }
if(app.idOrderUpdate) { if(app.idOrderUpdate) {
app.updateOrderFromUrl(); app.updateOrderFromUrl();
} }

setTimeout("opendistrib_popover();", 500);
}) ; }) ;
}, },
initCountActiveProducts: function() { initCountActiveProducts: function() {
} }
} }
this.initCountActiveProducts() ; this.initCountActiveProducts() ;
},
isOneProductMaximumQuantityExceeded: function() {
for(var i= 0; i < this.products.length; i++) {
if(this.isProductMaximumQuantityExceeded(this.products[i])) {
return true;
}
}

return false;
},
isProductMaximumQuantityExceeded: function(product) {
return product.productDistribution[0].quantity_max
&& product.quantity_ordered
&& product.quantity_ordered > product.productDistribution[0].quantity_max;
}, },
pointSaleActiveClick: function(event) { pointSaleActiveClick: function(event) {
var idPointSale = event.currentTarget.getAttribute('data-id-point-sale') ; var idPointSale = event.currentTarget.getAttribute('data-id-point-sale') ;
}, },
activeDistribution: function(event) { activeDistribution: function(event) {
var app = this ; var app = this ;
var active = parseInt(event.currentTarget.getAttribute('data-active'));

axios.get("ajax-process-active-distribution",{params: { axios.get("ajax-process-active-distribution",{params: {
idDistribution: this.distribution.id, idDistribution: this.distribution.id,
active: event.currentTarget.getAttribute('data-active')
active: active
}}) }})
.then(function(response) { .then(function(response) {
app.init() ; app.init() ;
app.alertsActiveDistribution(active, 'Distribution');
}) ; }) ;
}, },
activeWeekDistribution: function(event) { activeWeekDistribution: function(event) {
var app = this ; var app = this ;
var active = parseInt(event.currentTarget.getAttribute('data-active'));

axios.get("ajax-process-active-week-distribution",{params: { axios.get("ajax-process-active-week-distribution",{params: {
date: this.date.getFullYear() + '-' date: this.date.getFullYear() + '-'
+ ('0' + (this.date.getMonth() +1)).slice(-2) + '-' + ('0' + (this.date.getMonth() +1)).slice(-2) + '-'
+ ('0' + this.date.getDate()).slice(-2), + ('0' + this.date.getDate()).slice(-2),
active: event.currentTarget.getAttribute('data-active')
active: active
}}) }})
.then(function(response) { .then(function(response) {
app.init() ; app.init() ;
app.alertsActiveDistribution(active, 'Semaine de distribution');
}) ; }) ;
}, },
alertsActiveDistribution: function(active, label) {
if(!active) {
appAlerts.alert(
'success',
label+' désactivée.',
) ;
appAlerts.alert(
'info',
'Pensez à bien rembourser les clients qui auraient passé commande en utilisant leur crédit.',
6000
);
}
else {
appAlerts.alert(
'success',
label+' activée.',
) ;
}
},
pointSaleClick: function(event) { pointSaleClick: function(event) {
this.setIdActivePointSale(event.currentTarget.getAttribute('data-id-point-sale')) ; this.setIdActivePointSale(event.currentTarget.getAttribute('data-id-point-sale')) ;
}, },
Vue.set(app.ordersUpdate[app.getOrderUpdateKey()], 'id_user', idUser); Vue.set(app.ordersUpdate[app.getOrderUpdateKey()], 'id_user', idUser);
} }
}); });

// Passage à la ligne du dessous quand on appuie sur "Entrée"
$('.modal-form-order .input-quantity').keypress(function(e) {
if(e.which == 13) {
$(this).parent().parent().parent()
.next().find('.input-quantity').focus();
}
});
},500); },500);
}, },
getOrderUpdateKey: function() { getOrderUpdateKey: function() {

+ 13
- 9
backend/web/js/vuejs/document-form.js View File

}, },
deleteProductOrder: function (idProductOrder) { deleteProductOrder: function (idProductOrder) {
var app = this; var app = this;
axios.get(UrlManager.getBaseUrlAbsolute() + "document/ajax-delete-product-order", {
params: {
idProductOrder: idProductOrder
}
})
.then(function (response) {
appAlerts.alertResponse(response);
app.init();
});
result = confirm("Êtes-vous sûr de vouloir supprimer ce produit ? Cela le supprimera également de la commande à laquelle il est lié.");

if(result) {
axios.get(UrlManager.getBaseUrlAbsolute() + "document/ajax-delete-product-order", {
params: {
idProductOrder: idProductOrder
}
})
.then(function (response) {
appAlerts.alertResponse(response);
app.init();
});
}
}, },
formatProductAddPrice: function () { formatProductAddPrice: function () {
this.productAddPrice = Number(this.productAddPrice).toFixed(2).replace(',', '.'); this.productAddPrice = Number(this.productAddPrice).toFixed(2).replace(',', '.');

+ 16
- 0
backend/web/sass/distribution/_index.scss View File



table { table {


td.column-user {
position: relative;

&:hover .shortcuts {
display: block;
}

.shortcuts {
display: none;
float: right;
position: absolute;
top: 1px;
right: 1px;
}
}

td.tiller { td.tiller {
width: 60px; width: 60px;



+ 4
- 1
common/assets/CommonAsset.php View File

$this->addAsset('js','js/promise-polyfill/promise.min.js'); $this->addAsset('js','js/promise-polyfill/promise.min.js');
$this->addAsset('js','js/axios/axios.min.js'); $this->addAsset('js','js/axios/axios.min.js');
$this->addAsset('js','js/vuejs/vue.js'); $this->addAsset('js','js/vuejs/vue.js');
$this->addAsset('js','js/vuejs/vcalendar/vcalendar.min.js') ;

// Documentation : https://vcalendar.io/
$this->addAsset('js','js/vuejs/vcalendar/v-calendar.umd.min.js') ;

$this->addAsset('js','js/utils.js') ; $this->addAsset('js','js/utils.js') ;
} }
} }

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

*/ */


return [ return [
'version' => '23.6.A',
'version' => '23.6.B',
'adminEmail' => 'contact@opendistrib.net', 'adminEmail' => 'contact@opendistrib.net',
'supportEmail' => 'contact@opendistrib.net', 'supportEmail' => 'contact@opendistrib.net',
'user.passwordResetTokenExpire' => 3600, 'user.passwordResetTokenExpire' => 3600,

+ 15
- 6
common/logic/Distribution/Distribution/Repository/DistributionRepository.php View File

/** /**
* Récupère les distributions futures. * Récupère les distributions futures.
*/ */
public function findDistributionsIncoming(): array
public function findDistributionsIncoming($ignoreActive = false): array
{ {
$paramsWhere = [
'id_producer' => $this->getProducerContext()->id,
];

if(!$ignoreActive) {
$paramsWhere['active'] = 1;
}

$distributionsArray = Distribution::find() $distributionsArray = Distribution::find()
->where('date > \'' . date('Y-m-d') . '\'') ->where('date > \'' . date('Y-m-d') . '\'')
->andWhere([
'id_producer' => $this->getProducerContext()->id,
'active' => 1
])
->andWhere($paramsWhere)
->orderBy('date ASC') ->orderBy('date ASC')
->all(); ->all();


* Recherche les distributions futures où l'abonnement peut s'appliquer. * Recherche les distributions futures où l'abonnement peut s'appliquer.
*/ */
// searchMatchedIncomingDistributions // searchMatchedIncomingDistributions
public function findDistributionsIncomingMatchWithSubscrtiption(Subscription $subscription): array
public function findDistributionsIncomingMatchWithSubscrtiption(Subscription $subscription, bool $filterByOrderDeadline = false): array
{ {
$params = [ $params = [
':date_earliest_order' => date('Y-m-d'), ':date_earliest_order' => date('Y-m-d'),
} }
} }


if($filterByOrderDeadline) {
$matchedIncomingDistributionsArray = $this->distributionSolver->filterDistributionsByDateDelay($matchedIncomingDistributionsArray);
}

return $matchedIncomingDistributionsArray; return $matchedIncomingDistributionsArray;
} }



+ 2
- 2
common/logic/Distribution/Distribution/Service/DistributionBuilder.php View File

*/ */
public function addProductIncomingDistributions(Product $product): void public function addProductIncomingDistributions(Product $product): void
{ {
$distributionArray = $this->distributionRepository->findDistributionsIncoming();
$distributionArray = $this->distributionRepository->findDistributionsIncoming(true);
foreach ($distributionArray as $distribution) { foreach ($distributionArray as $distribution) {
$this->addProduct($distribution, $product); $this->addProduct($distribution, $product);
} }
*/ */
public function addPointSaleIncomingDistributions(PointSale $pointSale): void public function addPointSaleIncomingDistributions(PointSale $pointSale): void
{ {
$distributionArray = $this->distributionRepository->findDistributionsIncoming();
$distributionArray = $this->distributionRepository->findDistributionsIncoming(true);
foreach ($distributionArray as $distribution) { foreach ($distributionArray as $distribution) {
$this->addPointSale($distribution, $pointSale); $this->addPointSale($distribution, $pointSale);
} }

+ 22
- 27
common/logic/Order/Order/Service/OrderBuilder.php View File

use common\logic\Config\TaxRate\Model\TaxRate; use common\logic\Config\TaxRate\Model\TaxRate;
use common\logic\Distribution\Distribution\Model\Distribution; use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Distribution\Distribution\Repository\DistributionRepository; use common\logic\Distribution\Distribution\Repository\DistributionRepository;
use common\logic\Distribution\Distribution\Service\DistributionSolver;
use common\logic\Document\Document\Model\Document; use common\logic\Document\Document\Model\Document;
use common\logic\Order\Order\Model\Order; use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Repository\OrderRepository; use common\logic\Order\Order\Repository\OrderRepository;
protected SubscriptionRepository $subscriptionRepository; protected SubscriptionRepository $subscriptionRepository;
protected SubscriptionSolver $subscriptionSolver; protected SubscriptionSolver $subscriptionSolver;
protected ProductSolver $productSolver; protected ProductSolver $productSolver;
protected DistributionSolver $distributionSolver;


public function loadDependencies(): void public function loadDependencies(): void
{ {
$this->subscriptionRepository = $this->loadService(SubscriptionRepository::class); $this->subscriptionRepository = $this->loadService(SubscriptionRepository::class);
$this->subscriptionSolver = $this->loadService(SubscriptionSolver::class); $this->subscriptionSolver = $this->loadService(SubscriptionSolver::class);
$this->productSolver = $this->loadService(ProductSolver::class); $this->productSolver = $this->loadService(ProductSolver::class);
$this->distributionSolver = $this->loadService(DistributionSolver::class);
} }


public function instanciateOrder(Distribution $distribution): Order public function instanciateOrder(Distribution $distribution): Order
public function updateOrdersIncomingDistributionsFromSubscription(Subscription $subscription, $update = false): array public function updateOrdersIncomingDistributionsFromSubscription(Subscription $subscription, $update = false): array
{ {
$orderArray = []; $orderArray = [];
$matchedDistributionsArray = $this->distributionRepository->findDistributionsIncomingMatchWithSubscrtiption($subscription);
$matchedDistributionsArray = $this->distributionRepository->findDistributionsIncomingMatchWithSubscrtiption($subscription, true);


if ($update) { if ($update) {
$this->deleteOrdersIncomingDistributionsFromSubscription($subscription); $this->deleteOrdersIncomingDistributionsFromSubscription($subscription);
':id_subscription' => $subscription->id ':id_subscription' => $subscription->id
]; ];


$orderDeadline = $this->producerRepository->getConfig('order_deadline');
$hour = date('G');

if ($hour >= $orderDeadline) {
$conditionDistributionDate = 'distribution.date > :date_today';
} else {
$conditionDistributionDate = 'distribution.date >= :date_today';
}

$orders = Order::find() $orders = Order::find()
->joinWith('distribution') ->joinWith('distribution')
->where('distribution.id_producer = :id_producer') ->where('distribution.id_producer = :id_producer')
->andWhere($conditionDistributionDate)
->andWhere('distribution.date >= :date_today')
->andWhere('distribution.date ' . $comparatorDateStart . ' :date_start') ->andWhere('distribution.date ' . $comparatorDateStart . ' :date_start')
->andWhere('order.id_subscription = :id_subscription'); ->andWhere('order.id_subscription = :id_subscription');


$countOrdersDeleted = 0; $countOrdersDeleted = 0;
if ($ordersArray && count($ordersArray)) { if ($ordersArray && count($ordersArray)) {
foreach ($ordersArray as $order) { foreach ($ordersArray as $order) {
if($this->distributionSolver->isDistributionAvailable($order->distribution)) {
$theOrder = $this->orderRepository->findOneOrderById($order->id);
$this->initOrder($theOrder);

// remboursement de la commande
if ($theOrder->id_user && $this->orderSolver->getOrderAmount($theOrder, Order::AMOUNT_PAID) && $configCredit) {

$this->creditHistoryBuilder->createCreditHistory(
CreditHistory::TYPE_REFUND,
$this->orderSolver->getOrderAmount($theOrder, Order::AMOUNT_PAID),
$theOrder->distribution->producer,
$theOrder->user,
GlobalParam::getCurrentUser()
);
}


$theOrder = $this->orderRepository->findOneOrderById($order->id);
$this->initOrder($theOrder);

// remboursement de la commande
if ($theOrder->id_user && $this->orderSolver->getOrderAmount($theOrder, Order::AMOUNT_PAID) && $configCredit) {
$this->deleteOrder($order, true);


$this->creditHistoryBuilder->createCreditHistory(
CreditHistory::TYPE_REFUND,
$this->orderSolver->getOrderAmount($theOrder, Order::AMOUNT_PAID),
$theOrder->distribution->producer,
$theOrder->user,
GlobalParam::getCurrentUser()
);
$countOrdersDeleted++;
} }

$this->deleteOrder($order, true);

$countOrdersDeleted++;
} }
} }



+ 13
- 0
common/logic/PointSale/PointSale/Repository/PointSaleRepository.php View File

use common\logic\Distribution\Distribution\Model\Distribution; use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\PointSale\PointSale\Model\PointSale; use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\Producer\Producer\Model\Producer; use common\logic\Producer\Producer\Model\Producer;
use common\logic\User\User\Model\User;


class PointSaleRepository extends AbstractRepository class PointSaleRepository extends AbstractRepository
{ {


return $pointSalesArrayDropdown; return $pointSalesArrayDropdown;
} }

public function findByBillingUser(User $user)
{
return PointSale::find()
->where([
'id_producer' => GlobalParam::getCurrentProducerId(),
'status' => 1,
'id_user' => $user->id
])->orderBy(
'name ASC'
)->all();
}
} }

+ 7
- 0
common/logic/PointSale/PointSale/Service/PointSaleSolver.php View File

return $str; return $str;
} }


public function isPublic(PointSale $pointSale): bool
{
if($pointSale->restricted_access || ($pointSale->code && strlen($pointSale->code))) {
return false;
}


return true;
}
} }

+ 15
- 4
common/logic/Producer/Producer/Repository/ProducerRepository.php View File

return $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, $format); return $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, $format);
} }


public function getSummaryAmountsToBeBilled(Producer $producer, string $label, int $numberOfMonths = 1): string
public function getSummaryAmountsToBeBilled(Producer $producer, string $label, int $numberOfMonths = 1, $context = 'list'): string
{ {
$text = ''; $text = '';
$numMonthCurrent = date('m'); $numMonthCurrent = date('m');
$sumInvoicePrice = 0;


if ($numberOfMonths == 1 if ($numberOfMonths == 1
|| ($numberOfMonths == 3 && (in_array($numMonthCurrent, [1, 4, 7, 10]))) || ($numberOfMonths == 3 && (in_array($numMonthCurrent, [1, 4, 7, 10])))
|| ($numberOfMonths == 6 && (in_array($numMonthCurrent, [1, 7])))) {
|| ($numberOfMonths == 6 && (in_array($numMonthCurrent, [1, 7])))
|| $context == 'billing') {


for ($i = 1; $i <= $numberOfMonths; $i++) { for ($i = 1; $i <= $numberOfMonths; $i++) {
$month = date('Y-m', strtotime('-' . $i . ' month'));
$timeMonth = strtotime('-' . $i . ' month');
$month = date('Y-m', $timeMonth);
$turnover = $this->getTurnover($producer, $month); $turnover = $this->getTurnover($producer, $month);


if ($turnover) { if ($turnover) {
if($numberOfMonths > 1) {
$text .= ucfirst(strftime('%B ', $timeMonth)).' '.date('Y', $timeMonth).' : ';
}
$isBold = $this->producerSolver->isBillingTypeClassic($producer) && !$producer->option_billing_permanent_transfer; $isBold = $this->producerSolver->isBillingTypeClassic($producer) && !$producer->option_billing_permanent_transfer;
if ($isBold) $text .= '<strong>'; if ($isBold) $text .= '<strong>';
$text .= $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, true); $text .= $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, true);
if ($isBold) $text .= '</strong>'; if ($isBold) $text .= '</strong>';
$text .= ' / ' . Price::format($turnover, 0); $text .= ' / ' . Price::format($turnover, 0);
$text .= '<br />'; $text .= '<br />';

$sumInvoicePrice += $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, false);
} }
} }


if (strlen($text)) { if (strlen($text)) {
$text = $label . ' : <br />' . $text;
$text = '<i>'.$label.'</i>' . ' : <br />' . $text;
} }
}


if($numberOfMonths > 1) {
$text .= '<br />Total : <strong>'.Price::format($sumInvoicePrice, 0).'</strong>';
} }


return $text; return $text;

+ 38
- 6
common/logic/Product/Product/Service/ProductSolver.php View File

use common\helpers\Price; use common\helpers\Price;
use common\logic\AbstractService; use common\logic\AbstractService;
use common\logic\PointSale\PointSale\Model\PointSale; use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\PointSale\PointSale\Service\PointSaleSolver;
use common\logic\Product\Product\Model\Product; use common\logic\Product\Product\Model\Product;
use common\logic\Product\ProductPrice\Service\ProductPriceSolver; use common\logic\Product\ProductPrice\Service\ProductPriceSolver;
use common\logic\SolverInterface; use common\logic\SolverInterface;
class ProductSolver extends AbstractService implements SolverInterface class ProductSolver extends AbstractService implements SolverInterface
{ {
protected ProductPriceSolver $productPriceSolver; protected ProductPriceSolver $productPriceSolver;
protected PointSaleSolver $pointSaleSolver;


public function loadDependencies(): void public function loadDependencies(): void
{ {
$this->productPriceSolver = $this->loadService(ProductPriceSolver::class); $this->productPriceSolver = $this->loadService(ProductPriceSolver::class);
$this->pointSaleSolver = $this->loadService(PointSaleSolver::class);
} }


public function getPrice(Product $product, array $params = []): ?float public function getPrice(Product $product, array $params = []): ?float
$producer = GlobalParam::getCurrentProducer(); $producer = GlobalParam::getCurrentProducer();
if ($producer->option_export_display_product_reference if ($producer->option_export_display_product_reference
&& $product->reference && $product->reference
&& strlen($product->reference) > 0)
{
&& strlen($product->reference) > 0) {
return $product->reference; return $product->reference;
} }


return $product->name; return $product->name;
} }
public function isProductActiveByDay(Product $product, string $day): bool public function isProductActiveByDay(Product $product, string $day): bool
{ {
return $product->active && $product->$day; return $product->active && $product->$day;


public function getProductFieldNameQuantityMax(string $day): string public function getProductFieldNameQuantityMax(string $day): string
{ {
return 'quantity_max_'.$day;
return 'quantity_max_' . $day;
} }


public function isProductQuantityMaxDefinedByDay(Product $product, string $day): bool public function isProductQuantityMaxDefinedByDay(Product $product, string $day): bool
public function getProductQuantityMaxByDay(Product $product, string $day): ?float public function getProductQuantityMaxByDay(Product $product, string $day): ?float
{ {
$quantityMax = ($product->quantity_max && $product->quantity_max > 0) ? $product->quantity_max : null; $quantityMax = ($product->quantity_max && $product->quantity_max > 0) ? $product->quantity_max : null;
if($this->isProductQuantityMaxDefinedByDay($product, $day)) {
if ($this->isProductQuantityMaxDefinedByDay($product, $day)) {
$fieldQuantityMax = $this->getProductFieldNameQuantityMax($day); $fieldQuantityMax = $this->getProductFieldNameQuantityMax($day);
$quantityMax = $product->$fieldQuantityMax; $quantityMax = $product->$fieldQuantityMax;
} }
return $quantityMax; return $quantityMax;
} }

public function isPublic(Product $product): bool
{
if ($product->available_on_points_sale) {
return true;
} else {
foreach ($product->productPointSale as $productPointSale) {
if ($productPointSale->pointSale && $this->pointSaleSolver->isPublic($productPointSale->pointSale)) {
return true;
}
}
}

return false;
}

public function filterProductsByPointSale(array $productArray, PointSale $pointSale = null): array
{
$productArrayFilter = [];

if($pointSale) {
foreach ($productArray as $product) {
if ($this->isAvailableOnPointSale($product, $pointSale)) {
$productArrayFilter[] = $product;
}
}
}

return $productArrayFilter;
}
} }

+ 1
- 1
common/versions/23.4.A.php View File

<li>27/04/2023</li> <li>27/04/2023</li>
</ul> </ul>


<h4>Évolution</h4>
<h4>Évolutions</h4>
<ul> <ul>
<li> <li>
[Administration] Distributions > édition commande : possibilité de modifier les prix facturés [Administration] Distributions > édition commande : possibilité de modifier les prix facturés

+ 24
- 0
common/versions/23.6.B.php View File

<h4>Date de sortie</h4>
<ul>
<li>22/06/2023</li>
</ul>

<h4>Évolutions</h4>
<ul>
<li>[Administration et Espace producteur] Calendrier pour le choix du jour de distribution : affichage du lundi en premier</li>
<li>[Administration] Distribution : alerte remboursement commandes lors de la désactivation d'une distribution</li>
<li>[Administration] Distribution > édition commande : alerte si quantité max d'un produit dépassée</li>
<li>[Administration] Distributions > liste commandes : ajout lien vers fiche client (crédit, profil, commandes)</li>
<li>[Administration] Documents > Bons de livraison : alerte suppression produits</li>
<li>[Administration] Distributions > formulaire commande : raccourci "Entrée" pour passer à la ligne du dessous</li>
<li>[Administration] Utilisateur > édition : ajout info contact facturation</li>
<li>[Administration] Responsive > listes : accès facilité aux boutons d'action</li>
<li>[Espace producteur] Accueil : gestion visibilité produits présents uniquement sur un point de vente à accès restreint</li>
<li>[Espace producteur] Commande > choix du point de vente : ajout informations en fonction du jour choisi</li>
</ul>

<h4>Maintenance</h4>
<ul>
<li>[Espace producteur] Abonnements : correctif disponibilité produits par point de vente</li>
<li>Abonnements > ajout/modification : prise en compte des contraintes de délai et d'heure limite de commande dans la génération des commandes des distributions à venir</li>
</ul>

+ 2
- 0
common/web/js/vuejs/vcalendar/v-calendar.umd.min.js
File diff suppressed because it is too large
View File


+ 10
- 11
producer/controllers/OrderController.php View File



if (is_array($ordersUserArray) && count($ordersUserArray)) { if (is_array($ordersUserArray) && count($ordersUserArray)) {
foreach ($ordersUserArray as &$order) { foreach ($ordersUserArray as &$order) {
$orderManager->initOrder($order);
$order = array_merge($order->getAttributes(), [ $order = array_merge($order->getAttributes(), [
'amount_total' => $orderManager->getOrderAmountWithTax($order, Order::AMOUNT_TOTAL), 'amount_total' => $orderManager->getOrderAmountWithTax($order, Order::AMOUNT_TOTAL),
'date_distribution' => $order->distribution->date, 'date_distribution' => $order->distribution->date,


private function ajaxInfosPointsSale($producer, $distribution = false) private function ajaxInfosPointsSale($producer, $distribution = false)
{ {
$pointSaleManager = $this->getPointSaleManager();
$userManager = $this->getUserManager(); $userManager = $this->getUserManager();
$producerManager = $this->getProducerManager(); $producerManager = $this->getProducerManager();


$position = 0; $position = 0;


foreach ($pointsSaleArray as &$pointSale) { foreach ($pointsSaleArray as &$pointSale) {
$pointSaleObject = $pointSale;
$pointSale = array_merge($pointSale->getAttributes(), [ $pointSale = array_merge($pointSale->getAttributes(), [
'pointSaleDistribution' => [ 'pointSaleDistribution' => [
'id_distribution' => $pointSale->pointSaleDistribution ? $pointSale->pointSaleDistribution[0]->id_distribution : false, 'id_distribution' => $pointSale->pointSaleDistribution ? $pointSale->pointSaleDistribution[0]->id_distribution : false,
'id_distribution' => $distribution->id, 'id_distribution' => $distribution->id,
'id_point_sale' => $pointSale['id'] 'id_point_sale' => $pointSale['id']
]); ]);

$pointSale['infos'] = $pointSaleManager->getStrInfos($pointSaleObject, strtolower(date('l', strtotime($distribution->date))));
} }


$pointSale['position'] = $position; $pointSale['position'] = $position;
->orderBy('product_distribution.active DESC, order ASC') ->orderBy('product_distribution.active DESC, order ASC')
->all(); ->all();


$productsArrayFilter = [];

// filtre sur les points de vente
if($pointSale) {
foreach ($productsArray as $product) {
if ($productManager->isAvailableOnPointSale($product, $pointSale)) {
$productsArrayFilter[] = $product;
}
}
}

$productsArrayFilter = $productManager->filterProductsByPointSale($productsArray, $pointSale);


$indexProduct = 0; $indexProduct = 0;
foreach ($productsArrayFilter as $key => &$product) { foreach ($productsArrayFilter as $key => &$product) {
} }
} }


if($orderUser) {
$orderManager->initOrder($orderUser);
}

return $orderUser; return $orderUser;
} }
} }

+ 15
- 3
producer/controllers/SiteController.php View File

], ],
'sort' => false, 'sort' => false,
]); ]);
$this->filterProductsPublic($dataProviderProductsByCategories[$productCategory->id]);
} }


$queryProducts = Product::find() $queryProducts = Product::find()
'active' => true, 'active' => true,
'id_product_category' => null, 'id_product_category' => null,
]) ])
->with('productPointSale')
->orderBy('order ASC'); ->orderBy('order ASC');


$dataProviderProducts = new ActiveDataProvider([ $dataProviderProducts = new ActiveDataProvider([
], ],
'sort' => false, 'sort' => false,
]); ]);
$this->filterProductsPublic($dataProviderProducts);


$products = $queryProducts->all(); $products = $queryProducts->all();
foreach ($dataProviderProductsByCategories as $dataProvider) { foreach ($dataProviderProductsByCategories as $dataProvider) {
]); ]);
} }


public function filterProductsPublic($dataProviderProducts)
{
$productManager = $this->getProductManager();
$models = $dataProviderProducts->getModels();
foreach($models as $index => $product) {
if(!$productManager->isPublic($product)) {
unset($models[$index]);
}
}
$dataProviderProducts->setModels($models);
}

/** /**
* Affiche et traite le formulaire de contact dédié aux producteurs. * Affiche et traite le formulaire de contact dédié aux producteurs.
*/ */
if (strlen($email) && $model->sendEmail($email)) { if (strlen($email) && $model->sendEmail($email)) {
$isSent = true; $isSent = true;
} }
else {
die('email : '.$email);
}
} }


if ($isSent) { if ($isSent) {

+ 6
- 0
producer/controllers/SubscriptionController.php View File

} }
} }


$productPointSaleArray = [];
foreach($product->productPointSale as $productPointSale) {
$productPointSaleArray[] = $productPointSale->id_point_sale;
}

$product = array_merge( $product = array_merge(
$product->getAttributes(), $product->getAttributes(),
[ [
'user_producer' => $userProducer, 'user_producer' => $userProducer,
'point_sale' => $pointSale 'point_sale' => $pointSale
]), ]),
'product_point_sale_array' => $productPointSaleArray
] ]
); );



+ 6
- 5
producer/views/order/order.php View File

<div id="calendar"> <div id="calendar">
<v-calendar <v-calendar
is-inline is-inline
is-double-paned
is-expanded is-expanded
v-model="date" v-model="date"
mode="single" mode="single"
locale="fr"
:locale="{ id: 'fr', firstDayOfWeek: 1, masks: { weekdays: 'WW' } }"
:first-day-of-week="1"
columns="2"
color="green"
:formats="calendar.formats" :formats="calendar.formats"
:theme-styles="calendar.themeStyles" :theme-styles="calendar.themeStyles"
:attributes="calendar.attrs" :attributes="calendar.attrs"
<div class="comment" v-if="pointSale.userPointSale"> <div class="comment" v-if="pointSale.userPointSale">
{{ pointSale.userPointSale.comment }} {{ pointSale.userPointSale.comment }}
</div> </div>
<div class="comment" v-if="pointSale.infos && pointSale.infos.length > 0" v-html="pointSale.infos"></div>
</td> </td>
<td class="locality">{{ pointSale.locality }}</td> <td class="locality">{{ pointSale.locality }}</td>
<td class="actions"> <td class="actions">
<template v-if="producer.online_payment == 1"><a href="<?= \Yii::$app->urlManager->createUrl(['credit/add']) ?>">recharger votre crédit</a></template> <template v-if="producer.online_payment == 1"><a href="<?= \Yii::$app->urlManager->createUrl(['credit/add']) ?>">recharger votre crédit</a></template>
<template v-else>recharger votre crédit</template> auprès de votre producteur ou supprimer des produits.</span> <template v-else>recharger votre crédit</template> auprès de votre producteur ou supprimer des produits.</span>
Votre producteur n'autorise pas un crédit inférieur Votre producteur n'autorise pas un crédit inférieur
à <strong>{{ formatPrice(producer.credit_limit) }}</strong>.</div>
à <strong>{{ formatPrice(producer.credit_limit) }}</strong>.
/ {{ priceTotal() }}
</div>
<div class="block-actions"> <div class="block-actions">
<a class="btn btn-primary" href="<?= \Yii::$app->urlManager->createUrl(['site/index']) ?>">Retour à l'accueil</a> <a class="btn btn-primary" href="<?= \Yii::$app->urlManager->createUrl(['site/index']) ?>">Retour à l'accueil</a>
</div> </div>

+ 38
- 33
producer/web/css/screen.css View File

color: black; color: black;
font-size: 20px; font-size: 20px;
line-height: 25px; line-height: 25px;
font-weight: bold;
} }
/* line 219, ../sass/order/_order.scss */ /* line 219, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.name .comment {
color: gray;
}
/* line 224, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.actions { .order-order #main #app-order-order table#points-sale td.actions {
width: 150px; width: 150px;
} }
/* line 221, ../sass/order/_order.scss */
/* line 226, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale td.actions button { .order-order #main #app-order-order table#points-sale td.actions button {
width: 100%; width: 100%;
} }
/* line 227, ../sass/order/_order.scss */
/* line 232, ../sass/order/_order.scss */
.order-order #main #app-order-order table#points-sale tr.selected td { .order-order #main #app-order-order table#points-sale tr.selected td {
background-color: white; background-color: white;
} }
/* line 235, ../sass/order/_order.scss */
/* line 240, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name { .order-order #main #app-order-order table#products td.category-name {
font-family: "highvoltageregular"; font-family: "highvoltageregular";
font-size: 22px; font-size: 22px;
text-transform: uppercase; text-transform: uppercase;
padding-top: 13px; padding-top: 13px;
} }
/* line 242, ../sass/order/_order.scss */
/* line 247, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name .glyphicon-triangle-bottom, .order-order #main #app-order-order table#products td.category-name .glyphicon-triangle-bottom,
.order-order #main #app-order-order table#products td.category-name .glyphicon-triangle-right { .order-order #main #app-order-order table#products td.category-name .glyphicon-triangle-right {
font-size: 15px; font-size: 15px;
} }
/* line 247, ../sass/order/_order.scss */
/* line 252, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name span.label { .order-order #main #app-order-order table#products td.category-name span.label {
font-family: "Arial"; font-family: "Arial";
font-weight: normal; font-weight: normal;
text-transform: none; text-transform: none;
margin-left: 15px; margin-left: 15px;
} }
/* line 256, ../sass/order/_order.scss */
/* line 261, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.category-name:hover { .order-order #main #app-order-order table#products td.category-name:hover {
cursor: pointer; cursor: pointer;
background-color: #FF7F00; background-color: #FF7F00;
color: white; color: white;
} }
/* line 264, ../sass/order/_order.scss */
/* line 269, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.photo img { .order-order #main #app-order-order table#products td.photo img {
width: 100px; width: 100px;
} }
/* line 270, ../sass/order/_order.scss */
/* line 275, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.name .name { .order-order #main #app-order-order table#products td.name .name {
font-family: "capsuularegular"; font-family: "capsuularegular";
color: black; color: black;
line-height: 25px; line-height: 25px;
font-weight: bold; font-weight: bold;
} }
/* line 277, ../sass/order/_order.scss */
/* line 282, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.name .other { .order-order #main #app-order-order table#products td.name .other {
font-family: "capsuularegular"; font-family: "capsuularegular";
color: black; color: black;
font-weight: bold; font-weight: bold;
font-size: 17px; font-size: 17px;
} }
/* line 283, ../sass/order/_order.scss */
/* line 288, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.name .description { .order-order #main #app-order-order table#products td.name .description {
color: gray; color: gray;
} }
/* line 286, ../sass/order/_order.scss */
/* line 291, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products td.name .recipe { .order-order #main #app-order-order table#products td.name .recipe {
color: gray; color: gray;
} }
/* line 292, ../sass/order/_order.scss */
/* line 297, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices { .order-order #main #app-order-order table#products .price-unit .decreasing-prices {
margin-top: 10px; margin-top: 10px;
font-size: 10px; font-size: 10px;
padding-bottom: 2px; padding-bottom: 2px;
margin-bottom: 0px; margin-bottom: 0px;
} }
/* line 300, ../sass/order/_order.scss */
/* line 305, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li { .order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li {
margin-bottom: 5px; margin-bottom: 5px;
} }
/* line 302, ../sass/order/_order.scss */
/* line 307, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li strong { .order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li strong {
font-weight: bold; font-weight: bold;
} }
/* line 310, ../sass/order/_order.scss */
/* line 315, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit, .order-order #main #app-order-order table#products .price-total { .order-order #main #app-order-order table#products .price-unit, .order-order #main #app-order-order table#products .price-total {
width: 135px; width: 135px;
text-align: center; text-align: center;
} }
/* line 314, ../sass/order/_order.scss */
/* line 319, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .unit, .order-order #main #app-order-order table#products .price-total .unit { .order-order #main #app-order-order table#products .price-unit .unit, .order-order #main #app-order-order table#products .price-total .unit {
color: gray; color: gray;
font-size: 13px; font-size: 13px;
} }
/* line 319, ../sass/order/_order.scss */
/* line 324, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity { .order-order #main #app-order-order table#products .td-quantity {
width: 175px; width: 175px;
} }
/* line 321, ../sass/order/_order.scss */
/* line 326, ../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.quantity {
text-align: center; text-align: center;
border-right: 0px none; border-right: 0px none;
} }
/* line 325, ../sass/order/_order.scss */
/* line 330, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity .input-group-addon { .order-order #main #app-order-order table#products .td-quantity .input-group-addon {
padding: 5px; padding: 5px;
padding-left: 0px; padding-left: 0px;
border-left: 0px none; border-left: 0px none;
border-right: 0px none; border-right: 0px none;
} }
/* line 336, ../sass/order/_order.scss */
/* line 341, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary h3 { .order-order #main #app-order-order table#products tr.total .summary h3 {
margin-top: 0px; margin-top: 0px;
font-family: "capsuularegular"; font-family: "capsuularegular";
text-transform: none; text-transform: none;
margin-bottom: 5px; margin-bottom: 5px;
} }
/* line 343, ../sass/order/_order.scss */
/* line 348, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul { .order-order #main #app-order-order table#products tr.total .summary ul {
margin-bottom: 15px; margin-bottom: 15px;
padding-left: 20px; padding-left: 20px;
font-size: 23px; font-size: 23px;
} }
/* line 350, ../sass/order/_order.scss */
/* line 355, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul li .quantity { .order-order #main #app-order-order table#products tr.total .summary ul li .quantity {
font-size: 18px; font-size: 18px;
} }
/* line 354, ../sass/order/_order.scss */
/* line 359, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul li .name { .order-order #main #app-order-order table#products tr.total .summary ul li .name {
font-family: "capsuularegular"; font-family: "capsuularegular";
font-size: 24px; font-size: 24px;
} }
/* line 358, ../sass/order/_order.scss */
/* line 363, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul li .other { .order-order #main #app-order-order table#products tr.total .summary ul li .other {
font-family: "capsuularegular"; font-family: "capsuularegular";
font-size: 18px; font-size: 18px;
} }
/* line 366, ../sass/order/_order.scss */
/* line 371, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .price-total { .order-order #main #app-order-order table#products tr.total .price-total {
font-size: 23px; font-size: 23px;
} }
/* line 374, ../sass/order/_order.scss */
/* line 379, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .delivery { .order-order #main #app-order-order #content-step-payment .delivery {
margin-bottom: 20px; margin-bottom: 20px;
} }
/* line 377, ../sass/order/_order.scss */
/* line 382, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .delivery .delivery-home { .order-order #main #app-order-order #content-step-payment .delivery .delivery-home {
margin-bottom: 20px; margin-bottom: 20px;
} }
/* line 386, ../sass/order/_order.scss */
/* line 391, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .comment { .order-order #main #app-order-order #content-step-payment .comment {
margin-bottom: 20px; margin-bottom: 20px;
} }
/* line 391, ../sass/order/_order.scss */
/* line 396, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .credit .info { .order-order #main #app-order-order #content-step-payment .credit .info {
margin-left: 20px; margin-left: 20px;
color: gray; color: gray;
} }
/* line 398, ../sass/order/_order.scss */
/* line 403, ../sass/order/_order.scss */
.order-order #main #app-order-order #specific-delays { .order-order #main #app-order-order #specific-delays {
margin-top: 15px; margin-top: 15px;
} }
/* line 406, ../sass/order/_order.scss */
/* line 411, ../sass/order/_order.scss */
.order-order #main #app-order-order #infos { .order-order #main #app-order-order #infos {
margin-top: 30px; margin-top: 30px;
} }
/* line 408, ../sass/order/_order.scss */
/* line 413, ../sass/order/_order.scss */
.order-order #main #app-order-order #infos .panel-body { .order-order #main #app-order-order #infos .panel-body {
padding-top: 0px; padding-top: 0px;
white-space: pre-line; white-space: pre-line;
} }


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

+ 13
- 10
producer/web/js/vuejs/order-order.js View File

var arrayDate; var arrayDate;
for (var i = 0; i < distributions.length; i++) { for (var i = 0; i < distributions.length; i++) {
app.calendar.attrs.push({ app.calendar.attrs.push({
highlight: {
backgroundColor: '#5cb85c',
},
contentStyle: {
color: 'white',
},
dates: distributions[i].date,
highlight: true,
dates: distributions[i].date
}); });


arrayDate = distributions[i].date.split('-'); arrayDate = distributions[i].date.split('-');
if (app.isAvailableDate(dateOrder)) { if (app.isAvailableDate(dateOrder)) {


app.calendar.attrs.push({ app.calendar.attrs.push({
highlight: {
highlight: true,
popover: {
label: orders[i].pointSale.name + ' / ' + app.formatPrice(orders[i].amount_total),
hideIndicator: true
},
dates: orders[i].date_distribution


/*highlight: {
backgroundColor: '#FF7F00' backgroundColor: '#FF7F00'
}, },
contentStyle: { contentStyle: {
label: orders[i].pointSale.name + ' / ' + app.formatPrice(orders[i].amount_total), label: orders[i].pointSale.name + ' / ' + app.formatPrice(orders[i].amount_total),
hideIndicator: true hideIndicator: true
}, },
dates: orders[i].date_distribution,
dates: orders[i].date_distribution,*/
}); });
} }
} }
return this.formatPrice(price) ; return this.formatPrice(price) ;
} }
else { else {
return price ;
return numberDecimals(price, 2) ;
} }
}, },
productHasPrice: function(product) { productHasPrice: function(product) {

+ 9
- 4
producer/web/js/vuejs/subscription-form.js View File

} }
}, },
dayChange: function () { dayChange: function () {
console.log(this.monday + ' ' + this.tuesday + ' ' + this.wednesday + ' ' +
this.thursday + ' ' + this.friday + ' ' + this.saturday + ' ' + this.sunday);

var count = Number(this.monday) + Number(this.tuesday) + Number(this.wednesday) var count = Number(this.monday) + Number(this.tuesday) + Number(this.wednesday)
+ Number(this.thursday) + Number(this.friday) + Number(this.saturday) + Number(this.thursday) + Number(this.friday) + Number(this.saturday)
+ Number(this.sunday); + Number(this.sunday);
(!this.thursday || (this.thursday && product.thursday)) && (!this.thursday || (this.thursday && product.thursday)) &&
(!this.friday || (this.friday && product.friday)) && (!this.friday || (this.friday && product.friday)) &&
(!this.saturday || (this.saturday && product.saturday)) && (!this.saturday || (this.saturday && product.saturday)) &&
(!this.sunday || (this.sunday && product.sunday));
(!this.sunday || (this.sunday && product.sunday)) &&
(
(product.available_on_points_sale && !this.checkProductPointSaleInclude(product))
|| (!product.available_on_points_sale && this.checkProductPointSaleInclude(product))
)
;


if (!available) { if (!available) {
product.quantity_form = 0; product.quantity_form = 0;


return available; return available;
}, },
checkProductPointSaleInclude: function(product) {
return this.idPointSaleActive && product.product_point_sale_array.includes(parseInt(this.idPointSaleActive));
},
checkOneProductAvailable: function () { checkOneProductAvailable: function () {
var count = 0; var count = 0;
for (key in this.products) { for (key in this.products) {

+ 5
- 0
producer/web/sass/order/_order.scss View File

color: black ; color: black ;
font-size: 20px ; font-size: 20px ;
line-height: 25px ; line-height: 25px ;
font-weight: bold;
}

.comment {
color: gray;
} }
} }

Loading…
Cancel
Save