<?php /* * OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione * Copyright (C) DevCode s.r.l. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ include_once __DIR__.'/../../core.php'; use Modules\Statistiche\Stats; echo ' <script src="'.base_path().'/assets/dist/js/chartjs/Chart.min.js"></script>'; $start = $_SESSION['period_start']; $end = $_SESSION['period_end']; echo ' <div class="box box-warning"> <div class="box-header"> <h4 class="box-title"> '.tr('Periodi temporali').' </h4> <div class="box-tools pull-right"> <button class="btn btn-warning btn-xs" onclick="add_calendar()"> <i class="fa fa-plus"></i> '.tr('Aggiungi periodo').' </button> <button type="button" class="btn btn-box-tool" data-widget="collapse"> <i class="fa fa-minus"></i> </button> </div> </div> <div class="box-body collapse in" id="calendars"> </div> </div>'; // Fatturato echo ' <div class="box box-success"> <div class="box-header with-border"> <h3 class="box-title">'.tr('Vendite e acquisti').'</h3> <div class="box-tools pull-right"> <button type="button" class="btn btn-box-tool" data-widget="collapse"> <i class="fa fa-minus"></i> </button> </div> </div> <canvas class="box-body collapse in" id="fatturato" height="100"></canvas> </div>'; echo ' <script src="'.$structure->fileurl('js/functions.js').'"></script> <script src="'.$structure->fileurl('js/calendar.js').'"></script> <script src="'.$structure->fileurl('js/manager.js').'"></script> <script src="'.$structure->fileurl('js/stat.js').'"></script> <script src="'.$structure->fileurl('js/stats/line_chart.js').'"></script>'; // Script per il grafico del fatturato echo ' <script> start = moment("'.$start.'"); end = moment("'.$end.'"); months = get_months(start, end); var chart_options = { type: "line", data: { labels: [], datasets: [], }, options: { responsive: true, tooltips: { callbacks: { label: function(tooltipItem, data) { var dataset = data.datasets[tooltipItem.datasetIndex]; var label = dataset.labels ? dataset.labels[tooltipItem.index] : ""; if (label) { label += ": "; } label += tooltipItem.yLabel; return label; } } }, elements: { line: { tension: 0 } }, annotation: { annotations: [{ type: "line", mode: "horizontal", scaleID: "y-axis-0", value: 0, label: { enabled: false, } }] }, hover: { mode: "nearest", intersect: false }, scales: { xAxes: [{ display: true, scaleLabel: { display: true, labelString: "'.tr('Periodo').'" } }], yAxes: [{ display: true, scaleLabel: { display: true, labelString: "'.tr('Andamento').'" }, ticks: { // Include a dollar sign in the ticks callback: function(value, index, values) { return \''.html_entity_decode(currency()).' \' + value; } } }] }, } }; // Inzializzazione manager var info = { url: "'.str_replace('edit.php', '', $structure->fileurl('edit.php')).'", id_module: globals.id_module, id_record: globals.id_record, start_date: globals.start_date, end_date: globals.end_date, } var manager = new Manager(info); var chart_fatturato, chart_acquisti; $(document).ready(function() { var fatturato_canvas = document.getElementById("fatturato").getContext("2d"); //var acquisti_canvas = document.getElementById("acquisti").getContext("2d"); chart_fatturato = new Chart(fatturato_canvas, chart_options); //chart_acquisti = new Chart(fatturato_canvas, chart_options); add_calendar(); }); function init_calendar(calendar) { var fatturato = new LineChart(calendar, "actions.php", {op: "fatturato"}, chart_fatturato); var acquisti = new LineChart(calendar, "actions.php", {op: "acquisti"}, chart_fatturato); calendar.addElement(fatturato); calendar.addElement(acquisti); } </script>'; // Clienti top $clienti = $dbo->fetchArray('SELECT SUM(IF(reversed=1, -(co_righe_documenti.subtotale - co_righe_documenti.sconto), (co_righe_documenti.subtotale - co_righe_documenti.sconto))) AS totale, (SELECT COUNT(*) FROM co_documenti INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE co_documenti.idanagrafica =an_anagrafiche.idanagrafica AND co_documenti.data BETWEEN '.prepare($start).' AND '.prepare($end)." AND co_tipidocumento.dir='entrata') AS qta, an_anagrafiche.idanagrafica, an_anagrafiche.ragione_sociale FROM co_documenti INNER JOIN co_statidocumento ON co_statidocumento.id = co_documenti.idstatodocumento INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id INNER JOIN co_righe_documenti ON co_righe_documenti.iddocumento=co_documenti.id INNER JOIN an_anagrafiche ON an_anagrafiche.idanagrafica=co_documenti.idanagrafica WHERE co_tipidocumento.dir='entrata' AND (co_statidocumento.descrizione = 'Pagato' OR co_statidocumento.descrizione = 'Parzialmente pagato' OR co_statidocumento.descrizione = 'Emessa' ) AND co_documenti.data BETWEEN ".prepare($start).' AND '.prepare($end).' GROUP BY an_anagrafiche.idanagrafica ORDER BY SUM(subtotale - co_righe_documenti.sconto) DESC LIMIT 20'); $totale = $dbo->fetchArray("SELECT SUM(IF(reversed=1, -(co_righe_documenti.subtotale - co_righe_documenti.sconto), (co_righe_documenti.subtotale - co_righe_documenti.sconto))) AS totale FROM co_documenti INNER JOIN co_statidocumento ON co_statidocumento.id = co_documenti.idstatodocumento INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id INNER JOIN co_righe_documenti ON co_righe_documenti.iddocumento=co_documenti.id WHERE (co_statidocumento.descrizione = 'Pagato' OR co_statidocumento.descrizione = 'Parzialmente pagato' OR co_statidocumento.descrizione = 'Emessa' ) AND co_tipidocumento.dir='entrata' AND co_documenti.data BETWEEN ".prepare($start).' AND '.prepare($end)); echo ' <div class="row"> <div class="col-md-6"> <div class="box box-warning"> <div class="box-header with-border"> <h3 class="box-title">'.tr('I 20 clienti TOP').'</h3><span class="tip" title="'.tr('Valori iva esclusa').'"> <i class="fa fa-question-circle-o" aria-hidden="true"></i></span> <div class="box-tools pull-right"> <button type="button" class="btn btn-box-tool" data-widget="collapse"> <i class="fa fa-minus"></i> </button> </div> </div> <div class="box-body collapse in">'; if (!empty($clienti)) { echo ' <table class="table table-striped"> <tr> <th>'.tr('Ragione sociale').'</th> <th class="text-center">'.tr('Num. fatture').'</th> <th class="text-right" width="120">'.tr('Totale').'</th> <th class="text-right" width="120">'.tr('Percentuale').'<span class="tip" title="'.tr('Incidenza sul fatturato').'"> <i class="fa fa-question-circle-o" aria-hidden="true"></i></span></th> </tr>'; foreach ($clienti as $cliente) { echo ' <tr> <td>'.Modules::link('Anagrafiche', $cliente['idanagrafica'], $cliente['ragione_sociale']).'</td> <td class="text-right">'.intval($cliente['qta']).'</td> <td class="text-right">'.moneyFormat($cliente['totale'], 2).'</td> <td class="text-right">'.Translator::numberToLocale($cliente['totale'] * 100 / $totale[0]['totale'], 2).' %</td> </tr>'; } echo ' </table>'; } else { echo ' <p>'.tr('Nessuna vendita').'...</p>'; } echo ' </div> </div> </div>'; // Articoli più venduti $articoli = $dbo->fetchArray("SELECT SUM(IF(reversed=1, -co_righe_documenti.qta, co_righe_documenti.qta)) AS qta, SUM(IF(reversed=1, -(co_righe_documenti.subtotale - co_righe_documenti.sconto), (co_righe_documenti.subtotale - co_righe_documenti.sconto))) AS totale, mg_articoli.id, mg_articoli.codice, mg_articoli.descrizione, mg_articoli.um FROM co_documenti INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id INNER JOIN co_righe_documenti ON co_righe_documenti.iddocumento=co_documenti.id INNER JOIN mg_articoli ON mg_articoli.id=co_righe_documenti.idarticolo WHERE co_tipidocumento.dir='entrata' AND co_documenti.data BETWEEN ".prepare($start).' AND '.prepare($end).' GROUP BY co_righe_documenti.idarticolo ORDER BY SUM(co_righe_documenti.qta) DESC LIMIT 20'); $totale = $dbo->fetchArray("SELECT SUM(IF(reversed=1, -co_righe_documenti.qta, co_righe_documenti.qta)) AS totale_qta, SUM(IF(reversed=1, -(co_righe_documenti.subtotale - co_righe_documenti.sconto), (co_righe_documenti.subtotale - co_righe_documenti.sconto))) AS totale FROM co_documenti INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id INNER JOIN co_righe_documenti ON co_righe_documenti.iddocumento=co_documenti.id INNER JOIN mg_articoli ON mg_articoli.id=co_righe_documenti.idarticolo WHERE co_tipidocumento.dir='entrata' AND co_documenti.data BETWEEN ".prepare($start).' AND '.prepare($end)); echo ' <div class="col-md-6"> <div class="box box-danger"> <div class="box-header with-border"> <h3 class="box-title">'.tr('I 20 articoli più venduti').'</h3><span class="tip" title="'.tr('Valori iva esclusa').'"> <i class="fa fa-question-circle-o" aria-hidden="true"></i></span> <div class="box-tools pull-right"> <button type="button" class="btn btn-box-tool" data-widget="collapse"> <i class="fa fa-minus"></i> </button> </div> </div> <div class="box-body collapse in">'; if (!empty($articoli)) { echo ' <table class="table table-striped"> <tr> <th>'.tr('Articolo').'</th> <th class="text-right" width="120">'.tr('Q.tà').'</th> <th class="text-right" width="120">'.tr('Percentuale').'<span class="tip" title="'.tr('Incidenza sul numero di articoli venduti').'"> <i class="fa fa-question-circle-o" aria-hidden="true"></i></span></th> <th class="text-right" width="120">'.tr('Totale').'</th> </tr>'; foreach ($articoli as $articolo) { echo ' <tr> <td>'.Modules::link('Articoli', $articolo['id'], $articolo['codice'].' - '.$articolo['descrizione']).'</td> <td class="text-right">'.Translator::numberToLocale($articolo['qta'], 'qta').' '.$articolo['um'].'</td> <td class="text-right">'.Translator::numberToLocale($articolo['qta'] * 100 / $totale[0]['totale_qta'], 2).' %</td> <td class="text-right">'.moneyFormat($articolo['totale'], 2).'</td> </tr>'; } echo ' </table>'; } else { echo ' <p>'.tr('Nessun articolo è stato venduto').'...</p>'; } echo ' </div> </div> </div> </div>'; // Numero interventi per tipologia $tipi = $dbo->fetchArray('SELECT * FROM `in_tipiintervento`'); $dataset = ''; foreach ($tipi as $tipo) { $interventi = $dbo->fetchArray('SELECT COUNT(*) AS result, YEAR(in_interventi.data_richiesta) AS year, MONTH(in_interventi.data_richiesta) AS month FROM in_interventi WHERE in_interventi.idtipointervento = '.prepare($tipo['idtipointervento']).' AND in_interventi.data_richiesta BETWEEN '.prepare($start).' AND '.prepare($end).' GROUP BY YEAR(in_interventi.data_richiesta), MONTH(in_interventi.data_richiesta) ORDER BY YEAR(in_interventi.data_richiesta) ASC, MONTH(in_interventi.data_richiesta) ASC'); $interventi = Stats::monthly($interventi, $start, $end); //Random color $background = '#'.dechex(rand(256, 16777215)); $dataset .= '{ label: "'.$tipo['descrizione'].'", backgroundColor: "'.$background.'", data: [ '.implode(',', array_column($interventi, 'result')).' ] },'; } echo ' <div class="box box-info"> <div class="box-header with-border"> <h3 class="box-title">'.tr('Numero interventi per tipologia').'</h3> <div class="box-tools pull-right"> <button type="button" class="btn btn-box-tool" data-widget="collapse"> <i class="fa fa-minus"></i> </button> </div> </div> <canvas class="box-body collapse in" id="interventi_n_tipologia" height="100"></canvas> </div>'; // Script per il grafico del numero interventi per tipologia echo ' <script> $(document).ready(function() { new Chart(document.getElementById("interventi_n_tipologia").getContext("2d"), { type: "bar", data: { labels: months, datasets: [ '.$dataset.' ] }, options: { responsive: true, legend: { position: "bottom", }, } }); }); </script>'; // Ore interventi per tipologia $dataset = ''; foreach ($tipi as $tipo) { $interventi = $dbo->fetchArray('SELECT ROUND( SUM(in_interventi_tecnici.ore), 2 ) AS result, YEAR(in_interventi.data_richiesta) AS year, MONTH(in_interventi.data_richiesta) AS month FROM in_interventi INNER JOIN in_interventi_tecnici ON in_interventi.id=in_interventi_tecnici.idintervento WHERE in_interventi.idtipointervento = '.prepare($tipo['idtipointervento']).' AND in_interventi.data_richiesta BETWEEN '.prepare($start).' AND '.prepare($end).' GROUP BY YEAR(in_interventi.data_richiesta), MONTH(in_interventi.data_richiesta) ORDER BY YEAR(in_interventi.data_richiesta) ASC, MONTH(in_interventi.data_richiesta) ASC'); $interventi = Stats::monthly($interventi, $start, $end); //Random color $background = '#'.dechex(rand(256, 16777215)); $dataset .= '{ label: "'.$tipo['descrizione'].'", backgroundColor: "'.$background.'", data: [ '.implode(',', array_column($interventi, 'result')).' ] },'; } echo ' <div class="box box-info"> <div class="box-header with-border"> <h3 class="box-title">'.tr('Ore interventi per tipologia').'</h3> <div class="box-tools pull-right"> <button type="button" class="btn btn-box-tool" data-widget="collapse"> <i class="fa fa-minus"></i> </button> </div> </div> <canvas class="box-body collapse in" id="interventi_ore_tipologia" height="100"></canvas> </div>'; // Script per il grafico delle ore interventi per tipologia echo ' <script> $(document).ready(function() { new Chart(document.getElementById("interventi_ore_tipologia").getContext("2d"), { type: "bar", data: { labels: months, datasets: [ '.$dataset.' ] }, options: { responsive: true, legend: { position: "bottom", }, } }); }); </script>'; // Interventi per tecnico $tecnici = $dbo->fetchArray("SELECT an_anagrafiche.idanagrafica AS id, ragione_sociale, colore FROM an_anagrafiche INNER JOIN an_tipianagrafiche_anagrafiche ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica LEFT OUTER JOIN in_interventi_tecnici ON in_interventi_tecnici.idtecnico = an_anagrafiche.idanagrafica INNER JOIN in_interventi ON in_interventi_tecnici.idintervento=in_interventi.id WHERE an_anagrafiche.deleted_at IS NULL AND an_tipianagrafiche.descrizione='Tecnico' GROUP BY an_anagrafiche.idanagrafica ORDER BY ragione_sociale ASC"); $dataset = ''; foreach ($tecnici as $tecnico) { $sessioni = $dbo->fetchArray('SELECT SUM(in_interventi_tecnici.ore) AS result, CONCAT(CAST(SUM(in_interventi_tecnici.ore) AS char(20)),\' ore\') AS ore_lavorate, YEAR(in_interventi_tecnici.orario_inizio) AS year, MONTH(in_interventi_tecnici.orario_inizio) AS month FROM in_interventi_tecnici INNER JOIN `in_interventi` ON `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id` LEFT JOIN `in_statiintervento` ON `in_interventi`.`idstatointervento`=`in_statiintervento`.`idstatointervento` WHERE in_interventi_tecnici.idtecnico = '.prepare($tecnico['id']).' AND in_interventi_tecnici.orario_inizio BETWEEN '.prepare($start).' AND '.prepare($end).' AND `in_statiintervento`.`is_completato` = 1 GROUP BY YEAR(in_interventi_tecnici.orario_inizio), MONTH(in_interventi_tecnici.orario_inizio) ORDER BY YEAR(in_interventi_tecnici.orario_inizio) ASC, MONTH(in_interventi_tecnici.orario_inizio) ASC'); $sessioni = Stats::monthly($sessioni, $start, $end); //Colore tecnico $background = strtoupper($tecnico['colore']); if (empty($background) || $background == '#FFFFFF') { //Random color $background = '#'.dechex(rand(256, 16777215)); } $dataset .= '{ label: "'.$tecnico['ragione_sociale'].'", backgroundColor: "'.$background.'", data: [ '.implode(',', array_column($sessioni, 'result')).' ], },'; } echo ' <div class="box box-info"> <div class="box-header with-border"> <h3 class="box-title">'.tr('Ore di lavoro per tecnico').'</h3> <div class="box-tools pull-right"> <button type="button" class="btn btn-box-tool" data-widget="collapse"> <i class="fa fa-minus"></i> </button> </div> </div> <canvas class="box-body collapse in" id="sessioni" height="100"></canvas> </div>'; // Script per il grafico ore interventi per tecnico echo ' <script> $(document).ready(function() { new Chart(document.getElementById("sessioni").getContext("2d"), { type: "horizontalBar", data: { labels: months, datasets: [ '.$dataset.' ] }, options: { responsive: true, legend: { position: "bottom", }, scales: { xAxes: [{ ticks: { // Include a dollar sign in the ticks callback: function(value, index, values) { var text = ""; if (value<=1 && value!=0){ text = " ora"; }else{ text = " ore"; } return value + text; } } }] }, tooltips: { callbacks: { label: function(tooltipItem, data) { var dataset = data.datasets[tooltipItem.datasetIndex]; var label = dataset.labels ? dataset.labels[tooltipItem.index] : ""; if (label) { label += ": "; } label += tooltipItem.xLabel; if (tooltipItem.xLabel<=1) { label += " ora "; }else{ label += " ore "; } label += "(in attività completate)"; return label; } } }, } }); }); </script>';