Browse Source

Affichage des prix avec taxe & refactoring suscription #154

refactoring
Fab 5 years ago
parent
commit
5b78b03fe8
17 changed files with 1012 additions and 1094 deletions
  1. +10
    -7
      backend/controllers/SubscriptionController.php
  2. +2
    -8
      backend/views/subscription/_form.php
  3. +4
    -20
      backend/views/subscription/index.php
  4. +1
    -16
      backend/web/js/vuejs/subscription-form.js
  5. +0
    -77
      common/models/OrderOrderStatus.php
  6. +21
    -0
      common/models/Product.php
  7. +419
    -441
      common/models/Subscription.php
  8. +1
    -31
      common/models/SubscriptionForm.php
  9. +42
    -2
      common/web/js/utils.js
  10. +35
    -0
      console/migrations/m200108_145508_module_bl_devis_factures_suppression_price_unit_step_product_subscription.php
  11. +10
    -4
      producer/controllers/OrderController.php
  12. +284
    -289
      producer/controllers/SubscriptionController.php
  13. +2
    -2
      producer/views/order/order.php
  14. +3
    -2
      producer/views/subscription/_form.php
  15. +1
    -1
      producer/views/subscription/index.php
  16. +2
    -8
      producer/web/js/vuejs/order-order.js
  17. +175
    -186
      producer/web/js/vuejs/subscription-form.js

+ 10
- 7
backend/controllers/SubscriptionController.php View File

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

namespace backend\controllers;

use common\helpers\Debug;
use common\helpers\GlobalParam;
use common\models\Order ;
use common\models\Product ;
@@ -276,19 +277,21 @@ class SubscriptionController extends BackendController
}
$productsArray = $productsQuery->asArray()->orderBy('order ASC')->all() ;
/*Debug::dump($productsArray);*/
foreach($productsArray as &$theProduct) {
$theProduct['unit_save'] = $theProduct['unit'] ;
/*$theProduct['unit_save'] = $theProduct['unit'] ;
$theProduct['units'] = [] ;
$theProduct['units'][] = [
'unit' => $theProduct['unit'],
'wording_unit' => Product::strUnit($theProduct['unit'], 'wording_short'),
'step' => $theProduct['step'],
'price' => $theProduct['price']
] ;
] ;*/

$theProduct['wording_unit'] = Product::strUnit($theProduct['unit'], 'wording_short');

if(isset($theProduct['productSubscription'][0])) {
if($theProduct['productSubscription'][0]['unit'] != $theProduct['unit']) {
/*if($theProduct['productSubscription'][0]['unit'] != $theProduct['unit']) {
$theProduct['units'][] = [
'unit' => $theProduct['productSubscription'][0]['unit'],
'wording_unit' => Product::strUnit($theProduct['productSubscription'][0]['unit'], 'wording_short'),
@@ -298,7 +301,7 @@ class SubscriptionController extends BackendController
$theProduct['unit'] = $theProduct['productSubscription'][0]['unit'] ;
$theProduct['step'] = $theProduct['productSubscription'][0]['step'] ;
$theProduct['price'] = $theProduct['productSubscription'][0]['price'] ;
}
}*/
$theProduct['quantity'] = $theProduct['productSubscription'][0]['quantity'] * Product::$unitsArray[$theProduct['unit']]['coefficient'] ;
}
else {

+ 2
- 8
backend/views/subscription/_form.php View File

@@ -109,11 +109,8 @@ use common\helpers\GlobalParam ;
</span>
<input v-model="product.quantity" :name="'SubscriptionForm[products][product_'+product.id+']'" class="form-control input-quantity" />
<div class="input-group-addon">
<select class="form-control select-unit" :name="'product_unit_'+product.id" v-model="product.unit" v-if="product.units.length > 1" @change="changeUnitProductSubscription" :data-id-product="product.id">
<option v-for="unit in product.units" :value="unit.unit">{{ unit.wording_unit }}</option>
</select>
<span v-else>
{{ product.units[0].wording_unit }}
<span>
{{ product.wording_unit }}
</span>
</div>
<span class="input-group-btn">
@@ -121,9 +118,6 @@ use common\helpers\GlobalParam ;
</span>
</div>
</td>
<td>
<span v-if="product.units.length > 1 && product.unit != product.unit_save" class="glyphicon glyphicon-warning-sign" title="Unité différente du produit"></span>
</td>
</tr>
</table>
</div>

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

@@ -47,22 +47,11 @@ $this->addBreadcrumb($this->getTitle()) ;
$this->addButton(['label' => 'Nouvel abonnement <span class="glyphicon glyphicon-plus"></span>', 'url' => 'subscription/create', 'class' => 'btn btn-primary']) ;

$subscriptionsArray = Subscription::searchAll() ;
$hasUnitsNotMatch = false ;
foreach($subscriptionsArray as $subscription) {
if($subscription->hasUnitsNotMatch()) {
$hasUnitsNotMatch = true ;
}
}



?>
<div class="subscription-index">

<?php if($hasUnitsNotMatch) : ?>
<div class="alert alert-warning">
<span class="glyphicon glyphicon-warning-sign"></span> Attention, des unités ne correspondent pas entre vos produits et vos abonnements.<br />
Veuillez modifier vos abonnements et ajuster les unités / quantités pour régler le problème.
</div>
<?php endif; ?>
<?= GridView::widget([
'filterModel' => $searchModel,
@@ -93,7 +82,7 @@ foreach($subscriptionsArray as $subscription) {
foreach($model->productSubscription as $productSubscription)
{
if(isset($productSubscription->product)) {
$html .= Html::encode($productSubscription->product->name).' ('.($productSubscription->quantity * Product::$unitsArray[$productSubscription->unit]['coefficient']).'&nbsp;'.Product::strUnit($productSubscription->unit, 'wording_short').')<br />' ;
$html .= Html::encode($productSubscription->product->name).' ('.($productSubscription->quantity * Product::$unitsArray[$productSubscription->product->unit]['coefficient']).'&nbsp;'.Product::strUnit($productSubscription->product->unit, 'wording_short').')<br />' ;
}
else {
$html .= 'Produit non défini<br />' ;
@@ -105,12 +94,7 @@ foreach($subscriptionsArray as $subscription) {
{
$html .= '<span class="glyphicon glyphicon-warning-sign"></span> Aucun produit<br />' ;
}
// des unités ne correspondent pas
if($model->hasUnitsNotMatch()) {
$html .= '<span class="glyphicon glyphicon-warning-sign" title="Des unités ne correspondent pas"></span>' ;
}

return $html ;
}
],

+ 1
- 16
backend/web/js/vuejs/subscription-form.js View File

@@ -40,8 +40,7 @@ var app = new Vue({
data: {
showLoading: false,
loading: true,
products: [],
units: []
products: []
},
mounted: function() {
@@ -57,23 +56,9 @@ var app = new Vue({
axios.get("ajax-infos",{params: {idSubscription: $('#subscriptionform-id').val()}})
.then(function(response) {
app.products = response.data.products ;
app.units = response.data.units ;
app.showLoading = false ;
}) ;
},
changeUnitProductSubscription: function(event) {
for(var i = 0; i < this.products.length ; i++) {
if(this.products[i].id == event.currentTarget.getAttribute('data-id-product')) {
this.products[i].quantity = '' ;
for(var j = 0; j < this.products[i].units.length ; j ++) {
if(this.products[i].unit == this.products[i].units[j].unit) {
this.products[i].step = this.products[i].units[j].step ;
this.products[i].price = this.products[i].units[j].price ;
}
}
}
}
},
changeQuantityProductSubscription: function(increase, product) {
var step = step ? parseFloat(product.step) : 1 ;
if(!product.quantity) product.quantity = 0 ;

+ 0
- 77
common/models/OrderOrderStatus.php View File

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

namespace common\models;

use common\components\ActiveRecordCommon;
use Yii;

/**
* This is the model class for table "order_order_status".
*
* @property integer $id
* @property integer $id_order
* @property integer $id_order_status
* @property string $date
*/
class OrderOrderStatus extends ActiveRecordCommon
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'order_order_status';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['id_order', 'id_order_status'], 'integer'],
[['date'], 'safe'],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_order' => 'Commande',
'id_order_status' => 'Statut',
'date' => 'Date',
];
}
/*
* Relations
*/

public function getOrder()
{
return $this->hasOne(User::className(), ['id' => 'id_order']);
}
public function getOrderStatus()
{
return $this->hasOne(OrderStatus::className(), ['id' => 'id_order_status']);
}
/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch() {
return [
'with' => [],
'join_with' => ['order', 'orderStatus'],
'orderby' => 'date ASC',
'attribute_id_producer' => ''
] ;
}
}

+ 21
- 0
common/models/Product.php View File

@@ -38,7 +38,9 @@

namespace common\models;

use common\helpers\Debug;
use common\helpers\GlobalParam;
use common\helpers\Price;
use Yii;
use common\components\ActiveRecordCommon;

@@ -160,6 +162,13 @@ class Product extends ActiveRecordCommon
];
}

public function afterFind() {
if ($this->taxRate == null) {
$this->populateRelation('taxRate', GlobalParam::getCurrentProducer()->taxRate);
}
parent::afterFind();
}

public function getProductDistribution()
{
return $this->hasMany(ProductDistribution::className(), ['id_product' => 'id']);
@@ -172,6 +181,7 @@ class Product extends ActiveRecordCommon

public function getTaxRate()
{

return $this->hasOne(TaxRate::className(), ['id' => 'id_tax_rate']);
}

@@ -301,4 +311,15 @@ class Product extends ActiveRecordCommon

return $strUnit;
}

/**
* Retourne le prix du produit avec taxe
*/
public function getPriceWithTax()
{

return Price::getPriceWithTax($this->price, $this->taxRate->value);
}


}

+ 419
- 441
common/models/Subscription.php View File

@@ -1,52 +1,52 @@
<?php

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

namespace common\models;

use common\helpers\GlobalParam;
use Yii;
use common\components\ActiveRecordCommon ;
use common\components\ActiveRecordCommon;
use common\models\Producer;
use common\models\PointSale;
use common\models\UserPointSale;
use common\models\Order;
use common\models\ProductOrder;
use common\models\User ;
use common\models\User;

/**
* This is the model class for table "commande_auto".
@@ -71,426 +71,404 @@ use common\models\User ;
*/
class Subscription extends ActiveRecordCommon
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'subscription';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['id_producer', 'id_point_sale'], 'required'],
[['id_user', 'id_producer', 'id_point_sale', 'monday', 'tuesday',
'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'week_frequency'], 'integer'],
[['auto_payment'], 'boolean'],
[['date_begin', 'date_end', 'username','comment'], 'safe'],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_user' => 'Utilisateur',
'id_producer' => 'Etablissement',
'id_point_sale' => 'Point de vente',
'date_begin' => 'Date de début',
'date_end' => 'Date de fin',
'monday' => 'Lundi',
'tuesday' => 'Mardi',
'wednesday' => 'Mercredi',
'thursday' => 'Jeudi',
'friday' => 'Vendredi',
'saturday' => 'Samedi',
'sunday' => 'Dimanche',
'week_frequency' => 'Périodicité',
'auto_payment' => 'Paiement automatique',
'comment' => 'Commentaire'
];
}

/*
* Relations
*/
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'id_user']);
}

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

public function getPointSale()
{
return $this->hasOne(
PointSale::className(),
['id' => 'id_point_sale']
);
}

public function getProductSubscription()
{
return $this->hasMany(
ProductSubscription::className(),
['id_subscription' => 'id']
)->with('product');
}

/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
{
return [
'with' => ['producer'],
'join_with' => ['user', 'productSubscription', 'productSubscription.product', 'pointSale'],
'orderby' => 'user.name ASC',
'attribute_id_producer' => 'subscription.id_producer'
] ;
}
/**
* Ajoute la commande pour une date donnée.
*
* @param string $date
*/
public function add($date)
{
// distribution
$distribution = Distribution::searchOne([
'distribution.date' => date('Y-m-d', strtotime($date))
]) ;

if ($distribution && count($this->productSubscription)) {
// commande
$order = new Order;
if (strlen($this->username)) {
$order->username = $this->username;
$order->id_user = 0;
}
else {
$order->id_user = $this->id_user;
}
$order->date = date('Y-m-d H:i:s');
$order->origin = Order::ORIGIN_AUTO;
$order->id_point_sale = $this->id_point_sale;
$order->id_distribution = $distribution->id;
$order->id_subscription = $this->id;
if(strlen($this->comment)) {
$order->comment = $this->comment ;
}
$pointSale = PointSale::findOne($this->id_point_sale) ;
$creditFunctioning = $pointSale->getCreditFunctioning() ;
$order->auto_payment = 0 ;
if($order->id_user && Producer::getConfig('credit') && $pointSale->credit) {
if($creditFunctioning == Producer::CREDIT_FUNCTIONING_OPTIONAL) {
$order->auto_payment = $this->auto_payment ;
}
elseif($creditFunctioning == Producer::CREDIT_FUNCTIONING_MANDATORY) {
$order->auto_payment = 1 ;
}
elseif($creditFunctioning == Producer::CREDIT_FUNCTIONING_USER) {
$user = User::findOne($order->id_user) ;
$userProducer = UserProducer::searchOne([
'id_user' => $order->id_user,
'id_producer' => $distribution->id_producer
]) ;
if($userProducer) {
$order->auto_payment = $userProducer->credit_active ;
}
}
}
$userPointSale = UserPointSale::searchOne([
'id_point_sale' => $this->id_point_sale,
'id_user' => $this->id_user
]) ;

if ($userPointSale && strlen($userPointSale->comment)) {
$order->comment_point_sale = $userPointSale->comment;
}

$order->save();

// liaison utilisateur / point de vente
if($order->id_user) {
$pointSale = PointSale::findOne($this->id_point_sale) ;
$pointSale->linkUser($order->id_user) ;
}
// produits
$amountTotal = 0;
$productsAdd = false;
foreach ($this->productSubscription as $productSubscription) {
$productOrder = new ProductOrder;
$productOrder->id_order = $order->id;
$productOrder->id_product = $productSubscription->product->id;
$productOrder->quantity = $productSubscription->quantity;
$productOrder->price = $productSubscription->product->price;
$productOrder->unit = $productSubscription->unit;
$productOrder->step = $productSubscription->step;
$productOrder->save();
$productsAdd = true;
}

if (!$productsAdd) {
$order->delete();
}
/**
* @inheritdoc
*/
public static function tableName()
{
return 'subscription';
}
}
/**
* Ajoute les commandes pour une date donnée à partir des abonnements.
*
* @param string $date
* @param boolean $force
*/
public static function addAll($date, $force = false)
{
$distribution = Distribution::searchOne([
'date' => date('Y-m-d', strtotime($date)),
'id_producer' => GlobalParam::getCurrentProducerId(),
]) ;

if ($distribution) {
$arrayOrdersDistribution = Order::searchAll([
Order::tableName().'.id_distribution' => $distribution->id
]);
$arraySubscriptions = self::searchByDate($date);
foreach ($arraySubscriptions as $subscription) {
if(!$subscription->hasOrderAlreadyExist($arrayOrdersDistribution)) {
$subscription->add($date);
}
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['id_producer', 'id_point_sale'], 'required'],
[['id_user', 'id_producer', 'id_point_sale', 'monday', 'tuesday',
'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'week_frequency'], 'integer'],
[['auto_payment'], 'boolean'],
[['date_begin', 'date_end', 'username', 'comment'], 'safe'],
];
}
}
/**
* Informe s'il existe une commande correspond à l'abonnement courant.
*
* @param array $arrayOrders
* @return boolean
*/
public function hasOrderAlreadyExist($arrayOrders)
{
if(is_array($arrayOrders) && count($arrayOrders) > 0) {
foreach($arrayOrders as $order) {
if((($order->id_user > 0 && $order->id_user == $this->id_user) ||
(!$order->id_user && $order->username == $this->username)) &&
$order->id_point_sale == $this->id_point_sale) {
return true ;
}
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_user' => 'Utilisateur',
'id_producer' => 'Etablissement',
'id_point_sale' => 'Point de vente',
'date_begin' => 'Date de début',
'date_end' => 'Date de fin',
'monday' => 'Lundi',
'tuesday' => 'Mardi',
'wednesday' => 'Mercredi',
'thursday' => 'Jeudi',
'friday' => 'Vendredi',
'saturday' => 'Samedi',
'sunday' => 'Dimanche',
'week_frequency' => 'Périodicité',
'auto_payment' => 'Paiement automatique',
'comment' => 'Commentaire'
];
}
return false ;
}
/**
* Retourne les abonnements pour une date donnée.
*
* @param string $date
* @return array
*/
public static function searchByDate($date)
{
$date = date('Y-m-d', strtotime($date));
$subscriptions = Subscription::searchAll() ;

$arrSubscriptions = [];

foreach ($subscriptions as $s) {
if ($date >= $s->date_begin &&
(!$s->date_end || $date <= $s->date_end) &&
$s->matchWith($date))
{
$arrSubscriptions[] = $s;
}

/*
* Relations
*/

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

return $arrSubscriptions;
}
/**
* Valide le fait qu'un abonnement est bien compatible avec une date donnée.
*
* @param string $date
* @return boolean
*/
public function matchWith($date)
{
$arrayDays = [
1 => 'monday',
2 => 'tuesday',
3 => 'wednesday',
4 => 'thursday',
5 => 'friday',
6 => 'saturday',
7 => 'sunday'
] ;
$nbDays = (strtotime($date) - strtotime($this->date_begin)) / (24 * 60 * 60);
if (round($nbDays) % ($this->week_frequency * 7) < 7) {
$numDay = date('N', strtotime($date));
$day = $arrayDays[$numDay] ;
if ($this->$day) {
return true ;
}
public function getProducer()
{
return $this->hasOne(
Producer::className(),
['id' => 'id_producer']
);
}
return false ;
}
/**
* Recherche les distributions futures où l'abonnement peut s'appliquer.
*
* @return array
*/
public function searchMatchedIncomingDistributions()
{
$producer = GlobalParam::getCurrentProducer() ;
$params = [
':date_earliest_order' => $producer->getEarliestDateOrder(),
':date_begin' => date('Y-m-d', strtotime($this->date_begin)),
':id_producer' => GlobalParam::getCurrentProducerId()
] ;
$incomingDistributions = Distribution::find()
->where('id_producer = :id_producer')
->andWhere('date >= :date_begin')
->andWhere('date >= :date_earliest_order') ;
if($this->date_end) {
$incomingDistributions->andWhere('date < :date_end') ;
$params[':date_end'] = date('Y-m-d', strtotime($this->date_end)) ;

public function getPointSale()
{
return $this->hasOne(
PointSale::className(),
['id' => 'id_point_sale']
);
}
$incomingDistributions->orderBy('date ASC') ;
$incomingDistributions->params($params) ;
$incomingDistributionsArray = $incomingDistributions->all() ;
$matchedIncomingDistributionsArray = [] ;
foreach($incomingDistributionsArray as $incomingDistribution) {
if($this->matchWith($incomingDistribution->date)) {
$matchedIncomingDistributionsArray[] = $incomingDistribution ;
}

public function getProductSubscription()
{
return $this->hasMany(
ProductSubscription::className(),
['id_subscription' => 'id']
)->with('product');
}
return $matchedIncomingDistributionsArray ;
}
public function deleteOrdersIncomingDistributions()
{
$params = [
':id_producer' => GlobalParam::getCurrentProducerId(),
':date_today' => date('Y-m-d'),
':date_begin' => $this->date_begin,
':id_subscription' => $this->id
];
$orderDeadline = Producer::getConfig('order_deadline') ;
$hour = date('G') ;
if($hour >= $orderDeadline) {
$conditionDistributionDate = 'distribution.date > :date_today' ;

/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
{
return [
'with' => ['producer'],
'join_with' => ['user', 'productSubscription', 'productSubscription.product', 'pointSale'],
'orderby' => 'user.name ASC',
'attribute_id_producer' => 'subscription.id_producer'
];
}
else {
$conditionDistributionDate = 'distribution.date >= :date_today' ;

/**
* Ajoute la commande pour une date donnée.
*
* @param string $date
*/
public function add($date)
{
// distribution
$distribution = Distribution::searchOne([
'distribution.date' => date('Y-m-d', strtotime($date))
]);

if ($distribution && count($this->productSubscription)) {
// commande
$order = new Order;
if (strlen($this->username)) {
$order->username = $this->username;
$order->id_user = 0;
} else {
$order->id_user = $this->id_user;
}
$order->date = date('Y-m-d H:i:s');
$order->origin = Order::ORIGIN_AUTO;
$order->id_point_sale = $this->id_point_sale;
$order->id_distribution = $distribution->id;
$order->id_subscription = $this->id;
if (strlen($this->comment)) {
$order->comment = $this->comment;
}

$pointSale = PointSale::findOne($this->id_point_sale);
$creditFunctioning = $pointSale->getCreditFunctioning();

$order->auto_payment = 0;
if ($order->id_user && Producer::getConfig('credit') && $pointSale->credit) {
if ($creditFunctioning == Producer::CREDIT_FUNCTIONING_OPTIONAL) {
$order->auto_payment = $this->auto_payment;
} elseif ($creditFunctioning == Producer::CREDIT_FUNCTIONING_MANDATORY) {
$order->auto_payment = 1;
} elseif ($creditFunctioning == Producer::CREDIT_FUNCTIONING_USER) {
$user = User::findOne($order->id_user);
$userProducer = UserProducer::searchOne([
'id_user' => $order->id_user,
'id_producer' => $distribution->id_producer
]);
if ($userProducer) {
$order->auto_payment = $userProducer->credit_active;
}
}
}

$userPointSale = UserPointSale::searchOne([
'id_point_sale' => $this->id_point_sale,
'id_user' => $this->id_user
]);

if ($userPointSale && strlen($userPointSale->comment)) {
$order->comment_point_sale = $userPointSale->comment;
}

$order->save();

// liaison utilisateur / point de vente
if ($order->id_user) {
$pointSale = PointSale::findOne($this->id_point_sale);
$pointSale->linkUser($order->id_user);
}

// produits
$amountTotal = 0;
$productsAdd = false;
foreach ($this->productSubscription as $productSubscription) {
$productOrder = new ProductOrder;
$productOrder->id_order = $order->id;
$productOrder->id_product = $productSubscription->product->id;
$productOrder->quantity = $productSubscription->quantity;
$productOrder->price = $productSubscription->product->price;
$productOrder->unit = $productSubscription->unit;
$productOrder->step = $productSubscription->step;
$productOrder->save();
$productsAdd = true;
}

if (!$productsAdd) {
$order->delete();
}
}
}

/**
* Ajoute les commandes pour une date donnée à partir des abonnements.
*
* @param string $date
* @param boolean $force
*/
public static function addAll($date, $force = false)
{
$distribution = Distribution::searchOne([
'date' => date('Y-m-d', strtotime($date)),
'id_producer' => GlobalParam::getCurrentProducerId(),
]);

if ($distribution) {
$arrayOrdersDistribution = Order::searchAll([
Order::tableName() . '.id_distribution' => $distribution->id
]);
$arraySubscriptions = self::searchByDate($date);
foreach ($arraySubscriptions as $subscription) {
if (!$subscription->hasOrderAlreadyExist($arrayOrdersDistribution)) {
$subscription->add($date);
}
}

}
}

/**
* Informe s'il existe une commande correspond à l'abonnement courant.
*
* @param array $arrayOrders
* @return boolean
*/
public function hasOrderAlreadyExist($arrayOrders)
{
if (is_array($arrayOrders) && count($arrayOrders) > 0) {
foreach ($arrayOrders as $order) {
if ((($order->id_user > 0 && $order->id_user == $this->id_user) ||
(!$order->id_user && $order->username == $this->username)) &&
$order->id_point_sale == $this->id_point_sale) {
return true;
}
}
}

return false;
}
$orders = Order::find()
->joinWith('distribution')
->where('distribution.id_producer = :id_producer')
->andWhere($conditionDistributionDate)
->andWhere('distribution.date >= :date_begin')
->andWhere('order.id_subscription = :id_subscription') ;
if($this->date_end) {
$orders->andWhere('distribution.date <= :date_end') ;
$params[':date_end'] = $this->date_end ;

/**
* Retourne les abonnements pour une date donnée.
*
* @param string $date
* @return array
*/
public static function searchByDate($date)
{
$date = date('Y-m-d', strtotime($date));

$subscriptions = Subscription::searchAll();

$arrSubscriptions = [];

foreach ($subscriptions as $s) {
if ($date >= $s->date_begin &&
(!$s->date_end || $date <= $s->date_end) &&
$s->matchWith($date)) {
$arrSubscriptions[] = $s;
}
}

return $arrSubscriptions;
}

$orders->params($params) ;
$ordersArray = $orders->all() ;
$configCredit = Producer::getConfig('credit') ;
if($ordersArray && count($ordersArray)) {
foreach($ordersArray as $order) {
$theOrder = Order::searchOne(['id' => $order->id]) ;

// remboursement de la commande
if ($theOrder->id_user && $theOrder->getAmount(Order::AMOUNT_PAID) && $configCredit) {
$theOrder->saveCreditHistory(
CreditHistory::TYPE_REFUND,
$theOrder->getAmount(Order::AMOUNT_PAID),
$theOrder->distribution->id_producer,
$theOrder->id_user,
User::getCurrentId()
);
/**
* Valide le fait qu'un abonnement est bien compatible avec une date donnée.
*
* @param string $date
* @return boolean
*/
public function matchWith($date)
{
$arrayDays = [
1 => 'monday',
2 => 'tuesday',
3 => 'wednesday',
4 => 'thursday',
5 => 'friday',
6 => 'saturday',
7 => 'sunday'
];

$nbDays = (strtotime($date) - strtotime($this->date_begin)) / (24 * 60 * 60);
if (round($nbDays) % ($this->week_frequency * 7) < 7) {
$numDay = date('N', strtotime($date));
$day = $arrayDays[$numDay];
if ($this->$day) {
return true;
}
}
ProductOrder::deleteAll(['id_order' => $order->id]) ;
$order->delete() ;
}

return false;
}
}
public function updateIncomingDistributions($update = false)
{
$matchedDistributionsArray = $this->searchMatchedIncomingDistributions() ;
if($update) {
$this->deleteOrdersIncomingDistributions() ;

/**
* Recherche les distributions futures où l'abonnement peut s'appliquer.
*
* @return array
*/
public function searchMatchedIncomingDistributions()
{
$producer = GlobalParam::getCurrentProducer();
$params = [
':date_earliest_order' => $producer->getEarliestDateOrder(),
':date_begin' => date('Y-m-d', strtotime($this->date_begin)),
':id_producer' => GlobalParam::getCurrentProducerId()
];

$incomingDistributions = Distribution::find()
->where('id_producer = :id_producer')
->andWhere('date >= :date_begin')
->andWhere('date >= :date_earliest_order');

if ($this->date_end) {
$incomingDistributions->andWhere('date < :date_end');
$params[':date_end'] = date('Y-m-d', strtotime($this->date_end));
}

$incomingDistributions->orderBy('date ASC');

$incomingDistributions->params($params);
$incomingDistributionsArray = $incomingDistributions->all();

$matchedIncomingDistributionsArray = [];
foreach ($incomingDistributionsArray as $incomingDistribution) {
if ($this->matchWith($incomingDistribution->date)) {
$matchedIncomingDistributionsArray[] = $incomingDistribution;
}
}

return $matchedIncomingDistributionsArray;
}
if(count($matchedDistributionsArray)) {
foreach($matchedDistributionsArray as $distribution) {
$this->add($distribution->date) ;
}

public function deleteOrdersIncomingDistributions()
{
$params = [
':id_producer' => GlobalParam::getCurrentProducerId(),
':date_today' => date('Y-m-d'),
':date_begin' => $this->date_begin,
':id_subscription' => $this->id
];


$orderDeadline = Producer::getConfig('order_deadline');
$hour = date('G');

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

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

if ($this->date_end) {
$orders->andWhere('distribution.date <= :date_end');
$params[':date_end'] = $this->date_end;
}

$orders->params($params);

$ordersArray = $orders->all();
$configCredit = Producer::getConfig('credit');

if ($ordersArray && count($ordersArray)) {
foreach ($ordersArray as $order) {

$theOrder = Order::searchOne(['id' => $order->id]);

// remboursement de la commande
if ($theOrder->id_user && $theOrder->getAmount(Order::AMOUNT_PAID) && $configCredit) {
$theOrder->saveCreditHistory(
CreditHistory::TYPE_REFUND,
$theOrder->getAmount(Order::AMOUNT_PAID),
$theOrder->distribution->id_producer,
$theOrder->id_user,
User::getCurrentId()
);
}

ProductOrder::deleteAll(['id_order' => $order->id]);
$order->delete();
}
}
}
}
/**
* Retourne true si des unités des ProductSubscription ne correspondent pas
* aux Product.
*
* @return boolean
*/
public function hasUnitsNotMatch()
{
if(isset($this->productSubscription) && is_array($this->productSubscription)) {
foreach($this->productSubscription as $productSubscription) {
if(isset($productSubscription->product) && $productSubscription->unit != $productSubscription->product->unit) {
return true ;

public function updateIncomingDistributions($update = false)
{
$matchedDistributionsArray = $this->searchMatchedIncomingDistributions();

if ($update) {
$this->deleteOrdersIncomingDistributions();
}

if (count($matchedDistributionsArray)) {
foreach ($matchedDistributionsArray as $distribution) {
$this->add($distribution->date);
}
}
}
}
return false ;
}


}

+ 1
- 31
common/models/SubscriptionForm.php View File

@@ -166,37 +166,7 @@ class SubscriptionForm extends Model
$newProductSubscription = new ProductSubscription;
$newProductSubscription->id_subscription = $subscription->id;
$newProductSubscription->id_product = $idProduct;
if($this->isAdmin) {
$unit = (Yii::$app->getRequest()->post('product_unit_'.$idProduct)) ? Yii::$app->getRequest()->post('product_unit_'.$idProduct) : $product->unit ;
$newProductSubscription->unit = $unit;
$step = (Yii::$app->getRequest()->post('product_step_'.$idProduct)) ? Yii::$app->getRequest()->post('product_step_'.$idProduct) : $product->step ;
$newProductSubscription->step = $step;
$price = (Yii::$app->getRequest()->post('product_price_'.$idProduct)) ? Yii::$app->getRequest()->post('product_price_'.$idProduct) : $product->price ;
$newProductSubscription->price = $price;
}
else {
if(isset($productsSubscriptionsArray) && is_array($productsSubscriptionsArray)) {
foreach($productsSubscriptionsArray as $productSubscription) {
if($productSubscription->id_product == $idProduct) {
$newProductSubscription->unit = $productSubscription->unit ;
$newProductSubscription->step = $productSubscription->step ;
$newProductSubscription->price = $productSubscription->price ;
}
}
}
if(!$newProductSubscription->unit) {
$newProductSubscription->unit = $product->unit ;
}
if(!$newProductSubscription->step) {
$newProductSubscription->step = $product->step;
}
if(!$newProductSubscription->price) {
$newProductSubscription->price = $product->price;
}
}
$newProductSubscription->quantity = $quantity / Product::$unitsArray[$newProductSubscription->unit]['coefficient'];
$newProductSubscription->quantity = $quantity / Product::$unitsArray[$product->unit]['coefficient'];

$newProductSubscription->save();
}

+ 42
- 2
common/web/js/utils.js View File

@@ -2,18 +2,56 @@
* Created by fab on 30/12/17.
*/


/**
* Retourne un prix sans taxe sur base du prix avec tax
*
* @param priceWithTax
* @param taxRate
* @returns {string}
*/
function getPrice(priceWithTax, taxRate) {
return parseFloat(parseFloat(priceWithTax) / (taxRate + 1)).toFixed(2);
}

/**
* Retourne un prix avec taxe sur base du prix sans taxe
*
* @param priceWithoutTax
* @param taxRate
* @returns {string}
*/
function getPriceWithTax(priceWithoutTax, taxRate) {
return parseFloat(parseFloat(priceWithoutTax) * (taxRate + 1)).toFixed(2);
}

/**
* Formate un prix en l'arrondissant et en ajoutant le sigle de la monnaie
*
* @param price
* @returns {string}
*/
function formatPrice(price) {
return Number(price).toFixed(2).replace('.', ',') + ' €';
}

/**
* Formate une date au format jj/mm/yyyy
* @param date
* @returns {*}
*/
function formatDate(date) {
if (date) {
return ('0' + date.getDate()).slice(-2) + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + '/' + date.getFullYear();
}
return false;
}

/**
* Equivalent de console.log (ne déclenche pas d'erreur si la console est fermé)
*
* @param msg
*/

function log(msg) {
try {
console.log(msg);
@@ -22,7 +60,9 @@ function log(msg) {
}
}

//Convertit un formulaire ou un objet en JSON (utilisé pour l'envoie de donnée en ajax)
/**
* Convertit un formulaire ou un objet en JSON (utilisé pour l'envoie de donnée en ajax)
*/
$.fn.serializeObject = function () {
var o = {};
var a = this.serializeArray();

+ 35
- 0
console/migrations/m200108_145508_module_bl_devis_factures_suppression_price_unit_step_product_subscription.php View File

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

use yii\db\Migration;

class m200108_145508_module_bl_devis_factures_suppression_price_unit_step_product_subscription extends Migration
{
public function safeUp()
{
$this->dropColumn('product_subscription', 'unit') ;
$this->dropColumn('product_subscription', 'step') ;
$this->dropColumn('product_subscription', 'price') ;
}

public function safeDown()
{
echo "m200108_145508_module_bl_devis_factures_suppression_price_unit_step_product_subscription cannot be reverted.\n";

return false;
}

/*
// Use up()/down() to run migration code without a transaction.
public function up()
{

}

public function down()
{
echo "m200108_145508_module_bl_devis_factures_suppression_price_unit_step_product_subscription cannot be reverted.\n";

return false;
}
*/
}

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

@@ -38,6 +38,7 @@

namespace producer\controllers;

use common\helpers\Debug;
use common\helpers\GlobalParam;
use common\models\ProductDistribution;
use common\models\User;
@@ -605,15 +606,19 @@ class OrderController extends ProducerBaseController
$query->andOnCondition('product_distribution.id_distribution = ' . $distribution->id);
}])
->orderBy('product_distribution.active DESC, order ASC')
->asArray()
->all();

$indexProduct = 0;
foreach ($productsArray as &$product) {

if (!isset($product['productDistribution'][0])) {
$product['productDistribution'][0] = $distribution->linkProduct($product);
}
$product = array_merge(
$product->getAttributes(),
[
'price_with_tax' => $product->getPriceWithTax(),
'productDistribution' => $product['productDistribution']
]
);


$coefficient_unit = Product::$unitsArray[$product['unit']]['coefficient'];

@@ -642,6 +647,7 @@ class OrderController extends ProducerBaseController
$product['wording_unit'] = Product::strUnit($product['unit'], 'wording_unit', true);
}
$product['coefficient_unit'] = $coefficient_unit;

if ($product['quantity_remaining'] < 0) $product['quantity_remaining'] = 0;
$product['index'] = $indexProduct++;
}

+ 284
- 289
producer/controllers/SubscriptionController.php View File

@@ -1,311 +1,306 @@
<?php

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

namespace producer\controllers;

use common\helpers\Debug;
use common\helpers\GlobalParam;
use common\models\SubscriptionForm ;
use common\models\SubscriptionSearch ;
use common\models\Product ;
use common\models\SubscriptionForm;
use common\models\SubscriptionSearch;
use common\models\Product;

class SubscriptionController extends ProducerBaseController
class SubscriptionController extends ProducerBaseController
{
var $enableCsrfValidation = false;

public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'roles' => ['@'],
]
],
],
];
}

/**
* Liste les commandes récurrente du producteur.
*
* @return string
*/
public function actionIndex()
{
$searchModel = new SubscriptionSearch ;
$searchModel->id_user = User::getCurrentId() ;
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider
]);
}

public function actionAjaxProcess()
{
// form
$model = new SubscriptionForm;
$model->id_producer = GlobalParam::getCurrentProducerId();
$model->id_user = User::getCurrentId() ;
$posts = Yii::$app->request->post() ;
$idSubscription = (int) $posts['idSubscription'] ;
$isUpdate = false ;
if($idSubscription) {
$subscription = Subscription::findOne($idSubscription);
if ($subscription) {
$model->id = $idSubscription;
$isUpdate = true ;
}
}
if ($model->load($posts) && $model->validate()
&& $model->save())
{
$subscription = Subscription::searchOne([
'id' => $model->id
]) ;
$subscription->updateIncomingDistributions($isUpdate) ;
if($isUpdate) {
Yii::$app->getSession()->setFlash('success', 'Abonnement modifié');
}
else {
Yii::$app->getSession()->setFlash('success', 'Abonnement ajouté');
}
var $enableCsrfValidation = false;

public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'roles' => ['@'],
]
],
],
];
}
}
/**
* Crée une commande récurrente.
*
* @return string
*/
public function actionForm($id = 0)
{
return $this->render('form', [
'idSubscription' => (int) $id
]);
}

/**
* Modifie une commande récurrente.
*
* @param integer $id
* @return string
* @throws NotFoundHttpException
*/
public function actionUpdate($id)
{
// form
$model = new SubscriptionForm;
$subscription = Subscription::findOne($id);
if ($subscription) {
$model->id = $id;
$model->id_producer = $subscription->id_producer;
$model->id_user = $subscription->id_user;
$model->username = $subscription->username;
$model->id_point_sale = $subscription->id_point_sale;
$model->date_begin = date('d/m/Y', strtotime($subscription->date_begin));
if (strlen($subscription->date_end)) {
$model->date_end = date('d/m/Y', strtotime($subscription->date_end));
}
$model->monday = $subscription->monday;
$model->tuesday = $subscription->tuesday;
$model->wednesday = $subscription->wednesday;
$model->thursday = $subscription->thursday;
$model->friday = $subscription->friday;
$model->saturday = $subscription->saturday;
$model->sunday = $subscription->sunday;
$model->auto_payment = $subscription->auto_payment;
$model->week_frequency = $subscription->week_frequency;

// produits
$arrayProductsSubscription = ProductSubscription::searchAll([
'id_subscription' => $model->id
]) ;
foreach ($arrayProductsSubscription as $productSubscription) {
$model->products['product_' . $productSubscription->id_product] = $productSubscription->quantity;
}
} else {
throw new NotFoundHttpException('L\'abonnement est introuvable.', 404);

/**
* Liste les commandes récurrente du producteur.
*
* @return string
*/
public function actionIndex()
{
$searchModel = new SubscriptionSearch;
$searchModel->id_user = User::getCurrentId();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);

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

// produits
$productsArray = Product::searchAll() ;

if ($model->load(Yii::$app->request->post()) && $model->validate()) {
if (!strlen($model->date_end)) {
$model->date_end = null;
}
if ($model->save()) {
Yii::$app->getSession()->setFlash('success', 'Abonnement modifié');
$subscription = Subscription::findOne($model->id) ;
$matchedDistributionsArray = $subscription->searchMatchedIncomingDistributions() ;
if(count($matchedDistributionsArray)) {
return $this->redirect(['subscription/update-distributions', 'idSubscription' => $subscription->id,'update' => true]);
public function actionAjaxProcess()
{
// form
$model = new SubscriptionForm;
$model->id_producer = GlobalParam::getCurrentProducerId();
$model->id_user = User::getCurrentId();

$posts = Yii::$app->request->post();

$idSubscription = (int)$posts['idSubscription'];
$isUpdate = false;
if ($idSubscription) {
$subscription = Subscription::findOne($idSubscription);
if ($subscription) {
$model->id = $idSubscription;
$isUpdate = true;
}
}
else {
return $this->redirect(['subscription/index']);

if ($model->load($posts) && $model->validate()
&& $model->save()) {
$subscription = Subscription::searchOne([
'id' => $model->id
]);
$subscription->updateIncomingDistributions($isUpdate);

if ($isUpdate) {
Yii::$app->getSession()->setFlash('success', 'Abonnement modifié');
} else {
Yii::$app->getSession()->setFlash('success', 'Abonnement ajouté');
}
}
}
}

return $this->render('update', [
'model' => $model,
'productsArray' => $productsArray
]);
}

/**
* Supprime un abonnement
*
* @param integer $id
*/
public function actionDelete($id)
{
$subscription = Subscription::searchOne([
'id' => $id
]) ;
ProductSubscription::deleteAll(['id_subscription' => $id]);
$subscription->deleteOrdersIncomingDistributions() ;
$subscription->delete();
Yii::$app->getSession()->setFlash('success', 'Abonnement supprimé');
return $this->redirect(['subscription/index']);
}
public function actionAjaxInfos($idSubscription = 0)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$params = [] ;
if($idSubscription > 0) {
$arrayProductsSubscription = ProductSubscription::searchAll([
'id_subscription' => $idSubscription
]) ;
/**
* Crée une commande récurrente.
*
* @return string
*/
public function actionForm($id = 0)
{
return $this->render('form', [
'idSubscription' => (int)$id
]);
}
// Produits
$productsArray = Product::searchAll() ;
$indexProduct = 0 ;
foreach($productsArray as &$product) {
$quantity = 0 ;
$coefficientUnit = Product::$unitsArray[$product->unit]['coefficient'] ;
if(isset($arrayProductsSubscription) && count($arrayProductsSubscription)) {
foreach ($arrayProductsSubscription as $productSubscription) {
if($product->id == $productSubscription->id_product) {
$coefficientUnit = Product::$unitsArray[$productSubscription->unit]['coefficient'] ;
$quantity = $productSubscription->quantity * $coefficientUnit;
$product->step = $productSubscription->step;
$product->unit = $productSubscription->unit;
$product->price = $productSubscription->price;
}

/**
* Modifie une commande récurrente.
*
* @param integer $id
* @return string
* @throws NotFoundHttpException
*/
public function actionUpdate($id)
{
// form
$model = new SubscriptionForm;
$subscription = Subscription::findOne($id);
if ($subscription) {
$model->id = $id;
$model->id_producer = $subscription->id_producer;
$model->id_user = $subscription->id_user;
$model->username = $subscription->username;
$model->id_point_sale = $subscription->id_point_sale;
$model->date_begin = date('d/m/Y', strtotime($subscription->date_begin));
if (strlen($subscription->date_end)) {
$model->date_end = date('d/m/Y', strtotime($subscription->date_end));
}

$model->monday = $subscription->monday;
$model->tuesday = $subscription->tuesday;
$model->wednesday = $subscription->wednesday;
$model->thursday = $subscription->thursday;
$model->friday = $subscription->friday;
$model->saturday = $subscription->saturday;
$model->sunday = $subscription->sunday;
$model->auto_payment = $subscription->auto_payment;
$model->week_frequency = $subscription->week_frequency;

// produits
$arrayProductsSubscription = ProductSubscription::searchAll([
'id_subscription' => $model->id
]);

foreach ($arrayProductsSubscription as $productSubscription) {
$model->products['product_' . $productSubscription->id_product] = $productSubscription->quantity;
}
} else {
throw new NotFoundHttpException('L\'abonnement est introuvable.', 404);
}
}
$product = array_merge(
$product->getAttributes(),
[
'index' => $indexProduct ++,
'quantity_form' => $quantity,
'coefficient_unit' => $coefficientUnit,
'wording_unit' => Product::strUnit($product->unit, 'wording_unit', true),
'wording_short' => Product::strUnit($product->unit, 'wording_short'),
]
) ;

// produits
$productsArray = Product::searchAll();

if ($model->load(Yii::$app->request->post()) && $model->validate()) {
if (!strlen($model->date_end)) {
$model->date_end = null;
}
if ($model->save()) {
Yii::$app->getSession()->setFlash('success', 'Abonnement modifié');

$subscription = Subscription::findOne($model->id);
$matchedDistributionsArray = $subscription->searchMatchedIncomingDistributions();
if (count($matchedDistributionsArray)) {
return $this->redirect(['subscription/update-distributions', 'idSubscription' => $subscription->id, 'update' => true]);
} else {
return $this->redirect(['subscription/index']);
}
}
}

return $this->render('update', [
'model' => $model,
'productsArray' => $productsArray
]);
}
$params['products'] = $productsArray ;
$pointsSaleArray = PointSale::searchAll() ;
foreach($pointsSaleArray as &$pointSale) {
$pointSale = array_merge($pointSale->getAttributes(),[
'userPointSale' => ($pointSale->userPointSale ? $pointSale->userPointSale[0] : '')
]) ;
if($pointSale['code'] && strlen($pointSale['code'])) {
$pointSale['code'] = '***' ;
}

/**
* Supprime un abonnement
*
* @param integer $id
*/
public function actionDelete($id)
{
$subscription = Subscription::searchOne([
'id' => $id
]);
ProductSubscription::deleteAll(['id_subscription' => $id]);
$subscription->deleteOrdersIncomingDistributions();
$subscription->delete();
Yii::$app->getSession()->setFlash('success', 'Abonnement supprimé');
return $this->redirect(['subscription/index']);
}
$params['points_sale'] = $pointsSaleArray ;
if($idSubscription > 0) {
$subscription = Subscription::searchOne([
'id' => $idSubscription
]) ;
if(!$subscription || $subscription->id_user != User::getCurrentId()) {
throw new UserException('Abonnement introuvable') ;
}
else {
$params = array_merge($params, $subscription->getAttributes()) ;
}

public function actionAjaxInfos($idSubscription = 0)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$params = [];


if ($idSubscription > 0) {
$arrayProductsSubscription = ProductSubscription::searchAll([
'id_subscription' => $idSubscription
]);
}

// Produits
$productsArray = Product::searchAll();
$indexProduct = 0;
foreach ($productsArray as &$product) {

$quantity = 0;
$coefficientUnit = Product::$unitsArray[$product->unit]['coefficient'];
if (isset($arrayProductsSubscription) && count($arrayProductsSubscription)) {
foreach ($arrayProductsSubscription as $productSubscription) {
if ($product->id == $productSubscription->id_product) {
$coefficientUnit = Product::$unitsArray[$productSubscription->product->unit]['coefficient'];
$quantity = $productSubscription->quantity * $coefficientUnit;
}
}
}

$product = array_merge(
$product->getAttributes(),
[
'index' => $indexProduct++,
'quantity_form' => $quantity,
'coefficient_unit' => $coefficientUnit,
'wording_unit' => Product::strUnit($product->unit, 'wording_unit', true),
'wording_short' => Product::strUnit($product->unit, 'wording_short'),
'price_with_tax' => $product->getPriceWithTax(),
]
);
}

$params['products'] = $productsArray;

$pointsSaleArray = PointSale::searchAll();
foreach ($pointsSaleArray as &$pointSale) {
$pointSale = array_merge($pointSale->getAttributes(), [
'userPointSale' => ($pointSale->userPointSale ? $pointSale->userPointSale[0] : '')
]);
if ($pointSale['code'] && strlen($pointSale['code'])) {
$pointSale['code'] = '***';
}
}

$params['points_sale'] = $pointsSaleArray;

if ($idSubscription > 0) {
$subscription = Subscription::searchOne([
'id' => $idSubscription
]);

if (!$subscription || $subscription->id_user != User::getCurrentId()) {
throw new UserException('Abonnement introuvable');
} else {
$params = array_merge($params, $subscription->getAttributes());
}
}

return $params;
}
return $params ;
}
/**
* Vérifie le code saisi pour un point de vente.
*
* @param integer $idPointSale
* @param string $code
* @return boolean
*/
public function actionAjaxValidateCodePointSale($idPointSale, $code)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$pointSale = PointSale::findOne($idPointSale);
if ($pointSale) {
if ($pointSale->validateCode($code)) {
return 1;
}

/**
* Vérifie le code saisi pour un point de vente.
*
* @param integer $idPointSale
* @param string $code
* @return boolean
*/
public function actionAjaxValidateCodePointSale($idPointSale, $code)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

$pointSale = PointSale::findOne($idPointSale);
if ($pointSale) {
if ($pointSale->validateCode($code)) {
return 1;
}
}
return 0;
}
return 0;
}
}

+ 2
- 2
producer/views/order/order.php View File

@@ -195,7 +195,7 @@ $this->setTitle('Commander') ;
<div class="recipe" v-if="product.recipe.length">{{ product.recipe }}</div>
</td>
<td class="price-unit">
{{ formatPrice(product.price) }}<br /><span class="unit">{{ product.wording_unit }}</span>
{{ formatPrice(product.price_with_tax) }}<br /><span class="unit">{{ product.wording_unit }}</span>
</td>
<td class="td-quantity">
<div class="input-group">
@@ -210,7 +210,7 @@ $this->setTitle('Commander') ;
</div>
</td>
<td class="price-total">
{{ formatPrice(product.price * (product.quantity_form / product.coefficient_unit )) }}
{{ formatPrice(product.price_with_tax * (product.quantity_form / product.coefficient_unit )) }}
</td>
</tr>
<tr class="total">

+ 3
- 2
producer/views/subscription/_form.php View File

@@ -215,7 +215,8 @@ use common\models\PointSale ;
<div class="recipe" v-if="product.recipe.length">{{ product.recipe }}</div>
</td>
<td class="price-unit">
{{ formatPrice(product.price) }}<br /><span class="unit">{{ product.wording_unit }}</span>
{{ formatPrice(product.price_with_tax) }}<br /><span class="unit">{{ product.wording_unit }}</span>

</td>
<td class="quantity">
<div class="input-group">
@@ -232,7 +233,7 @@ use common\models\PointSale ;
</div>
</td>
<td class="price-total">
{{ formatPrice(product.price * (product.quantity_form / product.coefficient_unit )) }}
{{ formatPrice(product.price_with_tax * (product.quantity_form / product.coefficient_unit )) }}
</td>
</tr>
<tr class="total">

+ 1
- 1
producer/views/subscription/index.php View File

@@ -54,7 +54,7 @@ $columns = [
foreach($model->productSubscription as $productSubscription)
{
if(isset($productSubscription->product)) {
$html .= Html::encode($productSubscription->product->name).' ('.($productSubscription->quantity * Product::$unitsArray[$productSubscription->unit]['coefficient']) . '&nbsp'.Product::strUnit($productSubscription->unit, 'wording_short').')<br />' ;
$html .= Html::encode($productSubscription->product->name).' ('.($productSubscription->quantity * Product::$unitsArray[$productSubscription->product->unit]['coefficient']) . '&nbsp'.Product::strUnit($productSubscription->product->unit, 'wording_short').')<br />' ;
}
else {
$html .= 'Produit non défini<br />' ;

+ 2
- 8
producer/web/js/vuejs/order-order.js View File

@@ -89,13 +89,7 @@ var app = new Vue({
}
return false ;
},
formatPrice: function(price) {
var isNumberRegExp = new RegExp(/^[-+]?[0-9]+(\.[0-9]+)*$/);
if(isNumberRegExp.test(price)) {
return Number(price).toFixed(2).replace('.',',')+' €' ;
}
return '0 €' ;
},
formatPrice: formatPrice,
getPointSale: function(idPointSale) {
for(var key in this.pointsSale) {
if(this.pointsSale[key].id == idPointSale) {
@@ -297,7 +291,7 @@ var app = new Vue({
var price = 0 ;
for(var key in this.products) {
if(this.products[key].quantity_form > 0) {
price += (this.products[key].quantity_form / this.products[key].coefficient_unit) * this.products[key].price ;
price += (this.products[key].quantity_form / this.products[key].coefficient_unit) * this.products[key].price_with_tax ;
}
}
if(format) {

+ 175
- 186
producer/web/js/vuejs/subscription-form.js View File

@@ -1,4 +1,3 @@

var app = new Vue({
el: '#app-subscription-form',
data: {
@@ -25,186 +24,177 @@ var app = new Vue({
lastCountDays: 0,
comment: ''
},
mounted: function() {
mounted: function () {
this.init();
},
methods: {
init: function() {
var app = this ;
if($('#subscription-id').val() != 0) {
this.idSubscription = $('#subscription-id').val() ;
log: log,
init: function () {
var app = this;
if ($('#subscription-id').val() != 0) {
this.idSubscription = $('#subscription-id').val();
}
this.dateBegin = new Date() ;

axios.get("ajax-infos",{params: {idSubscription : this.idSubscription}})
.then(function(response) {
app.products = response.data.products ;
app.pointsSale = response.data.points_sale ;
if(app.idSubscription > 0) {
app.validatePointSale(response.data.id_point_sale) ;
app.weekFrequency = response.data.week_frequency ;
app.autoPayment = response.data.auto_payment ;
var arrayDateBegin = response.data.date_begin.split('-') ;
app.dateBegin = new Date(arrayDateBegin[0], arrayDateBegin[1] - 1, arrayDateBegin[2]) ;
if(response.data.date_end && response.data.date_end.length > 0) {
var arrayDateEnd = response.data.date_begin.split('-') ;
app.dateEnd = new Date(arrayDateEnd[0], arrayDateEnd[1] - 1, arrayDateEnd[2]) ;
this.dateBegin = new Date();

axios.get("ajax-infos", {params: {idSubscription: this.idSubscription}})
.then(function (response) {

app.products = response.data.products;
app.pointsSale = response.data.points_sale;

if (app.idSubscription > 0) {
app.validatePointSale(response.data.id_point_sale);
app.weekFrequency = response.data.week_frequency;
app.autoPayment = response.data.auto_payment;
var arrayDateBegin = response.data.date_begin.split('-');
app.dateBegin = new Date(arrayDateBegin[0], arrayDateBegin[1] - 1, arrayDateBegin[2]);
if (response.data.date_end && response.data.date_end.length > 0) {
var arrayDateEnd = response.data.date_begin.split('-');
app.dateEnd = new Date(arrayDateEnd[0], arrayDateEnd[1] - 1, arrayDateEnd[2]);
}
app.monday = response.data.monday ;
app.tuesday = response.data.tuesday ;
app.wednesday = response.data.wednesday ;
app.thursday = response.data.thursday ;
app.friday = response.data.friday ;
app.saturday = response.data.saturday ;
app.sunday = response.data.sunday ;
app.comment = response.data.comment ;
app.monday = response.data.monday;
app.tuesday = response.data.tuesday;
app.wednesday = response.data.wednesday;
app.thursday = response.data.thursday;
app.friday = response.data.friday;
app.saturday = response.data.saturday;
app.sunday = response.data.sunday;
app.comment = response.data.comment;
}
app.loading = false ;
});
},
formatDate: function(date) {
if(date) {
return ('0' + date.getDate()).slice(-2) + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + '/' + date.getFullYear() ;
}
return false ;

app.loading = false;
});

},
pointSaleClick: function(event) {
var app = this ;
var idPointSale = event.currentTarget.getAttribute('data-id-point-sale') ;
var hasCode = event.currentTarget.getAttribute('data-code') ;
if(hasCode) {
axios.get('ajax-validate-code-point-sale',{params: {
idPointSale: idPointSale,
code: this.pointsSaleCodes[idPointSale]
}}).then(function(response) {
if(response.data) {
app.getPointSale(idPointSale).invalid_code = false ;
app.validatePointSale(idPointSale) ;
formatDate: formatDate,

pointSaleClick: function (event) {
var app = this;
var idPointSale = event.currentTarget.getAttribute('data-id-point-sale');
var hasCode = event.currentTarget.getAttribute('data-code');

if (hasCode) {
axios.get('ajax-validate-code-point-sale', {
params: {
idPointSale: idPointSale,
code: this.pointsSaleCodes[idPointSale]
}
else {
app.getPointSale(idPointSale).invalid_code = true ;
}).then(function (response) {
if (response.data) {
app.getPointSale(idPointSale).invalid_code = false;
app.validatePointSale(idPointSale);
} else {
app.getPointSale(idPointSale).invalid_code = true;
Vue.set(app.pointsSaleCodes, idPointSale, '');
}
}) ;
}
else {
this.validatePointSale(idPointSale) ;
});
} else {
this.validatePointSale(idPointSale);
}
},
validatePointSale: function(idPointSale) {
if(this.idPointSaleActive != idPointSale) {
this.monday = false ;
this.tuesday = false ;
this.wednesday = false ;
this.thursday = false ;
this.friday = false ;
this.saturday = false ;
this.sunday = false ;
validatePointSale: function (idPointSale) {
if (this.idPointSaleActive != idPointSale) {
this.monday = false;
this.tuesday = false;
this.wednesday = false;
this.thursday = false;
this.friday = false;
this.saturday = false;
this.sunday = false;
}
this.pointSaleActive = this.getPointSale(idPointSale) ;
this.idPointSaleActive = idPointSale ;
opendistrib_scroll('step-date') ;
this.pointSaleActive = this.getPointSale(idPointSale);
this.idPointSaleActive = idPointSale;
opendistrib_scroll('step-date');
},
getPointSale: function(idPointSale) {
for(var key in this.pointsSale) {
if(this.pointsSale[key].id == idPointSale) {
return this.pointsSale[key] ;
getPointSale: function (idPointSale) {
for (var key in this.pointsSale) {
if (this.pointsSale[key].id == idPointSale) {
return this.pointsSale[key];
}
}
},
dayChange: function() {
console.log(this.monday+' '+this.tuesday+' '+this.wednesday+' '+
this.thursday+' '+this.friday+' '+this.saturday+' '+this.sunday) ;
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)
+ Number(this.thursday) + Number(this.friday) + Number(this.saturday)
+ Number(this.sunday) ;
if(count == 1 && this.lastCountDays == 0) {
this.lastCountDays = count ;
opendistrib_scroll('step-days') ;
+ Number(this.thursday) + Number(this.friday) + Number(this.saturday)
+ Number(this.sunday);
if (count == 1 && this.lastCountDays == 0) {
this.lastCountDays = count;
opendistrib_scroll('step-days');
}
},
checkProductAvailable: function(product) {
checkProductAvailable: function (product) {
var available = product.active &&
(!this.monday || (this.monday && product.monday)) &&
(!this.tuesday || (this.tuesday && product.tuesday)) &&
(!this.wednesday || (this.wednesday && product.wednesday)) &&
(!this.thursday || (this.thursday && product.thursday)) &&
(!this.friday || (this.friday && product.friday)) &&
(!this.saturday || (this.saturday && product.saturday)) &&
(!this.sunday || (this.sunday && product.sunday)) ;
if(!available) {
product.quantity_form = 0 ;
(!this.monday || (this.monday && product.monday)) &&
(!this.tuesday || (this.tuesday && product.tuesday)) &&
(!this.wednesday || (this.wednesday && product.wednesday)) &&
(!this.thursday || (this.thursday && product.thursday)) &&
(!this.friday || (this.friday && product.friday)) &&
(!this.saturday || (this.saturday && product.saturday)) &&
(!this.sunday || (this.sunday && product.sunday));
if (!available) {
product.quantity_form = 0;
}
return available ;
return available;
},
checkOneProductAvailable: function() {
var count = 0 ;
for(key in this.products) {
if(this.checkProductAvailable(this.products[key])) {
count ++ ;
checkOneProductAvailable: function () {
var count = 0;
for (key in this.products) {
if (this.checkProductAvailable(this.products[key])) {
count++;
}
}
return count ;
return count;
},
productQuantityClick: function(product, quantity) {
if( this.products[product.index].quantity_form + quantity >= 0) {
this.products[product.index].quantity_form += quantity ;
productQuantityClick: function (product, quantity) {
if (this.products[product.index].quantity_form + quantity >= 0) {
this.products[product.index].quantity_form += quantity;
}
},
oneProductOrdered: function() {
for(var key in this.products) {
if(this.products[key].quantity_form > 0) {
return true ;
oneProductOrdered: function () {
for (var key in this.products) {
if (this.products[key].quantity_form > 0) {
return true;
}
}
return false ;
},
formatPrice: function(price) {
var isNumberRegExp = new RegExp(/^[-+]?[0-9]+(\.[0-9]+)*$/);
if(isNumberRegExp.test(price) && price > 0) {
return Number(price).toFixed(2).replace('.',',')+' €' ;
}
return '--' ;
return false;
},
priceTotal: function(format) {
var price = 0 ;
for(var key in this.products) {
if(this.products[key].quantity_form > 0) {
price += (this.products[key].quantity_form / this.products[key].coefficient_unit) * this.products[key].price ;
formatPrice: formatPrice,
getPriceWithTax: getPriceWithTax,
priceTotal: function (format) {
var price = 0;
for (var key in this.products) {
if (this.products[key].quantity_form > 0) {
price += (this.products[key].quantity_form / this.products[key].coefficient_unit) * this.products[key].price_with_tax;
}
}
if(format) {
return this.formatPrice(price) ;
}
else {
return price ;
if (format) {
return this.formatPrice(price);
} else {
return price;
}
},
formSubmit: function() {
this.checkForm() ;
if(!this.errors.length && !this.disableSubmitButton) {
formSubmit: function () {
this.checkForm();
if (!this.errors.length && !this.disableSubmitButton) {

this.disableSubmitButton = true ;
this.disableSubmitButton = true;

var productsArray = {} ;
for(var key in this.products) {
if( this.products[key].quantity_form != null &&
var productsArray = {};
for (var key in this.products) {
if (this.products[key].quantity_form != null &&
this.products[key].quantity_form > 0) {
productsArray['product_'+this.products[key].id] = this.products[key].quantity_form ;
productsArray['product_' + this.products[key].id] = this.products[key].quantity_form;
}
}
axios.post('ajax-process', {
idSubscription: this.idSubscription,
SubscriptionForm: {
@@ -223,70 +213,69 @@ var app = new Vue({
products: productsArray,
comment: this.comment
}
}).then(function(response) {
window.location.href = opendistrib_base_url(true)+'subscription/index' ;
}).then(function (response) {
window.location.href = opendistrib_base_url(true) + 'subscription/index';
});
}
},
checkForm: function() {
var app = this ;
this.errors = [] ;
if(!this.idPointSaleActive) {
this.errors.push('Veuillez sélectionner un point de vente') ;
}
else {
if(this.pointSaleActive.code && this.pointSaleActive.code.length > 0) {
axios.get('ajax-validate-code-point-sale',{params: {
idPointSale: this.idPointSaleActive,
code: this.pointSaleActive.code
}}).then(function(response) {
if(response.data) {
app.pointsSale[idPointSale].invalid_code = false ;
checkForm: function () {
var app = this;
this.errors = [];

if (!this.idPointSaleActive) {
this.errors.push('Veuillez sélectionner un point de vente');
} else {
if (this.pointSaleActive.code && this.pointSaleActive.code.length > 0) {
axios.get('ajax-validate-code-point-sale', {
params: {
idPointSale: this.idPointSaleActive,
code: this.pointSaleActive.code
}
else {
app.pointsSale[idPointSale].invalid_code = true ;
}).then(function (response) {
if (response.data) {
app.pointsSale[idPointSale].invalid_code = false;
} else {
app.pointsSale[idPointSale].invalid_code = true;
Vue.set(app.pointsSaleCodes, idPointSale, '');
}
}) ;
});
}
}
var regexDate = /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/;
if(!this.dateBegin) {
this.errors.push('Veuillez sélectionner une date de début') ;
}
else {
if(!regexDate.test(this.formatDate(this.dateBegin))) {
this.errors.push('Mauvais format de date de début') ;

if (!this.dateBegin) {
this.errors.push('Veuillez sélectionner une date de début');
} else {
if (!regexDate.test(this.formatDate(this.dateBegin))) {
this.errors.push('Mauvais format de date de début');
}
}
if(this.dateEnd && this.dateEnd.length > 0 && !regexDate.test(this.formatDate(this.dateEnd))) {
this.errors.push('Mauvais format de date de fin') ;
if (this.dateEnd && this.dateEnd.length > 0 && !regexDate.test(this.formatDate(this.dateEnd))) {
this.errors.push('Mauvais format de date de fin');
}
if(this.weekFrequency != 1 && this.weekFrequency != 2 &&
if (this.weekFrequency != 1 && this.weekFrequency != 2 &&
this.weekFrequency != 3 && this.weekFrequency != 4) {
this.errors.push('Veuillez sélectionner une périodicité') ;
this.errors.push('Veuillez sélectionner une périodicité');
}
if(!this.monday && !this.tuesday && !this.wednesday && !this.thursday &&
if (!this.monday && !this.tuesday && !this.wednesday && !this.thursday &&
!this.friday && !this.saturday) {
this.errors.push('Veuillez sélectionner un jour de distribution') ;
this.errors.push('Veuillez sélectionner un jour de distribution');
}
if(!this.oneProductOrdered()) {
this.errors.push('Veuillez choisir au moins un produit') ;
if (!this.oneProductOrdered()) {
this.errors.push('Veuillez choisir au moins un produit');
}
if(this.errors.length) {
window.scroll(0, $('#page-title').position().top - 25) ;
if (this.errors.length) {
window.scroll(0, $('#page-title').position().top - 25);
}
}
}
});
});


Loading…
Cancel
Save