Browse Source

[backend] Rapports : génération du rapport

dev
Guillaume Bourgeois 5 years ago
parent
commit
8553f472cd
7 changed files with 466 additions and 336 deletions
  1. +59
    -0
      backend/controllers/ReportController.php
  2. +28
    -5
      backend/views/report/index.php
  3. +258
    -255
      backend/web/css/screen.css
  4. +46
    -2
      backend/web/js/vuejs/report-index.js
  5. +0
    -73
      backend/web/sass/distribution/_index.scss
  6. +1
    -1
      backend/web/sass/report/_index.scss
  7. +74
    -0
      backend/web/sass/screen.scss

+ 59
- 0
backend/controllers/ReportController.php View File



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

+ 28
- 5
backend/views/report/index.php View File

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

+ 258
- 255
backend/web/css/screen.css
File diff suppressed because it is too large
View File


+ 46
- 2
backend/web/js/vuejs/report-index.js View File

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



+ 0
- 73
backend/web/sass/distribution/_index.scss View File

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

} }



+ 1
- 1
backend/web/sass/report/_index.scss View File

} }
#report { #report {
margin-top: 43px ;
.section { .section {
margin-bottom: 15px ; margin-bottom: 15px ;

+ 74
- 0
backend/web/sass/screen.scss View File

} }
} }


/* 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 {

Loading…
Cancel
Save