@@ -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; |
@@ -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, |
@@ -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) ; |
@@ -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)) }} |
@@ -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> |
@@ -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) { |
@@ -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) ; | |||
} | |||
} | |||
}) ; |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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'); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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'); | |||
} | |||
} |
@@ -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; |
@@ -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 |
@@ -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; |
@@ -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 ; |
@@ -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 { |