dolibarr  18.0.0-alpha
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  $result[$i]['total'] = $row->total;
395  if ($i > 0 && $row->total > 0) {
396  $result[$i - 1]['total_diff'] = ($result[$i - 1]['total'] - $row->total) / $row->total * 100;
397  }
398  $result[$i]['avg'] = $row->avg;
399  if ($i > 0 && $row->avg > 0) {
400  $result[$i - 1]['avg_diff'] = ($result[$i - 1]['avg'] - $row->avg) / $row->avg * 100;
401  }
402  // For some $sql only
403  if (isset($row->weighted)) {
404  $result[$i]['weighted'] = $row->weighted;
405  if ($i > 0 && $row->weighted > 0) {
406  $result[$i - 1]['avg_weighted'] = ($result[$i - 1]['weighted'] - $row->weighted) / $row->weighted * 100;
407  }
408  }
409  $i++;
410  }
411  $this->db->free($resql);
412  } else {
413  dol_print_error($this->db);
414  }
415  return $result;
416  }
417 
418  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
428  protected function _getNbByMonth($year, $sql, $format = 0)
429  {
430  // phpcs:enable
431  global $langs;
432 
433  $result = array();
434  $res = array();
435 
436  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
437  $resql = $this->db->query($sql);
438  if ($resql) {
439  $num = $this->db->num_rows($resql);
440  $i = 0;
441  $j = 0;
442  while ($i < $num) {
443  $row = $this->db->fetch_row($resql);
444  $j = $row[0] * 1;
445  $result[$j] = $row[1];
446  $i++;
447  }
448  $this->db->free($resql);
449  } else {
450  dol_print_error($this->db);
451  }
452 
453  for ($i = 1; $i < 13; $i++) {
454  $res[$i] = (isset($result[$i]) ? $result[$i] : 0);
455  }
456 
457  $data = array();
458 
459  for ($i = 1; $i < 13; $i++) {
460  $month = 'unknown';
461  if ($format == 0) {
462  $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
463  } elseif ($format == 1) {
464  $month = $i;
465  } elseif ($format == 2) {
466  $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
467  }
468  //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
469  //$month=dol_substr($month,0,3);
470  $data[$i - 1] = array($month, $res[$i]);
471  }
472 
473  return $data;
474  }
475 
476  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
485  protected function _getAmountByMonth($year, $sql, $format = 0)
486  {
487  // phpcs:enable
488  global $langs;
489 
490  $result = array();
491  $res = array();
492 
493  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
494 
495  $resql = $this->db->query($sql);
496  if ($resql) {
497  $num = $this->db->num_rows($resql);
498  $i = 0;
499  while ($i < $num) {
500  $row = $this->db->fetch_row($resql);
501  $j = $row[0] * 1;
502  $result[$j] = $row[1];
503  $i++;
504  }
505  $this->db->free($resql);
506  } else {
507  dol_print_error($this->db);
508  }
509 
510  for ($i = 1; $i < 13; $i++) {
511  $res[$i] = (int) round((isset($result[$i]) ? $result[$i] : 0));
512  }
513 
514  $data = array();
515 
516  for ($i = 1; $i < 13; $i++) {
517  $month = 'unknown';
518  if ($format == 0) {
519  $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
520  } elseif ($format == 1) {
521  $month = $i;
522  } elseif ($format == 2) {
523  $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
524  }
525  //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
526  //$month=dol_substr($month,0,3);
527  $data[$i - 1] = array($month, $res[$i]);
528  }
529 
530  return $data;
531  }
532 
533  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
543  protected function _getAverageByMonth($year, $sql, $format = 0)
544  {
545  // phpcs:enable
546  global $langs;
547 
548  $result = array();
549  $res = array();
550 
551  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
552  $resql = $this->db->query($sql);
553  if ($resql) {
554  $num = $this->db->num_rows($resql);
555  $i = 0;
556  $j = 0;
557  while ($i < $num) {
558  $row = $this->db->fetch_row($resql);
559  $j = $row[0] * 1;
560  $result[$j] = $row[1];
561  $i++;
562  }
563  $this->db->free($resql);
564  } else {
565  dol_print_error($this->db);
566  }
567 
568  for ($i = 1; $i < 13; $i++) {
569  $res[$i] = (isset($result[$i]) ? $result[$i] : 0);
570  }
571 
572  $data = array();
573 
574  for ($i = 1; $i < 13; $i++) {
575  $month = 'unknown';
576  if ($format == 0) {
577  $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
578  } elseif ($format == 1) {
579  $month = $i;
580  } elseif ($format == 2) {
581  $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
582  }
583  //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
584  //$month=dol_substr($month,0,3);
585  $data[$i - 1] = array($month, $res[$i]);
586  }
587 
588  return $data;
589  }
590 
591 
592  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
600  protected function _getAllByProduct($sql, $limit = 10)
601  {
602  // phpcs:enable
603  global $langs;
604 
605  $result = array();
606 
607  dol_syslog(get_class($this).'::'.__FUNCTION__, LOG_DEBUG);
608  $resql = $this->db->query($sql);
609  if ($resql) {
610  $num = $this->db->num_rows($resql);
611  $i = 0;
612  $other = 0;
613  while ($i < $num) {
614  $row = $this->db->fetch_row($resql);
615  if ($i < $limit || $num == $limit) {
616  $result[$i] = array($row[0], $row[1]); // Ref of product, nb
617  } else {
618  $other += $row[1];
619  }
620  $i++;
621  }
622  if ($num > $limit) {
623  $result[$i] = array($langs->transnoentitiesnoconv("Other"), $other);
624  }
625  $this->db->free($resql);
626  } else {
627  dol_print_error($this->db);
628  }
629 
630  return $result;
631  }
632 
633  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
639  protected function _getAmountByYear($sql)
640  {
641  $result = array();
642  $resql = $this->db->query($sql);
643  if ($resql) {
644  $num = $this->db->num_rows($resql);
645  $i = 0;
646  while ($i < $num) {
647  $row = $this->db->fetch_row($resql);
648  $j = (int) $row[0];
649  $result[] = [
650  0 => (int) $row[0],
651  1 => (int) $row[1],
652  ];
653  $i++;
654  }
655  $this->db->free($resql);
656  }
657  return $result;
658  }
659 }
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:600
dol_filemtime
dol_filemtime($pathoffile)
Return time of a file.
Definition: files.lib.php:597
$sql
if(isModEnabled('facture') &&!empty($user->rights->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') &&!empty($user->rights->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:745
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:4994
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:348
Stats\_getAmountByMonth
_getAmountByMonth($year, $sql, $format=0)
Return the amount per month for a given year.
Definition: stats.class.php:485
dolChmod
dolChmod($filepath, $newmask='')
Change mod of a file.
Definition: functions.lib.php:6882
Stats\getAverageByMonthWithPrevYear
getAverageByMonthWithPrevYear($endyear, $startyear)
Return average of entity by month for several years.
Definition: stats.class.php:245
Stats\getAmountByMonthWithPrevYear
getAmountByMonthWithPrevYear($endyear, $startyear, $cachedelay=0, $format=0, $startmonth=1)
Return amount of elements by month for several years.
Definition: stats.class.php:151
Stats\_getAllByYear
_getAllByYear($sql)
Return nb of elements, total amount and avg amount each year.
Definition: stats.class.php:377
Stats\getAllByProductEntry
getAllByProductEntry($year, $cachedelay=0, $limit=10)
Return count, and sum of products.
Definition: stats.class.php:281
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1639
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:639
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:428
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2947
Stats\getAmountByMonth
getAmountByMonth($year, $format=0)
dol_is_dir
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:451
dol_mkdir
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Definition: functions.lib.php:6811
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:543