@@ -45,6 +45,7 @@ use common\models\Distribution ; | |||
class ReportController extends BackendController | |||
{ | |||
var $enableCsrfValidation = false; | |||
public function behaviors() | |||
{ | |||
@@ -120,4 +121,62 @@ class ReportController extends BackendController | |||
] ; | |||
} | |||
public function actionAjaxReport() | |||
{ | |||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||
$posts = Yii::$app->request->post(); | |||
$resArray = [] ; | |||
$conditionUsers = $this->_generateConditionSqlReport($posts, 'users', 'id_user') ; | |||
$conditionPointsSale = $this->_generateConditionSqlReport($posts, 'pointsSale', 'id_point_sale') ; | |||
$conditionDistributions = $this->_generateConditionSqlReport($posts, 'distributions', 'id_distribution') ; | |||
$res = Yii::$app->db->createCommand("SELECT product.name, SUM(product_order.quantity) AS quantity, SUM(product_order.price * product_order.quantity) AS total | |||
FROM `order`, product_order, product | |||
WHERE `order`.id = product_order.id_order | |||
AND product_order.id_product = product.id | |||
".$conditionUsers." | |||
".$conditionPointsSale." | |||
".$conditionDistributions." | |||
GROUP BY product.id | |||
ORDER BY product.name ASC | |||
") | |||
->queryAll(); | |||
$totalGlobal = 0 ; | |||
foreach($res as $line) { | |||
$total = Price::format(round($line['total'], 2)) ; | |||
if($line['quantity'] > 0) { | |||
$resArray[] = [ | |||
'name' => $line['name'], | |||
'quantity' => $line['quantity'], | |||
'total' => $total, | |||
] ; | |||
$totalGlobal += $total ; | |||
} | |||
} | |||
$resArray[] = [ | |||
'name' => '', | |||
'quantity' => '', | |||
'total' => '<strong>'.Price::format(round($totalGlobal, 2)).'</strong>', | |||
] ; | |||
return $resArray ; | |||
} | |||
public function _generateConditionSqlReport($posts, $name, $fieldOrder) | |||
{ | |||
$condition = '' ; | |||
if(isset($posts[$name]) && strlen($posts[$name])) { | |||
$idsArray = explode(',', $posts[$name]) ; | |||
for($i = 0; $i < count($idsArray); $i++) { | |||
$idsArray[$i] = (int) $idsArray[$i] ; | |||
} | |||
$condition = 'AND `order`.'.$fieldOrder.' IN ('.implode(',',$idsArray).') ' ; | |||
} | |||
return $condition ; | |||
} | |||
} |
@@ -46,7 +46,7 @@ $this->addBreadcrumb('Rapports') ; | |||
<div id="loading" v-if="showLoading"> | |||
<img src="<?= Yii::$app->urlManagerBackend->getBaseUrl(); ?>/img/loader.gif" alt="Chargement ..." /> | |||
</div> | |||
<div id="wrapper-app-report-index" :class="'wrapper-app-vuejs '+(showLoading ? '' : 'loaded')"> | |||
<div id="wrapper-app-report-index" :class="'wrapper-app-vuejs '+(loading ? '' : 'loaded')"> | |||
<div id="parameters" class="col-md-6"> | |||
<div id="nav-sections-report"> | |||
<a v-for="section in sections" :class="'btn-section btn '+(currentSection == section.id ? 'btn-primary' : 'btn-default')" @click="changeSection(section)"><span :class="'fa '+section.icon"></span> {{ section.name }}<span v-if="currentSection == section.id"> <span class="glyphicon glyphicon-triangle-bottom"></span></span></a> | |||
@@ -60,7 +60,7 @@ $this->addBreadcrumb('Rapports') ; | |||
<div class="content-max-height"> | |||
<ul id="list-users"> | |||
<li v-for="user in usersArray" v-if="!termSearchUser.length || (termSearchUser.length && (user.lastname.toLowerCase().indexOf(termSearchUser.toLowerCase()) != -1 || user.name.toLowerCase().indexOf(termSearchUser.toLowerCase()) != -1 ))"> | |||
<input type="checkbox" :id="'user_'+user.user_id" v-model="user.checked" /> | |||
<input type="checkbox" :id="'user_'+user.user_id" v-model="user.checked" @change="reportChange" /> | |||
<label :for="'user_'+user.user_id" v-html="user.lastname+' '+user.name"></label> | |||
</li> | |||
</ul> | |||
@@ -72,7 +72,7 @@ $this->addBreadcrumb('Rapports') ; | |||
<div class="content-max-height"> | |||
<ul class="list" id="list-points-sale"> | |||
<li v-for="pointSale in pointsSaleArray"> | |||
<input type="checkbox" :id="'pointsale_'+pointSale.id" v-model="pointSale.checked" /> | |||
<input type="checkbox" :id="'pointsale_'+pointSale.id" v-model="pointSale.checked" @change="reportChange" /> | |||
<label :for="'pointsale_'+pointSale.id" v-html="pointSale.name"></label> | |||
</li> | |||
</ul> | |||
@@ -91,7 +91,7 @@ $this->addBreadcrumb('Rapports') ; | |||
<a class="btn btn-default link-month-distribution" @click="distributionsMonth.display = !distributionsMonth.display">{{ distributionsMonth.month }} <span class="glyphicon glyphicon-menu-down"></span></a> | |||
<ul v-if="distributionsMonth.display"> | |||
<li v-for="distribution in distributionsMonth.distributions"> | |||
<input type="checkbox" :id="'distribution_'+distribution.id" v-model="distribution.checked" /> | |||
<input type="checkbox" :id="'distribution_'+distribution.id" v-model="distribution.checked" @change="reportChange" /> | |||
<label :for="'distribution_'+distribution.id">{{ distribution.date }}</label> | |||
</li> | |||
</ul> | |||
@@ -133,10 +133,33 @@ $this->addBreadcrumb('Rapports') ; | |||
</div> | |||
</div> | |||
<div id="report" v-if="countUsers() || countPointsSale() || countDistributions()"> | |||
<a href="#" class="btn btn-primary">Générer</a> | |||
<div class="content-report section" v-if="showReport"> | |||
<h3><span class="fa fa-pencil-square-o"></span> Rapport</h3> | |||
<table class="table table-bordered" v-if="tableReport.length > 1"> | |||
<thead> | |||
<tr> | |||
<th>Produit</th> | |||
<th>Quantité</th> | |||
<th>Total</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr v-for="line in tableReport"> | |||
<td>{{ line.name }}</td> | |||
<td>{{ line.quantity }}</td> | |||
<td v-html="line.total"></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<div class="alert alert-warning" v-else> | |||
Aucune donnée disponible pour ces critères. | |||
</div> | |||
</div> | |||
<a class="btn btn-primary" @click="generateReport()" v-else="!showReport"><span class="fa fa-pencil-square-o"></span> Générer</a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@@ -2,7 +2,10 @@ | |||
var app = new Vue({ | |||
el: '#app-report-index', | |||
data: { | |||
loading: true, | |||
showLoading: true, | |||
showReport: false, | |||
tableReport: [], | |||
currentSection: 'users', | |||
sections: [ | |||
{ | |||
@@ -42,6 +45,7 @@ var app = new Vue({ | |||
app.distributionYear = app.distributionYearsArray[app.distributionYearsArray.length - 1] ; | |||
app.distributionsByMonthArray = response.data.distributionsByMonthArray ; | |||
app.loading = false ; | |||
app.showLoading = false ; | |||
}); | |||
}, | |||
@@ -77,7 +81,47 @@ var app = new Vue({ | |||
} | |||
return count ; | |||
}, | |||
generateReport: function() { | |||
var app = this ; | |||
app.showLoading = true ; | |||
var data = new FormData(); | |||
var idsUsersArray = [] ; | |||
for(var i = 0; i < app.usersArray.length; i++) { | |||
if(app.usersArray[i].checked) { | |||
idsUsersArray.push(app.usersArray[i].user_id) ; | |||
} | |||
} | |||
var idsPointsSaleArray = [] ; | |||
for(var i = 0; i < app.pointsSaleArray.length; i++) { | |||
if(app.pointsSaleArray[i].checked) { | |||
idsPointsSaleArray.push(app.pointsSaleArray[i].id) ; | |||
} | |||
} | |||
var idsDistributionsArray = [] ; | |||
for(var i in this.distributionsByMonthArray) { | |||
for(var j = 0; j < this.distributionsByMonthArray[i].distributions.length; j++) { | |||
if(this.distributionsByMonthArray[i].distributions[j].checked) { | |||
idsDistributionsArray.push(app.distributionsByMonthArray[i].distributions[j].id) ; | |||
} | |||
} | |||
} | |||
data.append('users', idsUsersArray); | |||
data.append('pointsSale', idsPointsSaleArray); | |||
data.append('distributions', idsDistributionsArray); | |||
axios.post("ajax-report",data) | |||
.then(function(response) { | |||
app.tableReport = response.data ; | |||
app.showLoading = false ; | |||
app.showReport = true ; | |||
}); | |||
}, | |||
reportChange: function() { | |||
this.showReport = false; | |||
} | |||
} | |||
}); | |||
@@ -299,78 +299,5 @@ termes. | |||
} | |||
} | |||
.modal-mask { | |||
position: fixed; | |||
z-index: 9998; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
background-color: rgba(0, 0, 0, .5); | |||
display: table; | |||
transition: opacity .3s ease; | |||
} | |||
.modal-wrapper { | |||
display: table-cell; | |||
vertical-align: middle; | |||
} | |||
.modal-container { | |||
width: 70%; | |||
margin: 0px auto; | |||
padding: 20px 30px; | |||
background-color: #fff; | |||
border-radius: 2px; | |||
box-shadow: 0 2px 8px rgba(0, 0, 0, .33); | |||
transition: all .3s ease; | |||
font-family: Helvetica, Arial, sans-serif; | |||
} | |||
.modal-header { | |||
padding-bottom: 0px ; | |||
h3 { | |||
margin-top: 0; | |||
color: #333; | |||
text-transform: uppercase ; | |||
margin-bottom: 0px ; | |||
} | |||
} | |||
.modal-body { | |||
margin: 20px 0; | |||
max-height: 300px ; | |||
height: 300px ; | |||
overflow-y: scroll ; | |||
} | |||
.modal-default-button { | |||
float: right; | |||
} | |||
/* | |||
* The following styles are auto-applied to elements with | |||
* transition="modal" when their visibility is toggled | |||
* by Vue.js. | |||
* | |||
* You can easily play with the modal transition by editing | |||
* these styles. | |||
*/ | |||
.modal-enter { | |||
opacity: 0; | |||
} | |||
.modal-leave-active { | |||
opacity: 0; | |||
} | |||
.modal-enter .modal-container, | |||
.modal-leave-active .modal-container { | |||
-webkit-transform: scale(1.1); | |||
transform: scale(1.1); | |||
} | |||
} | |||
@@ -110,7 +110,7 @@ termes. | |||
} | |||
#report { | |||
margin-top: 43px ; | |||
.section { | |||
margin-bottom: 15px ; | |||
@@ -314,6 +314,80 @@ a.btn, button.btn { | |||
} | |||
} | |||
/* modals */ | |||
.modal-mask { | |||
position: fixed; | |||
z-index: 9998; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
background-color: rgba(0, 0, 0, .5); | |||
display: table; | |||
transition: opacity .3s ease; | |||
} | |||
.modal-wrapper { | |||
display: table-cell; | |||
vertical-align: middle; | |||
} | |||
.modal-container { | |||
width: 70%; | |||
margin: 0px auto; | |||
padding: 20px 30px; | |||
background-color: #fff; | |||
border-radius: 2px; | |||
box-shadow: 0 2px 8px rgba(0, 0, 0, .33); | |||
transition: all .3s ease; | |||
font-family: Helvetica, Arial, sans-serif; | |||
} | |||
.modal-header { | |||
padding-bottom: 0px ; | |||
h3 { | |||
margin-top: 0; | |||
color: #333; | |||
text-transform: uppercase ; | |||
margin-bottom: 0px ; | |||
} | |||
} | |||
.modal-body { | |||
margin: 20px 0; | |||
max-height: 300px ; | |||
height: 300px ; | |||
overflow-y: scroll ; | |||
} | |||
.modal-default-button { | |||
float: right; | |||
} | |||
/* | |||
* The following styles are auto-applied to elements with | |||
* transition="modal" when their visibility is toggled | |||
* by Vue.js. | |||
* | |||
* You can easily play with the modal transition by editing | |||
* these styles. | |||
*/ | |||
.modal-enter { | |||
opacity: 0; | |||
} | |||
.modal-leave-active { | |||
opacity: 0; | |||
} | |||
.modal-enter .modal-container, | |||
.modal-leave-active .modal-container { | |||
-webkit-transform: scale(1.1); | |||
transform: scale(1.1); | |||
} | |||
// liste de commandes | |||
.site-index, .user-commandes { | |||
#last-orders, #history-orders { |