class ReportController extends BackendController | class ReportController extends BackendController | ||||
{ | { | ||||
var $enableCsrfValidation = false; | |||||
public function behaviors() | public function behaviors() | ||||
{ | { | ||||
] ; | ] ; | ||||
} | } | ||||
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 ; | |||||
} | |||||
} | } |
<div id="loading" v-if="showLoading"> | <div id="loading" v-if="showLoading"> | ||||
<img src="<?= Yii::$app->urlManagerBackend->getBaseUrl(); ?>/img/loader.gif" alt="Chargement ..." /> | <img src="<?= Yii::$app->urlManagerBackend->getBaseUrl(); ?>/img/loader.gif" alt="Chargement ..." /> | ||||
</div> | </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="parameters" class="col-md-6"> | ||||
<div id="nav-sections-report"> | <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> | <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> | ||||
<div class="content-max-height"> | <div class="content-max-height"> | ||||
<ul id="list-users"> | <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 ))"> | <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> | <label :for="'user_'+user.user_id" v-html="user.lastname+' '+user.name"></label> | ||||
</li> | </li> | ||||
</ul> | </ul> | ||||
<div class="content-max-height"> | <div class="content-max-height"> | ||||
<ul class="list" id="list-points-sale"> | <ul class="list" id="list-points-sale"> | ||||
<li v-for="pointSale in pointsSaleArray"> | <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> | <label :for="'pointsale_'+pointSale.id" v-html="pointSale.name"></label> | ||||
</li> | </li> | ||||
</ul> | </ul> | ||||
<a class="btn btn-default link-month-distribution" @click="distributionsMonth.display = !distributionsMonth.display">{{ distributionsMonth.month }} <span class="glyphicon glyphicon-menu-down"></span></a> | <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"> | <ul v-if="distributionsMonth.display"> | ||||
<li v-for="distribution in distributionsMonth.distributions"> | <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> | <label :for="'distribution_'+distribution.id">{{ distribution.date }}</label> | ||||
</li> | </li> | ||||
</ul> | </ul> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div id="report" v-if="countUsers() || countPointsSale() || countDistributions()"> | <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> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> |
var app = new Vue({ | var app = new Vue({ | ||||
el: '#app-report-index', | el: '#app-report-index', | ||||
data: { | data: { | ||||
loading: true, | |||||
showLoading: true, | showLoading: true, | ||||
showReport: false, | |||||
tableReport: [], | |||||
currentSection: 'users', | currentSection: 'users', | ||||
sections: [ | sections: [ | ||||
{ | { | ||||
app.distributionYear = app.distributionYearsArray[app.distributionYearsArray.length - 1] ; | app.distributionYear = app.distributionYearsArray[app.distributionYearsArray.length - 1] ; | ||||
app.distributionsByMonthArray = response.data.distributionsByMonthArray ; | app.distributionsByMonthArray = response.data.distributionsByMonthArray ; | ||||
app.loading = false ; | |||||
app.showLoading = false ; | app.showLoading = false ; | ||||
}); | }); | ||||
}, | }, | ||||
} | } | ||||
return count ; | 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; | |||||
} | |||||
} | } | ||||
}); | }); | ||||
} | } | ||||
} | } | ||||
.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); | |||||
} | |||||
} | } | ||||
} | } | ||||
#report { | #report { | ||||
margin-top: 43px ; | |||||
.section { | .section { | ||||
margin-bottom: 15px ; | margin-bottom: 15px ; | ||||
} | } | ||||
} | } | ||||
/* 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 | // liste de commandes | ||||
.site-index, .user-commandes { | .site-index, .user-commandes { | ||||
#last-orders, #history-orders { | #last-orders, #history-orders { |