dolibarr  x.y.z
customreports.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2020 Laurent Destailleur <eldy@users.sourceforge.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  *
17  * Note: This tool can be included into a list page with :
18  * define('USE_CUSTOM_REPORT_AS_INCLUDE', 1);
19  * include DOL_DOCUMENT_ROOT.'/core/customreports.php';
20  */
21 
28 if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) {
29  require '../main.inc.php';
30 
31  // Get parameters
32  $action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ...
33  $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists)
34 
35  $mode = GETPOST('mode', 'alpha') ? GETPOST('mode', 'alpha') : 'graph';
36  $objecttype = GETPOST('objecttype', 'aZ09');
37  $tabfamily = GETPOST('tabfamily', 'aZ09');
38 
39  if (empty($objecttype)) {
40  $objecttype = 'thirdparty';
41  }
42 
43  $search_measures = GETPOST('search_measures', 'array');
44 
45  //$search_xaxis = GETPOST('search_xaxis', 'array');
46  if (GETPOST('search_xaxis', 'alpha') && GETPOST('search_xaxis', 'alpha') != '-1') {
47  $search_xaxis = array(GETPOST('search_xaxis', 'alpha'));
48  } else {
49  $search_xaxis = array();
50  }
51  //$search_groupby = GETPOST('search_groupby', 'array');
52  if (GETPOST('search_groupby', 'alpha') && GETPOST('search_groupby', 'alpha') != '-1') {
53  $search_groupby = array(GETPOST('search_groupby', 'alpha'));
54  } else {
55  $search_groupby = array();
56  }
57 
58  $search_yaxis = GETPOST('search_yaxis', 'array');
59  $search_graph = GETPOST('search_graph', 'restricthtml');
60 
61  // Load variable for pagination
62  $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;
63  $sortfield = GETPOST('sortfield', 'aZ09comma');
64  $sortorder = GETPOST('sortorder', 'aZ09comma');
65  $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
66  if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) {
67  $page = 0;
68  } // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action
69  $offset = $limit * $page;
70  $pageprev = $page - 1;
71  $pagenext = $page + 1;
72 
73  $diroutputmassaction = $conf->user->dir_temp.'/'.$user->id.'/customreport';
74 }
75 
76 require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";
77 require_once DOL_DOCUMENT_ROOT."/core/lib/company.lib.php";
78 require_once DOL_DOCUMENT_ROOT."/core/class/dolgraph.class.php";
79 require_once DOL_DOCUMENT_ROOT."/core/class/doleditor.class.php";
80 require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
81 
82 // Load traductions files requiredby by page
83 $langs->loadLangs(array("companies", "other", "exports", "sendings"));
84 
85 $extrafields = new ExtraFields($db);
86 
87 $hookmanager->initHooks(array('customreport')); // Note that conf->hooks_modules contains array
88 
89 $title = '';
90 $picto = '';
91 $head = array();
92 $object = null;
93 $ObjectClassName = '';
94 // Objects available by default
95 $arrayoftype = array(
96  'thirdparty' => array('label' => 'ThirdParties', 'ObjectClassName' => 'Societe', 'enabled' => isModEnabled('societe'), 'ClassPath' => "/societe/class/societe.class.php"),
97  'contact' => array('label' => 'Contacts', 'ObjectClassName' => 'Contact', 'enabled' => isModEnabled('societ'), 'ClassPath' => "/contact/class/contact.class.php"),
98  'proposal' => array('label' => 'Proposals', 'ObjectClassName' => 'Propal', 'enabled' => isModEnabled('propal'), 'ClassPath' => "/comm/propal/class/propal.class.php"),
99  'order' => array('label' => 'Orders', 'ObjectClassName' => 'Commande', 'enabled' => isModEnabled('commande'), 'ClassPath' => "/commande/class/commande.class.php"),
100  'invoice' => array('label' => 'Invoices', 'ObjectClassName' => 'Facture', 'enabled' => isModEnabled('facture'), 'ClassPath' => "/compta/facture/class/facture.class.php"),
101  'invoice_template'=>array('label' => 'PredefinedInvoices', 'ObjectClassName' => 'FactureRec', 'enabled' => isModEnabled('facture'), 'ClassPath' => "/compta/class/facturerec.class.php", 'langs'=>'bills'),
102  'contract' => array('label' => 'Contracts', 'ObjectClassName' => 'Contrat', 'enabled' => isModEnabled('contrat'), 'ClassPath' => "/contrat/class/contrat.class.php", 'langs'=>'contracts'),
103  'contractdet' => array('label' => 'ContractLines', 'ObjectClassName' => 'ContratLigne', 'enabled' => isModEnabled('contrat'), 'ClassPath' => "/contrat/class/contrat.class.php", 'langs'=>'contracts'),
104  'bom' => array('label' => 'BOM', 'ObjectClassName' => 'Bom', 'enabled' => isModEnabled('bom')),
105  'mo' => array('label' => 'MO', 'ObjectClassName' => 'Mo', 'enabled' => isModEnabled('mrp'), 'ClassPath' => "/mrp/class/mo.class.php"),
106  'ticket' => array('label' => 'Ticket', 'ObjectClassName' => 'Ticket', 'enabled' => isModEnabled('ticket')),
107  'member' => array('label' => 'Adherent', 'ObjectClassName' => 'Adherent', 'enabled' => isModEnabled('adherent'), 'ClassPath' => "/adherents/class/adherent.class.php", 'langs'=>'members'),
108  'cotisation' => array('label' => 'Subscriptions', 'ObjectClassName' => 'Subscription', 'enabled' => isModEnabled('adherent'), 'ClassPath' => "/adherents/class/subscription.class.php", 'langs'=>'members'),
109 );
110 
111 // Complete $arrayoftype by external modules
112 $parameters = array('objecttype'=>$objecttype, 'tabfamily'=>$tabfamily);
113 $reshook = $hookmanager->executeHooks('loadDataForCustomReports', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
114 if ($reshook < 0) {
115  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
116 } elseif (is_array($hookmanager->resArray)) {
117  if (!empty($hookmanager->resArray['title'])) { // Add entries for tabs
118  $title = $hookmanager->resArray['title'];
119  }
120  if (!empty($hookmanager->resArray['picto'])) { // Add entries for tabs
121  $picto = $hookmanager->resArray['picto'];
122  }
123  if (!empty($hookmanager->resArray['head'])) { // Add entries for tabs
124  $head = array_merge($head, $hookmanager->resArray['head']);
125  }
126  if (!empty($hookmanager->resArray['arrayoftype'])) { // Add entries from hook
127  foreach ($hookmanager->resArray['arrayoftype'] as $key => $val) {
128  $arrayoftype[$key] = $val;
129  }
130  }
131 }
132 
133 if ($objecttype) {
134  try {
135  if (!empty($arrayoftype[$objecttype]['ClassPath'])) {
136  dol_include_once($arrayoftype[$objecttype]['ClassPath']);
137  } else {
138  dol_include_once("/".$objecttype."/class/".$objecttype.".class.php");
139  }
140  $ObjectClassName = $arrayoftype[$objecttype]['ObjectClassName'];
141  $object = new $ObjectClassName($db);
142  } catch (Exception $e) {
143  print 'Failed to load class for type '.$objecttype;
144  }
145 }
146 
147 // Security check
148 $socid = 0;
149 if ($user->socid > 0) { // Protection if external user
150  //$socid = $user->socid;
151  accessforbidden();
152 }
153 
154 // Fetch optionals attributes and labels
155 $extrafields->fetch_name_optionals_label($object->table_element);
156 //$extrafields->fetch_name_optionals_label($object->table_element_line);
157 
158 $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
159 
160 $search_component_params = array('');
161 $search_component_params_hidden = GETPOST('search_component_params_hidden', 'alphanohtml');
162 
163 // For the case we enter a criteria manually, the search_component_params_input will be defined and must be used in priority
164 if (GETPOST('search_component_params_input', 'alphanohtml')) {
165  $search_component_params_hidden = GETPOST('search_component_params_input', 'alphanohtml');
166 }
167 
168 $MAXUNIQUEVALFORGROUP = 20;
169 $MAXMEASURESINBARGRAPH = 20;
170 
171 $YYYY = substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1);
172 $MM = substr($langs->trans("Month"), 0, 1).substr($langs->trans("Month"), 0, 1);
173 $DD = substr($langs->trans("Day"), 0, 1).substr($langs->trans("Day"), 0, 1);
174 $HH = substr($langs->trans("Hour"), 0, 1).substr($langs->trans("Hour"), 0, 1);
175 $MI = substr($langs->trans("Minute"), 0, 1).substr($langs->trans("Minute"), 0, 1);
176 $SS = substr($langs->trans("Second"), 0, 1).substr($langs->trans("Second"), 0, 1);
177 
178 $arrayofmesures = array();
179 $arrayofxaxis = array();
180 $arrayofgroupby = array();
181 $arrayofyaxis = array();
182 $arrayofvaluesforgroupby = array();
183 
184 $features = $object->element;
185 if (!empty($object->element_for_permission)) {
186  $features = $object->element_for_permission;
187 }
188 
189 restrictedArea($user, $features, 0, '');
190 
191 $error = 0;
192 
193 
194 /*
195  * Actions
196  */
197 
198 // None
199 
200 
201 
202 /*
203  * View
204  */
205 
206 $form = new Form($db);
207 $formother = new FormOther($db);
208 
209 if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) {
210  llxHeader('', $langs->transnoentitiesnoconv('CustomReports'), '');
211 
212  print dol_get_fiche_head($head, 'customreports', $title, -1, $picto);
213 }
214 
215 $newarrayoftype = array();
216 foreach ($arrayoftype as $key => $val) {
217  if (dol_eval($val['enabled'], 1, 1, '1')) {
218  $newarrayoftype[$key] = $arrayoftype[$key];
219  }
220  if (!empty($val['langs'])) {
221  $langs->load($val['langs']);
222  }
223 }
224 
225 $count = 0;
226 $arrayofmesures = fillArrayOfMeasures($object, 't', $langs->trans($newarrayoftype[$objecttype]['label']), $arrayofmesures, 0, $count);
227 $arrayofmesures = dol_sort_array($arrayofmesures, 'position', 'asc', 0, 0, 1);
228 
229 $count = 0;
230 $arrayofxaxis = fillArrayOfXAxis($object, 't', $langs->trans($newarrayoftype[$objecttype]['label']), $arrayofxaxis, 0, $count);
231 $arrayofxaxis = dol_sort_array($arrayofxaxis, 'position', 'asc', 0, 0, 1);
232 
233 $count = 0;
234 $arrayofgroupby = fillArrayOfGroupBy($object, 't', $langs->trans($newarrayoftype[$objecttype]['label']), $arrayofgroupby, 0, $count);
235 $arrayofgroupby = dol_sort_array($arrayofgroupby, 'position', 'asc', 0, 0, 1);
236 
237 
238 // Check parameters
239 if ($action == 'viewgraph') {
240  if (!count($search_measures)) {
241  setEventMessages($langs->trans("AtLeastOneMeasureIsRequired"), null, 'warnings');
242  } elseif ($mode == 'graph' && count($search_xaxis) > 1) {
243  setEventMessages($langs->trans("OnlyOneFieldForXAxisIsPossible"), null, 'warnings');
244  $search_xaxis = array(0 => $search_xaxis[0]);
245  }
246  if (count($search_groupby) >= 2) {
247  setEventMessages($langs->trans("ErrorOnlyOneFieldForGroupByIsPossible"), null, 'warnings');
248  $search_groupby = array(0 => $search_groupby[0]);
249  }
250  if (!count($search_xaxis)) {
251  setEventMessages($langs->trans("AtLeastOneXAxisIsRequired"), null, 'warnings');
252  } elseif ($mode == 'graph' && $search_graph == 'bars' && count($search_measures) > $MAXMEASURESINBARGRAPH) {
253  $langs->load("errors");
254  setEventMessages($langs->trans("GraphInBarsAreLimitedToNMeasures", $MAXMEASURESINBARGRAPH), null, 'warnings');
255  $search_graph = 'lines';
256  }
257 }
258 
259 // Get all possible values of fields when a 'group by' is set, and save this into $arrayofvaluesforgroupby
260 // $arrayofvaluesforgroupby will be used to forge lael of each grouped series
261 if (is_array($search_groupby) && count($search_groupby)) {
262  foreach ($search_groupby as $gkey => $gval) {
263  $gvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $gval);
264 
265  if (preg_match('/\-year$/', $search_groupby[$gkey])) {
266  $tmpval = preg_replace('/\-year$/', '', $search_groupby[$gkey]);
267  $fieldtocount .= 'DATE_FORMAT('.$tmpval.", '%Y')";
268  } elseif (preg_match('/\-month$/', $search_groupby[$gkey])) {
269  $tmpval = preg_replace('/\-month$/', '', $search_groupby[$gkey]);
270  $fieldtocount .= 'DATE_FORMAT('.$tmpval.", '%Y-%m')";
271  } elseif (preg_match('/\-day$/', $search_groupby[$gkey])) {
272  $tmpval = preg_replace('/\-day$/', '', $search_groupby[$gkey]);
273  $fieldtocount .= 'DATE_FORMAT('.$tmpval.", '%Y-%m-%d')";
274  } else {
275  $fieldtocount = $search_groupby[$gkey];
276  }
277 
278  $sql = "SELECT DISTINCT ".$fieldtocount." as val";
279 
280  if (strpos($fieldtocount, 'te.') === 0) {
281  $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element."_extrafields as te";
282  } else {
283  $tabletouse = $object->table_element;
284  $tablealiastouse = 't';
285  if (!empty($arrayofgroupby[$gval])) {
286  $tmpval = explode('.', $gval);
287  $tabletouse = $arrayofgroupby[$gval]['table'];
288  $tablealiastouse = $tmpval[0];
289  }
290  $sql .= " FROM ".MAIN_DB_PREFIX.$tabletouse." as ".$tablealiastouse;
291  }
292 
293  // Add the where here
294  /*
295  $sqlfilters = GETPOST('search_component_params_hidden', 'alphanohtml');
296  if ($sqlfilters) {
297  $errormessage = '';
298  if (dolCheckFilters($sqlfilters, $errormessage)) {
299  $regexstring = '\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^\‍(\‍)]+)\‍)';
300  $sql .= " WHERE (".preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $sqlfilters).")";
301  } else {
302  print $errormessage;
303  }
304  }*/
305 
306  $sql .= " LIMIT ".((int) ($MAXUNIQUEVALFORGROUP + 1));
307 
308  //print $sql;
309  $resql = $db->query($sql);
310  if (!$resql) {
311  dol_print_error($db);
312  }
313 
314  while ($obj = $db->fetch_object($resql)) {
315  if (is_null($obj->val)) {
316  $keytouse = '__NULL__';
317  $valuetranslated = $langs->transnoentitiesnoconv("NotDefined");
318  } elseif ($obj->val === '') {
319  $keytouse = '';
320  $valuetranslated = $langs->transnoentitiesnoconv("Empty");
321  } else {
322  $keytouse = (string) $obj->val;
323  $valuetranslated = $obj->val;
324  }
325 
326  $regs = array();
327  if (!empty($object->fields[$gvalwithoutprefix]['arrayofkeyval'])) {
328  $valuetranslated = $object->fields[$gvalwithoutprefix]['arrayofkeyval'][$obj->val];
329  if (is_null($valuetranslated)) {
330  $valuetranslated = $langs->transnoentitiesnoconv("UndefinedKey");
331  }
332  $valuetranslated = $langs->trans($valuetranslated);
333  } elseif (preg_match('/integer:([^:]+):([^:]+)$/', $object->fields[$gvalwithoutprefix]['type'], $regs)) {
334  $classname = $regs[1];
335  $classpath = $regs[2];
336  dol_include_once($classpath);
337  if (class_exists($classname)) {
338  $tmpobject = new $classname($db);
339  $tmpobject->fetch($obj->val);
340  foreach ($tmpobject->fields as $fieldkey => $field) {
341  if ($field['showoncombobox']) {
342  $valuetranslated = $tmpobject->$fieldkey;
343  //if ($valuetranslated == '-') $valuetranslated = $langs->transnoentitiesnoconv("Unknown")
344  break;
345  }
346  }
347  //$valuetranslated = $tmpobject->ref.'eee';
348  }
349  }
350 
351  $arrayofvaluesforgroupby['g_'.$gkey][$keytouse] = $valuetranslated;
352  }
353  // Add also the possible NULL value if field is a parent field that is not a strict join
354  $tmpfield = explode('.', $gval);
355  if ($tmpfield[0] != 't' || (is_array($object->fields[$tmpfield[1]]) && empty($object->fields[$tmpfield[1]]['notnull']))) {
356  dol_syslog("The group by field ".$gval." may be null (because field is null or it is a left join), so we add __NULL__ entry in list of possible values");
357  //var_dump($gval); var_dump($object->fields);
358  $arrayofvaluesforgroupby['g_'.$gkey]['__NULL__'] = $langs->transnoentitiesnoconv("NotDefined");
359  }
360 
361  asort($arrayofvaluesforgroupby['g_'.$gkey]);
362 
363  // Add a protection/error to refuse the request if number of differentr values for the group by is higher than $MAXUNIQUEVALFORGROUP
364  if (count($arrayofvaluesforgroupby['g_'.$gkey]) > $MAXUNIQUEVALFORGROUP) {
365  $langs->load("errors");
366  if (strpos($fieldtocount, 'te.') === 0) { // This is an extrafield
367  //if (!empty($extrafields->attributes[$object->table_element]['langfile'][$gvalwithoutprefix])) {
368  // $langs->load($extrafields->attributes[$object->table_element]['langfile'][$gvalwithoutprefix]);
369  //}
370  $keyforlabeloffield = $extrafields->attributes[$object->table_element]['label'][$gvalwithoutprefix];
371  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield);
372  } elseif (strpos($fieldtocount, 't__') === 0) { // This is a field of a foreign key
373  $reg = array();
374  if (preg_match('/^(.*)\.(.*)/', $gvalwithoutprefix, $reg)) {
375  $gvalwithoutprefix = preg_replace('/\..*$/', '', $gvalwithoutprefix);
376  $gvalwithoutprefix = preg_replace('/t__/', '', $gvalwithoutprefix);
377  $keyforlabeloffield = $object->fields[$gvalwithoutprefix]['label'];
378  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield).'-'.$reg[2];
379  } else {
380  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield);
381  }
382  } else { // This is a common field
383  $reg = array();
384  if (preg_match('/^(.*)\-(year|month|day)/', $gvalwithoutprefix, $reg)) {
385  $gvalwithoutprefix = preg_replace('/\-(year|month|day)/', '', $gvalwithoutprefix);
386  $keyforlabeloffield = $object->fields[$gvalwithoutprefix]['label'];
387  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield).'-'.$reg[2];
388  } else {
389  $keyforlabeloffield = $object->fields[$gvalwithoutprefix]['label'];
390  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield);
391  }
392  }
393  //var_dump($gkey.' '.$gval.' '.$gvalwithoutprefix.' '.$fieldtocount.' '.$keyforlabeloffield);
394  //var_dump($object->fields);
395  setEventMessages($langs->trans("ErrorTooManyDifferentValueForSelectedGroupBy", $MAXUNIQUEVALFORGROUP, $labeloffield), null, 'warnings');
396  $search_groupby = array();
397  }
398 
399  $db->free($resql);
400  }
401 }
402 //var_dump($arrayofvaluesforgroupby);exit;
403 
404 
405 $tmparray = dol_getdate(dol_now());
406 $endyear = $tmparray['year'];
407 $endmonth = $tmparray['mon'];
408 $datelastday = dol_get_last_day($endyear, $endmonth, 1);
409 $startyear = $endyear - 2;
410 
411 $param = '';
412 
413 print '<form method="post" action="'.$_SERVER['PHP_SELF'].'">';
414 print '<input type="hidden" name="token" value="'.newToken().'">';
415 print '<input type="hidden" name="action" value="viewgraph">';
416 print '<input type="hidden" name="tabfamily" value="'.$tabfamily.'">';
417 
418 $viewmode = '';
419 
420 $viewmode .= '<div class="divadvancedsearchfield">';
421 $arrayofgraphs = array('bars' => 'Bars', 'lines' => 'Lines'); // also 'pies'
422 $viewmode .= '<div class="inline-block opacitymedium"><span class="fas fa-chart-area paddingright" title="'.$langs->trans("Graph").'"></span>'.$langs->trans("Graph").'</div> ';
423 $viewmode .= $form->selectarray('search_graph', $arrayofgraphs, $search_graph, 0, 0, 0, 'minwidth100', 1);
424 $viewmode .= '</div>';
425 
426 $num = 0;
427 $massactionbutton = '';
428 $nav = '';
429 $newcardbutton = '';
430 $limit = 0;
431 
432 print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, -1, 'object_action', 0, $nav.'<span class="marginleftonly"></span>'.$newcardbutton, '', $limit, 1, 0, 1, $viewmode);
433 
434 
435 
436 print '<div class="liste_titre liste_titre_bydiv centpercent">';
437 
438 // Select object
439 print '<div class="divadvancedsearchfield center floatnone">';
440 print '<div class="inline-block"><span class="opacitymedium">'.$langs->trans("StatisticsOn").'</span></div> ';
441 print $form->selectarray('objecttype', $newarrayoftype, $objecttype, 0, 0, 0, '', 1, 0, 0, '', 'minwidth200', 1);
442 if (empty($conf->use_javascript_ajax)) {
443  print '<input type="submit" class="button buttongen button-save nomargintop" name="changeobjecttype" value="'.$langs->trans("Refresh").'">';
444 } else {
445  print '<!-- js code to reload page with good object type -->
446  <script type="text/javascript">
447  jQuery(document).ready(function() {
448  jQuery("#objecttype").change(function() {
449  console.log("Reload for "+jQuery("#objecttype").val());
450  location.href = "'.$_SERVER["PHP_SELF"].'?objecttype="+jQuery("#objecttype").val()+"'.($tabfamily ? '&tabfamily='.urlencode($tabfamily) : '').(GETPOST('show_search_component_params_hidden', 'int') ? '&show_search_component_params_hidden='.((int) GETPOST('show_search_component_params_hidden', 'int')) : '').'";
451  });
452  });
453  </script>';
454 }
455 print '</div><div class="clearboth"></div>';
456 
457 // Add Filter (you can use param &show_search_component_params_hidden=1 for debug)
458 print '<div class="divadvancedsearchfield quatrevingtpercent">';
459 print $form->searchComponent(array($object->element => $object->fields), $search_component_params, array(), $search_component_params_hidden);
460 print '</div>';
461 
462 // Add measures into array
463 $count = 0;
464 //var_dump($arrayofmesures);
465 print '<div class="divadvancedsearchfield clearboth">';
466 print '<div class="inline-block"><span class="fas fa-ruler-combined paddingright pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("Measures")).'"></span><span class="fas fa-caret-left caretleftaxis" title="'.dol_escape_htmltag($langs->trans("Measures")).'"></span></div>';
467 $simplearrayofmesures = array();
468 foreach ($arrayofmesures as $key => $val) {
469  $simplearrayofmesures[$key] = $arrayofmesures[$key]['label'];
470 }
471 print $form->multiselectarray('search_measures', $simplearrayofmesures, $search_measures, 0, 0, 'minwidth300', 1, 0, '', '', $langs->trans("Measures")); // Fill the array $arrayofmeasures with possible fields
472 print '</div>';
473 
474 // XAxis
475 $count = 0;
476 print '<div class="divadvancedsearchfield">';
477 print '<div class="inline-block"><span class="fas fa-ruler-combined paddingright pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("XAxis")).'"></span><span class="fas fa-caret-down caretdownaxis" title="'.dol_escape_htmltag($langs->trans("XAxis")).'"></span></div>';
478 //var_dump($arrayofxaxis);
479 print $formother->selectXAxisField($object, $search_xaxis, $arrayofxaxis, $langs->trans("XAxis"), 'minwidth300 maxwidth400'); // Fill the array $arrayofxaxis with possible fields
480 print '</div>';
481 
482 // Group by
483 $count = 0;
484 print '<div class="divadvancedsearchfield">';
485 print '<div class="inline-block opacitymedium"><span class="fas fa-ruler-horizontal paddingright pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("GroupBy")).'"></span></div>';
486 print $formother->selectGroupByField($object, $search_groupby, $arrayofgroupby, 'minwidth250 maxwidth300', $langs->trans("GroupBy")); // Fill the array $arrayofgroupby with possible fields
487 print '</div>';
488 
489 
490 if ($mode == 'grid') {
491  // YAxis
492  print '<div class="divadvancedsearchfield">';
493  foreach ($object->fields as $key => $val) {
494  if (empty($val['measure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1, 1, '1'))) {
495  if (in_array($key, array('id', 'rowid', 'entity', 'last_main_doc', 'extraparams'))) {
496  continue;
497  }
498  if (preg_match('/^fk_/', $key)) {
499  continue;
500  }
501  if (in_array($val['type'], array('html', 'text'))) {
502  continue;
503  }
504  if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
505  $arrayofyaxis['t.'.$key.'-year'] = array(
506  'label' => $langs->trans($val['label']).' ('.$YYYY.')',
507  'position' => $val['position'],
508  'table' => $object->table_element
509  );
510  $arrayofyaxis['t.'.$key.'-month'] = array(
511  'label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.')',
512  'position' => $val['position'],
513  'table' => $object->table_element
514  );
515  $arrayofyaxis['t.'.$key.'-day'] = array(
516  'label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.'-'.$DD.')',
517  'position' => $val['position'],
518  'table' => $object->table_element
519  );
520  } else {
521  $arrayofyaxis['t.'.$key] = array(
522  'label' => $val['label'],
523  'position' => (int) $val['position'],
524  'table' => $object->table_element
525  );
526  }
527  }
528  }
529  // Add measure from extrafields
530  if ($object->isextrafieldmanaged) {
531  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
532  if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1, 1, '1'))) {
533  $arrayofyaxis['te.'.$key] = array(
534  'label' => $extrafields->attributes[$object->table_element]['label'][$key],
535  'position' => (int) $extrafields->attributes[$object->table_element]['pos'][$key],
536  'table' => $object->table_element
537  );
538  }
539  }
540  }
541  $arrayofyaxis = dol_sort_array($arrayofyaxis, 'position');
542  $arrayofyaxislabel = array();
543  foreach ($arrayofyaxis as $key => $val) {
544  $arrayofyaxislabel[$key] = $val['label'];
545  }
546  print '<div class="inline-block opacitymedium"><span class="fas fa-ruler-vertical paddingright" title="'.$langs->trans("YAxis").'"></span>'.$langs->trans("YAxis").'</div> ';
547  print $form->multiselectarray('search_yaxis', $arrayofyaxislabel, $search_yaxis, 0, 0, 'minwidth100', 1);
548  print '</div>';
549 }
550 
551 if ($mode == 'graph') {
552  //
553 }
554 
555 print '<div class="divadvancedsearchfield">';
556 print '<input type="submit" class="button buttongen button-save nomargintop" value="'.$langs->trans("Refresh").'">';
557 print '</div>';
558 print '</div>';
559 print '</form>';
560 
561 // Generate the SQL request
562 $sql = '';
563 if (!empty($search_measures) && !empty($search_xaxis)) {
564  $fieldid = 'rowid';
565 
566  $sql = "SELECT ";
567  foreach ($search_xaxis as $key => $val) {
568  if (preg_match('/\-year$/', $val)) {
569  $tmpval = preg_replace('/\-year$/', '', $val);
570  $sql .= "DATE_FORMAT(".$tmpval.", '%Y') as x_".$key.', ';
571  } elseif (preg_match('/\-month$/', $val)) {
572  $tmpval = preg_replace('/\-month$/', '', $val);
573  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m') as x_".$key.', ';
574  } elseif (preg_match('/\-day$/', $val)) {
575  $tmpval = preg_replace('/\-day$/', '', $val);
576  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d') as x_".$key.', ';
577  } else {
578  $sql .= $val." as x_".$key.", ";
579  }
580  }
581  foreach ($search_groupby as $key => $val) {
582  if (preg_match('/\-year$/', $val)) {
583  $tmpval = preg_replace('/\-year$/', '', $val);
584  $sql .= "DATE_FORMAT(".$tmpval.", '%Y') as g_".$key.', ';
585  } elseif (preg_match('/\-month$/', $val)) {
586  $tmpval = preg_replace('/\-month$/', '', $val);
587  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m') as g_".$key.', ';
588  } elseif (preg_match('/\-day$/', $val)) {
589  $tmpval = preg_replace('/\-day$/', '', $val);
590  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d') as g_".$key.', ';
591  } else {
592  $sql .= $val." as g_".$key.", ";
593  }
594  }
595  foreach ($search_measures as $key => $val) {
596  if ($val == 't.count') {
597  $sql .= "COUNT(t.".$fieldid.") as y_".$key.', ';
598  } elseif (preg_match('/\-sum$/', $val)) {
599  $tmpval = preg_replace('/\-sum$/', '', $val);
600  $sql .= "SUM(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
601  } elseif (preg_match('/\-average$/', $val)) {
602  $tmpval = preg_replace('/\-average$/', '', $val);
603  $sql .= "AVG(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
604  } elseif (preg_match('/\-min$/', $val)) {
605  $tmpval = preg_replace('/\-min$/', '', $val);
606  $sql .= "MIN(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
607  } elseif (preg_match('/\-max$/', $val)) {
608  $tmpval = preg_replace('/\-max$/', '', $val);
609  $sql .= "MAX(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
610  }
611  }
612  $sql = preg_replace('/,\s*$/', '', $sql);
613  $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t";
614  // Add measure from extrafields
615  if ($object->isextrafieldmanaged) {
616  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as te ON te.fk_object = t.".$fieldid;
617  }
618  // Add table for link for multientity
619  if ($object->ismultientitymanaged) { // 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
620  if ($object->ismultientitymanaged == 1) {
621  // No table to add here
622  } else {
623  $tmparray = explode('@', $object->ismultientitymanaged);
624  $sql .= " INNER JOIN ".MAIN_DB_PREFIX.$tmparray[1]." as parenttableforentity ON t.".$tmparray[0]." = parenttableforentity.rowid";
625  $sql .= " AND parenttableforentity.entity IN (".getEntity($tmparray[1]).")";
626  }
627  }
628 
629  $listoftablesalreadyadded = array($object->table_element => $object->table_element);
630 
631  // Add LEFT JOIN for all parent tables mentionned into the Xaxis
632  //var_dump($arrayofxaxis); var_dump($search_xaxis);
633  foreach ($search_xaxis as $key => $val) {
634  if (!empty($arrayofxaxis[$val])) {
635  $tmpval = explode('.', $val);
636  //var_dump($arrayofxaxis[$val]['table']);
637  if (! in_array($arrayofxaxis[$val]['table'], $listoftablesalreadyadded)) { // We do not add join for main table already added
638  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$arrayofxaxis[$val]['table']." as ".$db->sanitize($tmpval[0])." ON t.".str_replace('t__', '', $db->sanitize($tmpval[0]))." = ".$db->sanitize($tmpval[0]).".rowid";
639  $listoftablesalreadyadded[$arrayofxaxis[$val]['table']] = $arrayofxaxis[$val]['table'];
640  }
641  } else {
642  dol_print_error($db, 'Found a key into search_xaxis not found into arrayofxaxis');
643  }
644  }
645 
646  // Add LEFT JOIN for all parent tables mentionned into the Group by
647  //var_dump($arrayofgroupby); var_dump($search_groupby);
648  foreach ($search_groupby as $key => $val) {
649  if (!empty($arrayofgroupby[$val])) {
650  $tmpval = explode('.', $val);
651  //var_dump($arrayofxaxis[$val]['table']);
652  if (! in_array($arrayofgroupby[$val]['table'], $listoftablesalreadyadded)) { // We do not add join for main table already added
653  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$arrayofgroupby[$val]['table']." as ".$tmpval[0]." ON t.".str_replace('t__', '', $tmpval[0])." = ".$tmpval[0].".rowid";
654  $listoftablesalreadyadded[$arrayofgroupby[$val]['table']] = $arrayofgroupby[$val]['table'];
655  }
656  } else {
657  dol_print_error($db, 'Found a key into search_groupby not found into arrayofgroupby');
658  }
659  }
660 
661  // Add LEFT JOIN for all parent tables mentionned into the Yaxis
662  //var_dump($arrayofgroupby); var_dump($search_groupby);
663  foreach ($search_measures as $key => $val) {
664  if (!empty($arrayofmesures[$val])) {
665  $tmpval = explode('.', $val);
666  //var_dump($arrayofxaxis[$val]['table']);
667  if (! in_array($arrayofmesures[$val]['table'], $listoftablesalreadyadded)) { // We do not add join for main table already added
668  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$arrayofmesures[$val]['table']." as ".$tmpval[0]." ON t.".str_replace('t__', '', $tmpval[0])." = ".$tmpval[0].".rowid";
669  $listoftablesalreadyadded[$arrayofmesures[$val]['table']] = $arrayofmesures[$val]['table'];
670  }
671  } else {
672  dol_print_error($db, 'Found a key into search_measures not found into arrayofmesures');
673  }
674  }
675 
676  $sql .= " WHERE 1 = 1";
677  if ($object->ismultientitymanaged == 1) { // 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
678  $sql .= " AND t.entity IN (".getEntity($object->element).")";
679  }
680  // Add the where here
681  $sqlfilters = $search_component_params_hidden;
682  if ($sqlfilters) {
683  $errormessage = '';
684  if (dolCheckFilters($sqlfilters, $errormessage)) {
685  $regexstring = '\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^\‍(\‍)]+)\‍)';
686  $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $sqlfilters).")";
687  } else {
688  print $errormessage;
689  }
690  }
691  $sql .= " GROUP BY ";
692  foreach ($search_xaxis as $key => $val) {
693  if (preg_match('/\-year$/', $val)) {
694  $tmpval = preg_replace('/\-year$/', '', $val);
695  $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
696  } elseif (preg_match('/\-month$/', $val)) {
697  $tmpval = preg_replace('/\-month$/', '', $val);
698  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
699  } elseif (preg_match('/\-day$/', $val)) {
700  $tmpval = preg_replace('/\-day$/', '', $val);
701  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
702  } else {
703  $sql .= $val.", ";
704  }
705  }
706  foreach ($search_groupby as $key => $val) {
707  if (preg_match('/\-year$/', $val)) {
708  $tmpval = preg_replace('/\-year$/', '', $val);
709  $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
710  } elseif (preg_match('/\-month$/', $val)) {
711  $tmpval = preg_replace('/\-month$/', '', $val);
712  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
713  } elseif (preg_match('/\-day$/', $val)) {
714  $tmpval = preg_replace('/\-day$/', '', $val);
715  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
716  } else {
717  $sql .= $val.', ';
718  }
719  }
720  $sql = preg_replace('/,\s*$/', '', $sql);
721  $sql .= ' ORDER BY ';
722  foreach ($search_xaxis as $key => $val) {
723  if (preg_match('/\-year$/', $val)) {
724  $tmpval = preg_replace('/\-year$/', '', $val);
725  $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
726  } elseif (preg_match('/\-month$/', $val)) {
727  $tmpval = preg_replace('/\-month$/', '', $val);
728  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
729  } elseif (preg_match('/\-day$/', $val)) {
730  $tmpval = preg_replace('/\-day$/', '', $val);
731  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
732  } else {
733  $sql .= $val.', ';
734  }
735  }
736  foreach ($search_groupby as $key => $val) {
737  if (preg_match('/\-year$/', $val)) {
738  $tmpval = preg_replace('/\-year$/', '', $val);
739  $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
740  } elseif (preg_match('/\-month$/', $val)) {
741  $tmpval = preg_replace('/\-month$/', '', $val);
742  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
743  } elseif (preg_match('/\-day$/', $val)) {
744  $tmpval = preg_replace('/\-day$/', '', $val);
745  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
746  } else {
747  $sql .= $val.', ';
748  }
749  }
750  $sql = preg_replace('/,\s*$/', '', $sql);
751 }
752 //print $sql;
753 
754 $legend = array();
755 foreach ($search_measures as $key => $val) {
756  $legend[] = $langs->trans($arrayofmesures[$val]['label']);
757 }
758 
759 $useagroupby = (is_array($search_groupby) && count($search_groupby));
760 //var_dump($useagroupby);
761 //var_dump($arrayofvaluesforgroupby);
762 
763 // Execute the SQL request
764 $totalnbofrecord = 0;
765 $data = array();
766 if ($sql) {
767  $resql = $db->query($sql);
768  if (!$resql) {
769  dol_print_error($db);
770  }
771 
772  $ifetch = 0;
773  $xi = 0;
774  $oldlabeltouse = '';
775  while ($obj = $db->fetch_object($resql)) {
776  $ifetch++;
777  if ($useagroupby) {
778  $xval = $search_xaxis[0];
779  $fieldforxkey = 'x_0';
780  $xlabel = $obj->$fieldforxkey;
781  $xvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $xval);
782 
783  // Define $xlabel
784  if (!empty($object->fields[$xvalwithoutprefix]['arrayofkeyval'])) {
785  $xlabel = $object->fields[$xvalwithoutprefix]['arrayofkeyval'][$obj->$fieldforxkey];
786  }
787  $labeltouse = (($xlabel || $xlabel == '0') ? dol_trunc($xlabel, 20, 'middle') : ($xlabel === '' ? $langs->transnoentitiesnoconv("Empty") : $langs->transnoentitiesnoconv("NotDefined")));
788 
789  if ($oldlabeltouse && ($labeltouse != $oldlabeltouse)) {
790  $xi++; // Increase $xi
791  }
792  //var_dump($labeltouse.' '.$oldlabeltouse.' '.$xi);
793  $oldlabeltouse = $labeltouse;
794 
795  /* Example of value for $arrayofvaluesforgroupby
796  * array (size=1)
797  * 'g_0' =>
798  * array (size=6)
799  * 0 => string '0' (length=1)
800  * '' => string 'Empty' (length=5)
801  * '__NULL__' => string 'Not defined' (length=11)
802  * 'done' => string 'done' (length=4)
803  * 'processing' => string 'processing' (length=10)
804  * 'undeployed' => string 'undeployed' (length=10)
805  */
806  foreach ($search_measures as $key => $val) {
807  $gi = 0;
808  foreach ($search_groupby as $gkey) {
809  //var_dump('*** Fetch #'.$ifetch.' for labeltouse='.$labeltouse.' measure number '.$key.' and group g_'.$gi);
810  //var_dump($arrayofvaluesforgroupby);
811  foreach ($arrayofvaluesforgroupby['g_'.$gi] as $gvaluepossiblekey => $gvaluepossiblelabel) {
812  $ykeysuffix = $gvaluepossiblelabel;
813  $gvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $gval);
814 
815  $fieldfory = 'y_'.$key;
816  $fieldforg = 'g_'.$gi;
817  $fieldforybis = 'y_'.$key.'_'.$ykeysuffix;
818  //var_dump('gvaluepossiblekey='.$gvaluepossiblekey.' gvaluepossiblelabel='.$gvaluepossiblelabel.' ykeysuffix='.$ykeysuffix.' gval='.$gval.' gvalwithoutsuffix='.$gvalwithoutprefix);
819  //var_dump('fieldforg='.$fieldforg.' obj->$fieldforg='.$obj->$fieldforg.' fieldfory='.$fieldfory.' obj->$fieldfory='.$obj->$fieldfory.' fieldforybis='.$fieldforybis);
820 
821  if (!is_array($data[$xi])) {
822  $data[$xi] = array();
823  }
824 
825  if (!array_key_exists('label', $data[$xi])) {
826  $data[$xi] = array();
827  $data[$xi]['label'] = $labeltouse;
828  }
829 
830  $objfieldforg = $obj->$fieldforg;
831  if (is_null($objfieldforg)) {
832  $objfieldforg = '__NULL__';
833  }
834 
835  if ($gvaluepossiblekey == '0') { // $gvaluepossiblekey can have type int or string. So we create a special if, used when value is '0'
836  //var_dump($objfieldforg.' == \'0\' -> '.($objfieldforg == '0'));
837  if ($objfieldforg == '0') {
838  // The record we fetch is for this group
839  $data[$xi][$fieldforybis] = $obj->$fieldfory;
840  } elseif (!isset($data[$xi][$fieldforybis])) {
841  // The record we fetch is not for this group
842  $data[$xi][$fieldforybis] = '0';
843  }
844  } else {
845  //var_dump((string) $objfieldforg.' === '.(string) $gvaluepossiblekey.' -> '.((string) $objfieldforg === (string) $gvaluepossiblekey));
846  if ((string) $objfieldforg === (string) $gvaluepossiblekey) {
847  // The record we fetch is for this group
848  $data[$xi][$fieldforybis] = $obj->$fieldfory;
849  } elseif (!isset($data[$xi][$fieldforybis])) {
850  // The record we fetch is not for this group
851  $data[$xi][$fieldforybis] = '0';
852  }
853  }
854  }
855  //var_dump($data[$xi]);
856  $gi++;
857  }
858  }
859  } else { // No group by
860  $xval = $search_xaxis[0];
861  $fieldforxkey = 'x_0';
862  $xlabel = $obj->$fieldforxkey;
863  $xvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $xval);
864 
865  // Define $xlabel
866  if (!empty($object->fields[$xvalwithoutprefix]['arrayofkeyval'])) {
867  $xlabel = $object->fields[$xvalwithoutprefix]['arrayofkeyval'][$obj->$fieldforxkey];
868  }
869 
870  $labeltouse = (($xlabel || $xlabel == '0') ? dol_trunc($xlabel, 20, 'middle') : ($xlabel === '' ? $langs->trans("Empty") : $langs->trans("NotDefined")));
871  $xarrayforallseries = array('label' => $labeltouse);
872  foreach ($search_measures as $key => $val) {
873  $fieldfory = 'y_'.$key;
874  $xarrayforallseries[$fieldfory] = $obj->$fieldfory;
875  }
876  $data[$xi] = $xarrayforallseries;
877  $xi++;
878  }
879  }
880 
881  $totalnbofrecord = count($data);
882 }
883 //var_dump($data);
884 
885 
886 print '<div class="customreportsoutput'.($totalnbofrecord ? '' : ' customreportsoutputnotdata').'">';
887 
888 
889 if ($mode == 'grid') {
890  // TODO
891 }
892 
893 if ($mode == 'graph') {
894  $WIDTH = '80%';
895  $HEIGHT = 200;
896 
897  // Show graph
898  $px1 = new DolGraph();
899  $mesg = $px1->isGraphKo();
900  if (!$mesg) {
901  //var_dump($legend);
902  //var_dump($data);
903  $px1->SetData($data);
904  unset($data);
905 
906  $arrayoftypes = array();
907  foreach ($search_measures as $key => $val) {
908  $arrayoftypes[] = $search_graph;
909  }
910 
911  $px1->SetLegend($legend);
912  $px1->SetMinValue($px1->GetFloorMinValue());
913  $px1->SetMaxValue($px1->GetCeilMaxValue());
914  $px1->SetWidth($WIDTH);
915  $px1->SetHeight($HEIGHT);
916  $px1->SetYLabel($langs->trans("Y"));
917  $px1->SetShading(3);
918  $px1->SetHorizTickIncrement(1);
919  $px1->SetCssPrefix("cssboxes");
920  $px1->SetType($arrayoftypes);
921  $px1->mode = 'depth';
922  $px1->SetTitle('');
923 
924  $dir = $conf->user->dir_temp;
925  dol_mkdir($dir);
926  $filenamenb = $dir.'/customreport_'.$object->element.'.png';
927  $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=user&file=customreport_'.$object->element.'.png';
928 
929  $px1->draw($filenamenb, $fileurlnb);
930 
931  $texttoshow = $langs->trans("NoRecordFound");
932  if (!GETPOSTISSET('search_measures') || !GETPOSTISSET('search_xaxis')) {
933  $texttoshow = $langs->trans("SelectYourGraphOptionsFirst");
934  }
935 
936  print $px1->show($totalnbofrecord ? 0 : $texttoshow);
937  }
938 }
939 
940 if ($sql) {
941  // Show admin info
942  print '<br>'.info_admin($langs->trans("SQLUsedForExport").':<br> '.$sql, 0, 0, 1, '', 'TechnicalInformation');
943 }
944 
945 print '<div>';
946 
947 if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) {
948  print dol_get_fiche_end();
949 }
950 
951 // End of page
952 llxFooter();
953 
954 $db->close();
955 
956 
957 
958 
959 
971 function fillArrayOfMeasures($object, $tablealias, $labelofobject, &$arrayofmesures, $level = 0, &$count = 0)
972 {
973  global $langs, $extrafields, $db;
974 
975  if ($level > 10) { // Protection against infinite loop
976  return $arrayofmesures;
977  }
978 
979  if ($level == 0) {
980  // Add the count of record only for the main/first level object. Parents are necessarly unique for each record.
981  $arrayofmesures[$tablealias.'.count'] = array(
982  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': Count',
983  'position' => 0,
984  'table' => $object->table_element
985  );
986  }
987 
988  // Add main fields of object
989  foreach ($object->fields as $key => $val) {
990  if (!empty($val['isameasure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1, 1, '1'))) {
991  $position = (empty($val['position']) ? 0 : intVal($val['position']));
992  $arrayofmesures[$tablealias.'.'.$key.'-sum'] = array(
993  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$langs->trans("Sum").')</span>',
994  'position' => ($position + ($count * 100000)).'.1',
995  'table' => $object->table_element
996  );
997  $arrayofmesures[$tablealias.'.'.$key.'-average'] = array(
998  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$langs->trans("Average").')</span>',
999  'position' => ($position + ($count * 100000)).'.2',
1000  'table' => $object->table_element
1001  );
1002  $arrayofmesures[$tablealias.'.'.$key.'-min'] = array(
1003  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$langs->trans("Minimum").')</span>',
1004  'position' => ($position + ($count * 100000)).'.3',
1005  'table' => $object->table_element
1006  );
1007  $arrayofmesures[$tablealias.'.'.$key.'-max'] = array(
1008  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$langs->trans("Maximum").')</span>',
1009  'position' => ($position + ($count * 100000)).'.4',
1010  'table' => $object->table_element
1011  );
1012  }
1013  }
1014  // Add extrafields to Measures
1015  if (!empty($object->isextrafieldmanaged)) {
1016  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
1017  if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1, 1, '1'))) {
1018  $position = (!empty($val['position']) ? $val['position'] : 0);
1019  $arrayofmesures[$tablealias.'e.'.$key.'-sum'] = array(
1020  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' <span class="opacitymedium">('.$langs->trans("Sum").')</span>',
1021  'position' => ($position+($count * 100000)).'.1',
1022  'table' => $object->table_element
1023  );
1024  $arrayofmesures[$tablealias.'e.'.$key.'-average'] = array(
1025  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' <span class="opacitymedium">('.$langs->trans("Average").')</span>',
1026  'position' => ($position+($count * 100000)).'.2',
1027  'table' => $object->table_element
1028  );
1029  $arrayofmesures[$tablealias.'e.'.$key.'-min'] = array(
1030  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' <span class="opacitymedium">('.$langs->trans("Minimum").')</span>',
1031  'position' => ($position+($count * 100000)).'.3',
1032  'table' => $object->table_element
1033  );
1034  $arrayofmesures[$tablealias.'e.'.$key.'-max'] = array(
1035  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' <span class="opacitymedium">('.$langs->trans("Maximum").')</span>',
1036  'position' => ($position+($count * 100000)).'.4',
1037  'table' => $object->table_element
1038  );
1039  }
1040  }
1041  }
1042  // Add fields for parent objects
1043  foreach ($object->fields as $key => $val) {
1044  if (preg_match('/^[^:]+:[^:]+:/', $val['type'])) {
1045  $tmptype = explode(':', $val['type'], 4);
1046  if ($tmptype[0] == 'integer' && $tmptype[1] && $tmptype[2]) {
1047  $newobject = $tmptype[1];
1048  dol_include_once($tmptype[2]);
1049  if (class_exists($newobject)) {
1050  $tmpobject = new $newobject($db);
1051  //var_dump($key); var_dump($tmpobject->element); var_dump($val['label']); var_dump($tmptype); var_dump('t-'.$key);
1052  $count++;
1053  $arrayofmesures = fillArrayOfMeasures($tmpobject, $tablealias.'__'.$key, $langs->trans($val['label']), $arrayofmesures, $level + 1, $count);
1054  } else {
1055  print 'For property '.$object->element.'->'.$key.', type="'.$val['type'].'": Failed to find class '.$newobject." in file ".$tmptype[2]."<br>\n";
1056  }
1057  }
1058  }
1059  }
1060 
1061  return $arrayofmesures;
1062 }
1063 
1064 
1076 function fillArrayOfXAxis($object, $tablealias, $labelofobject, &$arrayofxaxis, $level = 0, &$count = 0)
1077 {
1078  global $langs, $extrafields, $db;
1079 
1080  if ($level > 10) { // Protection against infinite loop
1081  return $arrayofxaxis;
1082  }
1083 
1084  if ($level >= 2) {
1085  return $arrayofxaxis;
1086  }
1087 
1088  $YYYY = substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1);
1089  $MM = substr($langs->trans("Month"), 0, 1).substr($langs->trans("Month"), 0, 1);
1090  $DD = substr($langs->trans("Day"), 0, 1).substr($langs->trans("Day"), 0, 1);
1091  $HH = substr($langs->trans("Hour"), 0, 1).substr($langs->trans("Hour"), 0, 1);
1092  $MI = substr($langs->trans("Minute"), 0, 1).substr($langs->trans("Minute"), 0, 1);
1093  $SS = substr($langs->trans("Second"), 0, 1).substr($langs->trans("Second"), 0, 1);
1094 
1095  // Add main fields of object
1096  foreach ($object->fields as $key => $val) {
1097  if (empty($val['measure'])) {
1098  if (in_array($key, array(
1099  'id', 'ref_ext', 'rowid', 'entity', 'last_main_doc', 'logo', 'logo_squarred', 'extraparams',
1100  'parent', 'photo', 'socialnetworks', 'webservices_url', 'webservices_key'))) {
1101  continue;
1102  }
1103  if (isset($val['enabled']) && !dol_eval($val['enabled'], 1, 1, '1')) {
1104  continue;
1105  }
1106  if (isset($val['visible']) && !dol_eval($val['visible'], 1, 1, '1')) {
1107  continue;
1108  }
1109  if (preg_match('/^fk_/', $key) && !preg_match('/^fk_statu/', $key)) {
1110  continue;
1111  }
1112  if (preg_match('/^pass/', $key)) {
1113  continue;
1114  }
1115  if (in_array($val['type'], array('html', 'text'))) {
1116  continue;
1117  }
1118  if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
1119  $position = (empty($val['position']) ? 0 : intVal($val['position']));
1120  $arrayofxaxis[$tablealias.'.'.$key.'-year'] = array(
1121  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.')</span>',
1122  'position' => ($position + ($count * 100000)).'.1',
1123  'table' => $object->table_element
1124  );
1125  $arrayofxaxis[$tablealias.'.'.$key.'-month'] = array(
1126  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.'-'.$MM.')</span>',
1127  'position' => ($position + ($count * 100000)).'.2',
1128  'table' => $object->table_element
1129  );
1130  $arrayofxaxis[$tablealias.'.'.$key.'-day'] = array(
1131  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.'-'.$MM.'-'.$DD.')</span>',
1132  'position' => ($position + ($count * 100000)).'.3',
1133  'table' => $object->table_element
1134  );
1135  } else {
1136  $position = (empty($val['position']) ? 0 : intVal($val['position']));
1137  $arrayofxaxis[$tablealias.'.'.$key] = array(
1138  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']),
1139  'position' => ($position + ($count * 100000)),
1140  'table' => $object->table_element
1141  );
1142  }
1143  }
1144  }
1145 
1146  // Add extrafields to X-Axis
1147  if (!empty($object->isextrafieldmanaged)) {
1148  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
1149  if ($extrafields->attributes[$object->table_element]['type'][$key] == 'separate') {
1150  continue;
1151  }
1152  if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key])) {
1153  continue;
1154  }
1155  $arrayofxaxis[$tablealias.'e.'.$key] = array(
1156  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]),
1157  'position' => 1000 + (int) $extrafields->attributes[$object->table_element]['pos'][$key] + ($count * 100000),
1158  'table' => $object->table_element
1159  );
1160  }
1161  }
1162 
1163  // Add fields for parent objects
1164  foreach ($object->fields as $key => $val) {
1165  if (preg_match('/^[^:]+:[^:]+:/', $val['type'])) {
1166  $tmptype = explode(':', $val['type'], 4);
1167  if ($tmptype[0] == 'integer' && $tmptype[1] && $tmptype[2]) {
1168  $newobject = $tmptype[1];
1169  dol_include_once($tmptype[2]);
1170  if (class_exists($newobject)) {
1171  $tmpobject = new $newobject($db);
1172  //var_dump($key); var_dump($tmpobject->element); var_dump($val['label']); var_dump($tmptype); var_dump('t-'.$key);
1173  $count++;
1174  $arrayofxaxis = fillArrayOfXAxis($tmpobject, $tablealias.'__'.$key, $langs->trans($val['label']), $arrayofxaxis, $level + 1, $count);
1175  } else {
1176  print 'For property '.$object->element.'->'.$key.', type="'.$val['type'].'": Failed to find class '.$newobject." in file ".$tmptype[2]."<br>\n";
1177  }
1178  }
1179  }
1180  }
1181 
1182  return $arrayofxaxis;
1183 }
1184 
1185 
1197 function fillArrayOfGroupBy($object, $tablealias, $labelofobject, &$arrayofgroupby, $level = 0, &$count = 0)
1198 {
1199  global $langs, $extrafields, $db;
1200 
1201  if ($level > 10) { // Protection against infinite loop
1202  return $arrayofgroupby;
1203  }
1204 
1205  if ($level >= 2) {
1206  return $arrayofgroupby;
1207  }
1208 
1209  $YYYY = substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1);
1210  $MM = substr($langs->trans("Month"), 0, 1).substr($langs->trans("Month"), 0, 1);
1211  $DD = substr($langs->trans("Day"), 0, 1).substr($langs->trans("Day"), 0, 1);
1212  $HH = substr($langs->trans("Hour"), 0, 1).substr($langs->trans("Hour"), 0, 1);
1213  $MI = substr($langs->trans("Minute"), 0, 1).substr($langs->trans("Minute"), 0, 1);
1214  $SS = substr($langs->trans("Second"), 0, 1).substr($langs->trans("Second"), 0, 1);
1215 
1216  // Add main fields of object
1217  foreach ($object->fields as $key => $val) {
1218  if (empty($val['isameasure'])) {
1219  if (in_array($key, array(
1220  'id', 'ref_ext', 'rowid', 'entity', 'last_main_doc', 'logo', 'logo_squarred', 'extraparams',
1221  'parent', 'photo', 'socialnetworks', 'webservices_url', 'webservices_key'))) {
1222  continue;
1223  }
1224  if (isset($val['enabled']) && !dol_eval($val['enabled'], 1, 1, '1')) {
1225  continue;
1226  }
1227  if (isset($val['visible']) && !dol_eval($val['visible'], 1, 1, '1')) {
1228  continue;
1229  }
1230  if (preg_match('/^fk_/', $key) && !preg_match('/^fk_statu/', $key)) {
1231  continue;
1232  }
1233  if (preg_match('/^pass/', $key)) {
1234  continue;
1235  }
1236  if (in_array($val['type'], array('html', 'text'))) {
1237  continue;
1238  }
1239  if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
1240  $position = (empty($val['position']) ? 0 : intVal($val['position']));
1241  $arrayofgroupby[$tablealias.'.'.$key.'-year'] = array(
1242  'label' => img_picto('', $object->picto,
1243  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.')</span>', 'position' => ($position + ($count * 100000)).'.1',
1244  'table' => $object->table_element
1245  );
1246  $arrayofgroupby[$tablealias.'.'.$key.'-month'] = array(
1247  'label' => img_picto('', $object->picto,
1248  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.'-'.$MM.')</span>', 'position' => ($position + ($count * 100000)).'.2',
1249  'table' => $object->table_element
1250  );
1251  $arrayofgroupby[$tablealias.'.'.$key.'-day'] = array(
1252  'label' => img_picto('', $object->picto,
1253  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.'-'.$MM.'-'.$DD.')</span>', 'position' => ($position + ($count * 100000)).'.3',
1254  'table' => $object->table_element
1255  );
1256  } else {
1257  $position = (empty($val['position']) ? 0 : intVal($val['position']));
1258  $arrayofgroupby[$tablealias.'.'.$key] = array(
1259  'label' => img_picto('', $object->picto,
1260  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']), 'position' => ($position + ($count * 100000)),
1261  'table' => $object->table_element
1262  );
1263  }
1264  }
1265  }
1266 
1267  // Add extrafields to Group by
1268  if (!empty($object->isextrafieldmanaged)) {
1269  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
1270  if ($extrafields->attributes[$object->table_element]['type'][$key] == 'separate') {
1271  continue;
1272  }
1273  if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key])) {
1274  continue;
1275  }
1276  $arrayofgroupby[$tablealias.'e.'.$key] = array(
1277  'label' => img_picto('', $object->picto,
1278  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]), 'position' => 1000 + (int) $extrafields->attributes[$object->table_element]['pos'][$key] + ($count * 100000),
1279  'table' => $object->table_element
1280  );
1281  }
1282  }
1283 
1284  // Add fields for parent objects
1285  foreach ($object->fields as $key => $val) {
1286  if (preg_match('/^[^:]+:[^:]+:/', $val['type'])) {
1287  $tmptype = explode(':', $val['type'], 4);
1288  if ($tmptype[0] == 'integer' && $tmptype[1] && $tmptype[2]) {
1289  $newobject = $tmptype[1];
1290  dol_include_once($tmptype[2]);
1291  if (class_exists($newobject)) {
1292  $tmpobject = new $newobject($db);
1293  //var_dump($key); var_dump($tmpobject->element); var_dump($val['label']); var_dump($tmptype); var_dump('t-'.$key);
1294  $count++;
1295  $arrayofgroupby = fillArrayOfGroupBy($tmpobject, $tablealias.'__'.$key, $langs->trans($val['label']), $arrayofgroupby, $level + 1, $count);
1296  } else {
1297  print 'For property '.$object->element.'->'.$key.', type="'.$val['type'].'": Failed to find class '.$newobject." in file ".$tmptype[2]."<br>\n";
1298  }
1299  }
1300  }
1301  }
1302 
1303  return $arrayofgroupby;
1304 }
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
Class to build graphs.
Class to manage standard extra fields.
Class to manage generation of HTML components Only common components must be here.
Classe permettant la generation de composants html autre Only common components are here.
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)) $resql
Social contributions to pay.
Definition: index.php:745
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition: date.lib.php:594
dolCheckFilters($sqlfilters, &$error='')
Return if a $sqlfilters parameter is valid and will pass the preg_replace_callback() to replace Gener...
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tabs of a record.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_get_fiche_end($notab=0)
Return tab footer of a card.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_now($mode='auto')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
dol_eval($s, $returnvalue=0, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.