diff --git a/class/digiriskstats.php b/class/digiriskstats.php new file mode 100644 index 000000000..3a7e8b855 --- /dev/null +++ b/class/digiriskstats.php @@ -0,0 +1,593 @@ + + * + * 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 . + */ + +/** + * \file class/digiriskstats.class.php + * \ingroup digiriskdolibarr + * \brief Common class to manage statistics reports + */ + +/** + * Parent class of statistics class + */ +abstract class DigiriskStats +{ + protected $db; + protected $lastfetchdate = array(); // Dates of cache file read by methods + public $cachefilesuffix = ''; // Suffix to add to name of cache file (to avoid file name conflicts) + + /** + * Return nb of elements by month for several years + * + * @param int $endyear Start year + * @param int $startyear End year + * @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save) + * @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month + * @param int $startmonth month of the fiscal year start min 1 max 12 ; if 1 = january + * @return array Array of values + */ + public function getNbByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1) + { + global $conf, $user, $langs; + + if ($startyear > $endyear) { + return -1; + } + + $datay = array(); + + // Search into cache + if (!empty($cachedelay)) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php'; + } + + $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache'; + $newmask = '0644'; + + $nowgmt = dol_now(); + + $foundintocache = 0; + if ($cachedelay > 0) { + $filedate = dol_filemtime($newpathofdestfile); + if ($filedate >= ($nowgmt - $cachedelay)) { + $foundintocache = 1; + + $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate; + } else { + dol_syslog(get_class($this).'::'.__FUNCTION__." cache file ".$newpathofdestfile." is not found or older than now - cachedelay (".$nowgmt." - ".$cachedelay.") so we can't use it."); + } + } + // Load file into $data + if ($foundintocache) { // Cache file found and is not too old + dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate."."); + $data = json_decode(file_get_contents($newpathofdestfile), true); + } else { + $year = $startyear; + $sm = $startmonth - 1; + if ($sm != 0) { + $year = $year - 1; + } + while ($year <= $endyear) { + $datay[$year] = $this->getNbByMonth($year, $format); + $year++; + } + + $data = array(); + + for ($i = 0; $i < 12; $i++) { + $data[$i][] = $datay[$endyear][($i + $sm) % 12][0]; + $year = $startyear; + while ($year <= $endyear) { + $data[$i][] = $datay[$year][($i + $sm) % 12][1]; + $year++; + } + } + + } + + // Save cache file + if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) { + dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk."); + if (!dol_is_dir($conf->user->dir_temp)) { + dol_mkdir($conf->user->dir_temp); + } + $fp = fopen($newpathofdestfile, 'w'); + fwrite($fp, json_encode($data)); + fclose($fp); + if (!empty($conf->global->MAIN_UMASK)) { + $newmask = $conf->global->MAIN_UMASK; + } + @chmod($newpathofdestfile, octdec($newmask)); + + $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt; + } + + // return array(array('Month',val1,val2,val3),...) + return $data; + } + + /** + * Return amount of elements by month for several years. + * Criterias used to build request are defined into the constructor of parent class into xxx/class/xxxstats.class.php + * The caller of class can add more filters into sql request by adding criteris into the $stats->where property just after + * calling constructor. + * + * @param int $endyear Start year + * @param int $startyear End year + * @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save) + * @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month + * @param int $startmonth month of the fiscal year start min 1 max 12 ; if 1 = january + * @return array Array of values + */ + public function getAmountByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1) + { + global $conf, $user, $langs; + + if ($startyear > $endyear) { + return -1; + } + + $datay = array(); + + // Search into cache + if (!empty($cachedelay)) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php'; + } + + $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache'; + $newmask = '0644'; + + $nowgmt = dol_now(); + + $foundintocache = 0; + if ($cachedelay > 0) { + $filedate = dol_filemtime($newpathofdestfile); + if ($filedate >= ($nowgmt - $cachedelay)) { + $foundintocache = 1; + + $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate; + } else { + dol_syslog(get_class($this).'::'.__FUNCTION__." cache file ".$newpathofdestfile." is not found or older than now - cachedelay (".$nowgmt." - ".$cachedelay.") so we can't use it."); + } + } + + // Load file into $data + if ($foundintocache) { // Cache file found and is not too old + dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate."."); + $data = json_decode(file_get_contents($newpathofdestfile), true); + } else { + $year = $startyear; + $sm = $startmonth - 1; + if ($sm != 0) { + $year = $year - 1; + } + while ($year <= $endyear) { + $datay[$year] = $this->getAmountByMonth($year, $format); + $year++; + } + + $data = array(); + // $data = array('xval'=>array(0=>xlabel,1=>yval1,2=>yval2...),...) + for ($i = 0; $i < 12; $i++) { + $data[$i][] = isset($datay[$endyear][($i + $sm) % 12]['label']) ? $datay[$endyear][($i + $sm) % 12]['label'] : $datay[$endyear][($i + $sm) % 12][0]; // set label + $year = $startyear; + while ($year <= $endyear) { + $data[$i][] = $datay[$year][($i + $sm) % 12][1]; // set yval for x=i + $year++; + } + } + } + + // Save cache file + if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) { + dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk."); + if (!dol_is_dir($conf->user->dir_temp)) { + dol_mkdir($conf->user->dir_temp); + } + $fp = fopen($newpathofdestfile, 'w'); + if ($fp) { + fwrite($fp, json_encode($data)); + fclose($fp); + if (!empty($conf->global->MAIN_UMASK)) { + $newmask = $conf->global->MAIN_UMASK; + } + @chmod($newpathofdestfile, octdec($newmask)); + } else { + dol_syslog("Failed to write cache file", LOG_ERR); + } + $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt; + } + + return $data; + } + + /** + * Return average of entity by month for several years + * + * @param int $endyear Start year + * @param int $startyear End year + * @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save) + * @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month + * @param int $startmonth month of the fiscal year start min 1 max 12 ; if 1 = january + * @return array Array of values + */ + public function getAverageByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1) + { + global $conf, $user, $langs; + + if ($startyear > $endyear) { + return -1; + } + + $datay = array(); + + // Search into cache + if (!empty($cachedelay)) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php'; + } + + $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache'; + $newmask = '0644'; + + $nowgmt = dol_now(); + + $foundintocache = 0; + if ($cachedelay > 0) { + $filedate = dol_filemtime($newpathofdestfile); + if ($filedate >= ($nowgmt - $cachedelay)) { + $foundintocache = 1; + + $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate; + } else { + dol_syslog(get_class($this).'::'.__FUNCTION__." cache file ".$newpathofdestfile." is not found or older than now - cachedelay (".$nowgmt." - ".$cachedelay.") so we can't use it."); + } + } + + // Load file into $data + if ($foundintocache) { // Cache file found and is not too old + dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate."."); + $data = json_decode(file_get_contents($newpathofdestfile), true); + } else { + $year = $startyear; + $sm = $startmonth - 1; + if ($sm != 0) { + $year = $year - 1; + } + while ($year <= $endyear) { + $datay[$year] = $this->getAverageByMonth($year); + $year++; + } + + $data = array(); + + for ($i = 0; $i < 12; $i++) { + $data[$i][] = $datay[$endyear][($i + $sm) % 12][0]; + $year = $startyear; + while ($year <= $endyear) { + $data[$i][] = $datay[$year][($i + $sm) % 12][1]; + $year++; + } + } + } + + // Save cache file + if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) { + dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk."); + if (!dol_is_dir($conf->user->dir_temp)) { + dol_mkdir($conf->user->dir_temp); + } + $fp = fopen($newpathofdestfile, 'w'); + if ($fp) { + fwrite($fp, json_encode($data)); + fclose($fp); + if (!empty($conf->global->MAIN_UMASK)) { + $newmask = $conf->global->MAIN_UMASK; + } + @chmod($newpathofdestfile, octdec($newmask)); + } else { + dol_syslog("Failed to write cache file", LOG_ERR); + } + $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt; + } + + return $data; + } + + // Here we have low level of shared code called by XxxStats.class.php + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Return nb of elements by year + * + * @param string $sql SQL request + * @return array + */ + protected function _getNbByYear($sql) + { + // phpcs:enable + $result = array(); + + dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $row = $this->db->fetch_row($resql); + $result[$i] = $row; + $i++; + } + $this->db->free($resql); + } else { + dol_print_error($this->db); + } + return $result; + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Return nb of elements, total amount and avg amount each year + * + * @param string $sql SQL request + * @return array Array with nb, total amount, average for each year + */ + protected function _getAllByYear($sql) + { + // phpcs:enable + $result = array(); + + dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $row = $this->db->fetch_object($resql); + $result[$i]['year'] = $row->year; + $result[$i]['nb'] = $row->nb; + if ($i > 0 && $row->nb > 0) { + $result[$i - 1]['nb_diff'] = ($result[$i - 1]['nb'] - $row->nb) / $row->nb * 100; + } + $result[$i]['total'] = $row->total; + if ($i > 0 && $row->total > 0) { + $result[$i - 1]['total_diff'] = ($result[$i - 1]['total'] - $row->total) / $row->total * 100; + } + $result[$i]['avg'] = $row->avg; + if ($i > 0 && $row->avg > 0) { + $result[$i - 1]['avg_diff'] = ($result[$i - 1]['avg'] - $row->avg) / $row->avg * 100; + } + // For some $sql only + if (isset($row->weighted)) { + $result[$i]['weighted'] = $row->weighted; + if ($i > 0 && $row->weighted > 0) { + $result[$i - 1]['avg_weighted'] = ($result[$i - 1]['weighted'] - $row->weighted) / $row->weighted * 100; + } + } + $i++; + } + $this->db->free($resql); + } else { + dol_print_error($this->db); + } + return $result; + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Renvoie le nombre de documents par mois pour une annee donnee + * Return number of documents per month for a given year + * + * @param int $year Year + * @param string $sql SQL + * @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month + * @return array Array of nb each month + */ + protected function _getNbByMonth($year, $sql, $format = 0) + { + // phpcs:enable + global $langs; + + $result = array(); + $res = array(); + + dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + $j = 0; + while ($i < $num) { + $row = $this->db->fetch_row($resql); + $j = $row[0] * 1; + $result[$j] = $row[1]; + $i++; + } + $this->db->free($resql); + } else { + dol_print_error($this->db); + } + + for ($i = 1; $i < 13; $i++) { + $res[$i] = (isset($result[$i]) ? $result[$i] : 0); + } + + $data = array(); + + for ($i = 1; $i < 13; $i++) { + $month = 'unknown'; + if ($format == 0) { + $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i)); + } elseif ($format == 1) { + $month = $i; + } elseif ($format == 2) { + $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i)); + } + //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b")); + //$month=dol_substr($month,0,3); + $data[$i - 1] = array($month, $res[$i]); + } + + return $data; + } + + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Return the amount per month for a given year + * + * @param int $year Year + * @param string $sql SQL + * @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month + * @return array + */ + protected function _getAmountByMonth($year, $sql, $format = 0) + { + // phpcs:enable + global $langs; + + $result = array(); + $res = array(); + + dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG); + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $row = $this->db->fetch_row($resql); + $j = $row[0] * 1; + $result[$j] = $row[1]; + $i++; + } + $this->db->free($resql); + } else { + dol_print_error($this->db); + } + + for ($i = 1; $i < 13; $i++) { + $res[$i] = (int) round((isset($result[$i]) ? $result[$i] : 0)); + } + + $data = array(); + + for ($i = 1; $i < 13; $i++) { + $month = 'unknown'; + if ($format == 0) { + $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i)); + } elseif ($format == 1) { + $month = $i; + } elseif ($format == 2) { + $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i)); + } + //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b")); + //$month=dol_substr($month,0,3); + $data[$i - 1] = array($month, $res[$i]); + } + + return $data; + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Renvoie le montant moyen par mois pour une annee donnee + * Return the amount average par month for a given year + * + * @param int $year Year + * @param string $sql SQL + * @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month + * @return array + */ + protected function _getAverageByMonth($year, $sql, $format = 0) + { + // phpcs:enable + global $langs; + + $result = array(); + $res = array(); + + dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + $j = 0; + while ($i < $num) { + $row = $this->db->fetch_row($resql); + $j = $row[0] * 1; + $result[$j] = $row[1]; + $i++; + } + $this->db->free($resql); + } else { + dol_print_error($this->db); + } + + for ($i = 1; $i < 13; $i++) { + $res[$i] = (isset($result[$i]) ? $result[$i] : 0); + } + + $data = array(); + + for ($i = 1; $i < 13; $i++) { + $month = 'unknown'; + if ($format == 0) { + $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i)); + } elseif ($format == 1) { + $month = $i; + } elseif ($format == 2) { + $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i)); + } + //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b")); + //$month=dol_substr($month,0,3); + $data[$i - 1] = array($month, $res[$i]); + } + + return $data; + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Returns the summed amounts per year for a given number of past years ending now + * @param string $sql SQL + * @return array + */ + protected function _getAmountByYear($sql) + { + $result = array(); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $row = $this->db->fetch_row($resql); + $j = (int) $row[0]; + $result[] = [ + 0 => (int) $row[0], + 1 => (int) $row[1], + ]; + $i++; + } + $this->db->free($resql); + } + return $result; + } +} + diff --git a/class/ticketdigiriskstats.class.php b/class/ticketdigiriskstats.class.php new file mode 100644 index 000000000..8aea386b1 --- /dev/null +++ b/class/ticketdigiriskstats.class.php @@ -0,0 +1,146 @@ + + * + * 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 . + */ + +/** + * \file class/ticketdigiriskstats.class.php + * \ingroup digiriskdolibarr + * \brief Fichier de la classe de gestion des stats des tickets + */ + +include_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php'; +include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; + +require_once __DIR__ . '/digiriskstats.php'; + +/** + * Class to manage stats for tickets + */ +class TicketDigiriskStats extends DigiriskStats +{ + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element; + + public $socid; + public $userid; + + public $from; + public $field; + public $where; + public $join; + + /** + * Constructor + * + * @param DoliDB $db Database handler + * @param int $socid Id third party for filter. This value must be forced during the new to external user company if user is an external user. + * @param int $userid Id user for filter (creation user) + * @param int $digiriskelementid Id digiriskelement for filter + * @param int $categticketid Id category of ticket for filter + */ + public function __construct($db, $socid, $userid = 0, $digiriskelementid = 0, $categticketid = 0) + { + $this->db = $db; + $this->socid = ($socid > 0 ? $socid : 0); + $this->userid = $userid; + $this->join = ''; + + $object = new Ticket($this->db); + $this->from = MAIN_DB_PREFIX.$object->table_element." as tk"; + $this->where = "tk.fk_statut >= 0"; + $this->where .= " AND tk.entity IN (".getEntity('ticket').")"; + if ($this->socid) { + $this->where .= " AND tk.fk_soc = ".((int) $this->socid); + } + if (is_array($this->userid) && count($this->userid) > 0) { + $this->where .= ' AND fk_user_create IN ('.$this->db->sanitize(join(',', $this->userid)).')'; + } elseif ($this->userid > 0) { + $this->where .= " AND fk_user_create = ".((int) $this->userid); + } + + if ($digiriskelementid) { + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'ticket_extrafields as tkextra ON tk.rowid = tkextra.fk_object'; + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'digiriskdolibarr_digiriskelement as e ON tkextra.digiriskdolibarr_ticket_service = e.rowid'; + $this->where .= ' AND e.rowid = '.((int) $digiriskelementid); + } + + if ($categticketid) { + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_ticket as ctk ON ctk.fk_ticket = tk.rowid'; + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie as c ON c.rowid = ctk.fk_categorie'; + $this->where .= ' AND c.rowid = '.((int) $categticketid); + } + } + + /** + * Return ticket number by month for a year + * + * @param int $year Year to scan + * @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month + * @return array Array of values + */ + public function getNbByMonth($year, $format = 0) + { + $sql = "SELECT date_format(tk.datec,'%m') as dc, COUNT(*) as nb"; + $sql .= " FROM ".$this->from; + $sql .= $this->join; + $sql .= " WHERE tk.datec BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; + $sql .= " AND ".$this->where; + $sql .= " GROUP BY dc"; + $sql .= $this->db->order('dc', 'DESC'); + + $res = $this->_getNbByMonth($year, $sql, $format); + + return $res; + } + + + /** + * Return ticket number per year + * + * @return array Array with number by year + */ + public function getNbByYear() + { + $sql = "SELECT date_format(tk.datec,'%Y') as dc, COUNT(*), SUM(c.".$this->field.")"; + $sql .= " FROM ".$this->from; + $sql .= $this->join; + $sql .= " WHERE ".$this->where; + $sql .= " GROUP BY dc"; + $sql .= $this->db->order('dc', 'DESC'); + + return $this->_getNbByYear($sql); + } + + /** + * Return nb, total and average + * + * @return array Array of values + */ + public function getAllByYear() + { + $sql = "SELECT date_format(tk.datec,'%Y') as year, COUNT(*) as nb"; + $sql .= " FROM ".$this->from; + $sql .= $this->join; + $sql .= " WHERE ".$this->where; + $sql .= " GROUP BY year"; + $sql .= $this->db->order('year', 'DESC'); + + return $this->_getAllByYear($sql); + } +} + diff --git a/core/modules/modDigiriskDolibarr.class.php b/core/modules/modDigiriskDolibarr.class.php index 135a95332..4863568cf 100644 --- a/core/modules/modDigiriskDolibarr.class.php +++ b/core/modules/modDigiriskDolibarr.class.php @@ -1275,8 +1275,8 @@ public function __construct($db) 'titre' => $langs->transnoentities('DashBoard'), 'prefix' => $pictoDigirisk, 'mainmenu' => 'ticket', - 'leftmenu' => 'dashboardticket', - 'url' => '/digiriskdolibarr/view/dashboard_ticket.php', + 'leftmenu' => 'ticketstats', + 'url' => '/digiriskdolibarr/view/ticketstats.php', 'langs' => 'digiriskdolibarr@digiriskdolibarr', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'position' => 48520 + $r, 'enabled' => '$conf->digiriskdolibarr->enabled && $conf->ticket->enabled', // Define condition to show or hide menu entry. Use '$conf->digiriskdolibarr->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. @@ -1285,6 +1285,22 @@ public function __construct($db) 'user' => 0, // 0=Menu for internal users, 1=external users, 2=both ); +// $this->menu[$r++] = array( +// 'fk_menu' => 'fk_mainmenu=ticket', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode +// 'type' => 'left', // This is a Left menu entry +// 'titre' => $langs->transnoentities('DashBoard'), +// 'prefix' => $pictoDigirisk, +// 'mainmenu' => 'ticket', +// 'leftmenu' => 'dashboardticket', +// 'url' => '/digiriskdolibarr/view/dashboard_ticket.php', +// 'langs' => 'digiriskdolibarr@digiriskdolibarr', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. +// 'position' => 48520 + $r, +// 'enabled' => '$conf->digiriskdolibarr->enabled && $conf->ticket->enabled', // Define condition to show or hide menu entry. Use '$conf->digiriskdolibarr->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. +// 'perms' => '$user->rights->ticket->read && $user->rights->digiriskdolibarr->lire', // Use 'perms'=>'$user->rights->digiriskdolibarr->level1->level2' if you want your menu with a permission rules +// 'target' => '', +// 'user' => 0, // 0=Menu for internal users, 1=external users, 2=both +// ); + // Exports profiles provided by this module $r = 1; diff --git a/langs/fr_FR/digiriskdolibarr.lang b/langs/fr_FR/digiriskdolibarr.lang index 780e6f290..c1553c9ce 100644 --- a/langs/fr_FR/digiriskdolibarr.lang +++ b/langs/fr_FR/digiriskdolibarr.lang @@ -1428,6 +1428,7 @@ TicketCreationSubject = Création de ticket via l'interface publique de Digirisk TicketDocumentCustomDigiriskTemplate = ODT custom des fiches de tickets HowToSetupDigiriskElement = Pour configurer les éléments de Digirisk (groupements/unités de travail), veuillez cliquer sur ce lien : ConfigDigiriskElement = Configuration des éléments de Digirisk +TicketStatistics = Statistiques des tickets diff --git a/view/ticketstats.php b/view/ticketstats.php new file mode 100644 index 000000000..f306d6250 --- /dev/null +++ b/view/ticketstats.php @@ -0,0 +1,268 @@ + + * + * 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 . + */ + +/** + * \file view/ticketstats.php + * \ingroup digiriskdolibarr + * \brief Page with tickets statistics + */ + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if ( ! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"] . "/main.inc.php"; +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; } +if ( ! $res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1)) . "/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1)) . "/main.inc.php"; +if ( ! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php"; +// Try main.inc.php using relative path +if ( ! $res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php"; +if ( ! $res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php"; +if ( ! $res) die("Include of main fails"); + +// Global variables definitions +global $conf, $db, $langs, $user; + +// Libraries +require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php'; +if (!empty($conf->category->enabled)) { + require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; +} + +require_once __DIR__ . '/../class/ticketdigiriskstats.class.php'; +require_once __DIR__ . '/../class/digiriskelement.class.php'; + +$WIDTH = DolGraph::getDefaultGraphSizeForStats('width'); +$HEIGHT = DolGraph::getDefaultGraphSizeForStats('height'); + +// Load translation files required by the page +$langs->loadLangs(array('orders', 'companies', 'other', 'tickets', 'categories')); + +if (!$user->rights->ticket->read) { + accessforbidden(); +} + +$object_status = GETPOST('object_status', 'intcomma'); +$userid = GETPOST('userid', 'int'); +$socid = GETPOST('socid', 'int'); +$digiriskelementid = GETPOST('digiriskelementid', 'int'); +$categticketid = GETPOST('categticketid', 'int'); +$ticketcats = GETPOST('ticketcats', 'array'); + +// Initialize technical objects +$object = new Ticket($db); +$digiriskelement = new DigiriskElement($db); + +// Security check +if ($user->socid > 0) { + $action = ''; + $socid = $user->socid; +} + +$nowyear = strftime("%Y", dol_now()); +$year = GETPOST('year') > 0 ? GETPOST('year', 'int') : $nowyear; +$startyear = $year - (empty($conf->global->MAIN_STATS_GRAPHS_SHOW_N_YEARS) ? 2 : max(1, min(10, $conf->global->MAIN_STATS_GRAPHS_SHOW_N_YEARS))); +$endyear = $year; + +/* + * View + */ + +$form = new Form($db); + +$title = $langs->trans("TicketStatistics"); +$dir = $conf->ticket->dir_temp; + +llxHeader('', $title); + +print load_fiche_titre($title, '', 'ticket'); + +dol_mkdir($dir); + +$stats = new TicketDigiriskStats($db, $socid, ($userid > 0 ? $userid: 0), ($digiriskelementid > 0 ? $digiriskelementid : 0), ($categticketid > 0 ? $categticketid: 0)); +if ($object_status != '' && $object_status >= 0) { + $stats->where .= ' AND tk.fk_statut IN ('.$db->sanitize($db->escape($object_status)).')'; +} +if (is_array($ticketcats) && !empty($ticketcats)) { + $stats->from .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_ticket as cattk ON (tk.rowid = cattk.fk_ticket)'; + $stats->where .= ' AND cattk.fk_categorie IN ('.$db->sanitize(implode(',', $ticketcats)).')'; +} + +// Build graphic number of object +$data = $stats->getNbByMonthWithPrevYear($endyear, $startyear, 0, 0, $conf->global->SOCIETE_FISCAL_MONTH_START); + +if (empty($user->rights->societe->client->voir) || $user->socid) { + $filenamenb = $dir.'/ticketdigiriskstatsnbinyear-'.$user->id.'-'.$year.'.png'; + $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=ticketdigiriskstats&file=ticketdigiriskstatsnbinyear-'.$user->id.'-'.$year.'.png'; +} else { + $filenamenb = $dir.'/ticketdigiriskstatsnbinyear-'.$year.'.png'; + $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=ticketdigiriskstats&file=ticketdigiriskstatsnbinyear-'.$year.'.png'; +} + +$px1 = new DolGraph(); +$mesg = $px1->isGraphKo(); +if (!$mesg) { + $px1->SetData($data); + $i = $startyear; $legend = array(); + while ($i <= $endyear) { + $legend[] = $i; + $i++; + } + $px1->SetLegend($legend); + $px1->SetMaxValue($px1->GetCeilMaxValue()); + $px1->SetMinValue(min(0, $px1->GetFloorMinValue())); + $px1->SetWidth($WIDTH); + $px1->SetHeight($HEIGHT); + $px1->SetYLabel($langs->trans("NbOfTicket")); + $px1->SetShading(3); + $px1->SetHorizTickIncrement(1); + $px1->mode = 'depth'; + $px1->SetTitle($langs->trans("NumberOfTicketsByMonth")); + + $px1->draw($filenamenb, $fileurlnb); +} + +// Show array +$data = $stats->getAllByYear(); +$arrayyears = array(); +foreach ($data as $val) { + if (!empty($val['year'])) { + $arrayyears[$val['year']] = $val['year']; + } +} +if (!count($arrayyears)) { + $arrayyears[$nowyear] = $nowyear; +} + +$h = 0; +$head = array(); +$head[$h][0] = DOL_URL_ROOT.'/custom/digiriskdolibarr/view/ticketstats.php'; +$head[$h][1] = $langs->trans("ByMonthYear"); +$head[$h][2] = 'byyear'; +$h++; + +complete_head_from_modules($conf, $langs, null, $head, $h, 'ticket'); + +print dol_get_fiche_head($head, 'byyear', $langs->trans("TicketStatistics"), -1); + +print '
'; + +// Show filter box +print '
'; +print ''; + +print ''; +print ''; +// Company +print ''; +// DigiriskElement +print ''; +// Category +if (!empty($conf->category->enabled)) { + $cat_type = Categorie::TYPE_TICKET; + $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Ticket")); + print ''; +} +// User +print ''; +// Year +print ''; +print ''; +print '
'.$langs->trans("Filter").'
'.$langs->trans("ThirdParty").''; +print img_picto('', 'company', 'class="pictofixedwidth"'); +print $form->select_company($socid, 'socid', '', 1, 0, 0, array(), 0, 'widthcentpercentminusx maxwidth300'); +print '
'.$langs->trans("GP/UT").''; +print img_picto('', '', 'class="pictofixedwidth"'); +print $digiriskelement->select_digiriskelement_list($digiriskelementid, 'digiriskelementid', '', 1, 0, array(), 0, 0,'widthcentpercentminusx maxwidth300', '', 0, 1); +print '
'.$cat_label.''; + $cate_arbo = $form->select_all_categories($cat_type, null, 'parent', null, null, 1); + print img_picto('', 'category', 'class="pictofixedwidth"'); + print $form->multiselectarray('ticketcats', $cate_arbo, GETPOST('ticketcats', 'array'), 0, 0, 'widthcentpercentminusx maxwidth300'); + print '
'.$langs->trans("CreatedBy").''; +print img_picto('', 'user', 'class="pictofixedwidth"'); +print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', $conf->entity, 0, 0, '', 0, '', 'widthcentpercentminusx maxwidth300'); +// Status +print '
'.$langs->trans("Status").''; +$liststatus = $object->statuts_short; +print $form->selectarray('object_status', $liststatus, GETPOST('object_status', 'intcomma'), -4, 0, 0, '', 1); +print '
'.$langs->trans("Year").''; +if (!in_array($year, $arrayyears)) { + $arrayyears[$year] = $year; +} +if (!in_array($nowyear, $arrayyears)) { + $arrayyears[$nowyear] = $nowyear; +} +arsort($arrayyears); +print $form->selectarray('year', $arrayyears, $year, 0, 0, 0, '', 0, 0, 0, '', 'width75'); +print '
'; +print '
'; + +print '

'; + +print '
'; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +$oldyear = 0; +foreach ($data as $val) { + $year = $val['year']; + while (!empty($year) && $oldyear > $year + 1) { // If we have empty year + $oldyear--; + + print ''; + print ''; + print ''; + print ''; + print ''; + } + + print ''; + print ''; + print ''; + print ''; + print ''; + $oldyear = $year; +} + +print '
'.$langs->trans("Year").''.$langs->trans("NbOfTickets").'%
0 ? '&userid='.$userid : '').'">'.$oldyear.'0
0 ? '&userid='.$userid : '').'">'.$year.''.$val['nb'].''.round($val['nb_diff']).'
'; +print '
'; + +print '
'; + +// Show graphs +print '
'; +if ($mesg) { + print $mesg; +} else { + print $px1->show(); +} +print '
'; + +print '
'; +print '
'; + +print dol_get_fiche_end(); + +// End of page +llxFooter(); +$db->close();