@@ -59,6 +59,11 @@ return [ | |||
'httpOnly' => true, | |||
], | |||
], | |||
'request' => [ | |||
'parsers' => [ | |||
'application/json' => 'yii\web\JsonParser', | |||
] | |||
], | |||
'cache' => [ | |||
'class' => 'yii\caching\FileCache', | |||
], |
@@ -0,0 +1,62 @@ | |||
<?php | |||
/** | |||
Copyright La boîte à pain (2018) | |||
contact@laboiteapain.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\assets; | |||
use yii\web\AssetBundle; | |||
use yii ; | |||
/** | |||
* @author Qiang Xue <qiang.xue@gmail.com> | |||
* @since 2.0 | |||
*/ | |||
class VuejsOrderOrderAsset 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/order-order.js') ; | |||
} | |||
} |
@@ -39,9 +39,14 @@ termes. | |||
namespace producer\controllers; | |||
use common\models\ProductDistribution ; | |||
use common\models\User ; | |||
use common\models\Producer ; | |||
use common\models\Order ; | |||
use DateTime; | |||
class OrderController extends ProducerBaseController | |||
{ | |||
var $enableCsrfValidation = false; | |||
public function behaviors() | |||
{ | |||
@@ -57,6 +62,11 @@ class OrderController extends ProducerBaseController | |||
], | |||
]; | |||
} | |||
public function actionOrder() | |||
{ | |||
return $this->render('order') ; | |||
} | |||
/** | |||
* Retourne au format JSON toutes les informations relatives à une | |||
@@ -130,7 +140,9 @@ class OrderController extends ProducerBaseController | |||
$deadline = 20; | |||
$date = date('Y-m-d'); | |||
if (isset($producer)) { | |||
$deadline = $producer->order_deadline; | |||
if($producer->order_deadline) { | |||
$deadline = $producer->order_deadline; | |||
} | |||
if (date('H') >= $deadline) { | |||
$date = date('Y-m-d', strtotime(date('Y-m-d')) + ($producer->order_delay) * (24 * 60 * 60)); | |||
} else { | |||
@@ -269,22 +281,26 @@ class OrderController extends ProducerBaseController | |||
* | |||
* @return mixed | |||
*/ | |||
public function actionCreate() | |||
public function actionAjaxProcess() | |||
{ | |||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||
$order = new Order ; | |||
$idProducer = $this->getProducer()->id ; | |||
$order = new Order; | |||
$posts = Yii::$app->request->post(); | |||
if ($idProducer) { | |||
$this->_verifyProducerActive($idProducer); | |||
} | |||
if ($order->load($posts)) { | |||
$order = Order::find() | |||
->where('id_distribution = ' . $posts['Order']['id_distribution']) | |||
->andWhere('id_user = ' . User::getCurrentId()) | |||
->where('id_distribution = :id_distribution') | |||
->andWhere('id_user = :id_user') | |||
->params([ | |||
':id_distribution' => $posts['Order']['id_distribution'], | |||
':id_user' => User::getCurrentId() | |||
]) | |||
->one(); | |||
if (!$order) { | |||
@@ -295,12 +311,14 @@ class OrderController extends ProducerBaseController | |||
$order->origin = Order::ORIGIN_USER; | |||
} | |||
$this->processForm($order); | |||
$errors = $this->processForm($order); | |||
if(count($errors)) { | |||
return ['status' => 'error', 'errors' => $errors] ; | |||
} | |||
} | |||
return $this->render('create', array_merge($this->initForm($order), [ | |||
'model' => $order | |||
])); | |||
return ['status' => 'success'] ; | |||
} | |||
/** | |||
@@ -359,9 +377,8 @@ class OrderController extends ProducerBaseController | |||
$totalQuantity = 0; | |||
foreach ($posts['Product'] as $key => $quantity) { | |||
$key = (int) str_replace('product_', '', $key); | |||
$product = Product::find()->where(['id' => $key])->one(); | |||
foreach ($posts['products'] as $key => $quantity) { | |||
$product = Product::find()->where(['id' => (int) $key])->one(); | |||
$totalQuantity += $quantity; | |||
if ($product && $quantity) { | |||
$productsArray[] = $product; | |||
@@ -400,7 +417,7 @@ class OrderController extends ProducerBaseController | |||
$pointSale = PointSale::findOne($posts['Order']['id_point_sale']); | |||
if ($pointSale) { | |||
if (strlen($pointSale->code) && !$pointSale->validateCode($posts['code_point_sale_' . $pointSale->id])) { | |||
if (strlen($pointSale->code) && !$pointSale->validateCode($posts['code_point_sale'])) { | |||
$errorPointSale = true; | |||
} | |||
} else { | |||
@@ -408,6 +425,8 @@ class OrderController extends ProducerBaseController | |||
} | |||
} | |||
$errors = [] ; | |||
if ($order->validate() && count($productsArray) && !$errorDate && !$errorPointSale) { | |||
// gestion point de vente | |||
@@ -445,7 +464,7 @@ class OrderController extends ProducerBaseController | |||
$productOrder->price = $product->price; | |||
$quantity = (int) $posts['Product']['product_' . $product->id]; | |||
$quantity = (int) $posts['products'][$product->id] ; | |||
if ($availableProducts[$product->id]['quantity_max'] && $quantity > $availableProducts[$product->id]['quantity_remaining']) { | |||
$quantity = $availableProducts[$product->id]['quantity_remaining']; | |||
} | |||
@@ -458,7 +477,7 @@ class OrderController extends ProducerBaseController | |||
} | |||
// credit | |||
$credit = isset($posts['credit']) && $posts['credit']; | |||
$credit = Producer::getConfig('credit'); | |||
$order = Order::searchOne([ | |||
'id' => $order->id | |||
]) ; | |||
@@ -498,20 +517,21 @@ class OrderController extends ProducerBaseController | |||
} | |||
// redirection | |||
$this->redirect(Yii::$app->urlManager->createUrl(['order/history', 'orderOk' => true])); | |||
//$this->redirect(Yii::$app->urlManager->createUrl(['order/history', 'orderOk' => true])); | |||
} | |||
else { | |||
if (!count($productsArray)) { | |||
Yii::$app->session->setFlash('error', "Vous n'avez choisi aucun produit"); | |||
$errors[] = "Vous n'avez choisi aucun produit" ; | |||
} | |||
if ($errorDate) { | |||
Yii::$app->session->setFlash('error', "Vous ne pouvez pas commander pour cette date."); | |||
$errors[] = "Vous ne pouvez pas commander pour cette date." ; | |||
} | |||
if ($errorPointSale) { | |||
Yii::$app->session->setFlash('error', "Point de vente invalide."); | |||
$errors[] = "Point de vente invalide." ; | |||
} | |||
} | |||
return $errors ; | |||
} | |||
/** | |||
@@ -563,15 +583,174 @@ class OrderController extends ProducerBaseController | |||
* @param string $code | |||
* @return boolean | |||
*/ | |||
public function actionValidateCodePointSale($idPointSale, $code) | |||
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 true; | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
public function actionAjaxInfos($date = '') | |||
{ | |||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||
$json = [] ; | |||
$format = 'Y-m-d' ; | |||
$dateObject = DateTime::createFromFormat($format, $date); | |||
// Producteur | |||
$producer = Producer::searchOne([ | |||
'id' => $this->getProducer()->id | |||
]) ; | |||
$json['producer'] = [ | |||
'order_infos' => $producer->order_infos, | |||
'credit' => $producer->credit | |||
] ; | |||
// Distributions | |||
$deadline = 20; | |||
$dateMini = date('Y-m-d'); | |||
if (isset($producer)) { | |||
if($producer->order_deadline) { | |||
$deadline = $producer->order_deadline; | |||
} | |||
if (date('H') >= $deadline) { | |||
$dateMini = date('Y-m-d', strtotime(date('Y-m-d')) + ($producer->order_delay) * (24 * 60 * 60)); | |||
} else { | |||
$dateMini = date('Y-m-d', strtotime(date('Y-m-d')) + ($producer->order_delay - 1) * (24 * 60 * 60)); | |||
} | |||
} | |||
$distributionsArray = Distribution::searchAll([ | |||
'active' => 1 | |||
], [ | |||
'conditions' => ['date > :date'], | |||
'params' => [':date' => $dateMini], | |||
]) ; | |||
$json['distributions'] = $distributionsArray ; | |||
// Commandes de l'utilisateur | |||
$ordersUserArray = Order::searchAll([ | |||
'id_user' => User::getCurrentId() | |||
], [ | |||
'conditions' => [ | |||
'distribution.date > :date' | |||
], | |||
'params' => [ | |||
':date' => $dateMini | |||
] | |||
]); | |||
foreach($ordersUserArray as &$order) { | |||
$order = array_merge($order->getAttributes(), [ | |||
'amount_total' => $order->getAmount(Order::AMOUNT_TOTAL), | |||
'date_distribution' => $order->distribution->date, | |||
'pointSale' => $order->pointSale->getAttributes() | |||
]) ; | |||
} | |||
$json['orders'] = $ordersUserArray; | |||
// User | |||
$userProducer = UserProducer::searchOne([ | |||
'id_producer' => $producer->id, | |||
'id_user' => User::getCurrentId() | |||
]) ; | |||
$json['credit'] = $userProducer->credit ; | |||
if($dateObject && $dateObject->format($format) === $date) { | |||
// Commande de l'utilisateur | |||
$orderUser = Order::searchOne([ | |||
'distribution.date' => $date, | |||
'id_user' => User::getCurrentId(), | |||
]); | |||
if($orderUser) { | |||
$json['order'] = array_merge($orderUser->getAttributes(), [ | |||
'amount_total' => $orderUser->getAmount(Order::AMOUNT_TOTAL), | |||
'amount_paid' => $orderUser->getAmount(Order::AMOUNT_PAID), | |||
]) ; | |||
} | |||
// distribution | |||
$distribution = Distribution::initDistribution($date) ; | |||
$json['distribution'] = $distribution ; | |||
$pointsSaleArray = PointSale::find() | |||
->joinWith(['pointSaleDistribution' => function($query) use ($distribution) { | |||
$query->where(['id_distribution' => $distribution->id]); | |||
} | |||
]) | |||
->with(['userPointSale' => function($query) { | |||
$query->onCondition(['id_user' => User::getCurrentId()]) ; | |||
}]) | |||
->where([ | |||
'id_producer' => $distribution->id_producer, | |||
]) | |||
->all(); | |||
foreach($pointsSaleArray as &$pointSale) { | |||
$pointSale = array_merge($pointSale->getAttributes(),[ | |||
'pointSaleDistribution' => [ | |||
'id_distribution' => $pointSale->pointSaleDistribution[0]->id_distribution, | |||
'id_point_sale' => $pointSale->pointSaleDistribution[0]->id_point_sale, | |||
'delivery' => $pointSale->pointSaleDistribution[0]->delivery | |||
], | |||
'userPointSale' => ($pointSale->userPointSale ? $pointSale->userPointSale[0] : '') | |||
]) ; | |||
} | |||
$json['points_sale'] = $pointsSaleArray; | |||
// Commandes totales | |||
$ordersArray = Order::searchAll([ | |||
'distribution.date' => $date, | |||
]); | |||
// Produits | |||
$productsArray = Product::find() | |||
->where([ | |||
'id_producer' => $this->getProducer()->id, | |||
]) | |||
->joinWith(['productDistribution' => function($query) use($distribution) { | |||
$query->andOnCondition('product_distribution.id_distribution = '.$distribution->id) ; | |||
}]) | |||
->orderBy('product_distribution.active DESC, order ASC') | |||
->asArray() | |||
->all(); | |||
$indexProduct = 0 ; | |||
foreach($productsArray as &$product) { | |||
$quantityOrder = Order::getProductQuantity($product['id'], $ordersArray) ; | |||
$product['quantity_ordered'] = $quantityOrder ; | |||
$product['quantity_remaining'] = $product['quantity_max'] - $quantityOrder ; | |||
if($orderUser) { | |||
$quantityOrderUser = Order::getProductQuantity($product['id'], [$orderUser]) ; | |||
$product['quantity_ordered'] = $quantityOrder ; | |||
$product['quantity_remaining'] = $product['quantity_max'] - $quantityOrder + $quantityOrderUser ; | |||
$product['quantity_form'] = $quantityOrderUser ; | |||
} | |||
else { | |||
$product['quantity_form'] = 0 ; | |||
} | |||
if($product['quantity_remaining'] < 0) $product['quantity_remaining'] = 0 ; | |||
$product['index'] = $indexProduct ++ ; | |||
} | |||
$json['products'] = $productsArray; | |||
} | |||
return false; | |||
return $json ; | |||
} | |||
} |
@@ -155,15 +155,15 @@ $producer = $this->context->getProducer() ; | |||
], | |||
[ | |||
'label' => '<span class="glyphicon glyphicon-plus"></span> Commander', | |||
'url' => Yii::$app->urlManager->createUrl(['order/create']), | |||
'url' => Yii::$app->urlManager->createUrl(['order/order']), | |||
'visible' => !Yii::$app->user->isGuest, | |||
'active' => $this->getControllerAction() == 'order/create' || $this->getControllerAction() == 'order/update', | |||
'active' => $this->getControllerAction() == 'order/order', | |||
], | |||
[ | |||
'label' => '<span class="glyphicon glyphicon-plus"></span> Commander', | |||
'url' => Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/producer','id' => $this->context->getProducer()->id,'return_url' => Yii::$app->urlManagerProducer->createAbsoluteUrl(['order/create','slug_producer' => $this->context->getProducer()->slug])]), | |||
'url' => Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/producer','id' => $this->context->getProducer()->id,'return_url' => Yii::$app->urlManagerProducer->createAbsoluteUrl(['order/order','slug_producer' => $this->context->getProducer()->slug])]), | |||
'visible' => Yii::$app->user->isGuest, | |||
'active' => $this->getControllerAction() == 'order/create' || $this->getControllerAction() == 'order/update', | |||
'active' => $this->getControllerAction() == 'order/order', | |||
], | |||
[ | |||
'label' => '<span class="glyphicon glyphicon-folder-open"></span> Historique', |
@@ -0,0 +1,271 @@ | |||
<?php | |||
/** | |||
Copyright La boîte à pain (2018) | |||
contact@laboiteapain.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. | |||
*/ | |||
\producer\assets\VuejsOrderOrderAsset::register($this); | |||
$this->setTitle('Commander') ; | |||
?> | |||
<div id="app-order-order" :class="{'loaded': !loadingInit}"> | |||
<div v-if="orderSuccess" id="order-success"> | |||
<div class="alert alert-success"> | |||
<span class="glyphicon glyphicon-ok glyphicon-big"></span> | |||
<div class="content"> | |||
<h3>Votre commande a bien été prise en compte</h3> | |||
<a href="<?= Yii::$app->urlManagerProducer->createUrl(['order/history']) ?>" class="btn btn-default"> | |||
<span class="glyphicon glyphicon-chevron-right"></span> | |||
Voir toutes mes commandes | |||
</a> | |||
</div> | |||
<div class="clr"></div> | |||
</div> | |||
<div class="alert alert-info"> | |||
<span class="glyphicon glyphicon-list-alt glyphicon-big"></span> | |||
<div class="content"> | |||
<h3>Récapitulatif de votre commande</h3> | |||
<ul> | |||
<li><span class="glyphicon glyphicon-time"></span> {{ dateFormat }}</li> | |||
<li><span class="glyphicon glyphicon-map-marker"></span> {{ pointSaleActive.name }} <span class="locality" v-if="pointSaleActive.locality.length > 0">à {{ pointSaleActive.locality }}</span></li> | |||
<li><span class="glyphicon glyphicon-th-list"></span> {{ countProductOrdered() }} produits</li> | |||
<li><span class="glyphicon glyphicon-chevron-right"></span> {{ priceTotal(true) }}</li> | |||
</ul> | |||
</div> | |||
<div class="clr"></div> | |||
</div> | |||
</div> | |||
<div v-else> | |||
<div :class="(producer != null && producer.order_infos.length) ? 'col-md-9' : 'col-md-12'"> | |||
<div id="steps"> | |||
<ul> | |||
<li id="step-date" :class="'col-md-3 '+((step == 'date') ? 'active' : '')"> | |||
<div class="info-step" v-if="dateFormat"> | |||
{{ dateFormat }} | |||
</div> | |||
<button @click="changeStep('date')" :class="'btn '+ (step == 'date' ? 'btn-primary' : 'btn-default')"> | |||
<span class="button-content"><span class="glyphicon glyphicon-time"></span> Date</span></span> | |||
</button> | |||
</li> | |||
<li id="step-point-sale" :class="'col-md-3 '+((step == 'point-sale') ? 'active ' : '')"> | |||
<div class="info-step" v-if="pointSaleActive"> | |||
{{ pointSaleActive.name }} | |||
</div> | |||
<button @click="changeStep('point-sale')" :class="'btn '+ (step == 'point-sale' ? 'btn-primary' : 'btn-default')" :disabled="step == 'date'"> | |||
<span class="button-content"><span class="glyphicon glyphicon-map-marker"></span> Points de vente</span> | |||
</button> | |||
</li> | |||
<li id="step-products" :class="'col-md-3 '+((step == 'products') ? 'active ' : '')"> | |||
<div class="info-step" v-if="oneProductOrdered()"> | |||
{{ countProductOrdered() }} produit{{ (countProductOrdered() > 1) ? 's' : '' }} | |||
</div> | |||
<button @click="changeStep('products')" :class="'btn '+ (step == 'products' ? 'btn-primary' : 'btn-default')" :disabled="step == 'date' || step == 'point-sale'"> | |||
<span class="button-content"><span class="glyphicon glyphicon-th-list"></span> Produits</span> | |||
</button> | |||
</li> | |||
<li id="step-payment" :class="'col-md-3 '+((step == 'payment') ? 'active' : '')"> | |||
<button @click="changeStep('payment')" :class="'btn '+ (step == 'payment' ? 'btn-primary' : 'btn-default')" :disabled="step == 'date' || step == 'point-sale' || step == 'products'"> | |||
<span class="button-content"><span class="glyphicon glyphicon-ok"></span> Confirmation</span> | |||
</button> | |||
</li> | |||
</ul> | |||
<div class="clr"></div> | |||
</div> | |||
<div class="content"> | |||
<transition name="slide"> | |||
<div id="content-step-date" v-if="step == 'date'"> | |||
<div id="legend"> | |||
<div><span id="distribution-date-color"></span> Prochains jours de distribution</div> | |||
<div><span id="order-date-color"></span> Vos commandes déjà enregistrées</div> | |||
</div> | |||
<div id="calendar"> | |||
<v-calendar | |||
is-inline | |||
is-double-paned | |||
is-expanded | |||
v-model="date" | |||
mode="single" | |||
:formats="calendar.formats" | |||
:theme-styles="calendar.themeStyles" | |||
:attributes="calendar.attrs" | |||
:available-dates="calendar.availableDates" | |||
@dayclick='dayClick'> | |||
></v-calendar> | |||
</div> | |||
</div> | |||
</transition> | |||
<transition name="slide"> | |||
<div id="content-step-point-sale" v-if="step == 'point-sale'"> | |||
<div v-if="loading"> | |||
Chargement ... | |||
</div> | |||
<div v-else> | |||
<table id="points-sale" class="table table-bordered" v-if="pointsSale.length"> | |||
<thead> | |||
<tr> | |||
<th>Nom</th> | |||
<th>Localité</th> | |||
<th></th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr v-for="pointSale in pointsSale" v-if="pointSale && pointSale.pointSaleDistribution.delivery" :class="(pointSaleActive && pointSale.id == pointSaleActive.id) ? 'selected' : ''"> | |||
<td class="name"> | |||
<span class="the-name">{{ pointSale.name }}</span> | |||
<div class="comment" v-if="pointSale.userPointSale"> | |||
{{ pointSale.userPointSale.comment }} | |||
</div> | |||
</td> | |||
<td class="locality">{{ pointSale.locality }}</td> | |||
<td class="actions"> | |||
<div :class="'form-group' + (pointSale.invalid_code ? ' has-error' : '')"> | |||
<div class="input-group" v-if="pointSale.code.length > 0"> | |||
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span> | |||
<input v-model="pointsSaleCodes[pointSale.id]" type="password" placeholder="Code" class="form-control input-code" /> | |||
</div> | |||
</div> | |||
<button class="btn btn-primary" @click="pointSaleClick" :data-code="pointSale.code.length > 0" :data-id-point-sale="pointSale.id"> | |||
<span class="glyphicon glyphicon-map-marker"></span> | |||
Choisir | |||
</button> | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<div class="alert alert-warning" v-else> | |||
Aucun point de vente disponible pour ce jour de distribution. | |||
</div> | |||
</div> | |||
</div> | |||
</transition> | |||
<transition name="slide"> | |||
<div id="content-step-products" v-if="step == 'products'"> | |||
<div v-if="products.length"> | |||
<table id="products" class="table table-bordered" > | |||
<thead> | |||
<tr> | |||
<th>Nom</th> | |||
<th>Prix unitaire</th> | |||
<th>Quantité</th> | |||
<th>Total</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr v-for="product in products" v-if="product.productDistribution[0].active == 1"> | |||
<td class="name"> | |||
<span class="name">{{ product.name }}</span> | |||
<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> | |||
<span v-if="product.quantity_form == product.quantity_remaining && product.quantity_max > 0" 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) }} | |||
</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> | |||
</span> | |||
<input type="text" v-model="product.quantity_form" class="form-control quantity" readonly="readonly" /> | |||
<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> | |||
</span> | |||
</div> | |||
</td> | |||
<td class="price-total"> | |||
{{ formatPrice(product.price * product.quantity_form) }} | |||
</td> | |||
</tr> | |||
<tr class="total"> | |||
<td colspan="3"></td> | |||
<td class="price-total">{{ priceTotal(true) }}</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<div class="block-actions"> | |||
<button class="btn btn-primary" @click="changeStep('payment')">Valider</button> | |||
</div> | |||
</div> | |||
<div class="alert alert-warning" v-else> | |||
Aucun produit disponible | |||
</div> | |||
</div> | |||
</transition> | |||
<transition name="slide"> | |||
<div id="content-step-payment" v-if="step == 'payment'"> | |||
<div class="comment"> | |||
<label for="order-comment">Commentaire</label> | |||
<textarea id="order-comment" v-model="comment" class="form-control"></textarea> | |||
</div> | |||
<div class="credit"> | |||
<div v-if="producer.credit == 1 && pointSaleActive.credit == 1"> | |||
<span class="glyphicon glyphicon-chevron-right"></span> La commande va être réglée via votre Crédit ({{ formatPrice(credit) }}). | |||
<div class="info"> | |||
<span v-if="order == null || order.amount_paid == 0">{{ priceTotal(true) }} seront débités</span> | |||
<span v-else-if="order != null && order.amount_paid > 0 && order.amount_paid < priceTotal()">{{ formatPrice(priceTotal() - order.amount_paid) }} seront débités</span> | |||
<span v-else-if="order != null && order.amount_paid > priceTotal()">{{ formatPrice(order.amount_paid - priceTotal()) }} seront remboursés</span> | |||
</div> | |||
</div> | |||
<div v-else> | |||
<span class="glyphicon glyphicon-chevron-right"></span> La commande sera à régler sur place. | |||
</div> | |||
</div> | |||
<div class="block-actions"> | |||
<button class="btn btn-primary" @click="confirmClick">Je confirme ma commande</button> | |||
</div> | |||
</div> | |||
</transition> | |||
</div> | |||
</div> | |||
<div id="infos" class="col-md-3" v-if="producer != null && producer.order_infos.length"> | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Informations | |||
</div> | |||
<div class="panel-body"> | |||
{{ producer.order_infos }} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@@ -1170,6 +1170,274 @@ termes. | |||
display: none; | |||
} | |||
/* line 3, ../sass/order/_order.scss */ | |||
.order-order #app-order-order { | |||
display: none; | |||
} | |||
/* line 7, ../sass/order/_order.scss */ | |||
.order-order #app-order-order.loaded { | |||
display: block; | |||
} | |||
/* line 11, ../sass/order/_order.scss */ | |||
.order-order #app-order-order .slide-enter-active { | |||
transition: all .2s ease; | |||
} | |||
/* line 15, ../sass/order/_order.scss */ | |||
.order-order #app-order-order .slide-leave-active { | |||
transition: all 0s ease; | |||
} | |||
/* line 19, ../sass/order/_order.scss */ | |||
.order-order #app-order-order .slide-enter, .order-order #app-order-order .slide-leave-to { | |||
transform: translateX(10px); | |||
opacity: 0; | |||
} | |||
/* line 24, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps { | |||
margin-bottom: 20px; | |||
} | |||
/* line 26, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul { | |||
margin-top: 30px; | |||
} | |||
/* line 28, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li { | |||
text-align: center; | |||
padding-right: 8px; | |||
padding-left: 8px; | |||
position: relative; | |||
} | |||
/* line 34, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .info-step { | |||
position: absolute; | |||
top: -30px; | |||
left: 0px; | |||
width: 100%; | |||
text-transform: normal; | |||
} | |||
/* line 42, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .glyphicon-chevron-right, .order-order #app-order-order #steps ul li.active .glyphicon-chevron-right { | |||
float: right; | |||
color: gray; | |||
position: relative; | |||
top: 10px; | |||
} | |||
/* line 50, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li#step-date { | |||
padding-left: 0px; | |||
} | |||
/* line 54, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li#step-payment { | |||
padding-right: 0px; | |||
} | |||
/* line 58, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li#step-payment .btn::after, .order-order #app-order-order #steps ul li#step-date .btn::before { | |||
display: none; | |||
} | |||
/* line 63, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .btn { | |||
color: #333; | |||
text-transform: uppercase; | |||
display: block; | |||
width: 100%; | |||
position: relative; | |||
background-color: #e0e0e0; | |||
-moz-border-radius: 0px; | |||
-webkit-border-radius: 0px; | |||
border-radius: 0px; | |||
border: 0px none; | |||
text-transform: uppercase; | |||
} | |||
/* line 74, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .btn .button-content { | |||
position: relative; | |||
left: 8px; | |||
} | |||
/* line 79, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .btn.btn-primary { | |||
background-color: #BB8757; | |||
} | |||
/* line 83, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .btn::after, .order-order #app-order-order #steps ul li .btn::before { | |||
content: ""; | |||
position: absolute; | |||
top: -1px; | |||
} | |||
/* line 89, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .btn::after { | |||
right: -34px; | |||
border: 17px solid transparent; | |||
border-left: 17px solid #e0e0e0; | |||
background-color: transparent; | |||
} | |||
/* line 96, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .btn::before { | |||
left: 0px; | |||
border: 17px solid transparent; | |||
border-left: 17px solid white; | |||
background-color: transparent; | |||
} | |||
/* line 103, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .btn.btn-primary::after { | |||
border-left: 17px solid #BB8757; | |||
} | |||
/* line 117, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #steps ul li .btn-primary { | |||
color: white; | |||
} | |||
/* line 125, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #legend #order-date-color, | |||
.order-order #app-order-order #legend #distribution-date-color { | |||
width: 13px; | |||
height: 13px; | |||
display: inline-block; | |||
} | |||
/* line 132, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #legend #order-date-color { | |||
background-color: #018548; | |||
} | |||
/* line 135, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #legend #distribution-date-color { | |||
background-color: #00A65A; | |||
} | |||
/* line 140, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #calendar { | |||
margin-bottom: 15px; | |||
} | |||
/* line 142, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #calendar .c-header .c-title-layout .c-title-popover .c-title-anchor .c-title[data-v-2083cb72] { | |||
font-size: 2rem; | |||
} | |||
/* line 145, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #calendar .c-day-background { | |||
padding: 20px; | |||
} | |||
/* line 150, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #calendar .c-day:hover .c-day-background { | |||
background-color: #F39C12 !important; | |||
} | |||
/* line 155, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #calendar .c-day-popover-content { | |||
font-size: 1.3rem; | |||
} | |||
/* line 160, ../sass/order/_order.scss */ | |||
.order-order #app-order-order .block-actions { | |||
text-align: right; | |||
margin-top: 20px; | |||
} | |||
/* line 167, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#points-sale td.name .the-name { | |||
text-transform: uppercase; | |||
font-family: "myriadpro-regular"; | |||
color: black; | |||
font-size: 16px; | |||
} | |||
/* line 175, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#points-sale td.actions { | |||
width: 150px; | |||
} | |||
/* line 177, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#points-sale td.actions button { | |||
width: 100%; | |||
} | |||
/* line 183, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#points-sale tr.selected td { | |||
background-color: #F8F1DD; | |||
} | |||
/* line 191, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products td.name .name { | |||
text-transform: uppercase; | |||
font-family: "myriadpro-regular"; | |||
color: black; | |||
font-size: 16px; | |||
} | |||
/* line 197, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products td.name .other { | |||
font-size: 14px; | |||
color: #333; | |||
} | |||
/* line 201, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products td.name .recipe { | |||
color: gray; | |||
} | |||
/* line 205, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products .price-unit, .order-order #app-order-order table#products .price-total { | |||
width: 100px; | |||
text-align: center; | |||
} | |||
/* line 209, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products .td-quantity { | |||
width: 150px; | |||
} | |||
/* line 211, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products .td-quantity input.quantity { | |||
text-align: center; | |||
} | |||
/* line 217, ../sass/order/_order.scss */ | |||
.order-order #app-order-order table#products tr.total .price-total { | |||
font-size: 23px; | |||
} | |||
/* line 224, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #content-step-payment .credit { | |||
margin-top: 20px; | |||
} | |||
/* line 227, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #content-step-payment .credit .info { | |||
margin-left: 20px; | |||
color: gray; | |||
} | |||
/* line 234, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #infos { | |||
margin-top: 30px; | |||
} | |||
/* line 236, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #infos .panel-body { | |||
padding-top: 0px; | |||
white-space: pre-line; | |||
} | |||
/* line 244, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #order-success .alert.alert-success .glyphicon-big { | |||
background-color: #00A65A; | |||
} | |||
/* line 250, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #order-success .alert.alert-info .glyphicon-big { | |||
background-color: #0097BC; | |||
padding: 55px 30px; | |||
} | |||
/* line 256, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #order-success .alert { | |||
padding: 0px; | |||
} | |||
/* line 258, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #order-success .alert .glyphicon-big { | |||
font-size: 90px; | |||
color: white; | |||
padding: 30px; | |||
float: left; | |||
} | |||
/* line 265, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #order-success .alert div.content { | |||
color: #333; | |||
padding: 20px; | |||
margin-left: 151px; | |||
} | |||
/* line 270, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #order-success .alert div.content h3 { | |||
font-family: "myriadpro-light"; | |||
text-transform: uppercase; | |||
font-size: 30px; | |||
color: #333; | |||
margin-bottom: 20px; | |||
margin-top: 0px; | |||
margin-left: 0px; | |||
text-align: left; | |||
padding-left: 0px; | |||
line-height: 35px; | |||
} | |||
/* line 283, ../sass/order/_order.scss */ | |||
.order-order #app-order-order #order-success .alert div.content .locality { | |||
color: gray; | |||
} | |||
/** | |||
Copyright La boîte à pain (2018) | |||
@@ -1305,7 +1573,51 @@ termes. | |||
width: 100%; | |||
} | |||
/* line 145, ../sass/_responsive.scss */ | |||
/* line 148, ../sass/_responsive.scss */ | |||
.order-order #app-order-order #steps ul li { | |||
padding-left: 0px; | |||
padding-right: 0px; | |||
} | |||
/* line 152, ../sass/_responsive.scss */ | |||
.order-order #app-order-order #steps ul li .info-step { | |||
display: none; | |||
} | |||
/* line 156, ../sass/_responsive.scss */ | |||
.order-order #app-order-order #steps ul li .btn::after, | |||
.order-order #app-order-order #steps ul li .btn::before { | |||
display: none; | |||
} | |||
/* line 167, ../sass/_responsive.scss */ | |||
.order-order #app-order-order table#products td.name .recipe { | |||
display: none; | |||
} | |||
/* line 173, ../sass/_responsive.scss */ | |||
.order-order #app-order-order table#products td.td-quantity .input-group-btn { | |||
width: 100%; | |||
display: block; | |||
} | |||
/* line 177, ../sass/_responsive.scss */ | |||
.order-order #app-order-order table#products td.td-quantity .input-group-btn button { | |||
width: 100%; | |||
display: block; | |||
} | |||
/* line 187, ../sass/_responsive.scss */ | |||
.order-order #app-order-order #order-success .alert .glyphicon-big { | |||
font-size: 90px; | |||
color: white; | |||
padding: 30px; | |||
display: block; | |||
width: 100%; | |||
text-align: center; | |||
margin-bottom: 20px; | |||
} | |||
/* line 196, ../sass/_responsive.scss */ | |||
.order-order #app-order-order #order-success .alert div.content { | |||
margin-left: 0px; | |||
text-align: center; | |||
} | |||
/* line 207, ../sass/_responsive.scss */ | |||
#footer .content { | |||
text-align: center; | |||
} |
@@ -0,0 +1,286 @@ | |||
var app = new Vue({ | |||
el: '#app-order-order', | |||
data: { | |||
loading: false, | |||
loadingInit: true, | |||
step: 'date', | |||
producer: null, | |||
date: null, | |||
dateFormat: null, | |||
distribution: null, | |||
pointsSale: [], | |||
pointSaleActive: null, | |||
pointsSaleCodes: [], | |||
products: [], | |||
comment: '', | |||
creditCheckbox: false, | |||
credit: 0, | |||
orderSuccess: false, | |||
calendar: { | |||
mode: 'single', | |||
attrs: [], | |||
availableDates: [], | |||
themeStyles: { | |||
wrapper: { | |||
background: '#BB8757', | |||
color: '#fafafa', | |||
}, | |||
header: { | |||
padding: '10px 10px', | |||
}, | |||
headerHorizontalDivider: { | |||
borderTop: 'solid rgba(255, 255, 255, 0.2) 1px', | |||
width: '80%', | |||
}, | |||
weekdays: { | |||
color: 'white', | |||
fontWeight: '600', | |||
padding: '10px 10px', | |||
fontSize: '2rem' | |||
}, | |||
weeks: { | |||
padding: '0 15px 15px 15px', | |||
}, | |||
dayContent: function(object) { | |||
var style = { | |||
fontSize: '1.5rem', | |||
padding: '20px', | |||
}; | |||
return style ; | |||
}, | |||
}, | |||
formats: { | |||
dayPopover: 'DD/MM/YYYY' | |||
} | |||
}, | |||
}, | |||
mounted: function() { | |||
if($('#distribution-date').size()) { | |||
this.date = new Date($('#distribution-date').html()) ; | |||
this.dateFormat = ('0' + this.date.getDate()).slice(-2)+ '/' | |||
+ ('0' + (this.date.getMonth() +1)).slice(-2) + '/' | |||
+ this.date.getFullYear() ; | |||
} | |||
this.init() ; | |||
this.loadingInit = false ; | |||
}, | |||
methods: { | |||
getDate: function() { | |||
return this.formatDate(this.date) ; | |||
}, | |||
formatDate: function(date) { | |||
if(date) { | |||
return date.getFullYear() + '-' | |||
+ ('0' + (date.getMonth() +1)).slice(-2) + '-' | |||
+ ('0' + date.getDate()).slice(-2) ; | |||
} | |||
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 '--' ; | |||
}, | |||
getPointSale: function(idPointSale) { | |||
for(var key in this.pointsSale) { | |||
if(this.pointsSale[key].id == idPointSale) { | |||
return this.pointsSale[key] ; | |||
} | |||
} | |||
}, | |||
init: function() { | |||
this.loading = true ; | |||
axios.get("ajax-infos",{params: {date : this.getDate()}}) | |||
.then(response => { | |||
this.producer = response.data.producer ; | |||
this.credit = response.data.credit ; | |||
this.calendar.attrs = [] ; | |||
this.calendar.availableDates = [] ; | |||
var distributions = response.data.distributions ; | |||
if(distributions.length) { | |||
var arrayDate ; | |||
for(var i= 0; i < distributions.length; i++) { | |||
this.calendar.attrs.push({ | |||
highlight: { | |||
backgroundColor: '#00A65A' | |||
}, | |||
dates: distributions[i].date, | |||
}) ; | |||
arrayDate = distributions[i].date.split('-') ; | |||
this.calendar.availableDates.push({ | |||
start: new Date(arrayDate[0], arrayDate[1] - 1, arrayDate[2]), | |||
end: new Date(arrayDate[0], arrayDate[1] - 1, arrayDate[2]) | |||
}) ; | |||
} | |||
} | |||
var orders = response.data.orders ; | |||
if(orders.length) { | |||
for(var i= 0; i < orders.length; i++) { | |||
this.calendar.attrs.push({ | |||
highlight: { | |||
backgroundColor: '#018548', | |||
}, | |||
popover: { | |||
label: orders[i].pointSale.name + ' / '+this.formatPrice(orders[i].amount_total), | |||
hideIndicator: true | |||
}, | |||
dates: orders[i].date_distribution, | |||
}) ; | |||
} | |||
} | |||
if(response.data.distribution) { | |||
this.distribution = response.data.distribution ; | |||
} | |||
if(response.data.points_sale) { | |||
this.pointsSale = [] ; | |||
for(var key in response.data.points_sale) { | |||
this.pointsSale[response.data.points_sale[key].id] = response.data.points_sale[key] ; | |||
this.pointsSaleCodes[response.data.points_sale[key].id] = '' ; | |||
Vue.set(this.pointsSaleCodes, response.data.points_sale[key].id, ''); | |||
} | |||
} | |||
if(response.data.products) { | |||
this.products = response.data.products ; | |||
} | |||
this.order = null ; | |||
if(response.data.order) { | |||
this.order = response.data.order ; | |||
this.pointSaleActive = this.getPointSale(response.data.order.id_point_sale) ; | |||
} | |||
else { | |||
this.pointSaleActive = null ; | |||
} | |||
this.loading = false ; | |||
}); | |||
}, | |||
changeStep: function(step) { | |||
var oldStep = this.step ; | |||
this.step = step ; | |||
window.scroll(0, $('#page-title').position().top - 25) ; | |||
if(oldStep == 'date' && step == 'point-sale') { | |||
this.init() ; | |||
} | |||
}, | |||
dayClick: function(day) { | |||
if(this.isAvailableDate(day.date)) { | |||
this.date = day.date ; | |||
this.dateFormat = ('0' + this.date.getDate()).slice(-2)+ '/' | |||
+ ('0' + (this.date.getMonth() +1)).slice(-2) + '/' | |||
+ this.date.getFullYear() ; | |||
this.init() ; | |||
this.changeStep('point-sale') ; | |||
} | |||
}, | |||
isAvailableDate: function(date) { | |||
for(var key in this.calendar.availableDates) { | |||
if(date.getTime() == this.calendar.availableDates[key].start.getTime()) { | |||
return true ; | |||
} | |||
} | |||
return false ; | |||
}, | |||
pointSaleClick: function(event) { | |||
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(response => { | |||
if(response.data) { | |||
this.pointsSale[idPointSale].invalid_code = false ; | |||
this.validatePointSale(idPointSale) ; | |||
} | |||
else { | |||
this.pointsSale[idPointSale].invalid_code = true ; | |||
Vue.set(this.pointsSaleCodes, idPointSale, ''); | |||
} | |||
}) ; | |||
} | |||
else { | |||
this.validatePointSale(idPointSale) ; | |||
} | |||
}, | |||
validatePointSale: function(idPointSale) { | |||
this.pointSaleActive = this.getPointSale(idPointSale) ; | |||
this.changeStep('products') ; | |||
}, | |||
productQuantityClick: function(product, quantity) { | |||
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_max) | |||
) { | |||
this.products[product.index].quantity_form += quantity ; | |||
} | |||
}, | |||
oneProductOrdered: function() { | |||
for(var key in this.products) { | |||
if(this.products[key].quantity_form > 0) { | |||
return true ; | |||
} | |||
} | |||
return false ; | |||
}, | |||
countProductOrdered: function() { | |||
var count = 0 ; | |||
for(var key in this.products) { | |||
if(this.products[key].quantity_form > 0) { | |||
count += this.products[key].quantity_form ; | |||
} | |||
} | |||
return count ; | |||
}, | |||
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].price ; | |||
} | |||
} | |||
if(format) { | |||
return this.formatPrice(price) ; | |||
} | |||
else { | |||
return price ; | |||
} | |||
}, | |||
confirmClick: function() { | |||
var productsArray = {} ; | |||
for(var key in this.products) { | |||
if( this.products[key].quantity_form != null && | |||
this.products[key].quantity_form > 0) { | |||
productsArray[this.products[key].id] = this.products[key].quantity_form ; | |||
} | |||
} | |||
axios.post('ajax-process', { | |||
Order: { | |||
id_distribution : this.distribution.id, | |||
id_point_sale: this.pointSaleActive.id, | |||
comment: this.comment | |||
}, | |||
code_point_sale: this.pointsSaleCodes[this.pointSaleActive.id], | |||
products: productsArray | |||
}).then(response => { | |||
if(response.data.status == 'success') { | |||
this.orderSuccess = true ; | |||
} | |||
}); | |||
} | |||
} | |||
}); |
@@ -141,6 +141,68 @@ termes. | |||
width: 100% ; | |||
} | |||
.order-order { | |||
#app-order-order { | |||
#steps { | |||
ul { | |||
li { | |||
padding-left: 0px ; | |||
padding-right: 0px ; | |||
.info-step { | |||
display: none ; | |||
} | |||
.btn::after, | |||
.btn::before { | |||
display: none ; | |||
} | |||
} | |||
} | |||
} | |||
table#products { | |||
td.name { | |||
.recipe { | |||
display: none ; | |||
} | |||
} | |||
td.td-quantity { | |||
.input-group-btn { | |||
width: 100% ; | |||
display: block ; | |||
button { | |||
width: 100% ; | |||
display: block ; | |||
} | |||
} | |||
} | |||
} | |||
#order-success { | |||
.alert { | |||
.glyphicon-big { | |||
font-size: 90px ; | |||
color: white ; | |||
padding: 30px ; | |||
display: block ; | |||
width: 100% ; | |||
text-align: center ; | |||
margin-bottom: 20px ; | |||
} | |||
div.content { | |||
margin-left: 0px ; | |||
text-align: center ; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
#footer { | |||
.content { | |||
text-align: center ; |
@@ -0,0 +1,292 @@ | |||
.order-order { | |||
#app-order-order { | |||
display: none ; | |||
&.loaded { | |||
display: block ; | |||
} | |||
.slide-enter-active { | |||
transition: all .2s ease; | |||
} | |||
.slide-leave-active { | |||
//transition: all .2s cubic-bezier(1.0, 0.5, 0.8, 1.0); | |||
transition: all 0s ease; | |||
} | |||
.slide-enter, .slide-leave-to { | |||
transform: translateX(10px); | |||
opacity: 0; | |||
} | |||
#steps { | |||
margin-bottom: 20px ; | |||
ul { | |||
margin-top: 30px ; | |||
li { | |||
text-align: center ; | |||
padding-right: 8px ; | |||
padding-left: 8px ; | |||
position: relative ; | |||
.info-step { | |||
position: absolute ; | |||
top: -30px ; | |||
left: 0px ; | |||
width: 100% ; | |||
text-transform: normal ; | |||
} | |||
.glyphicon-chevron-right, | |||
&.active .glyphicon-chevron-right { | |||
float: right ; | |||
color: gray ; | |||
position: relative ; | |||
top: 10px ; | |||
} | |||
&#step-date { | |||
padding-left: 0px ; | |||
} | |||
&#step-payment { | |||
padding-right: 0px ; | |||
} | |||
&#step-payment .btn::after, | |||
&#step-date .btn::before { | |||
display: none ; | |||
} | |||
.btn { | |||
color: #333 ; | |||
text-transform: uppercase ; | |||
display: block ; | |||
width: 100% ; | |||
position: relative ; | |||
background-color: #e0e0e0 ; | |||
@include border-radius(0px) ; | |||
border: 0px none ; | |||
text-transform: uppercase ; | |||
.button-content { | |||
position: relative; | |||
left: 8px ; | |||
} | |||
&.btn-primary { | |||
background-color: $color1 ; | |||
} | |||
&::after, &::before { | |||
content: '' ; | |||
position: absolute ; | |||
top: -1px ; | |||
} | |||
&::after { | |||
right: -34px ; | |||
border:17px solid transparent; | |||
border-left:17px solid #e0e0e0; | |||
background-color: transparent ; | |||
} | |||
&::before { | |||
left: 0px ; | |||
border:17px solid transparent; | |||
border-left:17px solid white; | |||
background-color: transparent ; | |||
} | |||
&.btn-primary::after { | |||
border-left:17px solid $color1; | |||
} | |||
&:hover { | |||
//background-color: lighten($color1, 5) ; | |||
} | |||
&:hover::after { | |||
//border:17px solid transparent; | |||
//border-left:17px solid #fefefe; | |||
} | |||
} | |||
.btn-primary { | |||
color: white ; | |||
} | |||
} | |||
} | |||
} | |||
#legend { | |||
#order-date-color, | |||
#distribution-date-color { | |||
width: 13px ; | |||
height: 13px ; | |||
display: inline-block ; | |||
} | |||
#order-date-color { | |||
background-color: #018548 ; | |||
} | |||
#distribution-date-color { | |||
background-color: #00A65A ; | |||
} | |||
} | |||
#calendar { | |||
margin-bottom: 15px ; | |||
.c-header .c-title-layout .c-title-popover .c-title-anchor .c-title[data-v-2083cb72] { | |||
font-size: 2rem ; | |||
} | |||
.c-day-background { | |||
padding: 20px ; | |||
} | |||
.c-day:hover { | |||
.c-day-background { | |||
background-color: #F39C12 !important ; | |||
} | |||
} | |||
.c-day-popover-content { | |||
font-size: 1.3rem ; | |||
} | |||
} | |||
.block-actions { | |||
text-align: right ; | |||
margin-top: 20px ; | |||
} | |||
table#points-sale { | |||
td.name { | |||
.the-name { | |||
text-transform: uppercase ; | |||
font-family: 'myriadpro-regular' ; | |||
color: black ; | |||
font-size: 16px ; | |||
} | |||
} | |||
td.actions { | |||
width: 150px ; | |||
button { | |||
width: 100% ; | |||
} | |||
} | |||
tr.selected { | |||
td { | |||
background-color: $color2 ; | |||
} | |||
} | |||
} | |||
table#products { | |||
td.name { | |||
.name { | |||
text-transform: uppercase ; | |||
font-family: 'myriadpro-regular' ; | |||
color: black ; | |||
font-size: 16px ; | |||
} | |||
.other { | |||
font-size: 14px ; | |||
color: #333 ; | |||
} | |||
.recipe { | |||
color: gray ; | |||
} | |||
} | |||
.price-unit, .price-total { | |||
width: 100px ; | |||
text-align: center ; | |||
} | |||
.td-quantity { | |||
width: 150px ; | |||
input.quantity { | |||
text-align: center ; | |||
} | |||
} | |||
tr.total { | |||
.price-total { | |||
font-size: 23px ; | |||
} | |||
} | |||
} | |||
#content-step-payment { | |||
.credit { | |||
margin-top: 20px ; | |||
.info { | |||
margin-left: 20px ; | |||
color: gray ; | |||
} | |||
} | |||
} | |||
#infos { | |||
margin-top: 30px ; | |||
.panel-body { | |||
padding-top: 0px ; | |||
white-space: pre-line ; | |||
} | |||
} | |||
#order-success { | |||
.alert.alert-success { | |||
.glyphicon-big { | |||
background-color: #00A65A ; | |||
} | |||
} | |||
.alert.alert-info { | |||
.glyphicon-big { | |||
background-color: #0097BC ; | |||
padding: 55px 30px ; | |||
} | |||
} | |||
.alert { | |||
padding: 0px ; | |||
.glyphicon-big { | |||
font-size: 90px ; | |||
color: white ; | |||
padding: 30px ; | |||
float: left ; | |||
} | |||
div.content { | |||
color: #333 ; | |||
padding: 20px ; | |||
margin-left: 151px ; | |||
h3 { | |||
font-family: 'myriadpro-light' ; | |||
text-transform: uppercase ; | |||
font-size: 30px ; | |||
color: #333 ; | |||
margin-bottom: 20px ; | |||
margin-top: 0px ; | |||
margin-left: 0px ; | |||
text-align: left ; | |||
padding-left: 0px ; | |||
line-height: 35px ; | |||
} | |||
.locality { | |||
color: gray ; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -41,4 +41,5 @@ termes. | |||
@import "site/_credit_history.scss"; | |||
@import "order/_form.scss"; | |||
@import "order/_history.scss"; | |||
@import "order/_order.scss"; | |||
@import "_responsive.scss"; |