stats.class.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  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. /**
  21. * \file htdocs/core/class/stats.class.php
  22. * \ingroup core
  23. * \brief Common class to manage statistics reports
  24. */
  25. /**
  26. * Parent class of statistics class
  27. */
  28. abstract class Stats
  29. {
  30. protected $db;
  31. protected $lastfetchdate = array(); // Dates of cache file read by methods
  32. public $cachefilesuffix = ''; // Suffix to add to name of cache file (to avoid file name conflicts)
  33. /**
  34. * @param int $year number
  35. * @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
  36. * @return int value
  37. */
  38. protected abstract function getNbByMonth($year, $format = 0);
  39. /**
  40. * Return nb of elements by month for several years
  41. *
  42. * @param int $endyear Start year
  43. * @param int $startyear End year
  44. * @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save)
  45. * @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
  46. * @param int $startmonth month of the fiscal year start min 1 max 12 ; if 1 = january
  47. * @return array Array of values
  48. */
  49. public function getNbByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1)
  50. {
  51. global $conf, $user, $langs;
  52. if ($startyear > $endyear) {
  53. return -1;
  54. }
  55. $datay = array();
  56. // Search into cache
  57. if (!empty($cachedelay)) {
  58. include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  59. include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
  60. }
  61. $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache';
  62. $newmask = '0644';
  63. $nowgmt = dol_now();
  64. $foundintocache = 0;
  65. if ($cachedelay > 0) {
  66. $filedate = dol_filemtime($newpathofdestfile);
  67. if ($filedate >= ($nowgmt - $cachedelay)) {
  68. $foundintocache = 1;
  69. $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate;
  70. } else {
  71. 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.");
  72. }
  73. }
  74. // Load file into $data
  75. if ($foundintocache) { // Cache file found and is not too old
  76. dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
  77. $data = json_decode(file_get_contents($newpathofdestfile), true);
  78. } else {
  79. $year = $startyear;
  80. $sm = $startmonth - 1;
  81. if ($sm != 0) {
  82. $year = $year - 1;
  83. }
  84. while ($year <= $endyear) {
  85. $datay[$year] = $this->getNbByMonth($year, $format);
  86. $year++;
  87. }
  88. $data = array();
  89. for ($i = 0; $i < 12; $i++) {
  90. $data[$i][] = $datay[$endyear][($i + $sm) % 12][0];
  91. $year = $startyear;
  92. while ($year <= $endyear) {
  93. // 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
  94. $data[$i][] = $datay[$year - (1 - floor(($i + $sm) / 12)) + ($sm == 0 ? 1 : 0)][($i + $sm) % 12][1];
  95. $year++;
  96. }
  97. }
  98. }
  99. // Save cache file
  100. if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
  101. dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
  102. if (!dol_is_dir($conf->user->dir_temp)) {
  103. dol_mkdir($conf->user->dir_temp);
  104. }
  105. $fp = fopen($newpathofdestfile, 'w');
  106. fwrite($fp, json_encode($data));
  107. fclose($fp);
  108. if (!empty($conf->global->MAIN_UMASK)) {
  109. $newmask = $conf->global->MAIN_UMASK;
  110. }
  111. @chmod($newpathofdestfile, octdec($newmask));
  112. $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt;
  113. }
  114. // return array(array('Month',val1,val2,val3),...)
  115. return $data;
  116. }
  117. /**
  118. * @param int $year year number
  119. * @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
  120. * @return int value
  121. */
  122. protected abstract function getAmountByMonth($year, $format = 0);
  123. /**
  124. * Return amount of elements by month for several years.
  125. * Criterias used to build request are defined into the constructor of parent class into xxx/class/xxxstats.class.php
  126. * The caller of class can add more filters into sql request by adding criteris into the $stats->where property just after
  127. * calling constructor.
  128. *
  129. * @param int $endyear Start year
  130. * @param int $startyear End year
  131. * @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save)
  132. * @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
  133. * @param int $startmonth month of the fiscal year start min 1 max 12 ; if 1 = january
  134. * @return array Array of values
  135. */
  136. public function getAmountByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1)
  137. {
  138. global $conf, $user, $langs;
  139. if ($startyear > $endyear) {
  140. return -1;
  141. }
  142. $datay = array();
  143. // Search into cache
  144. if (!empty($cachedelay)) {
  145. include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  146. include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
  147. }
  148. $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache';
  149. $newmask = '0644';
  150. $nowgmt = dol_now();
  151. $foundintocache = 0;
  152. if ($cachedelay > 0) {
  153. $filedate = dol_filemtime($newpathofdestfile);
  154. if ($filedate >= ($nowgmt - $cachedelay)) {
  155. $foundintocache = 1;
  156. $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate;
  157. } else {
  158. 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.");
  159. }
  160. }
  161. // Load file into $data
  162. if ($foundintocache) { // Cache file found and is not too old
  163. dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
  164. $data = json_decode(file_get_contents($newpathofdestfile), true);
  165. } else {
  166. $year = $startyear;
  167. $sm = $startmonth - 1;
  168. if ($sm != 0) {
  169. $year = $year - 1;
  170. }
  171. while ($year <= $endyear) {
  172. $datay[$year] = $this->getAmountByMonth($year, $format);
  173. $year++;
  174. }
  175. $data = array();
  176. // $data = array('xval'=>array(0=>xlabel,1=>yval1,2=>yval2...),...)
  177. for ($i = 0; $i < 12; $i++) {
  178. $data[$i][] = isset($datay[$endyear][($i + $sm) % 12]['label']) ? $datay[$endyear][($i + $sm) % 12]['label'] : $datay[$endyear][($i + $sm) % 12][0]; // set label
  179. $year = $startyear;
  180. while ($year <= $endyear) {
  181. // 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
  182. $data[$i][] = $datay[$year - (1 - floor(($i + $sm) / 12)) + ($sm == 0 ? 1 : 0)][($i + $sm) % 12][1]; // set yval for x=i
  183. $year++;
  184. }
  185. }
  186. }
  187. // Save cache file
  188. if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
  189. dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
  190. if (!dol_is_dir($conf->user->dir_temp)) {
  191. dol_mkdir($conf->user->dir_temp);
  192. }
  193. $fp = fopen($newpathofdestfile, 'w');
  194. if ($fp) {
  195. fwrite($fp, json_encode($data));
  196. fclose($fp);
  197. if (!empty($conf->global->MAIN_UMASK)) {
  198. $newmask = $conf->global->MAIN_UMASK;
  199. }
  200. @chmod($newpathofdestfile, octdec($newmask));
  201. } else {
  202. dol_syslog("Failed to write cache file", LOG_ERR);
  203. }
  204. $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt;
  205. }
  206. return $data;
  207. }
  208. /**
  209. * @param int $year year number
  210. * @return int value
  211. */
  212. protected abstract function getAverageByMonth($year);
  213. /**
  214. * Return average of entity by month for several years
  215. *
  216. * @param int $endyear Start year
  217. * @param int $startyear End year
  218. * @return array Array of values
  219. */
  220. public function getAverageByMonthWithPrevYear($endyear, $startyear)
  221. {
  222. if ($startyear > $endyear) {
  223. return -1;
  224. }
  225. $datay = array();
  226. $year = $startyear;
  227. while ($year <= $endyear) {
  228. $datay[$year] = $this->getAverageByMonth($year);
  229. $year++;
  230. }
  231. $data = array();
  232. for ($i = 0; $i < 12; $i++) {
  233. $data[$i][] = $datay[$endyear][$i][0];
  234. $year = $startyear;
  235. while ($year <= $endyear) {
  236. $data[$i][] = $datay[$year][$i][1];
  237. $year++;
  238. }
  239. }
  240. return $data;
  241. }
  242. /**
  243. * Return count, and sum of products
  244. *
  245. * @param int $year Year
  246. * @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save)
  247. * @param int $limit Limit
  248. * @return array Array of values
  249. */
  250. public function getAllByProductEntry($year, $cachedelay = 0, $limit = 10)
  251. {
  252. global $conf, $user, $langs;
  253. $data = array();
  254. // Search into cache
  255. if (!empty($cachedelay)) {
  256. include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  257. include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
  258. }
  259. $newpathofdestfile = $conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix) ? '' : $this->cachefilesuffix.'_').$langs->defaultlang.'_entity.'.$conf->entity.'_user'.$user->id.'.cache';
  260. $newmask = '0644';
  261. $nowgmt = dol_now();
  262. $foundintocache = 0;
  263. if ($cachedelay > 0) {
  264. $filedate = dol_filemtime($newpathofdestfile);
  265. if ($filedate >= ($nowgmt - $cachedelay)) {
  266. $foundintocache = 1;
  267. $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $filedate;
  268. } else {
  269. 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.");
  270. }
  271. }
  272. // Load file into $data
  273. if ($foundintocache) { // Cache file found and is not too old
  274. dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
  275. $data = json_decode(file_get_contents($newpathofdestfile), true);
  276. } else {
  277. $data = $this->getAllByProduct($year, $limit);
  278. // $data[$i][]=$datay[$year][$i][1]; // set yval for x=i
  279. }
  280. // Save cache file
  281. if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
  282. dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
  283. if (!dol_is_dir($conf->user->dir_temp)) {
  284. dol_mkdir($conf->user->dir_temp);
  285. }
  286. $fp = fopen($newpathofdestfile, 'w');
  287. if ($fp) {
  288. fwrite($fp, json_encode($data));
  289. fclose($fp);
  290. if (!empty($conf->global->MAIN_UMASK)) {
  291. $newmask = $conf->global->MAIN_UMASK;
  292. }
  293. @chmod($newpathofdestfile, octdec($newmask));
  294. }
  295. $this->lastfetchdate[get_class($this).'_'.__FUNCTION__] = $nowgmt;
  296. }
  297. return $data;
  298. }
  299. // Here we have low level of shared code called by XxxStats.class.php
  300. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  301. /**
  302. * Return nb of elements by year
  303. *
  304. * @param string $sql SQL request
  305. * @return array
  306. */
  307. protected function _getNbByYear($sql)
  308. {
  309. // phpcs:enable
  310. $result = array();
  311. dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
  312. $resql = $this->db->query($sql);
  313. if ($resql) {
  314. $num = $this->db->num_rows($resql);
  315. $i = 0;
  316. while ($i < $num) {
  317. $row = $this->db->fetch_row($resql);
  318. $result[$i] = $row;
  319. $i++;
  320. }
  321. $this->db->free($resql);
  322. } else {
  323. dol_print_error($this->db);
  324. }
  325. return $result;
  326. }
  327. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  328. /**
  329. * Return nb of elements, total amount and avg amount each year
  330. *
  331. * @param string $sql SQL request
  332. * @return array Array with nb, total amount, average for each year
  333. */
  334. protected function _getAllByYear($sql)
  335. {
  336. // phpcs:enable
  337. $result = array();
  338. dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
  339. $resql = $this->db->query($sql);
  340. if ($resql) {
  341. $num = $this->db->num_rows($resql);
  342. $i = 0;
  343. while ($i < $num) {
  344. $row = $this->db->fetch_object($resql);
  345. $result[$i]['year'] = $row->year;
  346. $result[$i]['nb'] = $row->nb;
  347. if ($i > 0 && $row->nb > 0) {
  348. $result[$i - 1]['nb_diff'] = ($result[$i - 1]['nb'] - $row->nb) / $row->nb * 100;
  349. }
  350. $result[$i]['total'] = $row->total;
  351. if ($i > 0 && $row->total > 0) {
  352. $result[$i - 1]['total_diff'] = ($result[$i - 1]['total'] - $row->total) / $row->total * 100;
  353. }
  354. $result[$i]['avg'] = $row->avg;
  355. if ($i > 0 && $row->avg > 0) {
  356. $result[$i - 1]['avg_diff'] = ($result[$i - 1]['avg'] - $row->avg) / $row->avg * 100;
  357. }
  358. // For some $sql only
  359. if (isset($row->weighted)) {
  360. $result[$i]['weighted'] = $row->weighted;
  361. if ($i > 0 && $row->weighted > 0) {
  362. $result[$i - 1]['avg_weighted'] = ($result[$i - 1]['weighted'] - $row->weighted) / $row->weighted * 100;
  363. }
  364. }
  365. $i++;
  366. }
  367. $this->db->free($resql);
  368. } else {
  369. dol_print_error($this->db);
  370. }
  371. return $result;
  372. }
  373. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  374. /**
  375. * Renvoie le nombre de documents par mois pour une annee donnee
  376. * Return number of documents per month for a given year
  377. *
  378. * @param int $year Year
  379. * @param string $sql SQL
  380. * @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
  381. * @return array Array of nb each month
  382. */
  383. protected function _getNbByMonth($year, $sql, $format = 0)
  384. {
  385. // phpcs:enable
  386. global $langs;
  387. $result = array();
  388. $res = array();
  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. $j = 0;
  395. while ($i < $num) {
  396. $row = $this->db->fetch_row($resql);
  397. $j = $row[0] * 1;
  398. $result[$j] = $row[1];
  399. $i++;
  400. }
  401. $this->db->free($resql);
  402. } else {
  403. dol_print_error($this->db);
  404. }
  405. for ($i = 1; $i < 13; $i++) {
  406. $res[$i] = (isset($result[$i]) ? $result[$i] : 0);
  407. }
  408. $data = array();
  409. for ($i = 1; $i < 13; $i++) {
  410. $month = 'unknown';
  411. if ($format == 0) {
  412. $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
  413. } elseif ($format == 1) {
  414. $month = $i;
  415. } elseif ($format == 2) {
  416. $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
  417. }
  418. //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
  419. //$month=dol_substr($month,0,3);
  420. $data[$i - 1] = array($month, $res[$i]);
  421. }
  422. return $data;
  423. }
  424. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  425. /**
  426. * Return the amount per month for a given year
  427. *
  428. * @param int $year Year
  429. * @param string $sql SQL
  430. * @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
  431. * @return array
  432. */
  433. protected function _getAmountByMonth($year, $sql, $format = 0)
  434. {
  435. // phpcs:enable
  436. global $langs;
  437. $result = array();
  438. $res = array();
  439. dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
  440. $resql = $this->db->query($sql);
  441. if ($resql) {
  442. $num = $this->db->num_rows($resql);
  443. $i = 0;
  444. while ($i < $num) {
  445. $row = $this->db->fetch_row($resql);
  446. $j = $row[0] * 1;
  447. $result[$j] = $row[1];
  448. $i++;
  449. }
  450. $this->db->free($resql);
  451. } else {
  452. dol_print_error($this->db);
  453. }
  454. for ($i = 1; $i < 13; $i++) {
  455. $res[$i] = (int) round((isset($result[$i]) ? $result[$i] : 0));
  456. }
  457. $data = array();
  458. for ($i = 1; $i < 13; $i++) {
  459. $month = 'unknown';
  460. if ($format == 0) {
  461. $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
  462. } elseif ($format == 1) {
  463. $month = $i;
  464. } elseif ($format == 2) {
  465. $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
  466. }
  467. //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
  468. //$month=dol_substr($month,0,3);
  469. $data[$i - 1] = array($month, $res[$i]);
  470. }
  471. return $data;
  472. }
  473. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  474. /**
  475. * Renvoie le montant moyen par mois pour une annee donnee
  476. * Return the amount average par month for a given year
  477. *
  478. * @param int $year Year
  479. * @param string $sql SQL
  480. * @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
  481. * @return array
  482. */
  483. protected function _getAverageByMonth($year, $sql, $format = 0)
  484. {
  485. // phpcs:enable
  486. global $langs;
  487. $result = array();
  488. $res = array();
  489. dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
  490. $resql = $this->db->query($sql);
  491. if ($resql) {
  492. $num = $this->db->num_rows($resql);
  493. $i = 0;
  494. $j = 0;
  495. while ($i < $num) {
  496. $row = $this->db->fetch_row($resql);
  497. $j = $row[0] * 1;
  498. $result[$j] = $row[1];
  499. $i++;
  500. }
  501. $this->db->free($resql);
  502. } else {
  503. dol_print_error($this->db);
  504. }
  505. for ($i = 1; $i < 13; $i++) {
  506. $res[$i] = (isset($result[$i]) ? $result[$i] : 0);
  507. }
  508. $data = array();
  509. for ($i = 1; $i < 13; $i++) {
  510. $month = 'unknown';
  511. if ($format == 0) {
  512. $month = $langs->transnoentitiesnoconv('MonthShort'.sprintf("%02d", $i));
  513. } elseif ($format == 1) {
  514. $month = $i;
  515. } elseif ($format == 2) {
  516. $month = $langs->transnoentitiesnoconv('MonthVeryShort'.sprintf("%02d", $i));
  517. }
  518. //$month=dol_print_date(dol_mktime(12,0,0,$i,1,$year),($format?"%m":"%b"));
  519. //$month=dol_substr($month,0,3);
  520. $data[$i - 1] = array($month, $res[$i]);
  521. }
  522. return $data;
  523. }
  524. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  525. /**
  526. * Return number or total of product refs
  527. *
  528. * @param string $sql SQL
  529. * @param int $limit Limit
  530. * @return array
  531. */
  532. protected function _getAllByProduct($sql, $limit = 10)
  533. {
  534. // phpcs:enable
  535. global $langs;
  536. $result = array();
  537. dol_syslog(get_class($this).'::'.__FUNCTION__."", LOG_DEBUG);
  538. $resql = $this->db->query($sql);
  539. if ($resql) {
  540. $num = $this->db->num_rows($resql);
  541. $i = 0;
  542. $other = 0;
  543. while ($i < $num) {
  544. $row = $this->db->fetch_row($resql);
  545. if ($i < $limit || $num == $limit) {
  546. $result[$i] = array($row[0], $row[1]); // Ref of product, nb
  547. } else {
  548. $other += $row[1];
  549. }
  550. $i++;
  551. }
  552. if ($num > $limit) {
  553. $result[$i] = array($langs->transnoentitiesnoconv("Other"), $other);
  554. }
  555. $this->db->free($resql);
  556. } else {
  557. dol_print_error($this->db);
  558. }
  559. return $result;
  560. }
  561. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  562. /**
  563. * Returns the summed amounts per year for a given number of past years ending now
  564. * @param string $sql SQL
  565. * @return array
  566. */
  567. protected function _getAmountByYear($sql)
  568. {
  569. $result = array();
  570. $resql = $this->db->query($sql);
  571. if ($resql) {
  572. $num = $this->db->num_rows($resql);
  573. $i = 0;
  574. while ($i < $num) {
  575. $row = $this->db->fetch_row($resql);
  576. $j = (int) $row[0];
  577. $result[] = [
  578. 0 => (int) $row[0],
  579. 1 => (int) $row[1],
  580. ];
  581. $i++;
  582. }
  583. $this->db->free($resql);
  584. }
  585. return $result;
  586. }
  587. }