dolibarr  16.0.5
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 -1;
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  $data[$i][] = $datay[$year - (1 - ((int) ($i + $sm) / 12)) + ($sm == 0 ? 1 : 0)][($i + $sm) % 12][1];
107  $year++;
108  }
109  }
110  }
111 
112  // Save cache file
113  if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
114  dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
115  if (!dol_is_dir($conf->user->dir_temp)) {
116  dol_mkdir($conf->user->dir_temp);
117  }
118  $fp = fopen($newpathofdestfile, 'w');
119  fwrite($fp, json_encode($data));
120  fclose($fp);
121  if (!empty($conf->global->MAIN_UMASK)) {
122  $newmask = $conf->global->MAIN_UMASK;
123  }
124  @chmod($newpathofdestfile, octdec($newmask));
125 
126  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt;
127  }
128 
129  // return array(array('Month',val1,val2,val3),...)
130  return $data;
131  }
132 
138  protected abstract function getAmountByMonth($year, $format = 0);
139 
153  public function getAmountByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1)
154  {
155  global $conf, $user, $langs;
156 
157  if ($startyear > $endyear) {
158  return -1;
159  }
160 
161  $datay = array();
162 
163  // Search into cache
164  if (!empty($cachedelay)) {
165  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
166  include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
167  }
168 
169  $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache';
170  $newmask = '0644';
171 
172  $nowgmt = dol_now();
173 
174  $foundintocache = 0;
175  if ($cachedelay > 0) {
176  $filedate = dol_filemtime($newpathofdestfile);
177  if ($filedate >= ($nowgmt - $cachedelay)) {
178  $foundintocache = 1;
179 
180  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate;
181  } else {
182  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.");
183  }
184  }
185 
186  // Load file into $data
187  if ($foundintocache) { // Cache file found and is not too old
188  dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
189  $data = json_decode(file_get_contents($newpathofdestfile), true);
190  } else {
191  $year = $startyear;
192  $sm = $startmonth - 1;
193  if ($sm != 0) {
194  $year = $year - 1;
195  }
196  while ($year <= $endyear) {
197  $datay[$year] = $this->getAmountByMonth($year, $format);
198  $year++;
199  }
200 
201  $data = array();
202  // $data = array('xval'=>array(0=>xlabel,1=>yval1,2=>yval2...),...)
203  for ($i = 0; $i < 12; $i++) {
204  $data[$i][] = isset($datay[$endyear][($i + $sm) % 12]['label']) ? $datay[$endyear][($i + $sm) % 12]['label'] : $datay[$endyear][($i + $sm) % 12][0]; // set label
205  $year = $startyear;
206  while ($year <= $endyear) {
207  $data[$i][] = $datay[$year - (1 - ((int) ($i + $sm) / 12)) + ($sm == 0 ? 1 : 0)][($i + $sm) % 12][1]; // set yval for x=i
208  $year++;
209  }
210  }
211  }
212 
213  // Save cache file
214  if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
215  dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
216  if (!dol_is_dir($conf->user->dir_temp)) {
217  dol_mkdir($conf->user->dir_temp);
218  }
219  $fp = fopen($newpathofdestfile, 'w');
220  if ($fp) {
221  fwrite($fp, json_encode($data));
222  fclose($fp);
223  if (!empty($conf->global->MAIN_UMASK)) {
224  $newmask = $conf->global->MAIN_UMASK;
225  }
226  @chmod($newpathofdestfile, octdec($newmask));
227  } else {
228  dol_syslog("Failed to write cache file", LOG_ERR);
229  }
230  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt;
231  }
232 
233  return $data;
234  }
235 
240  protected abstract function getAverageByMonth($year);
241 
249  public function getAverageByMonthWithPrevYear($endyear, $startyear)
250  {
251  if ($startyear > $endyear) {
252  return -1;
253  }
254 
255  $datay = array();
256 
257  $year = $startyear;
258  while ($year <= $endyear) {
259  $datay[$year] = $this->getAverageByMonth($year);
260  $year++;
261  }
262 
263  $data = array();
264 
265  for ($i = 0; $i < 12; $i++) {
266  $data[$i][] = $datay[$endyear][$i][0];
267  $year = $startyear;
268  while ($year <= $endyear) {
269  $data[$i][] = $datay[$year][$i][1];
270  $year++;
271  }
272  }
273 
274  return $data;
275  }
276 
285  public function getAllByProductEntry($year, $cachedelay = 0, $limit = 10)
286  {
287  global $conf, $user, $langs;
288 
289  $data = array();
290 
291  // Search into cache
292  if (!empty($cachedelay)) {
293  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
294  include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
295  }
296 
297  $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache';
298  $newmask = '0644';
299 
300  $nowgmt = dol_now();
301 
302  $foundintocache = 0;
303  if ($cachedelay > 0) {
304  $filedate = dol_filemtime($newpathofdestfile);
305  if ($filedate >= ($nowgmt - $cachedelay)) {
306  $foundintocache = 1;
307 
308  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate;
309  } else {
310  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.");
311  }
312  }
313 
314  // Load file into $data
315  if ($foundintocache) { // Cache file found and is not too old
316  dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
317  $data = json_decode(file_get_contents($newpathofdestfile), true);
318  } else {
319  $data = $this->getAllByProduct($year, $limit);
320  // $data[$i][]=$datay[$year][$i][1]; // set yval for x=i
321  }
322 
323  // Save cache file
324  if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
325  dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
326  if (!dol_is_dir($conf->user->dir_temp)) {
327  dol_mkdir($conf->user->dir_temp);
328  }
329  $fp = fopen($newpathofdestfile, 'w');
330  if ($fp) {
331  fwrite($fp, json_encode($data));
332  fclose($fp);
333  if (!empty($conf->global->MAIN_UMASK)) {
334  $newmask = $conf->global->MAIN_UMASK;
335  }
336  @chmod($newpathofdestfile, octdec($newmask));
337  }
338  $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt;
339  }
340 
341  return $data;
342  }
343 
344 
345  // Here we have low level of shared code called by XxxStats.class.php
346 
347 
348  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
355  protected function _getNbByYear($sql)
356  {
357  // phpcs:enable
358  $result = array();
359 
360  dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
361  $resql = $this->db->query($sql);
362  if ($resql) {
363  $num = $this->db->num_rows($resql);
364  $i = 0;
365  while ($i < $num) {
366  $row = $this->db->fetch_row($resql);
367  $result[$i] = $row;
368  $i++;
369  }
370  $this->db->free($resql);
371  } else {
372  dol_print_error($this->db);
373  }
374  return $result;
375  }
376 
377  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
384  protected function _getAllByYear($sql)
385  {
386  // phpcs:enable
387  $result = array();
388 
389  dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
390  $resql = $this->db->query($sql);
391  if ($resql) {
392  $num = $this->db->num_rows($resql);
393  $i = 0;
394  while ($i < $num) {
395  $row = $this->db->fetch_object($resql);
396  $result[$i]['year'] = $row->year;
397  $result[$i]['nb'] = $row->nb;
398  if ($i > 0 && $row->nb > 0) {
399  $result[$i - 1]['nb_diff'] = ($result[$i - 1]['nb'] - $row->nb) / $row->nb * 100;
400  }
401  $result[$i]['total'] = $row->total;
402  if ($i > 0 && $row->total > 0) {
403  $result[$i - 1]['total_diff'] = ($result[$i - 1]['total'] - $row->total) / $row->total * 100;
404  }
405  $result[$i]['avg'] = $row->avg;
406  if ($i > 0 && $row->avg > 0) {
407  $result[$i - 1]['avg_diff'] = ($result[$i - 1]['avg'] - $row->avg) / $row->avg * 100;
408  }
409  // For some $sql only
410  if (isset($row->weighted)) {
411  $result[$i]['weighted'] = $row->weighted;
412  if ($i > 0 && $row->weighted > 0) {
413  $result[$i - 1]['avg_weighted'] = ($result[$i - 1]['weighted'] - $row->weighted) / $row->weighted * 100;
414  }
415  }
416  $i++;
417  }
418  $this->db->free($resql);
419  } else {
420  dol_print_error($this->db);
421  }
422  return $result;
423  }
424 
425  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
435  protected function _getNbByMonth($year, $sql, $format = 0)
436  {
437  // phpcs:enable
438  global $langs;
439 
440  $result = array();
441  $res = array();
442 
443  dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
444  $resql = $this->db->query($sql);
445  if ($resql) {
446  $num = $this->db->num_rows($resql);
447  $i = 0;
448  $j = 0;
449  while ($i < $num) {
450  $row = $this->db->fetch_row($resql);
451  $j = $row[0] * 1;
452  $result[$j] = $row[1];
453  $i++;
454  }
455  $this->db->free($resql);
456  } else {
457  dol_print_error($this->db);
458  }
459 
460  for ($i = 1; $i < 13; $i++) {
461  $res[$i] = (isset($result[$i]) ? $result[$i] : 0);
462  }
463 
464  $data = array();
465 
466  for ($i = 1; $i < 13; $i++) {
467  $month = 'unknown';
468  if ($format == 0) {
469  $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
470  } elseif ($format == 1) {
471  $month = $i;
472  } elseif ($format == 2) {
473  $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
474  }
475  //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
476  //$month=dol_substr($month,0,3);
477  $data[$i - 1] = array($month, $res[$i]);
478  }
479 
480  return $data;
481  }
482 
483  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
492  protected function _getAmountByMonth($year, $sql, $format = 0)
493  {
494  // phpcs:enable
495  global $langs;
496 
497  $result = array();
498  $res = array();
499 
500  dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
501 
502  $resql = $this->db->query($sql);
503  if ($resql) {
504  $num = $this->db->num_rows($resql);
505  $i = 0;
506  while ($i < $num) {
507  $row = $this->db->fetch_row($resql);
508  $j = $row[0] * 1;
509  $result[$j] = $row[1];
510  $i++;
511  }
512  $this->db->free($resql);
513  } else {
514  dol_print_error($this->db);
515  }
516 
517  for ($i = 1; $i < 13; $i++) {
518  $res[$i] = (int) round((isset($result[$i]) ? $result[$i] : 0));
519  }
520 
521  $data = array();
522 
523  for ($i = 1; $i < 13; $i++) {
524  $month = 'unknown';
525  if ($format == 0) {
526  $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
527  } elseif ($format == 1) {
528  $month = $i;
529  } elseif ($format == 2) {
530  $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
531  }
532  //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
533  //$month=dol_substr($month,0,3);
534  $data[$i - 1] = array($month, $res[$i]);
535  }
536 
537  return $data;
538  }
539 
540  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
550  protected function _getAverageByMonth($year, $sql, $format = 0)
551  {
552  // phpcs:enable
553  global $langs;
554 
555  $result = array();
556  $res = array();
557 
558  dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
559  $resql = $this->db->query($sql);
560  if ($resql) {
561  $num = $this->db->num_rows($resql);
562  $i = 0;
563  $j = 0;
564  while ($i < $num) {
565  $row = $this->db->fetch_row($resql);
566  $j = $row[0] * 1;
567  $result[$j] = $row[1];
568  $i++;
569  }
570  $this->db->free($resql);
571  } else {
572  dol_print_error($this->db);
573  }
574 
575  for ($i = 1; $i < 13; $i++) {
576  $res[$i] = (isset($result[$i]) ? $result[$i] : 0);
577  }
578 
579  $data = array();
580 
581  for ($i = 1; $i < 13; $i++) {
582  $month = 'unknown';
583  if ($format == 0) {
584  $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
585  } elseif ($format == 1) {
586  $month = $i;
587  } elseif ($format == 2) {
588  $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
589  }
590  //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
591  //$month=dol_substr($month,0,3);
592  $data[$i - 1] = array($month, $res[$i]);
593  }
594 
595  return $data;
596  }
597 
598 
599  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
607  protected function _getAllByProduct($sql, $limit = 10)
608  {
609  // phpcs:enable
610  global $langs;
611 
612  $result = array();
613 
614  dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
615  $resql = $this->db->query($sql);
616  if ($resql) {
617  $num = $this->db->num_rows($resql);
618  $i = 0;
619  $other = 0;
620  while ($i < $num) {
621  $row = $this->db->fetch_row($resql);
622  if ($i < $limit || $num == $limit) {
623  $result[$i] = array($row[0], $row[1]); // Ref of product, nb
624  } else {
625  $other += $row[1];
626  }
627  $i++;
628  }
629  if ($num > $limit) {
630  $result[$i] = array($langs->transnoentitiesnoconv("Other"), $other);
631  }
632  $this->db->free($resql);
633  } else {
634  dol_print_error($this->db);
635  }
636 
637  return $result;
638  }
639 
640  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
646  protected function _getAmountByYear($sql)
647  {
648  $result = array();
649  $resql = $this->db->query($sql);
650  if ($resql) {
651  $num = $this->db->num_rows($resql);
652  $i = 0;
653  while ($i < $num) {
654  $row = $this->db->fetch_row($resql);
655  $j = (int) $row[0];
656  $result[] = [
657  0 => (int) $row[0],
658  1 => (int) $row[1],
659  ];
660  $i++;
661  }
662  $this->db->free($resql);
663  }
664  return $result;
665  }
666 }
db
$conf db
API class for accounts.
Definition: inc.php:41
Stats\_getAllByProduct
_getAllByProduct($sql, $limit=10)
Return number or total of product refs.
Definition: stats.class.php:607
dol_filemtime
dol_filemtime($pathoffile)
Return time of a file.
Definition: files.lib.php:593
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4830
Stats\getAverageByMonth
getAverageByMonth($year)
Stats
Parent class of statistics class.
Definition: stats.class.php:30
Stats\getNbByMonthWithPrevYear
getNbByMonthWithPrevYear($endyear, $startyear, $cachedelay=0, $format=0, $startmonth=1)
Return nb of elements by month for several years.
Definition: stats.class.php:53
Stats\_getNbByYear
_getNbByYear($sql)
Return nb of elements by year.
Definition: stats.class.php:355
Stats\_getAmountByMonth
_getAmountByMonth($year, $sql, $format=0)
Return the amount per month for a given year.
Definition: stats.class.php:492
Stats\getAverageByMonthWithPrevYear
getAverageByMonthWithPrevYear($endyear, $startyear)
Return average of entity by month for several years.
Definition: stats.class.php:249
Stats\getAmountByMonthWithPrevYear
getAmountByMonthWithPrevYear($endyear, $startyear, $cachedelay=0, $format=0, $startmonth=1)
Return amount of elements by month for several years.
Definition: stats.class.php:153
Stats\_getAllByYear
_getAllByYear($sql)
Return nb of elements, total amount and avg amount each year.
Definition: stats.class.php:384
Stats\getAllByProductEntry
getAllByProductEntry($year, $cachedelay=0, $limit=10)
Return count, and sum of products.
Definition: stats.class.php:285
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1589
Stats\getNbByMonth
getNbByMonth($year, $format=0)
Stats\_getAmountByYear
_getAmountByYear($sql)
Returns the summed amounts per year for a given number of past years ending now.
Definition: stats.class.php:646
Stats\_getNbByMonth
_getNbByMonth($year, $sql, $format=0)
Renvoie le nombre de documents par mois pour une annee donnee Return number of documents per month fo...
Definition: stats.class.php:435
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2831
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice') && $user->rights->supplier_invoice->lire)) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
Stats\getAmountByMonth
getAmountByMonth($year, $format=0)
dol_is_dir
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:447
dol_mkdir
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Definition: functions.lib.php:6589
Stats\_getAverageByMonth
_getAverageByMonth($year, $sql, $format=0)
Renvoie le montant moyen par mois pour une annee donnee Return the amount average par month for a giv...
Definition: stats.class.php:550