@@ -38,8 +38,11 @@ | |||
namespace backend\controllers; | |||
use common\models\Product; | |||
use common\models\User ; | |||
use common\models\Document ; | |||
use common\helpers\GlobalParam ; | |||
use common\models\Order ; | |||
class DocumentController extends BackendController | |||
{ | |||
@@ -152,10 +155,36 @@ class DocumentController extends BackendController | |||
]) ; | |||
if($document) { | |||
$productsArray = Product::searchAll([], [ | |||
'as_array' => true, | |||
]) ; | |||
$ordersArray = [] ; | |||
foreach($document->orders as $order) { | |||
$order->init() ; | |||
$productsOrderArray = [] ; | |||
foreach($order->productOrder as $productOrder) { | |||
$productsOrderArray[$productOrder->id] = $productOrder->getAttributes() ; | |||
} | |||
$ordersArray[$order->id] = array_merge( | |||
$order->getAttributes(), | |||
[ | |||
'productOrder' => $productsOrderArray, | |||
] | |||
); | |||
} | |||
return [ | |||
'return' => 'success', | |||
'address' => $document->address, | |||
'idUser' => $document->user->id | |||
'return' => 'success', | |||
'document' => $document->getAttributes(), | |||
'idUser' => $document->user->id, | |||
'products' => ArrayHelper::map($productsArray, 'id', function($product) { | |||
$product['wording_unit'] = Product::strUnit($product['unit']) ; | |||
return $product; | |||
}), | |||
'orders' => $ordersArray, | |||
'total' => $document->getAmount(Order::AMOUNT_TOTAL) | |||
] ; | |||
} | |||
} | |||
@@ -163,6 +192,61 @@ class DocumentController extends BackendController | |||
return ['return' => 'error'] ; | |||
} | |||
public function actionAjaxAddProduct($idDocument, $classDocument, $idProduct, $quantity, $price) | |||
{ | |||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||
if(Document::isValidClass($classDocument)) { | |||
$document = $classDocument::searchOne([ | |||
'id' => $idDocument | |||
]) ; | |||
$product = Product::searchOne([ | |||
'id' => $idProduct | |||
]) ; | |||
if($document && $product) { | |||
if(count($document->orders) == 0) { | |||
$order = new Order ; | |||
$order->id_user = $document->id_user ; | |||
$order->id_point_sale = null ; | |||
$order->id_distribution = null ; | |||
$order->origin = Order::ORIGIN_ADMIN ; | |||
$order->date = date('Y-m-d H:i:s'); | |||
$fieldIdDocument = 'id_'.$classDocument::tableName() ; | |||
$order->$fieldIdDocument = $document->id ; | |||
$order->save() ; | |||
} | |||
else { | |||
$order = $document->orders[0] ; | |||
} | |||
if($order) { | |||
$productOrder = new ProductOrder ; | |||
$productOrder->id_order = $order->id ; | |||
$productOrder->id_product = $idProduct ; | |||
$quantity = $quantity / Product::$unitsArray[$product->unit]['coefficient']; | |||
$productOrder->quantity = $quantity ; | |||
$productOrder->price = (float) $price ; | |||
$productOrder->unit = $product->unit ; | |||
$productOrder->step = $product->step ; | |||
$productOrder->id_tax_rate = $productOrder->id_tax_rate ? | |||
$product->taxRate->id : GlobalParam::getCurrentProducer()->taxRate->id ; | |||
$productOrder->save() ; | |||
return [ | |||
'return' => 'success', | |||
] ; | |||
} | |||
} | |||
} | |||
return [ | |||
'return' => 'error' | |||
] ; | |||
} | |||
protected function getClass() | |||
{ | |||
$class = get_class($this); |
@@ -35,6 +35,7 @@ | |||
* pris connaissance de la licence CeCILL, et que vous en avez accepté les | |||
* termes. | |||
*/ | |||
use yii\helpers\Html; | |||
use yii\widgets\ActiveForm; | |||
use common\models\Product; | |||
@@ -46,29 +47,32 @@ use common\models\Producer; | |||
?> | |||
<div class="document-form" id="app-document-form" data-class-document="<?= $model->getClass() ?>" data-id-document="<?= ($model->id > 0) ? $model->id : $model->id ?>"> | |||
<div class="document-form" id="app-document-form" data-class-document="<?= $model->getClass() ?>" | |||
data-id-document="<?= ($model->id > 0) ? $model->id : $model->id ?>"> | |||
<div class="<?php if($action == 'create') : ?>col-md-12<?php else : ?>col-md-4<?php endif; ?>"> | |||
<div class="<?= ($action == 'update') ? 'col-md-6' : '' ?>"> | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Informations | |||
Général | |||
</div> | |||
<div class="panel-body"> | |||
<?php $form = ActiveForm::begin(); ?> | |||
<?= $form->field($model, 'name')->label('Nom du document') ?> | |||
<?php $usersArray = User::findBy()->all() ; ?> | |||
<?= $form->field($model, 'id_user', [ | |||
'template' => '{label} <a href="'.Yii::$app->urlManager->createUrl(['user/create']).'" class="btn btn-xs btn-default">Nouvel utilisateur <span class="glyphicon glyphicon-plus"></span></a><div>{input}</div>{hint}', | |||
]) | |||
<?php $usersArray = User::findBy()->all(); ?> | |||
<?= $form->field($model, 'id_user', [ | |||
'template' => '{label} <a href="' . Yii::$app->urlManager->createUrl(['user/create']) . '" class="btn btn-xs btn-default">Nouvel utilisateur <span class="glyphicon glyphicon-plus"></span></a><div>{input}</div>{hint}', | |||
]) | |||
->dropDownList( | |||
ArrayHelper::map($usersArray, 'user_id', function($model) { return $model['lastname'].' '.$model['name']; }), | |||
ArrayHelper::map($usersArray, 'user_id', function ($model) { | |||
return $model['lastname'] . ' ' . $model['name']; | |||
}), | |||
[ | |||
'@change' => 'changeUser', | |||
'prompt' => '--', | |||
'v-model' => 'idUser', | |||
'@change' => 'changeUser', | |||
'prompt' => '--', | |||
'v-model' => 'idUser', | |||
] | |||
); ?> | |||
<?= $form->field($model, 'address')->textarea(['rows' => 3, 'v-model' => 'address']) ?> | |||
<?= $form->field($model, 'address')->textarea(['rows' => 3, 'v-model' => 'document.address']) ?> | |||
<div class="form-group"> | |||
<?= Html::submitButton($model->isNewRecord ? 'Ajouter' : 'Modifier', ['class' => 'btn btn-primary']) ?> | |||
</div> | |||
@@ -76,18 +80,136 @@ use common\models\Producer; | |||
</div> | |||
</div> | |||
</div> | |||
<?php if($action == 'update'): ?> | |||
<div class="col-md-8"> | |||
<?php if ($action == 'update'): ?> | |||
<div class="col-md-6"> | |||
<div id="" class="info-box"> | |||
<span class="info-box-icon bg-green"><i class="fa fa-sticky-note-o"></i></span> | |||
<div class="info-box-content"> | |||
<span class="info-box-text">Référence</span> | |||
<span class="info-box-number">{{ document.reference }}</span> | |||
<span class="info-box-text">Date</span> | |||
<span class="info-box-number">{{ document.date }}</span> | |||
</div> | |||
</div> | |||
<div id="" class="info-box"> | |||
<span class="info-box-icon bg-yellow"><i class="fa fa-euro"></i></span> | |||
<div class="info-box-content"> | |||
<span class="info-box-text">Total (TTC)</span> | |||
<span class="info-box-number">{{ formatPrice(total) }}</span> | |||
</div> | |||
</div> | |||
<div id="" class="info-box"> | |||
<span class="info-box-icon bg-blue"><i class="fa fa-download"></i></span> | |||
<div class="info-box-content"> | |||
<a href="#" class="btn btn-default">Télécharger (PDF)</a> | |||
</div> | |||
</div> | |||
<div id="" class="info-box"> | |||
<span class="info-box-icon bg-red"><i class="fa fa-flash"></i></span> | |||
<div class="info-box-content"> | |||
<a href="#" class="btn btn-default">Action 1</a> | |||
<a href="#" class="btn btn-default">Action 2</a> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="clr"></div> | |||
<div class=""> | |||
<div class="panel panel-default" id="block-add-product"> | |||
<div class="panel-heading"> | |||
Ajouter un produit | |||
</div> | |||
<div class="panel-body"> | |||
<div class="col-md-5"> | |||
<select class="form-control" v-model="productAddId" | |||
@change="changeProductAdd"> | |||
<option value="0" selected="selected">--</option> | |||
<option v-for="product in productsArray" :value="product.id"> | |||
{{ product.name }} | |||
</option> | |||
</select> | |||
</div> | |||
<template v-if="productAddId > 0"> | |||
<div class="col-md-2"> | |||
<div class="input-group"> | |||
<input type="text" class="form-control input-price" | |||
v-model="productAddPrice"/> | |||
<span class="input-group-addon"><span | |||
class="glyphicon glyphicon-euro"></span></span> | |||
</div> | |||
</div> | |||
<div class="col-md-3"> | |||
<div class="input-group input-group-quantity"> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default" type="button" | |||
@click="changeQuantityProductAdd(-1)">-</button> | |||
</span> | |||
<input type="text" class="form-control input-quantity" | |||
v-model="productAddQuantity"/> | |||
<span class="input-group-addon">{{ productsArray[productAddId].wording_unit }}</span> | |||
<span class="input-group-btn"> | |||
<button class="btn btn-default" | |||
type="button" | |||
@click="changeQuantityProductAdd(1)">+</button> | |||
</span> | |||
</div> | |||
</div> | |||
<div class="col-md-2"> | |||
<button class="btn btn-primary" value="Ajouter" | |||
@click="submitProductAdd">Ajouter | |||
</button> | |||
</div> | |||
</template> | |||
<div class="clr"></div> | |||
</div> | |||
</div> | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Produits | |||
</div> | |||
<div class="panel-body"> | |||
<div id="block-list-products"> | |||
<table class="table table-bordered"> | |||
<thead> | |||
<tr> | |||
<td>Nom</td> | |||
<td>Prix (unité)</td> | |||
<td>Quantité</td> | |||
<td>Total</td> | |||
<td>Supprimer</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<template v-for="order in ordersArray"> | |||
<tr v-for="productOrder in order.productOrder"> | |||
<td>{{ | |||
productsArray[productOrder.id_product].name | |||
}} | |||
</td> | |||
<td>{{ formatPrice(productOrder.price) }}</td> | |||
<td>{{ productOrder.quantity }}</td> | |||
<td>{{ formatPrice(productOrder.quantity * | |||
productOrder.price) }} | |||
</td> | |||
<td><a class="btn btn-default"><span | |||
class="glyphicon glyphicon-trash"></span></a> | |||
</td> | |||
</tr> | |||
</template> | |||
<tr> | |||
<td colspan="3"><strong>Total</strong></td> | |||
<td><strong>{{ formatPrice(total) }}</strong></td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<?php endif; ?> | |||
</div> |
@@ -2265,3 +2265,20 @@ termes. | |||
.report-index #report .section .comma:last-child { | |||
display: none; | |||
} | |||
/* line 4, ../sass/document/_form.scss */ | |||
.document-form .info-box .info-box-text { | |||
font-size: 13px; | |||
} | |||
/* line 7, ../sass/document/_form.scss */ | |||
.document-form .info-box .info-box-number { | |||
font-size: 15px; | |||
} | |||
/* line 12, ../sass/document/_form.scss */ | |||
.document-form #block-add-product .input-price { | |||
text-align: center; | |||
} | |||
/* line 16, ../sass/document/_form.scss */ | |||
.document-form #block-add-product .input-group-quantity .input-quantity { | |||
text-align: center; | |||
} |
@@ -38,18 +38,27 @@ termes. | |||
var app = new Vue({ | |||
el: '#app-document-form', | |||
data: { | |||
document: [], | |||
idDocument: 0, | |||
typeDocument: '', | |||
idUser: '', | |||
address : '' | |||
idUser: '', | |||
productsArray: [], | |||
productAddId: 0, | |||
productAddPrice: '', | |||
productAddQuantity: 1, | |||
ordersArray: [], | |||
total: 0 | |||
}, | |||
mounted: function() { | |||
this.init() ; | |||
}, | |||
methods: { | |||
formatPrice: formatPrice, | |||
init: function() { | |||
var idDocument = $('#app-document-form').attr('data-id-document') ; | |||
this.idDocument = idDocument ; | |||
var classDocument = $('#app-document-form').attr('data-class-document') ; | |||
this.classDocument = classDocument ; | |||
if(idDocument) { | |||
var app = this ; | |||
@@ -59,8 +68,11 @@ var app = new Vue({ | |||
}}) | |||
.then(function(response) { | |||
if(response.data.return == 'success') { | |||
app.address = response.data.address ; | |||
app.document = response.data.document ; | |||
app.idUser = response.data.idUser ; | |||
app.productsArray = response.data.products ; | |||
app.ordersArray = response.data.orders ; | |||
app.total = response.data.total ; | |||
} | |||
}) ; | |||
} | |||
@@ -78,6 +90,39 @@ var app = new Vue({ | |||
app.address = '' ; | |||
} | |||
}) ; | |||
}, | |||
formatPrice: formatPrice, | |||
getStepProductAdd: function() { | |||
return parseInt(this.productsArray[this.productAddId].step) ; | |||
}, | |||
changeProductAdd: function(event) { | |||
var idProduct = event.currentTarget.value ; | |||
this.productAddId = idProduct ; | |||
this.productAddPrice = parseFloat(this.productsArray[idProduct].price).toFixed(2) ; | |||
this.productAddQuantity = this.getStepProductAdd() ; | |||
}, | |||
changeQuantityProductAdd: function(quantity) { | |||
var step = this.getStepProductAdd() ; | |||
quantity = quantity * step ; | |||
this.productAddQuantity += quantity ; | |||
if(this.productAddQuantity < 1) { | |||
this.productAddQuantity = step ; | |||
} | |||
}, | |||
submitProductAdd: function() { | |||
var app = this ; | |||
axios.get(UrlManager.getBaseUrlAbsolute()+"document/ajax-add-product",{params: { | |||
idDocument: app.idDocument, | |||
classDocument: app.classDocument, | |||
idProduct: app.productAddId, | |||
quantity: app.productAddQuantity, | |||
price: app.productAddPrice, | |||
}}) | |||
.then(function(response) { | |||
app.productAddId = 0 ; | |||
app.init() ; | |||
alert('Produit ajouté') ; | |||
}) ; | |||
} | |||
} | |||
}); |
@@ -0,0 +1,21 @@ | |||
.document-form { | |||
.info-box { | |||
.info-box-text { | |||
font-size: 13px ; | |||
} | |||
.info-box-number { | |||
font-size: 15px ; | |||
} | |||
} | |||
#block-add-product { | |||
.input-price { | |||
text-align: center ; | |||
} | |||
.input-group-quantity { | |||
.input-quantity { | |||
text-align: center ; | |||
} | |||
} | |||
} | |||
} |
@@ -1480,4 +1480,5 @@ a.btn, button.btn { | |||
@import "user/_form.scss" ; | |||
@import "producer/_update.scss" ; | |||
@import "point_sale/_index.scss" ; | |||
@import "report/_index.scss" ; | |||
@import "report/_index.scss" ; | |||
@import "document/_form.scss" ; |
@@ -142,6 +142,11 @@ class Document extends ActiveRecordCommon | |||
return str_replace('common\models\\','',get_class($this)) ; | |||
} | |||
public function isValidClass($typeDocument) | |||
{ | |||
return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']) ; | |||
} | |||
public function generateReference() | |||
{ | |||
$class = $this->getClass() ; | |||
@@ -174,9 +179,4 @@ class Document extends ActiveRecordCommon | |||
} | |||
} | |||
} | |||
public function isValidClass($typeDocument) | |||
{ | |||
return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']) ; | |||
} | |||
} |
@@ -92,8 +92,8 @@ class Order extends ActiveRecordCommon | |||
public function rules() | |||
{ | |||
return [ | |||
[['id_user', 'date', 'id_point_sale', 'id_distribution'], 'required', 'message' => ''], | |||
[['id_user', 'id_point_sale', 'id_distribution', 'id_subscription', 'id_order_status', 'id_invoice', 'id_quotation', 'id_delivery_note'], 'integer'], | |||
[['id_user', 'date'], 'required', 'message' => ''], | |||
[['id_user', 'id_point_sale', 'id_distribution', 'id_subscription', 'id_invoice', 'id_quotation', 'id_delivery_note'], 'integer'], | |||
[['auto_payment', 'tiller_synchronization'], 'boolean'], | |||
[['date', 'date_update', 'comment', 'comment_point_sale', 'mean_payment'], 'safe'] | |||
]; | |||
@@ -112,7 +112,6 @@ class Order extends ActiveRecordCommon | |||
'id_point_sale' => 'Point de vente', | |||
'id_distribution' => 'Date de distribution', | |||
'id_subscription' => 'Abonnement', | |||
'id_order_status' => 'Statut', | |||
'id_invoice' => 'Facture', | |||
'id_quotation' => 'Devis', | |||
'id_delivery_note' => 'Bon de livraison' |
@@ -0,0 +1,20 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema; | |||
class m200109_070952_module_devis_bl_factures_champs_order_valeur_default extends Migration | |||
{ | |||
public function safeUp() | |||
{ | |||
$this->alterColumn('order', 'id_point_sale', Schema::TYPE_INTEGER.' DEFAULT NULL') ; | |||
$this->alterColumn('order', 'id_distribution', Schema::TYPE_INTEGER.' DEFAULT NULL') ; | |||
} | |||
public function safeDown() | |||
{ | |||
$this->alterColumn('order', 'id_point_sale', Schema::TYPE_INTEGER) ; | |||
$this->alterColumn('order', 'id_distribution', Schema::TYPE_INTEGER) ; | |||
} | |||
} |