Browse Source

Merge branch 'feature/prix_degressifs' into dev

refactoring
Guillaume 2 years ago
parent
commit
709414e7f9
16 changed files with 555 additions and 249 deletions
  1. +11
    -11
      backend/controllers/DistributionController.php
  2. +2
    -10
      backend/controllers/DocumentController.php
  3. +1
    -0
      backend/controllers/ProductController.php
  4. +4
    -2
      backend/views/product/update/prices/_form.php
  5. +10
    -0
      backend/views/product/update/prices/list.php
  6. +41
    -12
      backend/web/js/vuejs/distribution-index.js
  7. +26
    -3
      backend/web/js/vuejs/document-form.js
  8. +102
    -52
      common/models/Product.php
  9. +178
    -97
      common/models/ProductPrice.php
  10. +2
    -1
      common/models/Subscription.php
  11. +26
    -0
      console/migrations/m220804_095203_prix_degressifs_champs_from_quantity.php
  12. +29
    -30
      producer/controllers/OrderController.php
  13. +17
    -5
      producer/views/order/order.php
  14. +36
    -20
      producer/web/css/screen.css
  15. +49
    -5
      producer/web/js/vuejs/order-order.js
  16. +21
    -1
      producer/web/sass/order/_order.scss

+ 11
- 11
backend/controllers/DistributionController.php View File

@@ -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;

+ 2
- 10
backend/controllers/DocumentController.php View File

@@ -363,16 +363,8 @@ class DocumentController extends BackendController
'id',
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
]);

+ 1
- 0
backend/controllers/ProductController.php View File

@@ -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) ;

+ 4
- 2
backend/views/product/update/prices/_form.php View File

@@ -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 View File

@@ -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) {

+ 41
- 12
backend/web/js/vuejs/distribution-index.js View File

@@ -591,22 +591,26 @@ 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);
}
}
}
@@ -616,7 +620,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 +654,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 +756,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) ;
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
});
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);
Vue.set(this.order.productOrder[id_product], 'price', app.getBestProductPrice(this.order, id_product, theQuantity));
}
},
productPriceChange: function(event) {

+ 26
- 3
backend/web/js/vuejs/document-form.js View File

@@ -141,10 +141,32 @@ var app = new Vue({
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.productAddPrice = this.getBestProductPrice(idProduct, this.getStepProductAdd());
this.productAddQuantity = this.getStepProductAdd() ;
},
},
getBestProductPrice: function(idProduct, theQuantity) {
var thePriceWithTax = 9999;
var pricesArray = this.productsArray[idProduct].prices;
var unitCoefficient = this.productsArray[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;
}
},
changeQuantityProductAdd: function(quantity) {
var step = this.getStepProductAdd() ;
quantity = quantity * step ;
@@ -152,6 +174,7 @@ var app = new Vue({
if(this.productAddQuantity < 1) {
this.productAddQuantity = step ;
}
this.productAddPrice = this.getBestProductPrice(app.productAddId, this.productAddQuantity);
},
submitProductAdd: function() {
var app = this ;

+ 102
- 52
common/models/Product.php View File

@@ -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,109 @@ 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);

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

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

return [];
}

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;
}
}


+ 178
- 97
common/models/ProductPrice.php View File

@@ -53,113 +53,194 @@ 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', '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',
'from_quantity' => 'À partir de la quantité',
];
}

/*
* Relations
*/

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 static function percentValues()
{
$percentValues = [
'' => 'Aucun'
];

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

/**
* @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'],
];
}
return $percentValues;
}

/**
* @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',
];
public static function hasMatchOfType($specificPriceArray, $typeMatch, $user, $pointSale)
{
foreach($specificPriceArray as $specificPrice) {
if($specificPrice->$typeMatch($user, $pointSale)) {
return true;
}
}

/*
* Relations
*/
return false;
}

public function getProduct()
{
return $this->hasOne(
Product::className(),
['id' => 'id_product']
);
public static function getPriorityMatchOfSpecificPriceArray($specificPriceArray, $user, $pointSale)
{
if(self::hasMatchOfType($specificPriceArray, 'matchUser', $user, $pointSale)) {
return 'matchUser';
}

public function getPointSale()
{
return $this->hasOne(
PointSale::className(),
['id' => 'id_point_sale']
);
if(self::hasMatchOfType($specificPriceArray, 'matchUserGroup', $user, $pointSale)) {
return 'matchUserGroup';
}

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

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

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

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

return $percentValues ;
if(self::hasMatchOfType($specificPriceArray, 'matchUserPointSale', $user, $pointSale)) {
return 'matchUserPointSale';
}

return null;
}

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

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;
}
}

+ 2
- 1
common/models/Subscription.php View File

@@ -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;

+ 26
- 0
console/migrations/m220804_095203_prix_degressifs_champs_from_quantity.php View File

@@ -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 View File

@@ -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 View File

@@ -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 View File

@@ -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 View File

@@ -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.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 View File

@@ -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 {

Loading…
Cancel
Save