dolibarr  18.0.6
stats.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (c) 2008-2013 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2012 Marcos GarcĂ­a <marcosgdf@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  */
20 
30 abstract class Stats
31 {
32  protected $db;
33  protected $lastfetchdate = array(); // Dates of cache file read by methods
34  public $cachefilesuffix = ''; // Suffix to add to name of cache file (to avoid file name conflicts)
35 
41  protected abstract function getNbByMonth($year, $format = 0);
42 
53  public function getNbByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1)
54  {
55  global $conf, $user, $langs;
56 
57  if ($startyear > $endyear) {
58  return array();
59  }
60 
61  $datay = array();
62 
63  // Search into cache
64  if (!empty($cachedelay)) {
65  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
66  include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
67  }
68 
69  $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache';
70  $newmask = '0644';
71 
72  $nowgmt = dol_now();
73 
74  $foundintocache = 0;
75  if ($cachedelay > 0) {
76  $filedate = dol_filemtime($newpathofdestfile);
77  if ($filedate >= ($nowgmt - $cachedelay)) {
78  $foundintocache = 1;
79 
80  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate;
81  } else {
82  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.");
83  }
84  }
85  // Load file into $data
86  if ($foundintocache) { // Cache file found and is not too old
87  dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
88  $data = json_decode(file_get_contents($newpathofdestfile), true);
89  } else {
90  $year = $startyear;
91  $sm = $startmonth - 1;
92  if ($sm != 0) {
93  $year = $year - 1;
94  }
95  while ($year <= $endyear) {
96  $datay[$year] = $this->getNbByMonth($year, $format);
97  $year++;
98  }
99 
100  $data = array();
101 
102  for ($i = 0; $i < 12; $i++) {
103  $data[$i][] = $datay[$endyear][($i + $sm) % 12][0];
104  $year = $startyear;
105  while ($year <= $endyear) {
106  // floor(($i + $sm) / 12)) is 0 if we are after the month start $sm and same year, become 1 when we reach january of next year
107  $data[$i][] = $datay[$year - (1 - floor(($i + $sm) / 12)) + ($sm == 0 ? 1 : 0)][($i + $sm) % 12][1];
108  $year++;
109  }
110  }
111  }
112 
113  // Save cache file
114  if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
115  dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
116  if (!dol_is_dir($conf->user->dir_temp)) {
117  dol_mkdir($conf->user->dir_temp);
118  }
119  $fp = fopen($newpathofdestfile, 'w');
120  fwrite($fp, json_encode($data));
121  fclose($fp);
122  dolChmod($newpathofdestfile);
123 
124  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt;
125  }
126 
127  // return array(array('Month',val1,val2,val3),...)
128  return $data;
129  }
130 
136  protected abstract function getAmountByMonth($year, $format = 0);
137 
151  public function getAmountByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1)
152  {
153  global $conf, $user, $langs;
154 
155  if ($startyear > $endyear) {
156  return array();
157  }
158 
159  $datay = array();
160 
161  // Search into cache
162  if (!empty($cachedelay)) {
163  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
164  include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
165  }
166 
167  $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache';
168  $newmask = '0644';
169 
170  $nowgmt = dol_now();
171 
172  $foundintocache = 0;
173  if ($cachedelay > 0) {
174  $filedate = dol_filemtime($newpathofdestfile);
175  if ($filedate >= ($nowgmt - $cachedelay)) {
176  $foundintocache = 1;
177 
178  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate;
179  } else {
180  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.");
181  }
182  }
183 
184  // Load file into $data
185  if ($foundintocache) { // Cache file found and is not too old
186  dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
187  $data = json_decode(file_get_contents($newpathofdestfile), true);
188  } else {
189  $year = $startyear;
190  $sm = $startmonth - 1;
191  if ($sm != 0) {
192  $year = $year - 1;
193  }
194  while ($year <= $endyear) {
195  $datay[$year] = $this->getAmountByMonth($year, $format);
196  $year++;
197  }
198 
199  $data = array();
200  // $data = array('xval'=>array(0=>xlabel,1=>yval1,2=>yval2...),...)
201  for ($i = 0; $i < 12; $i++) {
202  $data[$i][] = isset($datay[$endyear][($i + $sm) % 12]['label']) ? $datay[$endyear][($i + $sm) % 12]['label'] : $datay[$endyear][($i + $sm) % 12][0]; // set label
203  $year = $startyear;
204  while ($year <= $endyear) {
205  // floor(($i + $sm) / 12)) is 0 if we are after the month start $sm and same year, become 1 when we reach january of next year
206  $data[$i][] = $datay[$year - (1 - floor(($i + $sm) / 12)) + ($sm == 0 ? 1 : 0)][($i + $sm) % 12][1]; // set yval for x=i
207  $year++;
208  }
209  }
210  }
211 
212  // Save cache file
213  if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
214  dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
215  if (!dol_is_dir($conf->user->dir_temp)) {
216  dol_mkdir($conf->user->dir_temp);
217  }
218  $fp = fopen($newpathofdestfile, 'w');
219  if ($fp) {
220  fwrite($fp, json_encode($data));
221  fclose($fp);
222  dolChmod($newpathofdestfile);
223  } else {
224  dol_syslog("Failed to write cache file", LOG_ERR);
225  }
226  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt;
227  }
228 
229  return $data;
230  }
231 
236  protected abstract function getAverageByMonth($year);
237 
245  public function getAverageByMonthWithPrevYear($endyear, $startyear)
246  {
247  if ($startyear > $endyear) {
248  return array();
249  }
250 
251  $datay = array();
252 
253  $year = $startyear;
254  while ($year <= $endyear) {
255  $datay[$year] = $this->getAverageByMonth($year);
256  $year++;
257  }
258 
259  $data = array();
260 
261  for ($i = 0; $i < 12; $i++) {
262  $data[$i][] = $datay[$endyear][$i][0];
263  $year = $startyear;
264  while ($year <= $endyear) {
265  $data[$i][] = $datay[$year][$i][1];
266  $year++;
267  }
268  }
269 
270  return $data;
271  }
272 
281  public function getAllByProductEntry($year, $cachedelay = 0, $limit = 10)
282  {
283  global $conf, $user, $langs;
284 
285  $data = array();
286 
287  // Search into cache
288  if (!empty($cachedelay)) {
289  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
290  include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
291  }
292 
293  $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache';
294  $newmask = '0644';
295 
296  $nowgmt = dol_now();
297 
298  $foundintocache = 0;
299  if ($cachedelay > 0) {
300  $filedate = dol_filemtime($newpathofdestfile);
301  if ($filedate >= ($nowgmt - $cachedelay)) {
302  $foundintocache = 1;
303 
304  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate;
305  } else {
306  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.");
307  }
308  }
309 
310  // Load file into $data
311  if ($foundintocache) { // Cache file found and is not too old
312  dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
313  $data = json_decode(file_get_contents($newpathofdestfile), true);
314  } else {
315  $data = $this->getAllByProduct($year, $limit);
316  // $data[$i][]=$datay[$year][$i][1]; // set yval for x=i
317  }
318 
319  // Save cache file
320  if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
321  dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
322  if (!dol_is_dir($conf->user->dir_temp)) {
323  dol_mkdir($conf->user->dir_temp);
324  }
325  $fp = fopen($newpathofdestfile, 'w');
326  if ($fp) {
327  fwrite($fp, json_encode($data));
328  fclose($fp);
329  dolChmod($newpathofdestfile);
330  }
331  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt;
332  }
333 
334  return $data;
335  }
336 
337 
338  // Here we have low level of shared code called by XxxStats.class.php
339 
340 
341  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
348  protected function _getNbByYear($sql)
349  {
350  // phpcs:enable
351  $result = array();
352 
353  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
354  $resql = $this->db->query($sql);
355  if ($resql) {
356  $num = $this->db->num_rows($resql);
357  $i = 0;
358  while ($i < $num) {
359  $row = $this->db->fetch_row($resql);
360  $result[$i] = $row;
361  $i++;
362  }
363  $this->db->free($resql);
364  } else {
365  dol_print_error($this->db);
366  }
367  return $result;
368  }
369 
370  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
377  protected function _getAllByYear($sql)
378  {
379  // phpcs:enable
380  $result = array();
381 
382  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
383  $resql = $this->db->query($sql);
384  if ($resql) {
385  $num = $this->db->num_rows($resql);
386  $i = 0;
387  while ($i < $num) {
388  $row = $this->db->fetch_object($resql);
389  $result[$i]['year'] = $row->year;
390  $result[$i]['nb'] = $row->nb;
391  if ($i > 0 && $row->nb > 0) {
392  $result[$i - 1]['nb_diff'] = ($result[$i - 1]['nb'] - $row->nb) / $row->nb * 100;
393  }
394  // For some $sql only
395  if (property_exists($row, 'total')) {
396  $result[$i]['total'] = $row->total;
397  if ($i > 0 && $row->total > 0) {
398  $result[$i - 1]['total_diff'] = ($result[$i - 1]['total'] - $row->total) / $row->total * 100;
399  }
400  }
401  // For some $sql only
402  if (property_exists($row, 'total')) {
403  $result[$i]['avg'] = $row->avg;
404  if ($i > 0 && $row->avg > 0) {
405  $result[$i - 1]['avg_diff'] = ($result[$i - 1]['avg'] - $row->avg) / $row->avg * 100;
406  }
407  }
408  // For some $sql only
409  if (property_exists($row, 'weighted')) {
410  $result[$i]['weighted'] = $row->weighted;
411  if ($i > 0 && $row->weighted > 0) {
412  $result[$i - 1]['avg_weighted'] = ($result[$i - 1]['weighted'] - $row->weighted) / $row->weighted * 100;
413  }
414  }
415  $i++;
416  }
417  $this->db->free($resql);
418  } else {
419  dol_print_error($this->db);
420  }
421  return $result;
422  }
423 
424  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
434  protected function _getNbByMonth($year, $sql, $format = 0)
435  {
436  // phpcs:enable
437  global $langs;
438 
439  $result = array();
440  $res = array();
441 
442  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
443  $resql = $this->db->query($sql);
444  if ($resql) {
445  $num = $this->db->num_rows($resql);
446  $i = 0;
447  $j = 0;
448  while ($i < $num) {
449  $row = $this->db->fetch_row($resql);
450  $j = $row[0] * 1;
451  $result[$j] = $row[1];
452  $i++;
453  }
454  $this->db->free($resql);
455  } else {
456  dol_print_error($this->db);
457  }
458 
459  for ($i = 1; $i < 13; $i++) {
460  $res[$i] = (isset($result[$i]) ? $result[$i] : 0);
461  }
462 
463  $data = array();
464 
465  for ($i = 1; $i < 13; $i++) {
466  $month = 'unknown';
467  if ($format == 0) {
468  $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
469  } elseif ($format == 1) {
470  $month = $i;
471  } elseif ($format == 2) {
472  $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
473  }
474  //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
475  //$month=dol_substr($month,0,3);
476  $data[$i - 1] = array($month, $res[$i]);
477  }
478 
479  return $data;
480  }
481 
482  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
491  protected function _getAmountByMonth($year, $sql, $format = 0)
492  {
493  // phpcs:enable
494  global $langs;
495 
496  $result = array();
497  $res = array();
498 
499  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
500 
501  $resql = $this->db->query($sql);
502  if ($resql) {
503  $num = $this->db->num_rows($resql);
504  $i = 0;
505  while ($i < $num) {
506  $row = $this->db->fetch_row($resql);
507  $j = $row[0] * 1;
508  $result[$j] = $row[1];
509  $i++;
510  }
511  $this->db->free($resql);
512  } else {
513  dol_print_error($this->db);
514  }
515 
516  for ($i = 1; $i < 13; $i++) {
517  $res[$i] = (int) round((isset($result[$i]) ? $result[$i] : 0));
518  }
519 
520  $data = array();
521 
522  for ($i = 1; $i < 13; $i++) {
523  $month = 'unknown';
524  if ($format == 0) {
525  $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
526  } elseif ($format == 1) {
527  $month = $i;
528  } elseif ($format == 2) {
529  $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
530  }
531  //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
532  //$month=dol_substr($month,0,3);
533  $data[$i - 1] = array($month, $res[$i]);
534  }
535 
536  return $data;
537  }
538 
539  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
549  protected function _getAverageByMonth($year, $sql, $format = 0)
550  {
551  // phpcs:enable
552  global $langs;
553 
554  $result = array();
555  $res = array();
556 
557  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
558  $resql = $this->db->query($sql);
559  if ($resql) {
560  $num = $this->db->num_rows($resql);
561  $i = 0;
562  $j = 0;
563  while ($i < $num) {
564  $row = $this->db->fetch_row($resql);
565  $j = $row[0] * 1;
566  $result[$j] = $row[1];
567  $i++;
568  }
569  $this->db->free($resql);
570  } else {
571  dol_print_error($this->db);
572  }
573 
574  for ($i = 1; $i < 13; $i++) {
575  $res[$i] = (isset($result[$i]) ? $result[$i] : 0);
576  }
577 
578  $data = array();
579 
580  for ($i = 1; $i < 13; $i++) {
581  $month = 'unknown';
582  if ($format == 0) {
583  $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
584  } elseif ($format == 1) {
585  $month = $i;
586  } elseif ($format == 2) {
587  $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
588  }
589  //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
590  //$month=dol_substr($month,0,3);
591  $data[$i - 1] = array($month, $res[$i]);
592  }
593 
594  return $data;
595  }
596 
597 
598  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
606  protected function _getAllByProduct($sql, $limit = 10)
607  {
608  // phpcs:enable
609  global $langs;
610 
611  $result = array();
612 
613  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
614  $resql = $this->db->query($sql);
615  if ($resql) {
616  $num = $this->db->num_rows($resql);
617  $i = 0;
618  $other = 0;
619  while ($i < $num) {
620  $row = $this->db->fetch_row($resql);
621  if ($i < $limit || $num == $limit) {
622  $result[$i] = array($row[0], $row[1]); // Ref of product, nb
623  } else {
624  $other += $row[1];
625  }
626  $i++;
627  }
628  if ($num > $limit) {
629  $result[$i] = array($langs->transnoentitiesnoconv("Other"), $other);
630  }
631  $this->db->free($resql);
632  } else {
633  dol_print_error($this->db);
634  }
635 
636  return $result;
637  }
638 
639  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
645  protected function _getAmountByYear($sql)
646  {
647  $result = array();
648  $resql = $this->db->query($sql);
649  if ($resql) {
650  $num = $this->db->num_rows($resql);
651  $i = 0;
652  while ($i < $num) {
653  $row = $this->db->fetch_row($resql);
654  $j = (int) $row[0];
655  $result[] = [
656  0 => (int) $row[0],
657  1 => (int) $row[1],
658  ];
659  $i++;
660  }
661  $this->db->free($resql);
662  }
663  return $result;
664  }
665 }
Parent class of statistics class.
Definition: stats.class.php:31
getNbByMonth($year, $format=0)
getAmountByMonth($year, $format=0)
getAverageByMonth($year)
_getAmountByYear($sql)
Returns the summed amounts per year for a given number of past years ending now.
_getAverageByMonth($year, $sql, $format=0)
Renvoie le montant moyen par mois pour une annee donnee Return the amount average par month for a giv...
_getAmountByMonth($year, $sql, $format=0)
Return the amount per month for a given year.
_getNbByYear($sql)
Return nb of elements by year.
_getAllByYear($sql)
Return nb of elements, total amount and avg amount each year.
getAmountByMonthWithPrevYear($endyear, $startyear, $cachedelay=0, $format=0, $startmonth=1)
Return amount of elements by month for several years.
getNbByMonthWithPrevYear($endyear, $startyear, $cachedelay=0, $format=0, $startmonth=1)
Return nb of elements by month for several years.
Definition: stats.class.php:53
getAllByProductEntry($year, $cachedelay=0, $limit=10)
Return count, and sum of products.
getAverageByMonthWithPrevYear($endyear, $startyear)
Return average of entity by month for several years.
_getAllByProduct($sql, $limit=10)
Return number or total of product refs.
_getNbByMonth($year, $sql, $format=0)
Renvoie le nombre de documents par mois pour une annee donnee Return number of documents per month fo...
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
dol_filemtime($pathoffile)
Return time of a file.
Definition: files.lib.php:599
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:453
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)