Browse Source

[Administration] Factures > édition : gestion des modification de prix facturés

feature/souke
Guillaume Bourgeois 10 months ago
parent
commit
1e0eec7aed
8 changed files with 168 additions and 72 deletions
  1. +15
    -2
      backend/controllers/DocumentController.php
  2. +27
    -12
      backend/views/document/_form.php
  3. +21
    -7
      backend/web/css/screen.css
  4. +27
    -1
      backend/web/js/vuejs/document-form.js
  5. +62
    -40
      backend/web/sass/document/_form.scss
  6. +7
    -6
      common/helpers/Ajax.php
  7. +8
    -3
      common/logic/Order/ProductOrder/Service/ProductOrderBuilder.php
  8. +1
    -1
      common/logic/Order/ProductOrder/Service/ProductOrderSolver.php

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

@@ -591,6 +591,7 @@ class DocumentController extends BackendController

foreach ($order->productOrder as $productOrder) {
$productsOrderArray[$productOrder->id] = array_merge($productOrder->getAttributes(), [
'url_product' => $this->getUrlManagerBackend()->createUrl(['product/update', 'id' => $productOrder->id_product]),
'url_order' => $this->getUrlManagerBackend()->createUrl(['distribution/index', 'idOrderUpdate' => $productOrder->id_order])
]);
}
@@ -701,12 +702,10 @@ class DocumentController extends BackendController
public function actionAjaxDeleteProductOrder($idProductOrder)
{
$productOrderModule = $this->getProductOrderModule();

$productOrder = $productOrderModule->findOneProductOrderById($idProductOrder);

if ($productOrder) {
$productOrderModule->delete($productOrder);

return Ajax::responseSuccess('Produit supprimé');
}

@@ -771,6 +770,20 @@ class DocumentController extends BackendController
}
}

public function actionAjaxUpdateProductOrderInvoicePrice($idProductOrder, $invoicePrice)
{
$productOrderModule = $this->getProductOrderModule();
$productOrder = $productOrderModule->getRepository()->findOneProductOrderById((int) $idProductOrder);
if($productOrder) {
$productOrderModule->getBuilder()->updateProductOrderInvoicePriceByValue($productOrder, (float) $invoicePrice);
return Ajax::responseSuccess("Prix mis à jour", [
'invoice_price' => $productOrder->invoice_price
]);
}

return Ajax::responseError("Une erreur est survenue.");
}

public function getClass()
{
$class = get_class($this);

+ 27
- 12
backend/views/document/_form.php View File

@@ -212,12 +212,6 @@ $documentClass = $documentModule->getClass($model);
class="btn btn-sm btn-default"><span class="glyphicon glyphicon-download-alt"></span> Télécharger
(PDF)</a>

<?php if ($documentModule->isStatusValid($model)): ?>
<a href="<?= Yii::$app->urlManager->createUrl([Yii::$app->controller->getControllerUrl() . '/regenerate', 'id' => $model->id]) ?>"
class="btn btn-sm btn-default"><span class="glyphicon glyphicon-repeat"></span> Regénérer
(PDF)</a>
<?php endif; ?>

<?php if ($documentClass == 'Invoice' && $producerModule->getConfig('option_export_evoliz')): ?>
<a href="<?= Yii::$app->urlManager->createUrl([Yii::$app->controller->getControllerUrl() . '/export-csv-evoliz', 'id' => $model->id]) ?>"
class="btn btn-sm btn-default"><span class="glyphicon glyphicon-save-file"></span> Export Evoliz
@@ -233,6 +227,12 @@ $documentClass = $documentModule->getClass($model);
href="<?= Yii::$app->urlManager->createUrl([Yii::$app->controller->getControllerUrl() . '/validate', 'id' => $model->id, 'backUpdateForm' => 1]) ?>"
class="btn btn-sm btn-default"><span class="glyphicon glyphicon-ok"></span> Valider le document</a>

<?php if ($documentModule->isStatusValid($model)): ?>
<a href="<?= Yii::$app->urlManager->createUrl([Yii::$app->controller->getControllerUrl() . '/regenerate', 'id' => $model->id]) ?>"
class="btn btn-sm btn-default"><span class="glyphicon glyphicon-repeat"></span> Regénérer
(PDF)</a>
<?php endif; ?>

<?php if (isset($model->user) && strlen($model->user->email) > 0): ?>
<a v-if="!document.is_sent"
href="<?= Yii::$app->urlManager->createUrl([Yii::$app->controller->getControllerUrl() . '/send', 'id' => $model->id, 'backUpdateForm' => 1]) ?>"
@@ -378,22 +378,37 @@ $documentClass = $documentModule->getClass($model);
<template v-for="order in ordersArray">
<tr v-for="productOrder in order.productOrder">
<td class="col-md-4">
<div class="product-name">{{ getProductById(productOrder.id_product).name }}
<div class="product-name">
<a :href="productOrder.url_product" target="_blank">
{{ getProductById(productOrder.id_product).name }}
</a>
</div>
<ul class="product-order-meta">
<li v-if="order.distribution_date">Commande : <a class="btn btn-sm btn-default"
:href="productOrder.url_order">{{
<li v-if="order.distribution_date">Commande : <a :href="productOrder.url_order">{{
order.distribution_date }}</a></li>
<li>Utilisateur : {{ order.username }}</li>
<li v-if="order.point_sale_name">Point de vente : {{ order.point_sale_name }}</li>
</ul>
</td>
<td class="col-md-2">
{{ formatPrice(getProductOrderPrice(productOrder)) }}
<template v-if="document.status == 'draft'">
<div class="input-group input-group-edit-invoice-price">
<input type="text" class="form-control" :id="'input-product-order-invoice-price-'+productOrder.id" :value="getProductOrderPrice(productOrder)" :data-id-product-order="productOrder.id" @keyup="showProductOrderInvoicePriceButtonApply" />
<span class="input-group-addon">€</span>
</div>
<div class="product-order-invoice-price-button-apply" :id="'product-order-invoice-price-button-apply-'+productOrder.id">
<button class="btn btn-success" type="button" :data-id-product-order="productOrder.id" @click="updateProductOrderInvoicePrice">
<span class="glyphicon glyphicon-ok"></span>
</button>
</div>
</template>
<template v-else>
{{ formatPrice(getProductOrderPrice(productOrder)) }}
</template>
<template
v-if="document.status == 'draft' && getProductOrderPrice(productOrder) != getBestProductPrice(productOrder.id_product, productOrder.quantity)">
<i class="fa fa-exclamation-triangle"
title="Prix différent de celui défini au niveau du produit"></i>
<i class="different-price fa fa-exclamation-triangle"
:title="'Prix différent de celui défini au niveau du produit ('+getBestProductPrice(productOrder.id_product, productOrder.quantity)+' €)'"></i>
</template>
</td>
<td class="col-md-2">{{ productOrder.quantity }}</td>

+ 21
- 7
backend/web/css/screen.css View File

@@ -2827,37 +2827,51 @@ termes.
.document-form .info-box .info-box-text {
font-size: 13px;
}
/* line 7, ../sass/document/_form.scss */
/* line 8, ../sass/document/_form.scss */
.document-form .info-box .info-box-number {
font-size: 15px;
}
/* line 12, ../sass/document/_form.scss */
/* line 14, ../sass/document/_form.scss */
.document-form #block-add-product .input-price {
text-align: center;
}
/* line 16, ../sass/document/_form.scss */
/* line 19, ../sass/document/_form.scss */
.document-form #block-add-product .input-group-quantity .input-quantity {
text-align: center;
}
/* line 22, ../sass/document/_form.scss */
/* line 25, ../sass/document/_form.scss */
.document-form #block-add-product .total .input-group {
margin-bottom: 10px;
}
/* line 25, ../sass/document/_form.scss */
/* line 29, ../sass/document/_form.scss */
.document-form #block-add-product .total .btn {
float: right;
}
/* line 32, ../sass/document/_form.scss */
/* line 36, ../sass/document/_form.scss */
.document-form #block-list-products ul.product-order-meta {
padding: 0px;
margin: 0px;
padding-left: 20px;
}
/* line 37, ../sass/document/_form.scss */
/* line 41, ../sass/document/_form.scss */
.document-form #block-list-products ul.product-order-meta li {
color: gray;
font-size: 11px;
}
/* line 51, ../sass/document/_form.scss */
.document-form #block-list-products .product-order-invoice-price-button-apply {
display: none;
}
/* line 54, ../sass/document/_form.scss */
.document-form #block-list-products .product-order-invoice-price-button-apply .btn {
display: block;
width: 100%;
}
/* line 60, ../sass/document/_form.scss */
.document-form #block-list-products .different-price {
position: relative;
top: 5px;
}

/* line 7, ../sass/document/_index.scss */
.quotation-index .content-wrapper .content table.table .column-actions,

+ 27
- 1
backend/web/js/vuejs/document-form.js View File

@@ -122,7 +122,7 @@ var app = new Vue({
var price = 0;
if (documentClass == 'DeliveryNote' || documentClass == 'Invoice') {
price = productOrder.invoice_price;
if (!price) {
if (isNaN(price) || price === null) {
price = productOrder.price;
}
} else {
@@ -327,6 +327,32 @@ var app = new Vue({
if (isNaN(this.productAddQuantity)) {
this.productAddQuantity = 1;
}
},
showProductOrderInvoicePriceButtonApply: function(event) {
if(event.key == 'Enter') {
this.updateProductOrderInvoicePrice(event);
}
else {
var idProductOrder = event.currentTarget.getAttribute('data-id-product-order');
$('#product-order-invoice-price-button-apply-'+idProductOrder).show();
}
},
updateProductOrderInvoicePrice: function (event) {
var idProductOrder = event.currentTarget.getAttribute('data-id-product-order');
var invoicePrice = $('#input-product-order-invoice-price-'+idProductOrder).val();

axios.get(UrlManager.getBaseUrlAbsolute() + "document/ajax-update-product-order-invoice-price", {
params: {
idProductOrder: idProductOrder,
invoicePrice: invoicePrice
}
})
.then(function (response) {
appAlerts.alertResponse(response);
$('#input-product-order-invoice-price-'+idProductOrder).val(response.data.datas.invoice_price);
$('#product-order-invoice-price-button-apply-'+idProductOrder).hide();
app.init();
});
}
}
});

+ 62
- 40
backend/web/sass/document/_form.scss View File

@@ -1,43 +1,65 @@

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

.total {
.input-group {
margin-bottom: 10px ;
}
.btn {
float: right ;
}
}
}

#block-list-products {
ul.product-order-meta {
padding: 0px ;
margin: 0px ;
padding-left: 20px ;

li {
color: gray ;
font-size: 11px ;
}
}
}
.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;
}
}

.total {
.input-group {
margin-bottom: 10px;
}

.btn {
float: right;
}
}
}

#block-list-products {
ul.product-order-meta {
padding: 0px;
margin: 0px;
padding-left: 20px;

li {
color: gray;
font-size: 11px;
}
}

.input-group-edit-invoice-price {

}

.product-order-invoice-price-button-apply {
display: none;

.btn {
display: block;
width: 100%;
}
}

.different-price {
position: relative;
top: 5px;
}
}
}

+ 7
- 6
common/helpers/Ajax.php View File

@@ -7,17 +7,17 @@ class Ajax
const RESPONSE_TYPE_ERROR = 'error';
const RESPONSE_TYPE_SUCCESS = 'success';

public static function responseSuccess(string $message): array
public static function responseSuccess(string $message, array $datas = []): array
{
return self::response(self::RESPONSE_TYPE_SUCCESS, $message);
return self::response(self::RESPONSE_TYPE_SUCCESS, $message, $datas);
}

public static function responseError(string $message): array
public static function responseError(string $message, array $datas = []): array
{
return self::response(self::RESPONSE_TYPE_ERROR, $message);
return self::response(self::RESPONSE_TYPE_ERROR, $message, $datas);
}

private static function response(string $responseType, string $message): array
private static function response(string $responseType, string $message, array $datas = []): array
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

@@ -26,7 +26,8 @@ class Ajax
'alert' => [
'type' => self::getAlertClass($responseType),
'message' => $message
]
],
'datas' => $datas
];
}


+ 8
- 3
common/logic/Order/ProductOrder/Service/ProductOrderBuilder.php View File

@@ -58,21 +58,26 @@ class ProductOrderBuilder extends AbstractBuilder
'quantity' => $quantity
]);

$this->saveUpdate($productOrder);
$this->update($productOrder);

return $productOrder;
}

public function updateProductOrderInvoicePrice(ProductOrder $productOrder, array $params = []): void
{

$productOrder->invoice_price = $this->productSolver->getPrice($productOrder->product, [
'user' => (isset($params['user']) && $params['user']) ? $params['user'] : null,
'user_producer' => (isset($params['user_producer']) && $params['user_producer']) ? $params['user_producer'] : null,
'point_sale' => (isset($params['point_sale']) && $params['point_sale']) ? $params['point_sale'] : null,
'quantity' => $productOrder->quantity
]);
$this->saveUpdate($productOrder);
$this->update($productOrder);
}

public function updateProductOrderInvoicePriceByValue(ProductOrder $productOrder, float $invoicePrice)
{
$productOrder->invoice_price = $invoicePrice;
$this->update($productOrder);
}

public function deleteProductOrdersByOrder(Order $order): void

+ 1
- 1
common/logic/Order/ProductOrder/Service/ProductOrderSolver.php View File

@@ -63,7 +63,7 @@ class ProductOrderSolver extends AbstractService implements SolverInterface

public function getPriceByTypeTotal(ProductOrder $productOrder, string $typeTotal = Order::AMOUNT_TOTAL)
{
if ($typeTotal == Order::INVOICE_AMOUNT_TOTAL && $productOrder->invoice_price) {
if ($typeTotal == Order::INVOICE_AMOUNT_TOTAL && $productOrder->invoice_price !== null) {
return $productOrder->invoice_price;
}


Loading…
Cancel
Save