@@ -0,0 +1,62 @@ | |||
<?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. | |||
*/ | |||
namespace backend\assets; | |||
use yii\web\AssetBundle; | |||
use yii ; | |||
/** | |||
* @author Qiang Xue <qiang.xue@gmail.com> | |||
* @since 2.0 | |||
*/ | |||
class VuejsSubscriptionFormAsset extends \common\components\MyAssetBundle | |||
{ | |||
public $basePath = '@webroot'; | |||
public $baseUrl = '@web'; | |||
public $css = []; | |||
public $js = []; | |||
public $depends = [ | |||
'common\assets\CommonAsset' | |||
]; | |||
public function __construct() | |||
{ | |||
parent::__construct() ; | |||
$this->addAsset('js','js/vuejs/subscription-form.js') ; | |||
} | |||
} |
@@ -164,8 +164,13 @@ class DistributionController extends BackendController | |||
foreach($productsArray as &$theProduct) { | |||
$quantityOrder = Order::getProductQuantity($theProduct['id'], $ordersArray) ; | |||
$theProduct['quantity_ordered'] = $quantityOrder ; | |||
$theProduct['quantity_remaining'] = $theProduct['quantity_max'] - $quantityOrder ; | |||
if($theProduct['quantity_remaining'] < 0) $theProduct['quantity_remaining'] = 0 ; | |||
if(!is_numeric($theProduct['productDistribution'][0]['quantity_max'])) { | |||
$theProduct['quantity_remaining'] = null ; | |||
} | |||
else { | |||
$theProduct['quantity_remaining'] = $theProduct['productDistribution'][0]['quantity_max'] - $quantityOrder ; | |||
} | |||
$theProduct['quantity_form'] = 0 ; | |||
if($theProduct['productDistribution'][0]['active'] && $theProduct['productDistribution'][0]['quantity_max']) { | |||
@@ -181,11 +186,24 @@ class DistributionController extends BackendController | |||
// orders as array | |||
if($ordersArray) { | |||
foreach($ordersArray as &$order) { | |||
$productOrderArray = \yii\helpers\ArrayHelper::map($order->productOrder, 'id_product', 'quantity') ; | |||
foreach($ordersArray as &$order) { | |||
$productOrderArray = [] ; | |||
foreach($order->productOrder as $productOrder) { | |||
$productOrderArray[$productOrder->id_product] = [ | |||
'quantity' => $productOrder->quantity * Product::$unitsArray[$productOrder->unit]['coefficient'], | |||
'unit' => $productOrder->unit, | |||
] ; | |||
} | |||
/*$productOrderArray = \yii\helpers\ArrayHelper::map($order->productOrder, 'id_product', 'quantity') ; | |||
*/ | |||
foreach($productsArray as $product) { | |||
if(!isset($productOrderArray[$product['id']])) { | |||
$productOrderArray[$product['id']] = 0 ; | |||
$productOrderArray[$product['id']] = [ | |||
'quantity' => 0, | |||
'unit' => $product['unit'] | |||
] ; | |||
} | |||
} | |||
@@ -254,7 +272,10 @@ class DistributionController extends BackendController | |||
// order create | |||
$productOrderArray = [] ; | |||
foreach($productsArray as $product) { | |||
$productOrderArray[$product['id']] = 0 ; | |||
$productOrderArray[$product['id']] = [ | |||
'quantity' => 0, | |||
'unit' => $product['unit'] | |||
] ; | |||
} | |||
$json['order_create'] = [ | |||
'id_point_sale' => $idPointSaleDefault, | |||
@@ -443,7 +464,7 @@ class DistributionController extends BackendController | |||
foreach($pointSale->orders as $order) { | |||
$orderLine = [$order->getStrUser()] ; | |||
foreach($order->productOrder as $productOrder) { | |||
$orderLine[$productsIndexArray[$productOrder->id_product]] = $productOrder->quantity ; | |||
$orderLine[$productsIndexArray[$productOrder->id_product]] = $productOrder->quantity . ' '.Product::strUnit($productOrder->unit, 'wording_short', true); | |||
} | |||
$datas[] = $this->_lineOrderReportCSV($orderLine, $cpt) ; | |||
} | |||
@@ -451,13 +472,15 @@ class DistributionController extends BackendController | |||
// total point de vente | |||
$totalsPointSaleArray = ['Total'] ; | |||
foreach ($productsArray as $product) { | |||
$quantity = Order::getProductQuantity($product->id, $pointSale->orders); | |||
if($quantity) { | |||
$index = $productsIndexArray[$product->id] ; | |||
if(!isset($totalsPointSaleArray[$index])) { | |||
$totalsPointSaleArray[$index] = 0 ; | |||
foreach(Product::$unitsArray as $unit => $dataUnit) { | |||
$quantity = Order::getProductQuantity($product->id, $pointSale->orders, false, $unit); | |||
if ($quantity) { | |||
$index = $productsIndexArray[$product->id] ; | |||
if(!isset($totalsPointSaleArray[$index])) { | |||
$totalsPointSaleArray[$index] = '' ; | |||
} | |||
$totalsPointSaleArray[$index] .= $quantity . ' '.Product::strUnit($unit, 'wording_short', true).' '; | |||
} | |||
$totalsPointSaleArray[$index] += $quantity ; | |||
} | |||
} | |||
@@ -469,13 +492,15 @@ class DistributionController extends BackendController | |||
// global | |||
$totalsGlobalArray = ['> Totaux'] ; | |||
foreach ($productsArray as $product) { | |||
$quantity = Order::getProductQuantity($product->id, $ordersArray); | |||
if($quantity) { | |||
$index = $productsIndexArray[$product->id] ; | |||
if(!isset($totalsGlobalArray[$index])) { | |||
$totalsGlobalArray[$index] = 0 ; | |||
foreach(Product::$unitsArray as $unit => $dataUnit) { | |||
$quantity = Order::getProductQuantity($product->id, $ordersArray, false, $unit); | |||
if ($quantity) { | |||
$index = $productsIndexArray[$product->id] ; | |||
if(!isset($totalsGlobalArray[$index])) { | |||
$totalsGlobalArray[$index] = '' ; | |||
} | |||
$totalsGlobalArray[$index] .= $quantity . ' '.Product::strUnit($unit, 'wording_short', true).' '; | |||
} | |||
$totalsGlobalArray[$index] += $quantity ; | |||
} | |||
} | |||
@@ -105,6 +105,8 @@ class OrderController extends BackendController | |||
$productOrder->id_product = $product->id; | |||
$productOrder->quantity = $quantity; | |||
$productOrder->price = $p->price; | |||
$productOrder->unit = $p->unit; | |||
$productOrder->step = $p->step; | |||
$productOrder->save(); | |||
} | |||
} | |||
@@ -138,6 +140,8 @@ class OrderController extends BackendController | |||
$productOrder->id_product = $product->id; | |||
$productOrder->quantity = $quantity; | |||
$productOrder->price = $p->price; | |||
$productOrder->unit = $p->unit; | |||
$productOrder->step = $p->step; | |||
$productOrder->save(); | |||
} | |||
} | |||
@@ -860,13 +864,16 @@ class OrderController extends BackendController | |||
$order->save(); | |||
foreach ($products as $key => $quantity) { | |||
foreach ($products as $key => $dataProductOrder) { | |||
$product = Product::findOne($key); | |||
$quantity = $dataProductOrder->quantity / Product::$unitsArray[$dataProductOrder->unit]['coefficient'] ; | |||
if ($product && $quantity) { | |||
$productOrder = new ProductOrder; | |||
$productOrder->id_order = $order->id; | |||
$productOrder->id_product = $key; | |||
$productOrder->quantity = $quantity; | |||
$productOrder->unit = $product->unit; | |||
$productOrder->step = $product->step; | |||
$productOrder->price = $product->price; | |||
$productOrder->save(); | |||
} | |||
@@ -906,12 +913,15 @@ class OrderController extends BackendController | |||
$order->distribution->id_producer == Producer::getId()) { | |||
$products = json_decode($products); | |||
foreach ($products as $key => $quantity) { | |||
foreach ($products as $key => $dataProductOrder) { | |||
$productOrder = ProductOrder::findOne([ | |||
'id_order' => $idOrder, | |||
'id_product' => $key | |||
]); | |||
$quantity = $dataProductOrder->quantity | |||
/ Product::$unitsArray[$dataProductOrder->unit]['coefficient'] ; | |||
if ($quantity) { | |||
if ($productOrder) { | |||
$productOrder->quantity = $quantity; | |||
@@ -923,6 +933,8 @@ class OrderController extends BackendController | |||
$productOrder->id_order = $idOrder; | |||
$productOrder->id_product = $key; | |||
$productOrder->quantity = $quantity; | |||
$productOrder->unit = $product->unit; | |||
$productOrder->step = $product->step; | |||
$productOrder->price = $product->price; | |||
} | |||
} |
@@ -38,6 +38,8 @@ termes. | |||
namespace backend\controllers; | |||
use common\models\Order ; | |||
use common\models\Product ; | |||
use common\models\SubscriptionSearch ; | |||
class SubscriptionController extends BackendController | |||
{ | |||
@@ -88,6 +90,7 @@ class SubscriptionController extends BackendController | |||
{ | |||
// form | |||
$model = new SubscriptionForm; | |||
$model->isAdmin = true ; | |||
$model->id_producer = Producer::getId(); | |||
if($idOrder) { | |||
@@ -148,6 +151,7 @@ class SubscriptionController extends BackendController | |||
{ | |||
// form | |||
$model = new SubscriptionForm; | |||
$model->isAdmin = true ; | |||
$subscription = Subscription::findOne($id); | |||
if ($subscription) { | |||
$model->id = $id; | |||
@@ -170,7 +174,6 @@ class SubscriptionController extends BackendController | |||
$model->auto_payment = $subscription->auto_payment; | |||
$model->week_frequency = $subscription->week_frequency; | |||
// produits | |||
$arrayProductsSubscription = ProductSubscription::searchAll([ | |||
'id_subscription' => $model->id | |||
@@ -249,6 +252,55 @@ class SubscriptionController extends BackendController | |||
'update' => $update | |||
]) ; | |||
} | |||
public function actionAjaxInfos($idSubscription = 0) | |||
{ | |||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||
$productsQuery = Product::find() | |||
->where(['id_producer' => Producer::getId(),]) ; | |||
if($idSubscription) { | |||
$productsQuery->joinWith(['productSubscription' => function($query) use($idSubscription) { | |||
$query->andOnCondition('product_subscription.id_subscription = '.((int) $idSubscription)) ; | |||
}]) ; | |||
} | |||
$productsArray = $productsQuery->asArray()->all() ; | |||
foreach($productsArray as &$theProduct) { | |||
$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'] | |||
] ; | |||
if(isset($theProduct['productSubscription'][0])) { | |||
if($theProduct['productSubscription'][0]['unit'] != $theProduct['unit']) { | |||
$theProduct['units'][] = [ | |||
'unit' => $theProduct['productSubscription'][0]['unit'], | |||
'wording_unit' => Product::strUnit($theProduct['productSubscription'][0]['unit'], 'wording_short'), | |||
'step' => $theProduct['productSubscription'][0]['step'], | |||
'price' => $theProduct['productSubscription'][0]['price'], | |||
] ; | |||
$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 { | |||
$theProduct['quantity'] = '' ; | |||
} | |||
} | |||
return [ | |||
'products' => $productsArray | |||
] ; | |||
} | |||
} |
@@ -119,8 +119,14 @@ $this->setPageTitle('Distributions') ; | |||
<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>{{ product.name }}</td> | |||
<td class="quantity-ordered">{{ product.quantity_ordered ? product.quantity_ordered : '-' }}</td> | |||
<td class="quantity-max"><input type="text" class="form-control quantity-max" placeholder="∞" :data-id-product="product.id" v-model="product.productDistribution[0].quantity_max" @keyup="productQuantityMaxChange" /></td> | |||
<td class="quantity-ordered">{{ product.quantity_ordered ? product.quantity_ordered + ' '+ ((product.unit == 'piece') ? ' p.' : ' '+(product.unit == 'g' || product.unit == 'kg') ? 'kg' : 'litre(s)') : '∅' }}</td> | |||
<td class="quantity-max"> | |||
<div class="input-group"> | |||
<input type="text" class="form-control quantity-max" placeholder="∞" :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> | |||
</div> | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
@@ -415,8 +421,8 @@ $this->setPageTitle('Distributions') ; | |||
<td colspan="6"> | |||
<strong><span class="glyphicon glyphicon-menu-right"></span> Produits</strong> | |||
<ul> | |||
<li v-for="product in products" v-if="order.productOrder[product.id] > 0"> | |||
{{ order.productOrder[product.id] }} x {{ product.name }} <span v-if="product.productDistribution[0].active == 0" class="glyphicon glyphicon-warning-sign" title="Ce produit n'est pas activé"></span> | |||
<li v-for="product in products" v-if="order.productOrder[product.id].quantity > 0"> | |||
{{ product.name }} : {{ order.productOrder[product.id].quantity }} {{ order.productOrder[product.id].unit == 'piece' ? ' pièce(s)' : ' '+order.productOrder[product.id].unit }} <span v-if="product.productDistribution[0].active == 0" class="glyphicon glyphicon-warning-sign" title="Ce produit n'est pas activé"></span> | |||
</li> | |||
</ul> | |||
<div v-if="order.comment && order.comment.length > 0" class="comment"> | |||
@@ -468,6 +474,14 @@ $this->setPageTitle('Distributions') ; | |||
<div class="col-md-8"> | |||
<label class="control-label">Produits</label> | |||
<table class="table table-condensed table-bordered table-hover table-products"> | |||
<thead> | |||
<tr> | |||
<th></th> | |||
<th>Nom</th> | |||
<th>Quantité</th> | |||
<th>Reste</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr v-for="product in products" :class="(order.productOrder[product.id] > 0) ? 'product-ordered' : ''"> | |||
<td> | |||
@@ -478,15 +492,18 @@ $this->setPageTitle('Distributions') ; | |||
<td class="quantity"> | |||
<div class="input-group"> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default btn-moins" type="button" @click="productQuantityClick(product.id, -1)"><span class="glyphicon glyphicon-minus"></span></button> | |||
<button class="btn btn-default btn-moins" type="button" @click="productQuantityClick(product.id, order.productOrder[product.id].unit == 'piece' ? -1 : -parseFloat(product.step))"><span class="glyphicon glyphicon-minus"></span></button> | |||
</span> | |||
<input type="text" v-model="order.productOrder[product.id]" class="form-control" /> | |||
<input type="text" v-model="order.productOrder[product.id].quantity" class="form-control" /> | |||
<span class="input-group-addon">{{ order.productOrder[product.id].unit == 'piece' ? 'p.' : order.productOrder[product.id].unit }}</span> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default btn-plus" type="button" @click="productQuantityClick(product.id, 1)"><span class="glyphicon glyphicon-plus"></span></button> | |||
<button class="btn btn-default btn-plus" type="button" @click="productQuantityClick(product.id, order.productOrder[product.id].unit == 'piece' ? 1 : parseFloat(product.step))"><span class="glyphicon glyphicon-plus"></span></button> | |||
</span> | |||
</div> | |||
</td> | |||
<td class="quantity-remaining">/ {{ product.quantity_remaining }}</td> | |||
<td class="quantity-remaining infinite" v-if="product.quantity_remaining === null || order.productOrder[product.id].unit != product.unit">∞</td> | |||
<td class="quantity-remaining negative" v-else-if="product.quantity_remaining <= 0">{{ product.quantity_remaining }} {{ order.productOrder[product.id].unit == 'piece' ? ' p.' : ' '+(order.productOrder[product.id].unit == 'g' || order.productOrder[product.id].unit == 'kg') ? 'kg' : 'litre(s)' }}</td> | |||
<td class="quantity-remaining has-quantity" v-else>{{ product.quantity_remaining }} {{ order.productOrder[product.id].unit == 'piece' ? ' p.' : ' '+(order.productOrder[product.id].unit == 'g' || order.productOrder[product.id].unit == 'kg') ? 'kg' : 'litre(s)' }}</td> | |||
</tr> | |||
</tbody> | |||
</table> |
@@ -37,6 +37,7 @@ termes. | |||
*/ | |||
use common\models\Order ; | |||
use common\models\Product ; | |||
$dayWeek = date('w', strtotime($date)); | |||
$dayWeekArray = [0 => 'sunday', 1 => 'monday', 2 => 'tuesday', 3 => 'wednesday', 4 => 'thursday', 5 => 'friday', 6 => 'saturday']; | |||
@@ -91,7 +92,7 @@ foreach ($pointsSaleArray as $pointSale) { | |||
$add = false; | |||
foreach ($order->productOrder as $productOrder) { | |||
if ($product->id == $productOrder->id_product) { | |||
$strProducts .= $productOrder->quantity . ' ' . $product->name . ', '; | |||
$strProducts .= $product->name . ' (' .$productOrder->quantity . ' '.Product::strUnit($productOrder->unit, 'wording_short', true).'), '; | |||
$add = true; | |||
} | |||
} | |||
@@ -133,11 +134,11 @@ foreach ($pointsSaleArray as $pointSale) { | |||
$strProducts = ''; | |||
foreach ($productsArray as $product) { | |||
$quantity = Order::getProductQuantity($product->id, $pointSale->orders); | |||
$strQuantity = ''; | |||
if ($quantity) { | |||
$strQuantity = $quantity; | |||
$strProducts .= $strQuantity .' '. $product->name . ', '; | |||
foreach(Product::$unitsArray as $unit => $dataUnit) { | |||
$quantity = Order::getProductQuantity($product->id, $pointSale->orders, false, $unit); | |||
if ($quantity) { | |||
$strProducts .= $product->name . ' (' .$quantity . ' '.Product::strUnit($unit, 'wording_short', true).'), '; | |||
} | |||
} | |||
} | |||
@@ -170,14 +171,14 @@ foreach ($pointsSaleArray as $pointSale) | |||
if (count($pointSale->orders)) | |||
{ | |||
$html .= '<tr><td>'.$pointSale->name.'</td><td>' ; | |||
foreach ($productsArray as $product) { | |||
$quantity = Order::getProductQuantity($product->id, $pointSale->orders); | |||
$strQuantity = ($quantity) ? $quantity : '' ; | |||
if(strlen($strQuantity)) { | |||
$html .= $strQuantity . ' '.$product->name.', ' ; | |||
foreach(Product::$unitsArray as $unit => $dataUnit) { | |||
$quantity = Order::getProductQuantity($product->id, $pointSale->orders, false, $unit); | |||
if ($quantity) { | |||
$html .= $product->name . ' (' .$quantity . ' '.Product::strUnit($unit, 'wording_short', true).'), '; | |||
} | |||
} | |||
} | |||
$html = substr($html, 0, strlen($html) - 2) ; | |||
@@ -189,10 +190,13 @@ foreach ($pointsSaleArray as $pointSale) | |||
// total | |||
$html .= '<tr><td><strong>Total</strong></td><td>' ; | |||
foreach ($productsArray as $product) { | |||
$quantity = Order::getProductQuantity($product->id, $ordersArray); | |||
if($quantity) { | |||
$html .= $quantity . ' '.$product->name.', ' ; | |||
foreach(Product::$unitsArray as $unit => $dataUnit) { | |||
$quantity = Order::getProductQuantity($product->id, $ordersArray, false, $unit); | |||
if ($quantity) { | |||
$html .= $product->name . ' (' .$quantity . ' '.Product::strUnit($unit, 'wording_short', true).'), '; | |||
} | |||
} | |||
} | |||
@@ -37,7 +37,9 @@ termes. | |||
*/ | |||
use yii\helpers\Html; | |||
use yii\widgets\ActiveForm; | |||
use yii\bootstrap\ActiveForm; | |||
use common\models\Product; | |||
use yii\helpers\ArrayHelper ; | |||
/* @var $this yii\web\View */ | |||
/* @var $model app\models\Produit */ | |||
@@ -48,47 +50,60 @@ use yii\widgets\ActiveForm; | |||
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?> | |||
<?= $form->field($model, 'active')->radioList([1 => 'Oui',0 => 'Non' ]) ?> | |||
<?= $form->field($model, 'name')->textInput(['maxlength' => 255]) ?> | |||
<?= $form->field($model, 'description')->textInput(['maxlength' => 255]) ?> | |||
<?= $form->field($model, 'recipe')->textarea() ?> | |||
<?= $form->field($model, 'price')->textInput() ?> | |||
<?= $form->field($model, 'weight')->textInput() ?> | |||
<?= $form->field($model, 'quantity_max') | |||
->hint('Renseignez ce champs si vous souhaitez limiter la quantité commandable pour ce produit.') | |||
->textInput() ?> | |||
<?= $form->field($model, 'photo')->fileInput() ?> | |||
<?php | |||
if(strlen($model->photo)) { | |||
$url = Yii::$app->urlManagerProducer->getHostInfo().'/'.Yii::$app->urlManagerProducer->baseUrl ; | |||
echo '<img class="photo-product" src="'.$url.'/uploads/'.$model->photo.'" width="200px" /><br />' ; | |||
echo '<input type="checkbox" name="delete_photo" id="delete_photo" /> <label for="delete_photo">Supprimer la photo</label><br /><br />' ; | |||
} | |||
?> | |||
<h2>Jours de distribution</h2> | |||
<div id="days-production"> | |||
<?= $form->field($model, 'monday')->checkbox() ?> | |||
<?= $form->field($model, 'tuesday')->checkbox() ?> | |||
<?= $form->field($model, 'wednesday')->checkbox() ?> | |||
<?= $form->field($model, 'thursday')->checkbox() ?> | |||
<?= $form->field($model, 'friday')->checkbox() ?> | |||
<?= $form->field($model, 'saturday')->checkbox() ?> | |||
<?= $form->field($model, 'sunday')->checkbox() ?> | |||
<div> | |||
<div class="col-md-8"> | |||
<?= $form->field($model, 'active')->radioList([1 => 'Oui',0 => 'Non' ]) ?> | |||
<?= $form->field($model, 'name')->textInput(['maxlength' => 255]) ?> | |||
<?= $form->field($model, 'description')->textInput(['maxlength' => 255]) ?> | |||
<?= $form->field($model, 'recipe')->textarea()->label('Description longue') ?> | |||
<?= $form->field($model, 'unit') | |||
->dropDownList(ArrayHelper::map(Product::$unitsArray, 'unit', 'wording')) | |||
->label('Unité (pièce, poids ou volume)'); ?> | |||
<?= $form->field($model, 'price',[ | |||
'inputTemplate' => '<div class="input-group">{input}<span class="input-group-addon"><span class="glyphicon glyphicon-euro"></span></span></div>', | |||
]) ?> | |||
<?= $form->field($model, 'step')->textInput()->hint('Définit ce qui est ajouté ou enlevé lors des changements de quantité.') ?> | |||
<?= $form->field($model, 'weight')->textInput()->label('Poids (g)') ?> | |||
<?= $form->field($model, 'quantity_max') | |||
->hint('Renseignez ce champs si vous souhaitez limiter la quantité commandable pour une distribution.') | |||
->textInput() ?> | |||
<?php | |||
if(!$model->isNewRecord) { | |||
echo $form->field($model, 'apply_distributions') | |||
->checkbox() | |||
->hint('Sélectionnez cette option si vous souhaitez que ces modifications soient répercutées dans les distributions à venir déjà initialisées.'); | |||
} | |||
?> | |||
</div> | |||
<div class="col-md-4"> | |||
<?= $form->field($model, 'photo')->fileInput() ?> | |||
<?php | |||
if(strlen($model->photo)) { | |||
$url = Yii::$app->urlManagerProducer->getHostInfo().'/'.Yii::$app->urlManagerProducer->baseUrl ; | |||
echo '<img class="photo-product" src="'.$url.'/uploads/'.$model->photo.'" width="200px" /><br />' ; | |||
echo '<input type="checkbox" name="delete_photo" id="delete_photo" /> <label for="delete_photo">Supprimer la photo</label><br /><br />' ; | |||
} | |||
?> | |||
<div id="days-production"> | |||
<h2>Jours de distribution</h2> | |||
<?= $form->field($model, 'monday')->checkbox() ?> | |||
<?= $form->field($model, 'tuesday')->checkbox() ?> | |||
<?= $form->field($model, 'wednesday')->checkbox() ?> | |||
<?= $form->field($model, 'thursday')->checkbox() ?> | |||
<?= $form->field($model, 'friday')->checkbox() ?> | |||
<?= $form->field($model, 'saturday')->checkbox() ?> | |||
<?= $form->field($model, 'sunday')->checkbox() ?> | |||
</div> | |||
<div class="clr"></div> | |||
</div> | |||
<div class="clr"></div> | |||
</div> | |||
<div class="clr"></div> | |||
<?= $form->field($model, 'id_producer')->hiddenInput()->label('') ?> | |||
<?php | |||
if(!$model->isNewRecord) { | |||
echo $form->field($model, 'apply_distributions') | |||
->checkbox() | |||
->hint('Sélectionnez cette option si vous souhaitez que ces modifications soient répercutées dans les distributions à venir déjà initialisées.'); | |||
} | |||
?> | |||
<?= $form->field($model, 'id_producer')->hiddenInput()->label('') ?> | |||
<div class="form-group"> | |||
<?= Html::submitButton($model->isNewRecord ? 'Ajouter' : 'Modifier', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> | |||
</div> |
@@ -39,6 +39,7 @@ termes. | |||
use yii\helpers\Html; | |||
use yii\grid\GridView; | |||
use common\helpers\Url ; | |||
use common\models\Product ; | |||
$this->setTitle('Produits') ; | |||
$this->addBreadcrumb($this->getTitle()) ; | |||
@@ -76,6 +77,17 @@ $this->addButton(['label' => 'Nouveau produit <span class="glyphicon glyphicon-p | |||
], | |||
'name', | |||
'description', | |||
[ | |||
'attribute' => 'price', | |||
'value' => function($model) { | |||
$return = '' ; | |||
if($model->price) { | |||
$return = Price::format($model->price).' ('.Product::strUnit($model->unit, 'wording_unit', true).')' ; | |||
} | |||
return $return ; | |||
} | |||
], | |||
[ | |||
'attribute' => 'active', | |||
'headerOptions' => ['class' => 'active'], |
@@ -92,34 +92,43 @@ $this->title = 'Tableau de bord'; | |||
<?php endif; ?> | |||
<div id="distributions"> | |||
<!-- distributions --> | |||
<?php if(count($distributionsArray)): ?> | |||
<?php foreach($distributionsArray as $distribution): ?> | |||
<div class="col-md-4 col-sm-12 col-xs-12"> | |||
<div class="info-box"> | |||
<span class="info-box-icon bg-green date"> | |||
<span class="day"><?= strftime('%A', strtotime($distribution->date)) ?></span> | |||
<span class="num"><?= date('d', strtotime($distribution->date)) ?></span> | |||
<span class="month"><?= strftime('%B', strtotime($distribution->date)) ?></span> | |||
</span> | |||
<div class="info-box-content"> | |||
<span class="info-box-text"> | |||
<?php if(count($distribution->order)): ?> | |||
<strong><?= count($distribution->order); ?></strong> COMMANDES | |||
<?php else: ?> | |||
AUCUNE COMMANDE | |||
<?php endif; ?> | |||
</span> | |||
<span class="info-box-number"></span> | |||
<div class="buttons"> | |||
<?= Html::a('<span class="fa fa-eye"></span>', ['distribution/index', 'date' => $distribution->date], ['class' => 'btn btn-default']); ?> | |||
<?php if(count($distribution->order)): ?><?= Html::a('<span class="fa fa-download"></span>', ['distribution/report', 'date' => $distribution->date], ['class' => 'btn btn-default']); ?><?php endif; ?> | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
<h3 class="panel-title"> | |||
Prochaines distributions | |||
</h3> | |||
</div> | |||
<div class="panel-body"> | |||
<!-- distributions --> | |||
<?php if(count($distributionsArray)): ?> | |||
<?php foreach($distributionsArray as $distribution): ?> | |||
<div class="col-md-4 col-sm-12 col-xs-12"> | |||
<div class="info-box"> | |||
<span class="info-box-icon bg-green date"> | |||
<span class="day"><?= strftime('%A', strtotime($distribution->date)) ?></span> | |||
<span class="num"><?= date('d', strtotime($distribution->date)) ?></span> | |||
<span class="month"><?= strftime('%B', strtotime($distribution->date)) ?></span> | |||
</span> | |||
<div class="info-box-content"> | |||
<span class="info-box-text"> | |||
<?php if(count($distribution->order)): ?> | |||
<strong><?= count($distribution->order); ?></strong> COMMANDES | |||
<?php else: ?> | |||
AUCUNE COMMANDE | |||
<?php endif; ?> | |||
</span> | |||
<span class="info-box-number"></span> | |||
<div class="buttons"> | |||
<?= Html::a('<span class="fa fa-eye"></span>', ['distribution/index', 'date' => $distribution->date], ['class' => 'btn btn-default']); ?> | |||
<?php if(count($distribution->order)): ?><?= Html::a('<span class="fa fa-download"></span>', ['distribution/report', 'date' => $distribution->date], ['class' => 'btn btn-default']); ?><?php endif; ?> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<?php endforeach; ?> | |||
<?php endif; ?> | |||
<?php endforeach; ?> | |||
<?php endif; ?> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="clr"></div> |
@@ -42,10 +42,15 @@ use yii\helpers\ArrayHelper ; | |||
use common\models\User ; | |||
use common\models\PointSale ; | |||
\backend\assets\VuejsSubscriptionFormAsset::register($this); | |||
?> | |||
<div class="subscription-form"> | |||
<div class="subscription-form" id="app-subscription-form"> | |||
<?php $form = ActiveForm::begin(['enableClientValidation' => false]); ?> | |||
<?php if($model->id): ?> | |||
<?= $form->field($model, 'id')->hiddenInput() ?> | |||
<?php endif; ?> | |||
<div class="col-md-5" id="bloc-select-user"> | |||
<?= $form->field($model, 'id_user')->dropDownList( ArrayHelper::map(User::find()->joinWith('userProducer')->where('user_producer.id_producer = '.Producer::getId())->andWhere('user_producer.active = 1')->orderBy('lastname ASC, name ASC')->all(), 'id', function($model, $defaultValue) { | |||
return $model['lastname'].' '.$model['name']; | |||
@@ -91,23 +96,34 @@ use common\models\PointSale ; | |||
echo '<div class="alert alert-danger">'.$model->errors['products'][0].'</div>' ; | |||
} | |||
?> | |||
<table class="table table-bordered table-condensed table-hover"> | |||
<?php foreach ($productsArray as $p) : ?> | |||
<tr> | |||
<td><?= Html::encode($p->name) ?></td> | |||
<table class="table table-bordered table-condensed table-hover" id="products"> | |||
<tr v-for="product in products"> | |||
<td>{{ product.name }}</td> | |||
<td> | |||
<input type="hidden" :value="product.step" :name="'product_step_'+product.step" /> | |||
<input type="hidden" :value="product.price" :name="'product_price_'+product.price" /> | |||
<div class="input-group"> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default btn-moins" type="button"><span class="glyphicon glyphicon-minus"></span></button> | |||
<button class="btn btn-default" type="button" @click="changeQuantityProductSubscription(false, product)"><span class="glyphicon glyphicon-minus"></span></button> | |||
</span> | |||
<?= Html::input('text', 'SubscriptionForm[products][product_'.$p->id.']', (isset($model->products['product_'.$p->id])) ? $model->products['product_'.$p->id] : '', ['class' => 'form-control quantity']) ?> | |||
<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> | |||
</div> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default btn-plus" type="button"><span class="glyphicon glyphicon-plus"></span></button> | |||
<button class="btn btn-default" type="button" @click="changeQuantityProductSubscription(true, product)"><span class="glyphicon glyphicon-plus"></span></button> | |||
</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> | |||
<?php endforeach; ?> | |||
</table> | |||
</div> | |||
@@ -38,6 +38,7 @@ termes. | |||
use yii\helpers\Html; | |||
use yii\grid\GridView; | |||
use common\models\Product ; | |||
$this->setTitle('Abonnements') ; | |||
@@ -76,7 +77,7 @@ $this->addButton(['label' => 'Nouvel abonnement <span class="glyphicon glyphicon | |||
foreach($model->productSubscription as $productSubscription) | |||
{ | |||
if(isset($productSubscription->product)) { | |||
$html .= $productSubscription->quantity . ' x '.Html::encode($productSubscription->product->name).'<br />' ; | |||
$html .= Html::encode($productSubscription->product->name).' ('.($productSubscription->quantity * Product::$unitsArray[$productSubscription->unit]['coefficient']).' '.Product::strUnit($productSubscription->unit, 'wording_short').')<br />' ; | |||
} | |||
else { | |||
$html .= 'Produit non défini<br />' ; | |||
@@ -86,7 +87,12 @@ $this->addButton(['label' => 'Nouvel abonnement <span class="glyphicon glyphicon | |||
// aucun produit | |||
if(!count($model->productSubscription)) | |||
{ | |||
$html .= '<span class="glyphicon glyphicon-warning-sign"></span> Aucun produit' ; | |||
$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 ; |
@@ -1683,24 +1683,28 @@ body.login-page .login-box .login-box-body a:hover { | |||
color: #ff8c1a; | |||
} | |||
/* line 5, ../sass/site/_index.scss */ | |||
/* line 4, ../sass/site/_index.scss */ | |||
.site-index #distributions .info-box { | |||
border: solid 1px #e0e0e0; | |||
} | |||
/* line 6, ../sass/site/_index.scss */ | |||
.site-index #distributions .info-box .date { | |||
text-transform: uppercase; | |||
font-size: 12px; | |||
line-height: 20px; | |||
padding-top: 10px; | |||
} | |||
/* line 11, ../sass/site/_index.scss */ | |||
/* line 12, ../sass/site/_index.scss */ | |||
.site-index #distributions .info-box .date span { | |||
display: block; | |||
} | |||
/* line 17, ../sass/site/_index.scss */ | |||
/* line 18, ../sass/site/_index.scss */ | |||
.site-index #distributions .info-box .date .num { | |||
font-size: 30px; | |||
padding-top: 5px; | |||
padding-bottom: 5px; | |||
} | |||
/* line 29, ../sass/site/_index.scss */ | |||
/* line 30, ../sass/site/_index.scss */ | |||
.site-index #distributions .info-box-content .buttons { | |||
margin-top: 10px; | |||
} | |||
@@ -1710,6 +1714,36 @@ body.login-page .login-box .login-box-body a:hover { | |||
width: 50px; | |||
} | |||
/* line 3, ../sass/subscription/_form.scss */ | |||
.subscription-form .field-subscriptionform-id { | |||
display: none; | |||
} | |||
/* line 7, ../sass/subscription/_form.scss */ | |||
.subscription-form table#products .input-quantity { | |||
text-align: center; | |||
border-right: 0px none; | |||
} | |||
/* line 11, ../sass/subscription/_form.scss */ | |||
.subscription-form table#products .input-group-addon { | |||
padding: 5px; | |||
padding-left: 0px; | |||
margin: 0px; | |||
border-left: 0px none; | |||
border-right: 0px none; | |||
} | |||
/* line 18, ../sass/subscription/_form.scss */ | |||
.subscription-form table#products .select-unit { | |||
padding: 0px; | |||
width: 58px; | |||
text-align: center; | |||
height: 22px; | |||
} | |||
/* line 24, ../sass/subscription/_form.scss */ | |||
.subscription-form table#products .glyphicon-warning-sign { | |||
position: relative; | |||
top: 10px; | |||
} | |||
/* line 3, ../sass/product/_index.scss */ | |||
.product-index .td-photo { | |||
max-width: 100px; | |||
@@ -1725,16 +1759,25 @@ body.login-page .login-box .login-box-body a:hover { | |||
background-color: white; | |||
} | |||
/* line 5, ../sass/product/_form.scss */ | |||
/* line 6, ../sass/product/_form.scss */ | |||
.product-create #product-active label, | |||
.product-update #product-active label { | |||
margin-right: 15px; | |||
} | |||
/* line 10, ../sass/product/_form.scss */ | |||
.product-create #days-production .form-group, | |||
.product-update #days-production .form-group { | |||
float: left; | |||
margin-right: 15px; | |||
.product-create #days-production, | |||
.product-update #days-production { | |||
margin-top: 30px; | |||
} | |||
/* line 13, ../sass/product/_form.scss */ | |||
.product-create #days-production h2, | |||
.product-update #days-production h2 { | |||
font-size: 20px; | |||
} | |||
/* line 16, ../sass/product/_form.scss */ | |||
.product-create #days-production label, | |||
.product-update #days-production label { | |||
font-weight: normal; | |||
} | |||
/** | |||
@@ -1883,7 +1926,7 @@ termes. | |||
} | |||
/* line 155, ../sass/distribution/_index.scss */ | |||
.distribution-index #modal-products table.table td.quantity-max { | |||
width: 70px; | |||
width: 120px; | |||
} | |||
/* line 158, ../sass/distribution/_index.scss */ | |||
.distribution-index #modal-products table.table td.quantity-max input { | |||
@@ -1979,30 +2022,55 @@ termes. | |||
} | |||
/* line 267, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-form-order table.table-products td.quantity { | |||
width: 150px; | |||
width: 165px; | |||
} | |||
/* line 270, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-form-order table.table-products td.quantity input { | |||
text-align: center; | |||
color: gray; | |||
color: black; | |||
} | |||
/* line 276, ../sass/distribution/_index.scss */ | |||
/* line 274, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-form-order table.table-products td.quantity .form-control { | |||
border-right: 0px none; | |||
padding-right: 4px; | |||
} | |||
/* line 278, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-form-order table.table-products td.quantity .input-group-addon { | |||
padding: 5px; | |||
padding-left: 0px; | |||
margin: 0px; | |||
border-left: 0px none; | |||
border-right: 0px none; | |||
} | |||
/* line 286, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-form-order table.table-products td.quantity-remaining { | |||
text-align: right; | |||
} | |||
/* line 282, ../sass/distribution/_index.scss */ | |||
/* line 289, ../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 { | |||
color: #00A65A; | |||
} | |||
/* line 293, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-form-order table.table-products td.quantity-remaining.negative { | |||
color: #DD4B39; | |||
} | |||
/* line 297, ../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 { | |||
font-size: 18px; | |||
} | |||
/* line 304, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-form-order .actions-form button { | |||
margin-left: 15px; | |||
} | |||
/* line 290, ../sass/distribution/_index.scss */ | |||
/* line 312, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-payment .info-box .info-box-icon { | |||
width: 50px; | |||
} | |||
/* line 292, ../sass/distribution/_index.scss */ | |||
/* line 314, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-payment .info-box .info-box-icon i { | |||
font-size: 30px; | |||
} | |||
/* line 296, ../sass/distribution/_index.scss */ | |||
/* line 318, ../sass/distribution/_index.scss */ | |||
.distribution-index .modal-payment .info-box .info-box-content { | |||
margin-left: 50px; | |||
} |
@@ -52,6 +52,7 @@ $(document).ready(function() { | |||
chat_index_commandes_maj_points_vente() ; | |||
// admin | |||
chat_select_etablissement() ; | |||
chat_products() ; | |||
}) ; | |||
var UrlManager = { | |||
@@ -64,6 +65,56 @@ var UrlManager = { | |||
} | |||
}; | |||
function chat_products() { | |||
if($('.product-create').size() || $('.product-update').size()) { | |||
chat_products_event_unit(false) ; | |||
$('#product-unit').change(function() { | |||
chat_products_event_unit(true) ; | |||
}) ; | |||
} | |||
} | |||
function chat_products_event_unit(change) { | |||
var unit = $('#product-unit').val() ; | |||
if(unit == 'piece') { | |||
$('.field-product-step').hide() ; | |||
$('.field-product-weight').show() ; | |||
} | |||
else { | |||
$('.field-product-step').show() ; | |||
$('.field-product-weight').hide() ; | |||
} | |||
var label_price = $('.field-product-price .control-label') ; | |||
var label_step = $('.field-product-step .control-label') ; | |||
var label_quantity_max = $('.field-product-quantity_max .control-label') ; | |||
if(unit == 'piece') { | |||
label_price.html('Prix (la pièce)') ; | |||
label_quantity_max.html('Quantité max par défaut (pièces)') ; | |||
} | |||
else if(unit == 'g' || unit == 'kg') { | |||
label_price.html('Prix (au kg)') ; | |||
label_quantity_max.html('Quantité max par défaut (kg)') ; | |||
label_step.html('Pas ('+unit+')') ; | |||
} | |||
else if(unit == 'mL' || unit == 'L') { | |||
label_price.html('Prix (au litre)') ; | |||
label_quantity_max.html('Quantité max par défaut (litres)') ; | |||
label_step.html('Pas ('+unit+')') ; | |||
} | |||
if(change) { | |||
if(unit == 'piece') { | |||
$('#product-step').val(1) ; | |||
} | |||
else { | |||
$('#product-step').val('') ; | |||
} | |||
} | |||
} | |||
function chat_tooltip() { | |||
$('[data-toggle="tooltip"]').tooltip({container:'body'}); | |||
} |
@@ -428,7 +428,7 @@ Vue.component('order-form',{ | |||
var countProducts = 0 ; | |||
for(var key in this.order.productOrder) { | |||
if(this.order.productOrder[key] > 0) { | |||
if(this.order.productOrder[key].quantity > 0) { | |||
countProducts ++ ; | |||
} | |||
} | |||
@@ -502,9 +502,12 @@ Vue.component('order-form',{ | |||
} | |||
}, | |||
productQuantityClick: function(id_product, quantity) { | |||
if(this.order.productOrder[id_product] + quantity >= 0) { | |||
var theQuantity = this.order.productOrder[id_product] + quantity ; | |||
Vue.set(this.order.productOrder, id_product, theQuantity); | |||
if(!this.order.productOrder[id_product].quantity) { | |||
this.order.productOrder[id_product].quantity = 0 ; | |||
} | |||
if(parseFloat(this.order.productOrder[id_product].quantity) + quantity >= 0) { | |||
var theQuantity = parseFloat(this.order.productOrder[id_product].quantity) + parseFloat(quantity) ; | |||
Vue.set(this.order.productOrder, id_product, {quantity: theQuantity, unit: this.order.productOrder[id_product].unit}); | |||
} | |||
} | |||
} |
@@ -0,0 +1,90 @@ | |||
/** | |||
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. | |||
*/ | |||
var app = new Vue({ | |||
el: '#app-subscription-form', | |||
data: { | |||
showLoading: false, | |||
loading: true, | |||
products: [], | |||
units: [] | |||
}, | |||
mounted: function() { | |||
this.init() ; | |||
this.loading = false ; | |||
}, | |||
methods: { | |||
init: function() { | |||
var app = this ; | |||
this.showLoading = true ; | |||
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 = parseFloat(product.step) ; | |||
if(!product.quantity) product.quantity = 0 ; | |||
var quantity = parseFloat(product.quantity) ; | |||
if(!increase) { | |||
step = -step ; | |||
} | |||
if(quantity + step >= 0) { | |||
product.quantity = quantity + step ; | |||
} | |||
if(!product.quantity) product.quantity = '' ; | |||
} | |||
} | |||
}); |
@@ -153,7 +153,7 @@ termes. | |||
width: 50px ; | |||
} | |||
td.quantity-max { | |||
width: 70px ; | |||
width: 120px ; | |||
input { | |||
text-align: center ; | |||
@@ -265,16 +265,38 @@ termes. | |||
} | |||
td.quantity { | |||
width: 150px ; | |||
width: 165px ; | |||
input { | |||
text-align: center ; | |||
color: gray ; | |||
color: black ; | |||
} | |||
.form-control { | |||
border-right: 0px none ; | |||
padding-right: 4px ; | |||
} | |||
.input-group-addon { | |||
padding: 5px ; | |||
padding-left: 0px ; | |||
margin: 0px ; | |||
border-left: 0px none ; | |||
border-right: 0px none ; | |||
} | |||
} | |||
td.quantity-remaining { | |||
text-align: right ; | |||
&.quantity-remaining, &.infinite { | |||
color: #00A65A ; | |||
} | |||
&.negative { | |||
color: #DD4B39 ; | |||
} | |||
&.infinite, &.empty { | |||
font-size: 18px ; | |||
} | |||
} | |||
} | |||
@@ -1,15 +1,20 @@ | |||
.product-create, | |||
.product-update { | |||
#product-active { | |||
label { | |||
margin-right: 15px ; | |||
} | |||
} | |||
#days-production { | |||
.form-group { | |||
float: left ; | |||
margin-right: 15px ; | |||
margin-top: 30px ; | |||
h2 { | |||
font-size: 20px ; | |||
} | |||
label { | |||
font-weight: normal ; | |||
} | |||
} | |||
} |
@@ -1458,6 +1458,7 @@ a.btn, button.btn { | |||
@import "_adminlte.scss" ; | |||
@import "site/_index.scss" ; | |||
@import "subscription/_index.scss" ; | |||
@import "subscription/_form.scss" ; | |||
@import "product/_index.scss" ; | |||
@import "product/_form.scss" ; | |||
@import "stats/_products.scss" ; |
@@ -2,6 +2,7 @@ | |||
.site-index { | |||
#distributions { | |||
.info-box { | |||
border: solid 1px #e0e0e0 ; | |||
.date { | |||
text-transform: uppercase ; | |||
font-size: 12px ; |
@@ -0,0 +1,29 @@ | |||
.subscription-form { | |||
.field-subscriptionform-id { | |||
display: none; | |||
} | |||
table#products { | |||
.input-quantity { | |||
text-align: center ; | |||
border-right: 0px none ; | |||
} | |||
.input-group-addon { | |||
padding: 5px ; | |||
padding-left: 0px ; | |||
margin: 0px ; | |||
border-left: 0px none ; | |||
border-right: 0px none ; | |||
} | |||
.select-unit { | |||
padding: 0px; | |||
width: 58px; | |||
text-align: center; | |||
height: 22px; | |||
} | |||
.glyphicon-warning-sign { | |||
position: relative; | |||
top: 10px ; | |||
} | |||
} | |||
} |
@@ -160,7 +160,7 @@ class Order extends ActiveRecordCommon | |||
*/ | |||
public static function defaultOptionsSearch() { | |||
return [ | |||
'with' => ['productOrder', 'creditHistory','creditHistory.userAction' , 'pointSale'], | |||
'with' => ['productOrder','productOrder.product','creditHistory','creditHistory.userAction' , 'pointSale'], | |||
'join_with' => ['distribution', 'user', 'user.userProducer'], | |||
'orderby' => 'order.date ASC', | |||
'attribute_id_producer' => 'distribution.id_producer' | |||
@@ -186,14 +186,14 @@ class Order extends ActiveRecordCommon | |||
public function initAmount() { | |||
if (isset($this->productOrder)) { | |||
foreach ($this->productOrder as $productOrder) { | |||
if ($productOrder->sale_mode == Product::SALE_MODE_UNIT) { | |||
$this->amount += $productOrder->price * $productOrder->quantity ; | |||
$this->amount += $productOrder->price * $productOrder->quantity ; | |||
if ($productOrder->unit == 'piece') { | |||
if(isset($productOrder->product)) { | |||
$this->weight += ($productOrder->quantity * $productOrder->product->weight) / 1000 ; | |||
} | |||
} | |||
elseif ($productOrder->sale_mode == Product::SALE_MODE_WEIGHT) { | |||
$this->amount += $productOrder->price * $productOrder->quantity / 1000; | |||
else { | |||
$this->weight += $productOrder->quantity ; | |||
} | |||
} | |||
} | |||
@@ -379,7 +379,7 @@ class Order extends ActiveRecordCommon | |||
$i = 0; | |||
foreach ($this->productOrder as $p) { | |||
if (isset($p->product)) { | |||
$html .= $p->quantity . ' x ' . Html::encode($p->product->name); | |||
$html .= Html::encode($p->product->name) .' ('. $p->quantity .' '.Product::strUnit($p->unit, 'wording_short', true).')'; | |||
if (++$i != $count) { | |||
$html .= '<br />'; | |||
} | |||
@@ -598,15 +598,16 @@ class Order extends ActiveRecordCommon | |||
* | |||
* @return integer | |||
*/ | |||
public static function getProductQuantity($idProduct, $orders, $ignoreCancel = false) | |||
{ | |||
public static function getProductQuantity($idProduct, $orders, $ignoreCancel = false, $unit = null) | |||
{ | |||
$quantity = 0; | |||
if (isset($orders) && is_array($orders) && count($orders)) { | |||
foreach ($orders as $c) { | |||
if(is_null($c->date_delete) || $ignoreCancel) { | |||
foreach ($c->productOrder as $po) { | |||
if ($po->id_product == $idProduct) { | |||
if ($po->id_product == $idProduct && | |||
((is_null($unit) && $po->product->unit == $po->unit) || (!is_null($unit) && strlen($unit) && $po->unit == $unit))) { | |||
$quantity += $po->quantity ; | |||
} | |||
} | |||
@@ -666,7 +667,12 @@ class Order extends ActiveRecordCommon | |||
$count = 0 ; | |||
if($this->productOrder && is_array($this->productOrder)) { | |||
foreach($this->productOrder as $productOrder) { | |||
$count += $productOrder->quantity ; | |||
if($productOrder->unit == 'piece') { | |||
$count ++ ; | |||
} | |||
else { | |||
$count += $productOrder->quantity ; | |||
} | |||
} | |||
} | |||
return $count ; |
@@ -52,14 +52,51 @@ use common\components\ActiveRecordCommon ; | |||
* @property double $price | |||
* @property double $pweight | |||
* @property string $recipe | |||
* @property string $unit | |||
* @property double $step | |||
*/ | |||
class Product extends ActiveRecordCommon | |||
{ | |||
var $total = 0; | |||
var $apply_distributions = false ; | |||
const SALE_MODE_UNIT = 'unit' ; | |||
const SALE_MODE_WEIGHT = 'weight' ; | |||
public static $unitsArray = [ | |||
'piece' => [ | |||
'unit' => 'piece', | |||
'wording_unit' => 'la pièce', | |||
'wording' => 'pièce(s)', | |||
'wording_short' => 'p.', | |||
'coefficient' => 1 | |||
], | |||
'g' => [ | |||
'unit' => 'g', | |||
'wording_unit' => 'le g', | |||
'wording' => 'g', | |||
'wording_short' => 'g', | |||
'coefficient' => 1000 | |||
], | |||
'kg' => [ | |||
'unit' => 'kg', | |||
'wording_unit' => 'le kg', | |||
'wording' => 'kg', | |||
'wording_short' => 'kg', | |||
'coefficient' => 1 | |||
], | |||
'mL' => [ | |||
'unit' => 'mL', | |||
'wording_unit' => 'le mL', | |||
'wording' => 'mL', | |||
'wording_short' => 'mL', | |||
'coefficient' => 1000 | |||
], | |||
'L' => [ | |||
'unit' => 'L', | |||
'wording_unit' => 'le litre', | |||
'wording' => 'L', | |||
'wording_short' => 'L', | |||
'coefficient' => 1 | |||
], | |||
]; | |||
/** | |||
* @inheritdoc | |||
@@ -78,10 +115,16 @@ class Product extends ActiveRecordCommon | |||
[['name', 'id_producer'], 'required'], | |||
[['active', 'order', 'quantity_max', 'id_producer'], 'integer'], | |||
[['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'unavailable','apply_distributions'], 'boolean'], | |||
[['price', 'weight'], 'number'], | |||
[['price', 'weight', 'step'], 'number'], | |||
[[ 'photo'], 'file'], | |||
[['name', 'description', 'photo'], 'string', 'max' => 255], | |||
[['name', 'description', 'photo', 'unit'], 'string', 'max' => 255], | |||
[['recipe'], 'string', 'max' => 1000], | |||
['step', 'required', 'message' => 'Champs obligatoire', 'when' => function($model) { | |||
if($model->unit == 'piece') { | |||
return true ; | |||
} | |||
return false ; | |||
}], | |||
]; | |||
} | |||
@@ -96,8 +139,8 @@ class Product extends ActiveRecordCommon | |||
'description' => 'Description', | |||
'active' => 'Actif', | |||
'photo' => 'Photo', | |||
'price' => 'Prix', | |||
'weight' => 'Poids (g)', | |||
'price' => 'Prix (€)', | |||
'weight' => 'Poids', | |||
'recipe' => 'Recette', | |||
'monday' => 'Lundi', | |||
'tuesday' => 'Mardi', | |||
@@ -109,7 +152,9 @@ class Product extends ActiveRecordCommon | |||
'order' => 'Ordre', | |||
'quantity_max' => 'Quantité max par défaut', | |||
'unavailable' => 'Épuisé', | |||
'apply_distributions' => 'Appliquer ces modifications dans les distributions futures' | |||
'apply_distributions' => 'Appliquer ces modifications dans les distributions futures', | |||
'unit' => 'Unité', | |||
'step' => 'Pas' | |||
]; | |||
} | |||
@@ -118,6 +163,11 @@ class Product extends ActiveRecordCommon | |||
return $this->hasMany(ProductDistribution::className(), ['id_product' => 'id']); | |||
} | |||
public function getProductSubscription() | |||
{ | |||
return $this->hasMany(ProductSubscription::className(), ['id_product' => 'id']); | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
@@ -216,5 +266,31 @@ class Product extends ActiveRecordCommon | |||
return $productGift ; | |||
} | |||
/** | |||
* Retourne le libellé d'une unité. | |||
* | |||
* @param $format wording_unit, wording, short | |||
* @param $unitInDb Unité stockée en base de données (ex: si g > kg, si mL > L) | |||
* @return $string Libellé de l'unité | |||
*/ | |||
public static function strUnit($unit, $format = 'wording_short', $unitInDb = false) | |||
{ | |||
$strUnit = '' ; | |||
if($unitInDb) { | |||
if($unit == 'g') { | |||
$unit = 'kg' ; | |||
} | |||
if($unit == 'mL') { | |||
$unit = 'L' ; | |||
} | |||
} | |||
if(isset(self::$unitsArray[$unit]) && isset(self::$unitsArray[$unit][$format])) { | |||
$strUnit = self::$unitsArray[$unit][$format] ; | |||
} | |||
return $strUnit ; | |||
} | |||
} |
@@ -48,6 +48,7 @@ use common\components\ActiveRecordCommon ; | |||
* @property integer $id_order | |||
* @property integer $id_product | |||
* @property double $quantity | |||
* @property string $unit | |||
*/ | |||
class ProductOrder extends ActiveRecordCommon | |||
{ | |||
@@ -77,6 +78,7 @@ class ProductOrder extends ActiveRecordCommon | |||
return [ | |||
[['id_order', 'id_product', 'quantity'], 'required'], | |||
[['id_order', 'id_product'], 'integer'], | |||
[['unit'], 'string', 'max' => 255], | |||
[['quantity'], 'number', 'min' => 0] | |||
]; | |||
} | |||
@@ -91,6 +93,7 @@ class ProductOrder extends ActiveRecordCommon | |||
'id_order' => 'Commande', | |||
'id_product' => 'Product', | |||
'quantity' => 'Quantité', | |||
'unit' => 'Unité' | |||
]; | |||
} | |||
@@ -240,6 +240,8 @@ class Subscription extends ActiveRecordCommon | |||
$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; | |||
} | |||
@@ -453,4 +455,23 @@ class Subscription extends ActiveRecordCommon | |||
} | |||
} | |||
} | |||
/** | |||
* 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 ; | |||
} | |||
} | |||
} | |||
return false ; | |||
} | |||
} |
@@ -48,7 +48,7 @@ use common\models\SubscriptionProduct; | |||
*/ | |||
class SubscriptionForm extends Model | |||
{ | |||
public $isAdmin = false ; | |||
public $id; | |||
public $id_user; | |||
public $username; | |||
@@ -151,17 +151,49 @@ class SubscriptionForm extends Model | |||
// produits | |||
if ($this->id) { | |||
$productsSubscriptionsArray = ProductSubscription::findAll(['id_subscription' => $this->id]) ; | |||
ProductSubscription::deleteAll(['id_subscription' => $this->id]); | |||
} | |||
foreach ($this->products as $nameInput => $quantity) { | |||
if ($quantity) { | |||
$idProduct = str_replace('product_', '', $nameInput); | |||
$subscriptionProduct = new ProductSubscription; | |||
$subscriptionProduct->id_subscription = $subscription->id; | |||
$subscriptionProduct->id_product = $idProduct; | |||
$subscriptionProduct->quantity = $quantity; | |||
$subscriptionProduct->save(); | |||
$idProduct = (int) str_replace('product_', '', $nameInput); | |||
$product = Product::findOne($idProduct) ; | |||
$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 { | |||
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->save(); | |||
} | |||
} | |||
@@ -0,0 +1,26 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\mysql\Schema; | |||
class m190508_155647_ajout_champs_vente_kilo extends Migration { | |||
public function up() { | |||
$this->dropColumn('product', 'sale_mode') ; | |||
$this->addColumn('product', 'unit', Schema::TYPE_STRING.' DEFAULT \'piece\'') ; | |||
$this->addColumn('product', 'step', Schema::TYPE_FLOAT.' DEFAULT 1') ; | |||
$this->dropColumn('product_order', 'sale_mode') ; | |||
$this->addColumn('product_order', 'unit', Schema::TYPE_STRING.' DEFAULT \'piece\'') ; | |||
} | |||
public function down() { | |||
$this->addColumn('product', 'sale_mode', Schema::TYPE_STRING.' DEFAULT \'unit\'') ; | |||
$this->dropColumn('product', 'unit') ; | |||
$this->dropColumn('product', 'step') ; | |||
$this->addColumn('product_order', 'sale_mode', Schema::TYPE_STRING.' DEFAULT \'unit\'') ; | |||
$this->dropColumn('product_order', 'unit') ; | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\mysql\Schema; | |||
class m190510_074749_ajout_champs_product_order_step extends Migration { | |||
public function up() { | |||
$this->addColumn('product_order', 'step', Schema::TYPE_FLOAT.' DEFAULT 1') ; | |||
} | |||
public function down() { | |||
$this->dropColumn('product_order','step') ; | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\mysql\Schema; | |||
class m190511_061123_ajout_champs_unit_product_subscription extends Migration { | |||
public function up() { | |||
$this->addColumn('product_subscription', 'unit', Schema::TYPE_STRING . ' DEFAULT \'piece\''); | |||
$this->addColumn('product_subscription', 'step', Schema::TYPE_FLOAT . ' DEFAULT 1'); | |||
} | |||
public function down() { | |||
$this->dropColumn('product_subscription', 'unit'); | |||
$this->dropColumn('product_subscription', 'step'); | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\mysql\Schema; | |||
class m190515_122438_ajout_champs_price_product_subscription extends Migration { | |||
public function up() { | |||
$this->addColumn('product_subscription', 'price', Schema::TYPE_FLOAT. ' DEFAULT 0') ; | |||
$productsSubscriptionsArray = common\models\ProductSubscription::find()->all() ; | |||
$productsArray = common\models\Product::find()->all() ; | |||
foreach($productsSubscriptionsArray as $productSubscription) { | |||
foreach($productsArray as $product) { | |||
if($productSubscription->id_product == $product->id) { | |||
$productSubscription->price = $product->price ; | |||
$productSubscription->save() ; | |||
} | |||
} | |||
} | |||
} | |||
public function down() { | |||
$this->dropColumn('product_subscription', 'price') ; | |||
} | |||
} |
@@ -43,6 +43,7 @@ use common\models\User ; | |||
use common\models\Producer ; | |||
use common\models\Order ; | |||
use common\models\UserPointSale ; | |||
use common\models\Product ; | |||
use DateTime; | |||
class OrderController extends ProducerBaseController | |||
@@ -228,7 +229,6 @@ class OrderController extends ProducerBaseController | |||
} | |||
} | |||
// date | |||
$errorDate = false; | |||
if (isset($order->id_distribution)) { | |||
@@ -303,6 +303,13 @@ class OrderController extends ProducerBaseController | |||
// suppression de tous les enregistrements ProductOrder | |||
if (!is_null($order)) { | |||
ProductOrder::deleteAll(['id_order' => $order->id]); | |||
$stepsArray = [] ; | |||
if(isset($order->productOrder)) { | |||
foreach($order->productOrder as $productOrder) { | |||
$unitsArray[$productOrder->id_product] = $productOrder->unit; | |||
} | |||
} | |||
} | |||
// produits dispos | |||
@@ -317,14 +324,16 @@ class OrderController extends ProducerBaseController | |||
$productOrder->price = $product->price; | |||
$quantity = (int) $posts['products'][$product->id] ; | |||
$unit = (!is_null($order) && isset($unitsArray[$product->id])) ? $unitsArray[$product->id] : $product->unit ; | |||
$coefficient = Product::$unitsArray[$unit]['coefficient'] ; | |||
$quantity = ((int) $posts['products'][$product->id]) / $coefficient ; | |||
if ($availableProducts[$product->id]['quantity_max'] && $quantity > $availableProducts[$product->id]['quantity_remaining']) { | |||
$quantity = $availableProducts[$product->id]['quantity_remaining']; | |||
} | |||
$productOrder->quantity = $quantity; | |||
$productOrder->sale_mode = Product::SALE_MODE_UNIT ; | |||
$productOrder->unit = $product->unit ; | |||
$productOrder->step = $product->step ; | |||
$productOrder->save(); | |||
} | |||
} | |||
@@ -600,6 +609,8 @@ class OrderController extends ProducerBaseController | |||
$indexProduct = 0 ; | |||
foreach($productsArray as &$product) { | |||
$coefficient_unit = Product::$unitsArray[$product['unit']]['coefficient'] ; | |||
if(is_null($product['photo'])) { | |||
$product['photo'] = '' ; | |||
} | |||
@@ -613,17 +624,23 @@ class OrderController extends ProducerBaseController | |||
$quantityOrderUser = Order::getProductQuantity($product['id'], [$orderUser], true) ; | |||
$product['quantity_ordered'] = $quantityOrder ; | |||
$product['quantity_remaining'] = $product['quantity_max'] - $quantityOrder + $quantityOrderUser ; | |||
$product['quantity_form'] = $quantityOrderUser ; | |||
$product['quantity_form'] = $quantityOrderUser * $coefficient_unit ; | |||
foreach($orderUser->productOrder as $productOrder) { | |||
if($productOrder->id_product == $product['id']) { | |||
$product['wording_unit'] = Product::strUnit($productOrder->unit,'wording_unit', true) ; | |||
$product['step'] = $productOrder->step ; | |||
} | |||
} | |||
} | |||
else { | |||
$product['quantity_form'] = 0 ; | |||
$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 ++ ; | |||
} | |||
$json['products'] = $productsArray; | |||
} | |||
@@ -40,6 +40,7 @@ namespace producer\controllers; | |||
use common\models\SubscriptionForm ; | |||
use common\models\SubscriptionSearch ; | |||
use common\models\Product ; | |||
class SubscriptionController extends ProducerBaseController | |||
{ | |||
@@ -221,33 +222,38 @@ class SubscriptionController extends ProducerBaseController | |||
if($idSubscription > 0) { | |||
// Quantités produit de l'abonnement | |||
$productQuantitiesArray = [] ; | |||
$arrayProductsSubscription = ProductSubscription::searchAll([ | |||
'id_subscription' => $idSubscription | |||
]) ; | |||
if(count($arrayProductsSubscription)) { | |||
foreach ($arrayProductsSubscription as $productSubscription) { | |||
$productQuantitiesArray[$productSubscription->id_product] = $productSubscription->quantity; | |||
} | |||
} | |||
} | |||
// Produits | |||
$productsArray = Product::searchAll() ; | |||
$indexProduct = 0 ; | |||
foreach($productsArray as &$product) { | |||
$quantity = 0 ; | |||
if(isset($productQuantitiesArray) && count($productQuantitiesArray) && isset($productQuantitiesArray[$product->id])) { | |||
$quantity = $productQuantitiesArray[$product->id] ; | |||
$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; | |||
} | |||
} | |||
} | |||
$product = array_merge( | |||
$product->getAttributes(), | |||
[ | |||
'index' => $indexProduct ++, | |||
'quantity_form' => $quantity | |||
'quantity_form' => $quantity, | |||
'coefficient_unit' => $coefficientUnit, | |||
'wording_unit' => Product::strUnit($product->unit, 'wording_unit', true), | |||
'wording_short' => Product::strUnit($product->unit, 'wording_short'), | |||
] | |||
) ; | |||
} |
@@ -37,6 +37,7 @@ termes. | |||
*/ | |||
use yii\widgets\ActiveForm; | |||
use common\models\Product; | |||
?> | |||
<div class="order-form"> | |||
@@ -216,7 +217,9 @@ use yii\widgets\ActiveForm; | |||
<span class="name"><?= Html::encode($product->name); ?></span> - <span class="description"><?= Html::encode($product->getDescription()); ?></span><br /> | |||
<span class="recipe"><?= Html::encode($product->recipe); ?></span> | |||
</td> | |||
<td class="price-unit"><span class="price"><?= number_format($product->price, 2); ?></span> €</td> | |||
<td class="price-unit"> | |||
<span class="price"><?= Price::format($product->price); ?></span> € | |||
</td> | |||
<td class="column-quantity"> | |||
<div class="input-group" <?php if (isset($availableProducts[$product->id]) && $availableProducts[$product->id]['quantity_remaining'] == 0 && $quantity == 0): ?>style="display:none;"<?php endif; ?>> | |||
<span class="input-group-btn"> |
@@ -186,33 +186,34 @@ $this->setTitle('Commander') ; | |||
<span class="other"> | |||
<span v-if="product.description.length">/</span> | |||
<span class="description">{{ product.description }}</span> | |||
<span v-if="product.weight">({{ product.weight }}g)</span> | |||
<span v-if="product.unit == 'piece' && product.weight">({{ product.weight }}g)</span> | |||
</span> | |||
<span v-if="product.quantity_form == product.quantity_remaining && product.quantity_max > 0" class="label label-danger"> | |||
<span v-if="product.quantity_max > 0 && ((product.quantity_form / product.coefficient_unit == product.quantity_remaining) || ((product.quantity_remaining * product.coefficient_unit) - product.quantity_form) < product.step)" class="label label-danger"> | |||
Épuisé | |||
</span> | |||
<div class="recipe" v-if="product.recipe.length">{{ product.recipe }}</div> | |||
</td> | |||
<td class="price-unit"> | |||
{{ formatPrice(product.price) }} | |||
{{ formatPrice(product.price) }}<br /><span class="unit">{{ product.wording_unit }}</span> | |||
</td> | |||
<td class="td-quantity"> | |||
<div class="input-group"> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default btn-moins" type="button" @click="productQuantityClick(product, -1)" :disabled="product.quantity_form == 0"><span class="glyphicon glyphicon-minus"></span></button> | |||
<button class="btn btn-default btn-moins" type="button" @click="productQuantityClick(product, product.unit == 'piece' ? -1 : -parseFloat(product.step))" :disabled="product.quantity_form == 0"><span class="glyphicon glyphicon-minus"></span></button> | |||
</span> | |||
<input type="text" v-model="product.quantity_form" class="form-control quantity" readonly="readonly" /> | |||
<span class="input-group-addon">{{ product.unit == 'piece' ? 'p.' : product.unit }}</span> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default btn-plus" type="button" @click="productQuantityClick(product, 1)" :disabled="product.quantity_form == product.quantity_remaining && product.quantity_max > 0"><span class="glyphicon glyphicon-plus"></span></button> | |||
<button class="btn btn-default btn-plus" type="button" @click="productQuantityClick(product, product.unit == 'piece' ? 1 : parseFloat(product.step))" :disabled="product.quantity_form == product.quantity_remaining && product.quantity_max > 0"><span class="glyphicon glyphicon-plus"></span></button> | |||
</span> | |||
</div> | |||
</td> | |||
<td class="price-total"> | |||
{{ formatPrice(product.price * product.quantity_form) }} | |||
{{ formatPrice(product.price * (product.quantity_form / product.coefficient_unit )) }} | |||
</td> | |||
</tr> | |||
<tr class="total"> | |||
<td colspan="3"></td> | |||
<td colspan="4"></td> | |||
<td class="price-total">{{ priceTotal(true) }}</td> | |||
</tr> | |||
</tbody> |
@@ -125,7 +125,7 @@ $this->setPageTitle(Html::encode($producer->type.' à '.$producer->city)) ; | |||
'attribute' => 'price', | |||
'value' => function($model) { | |||
if($model->price) { | |||
return Price::format($model->price) ; | |||
return Price::format($model->price).' ('.Product::strUnit($model->unit, 'wording_unit', true).')' ; | |||
} | |||
return '' ; | |||
} |
@@ -215,21 +215,24 @@ use common\models\PointSale ; | |||
<div class="recipe" v-if="product.recipe.length">{{ product.recipe }}</div> | |||
</td> | |||
<td class="price-unit"> | |||
{{ formatPrice(product.price) }} | |||
{{ formatPrice(product.price) }}<br /><span class="unit">{{ product.wording_unit }}</span> | |||
</td> | |||
<td class="quantity"> | |||
<div class="input-group"> | |||
<input type="hidden" :value="product.step" :name="'product_step_'+product.step" /> | |||
<input type="hidden" :value="product.unit" :name="'product_unit_'+product.unit" /> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default" type="button" @click="productQuantityClick(product, -1)"><span class="glyphicon glyphicon-minus"></span></button> | |||
<button class="btn btn-default" type="button" @click="productQuantityClick(product, -product.step)"><span class="glyphicon glyphicon-minus"></span></button> | |||
</span> | |||
<input type="text" v-model="product.quantity_form" :class="'form-control '+((product.quantity_form > 0) ? 'has-quantity' : '')"> | |||
<span class="input-group-addon">{{ product.wording_short }}</span> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default" type="button" @click="productQuantityClick(product, 1)"><span class="glyphicon glyphicon-plus"></span></button> | |||
<button class="btn btn-default" type="button" @click="productQuantityClick(product, product.step)"><span class="glyphicon glyphicon-plus"></span></button> | |||
</span> | |||
</div> | |||
</td> | |||
<td class="price-total"> | |||
{{ formatPrice(product.price * product.quantity_form) }} | |||
{{ formatPrice(product.price * (product.quantity_form / product.coefficient_unit )) }} | |||
</td> | |||
</tr> | |||
<tr class="total"> |
@@ -38,6 +38,7 @@ termes. | |||
use yii\helpers\Html; | |||
use yii\grid\GridView; | |||
use common\models\Product ; | |||
$this->setTitle('Abonnements') ; | |||
$this->addButton(['label' => '<span class="glyphicon glyphicon-plus"></span> Ajouter', 'url' => 'subscription/form', 'class' => 'btn btn-primary']) ; | |||
@@ -52,7 +53,7 @@ $columns = [ | |||
foreach($model->productSubscription as $productSubscription) | |||
{ | |||
if(isset($productSubscription->product)) { | |||
$html .= $productSubscription->quantity . ' x '.Html::encode($productSubscription->product->name).'<br />' ; | |||
$html .= Html::encode($productSubscription->product->name).' ('.($productSubscription->quantity * Product::$unitsArray[$productSubscription->unit]['coefficient']) . ' '.Product::strUnit($productSubscription->unit, 'wording_short').')<br />' ; | |||
} | |||
else { | |||
$html .= 'Produit non défini<br />' ; |
@@ -1486,31 +1486,45 @@ termes. | |||
text-align: center; | |||
} | |||
/* line 224, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products .price-unit .unit, .order-order #app-order-order table#products .price-total .unit { | |||
color: gray; | |||
font-size: 13px; | |||
} | |||
/* line 229, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products .td-quantity { | |||
width: 150px; | |||
width: 175px; | |||
} | |||
/* line 226, ../sass/order/_order.scss */ | |||
/* line 231, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products .td-quantity input.quantity { | |||
text-align: center; | |||
border-right: 0px none; | |||
} | |||
/* line 232, ../sass/order/_order.scss */ | |||
/* line 235, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products .td-quantity .input-group-addon { | |||
padding: 5px; | |||
padding-left: 0px; | |||
margin: 0px; | |||
border-left: 0px none; | |||
border-right: 0px none; | |||
} | |||
/* line 245, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products tr.total .price-total { | |||
font-size: 23px; | |||
} | |||
/* line 240, ../sass/order/_order.scss */ | |||
/* line 253, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #content-step-payment .credit .info { | |||
margin-left: 20px; | |||
color: gray; | |||
} | |||
/* line 246, ../sass/order/_order.scss */ | |||
/* line 259, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #content-step-payment .comment { | |||
margin-bottom: 20px; | |||
} | |||
/* line 251, ../sass/order/_order.scss */ | |||
/* line 264, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #infos { | |||
margin-top: 30px; | |||
} | |||
/* line 253, ../sass/order/_order.scss */ | |||
/* line 266, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #infos .panel-body { | |||
padding-top: 0px; | |||
white-space: pre-line; | |||
@@ -1663,43 +1677,57 @@ termes. | |||
/* line 73, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products td.quantity, | |||
.subscription-update .subscription-form .products td.quantity { | |||
width: 150px; | |||
width: 180px; | |||
} | |||
/* line 76, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products td.quantity input, | |||
.subscription-update .subscription-form .products td.quantity input { | |||
text-align: center; | |||
border-right: 0px none; | |||
} | |||
/* line 79, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products td.quantity input.has-quantity, | |||
.subscription-update .subscription-form .products td.quantity input.has-quantity { | |||
font-weight: bold; | |||
} | |||
/* line 85, ../sass/subscription/_form.scss */ | |||
/* line 84, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products td.quantity .input-group-addon, | |||
.subscription-update .subscription-form .products td.quantity .input-group-addon { | |||
background-color: white; | |||
padding-left: 0px; | |||
border-left: 0px none; | |||
} | |||
/* line 91, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products .name, | |||
.subscription-update .subscription-form .products .name { | |||
font-family: "capsuularegular"; | |||
font-size: 20px; | |||
color: black; | |||
} | |||
/* line 91, ../sass/subscription/_form.scss */ | |||
/* line 97, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products .description, | |||
.subscription-update .subscription-form .products .description { | |||
font-style: italic; | |||
} | |||
/* line 95, ../sass/subscription/_form.scss */ | |||
/* line 101, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products .recipe, | |||
.subscription-update .subscription-form .products .recipe { | |||
font-size: 12px; | |||
} | |||
/* line 99, ../sass/subscription/_form.scss */ | |||
/* line 105, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products .price-unit, .subscription-create .subscription-form .products .price-total, | |||
.subscription-update .subscription-form .products .price-unit, | |||
.subscription-update .subscription-form .products .price-total { | |||
text-align: center; | |||
width: 150px; | |||
} | |||
/* line 104, ../sass/subscription/_form.scss */ | |||
/* line 110, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products .unit, | |||
.subscription-update .subscription-form .products .unit { | |||
color: gray; | |||
font-size: 13px; | |||
} | |||
/* line 115, ../sass/subscription/_form.scss */ | |||
.subscription-create .subscription-form .products tr.total .price-total, | |||
.subscription-update .subscription-form .products tr.total .price-total { | |||
text-align: center; |
@@ -255,8 +255,9 @@ var app = new Vue({ | |||
this.changeStep('products') ; | |||
}, | |||
productQuantityClick: function(product, quantity) { | |||
console.log(this.products[product.index].quantity_remaining) ; | |||
if( this.products[product.index].quantity_form + quantity >= 0 && | |||
(this.products[product.index].quantity_form + quantity <= this.products[product.index].quantity_remaining || | |||
(this.products[product.index].quantity_form + quantity <= (this.products[product.index].quantity_remaining * this.products[product.index].coefficient_unit) || | |||
!this.products[product.index].quantity_max) | |||
) { | |||
this.products[product.index].quantity_form += quantity ; | |||
@@ -274,7 +275,12 @@ var app = new Vue({ | |||
var count = 0 ; | |||
for(var key in this.products) { | |||
if(this.products[key].quantity_form > 0) { | |||
count += this.products[key].quantity_form ; | |||
if(this.products[key].unit != 'piece') { | |||
count ++ ; | |||
} | |||
else { | |||
count += this.products[key].quantity_form ; | |||
} | |||
} | |||
} | |||
return count ; | |||
@@ -283,7 +289,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].price ; | |||
price += (this.products[key].quantity_form / this.products[key].coefficient_unit) * this.products[key].price ; | |||
} | |||
} | |||
if(format) { |
@@ -179,7 +179,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].price ; | |||
price += (this.products[key].quantity_form / this.products[key].coefficient_unit) * this.products[key].price ; | |||
} | |||
} | |||
if(format) { |
@@ -220,11 +220,24 @@ | |||
.price-unit, .price-total { | |||
width: 100px ; | |||
text-align: center ; | |||
.unit { | |||
color: gray ; | |||
font-size: 13px ; | |||
} | |||
} | |||
.td-quantity { | |||
width: 150px ; | |||
width: 175px ; | |||
input.quantity { | |||
text-align: center ; | |||
border-right: 0px none ; | |||
} | |||
.input-group-addon { | |||
padding: 5px ; | |||
padding-left: 0px ; | |||
margin: 0px ; | |||
border-left: 0px none ; | |||
border-right: 0px none ; | |||
} | |||
} | |||
@@ -71,15 +71,21 @@ | |||
} | |||
td.quantity { | |||
width: 150px ; | |||
width: 180px ; | |||
input { | |||
text-align: center ; | |||
border-right: 0px none ; | |||
&.has-quantity { | |||
font-weight: bold ; | |||
} | |||
} | |||
.input-group-addon { | |||
background-color: white ; | |||
padding-left: 0px ; | |||
border-left: 0px none ; | |||
} | |||
} | |||
.name { | |||
@@ -101,6 +107,11 @@ | |||
width: 150px ; | |||
} | |||
.unit { | |||
color: gray ; | |||
font-size: 13px ; | |||
} | |||
tr.total .price-total { | |||
text-align: center ; | |||
font-size: 20px ; |