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
30abstract 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.
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.
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...
dol_filemtime($pathoffile)
Return time of a file.
dol_is_dir($folder)
Test if filename is a directory.
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)