Переглянути джерело

Merge branch 'dev'

prodstable
Guillaume Bourgeois 2 роки тому
джерело
коміт
e9cb2cb4aa
18 змінених файлів з 830 додано та 475 видалено
  1. +11
    -11
      backend/controllers/DistributionController.php
  2. +3
    -16
      backend/controllers/DocumentController.php
  3. +1
    -0
      backend/controllers/ProductController.php
  4. +3
    -3
      backend/views/document/_form.php
  5. +4
    -2
      backend/views/product/update/prices/_form.php
  6. +10
    -0
      backend/views/product/update/prices/list.php
  7. +55
    -18
      backend/web/js/vuejs/distribution-index.js
  8. +199
    -148
      backend/web/js/vuejs/document-form.js
  9. +73
    -64
      common/helpers/Tiller.php
  10. +101
    -52
      common/models/Product.php
  11. +190
    -93
      common/models/ProductPrice.php
  12. +2
    -7
      common/models/Subscription.php
  13. +26
    -0
      console/migrations/m220804_095203_prix_degressifs_champs_from_quantity.php
  14. +29
    -30
      producer/controllers/OrderController.php
  15. +17
    -5
      producer/views/order/order.php
  16. +36
    -20
      producer/web/css/screen.css
  17. +49
    -5
      producer/web/js/vuejs/order-order.js
  18. +21
    -1
      producer/web/sass/order/_order.scss

+ 11
- 11
backend/controllers/DistributionController.php Переглянути файл

@@ -431,15 +431,16 @@ class DistributionController extends BackendController
];
}

public function actionAjaxUpdateProductOrder($idDistribution, $idUser = false, $idPointSale = false)
{
public function actionAjaxUpdateProductOrder(
$idDistribution,
$idUser = false,
$idPointSale = false,
$idOrder = false
) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

$distribution = Distribution::findOne($idDistribution);
$user = User::findOne($idUser);
$userProducer = UserProducer::searchOne([
'id_user' => $idUser,
]);
$pointSale = PointSale::findOne($idPointSale);

$productsArray = Product::find()
@@ -455,14 +456,13 @@ class DistributionController extends BackendController

$productOrderArray = [];
foreach ($productsArray as $product) {
$priceArray = $product->getPriceArray($user, $pointSale);

$productOrderArray[$product['id']] = [
'quantity' => 0,
'unit' => $product->unit,
'price' => $product->getPriceWithTax([
'user' => $user,
'user_producer' => $userProducer,
'point_sale' => $pointSale
]),
'unit_coefficient' => Product::$unitsArray[$product->unit]['coefficient'],
'prices' => $priceArray,
'active' => $product->productDistribution[0]->active
&& (!$pointSale || $product->isAvailableOnPointSale($pointSale))
];
@@ -1388,7 +1388,7 @@ class DistributionController extends BackendController
]);

$returnTillerObject = json_decode($returnTiller);
$order->tiller_external_id = ''.$returnTillerObject->id;
$order->tiller_external_id = '' . $returnTillerObject->id;
$order->save();

$return[] = $returnTiller;

+ 3
- 16
backend/controllers/DocumentController.php Переглянути файл

@@ -360,30 +360,17 @@ class DocumentController extends BackendController

$productsArray = yii\helpers\ArrayHelper::map(
$productsArray,
'id',
'order',
function ($product) use ($document, $userProducer, $pointSale) {
return array_merge($product->getAttributes(), [
'price_with_tax' => $product->getPriceWithTax([
'user' => $document->user,
'user_producer' => $userProducer,
'point_sale' => $pointSale,
]),
'price' => $product->getPrice([
'user' => $document->user,
'user_producer' => $userProducer,
'point_sale' => $pointSale,
]),
'unit_coefficient' => Product::$unitsArray[$product->unit]['coefficient'],
'prices' => $product->getPriceArray($userProducer->user, $pointSale),
'wording_unit' => $product->wording_unit,
'tax_rate' => $product->taxRate->value
]);
}
);

// ne fonctionne pas, à creuser
/*uasort($productsArray, function($a, $b) {
return $a['order'] < $b['order'] ? 1 : -1;
});*/

return [
'return' => 'success',
'tax_rate_producer' => GlobalParam::getCurrentProducer()->taxRate->value,

+ 1
- 0
backend/controllers/ProductController.php Переглянути файл

@@ -263,6 +263,7 @@ class ProductController extends BackendController
'id_user' => $model->id_user ? $model->id_user : null,
'id_user_group' => $model->id_user_group ? $model->id_user_group : null,
'id_point_sale' => $model->id_point_sale ? $model->id_point_sale : null,
'from_quantity' => $model->from_quantity ? $model->from_quantity : null,
] ;

$productPriceExist = ProductPrice::findOne($conditionsProductPriceExist) ;

+ 3
- 3
backend/views/document/_form.php Переглянути файл

@@ -207,7 +207,7 @@ use common\models\Producer;
</span>
<input type="text" class="form-control input-quantity"
v-model="productAddQuantity" @change="formatProductAddQuantity"/>
<span class="input-group-addon">{{ productsArray[productAddId].wording_unit }}</span>
<span class="input-group-addon">{{ getProductById(productAddId).wording_unit }}</span>
<span class="input-group-btn">
<button class="btn btn-default"
type="button"
@@ -254,7 +254,7 @@ use common\models\Producer;
<template v-for="order in ordersArray">
<tr v-for="productOrder in order.productOrder">
<td class="col-md-4">
<div class="product-name">{{ productsArray[productOrder.id_product].name }}</div>
<div class="product-name">{{ getProductById(productOrder.id_product).name }}</div>
<ul class="product-order-meta">
<li>{{ order.username }}</li>
<li v-if="order.distribution_date">{{ order.distribution_date }}</li>
@@ -266,7 +266,7 @@ use common\models\Producer;
</td>
<td class="col-md-2">{{ productOrder.quantity }}</td>
<td class="col-md-1" v-if="taxRateProducer != 0">
{{ productsArray[productOrder.id_product].tax_rate * 100 }} %
{{ getProductById(productOrder.id_product).tax_rate * 100 }} %
</td>
<td class="col-md-2">
{{ formatPrice(productOrder.quantity * getProductOrderPrice(productOrder)) }}

+ 4
- 2
backend/views/product/update/prices/_form.php Переглянути файл

@@ -30,6 +30,7 @@ use common\models\User ;
<?= $form->field($model, 'id_user')->dropDownList(User::populateDropdownList()); ?>
<?= $form->field($model, 'id_user_group')->dropDownList(UserGroup::populateDropdownList()); ?>
<?= $form->field($model, 'id_point_sale')->dropDownList(PointSale::populateDropdownList()); ?>
<?= $form->field($model, 'from_quantity')->label('À partir de la quantité ('.Product::strUnit(Product::getRefUnit($modelProduct->unit), 'wording').')'); ?>

<?php
$producer = GlobalParam::getCurrentProducer();
@@ -38,17 +39,18 @@ use common\models\User ;
$taxRateValue = $modelProduct->taxRate->value ;
}
?>

<?= $form->field($model, 'price', [
'template' => '
<div class="row">
<div class="col-xs-6">
<label for="product-price" class="control-label without-tax">Prix ('.Product::strUnit($modelProduct->unit, 'wording_unit').') HT</label>
<label for="product-price" class="control-label without-tax">Prix ('.Product::strUnit(Product::getRefUnit($modelProduct->unit), 'wording_unit').') HT</label>
<div class="input-group">
{input} <span class="input-group-addon"><span class="glyphicon glyphicon-euro"></span></span>
</div>
</div>
<div class="col-xs-6">
<label for="productprice-price-with-tax" class="control-label with-tax">Prix ('.Product::strUnit($modelProduct->unit, 'wording_unit').') TTC</label>
<label for="productprice-price-with-tax" class="control-label with-tax">Prix ('.Product::strUnit(Product::getRefUnit($modelProduct->unit), 'wording_unit').') TTC</label>
<div class="input-group">
<input type="text" id="productprice-price-with-tax" class="form-control" name="" value="" data-tax-rate-value="'.$taxRateValue.'">
<span class="input-group-addon"><span class="glyphicon glyphicon-euro"></span></span>

+ 10
- 0
backend/views/product/update/prices/list.php Переглянути файл

@@ -102,6 +102,16 @@ $this->addBreadcrumb('Modifier');
return '<span class="label label-success">Tous</span>' ;
}
],
[
'attribute' => 'from_quantity',
'value' => function ($productPrice) {
if($productPrice->from_quantity) {
return $productPrice->from_quantity.' '.Product::strUnit(Product::getRefUnit($productPrice->product->unit), 'wording');
}

return '' ;
}
],
[
'attribute' => 'price',
'value' => function ($productPrice) {

+ 55
- 18
backend/web/js/vuejs/distribution-index.js Переглянути файл

@@ -365,12 +365,12 @@ var app = new Vue({
this.idOrderUpdate = idOrder ;
this.showModalFormOrderUpdate = true ;
this.initModalFormOrder() ;
this.updateProductOrderPrices();
this.updateProductOrderPrices(false);
},
openModalFormOrderCreate: function() {
this.showModalFormOrderCreate = true ;
this.initModalFormOrder() ;
this.updateProductOrderPrices() ;
this.updateProductOrderPrices(false) ;
},
initModalFormOrder: function() {
setTimeout(function() {
@@ -569,7 +569,7 @@ var app = new Vue({
}) ;
},

updateProductOrderPrices: function() {
updateProductOrderPrices: function(updatePricesOnUpdateOrder) {
var app = this ;
app.loadingUpdateProductOrder = true;
var order = null ;
@@ -591,22 +591,34 @@ var app = new Vue({
params: {
idDistribution: app.distribution.id,
idUser: order.id_user,
idPointSale: order.id_point_sale
idPointSale: order.id_point_sale,
idOrder: order.id
}
})
.then(function (response) {
if (response.data) {
for (idProduct in response.data) {
if (app.showModalFormOrderCreate) {
Vue.set(app.orderCreate.productOrder[idProduct], 'price', response.data[idProduct].price);
Vue.set(app.orderCreate.productOrder[idProduct], 'prices', response.data[idProduct].prices);
Vue.set(app.orderCreate.productOrder[idProduct], 'active', response.data[idProduct].active);
Vue.set(app.orderCreate.productOrder[idProduct], 'unit_coefficient', response.data[idProduct].unit_coefficient);
Vue.set(app.orderCreate.productOrder[idProduct], 'price', app.getBestProductPrice(app.orderCreate, idProduct, app.orderCreate.productOrder[idProduct].quantity));
}

if (app.showModalFormOrderUpdate && app.idOrderUpdate) {
for (keyOrderUpdate in app.ordersUpdate) {
if (order.id == app.idOrderUpdate) {
Vue.set(app.ordersUpdate[keyOrderUpdate].productOrder[idProduct], 'price', response.data[idProduct].price);
Vue.set(app.ordersUpdate[keyOrderUpdate].productOrder[idProduct], 'prices', response.data[idProduct].prices);
Vue.set(app.ordersUpdate[keyOrderUpdate].productOrder[idProduct], 'active', response.data[idProduct].active);
Vue.set(app.ordersUpdate[keyOrderUpdate].productOrder[idProduct], 'unit_coefficient', response.data[idProduct].unit_coefficient);

if(updatePricesOnUpdateOrder) {
console.log('new price : ');
Vue.set(
app.ordersUpdate[keyOrderUpdate].productOrder[idProduct],
'price',
app.getBestProductPrice(app.ordersUpdate[keyOrderUpdate], idProduct, app.ordersUpdate[keyOrderUpdate].productOrder[idProduct].quantity));
}
}
}
}
@@ -616,7 +628,31 @@ var app = new Vue({
app.loadingUpdateProductOrder = false;
});
}
}
},
getBestProductPrice: function(order, idProduct, theQuantity) {
var thePriceWithTax = 9999;
var pricesArray = order.productOrder[idProduct].prices;
var unitCoefficient = order.productOrder[idProduct].unit_coefficient;
if(theQuantity) {
theQuantity = theQuantity / unitCoefficient;
}

for(var i = 0; i < pricesArray.length ; i++) {
var priceWithTax = pricesArray[i].price_with_tax;
var fromQuantity = pricesArray[i].from_quantity;

if(priceWithTax < thePriceWithTax && fromQuantity <= theQuantity) {
thePriceWithTax = priceWithTax;
}
}

if(thePriceWithTax == 9999) {
return 0;
}
else {
return thePriceWithTax;
}
},
},
});

@@ -626,6 +662,7 @@ Vue.component('modal', {

Vue.component('order-form',{
props: ['date', 'pointsSale','meansPayment', 'users', 'products', 'order', 'producer', 'loadingUpdateProductOrder'],
emits: ['updateProductPrice'],
data: function() {
return {
errors: [],
@@ -727,14 +764,14 @@ Vue.component('order-form',{
this.order.productOrder[id_product].quantity = 0 ;
}
if(parseFloat(this.order.productOrder[id_product].quantity) + quantity >= 0) {
var theQuantity = parseFloat(this.order.productOrder[id_product].quantity) + parseFloat(quantity) ;
var theQuantity = (parseFloat(this.order.productOrder[id_product].quantity) + parseFloat(quantity)).toFixed(2);
var theQuantityDecimal = theQuantity % 1;
if(theQuantityDecimal == 0) {
theQuantity = parseInt(theQuantity);
}

Vue.set(this.order.productOrder, id_product, {
quantity: theQuantity.toFixed(2),
unit: this.order.productOrder[id_product].unit,
price: this.order.productOrder[id_product].price,
active: this.order.productOrder[id_product].active
});
Vue.set(this.order.productOrder[id_product], 'quantity', theQuantity);
Vue.set(this.order.productOrder[id_product], 'price', app.getBestProductPrice(this.order, id_product, theQuantity));
}
},
productPriceChange: function(event) {
@@ -757,14 +794,14 @@ Vue.component('order-form',{
}})
.then(function(response) {
app.order.id_point_sale = response.data.id_favorite_point_sale ;
app.updateProductOrderPrices() ;
app.updateProductOrderPrices(true) ;
}) ;
},
pointSaleChange: function(event) {
this.updateProductOrderPrices() ;
this.updateProductOrderPrices(true) ;
},
updateProductOrderPrices: function() {
this.$emit('updateproductorderprices') ;
updateProductOrderPrices: function(updateProductOrderPrices) {
this.$emit('updateproductorderprices', updateProductOrderPrices) ;
}
}
}) ;

+ 199
- 148
backend/web/js/vuejs/document-form.js Переглянути файл

@@ -1,39 +1,38 @@
/**
Copyright distrib (2018)

/**
Copyright distrib (2018)

contact@opendistrib.net

Ce logiciel est un programme informatique servant à aider les producteurs
à distribuer leur production en circuits courts.

Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".

En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.

A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.

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

Ce logiciel est un programme informatique servant à aider les producteurs
à distribuer leur production en circuits courts.

Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".

En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.

A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.

Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/

var app = new Vue({
el: '#app-document-form',
@@ -52,142 +51,194 @@ var app = new Vue({
total: 0,
total_with_tax: 0
},
mounted: function() {
this.init() ;
mounted: function () {
this.init();
},
methods: {
formatPrice: formatPrice,
init: function() {
if(this.getDocumentId()) {
var app = this ;
axios.get(UrlManager.getBaseUrlAbsolute()+"document/ajax-init",{params: {
idDocument: this.getDocumentId(),
classDocument: this.getDocumentClass()
}})
.then(function(response) {
if(response.data.return == 'success') {
app.document = response.data.document ;
app.taxRateProducer = response.data.tax_rate_producer ;
app.idUser = response.data.id_user ;
app.productsArray = response.data.products ;
app.ordersArray = response.data.orders ;
app.total = response.data.total ;
app.total_with_tax = response.data.total_with_tax ;

if(app.idUser > 0) {
app.changeUser() ;
}
}
}) ;
init: function () {

if (this.getDocumentId()) {
var app = this;
axios.get(UrlManager.getBaseUrlAbsolute() + "document/ajax-init", {
params: {
idDocument: this.getDocumentId(),
classDocument: this.getDocumentClass()
}
})
.then(function (response) {
if (response.data.return == 'success') {
app.document = response.data.document;
app.taxRateProducer = response.data.tax_rate_producer;
app.idUser = response.data.id_user;
app.productsArray = response.data.products;
app.ordersArray = response.data.orders;
app.total = response.data.total;
app.total_with_tax = response.data.total_with_tax;

if (app.idUser > 0) {
app.changeUser();
}
}
});
}
},
getProductById: function(idProduct) {
var app = this;

for(var i = 0; i <= Object.keys(this.productsArray).length ; i++) {
if(app.productsArray[i] && app.productsArray[i].id == idProduct) {
return app.productsArray[i];
}
}

return false;
},
getDocumentId: function() {
var documentId = $('#app-document-form').attr('data-id-document') ;
return documentId ;
getDocumentId: function () {
var documentId = $('#app-document-form').attr('data-id-document');
return documentId;
},
getDocumentClass: function() {
var documentClass = $('#app-document-form').attr('data-class-document') ;
return documentClass ;
getDocumentClass: function () {
var documentClass = $('#app-document-form').attr('data-class-document');
return documentClass;
},
getProductOrderPrice: function(productOrder) {
var documentClass = this.getDocumentClass() ;
var price = 0 ;
if(documentClass == 'DeliveryNote' || documentClass == 'Invoice') {
price = productOrder.invoice_price ;
if(!price) {
price = productOrder.price ;
getProductOrderPrice: function (productOrder) {
var documentClass = this.getDocumentClass();
var price = 0;
if (documentClass == 'DeliveryNote' || documentClass == 'Invoice') {
price = productOrder.invoice_price;
if (!price) {
price = productOrder.price;
}
}
else {
price = productOrder.price ;
} else {
price = productOrder.price;
}

return price ;
return price;
},
changeUser: function() {
var app = this ;
axios.get(UrlManager.getBaseUrlAbsolute()+"document/ajax-user-infos",{params: {
idUser: app.idUser,
classDocument: app.getDocumentClass(),
idDocument: app.getDocumentId(),
typeAction: $('#type-action').val(),
}})
.then(function(response) {
if(response.data.return == 'success') {
Vue.set(app.document, 'address', response.data.address);
app.deliveryNotes = response.data.delivery_notes ;
}
else {
app.document.address = '' ;
}
}) ;
},
formatPrice: formatPrice,
validateDocument: function() {
var app = this ;
axios.get(UrlManager.getBaseUrlAbsolute()+"document/ajax-validate-document",{params: {
changeUser: function () {
var app = this;
axios.get(UrlManager.getBaseUrlAbsolute() + "document/ajax-user-infos", {
params: {
idUser: app.idUser,
classDocument: app.getDocumentClass(),
idDocument: app.getDocumentId(),
typeAction: $('#type-action').val(),
}
})
.then(function (response) {
if (response.data.return == 'success') {
Vue.set(app.document, 'address', response.data.address);
app.deliveryNotes = response.data.delivery_notes;
} else {
app.document.address = '';
}
});
},
validateDocument: function () {
var app = this;
axios.get(UrlManager.getBaseUrlAbsolute() + "document/ajax-validate-document", {
params: {
idDocument: app.getDocumentId(),
classDocument: app.getDocumentClass(),
}})
.then(function(response) {
appAlerts.alertResponse(response) ;
app.init() ;
}) ;
}
})
.then(function (response) {
appAlerts.alertResponse(response);
app.init();
});
},
getStepProductAdd: function () {
var step = parseInt(this.getProductById(this.productAddId).step);
if(!step) {
step = 1;
}

return step;
},
getStepProductAdd: function() {
return parseInt(this.productsArray[this.productAddId].step) ;
changeProductAdd: function (event) {
var idProduct = event.currentTarget.value;
this.productAddId = idProduct;
this.productAddPrice = this.getBestProductPrice(idProduct, this.getStepProductAdd());
this.productAddQuantity = this.getStepProductAdd();
},
changeProductAdd: function(event) {
var idProduct = event.currentTarget.value ;
this.productAddId = idProduct ;
//this.productAddPrice = parseFloat(this.productsArray[idProduct].price).toFixed(2) ;
this.productAddPrice = parseFloat(this.productsArray[idProduct].price);
this.productAddQuantity = this.getStepProductAdd() ;
},
changeQuantityProductAdd: function(quantity) {
var step = this.getStepProductAdd() ;
quantity = quantity * step ;
this.productAddQuantity += quantity ;
if(this.productAddQuantity < 1) {
this.productAddQuantity = step ;
getBestProductPrice: function (idProduct, theQuantity) {
var product = this.getProductById(idProduct);

var thePriceWithTax = 9999;
var pricesArray = product.prices;
var unitCoefficient = product.unit_coefficient;

if (theQuantity) {
theQuantity = theQuantity / unitCoefficient;
}

for (var i = 0; i < pricesArray.length; i++) {
if(pricesArray[i]) {
var priceWithTax = pricesArray[i].price_with_tax;
var fromQuantity = pricesArray[i].from_quantity;

if (priceWithTax < thePriceWithTax && fromQuantity <= theQuantity) {
thePriceWithTax = priceWithTax;
}
}
}

if (thePriceWithTax == 9999) {
return 0;
}
else {
return thePriceWithTax;
}
},
submitProductAdd: function() {
var app = this ;
axios.get(UrlManager.getBaseUrlAbsolute()+"document/ajax-add-product",{params: {
idDocument: this.getDocumentId(),
classDocument: this.getDocumentClass(),
idProduct: app.productAddId,
quantity: app.productAddQuantity,
price: app.productAddPrice,
}})
.then(function(response) {
appAlerts.alertResponse(response) ;
app.productAddId = 0 ;
app.init() ;
}) ;
changeQuantityProductAdd: function (quantity) {
var step = this.getStepProductAdd();
quantity = quantity * step;
this.productAddQuantity += quantity;
if (this.productAddQuantity < 1) {
this.productAddQuantity = step;
}
this.productAddPrice = this.getBestProductPrice(app.productAddId, this.productAddQuantity);
},
deleteProductOrder: function(idProductOrder) {
var app = this ;
axios.get(UrlManager.getBaseUrlAbsolute()+"document/ajax-delete-product-order",{params: {
submitProductAdd: function () {
var app = this;
axios.get(UrlManager.getBaseUrlAbsolute() + "document/ajax-add-product", {
params: {
idDocument: this.getDocumentId(),
classDocument: this.getDocumentClass(),
idProduct: app.productAddId,
quantity: app.productAddQuantity,
price: app.productAddPrice,
}
})
.then(function (response) {
appAlerts.alertResponse(response);
app.productAddId = 0;
app.init();
});
},
deleteProductOrder: function (idProductOrder) {
var app = this;
axios.get(UrlManager.getBaseUrlAbsolute() + "document/ajax-delete-product-order", {
params: {
idProductOrder: idProductOrder
}})
.then(function(response) {
appAlerts.alertResponse(response) ;
app.init() ;
}) ;
}
})
.then(function (response) {
appAlerts.alertResponse(response);
app.init();
});
},
formatProductAddPrice: function() {
formatProductAddPrice: function () {
this.productAddPrice = Number(this.productAddPrice).toFixed(2).replace(',', '.');
if(isNaN(this.productAddPrice)) {
this.productAddPrice = 0 ;
if (isNaN(this.productAddPrice)) {
this.productAddPrice = 0;
}
},
formatProductAddQuantity: function() {
this.productAddQuantity = parseInt(this.productAddQuantity) ;
if(isNaN(this.productAddQuantity)) {
this.productAddQuantity = 1 ;
formatProductAddQuantity: function () {
this.productAddQuantity = parseInt(this.productAddQuantity);
if (isNaN(this.productAddQuantity)) {
this.productAddQuantity = 1;
}
}
}

+ 73
- 64
common/helpers/Tiller.php Переглянути файл

@@ -42,82 +42,91 @@ use linslin\yii2\curl;

class Tiller
{
var $curl;
var $producer_tiller;
var $provider_token;
var $restaurant_token;
//var $url_api = 'https://developers.tillersystems.com/api/';
var $url_api = 'https://app.tillersystems.com/api/';
var $curl;
var $producer_tiller;
var $provider_token;
var $restaurant_token;
//var $url_api = 'https://developers.tillersystems.com/api/';
var $url_api = 'https://app.tillersystems.com/api/';

public function __construct()
{
$this->curl = new curl\Curl();
$this->producer_tiller = Producer::getConfig('tiller');
$this->provider_token = Producer::getConfig('tiller_provider_token');
$this->restaurant_token = Producer::getConfig('tiller_restaurant_token');
}
public function __construct()
{
$this->curl = new curl\Curl();
$this->producer_tiller = Producer::getConfig('tiller');
$this->provider_token = Producer::getConfig('tiller_provider_token');
$this->restaurant_token = Producer::getConfig('tiller_restaurant_token');
}

public function getOrders($date)
{
if ($this->producer_tiller) {
$orders = $this->curl->setGetParams([
'provider_token' => $this->provider_token,
'restaurant_token' => $this->restaurant_token,
'dateFrom' => date('Y-m-d H-i-s', strtotime($date)),
'dateTo' => date('Y-m-d H-i-s', strtotime($date) + 24 * 60 * 60 - 1),
'status' => 'IN_PROGRESS',
])->get($this->url_api . 'orders');
public function getOrders($date)
{
if ($this->producer_tiller) {
$orders = $this->curl->setGetParams([
'provider_token' => $this->provider_token,
'restaurant_token' => $this->restaurant_token,
'dateFrom' => date('Y-m-d H-i-s', strtotime($date)),
'dateTo' => date(
'Y-m-d H-i-s',
strtotime($date) + 24 * 60 * 60 - 1
),
'status' => 'IN_PROGRESS',
])->get($this->url_api . 'orders');

return json_decode($orders);
}
return json_decode($orders);
}
}

public function isSynchro($date)
{
if ($this->producer_tiller) {
$ordersTiller = $this->getOrders($date);
$ordersOpendistrib = Order::searchAll([
'distribution.date' => $date,
'order.tiller_synchronization' => 1
], [
'conditions' => 'date_delete IS NULL'
]);

$ordersOpendistribSynchro = [];
public function isSynchro($date)
{
if ($this->producer_tiller) {
$ordersTiller = $this->getOrders($date);
$ordersOpendistrib = Order::searchAll([
'distribution.date' => $date,
'order.tiller_synchronization' => 1
], [
'conditions' => 'date_delete IS NULL'
]);

if ($ordersOpendistrib) {
foreach ($ordersOpendistrib as $orderOpendistrib) {
$ordersOpendistribSynchro[$orderOpendistrib->id] = false;
if(isset($ordersTiller->orders)) {
foreach ($ordersTiller->orders as $orderTiller) {
if ($orderOpendistrib->tiller_external_id == $orderTiller->id
&& (int) round($orderOpendistrib->getAmountWithTax(Order::AMOUNT_TOTAL) * 100) == (int) $orderTiller->currentBill) {
$ordersOpendistribSynchro = [];

$ordersOpendistribSynchro[$orderOpendistrib->id] = true;
}
}
}
}
}

foreach ($ordersOpendistribSynchro as $idOrder => $isSynchro) {
if (!$isSynchro) {
return false;
if ($ordersOpendistrib) {
foreach ($ordersOpendistrib as $orderOpendistrib) {
$ordersOpendistribSynchro[$orderOpendistrib->id] = false;
if (isset($ordersTiller->orders)) {
foreach ($ordersTiller->orders as $orderTiller) {
if ($orderOpendistrib->tiller_external_id == $orderTiller->id) {
$amountTotalOrderOpendistrib = (int)round(
$orderOpendistrib->getAmountWithTax(Order::AMOUNT_TOTAL) * 100
);
if ($amountTotalOrderOpendistrib == (int)$orderTiller->currentPayedAmount
|| $amountTotalOrderOpendistrib == (int)$orderTiller->currentBill) {
$ordersOpendistribSynchro[$orderOpendistrib->id] = true;
}
}
}
}
}
}

return true;
foreach ($ordersOpendistribSynchro as $idOrder => $isSynchro) {
if (!$isSynchro) {
return false;
}
}

return true;
}
}

public function postOrder($params)
{
if ($this->producer_tiller) {
return $this->curl->setPostParams(array_merge([
'provider_token' => $this->provider_token,
'restaurant_token' => $this->restaurant_token,
], $params))
->post($this->url_api . 'orders');
}
public function postOrder($params)
{
if ($this->producer_tiller) {
return $this->curl->setPostParams(
array_merge([
'provider_token' => $this->provider_token,
'restaurant_token' => $this->restaurant_token,
], $params)
)
->post($this->url_api . 'orders');
}
}
}

+ 101
- 52
common/models/Product.php Переглянути файл

@@ -77,6 +77,7 @@ class Product extends ActiveRecordCommon
'coefficient' => 1
],
'g' => [
'ref_unit' => 'kg',
'unit' => 'g',
'wording_unit' => 'le g',
'wording' => 'g',
@@ -91,6 +92,7 @@ class Product extends ActiveRecordCommon
'coefficient' => 1
],
'mL' => [
'ref_unit' => 'L',
'unit' => 'mL',
'wording_unit' => 'le mL',
'wording' => 'mL',
@@ -350,6 +352,15 @@ class Product extends ActiveRecordCommon
return $productGift;
}

public function getRefUnit($unit)
{
if(isset(self::$unitsArray[$unit]) && isset(self::$unitsArray[$unit]['ref_unit'])) {
return self::$unitsArray[$unit]['ref_unit'];
}

return $unit;
}

/**
* Retourne le libellé d'une unité.
*
@@ -377,70 +388,108 @@ class Product extends ActiveRecordCommon
return $strUnit;
}

public function getPrice($params = [])
public function getPriceArray($user, $pointSale)
{
$specificPrices = $this->productPrice ;
$priceArray = [];

$user = isset($params['user']) ? $params['user'] : false ;
$userProducer = isset($params['user_producer']) ? $params['user_producer'] : false ;
$pointSale = isset($params['point_sale']) ? $params['point_sale'] : false ;
$userProducer = null;
if($user) {
$userProducer = UserProducer::searchOne([
'id_user' => $user->id,
]);
}

if($specificPrices && ($user || $pointSale)) {
// specific prices
$specificPriceArray = $this->getSpecificPricesFilterByPriorityMatch(
$this->productPrice,
$user,
$pointSale
);

foreach ($specificPriceArray as $specificPrice) {
$priceArray[] = [
'from_quantity' => $specificPrice->from_quantity ? $specificPrice->from_quantity : 0,
'price_with_tax' => $this->getPriceWithTax([
'user' => $user,
'user_producer' => $userProducer,
'point_sale' => $pointSale,
'quantity' => $specificPrice->from_quantity
]),
];
}

$specificPricesArray = [
'user' => false,
'pointsale' => false,
'user_pointsale' => false,
'usergroup' => false,
] ;
if(!$this->hasPriceWithQuantityZero($priceArray)) {
// base price
$priceArray[] = [
'from_quantity' => 0,
'price_with_tax' => $this->getPriceWithTax(),
];
}

foreach($specificPrices as $specificPrice) {
if($user
&& $specificPrice->id_user
&& !$specificPrice->id_point_sale
&& !$specificPrice->id_user_group
&& $specificPrice->id_user == $user->id) {
usort($priceArray, function($a, $b) {
if($a['price_with_tax'] < $b['price_with_tax']) {
return 1;
}
elseif($a['price_with_tax'] > $b['price_with_tax']) {
return -1;
}
else {
return 0;
}
});

$specificPricesArray['user'] = $specificPrice->price ;
}
if($user
&& $specificPrice->id_user_group
&& !$specificPrice->id_point_sale
&& !$specificPrice->id_user
&& $user->belongsToUserGroup($specificPrice->id_user_group)) {
return $priceArray;
}

$specificPricesArray['usergroup'] = $specificPrice->price ;
}
if($pointSale
&& $specificPrice->id_point_sale
&& !$specificPrice->id_user
&& !$specificPrice->id_user_group
&& $specificPrice->id_point_sale == $pointSale->id) {
public function hasPriceWithQuantityZero($priceArray)
{
foreach($priceArray as $price) {
if($price['from_quantity'] == 0) {
return true;
}
}

$specificPricesArray['pointsale'] = $specificPrice->price ;
}
return false;
}

if($pointSale && $user
&& $specificPrice->id_point_sale
&& $specificPrice->id_user
&& $specificPrice->id_point_sale == $pointSale->id
&& $specificPrice->id_user == $user->id) {
public function getSpecificPricesFilterByPriorityMatch($specificPrices, $user, $pointSale)
{
$priorityMatchSpecificPrice = ProductPrice::getPriorityMatchOfSpecificPriceArray($specificPrices, $user, $pointSale);
$specificPricesFilter = [];

$specificPricesArray['user_pointsale'] = $specificPrice->price ;
}
}
foreach($specificPrices as $keySpecificPrice => $specificPrice) {
if(($priorityMatchSpecificPrice && $specificPrice->$priorityMatchSpecificPrice($user, $pointSale))
|| $specificPrice->matchFromQuantityOnly()) {

if($specificPricesArray['user_pointsale']) {
return $specificPricesArray['user_pointsale'] ;
}
elseif($specificPricesArray['user']) {
return $specificPricesArray['user'] ;
}
elseif($specificPricesArray['usergroup']) {
return $specificPricesArray['usergroup'] ;
$specificPricesFilter[] = $specificPrice;
}
}

return $specificPricesFilter;
}

public function getPrice($params = [])
{
$specificPrices = $this->productPrice ;

$user = isset($params['user']) ? $params['user'] : false ;
$userProducer = isset($params['user_producer']) ? $params['user_producer'] : false ;
$pointSale = isset($params['point_sale']) ? $params['point_sale'] : false ;
$quantity = (isset($params['quantity']) && $params['quantity']) ? $params['quantity'] : 1 ;

if($specificPrices && ($user || $pointSale)) {
$specificPrices = $this->getSpecificPricesFilterByPriorityMatch($specificPrices, $user, $pointSale);
$bestPrice = 9999;
foreach($specificPrices as $specificPrice) {
$fromQuantity = $specificPrice->from_quantity;
if((($fromQuantity && $fromQuantity <= $quantity) || !$fromQuantity)
&& $specificPrice->price < $bestPrice) {
$bestPrice = $specificPrice->price;
}
}
elseif($specificPricesArray['pointsale']) {
return $specificPricesArray['pointsale'] ;

if($bestPrice != 9999) {
return $bestPrice;
}
}


+ 190
- 93
common/models/ProductPrice.php Переглянути файл

@@ -53,113 +53,210 @@ use common\components\ActiveRecordCommon;
class ProductPrice extends ActiveRecordCommon
{

/**
* @inheritdoc
*/
public static function tableName()
{
return 'product_price';
}
/**
* @inheritdoc
*/
public static function tableName()
{
return 'product_price';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
['id_user', 'required', 'when' => function($model) {
return !$model->id_point_sale && !$model->id_user_group ;
}, 'message' => 'Vous devez renseigner au moins un utilisateur, un point de vente ou un groupe d\'utilisateur'],
['id_point_sale', 'required', 'when' => function($model) {
return !$model->id_user && !$model->id_user_group ;
}, 'message' => 'Vous devez renseigner au moins un utilisateur, un point de vente ou un groupe d\'utilisateur'],
['id_user_group', 'required', 'when' => function($model) {
return !$model->id_user && !$model->id_point_sale ;
}, 'message' => 'Vous devez renseigner au moins un utilisateur, un point de vente ou un groupe d\'utilisateur'],
[['id_product', 'price'], 'required'],
[['id_product', 'id_user', 'id_point_sale', 'id_user_group', 'percent'], 'integer'],
[['price'], 'double'],
];
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[
'id_user',
'required',
'when' => function ($model) {
return !$model->id_point_sale && !$model->id_user_group && !$model->from_quantity;
},
'message' => 'Vous devez renseigner au moins un utilisateur, un point de vente, un groupe d\'utilisateur ou une quantité'
],
[
'id_point_sale',
'required',
'when' => function ($model) {
return !$model->id_user && !$model->id_user_group && !$model->from_quantity;
},
'message' => 'Vous devez renseigner au moins un utilisateur, un point de vente, un groupe d\'utilisateur ou une quantité'
],
[
'id_user_group',
'required',
'when' => function ($model) {
return !$model->id_user && !$model->id_point_sale && !$model->from_quantity;
},
'message' => 'Vous devez renseigner au moins un utilisateur, un point de vente, un groupe d\'utilisateur ou une quantité'
],
[
'from_quantity',
'required',
'when' => function ($model) {
return !$model->id_user && !$model->id_user_group && !$model->id_point_sale;
},
'message' => 'Vous devez renseigner au moins un utilisateur, un point de vente, un groupe d\'utilisateur ou une quantité'
],
[['id_product', 'price'], 'required'],
[['id_product', 'id_user', 'id_point_sale', 'id_user_group', 'percent'], 'integer'],
[['price', 'from_quantity'], 'double'],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_product' => 'Produit',
'id_user' => 'Utilisateur',
'id_point_sale' => 'Point de vente',
'id_user_group' => "Groupe d'utilisateur",
'price' => 'Prix (HT)',
'percent' => 'Pourcentage',
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_product' => 'Produit',
'id_user' => 'Utilisateur',
'id_point_sale' => 'Point de vente',
'id_user_group' => "Groupe d'utilisateur",
'price' => 'Prix (HT)',
'percent' => 'Pourcentage',
'from_quantity' => 'À partir de la quantité',
];
}

/*
* Relations
*/
/*
* Relations
*/

public function getProduct()
{
return $this->hasOne(
Product::className(),
['id' => 'id_product']
);
}
public function getProduct()
{
return $this->hasOne(
Product::className(),
['id' => 'id_product']
);
}

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

public function getUserGroup()
{
return $this->hasOne(
UserGroup::className(),
['id' => 'id_user_group']
);
}

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

/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
{
return [
'with' => ['user', 'pointSale'],
'join_with' => ['product'],
'orderby' => '',
'attribute_id_producer' => 'product.id_producer'
];
}

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

for ($i = -50; $i < 51; $i = $i + 5) {
$percentValues[$i] = $i . ' %';
}

public function getUserGroup()
{
return $this->hasOne(
UserGroup::className(),
['id' => 'id_user_group']
);
return $percentValues;
}

public static function hasMatchOfType($specificPriceArray, $typeMatch, $user, $pointSale)
{
foreach($specificPriceArray as $specificPrice) {
if($specificPrice->$typeMatch($user, $pointSale)) {
return true;
}
}

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

public static function getPriorityMatchOfSpecificPriceArray($specificPriceArray, $user, $pointSale)
{
if(self::hasMatchOfType($specificPriceArray, 'matchUser', $user, $pointSale)) {
return 'matchUser';
}
if(self::hasMatchOfType($specificPriceArray, 'matchUserGroup', $user, $pointSale)) {
return 'matchUserGroup';
}
if(self::hasMatchOfType($specificPriceArray, 'matchPointSale', $user, $pointSale)) {
return 'matchPointSale';
}

/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
{
return [
'with' => ['user', 'pointSale'],
'join_with' => ['product'],
'orderby' => '',
'attribute_id_producer' => 'product.id_producer'
];
if(self::hasMatchOfType($specificPriceArray, 'matchUserPointSale', $user, $pointSale)) {
return 'matchUserPointSale';
}

public static function percentValues()
{
$percentValues = [
'' => 'Aucun'
] ;
return null;
}

for($i = -50 ; $i < 51 ; $i = $i + 5) {
$percentValues[$i] = $i.' %' ;
}
public function matchUser($user, $pointSale)
{
return $user
&& $this->id_user
&& !$this->id_point_sale
&& !$this->id_user_group
&& $this->id_user == $user->id;
}

return $percentValues ;
}
public function matchUserGroup($user, $pointSale)
{
return $user
&& $this->id_user_group
&& !$this->id_point_sale
&& !$this->id_user
&& $user->belongsToUserGroup($this->id_user_group);
}

public function matchPointSale($user, $pointSale)
{
return $pointSale
&& $this->id_point_sale
&& !$this->id_user
&& !$this->id_user_group
&& $this->id_point_sale == $pointSale->id;
}

public function matchUserPointSale($user, $pointSale)
{
return $pointSale && $user
&& $this->id_point_sale
&& $this->id_user
&& $this->id_point_sale == $pointSale->id
&& $this->id_user == $user->id;
}

public function matchFromQuantityOnly()
{
return !$this->id_user
&& !$this->id_point_sale
&& !$this->id_user_group
&& $this->from_quantity;
}
}

+ 2
- 7
common/models/Subscription.php Переглянути файл

@@ -255,7 +255,8 @@ class Subscription extends ActiveRecordCommon
$productOrder->quantity = $productSubscription->quantity;
$productOrder->price = $productSubscription->product->getPrice([
'user' => $user,
'point_sale' => $pointSale
'point_sale' => $pointSale,
'quantity' => $productSubscription->quantity
]);
$productOrder->unit = $productSubscription->product->unit;
$productOrder->step = $productSubscription->product->step;
@@ -443,11 +444,6 @@ class Subscription extends ActiveRecordCommon
->andWhere('distribution.date >= :date_begin')
->andWhere('order.id_subscription = :id_subscription');

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

$orders->params($params);

$ordersArray = $orders->all();
@@ -469,7 +465,6 @@ class Subscription extends ActiveRecordCommon
);
}

ProductOrder::deleteAll(['id_order' => $order->id]);
$order->delete();
}
}

+ 26
- 0
console/migrations/m220804_095203_prix_degressifs_champs_from_quantity.php Переглянути файл

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

use yii\db\Migration;
use yii\db\Schema;

/**
* Class m220804_095203_prix_degressifs_champs_from_quantity
*/
class m220804_095203_prix_degressifs_champs_from_quantity extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('product_price', 'from_quantity', Schema::TYPE_FLOAT.' DEFAULT NULL');
}

/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropColumn('product_price', 'from_quantity');
}
}

+ 29
- 30
producer/controllers/OrderController.php Переглянути файл

@@ -466,14 +466,7 @@ class OrderController extends ProducerBaseController
$productOrder = new ProductOrder();
$productOrder->id_order = $order->id;
$productOrder->id_product = $product->id;

$productOrder->price = $product->getPrice([
'user' => User::getCurrent(),
'user_producer' => $userProducer,
'point_sale' => $pointSale
]);
$productOrder->id_tax_rate = $product->taxRate->id;

$unit = (!is_null(
$order
) && isset($unitsArray[$product->id])) ? $unitsArray[$product->id] : $product->unit;
@@ -482,8 +475,13 @@ class OrderController extends ProducerBaseController
if ($availableProducts[$product->id]['quantity_max'] && $quantity > $availableProducts[$product->id]['quantity_remaining']) {
$quantity = $availableProducts[$product->id]['quantity_remaining'];
}

$productOrder->quantity = $quantity;
$productOrder->price = $product->getPrice([
'user' => User::getCurrent(),
'user_producer' => $userProducer,
'point_sale' => $pointSale,
'quantity' => $quantity
]);
$productOrder->unit = $product->unit;
$productOrder->step = $product->step;
$productOrder->save();
@@ -702,14 +700,13 @@ class OrderController extends ProducerBaseController
for ($i = 0; $i < count($distributionsArray); $i++) {
$distribution = $distributionsArray[$i];
if (Distribution::isPointSaleActive($distribution, $pointSaleId)) {

$countOrders = (int) Order::searchCount([
'id_distribution' => $distribution->id,
'id_point_sale' => $pointSaleId
]);
$countOrders = (int)Order::searchCount([
'id_distribution' => $distribution->id,
'id_point_sale' => $pointSaleId
]);
$orderUserPointSale = $this->_getOrderUser($distribution->date, $pointSaleId);

if(!$pointSaleCurrent->maximum_number_orders
if (!$pointSaleCurrent->maximum_number_orders
|| ($orderUserPointSale && $orderUserPointSale->id_point_sale == $pointSaleId)
|| ($pointSaleCurrent->maximum_number_orders &&
($countOrders < $pointSaleCurrent->maximum_number_orders))) {
@@ -812,16 +809,18 @@ class OrderController extends ProducerBaseController
]);

$productsArray = $productsArray->joinWith([
'productDistribution' => function ($query) use ($distribution) {
'productDistribution' => function ($query) use (
$distribution
) {
$query->andOnCondition(
'product_distribution.id_distribution = ' . $distribution->id
);
},
/*'productPointSale' => function ($query) use ($pointSaleCurrent) {
$query->andOnCondition(
'product_point_sale.id_point_sale = ' . $pointSaleCurrent->id
);
},*/
/*'productPointSale' => function ($query) use ($pointSaleCurrent) {
$query->andOnCondition(
'product_point_sale.id_point_sale = ' . $pointSaleCurrent->id
);
},*/
'productPrice'
])
->orderBy('product_distribution.active DESC, order ASC')
@@ -830,8 +829,8 @@ class OrderController extends ProducerBaseController
$productsArrayFilter = [];

// filtre sur les points de vente
foreach($productsArray as $product) {
if($product->isAvailableOnPointSale($pointSaleCurrent)) {
foreach ($productsArray as $product) {
if ($product->isAvailableOnPointSale($pointSaleCurrent)) {
$productsArrayFilter[] = $product;
}
}
@@ -841,11 +840,8 @@ class OrderController extends ProducerBaseController
$product = array_merge(
$product->getAttributes(),
[
'price_with_tax' => $product->getPriceWithTax([
'user' => User::getCurrent(),
'user_producer' => $userProducer,
'point_sale' => $pointSaleCurrent
]),
'unit_coefficient' => Product::$unitsArray[$product->unit]['coefficient'],
'prices' => $product->getPriceArray($userProducer->user, $pointSaleCurrent),
'productDistribution' => $product['productDistribution'],
'productPointSale' => $product['productPointSale'],
]
@@ -861,6 +857,8 @@ class OrderController extends ProducerBaseController
$quantityOrder = Order::getProductQuantity($product['id'], $ordersArray);
$product['quantity_ordered'] = $quantityOrder;
$product['quantity_remaining'] = $product['quantity_max'] - $quantityOrder;
$product['wording_unit'] = Product::strUnit($product['unit'], 'wording_unit', true);
$product['wording_unit_ref'] = Product::strUnit($product['unit'], 'wording_short', true);

if ($orderUser) {
$quantityOrderUser = Order::getProductQuantity($product['id'], [$orderUser], true);
@@ -893,7 +891,8 @@ class OrderController extends ProducerBaseController
return $json;
}

private function _getOrderUser($date, $pointSaleId = false) {
private function _getOrderUser($date, $pointSaleId = false)
{
$orderUser = false;
if (User::getCurrentId()) {
$conditionOrderUser = [
@@ -979,14 +978,14 @@ class OrderController extends ProducerBaseController
}

if ($distribution) {
$pointSale['count_orders'] = (int) Order::searchCount([
$pointSale['count_orders'] = (int)Order::searchCount([
'id_distribution' => $distribution->id,
'id_point_sale' => $pointSale['id']
]);
}

$pointSale['position'] = $position;
$position ++;
$position++;
}

$favoritePointSale = false;

+ 17
- 5
producer/views/order/order.php Переглянути файл

@@ -303,10 +303,22 @@ $producer = GlobalParam::getCurrentProducer() ;
<div class="recipe" v-if="product.recipe.length">{{ product.recipe }}</div>
</td>
<td class="price-unit">
<template v-if="product.price_with_tax >= 0">{{ formatPrice(product.price_with_tax) }}<br /><span class="unit">{{ product.wording_unit }}</span></template>
<template v-if="productHasPrice(product)">
<div>
{{ formatPrice(getBestProductPrice(product.id, product.quantity_form)) }}<br />
<span class="unit">{{ product.wording_unit }}</span>
</div>
<div v-if="productHasPriceWithFromQuantity(product)" class="alert alert-info decreasing-prices">
<ul>
<li v-for="price in product.prices" v-if="price.from_quantity > 0">
<strong>{{ formatPrice(price.price_with_tax) }}</strong><br />à partir de {{ price.from_quantity }} {{ product.wording_unit_ref }}
</li>
</ul>
</div>
</template>
</td>
<td class="td-quantity">
<template v-if="product.price_with_tax >= 0">
<template v-if="productHasPrice(product)">
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default btn-moins" type="button" @click="productQuantityClick(product, product.unit == 'piece' ? -1 : -parseFloat(product.step))" :disabled="product.quantity_form == 0"><span class="glyphicon glyphicon-minus"></span></button>
@@ -320,8 +332,8 @@ $producer = GlobalParam::getCurrentProducer() ;
</template>
</td>
<td class="price-total">
<template v-if="product.price_with_tax >= 0 && product.quantity_form > 0">
{{ formatPrice(product.price_with_tax * (product.quantity_form / product.coefficient_unit )) }}
<template v-if="productHasPrice(product) && product.quantity_form > 0">
{{ formatPrice(getBestProductPrice(product.id, product.quantity_form) * (product.quantity_form / product.coefficient_unit )) }}
</template>
</td>
</tr>
@@ -475,7 +487,7 @@ $producer = GlobalParam::getCurrentProducer() ;
</div>
</div>

<div v-if="producer.online_payment && producer.option_online_payment_type == 'credit'" id="credit-online-payment">
<div v-if="producer != null && producer.online_payment && producer.option_online_payment_type == 'credit'" id="credit-online-payment">
<div class="panel panel-default">
<div class="panel-heading">
<i class="glyphicon glyphicon-euro"></i> Paiement en ligne

+ 36
- 20
producer/web/css/screen.css Переглянути файл

@@ -1548,26 +1548,42 @@ termes.
.order-order #main #app-order-order table#products td.name .recipe {
color: gray;
}
/* line 284, ../sass/order/_order.scss */
/* line 286, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices {
margin-top: 10px;
font-size: 10px;
padding-top: 6px;
padding-bottom: 2px;
margin-bottom: 0px;
}
/* line 294, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li {
margin-bottom: 5px;
}
/* line 296, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .decreasing-prices ul li strong {
font-weight: bold;
}
/* line 304, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit, .order-order #main #app-order-order table#products .price-total {
width: 100px;
width: 120px;
text-align: center;
}
/* line 288, ../sass/order/_order.scss */
/* line 308, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .price-unit .unit, .order-order #main #app-order-order table#products .price-total .unit {
color: gray;
font-size: 13px;
}
/* line 293, ../sass/order/_order.scss */
/* line 313, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity {
width: 175px;
}
/* line 295, ../sass/order/_order.scss */
/* line 315, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity input.quantity {
text-align: center;
border-right: 0px none;
}
/* line 299, ../sass/order/_order.scss */
/* line 319, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products .td-quantity .input-group-addon {
padding: 5px;
padding-left: 0px;
@@ -1575,69 +1591,69 @@ termes.
border-left: 0px none;
border-right: 0px none;
}
/* line 310, ../sass/order/_order.scss */
/* line 330, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary h3 {
margin-top: 0px;
font-family: "capsuularegular";
text-transform: none;
margin-bottom: 5px;
}
/* line 317, ../sass/order/_order.scss */
/* line 337, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul {
margin-bottom: 15px;
padding-left: 20px;
font-size: 23px;
}
/* line 324, ../sass/order/_order.scss */
/* line 344, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul li .quantity {
font-size: 18px;
}
/* line 328, ../sass/order/_order.scss */
/* line 348, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul li .name {
font-family: "capsuularegular";
font-size: 24px;
}
/* line 332, ../sass/order/_order.scss */
/* line 352, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .summary ul li .other {
font-family: "arial";
font-size: 14px;
}
/* line 339, ../sass/order/_order.scss */
/* line 359, ../sass/order/_order.scss */
.order-order #main #app-order-order table#products tr.total .price-total {
font-size: 23px;
}
/* line 347, ../sass/order/_order.scss */
/* line 367, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .delivery {
margin-bottom: 20px;
}
/* line 350, ../sass/order/_order.scss */
/* line 370, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .delivery .delivery-home {
margin-bottom: 20px;
}
/* line 359, ../sass/order/_order.scss */
/* line 379, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .comment {
margin-bottom: 20px;
}
/* line 364, ../sass/order/_order.scss */
/* line 384, ../sass/order/_order.scss */
.order-order #main #app-order-order #content-step-payment .credit .info {
margin-left: 20px;
color: gray;
}
/* line 371, ../sass/order/_order.scss */
/* line 391, ../sass/order/_order.scss */
.order-order #main #app-order-order #specific-delays {
margin-top: 15px;
}
/* line 379, ../sass/order/_order.scss */
/* line 399, ../sass/order/_order.scss */
.order-order #main #app-order-order #infos {
margin-top: 30px;
}
/* line 381, ../sass/order/_order.scss */
/* line 401, ../sass/order/_order.scss */
.order-order #main #app-order-order #infos .panel-body {
padding-top: 0px;
white-space: pre-line;
}

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

+ 49
- 5
producer/web/js/vuejs/order-order.js Переглянути файл

@@ -4,6 +4,7 @@ var app = new Vue({
el: '#app-order-order',
data() {
return Object.assign({
order: null,
loading: false,
loadingInit: true,
step: null,
@@ -67,10 +68,7 @@ var app = new Vue({
}, window.appInitValues);
},
mounted: function() {

let fr = new Intl.Locale("fr-FR");
console.log(fr);

var dateDefined = $('#order-distribution-date').size() || $('#distribution-date').size() ;

if(dateDefined) {
@@ -117,6 +115,13 @@ var app = new Vue({
}
}
},
getProduct: function(idProduct) {
for(var key in this.products) {
if(this.products[key].id == idProduct) {
return this.products[key] ;
}
}
},
init: function(type, oldStep, step) {

var app = this ;
@@ -458,8 +463,9 @@ var app = new Vue({
priceTotal: function(format) {
var price = 0 ;
for(var key in this.products) {
if(this.products[key].quantity_form > 0) {
price += (this.products[key].quantity_form / this.products[key].coefficient_unit) * this.products[key].price_with_tax ;
var quantity = this.products[key].quantity_form;
if(quantity > 0) {
price += (quantity / this.products[key].unit_coefficient) * this.getBestProductPrice(this.products[key].id, this.products[key].quantity_form);
}
}
if(format) {
@@ -469,6 +475,44 @@ var app = new Vue({
return price ;
}
},
productHasPrice: function(product) {
return product.prices && product.prices.length > 0;
},
productHasPriceWithFromQuantity: function(product) {
if(this.productHasPrice(product)) {
for(var i = 0; i < product.prices.length; i++) {
if(product.prices[i].from_quantity > 0) {
return true;
}
}
}

return false;
},
getBestProductPrice: function(idProduct, theQuantity) {
var thePriceWithTax = 9999;
var product = this.getProduct(idProduct);
var pricesArray = product.prices;
var unitCoefficient = product.unit_coefficient;
if(theQuantity) {
theQuantity = theQuantity / unitCoefficient;
}

for(var i = 0; i < pricesArray.length ; i++) {
var priceWithTax = pricesArray[i].price_with_tax;
var fromQuantity = pricesArray[i].from_quantity;

if(priceWithTax < thePriceWithTax && fromQuantity <= theQuantity) {
thePriceWithTax = priceWithTax;
}
}
if(thePriceWithTax == 9999) {
return 0;
}
else {
return thePriceWithTax;
}
},
confirmClick: function() {

var app = this ;

+ 21
- 1
producer/web/sass/order/_order.scss Переглянути файл

@@ -281,8 +281,28 @@
color: gray ;
}
}

.price-unit {
.decreasing-prices {
margin-top: 10px;
font-size: 10px;
padding-top: 6px;
padding-bottom: 2px;
margin-bottom: 0px;

ul {
li {
margin-bottom: 5px;
strong {
font-weight: bold;
}
}
}
}
}

.price-unit, .price-total {
width: 100px ;
width: 120px ;
text-align: center ;
.unit {

Завантаження…
Відмінити
Зберегти