浏览代码

Ajout / modification d'un abonnement

dev
父节点
当前提交
272f9456e7
共有 23 个文件被更改,包括 840 次插入222 次删除
  1. +1
    -6
      common/components/ActiveRecordCommon.php
  2. +1
    -1
      common/models/Order.php
  3. +9
    -5
      common/models/Producer.php
  4. +57
    -46
      common/models/Subscription.php
  5. +1
    -0
      common/models/SubscriptionForm.php
  6. +1
    -1
      common/models/SubscriptionSearch.php
  7. +25
    -14
      producer/assets/VuejsSubscriptionFormAsset.php
  8. +1
    -1
      producer/controllers/OrderController.php
  9. +96
    -43
      producer/controllers/SubscriptionController.php
  10. +4
    -4
      producer/views/credit/history.php
  11. +14
    -3
      producer/views/layouts/main.php
  12. +1
    -1
      producer/views/order/history.php
  13. +158
    -52
      producer/views/subscription/_form.php
  14. +7
    -6
      producer/views/subscription/form.php
  15. +14
    -12
      producer/views/subscription/index.php
  16. +123
    -21
      producer/web/css/screen.css
  17. +5
    -0
      producer/web/js/lechatdesnoisettes.js
  18. +0
    -1
      producer/web/js/vuejs/order-order.js
  19. +225
    -0
      producer/web/js/vuejs/subscription-form.js
  20. +19
    -4
      producer/web/sass/_layout.scss
  21. +1
    -1
      producer/web/sass/order/_form.scss
  22. +1
    -0
      producer/web/sass/screen.scss
  23. +76
    -0
      producer/web/sass/subscription/_form.scss

+ 1
- 6
common/components/ActiveRecordCommon.php 查看文件

@@ -73,12 +73,7 @@ class ActiveRecordCommon extends \yii\db\ActiveRecord
if (isset($options['attribute_id_producer']) && strlen($options['attribute_id_producer'])
&& !isset($params[$options['attribute_id_producer']]) && !Yii::$app->user->isGuest)
{
if(Yii::$app->controller->module->id == 'app-producer') {
$params[$options['attribute_id_producer']] = Yii::$app->controller->getProducer()->id ;
}
else {
$params[$options['attribute_id_producer']] = Producer::getId() ;
}
$params[$options['attribute_id_producer']] = Producer::getId() ;
}
if(!isset($options['type_search'])) {

+ 1
- 1
common/models/Order.php 查看文件

@@ -408,7 +408,7 @@ class Order extends ActiveRecordCommon
}
}
else {
$html .= '<span class="label label-default">À régler sur place</span>';
$html .= '<span class="label label-default">Non réglé</span>';
}

return $html;

+ 9
- 5
common/models/Producer.php 查看文件

@@ -355,15 +355,19 @@ class Producer extends ActiveRecordCommon
}
/**
* Retourne le producteur courant (le producteur auquel l'utilisateur
* connecté est rattaché).
* Retourne l'ID du producteur courant.
*
* @return integer|boolean
*/
public static function getId()
{
if(!Yii::$app->user->isGuest) {
return Yii::$app->user->identity->id_producer ;
{
if(Yii::$app->controller->module->id == 'app-backend') {
if(!Yii::$app->user->isGuest) {
return Yii::$app->user->identity->id_producer ;
}
}
else {
return Yii::$app->controller->getProducer()->id ; ;
}
return false ;

+ 57
- 46
common/models/Subscription.php 查看文件

@@ -262,51 +262,57 @@ class Subscription extends ActiveRecordCommon
$arrSubscriptions = [];

foreach ($subscriptions as $s) {
// vérif dates
if ($date >= $s->date_begin &&
(!$s->date_end || $date <= $s->date_end))
{
// périodicite
$nbDays = (strtotime($date) - strtotime($s->date_begin)) / (24 * 60 * 60);
if ($nbDays % ($s->week_frequency * 7) < 7) {
// jour de la semaine
$day = date('N', strtotime($date));
switch ($day) {
case 1 : $day = 'monday';
break;
case 2 : $day = 'tuesday';
break;
case 3 : $day = 'wednesday';
break;
case 4 : $day = 'thursday';
break;
case 5 : $day = 'friday';
break;
case 6 : $day = 'saturday';
break;
case 7 : $day = 'sunday';
break;
}

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

return $arrSubscriptions;
}
/**
* Valide le fait qu'un abonnement est bien compatible avec une date donnée.
*
* @param string $date
* @return boolean
*/
public function matchWith($date)
{
$arrayDays = [
1 => 'monday',
2 => 'tuesday',
3 => 'wednesday',
4 => 'thursday',
5 => 'friday',
6 => 'saturday',
7 => 'sunday'
] ;
$nbDays = (strtotime($date) - strtotime($this->date_begin)) / (24 * 60 * 60);
if ($nbDays % ($this->week_frequency * 7) < 7) {
$numDay = date('N', strtotime($date));
$day = $arrayDays[$numDay] ;
if ($this->$day) {
return true ;
}
}
return false ;
}
/**
* Recherche les distributions futures où l'abonnement peut s'appliquer.
*
* @return array
*/
public function searchMatchedIncomingDistributions()
{
{
$producer = Producer::getCurrent() ;
$params = [
':date_today' => date('Y-m-d'),
':date_earliest_order' => $producer->getEarliestDateOrder(),
':date_begin' => date('Y-m-d', strtotime($this->date_begin)),
':id_producer' => Producer::getId()
] ;
@@ -314,7 +320,7 @@ class Subscription extends ActiveRecordCommon
$incomingDistributions = Distribution::find()
->where('id_producer = :id_producer')
->andWhere('date >= :date_begin')
->andWhere('date >= :date_today') ;
->andWhere('date >= :date_earliest_order') ;
if($this->date_end) {
$incomingDistributions->andWhere('date < :date_end') ;
@@ -327,25 +333,14 @@ class Subscription extends ActiveRecordCommon
$incomingDistributionsArray = $incomingDistributions->all() ;
$matchedIncomingDistributionsArray = [] ;
$arrayDays = [
1 => 'monday',
2 => 'tuesday',
3 => 'wednesday',
4 => 'thursday',
5 => 'friday',
6 => 'saturday',
7 => 'sunday'
] ;
foreach($incomingDistributionsArray as $incomingDistribution) {
$numDay = date('N', strtotime($incomingDistribution->date)) ;
$day = $arrayDays[$numDay] ;
if($this->$day) {
if($this->matchWith($incomingDistribution->date)) {
$matchedIncomingDistributionsArray[] = $incomingDistribution ;
}
}
return $matchedIncomingDistributionsArray ;
}
}
public function deleteOrdersIncomingDistributions()
{
@@ -364,7 +359,7 @@ class Subscription extends ActiveRecordCommon
->andWhere('order.id_subscription = :id_subscription') ;
if($this->date_end) {
$orders->andWhere('distribution.date =< :date_end') ;
$orders->andWhere('distribution.date <= :date_end') ;
$params[':date_end'] = $this->date_end ;
}

@@ -374,8 +369,24 @@ class Subscription extends ActiveRecordCommon
if($ordersArray && count($ordersArray)) {
foreach($ordersArray as $order) {
ProductOrder::deleteAll(['id_order' => $order->id]) ;
$order->delete() ;
}
}
}
public function updateIncomingDistributions($update = false)
{
$matchedDistributionsArray = $this->searchMatchedIncomingDistributions() ;
if($update) {
$this->deleteOrdersIncomingDistributions() ;
}
if(count($matchedDistributionsArray)) {
foreach($matchedDistributionsArray as $distribution) {
$this->add($distribution->date) ;
}
}
}
}

+ 1
- 0
common/models/SubscriptionForm.php 查看文件

@@ -168,6 +168,7 @@ class SubscriptionForm extends Model
if(!$this->id) {
$this->id = $subscription->id ;
}
}
return true;
}

+ 1
- 1
common/models/SubscriptionSearch.php 查看文件

@@ -65,7 +65,7 @@ class SubscriptionSearch extends Subscription
->where(['subscription.id_producer' => Producer::getId()])
;
$dataProvider = new ActiveDataProvider([
$dataProvider = new \yii\data\ActiveDataProvider([
'query' => $query,
'sort' => ['attributes' => ['username']],
'pagination' => [

producer/views/subscription/update.php → producer/assets/VuejsSubscriptionFormAsset.php 查看文件

@@ -1,5 +1,4 @@
<?php

/**
Copyright La boîte à pain (2018)

@@ -36,16 +35,28 @@ pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/

use yii\helpers\Html;

$this->setTitle('Modifier un abonnement') ;
$this->addBreadcrumb(['label' => 'Abonnements', 'url' => ['index']]) ;
$this->addBreadcrumb('Modifier') ;
?>

<div class="subscription-update">
<?= $this->render('_form', [
'model' => $model,
'productsArray' => $productsArray
]) ?>
</div>
namespace producer\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') ;
}
}

+ 1
- 1
producer/controllers/OrderController.php 查看文件

@@ -93,7 +93,7 @@ class OrderController extends ProducerBaseController
->joinWith('distribution', 'distribution.producer')
->where([
'id_user' => Yii::$app->user->id,
'distribution.id_producer' => $this->getProducer()->id
'distribution.id_producer' => Producer::getId()
])
->orderBy('distribution.date DESC'),
'pagination' => [

+ 96
- 43
producer/controllers/SubscriptionController.php 查看文件

@@ -73,6 +73,9 @@ termes.

namespace producer\controllers;

use common\models\SubscriptionForm ;
use common\models\SubscriptionSearch ;

class SubscriptionController extends ProducerBaseController
{
var $enableCsrfValidation = false;
@@ -109,38 +112,51 @@ class SubscriptionController extends ProducerBaseController
]);
}

/**
* Crée une commande récurrente.
*
* @return string
*/
public function actionCreate()
public function actionAjaxProcess()
{
// form
$model = new SubscriptionForm;
$model->id_producer = Producer::getId();
// produits
$productsArray = Product::searchAll() ;
$model->id_user = User::getCurrentId() ;
$posts = Yii::$app->request->post() ;
if ($model->load(Yii::$app->request->post()) && $model->validate()
$idSubscription = (int) $posts['idSubscription'] ;
$isUpdate = false ;
if($idSubscription) {
$subscription = Subscription::findOne($idSubscription);
if ($subscription) {
$model->id = $idSubscription;
$isUpdate = true ;
}
}
if ($model->load($posts) && $model->validate()
&& $model->save())
{
Yii::$app->getSession()->setFlash('success', 'Abonnement ajouté');
{
$subscription = Subscription::searchOne([
'id' => $model->id
]) ;
$subscription->updateIncomingDistributions($isUpdate) ;
$subscription = Subscription::findOne($model->id) ;
$matchedDistributionsArray = $subscription->searchMatchedIncomingDistributions() ;
if(count($matchedDistributionsArray)) {
return $this->redirect(['subscription/update-distributions', 'idSubscription' => $subscription->id]);
if($isUpdate) {
Yii::$app->getSession()->setFlash('success', 'Abonnement modifié');
}
else {
return $this->redirect(['subscription/index']);
Yii::$app->getSession()->setFlash('success', 'Abonnement ajouté');
}
}

return $this->render('create', [
'model' => $model,
'productsArray' => $productsArray
}
/**
* Crée une commande récurrente.
*
* @return string
*/
public function actionForm($id = 0)
{
return $this->render('form', [
'idSubscription' => (int) $id
]);
}

@@ -177,7 +193,6 @@ class SubscriptionController extends ProducerBaseController
$model->auto_payment = $subscription->auto_payment;
$model->week_frequency = $subscription->week_frequency;


// produits
$arrayProductsSubscription = ProductSubscription::searchAll([
'id_subscription' => $model->id
@@ -218,40 +233,78 @@ class SubscriptionController extends ProducerBaseController
}

/**
* Supprime une commande récurrente.
* Supprime un abonnement
*
* @param integer $id
*/
public function actionDelete($id)
{
$subscription = Subscription::searchOne([
'id' => $id
]) ;
ProductSubscription::deleteAll(['id_subscription' => $id]);
Subscription::findOne($id)->delete();
$subscription->deleteOrdersIncomingDistributions() ;
$subscription->delete();
Yii::$app->getSession()->setFlash('success', 'Abonnement supprimé');
return $this->redirect(['subscription/index']);
}
public function actionUpdateDistributions($idSubscription, $generate = false, $update = false)
{
$subscription = Subscription::findOne($idSubscription) ;
$matchedDistributionsArray = $subscription->searchMatchedIncomingDistributions() ;
public function actionAjaxInfos($idSubscription = 0)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$params = [] ;
if($generate) {
if($update) {
$subscription->deleteOrdersIncomingDistributions() ;
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;
}
}
foreach($matchedDistributionsArray as $distribution) {
$subscription->add($distribution->date) ;
}
// 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] ;
}
Yii::$app->getSession()->setFlash('success', 'Commandes '.($update ? 're-' : '').'générées dans les distributions futures.');
return $this->redirect(['subscription/index']) ;
$product = array_merge(
$product->getAttributes(),
[
'index' => $indexProduct ++,
'quantity_form' => $quantity
]
) ;
}
return $this->render('update_distributions',[
'matchedDistributionsArray' => $matchedDistributionsArray,
'idSubscription' => $idSubscription,
'update' => $update
]) ;
}
$params['products'] = $productsArray ;
$pointsSaleArray = PointSale::searchAll() ;
$params['points_sale'] = $pointsSaleArray ;
if($idSubscription > 0) {
$subscription = Subscription::searchOne([
'id' => $idSubscription
]) ;
if(!$subscription || $subscription->id_user != User::getCurrentId()) {
throw new UserException('Abonnement introuvable') ;
}
else {
$params = array_merge($params, $subscription->getAttributes()) ;
}
}
return $params ;
}
}

+ 4
- 4
producer/views/credit/history.php 查看文件

@@ -41,11 +41,11 @@ use yii\helpers\Html;
$this->setTitle('Crédit : <span id="credit-user">'.number_format($creditUser, 2).' €</span>');
$this->setPageTitle('Crédit');

?>
if($this->context->getProducer()->online_payment) {
$this->addButton(['label' => '<span class="glyphicon glyphicon-credit-card"></span> Créditer mon compte', 'url' => 'credit/add', 'class' => 'btn btn-primary']) ;
}

<?php if($this->context->getProducer()->online_payment): ?>
<?= Html::a('<span class="glyphicon glyphicon-credit-card"></span> Créditer mon compte', ['credit/add'], ['class' => 'btn btn-primary']); ?><br /><br />
<?php endif; ?>
?>

<?= GridView::widget([
// 'filterModel' => $searchModel,

+ 14
- 3
producer/views/layouts/main.php 查看文件

@@ -167,7 +167,7 @@ $producer = $this->context->getProducer() ;
'active' => $this->getControllerAction() == 'order/order',
],
[
'label' => '<span class="glyphicon glyphicon-folder-open"></span> Historique',
'label' => '<span class="glyphicon glyphicon-folder-open"></span> Mes commandes',
'url' => Yii::$app->urlManager->createUrl(['order/history']),
'visible' => !Yii::$app->user->isGuest,
'active' => $this->getControllerAction() == 'order/history',
@@ -201,7 +201,18 @@ $producer = $this->context->getProducer() ;
</nav>
<?php if(strlen($this->getTitle())): ?>
<h2 id="page-title"><?= $this->getTitle(); ?></h2>
<h2 id="page-title">
<?= $this->getTitle(); ?>
<?php
if(count($this->buttons)): ?>
<span id="buttons">
<?php foreach($this->buttons as $button) {
echo '<a href="'.Yii::$app->urlManagerProducer->createUrl($button['url']).'" class="'.$button['class'].'">'.$button['label'].'</a>' ;
}
?>
</span>
<?php endif; ?>
</h2>
<?php endif; ?>
<section id="content">
@@ -215,7 +226,7 @@ $producer = $this->context->getProducer() ;
<?= Yii::$app->session->getFlash('success') ?>
</div>
<?php endif; ?>
<?= $content ?>
</section>
</div>

+ 1
- 1
producer/views/order/history.php 查看文件

@@ -39,7 +39,7 @@ termes.
use yii\bootstrap\ActiveForm;
use common\models\Order ;

$this->setTitle('Historique de mes commandes') ;
$this->setTitle('Mes commandes') ;

?>


+ 158
- 52
producer/views/subscription/_form.php 查看文件

@@ -42,74 +42,180 @@ use yii\helpers\ArrayHelper ;
use common\models\User ;
use common\models\PointSale ;

\producer\assets\VuejsSubscriptionFormAsset::register($this) ;

?>

<div class="subscription-form">
<?php $form = ActiveForm::begin(['enableClientValidation' => false]); ?>
<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'];
}), ['prompt' => '--','class' => 'form-control user-id', ]) ?>
<div class="subscription-form" id="app-subscription-form">
<form @submit.prevent="formSubmit()" v-show="loading == false">
<input type="hidden" id="subscription-id" value="<?= $idSubscription; ?>" />
<div class="alert alert-danger" v-if="errors.length">
<ul>
<li v-for="error in errors">
{{ error }}
</li>
</ul>
</div>
<div class="col-md-1" id="or-user">
<span>OU</span>
<div class="form-group field-subscriptionform-id_point_sale required">
<h3><span>Point de vente</span></h3>
<div class="points-sale" v-for="pointSale in pointsSale" v-if="pointSale.delivery_monday || pointSale.delivery_tuesday || pointSale.delivery_wednesday || pointSale.delivery_thursday || pointSale.delivery_friday || pointSale.delivery_saturday || pointSale.delivery_sunday">
<input type="radio" :id="'point-sale-'+pointSale.id" name="SubscriptionForm[id_point_sale]" :value="pointSale.id" v-model="idPointSaleActive" @change="pointSaleChange()" />
<label :for="'point-sale-'+pointSale.id">{{ pointSale.name }} <span v-if="pointSale.locality.length > 0" class="locality">/ {{ pointSale.locality }}</span></label>
</div>
<div class="help-block"></div>
</div>
<h3><span>Dates</span></h3>
<div class="col-md-4">
<div class="form-group">
<label>Date de début</label>
<v-date-picker
mode="single"
v-model="dateBegin"
:input-props='{class: "form-control", placeholder: "" }'>
</v-date-picker>
</div>
</div>
<div class="col-md-6">
<?= $form->field($model, 'username')->textInput() ?>
<div class="clr"></div>
<div class="col-md-4">
<div class="form-group">
<label>Date de fin</label>
<v-date-picker
mode="single"
v-model="dateEnd"
:min-date="dateBegin"
:input-props='{class: "form-control", placeholder: ""}'>
</v-date-picker>
<div class="hint-block">Laisser vide pour une durée indéterminée</div>
</div>
</div>
<div class="clr"></div>
<?= $form->field($model, 'id_producer')->hiddenInput() ?>
<?= $form->field($model, 'id_point_sale')->dropDownList(ArrayHelper::map(PointSale::find()->where('id_producer = '.Producer::getId())->all(), 'id', function($model, $defaultValue) {
return $model['name'];
}), ['prompt' => '--','class' => 'form-control user-id']) ?>
<?= $form->field($model, 'date_begin') ?>
<?= $form->field($model, 'date_end')->hint('Laisser vide pour une durée indéterminée') ?>
<div class="days">
<h2>Jours</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 class="col-md-4">
<label for="subscriptionform-week_frequency">Périodicité</label>
<select id="subscriptionform-week_frequency" class="form-control" v-model="weekFrequency">
<option value="1">Toutes les semaines</option>
<option value="2">Toutes les 2 semaines</option>
<option value="3">Toutes les 3 semaines</option>
<option value="4">Tous les mois</option>
</select>
</div>
<div class="clr"></div>
<?= $form->field($model, 'week_frequency')->dropDownList([1=>1, 2=>2, 3=>3, 4=>4]) ?>
<h3><span>Paiement</span></h3>

<?php if(Producer::getConfig('credit')): ?>
<div class="form-group field-subscriptionform-auto_payment">
<label><input type="checkbox" id="subscriptionform-auto_payment" name="SubscriptionForm[auto_payment]" v-model="autoPayment"> Paiement automatique</label>
<div class="hint-block">Cochez cette case si vous souhaitez que votre Crédit soit automatiquement débité.</div>
<div class="help-block"></div>
</div>
<?php endif; ?>
<div class="days" v-if="pointSaleActive">
<h3><span>Jours</span></h3>
<div v-if="pointSaleActive.delivery_monday == true">
<div class="form-group field-subscriptionform-monday">
<label><input type="checkbox" id="subscriptionform-monday" v-model="monday"> Lundi</label>
</div>
</div>
<div v-if="pointSaleActive.delivery_tuesday == true">
<div class="form-group field-subscriptionform-monday">
<label><input type="checkbox" id="subscriptionform-tuesday" v-model="tuesday"> Mardi</label>
</div>
</div>
<div v-if="pointSaleActive.delivery_wednesday == true">
<div class="form-group field-subscriptionform-wednesday">
<label><input type="checkbox" id="subscriptionform-wednesday" v-model="wednesday"> Mercredi</label>
</div>
</div>
<div v-if="pointSaleActive.delivery_thursday == true">
<div class="form-group field-subscriptionform-thursday">
<label><input type="checkbox" id="subscriptionform-thursday" v-model="thursday"> Jeudi</label>
</div>
</div>
<div v-if="pointSaleActive.delivery_friday == true">
<div class="form-group field-subscriptionform-friday">
<label><input type="checkbox" id="subscriptionform-friday" v-model="friday"> Vendredi</label>
</div>
</div>
<div v-if="pointSaleActive.delivery_saturday == true">
<div class="form-group field-subscriptionform-saturday">
<label><input type="checkbox" id="subscriptionform-saturday" v-model="saturday"> Samedi</label>
</div>
</div>
<div v-if="pointSaleActive.delivery_sunday == true">
<div class="form-group field-subscriptionform-sunday">
<label><input type="checkbox" id="subscriptionform-sunday" v-model="sunday"> Dimanche</label>
</div>
</div>

<?= $form->field($model, 'auto_payment')
->checkbox()
->hint('Cochez cette case si vous souhaitez que le crédit pain du client soit automatiquement débité lors de la création de la commande.<br />'
. 'Attention, un compte client existant doit être spécifié en haut de ce formulaire.') ?>
<div class="alert alert-warning" v-if="!pointSaleActive.delivery_monday && !pointSaleActive.delivery_tuesday && !pointSaleActive.delivery_wednesday && !pointSaleActive.delivery_thursday && !pointSaleActive.delivery_friday && !pointSaleActive.delivery_saturday && !pointSaleActive.delivery_sunday">
Aucun jour de distribution disponible pour ce point de vente.
</div>
</div>
<div class="products">
<h2>Produits</h2>
<div class="clr"></div>
<div class="products" v-if="(monday || tuesday || wednesday || thursday || friday || saturday || sunday) && checkOneProductAvailable()">
<h3><span>Produits</span></h3>
<?php if(isset($model->errors['products']) && count($model->errors['products']))
{
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>
<td>
<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>
</span>
<?= Html::input('text', 'SubscriptionForm[products][product_'.$p->id.']', (isset($model->products['product_'.$p->id])) ? $model->products['product_'.$p->id] : '', ['class' => 'form-control quantity']) ?>
<span class="input-group-btn">
<button class="btn btn-default btn-plus" type="button"><span class="glyphicon glyphicon-plus"></span></button>
<table :class="'table table-bordered table-condensed table-hover' + (monday ? ' monday-active' : '') + (tuesday ? ' tuesday-active' : '') + (wednesday ? ' wednesday-active' : '') + (thursday ? ' thursday-active' : '') + (friday ? ' friday-active' : '') + (saturday ? ' saturday-active' : '') + (sunday ? ' sunday-active' : '')">
<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="checkProductAvailable(product)">
<td>
<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>
</div>
</td>
</tr>
<?php endforeach; ?>
<div class="recipe" v-if="product.recipe.length">{{ product.recipe }}</div>
</td>
<td class="price-unit">
{{ formatPrice(product.price) }}
</td>
<td class="quantity">
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button" @click="productQuantityClick(product, -1)"><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-btn">
<button class="btn btn-default" type="button" @click="productQuantityClick(product, 1)"><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>
<div v-if="!checkOneProductAvailable()" class="alert alert-warning">
Aucun produit n'est disponible pour les jours de distribution sélectionnés.
</div>
</div>
<?= Html::submitButton('Enregistrer' , ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end(); ?>
<button class="btn btn-primary" disabled="disabled" v-if="disableSubmitButton">Enregistrer</button>
<button class="btn btn-primary" v-else>Enregistrer</button>
</form>
</div>

producer/views/subscription/create.php → producer/views/subscription/form.php 查看文件

@@ -38,15 +38,16 @@ termes.

use yii\helpers\Html;

$this->setTitle('Ajouter un abonnement') ;
$this->addBreadcrumb(['label' => 'Abonnements', 'url' => ['index']]) ;
$this->addBreadcrumb('Ajouter') ;

if($idSubscription > 0) {
$this->setTitle('Modifier un abonnement') ;
}
else {
$this->setTitle('Ajouter un abonnement') ;
}
?>

<div class="subscription-create">
<?= $this->render('_form', [
'model' => $model,
'productsArray' => $productsArray
'idSubscription' => $idSubscription
]) ?>
</div>

+ 14
- 12
producer/views/subscription/index.php 查看文件

@@ -40,7 +40,7 @@ use yii\helpers\Html;
use yii\grid\GridView;

$this->setTitle('Abonnements') ;
$this->addButton(['label' => '+ Ajouter', 'url' => 'subscription/form', 'class' => 'btn btn-primary']) ;

$columns = [
[
@@ -69,7 +69,6 @@ $columns = [
}
],
[
'attribute' => 'id_point_sale',
'label' => 'Point de vente',
'format' => 'raw',
'filter' => ArrayHelper::map(PointSale::find()->where(['id_producer' => Producer::getId()])->asArray()->all(), 'id', 'name'),
@@ -153,7 +152,6 @@ $columns = [
if(Producer::getConfig('credit')) {
$columns[] = [
'attribute' => 'auto_payment',
'format' => 'raw',
'label' => 'Paiement automatique',
'headerOptions' => ['class' => 'column-auto-payment'],
@@ -172,13 +170,13 @@ if(Producer::getConfig('credit')) {
$columns[] = [
'class' => 'yii\grid\ActionColumn',
'template' => '{update} {delete}',
'template' => '{form} {delete}',
'headerOptions' => ['class' => 'column-actions'],
'contentOptions' => ['class' => 'column-actions'],
'buttons' => [
'update' => function ($url, $model) {
'form' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, [
'title' => Yii::t('app', 'Modifier'), 'class' => 'btn btn-default'
'title' => Yii::t('app', 'Modifier'), 'class' => 'btn btn-default'
]);
},
'delete' => function ($url, $model) {
@@ -191,10 +189,14 @@ $columns[] = [

?>
<div class="subscription-index">
<?= GridView::widget([
'filterModel' => $searchModel,
'dataProvider' => $dataProvider,
'columns' => $columns,
]); ?>
<?php if($dataProvider->getCount()): ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => $columns,
]); ?>
<?php else: ?>
<div class="alert alert-info">
Vous n'avez encore aucun abonnement chez ce producteur.
</div>
<?php endif; ?>
</div>

+ 123
- 21
producer/web/css/screen.css 查看文件

@@ -400,7 +400,7 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
padding: 10px;
}
/* line 307, ../sass/_layout.scss */
#main #page-title {
#main h2#page-title {
padding-left: 15px;
padding-right: 15px;
padding-bottom: 15px;
@@ -412,7 +412,12 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
top: -10px;
text-align: center;
}
/* line 320, ../sass/_layout.scss */
/* line 319, ../sass/_layout.scss */
#main h2#page-title #buttons {
margin-bottom: 15px;
font-family: "Arial";
}
/* line 326, ../sass/_layout.scss */
#main .container {
padding: 0px;
background-color: white;
@@ -420,39 +425,39 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
border-left: solid 1px #e0e0e0;
border-right: solid 1px #e0e0e0;
}
/* line 328, ../sass/_layout.scss */
/* line 334, ../sass/_layout.scss */
#main #content {
padding-bottom: 20px;
padding: 0px 20px 20px 20px;
}
/* line 332, ../sass/_layout.scss */
/* line 338, ../sass/_layout.scss */
#main #content h1, #main #content h2, #main #content h3, #main #content h4, #main #content h5, #main #content h6 {
font-family: "myriadpro-regular";
margin-top: 30px;
margin-bottom: 20px;
}
/* line 337, ../sass/_layout.scss */
/* line 343, ../sass/_layout.scss */
#main #content h1.first, #main #content h2.first, #main #content h3.first, #main #content h4.first, #main #content h5.first, #main #content h6.first {
margin-top: 0px;
}
/* line 342, ../sass/_layout.scss */
/* line 348, ../sass/_layout.scss */
#main #content h1 {
font-size: 30px;
}
/* line 346, ../sass/_layout.scss */
/* line 352, ../sass/_layout.scss */
#main #content h2 {
font-size: 25px;
}
/* line 351, ../sass/_layout.scss */
/* line 357, ../sass/_layout.scss */
#main #content h3 {
font-family: "myriadpro-light";
text-transform: uppercase;
font-size: 23px;
padding: 10px 0px 10px 10px;
color: white;
text-align: center;
text-align: left;
margin-bottom: 30px;
margin-top: 45px;
}
/* line 358, ../sass/_layout.scss */
/* line 365, ../sass/_layout.scss */
#main #content h3 span {
background-color: #BB8757;
padding: 10px 20px;
@@ -461,29 +466,33 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
color: #BB8757;
border: dotted 1px #BB8757;
}
/* line 369, ../sass/_layout.scss */
/* line 376, ../sass/_layout.scss */
#main #content h4 {
font-size: 20px;
}
/* line 373, ../sass/_layout.scss */
/* line 380, ../sass/_layout.scss */
#main #content h5 {
font-size: 18px;
}
/* line 377, ../sass/_layout.scss */
/* line 384, ../sass/_layout.scss */
#main #content h6 {
font-size: 16px;
}
/* line 390, ../sass/_layout.scss */
#main #content form .form-group .hint-block {
color: gray;
}

/* line 383, ../sass/_layout.scss */
/* line 398, ../sass/_layout.scss */
#footer {
background-color: #BB8757;
height: 100px;
}
/* line 387, ../sass/_layout.scss */
/* line 402, ../sass/_layout.scss */
#footer .container {
padding: 0px;
}
/* line 389, ../sass/_layout.scss */
/* line 404, ../sass/_layout.scss */
#footer .container .overflow {
height: 30px;
background-color: white;
@@ -491,18 +500,18 @@ ul.pagination li a:hover, ul.pagination li a:focus, ul.pagination li a:active {
border-right: solid 1px #e0e0e0;
border-bottom: solid 1px #e0e0e0;
}
/* line 397, ../sass/_layout.scss */
/* line 412, ../sass/_layout.scss */
#footer .container .content {
padding-top: 20px;
color: white;
}
/* line 401, ../sass/_layout.scss */
/* line 416, ../sass/_layout.scss */
#footer .container .content a {
color: white;
text-decoration: underline;
margin-right: 10px;
}
/* line 409, ../sass/_layout.scss */
/* line 424, ../sass/_layout.scss */
#footer .container #code-source img {
height: 20px;
}
@@ -1454,6 +1463,99 @@ termes.
color: gray;
}

/* line 7, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .points-sale .locality,
.subscription-update .subscription-form .points-sale .locality {
color: gray;
}
/* line 10, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .points-sale label,
.subscription-update .subscription-form .points-sale label {
cursor: pointer;
}
/* line 16, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .days .form-group,
.subscription-update .subscription-form .days .form-group {
float: left;
margin-right: 15px;
}
/* line 23, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .products .monday, .subscription-create .subscription-form .products .tuesday, .subscription-create .subscription-form .products .wednesday, .subscription-create .subscription-form .products .thursday,
.subscription-create .subscription-form .products .friday, .subscription-create .subscription-form .products .saturday, .subscription-create .subscription-form .products .sunday, .subscription-create .subscription-form .products .no-day,
.subscription-update .subscription-form .products .monday,
.subscription-update .subscription-form .products .tuesday,
.subscription-update .subscription-form .products .wednesday,
.subscription-update .subscription-form .products .thursday,
.subscription-update .subscription-form .products .friday,
.subscription-update .subscription-form .products .saturday,
.subscription-update .subscription-form .products .sunday,
.subscription-update .subscription-form .products .no-day {
display: none;
}
/* line 28, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .products .monday-active .monday,
.subscription-create .subscription-form .products .tuesday-active .tuesday,
.subscription-create .subscription-form .products .wednesday-active .wednesday,
.subscription-create .subscription-form .products .thursday-active .thursday,
.subscription-create .subscription-form .products .friday-active .friday,
.subscription-create .subscription-form .products .saturday-active .saturday,
.subscription-create .subscription-form .products .sunday-active .sunday,
.subscription-update .subscription-form .products .monday-active .monday,
.subscription-update .subscription-form .products .tuesday-active .tuesday,
.subscription-update .subscription-form .products .wednesday-active .wednesday,
.subscription-update .subscription-form .products .thursday-active .thursday,
.subscription-update .subscription-form .products .friday-active .friday,
.subscription-update .subscription-form .products .saturday-active .saturday,
.subscription-update .subscription-form .products .sunday-active .sunday {
display: block;
}
/* line 38, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .products td.quantity,
.subscription-update .subscription-form .products td.quantity {
width: 150px;
}
/* line 41, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .products td.quantity input,
.subscription-update .subscription-form .products td.quantity input {
text-align: center;
}
/* line 44, ../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 50, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .products .name,
.subscription-update .subscription-form .products .name {
font-family: "comfortaalight";
font-weight: bold;
text-transform: uppercase;
font-size: 18px;
}
/* line 57, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .products .description,
.subscription-update .subscription-form .products .description {
font-style: italic;
}
/* line 61, ../sass/subscription/_form.scss */
.subscription-create .subscription-form .products .recipe,
.subscription-update .subscription-form .products .recipe {
font-size: 12px;
}
/* line 65, ../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 70, ../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;
font-size: 20px;
}

/**
Copyright La boîte à pain (2018)


+ 5
- 0
producer/web/js/lechatdesnoisettes.js 查看文件

@@ -80,8 +80,13 @@ $(document).ready(function() {
chat_systeme_commande() ;
chat_profil_user() ;
$('.dropdown-toggle').dropdown() ;
chat_datepicker() ;
}) ;

function chat_datepicker() {
$('input.datepicker').datepicker({dateFormat:'dd/mm/yy'}) ;
}

function chat_profil_user() {
if($('#profil-user').size()) {
if($('#user-no_mail').is(':checked')) {

+ 0
- 1
producer/web/js/vuejs/order-order.js 查看文件

@@ -226,7 +226,6 @@ var app = new Vue({
(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 ;
}
},

+ 225
- 0
producer/web/js/vuejs/subscription-form.js 查看文件

@@ -0,0 +1,225 @@

var app = new Vue({
el: '#app-subscription-form',
data: {
loading: true,
idSubscription: 0,
pointsSale: [],
idPointSaleActive: 0,
pointSaleActive: null,
dateBegin: null,
dateEnd: null,
weekFrequency: 1,
autoPayment: true,
monday: false,
tuesday: false,
wednesday: false,
thursday: false,
friday: false,
saturday: false,
sunday: false,
products: [],
errors: [],
disableSubmitButton: false,
},
mounted: function() {
this.init();
},
methods: {
init: function() {
if($('#subscription-id').val() != 0) {
this.idSubscription = $('#subscription-id').val() ;
}
this.dateBegin = new Date() ;

axios.get("ajax-infos",{params: {idSubscription : this.idSubscription}})
.then(response => {
this.products = response.data.products ;
this.pointsSale = response.data.points_sale ;
if(this.idSubscription > 0) {
this.idPointSaleActive = response.data.id_point_sale ;
this.pointSaleChange() ;
this.weekFrequency = response.data.week_frequency ;
this.autoPayment = response.data.auto_payment ;
var arrayDateBegin = response.data.date_begin.split('-') ;
this.dateBegin = new Date(arrayDateBegin[0], arrayDateBegin[1] - 1, arrayDateBegin[2]) ;
if(response.data.date_end && response.data.date_end.length > 0) {
var arrayDateEnd = response.data.date_begin.split('-') ;
this.dateEnd = new Date(arrayDateEnd[0], arrayDateEnd[1] - 1, arrayDateEnd[2]) ;
}
this.monday = response.data.monday ;
this.tuesday = response.data.tuesday ;
this.wednesday = response.data.wednesday ;
this.thursday = response.data.thursday ;
this.friday = response.data.friday ;
this.saturday = response.data.saturday ;
this.sunday = response.data.sunday ;
}
this.loading = false ;
});
},
formatDate: function(date) {
if(date) {
return ('0' + date.getDate()).slice(-2) + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + '/' + date.getFullYear() ;
}
return false ;
},
pointSaleChange: function() {
for(key in this.pointsSale) {
if(this.pointsSale[key].id == this.idPointSaleActive) {
this.pointSaleActive = this.pointsSale[key] ;
this.monday = false ;
this.tuesday = false ;
this.wednesday = false ;
this.thursday = false ;
this.friday = false ;
this.saturday = false ;
this.sunday = false ;
}
}
},
checkProductAvailable: function(product) {
var available = product.active &&
(!this.monday || (this.monday && product.monday)) &&
(!this.tuesday || (this.tuesday && product.tuesday)) &&
(!this.wednesday || (this.wednesday && product.wednesday)) &&
(!this.thursday || (this.thursday && product.thursday)) &&
(!this.friday || (this.friday && product.friday)) &&
(!this.saturday || (this.saturday && product.saturday)) &&
(!this.sunday || (this.sunday && product.sunday)) ;
if(!available) {
product.quantity_form = 0 ;
}
return available ;
},
checkOneProductAvailable: function() {
var count = 0 ;
for(key in this.products) {
if(this.checkProductAvailable(this.products[key])) {
count ++ ;
}
}
return count ;
},
productQuantityClick: function(product, quantity) {
if( this.products[product.index].quantity_form + quantity >= 0) {
this.products[product.index].quantity_form += quantity ;
}
},
oneProductOrdered: function() {
for(var key in this.products) {
if(this.products[key].quantity_form > 0) {
return true ;
}
}
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 '--' ;
},
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 ;
}
},
formSubmit: function() {
this.checkForm() ;
if(!this.errors.length && !this.disableSubmitButton) {

this.disableSubmitButton = true ;

var productsArray = {} ;
for(var key in this.products) {
if( this.products[key].quantity_form != null &&
this.products[key].quantity_form > 0) {
productsArray['product_'+this.products[key].id] = this.products[key].quantity_form ;
}
}
axios.post('ajax-process', {
idSubscription: this.idSubscription,
SubscriptionForm: {
id_point_sale: this.idPointSaleActive,
date_begin: this.dateBegin ? this.formatDate(this.dateBegin) : '',
date_end: this.dateEnd ? this.formatDate(this.dateEnd) : '',
week_frequency: this.weekFrequency,
auto_payment: this.autoPayment,
monday: this.monday == true ? 1 : 0,
tuesday: this.tuesday == true ? 1 : 0,
wednesday: this.wednesday == true ? 1 : 0,
thursday: this.thursday == true ? 1 : 0,
friday: this.friday == true ? 1 : 0,
saturday: this.saturday == true ? 1 : 0,
sunday: this.sunday == true ? 1 : 0,
products: productsArray
}
}).then(response => {
window.location.href = chat_base_url(true)+'subscription/index' ;
});
}
},
checkForm: function() {
this.errors = [] ;
if(!this.idPointSaleActive) {
this.errors.push('Veuillez sélectionner un point de vente') ;
}
var regexDate = /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/;
if(!this.dateBegin) {
this.errors.push('Veuillez sélectionner une date de début') ;
}
else {
if(!regexDate.test(this.formatDate(this.dateBegin))) {
this.errors.push('Mauvais format de date de début') ;
}
}
if(this.dateEnd && this.dateEnd.length > 0 && !regexDate.test(this.formatDate(this.dateEnd))) {
this.errors.push('Mauvais format de date de fin') ;
}
if(this.weekFrequency != 1 && this.weekFrequency != 2 &&
this.weekFrequency != 3 && this.weekFrequency != 4) {
this.errors.push('Veuillez sélectionner une périodicité') ;
}
if(!this.monday && !this.tuesday && !this.wednesday && !this.thursday &&
!this.friday && !this.saturday) {
this.errors.push('Veuillez sélectionner un jour de distribution') ;
}
if(!this.oneProductOrdered()) {
this.errors.push('Veuillez choisir au moins un produit') ;
}
if(this.errors.length) {
window.scroll(0, $('#page-title').position().top - 25) ;
}
}
}
});


+ 19
- 4
producer/web/sass/_layout.scss 查看文件

@@ -304,7 +304,7 @@ ul.pagination {
}
}
#page-title {
h2#page-title {
padding-left: 15px ;
padding-right: 15px ;
padding-bottom: 15px ;
@@ -315,6 +315,12 @@ ul.pagination {
position: relative ;
top: -10px ;
text-align: center ;
#buttons {
//float: right ;
margin-bottom: 15px ;
font-family: 'Arial' ;
}
}
.container {
@@ -352,9 +358,10 @@ ul.pagination {
font-family: 'myriadpro-light' ;
text-transform: uppercase ;
font-size: 23px ;
padding: 10px 0px 10px 10px ;
color: white ;
text-align: center ;
text-align: left ;
margin-bottom: 30px ;
margin-top: 45px ;
span {
background-color: $color1 ;
padding: 10px 20px ;
@@ -377,6 +384,14 @@ ul.pagination {
h6 {
font-size: 16px ;
}
form {
.form-group {
.hint-block {
color: gray ;
}
}
}
}
}


+ 1
- 1
producer/web/sass/order/_form.scss 查看文件

@@ -63,7 +63,7 @@ termes.
}

.ui-datepicker-title {
color: white
color: white ;
}

.ui-datepicker-prev,

+ 1
- 0
producer/web/sass/screen.scss 查看文件

@@ -43,4 +43,5 @@ termes.
@import "order/_history.scss";
@import "order/_order.scss";
@import "credit/_add.scss";
@import "subscription/_form.scss";
@import "_responsive.scss";

+ 76
- 0
producer/web/sass/subscription/_form.scss 查看文件

@@ -0,0 +1,76 @@

.subscription-create,
.subscription-update {
.subscription-form {
.points-sale {
.locality {
color: gray ;
}
label {
cursor: pointer ;
}
}
.days {
.form-group {
float: left ;
margin-right: 15px ;
}
}
.products {
.monday, .tuesday, .wednesday, .thursday,
.friday, .saturday, .sunday, .no-day {
display: none ;
}
.monday-active .monday,
.tuesday-active .tuesday,
.wednesday-active .wednesday,
.thursday-active .thursday,
.friday-active .friday,
.saturday-active .saturday,
.sunday-active .sunday {
display: block ;
}
td.quantity {
width: 150px ;
input {
text-align: center ;
&.has-quantity {
font-weight: bold ;
}
}
}
.name {
font-family: "comfortaalight" ;
font-weight: bold ;
text-transform: uppercase ;
font-size: 18px ;
}

.description {
font-style: italic;
}

.recipe {
font-size: 12px ;
}
.price-unit, .price-total {
text-align: center ;
width: 150px ;
}
tr.total .price-total {
text-align: center ;
font-size: 20px ;
}
}
}
}

正在加载...
取消
保存