dolibarr  17.0.4
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  $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
299  }*/
300 
301  $sql .= " LIMIT ".((int) ($MAXUNIQUEVALFORGROUP + 1));
302 
303  //print $sql;
304  $resql = $db->query($sql);
305  if (!$resql) {
306  dol_print_error($db);
307  }
308 
309  while ($obj = $db->fetch_object($resql)) {
310  if (is_null($obj->val)) {
311  $keytouse = '__NULL__';
312  $valuetranslated = $langs->transnoentitiesnoconv("NotDefined");
313  } elseif ($obj->val === '') {
314  $keytouse = '';
315  $valuetranslated = $langs->transnoentitiesnoconv("Empty");
316  } else {
317  $keytouse = (string) $obj->val;
318  $valuetranslated = $obj->val;
319  }
320 
321  $regs = array();
322  if (!empty($object->fields[$gvalwithoutprefix]['arrayofkeyval'])) {
323  $valuetranslated = $object->fields[$gvalwithoutprefix]['arrayofkeyval'][$obj->val];
324  if (is_null($valuetranslated)) {
325  $valuetranslated = $langs->transnoentitiesnoconv("UndefinedKey");
326  }
327  $valuetranslated = $langs->trans($valuetranslated);
328  } elseif (preg_match('/integer:([^:]+):([^:]+)$/', $object->fields[$gvalwithoutprefix]['type'], $regs)) {
329  $classname = $regs[1];
330  $classpath = $regs[2];
331  dol_include_once($classpath);
332  if (class_exists($classname)) {
333  $tmpobject = new $classname($db);
334  $tmpobject->fetch($obj->val);
335  foreach ($tmpobject->fields as $fieldkey => $field) {
336  if ($field['showoncombobox']) {
337  $valuetranslated = $tmpobject->$fieldkey;
338  //if ($valuetranslated == '-') $valuetranslated = $langs->transnoentitiesnoconv("Unknown")
339  break;
340  }
341  }
342  //$valuetranslated = $tmpobject->ref.'eee';
343  }
344  }
345 
346  $arrayofvaluesforgroupby['g_'.$gkey][$keytouse] = $valuetranslated;
347  }
348  // Add also the possible NULL value if field is a parent field that is not a strict join
349  $tmpfield = explode('.', $gval);
350  if ($tmpfield[0] != 't' || (is_array($object->fields[$tmpfield[1]]) && empty($object->fields[$tmpfield[1]]['notnull']))) {
351  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");
352  //var_dump($gval); var_dump($object->fields);
353  $arrayofvaluesforgroupby['g_'.$gkey]['__NULL__'] = $langs->transnoentitiesnoconv("NotDefined");
354  }
355 
356  asort($arrayofvaluesforgroupby['g_'.$gkey]);
357 
358  // Add a protection/error to refuse the request if number of differentr values for the group by is higher than $MAXUNIQUEVALFORGROUP
359  if (count($arrayofvaluesforgroupby['g_'.$gkey]) > $MAXUNIQUEVALFORGROUP) {
360  $langs->load("errors");
361  if (strpos($fieldtocount, 'te.') === 0) { // This is an extrafield
362  //if (!empty($extrafields->attributes[$object->table_element]['langfile'][$gvalwithoutprefix])) {
363  // $langs->load($extrafields->attributes[$object->table_element]['langfile'][$gvalwithoutprefix]);
364  //}
365  $keyforlabeloffield = $extrafields->attributes[$object->table_element]['label'][$gvalwithoutprefix];
366  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield);
367  } elseif (strpos($fieldtocount, 't__') === 0) { // This is a field of a foreign key
368  $reg = array();
369  if (preg_match('/^(.*)\.(.*)/', $gvalwithoutprefix, $reg)) {
370  $gvalwithoutprefix = preg_replace('/\..*$/', '', $gvalwithoutprefix);
371  $gvalwithoutprefix = preg_replace('/t__/', '', $gvalwithoutprefix);
372  $keyforlabeloffield = $object->fields[$gvalwithoutprefix]['label'];
373  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield).'-'.$reg[2];
374  } else {
375  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield);
376  }
377  } else { // This is a common field
378  $reg = array();
379  if (preg_match('/^(.*)\-(year|month|day)/', $gvalwithoutprefix, $reg)) {
380  $gvalwithoutprefix = preg_replace('/\-(year|month|day)/', '', $gvalwithoutprefix);
381  $keyforlabeloffield = $object->fields[$gvalwithoutprefix]['label'];
382  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield).'-'.$reg[2];
383  } else {
384  $keyforlabeloffield = $object->fields[$gvalwithoutprefix]['label'];
385  $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield);
386  }
387  }
388  //var_dump($gkey.' '.$gval.' '.$gvalwithoutprefix.' '.$fieldtocount.' '.$keyforlabeloffield);
389  //var_dump($object->fields);
390  setEventMessages($langs->trans("ErrorTooManyDifferentValueForSelectedGroupBy", $MAXUNIQUEVALFORGROUP, $labeloffield), null, 'warnings');
391  $search_groupby = array();
392  }
393 
394  $db->free($resql);
395  }
396 }
397 //var_dump($arrayofvaluesforgroupby);exit;
398 
399 
400 $tmparray = dol_getdate(dol_now());
401 $endyear = $tmparray['year'];
402 $endmonth = $tmparray['mon'];
403 $datelastday = dol_get_last_day($endyear, $endmonth, 1);
404 $startyear = $endyear - 2;
405 
406 $param = '';
407 
408 print '<form method="post" action="'.$_SERVER['PHP_SELF'].'">';
409 print '<input type="hidden" name="token" value="'.newToken().'">';
410 print '<input type="hidden" name="action" value="viewgraph">';
411 print '<input type="hidden" name="tabfamily" value="'.$tabfamily.'">';
412 
413 $viewmode = '';
414 
415 $viewmode .= '<div class="divadvancedsearchfield">';
416 $arrayofgraphs = array('bars' => 'Bars', 'lines' => 'Lines'); // also 'pies'
417 $viewmode .= '<div class="inline-block opacitymedium"><span class="fas fa-chart-area paddingright" title="'.$langs->trans("Graph").'"></span>'.$langs->trans("Graph").'</div> ';
418 $viewmode .= $form->selectarray('search_graph', $arrayofgraphs, $search_graph, 0, 0, 0, 'minwidth100', 1);
419 $viewmode .= '</div>';
420 
421 $num = 0;
422 $massactionbutton = '';
423 $nav = '';
424 $newcardbutton = '';
425 $limit = 0;
426 
427 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);
428 
429 
430 
431 print '<div class="liste_titre liste_titre_bydiv centpercent">';
432 
433 // Select object
434 print '<div class="divadvancedsearchfield center floatnone">';
435 print '<div class="inline-block"><span class="opacitymedium">'.$langs->trans("StatisticsOn").'</span></div> ';
436 print $form->selectarray('objecttype', $newarrayoftype, $objecttype, 0, 0, 0, '', 1, 0, 0, '', 'minwidth200', 1);
437 if (empty($conf->use_javascript_ajax)) {
438  print '<input type="submit" class="button buttongen button-save nomargintop" name="changeobjecttype" value="'.$langs->trans("Refresh").'">';
439 } else {
440  print '<!-- js code to reload page with good object type -->
441  <script type="text/javascript">
442  jQuery(document).ready(function() {
443  jQuery("#objecttype").change(function() {
444  console.log("Reload for "+jQuery("#objecttype").val());
445  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')) : '').'";
446  });
447  });
448  </script>';
449 }
450 print '</div><div class="clearboth"></div>';
451 
452 // Add Filter (you can use param &show_search_component_params_hidden=1 for debug)
453 print '<div class="divadvancedsearchfield quatrevingtpercent">';
454 print $form->searchComponent(array($object->element => $object->fields), $search_component_params, array(), $search_component_params_hidden);
455 print '</div>';
456 
457 // Add measures into array
458 $count = 0;
459 //var_dump($arrayofmesures);
460 print '<div class="divadvancedsearchfield clearboth">';
461 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>';
462 $simplearrayofmesures = array();
463 foreach ($arrayofmesures as $key => $val) {
464  $simplearrayofmesures[$key] = $arrayofmesures[$key]['label'];
465 }
466 print $form->multiselectarray('search_measures', $simplearrayofmesures, $search_measures, 0, 0, 'minwidth300', 1, 0, '', '', $langs->trans("Measures")); // Fill the array $arrayofmeasures with possible fields
467 print '</div>';
468 
469 // XAxis
470 $count = 0;
471 print '<div class="divadvancedsearchfield">';
472 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>';
473 //var_dump($arrayofxaxis);
474 print $formother->selectXAxisField($object, $search_xaxis, $arrayofxaxis, $langs->trans("XAxis"), 'minwidth300 maxwidth400'); // Fill the array $arrayofxaxis with possible fields
475 print '</div>';
476 
477 // Group by
478 $count = 0;
479 print '<div class="divadvancedsearchfield">';
480 print '<div class="inline-block opacitymedium"><span class="fas fa-ruler-horizontal paddingright pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("GroupBy")).'"></span></div>';
481 print $formother->selectGroupByField($object, $search_groupby, $arrayofgroupby, 'minwidth250 maxwidth300', $langs->trans("GroupBy")); // Fill the array $arrayofgroupby with possible fields
482 print '</div>';
483 
484 
485 if ($mode == 'grid') {
486  // YAxis
487  print '<div class="divadvancedsearchfield">';
488  foreach ($object->fields as $key => $val) {
489  if (empty($val['measure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1, 1, '1'))) {
490  if (in_array($key, array('id', 'rowid', 'entity', 'last_main_doc', 'extraparams'))) {
491  continue;
492  }
493  if (preg_match('/^fk_/', $key)) {
494  continue;
495  }
496  if (in_array($val['type'], array('html', 'text'))) {
497  continue;
498  }
499  if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
500  $arrayofyaxis['t.'.$key.'-year'] = array(
501  'label' => $langs->trans($val['label']).' ('.$YYYY.')',
502  'position' => $val['position'],
503  'table' => $object->table_element
504  );
505  $arrayofyaxis['t.'.$key.'-month'] = array(
506  'label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.')',
507  'position' => $val['position'],
508  'table' => $object->table_element
509  );
510  $arrayofyaxis['t.'.$key.'-day'] = array(
511  'label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.'-'.$DD.')',
512  'position' => $val['position'],
513  'table' => $object->table_element
514  );
515  } else {
516  $arrayofyaxis['t.'.$key] = array(
517  'label' => $val['label'],
518  'position' => (int) $val['position'],
519  'table' => $object->table_element
520  );
521  }
522  }
523  }
524  // Add measure from extrafields
525  if ($object->isextrafieldmanaged) {
526  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
527  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'))) {
528  $arrayofyaxis['te.'.$key] = array(
529  'label' => $extrafields->attributes[$object->table_element]['label'][$key],
530  'position' => (int) $extrafields->attributes[$object->table_element]['pos'][$key],
531  'table' => $object->table_element
532  );
533  }
534  }
535  }
536  $arrayofyaxis = dol_sort_array($arrayofyaxis, 'position');
537  $arrayofyaxislabel = array();
538  foreach ($arrayofyaxis as $key => $val) {
539  $arrayofyaxislabel[$key] = $val['label'];
540  }
541  print '<div class="inline-block opacitymedium"><span class="fas fa-ruler-vertical paddingright" title="'.$langs->trans("YAxis").'"></span>'.$langs->trans("YAxis").'</div> ';
542  print $form->multiselectarray('search_yaxis', $arrayofyaxislabel, $search_yaxis, 0, 0, 'minwidth100', 1);
543  print '</div>';
544 }
545 
546 if ($mode == 'graph') {
547  //
548 }
549 
550 print '<div class="divadvancedsearchfield">';
551 print '<input type="submit" class="button buttongen button-save nomargintop" value="'.$langs->trans("Refresh").'">';
552 print '</div>';
553 print '</div>';
554 print '</form>';
555 
556 // Generate the SQL request
557 $sql = '';
558 if (!empty($search_measures) && !empty($search_xaxis)) {
559  $fieldid = 'rowid';
560 
561  $sql = "SELECT ";
562  foreach ($search_xaxis as $key => $val) {
563  if (preg_match('/\-year$/', $val)) {
564  $tmpval = preg_replace('/\-year$/', '', $val);
565  $sql .= "DATE_FORMAT(".$tmpval.", '%Y') as x_".$key.', ';
566  } elseif (preg_match('/\-month$/', $val)) {
567  $tmpval = preg_replace('/\-month$/', '', $val);
568  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m') as x_".$key.', ';
569  } elseif (preg_match('/\-day$/', $val)) {
570  $tmpval = preg_replace('/\-day$/', '', $val);
571  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d') as x_".$key.', ';
572  } else {
573  $sql .= $val." as x_".$key.", ";
574  }
575  }
576  foreach ($search_groupby as $key => $val) {
577  if (preg_match('/\-year$/', $val)) {
578  $tmpval = preg_replace('/\-year$/', '', $val);
579  $sql .= "DATE_FORMAT(".$tmpval.", '%Y') as g_".$key.', ';
580  } elseif (preg_match('/\-month$/', $val)) {
581  $tmpval = preg_replace('/\-month$/', '', $val);
582  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m') as g_".$key.', ';
583  } elseif (preg_match('/\-day$/', $val)) {
584  $tmpval = preg_replace('/\-day$/', '', $val);
585  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d') as g_".$key.', ';
586  } else {
587  $sql .= $val." as g_".$key.", ";
588  }
589  }
590  foreach ($search_measures as $key => $val) {
591  if ($val == 't.count') {
592  $sql .= "COUNT(t.".$fieldid.") as y_".$key.', ';
593  } elseif (preg_match('/\-sum$/', $val)) {
594  $tmpval = preg_replace('/\-sum$/', '', $val);
595  $sql .= "SUM(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
596  } elseif (preg_match('/\-average$/', $val)) {
597  $tmpval = preg_replace('/\-average$/', '', $val);
598  $sql .= "AVG(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
599  } elseif (preg_match('/\-min$/', $val)) {
600  $tmpval = preg_replace('/\-min$/', '', $val);
601  $sql .= "MIN(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
602  } elseif (preg_match('/\-max$/', $val)) {
603  $tmpval = preg_replace('/\-max$/', '', $val);
604  $sql .= "MAX(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
605  }
606  }
607  $sql = preg_replace('/,\s*$/', '', $sql);
608  $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t";
609  // Add measure from extrafields
610  if ($object->isextrafieldmanaged) {
611  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as te ON te.fk_object = t.".$fieldid;
612  }
613  // Add table for link for multientity
614  if ($object->ismultientitymanaged) { // 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
615  if ($object->ismultientitymanaged == 1) {
616  // No table to add here
617  } else {
618  $tmparray = explode('@', $object->ismultientitymanaged);
619  $sql .= " INNER JOIN ".MAIN_DB_PREFIX.$tmparray[1]." as parenttableforentity ON t.".$tmparray[0]." = parenttableforentity.rowid";
620  $sql .= " AND parenttableforentity.entity IN (".getEntity($tmparray[1]).")";
621  }
622  }
623 
624  $listoftablesalreadyadded = array($object->table_element => $object->table_element);
625 
626  // Add LEFT JOIN for all parent tables mentionned into the Xaxis
627  //var_dump($arrayofxaxis); var_dump($search_xaxis);
628  foreach ($search_xaxis as $key => $val) {
629  if (!empty($arrayofxaxis[$val])) {
630  $tmpval = explode('.', $val);
631  //var_dump($arrayofxaxis[$val]['table']);
632  if (! in_array($arrayofxaxis[$val]['table'], $listoftablesalreadyadded)) { // We do not add join for main table already added
633  $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";
634  $listoftablesalreadyadded[$arrayofxaxis[$val]['table']] = $arrayofxaxis[$val]['table'];
635  }
636  } else {
637  dol_print_error($db, 'Found a key into search_xaxis not found into arrayofxaxis');
638  }
639  }
640 
641  // Add LEFT JOIN for all parent tables mentionned into the Group by
642  //var_dump($arrayofgroupby); var_dump($search_groupby);
643  foreach ($search_groupby as $key => $val) {
644  if (!empty($arrayofgroupby[$val])) {
645  $tmpval = explode('.', $val);
646  //var_dump($arrayofxaxis[$val]['table']);
647  if (! in_array($arrayofgroupby[$val]['table'], $listoftablesalreadyadded)) { // We do not add join for main table already added
648  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$arrayofgroupby[$val]['table']." as ".$tmpval[0]." ON t.".str_replace('t__', '', $tmpval[0])." = ".$tmpval[0].".rowid";
649  $listoftablesalreadyadded[$arrayofgroupby[$val]['table']] = $arrayofgroupby[$val]['table'];
650  }
651  } else {
652  dol_print_error($db, 'Found a key into search_groupby not found into arrayofgroupby');
653  }
654  }
655 
656  // Add LEFT JOIN for all parent tables mentionned into the Yaxis
657  //var_dump($arrayofgroupby); var_dump($search_groupby);
658  foreach ($search_measures as $key => $val) {
659  if (!empty($arrayofmesures[$val])) {
660  $tmpval = explode('.', $val);
661  //var_dump($arrayofxaxis[$val]['table']);
662  if (! in_array($arrayofmesures[$val]['table'], $listoftablesalreadyadded)) { // We do not add join for main table already added
663  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$arrayofmesures[$val]['table']." as ".$tmpval[0]." ON t.".str_replace('t__', '', $tmpval[0])." = ".$tmpval[0].".rowid";
664  $listoftablesalreadyadded[$arrayofmesures[$val]['table']] = $arrayofmesures[$val]['table'];
665  }
666  } else {
667  dol_print_error($db, 'Found a key into search_measures not found into arrayofmesures');
668  }
669  }
670 
671  $sql .= " WHERE 1 = 1";
672  if ($object->ismultientitymanaged == 1) { // 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
673  $sql .= " AND t.entity IN (".getEntity($object->element).")";
674  }
675  // Add the where here
676  $sqlfilters = $search_component_params_hidden;
677  if ($sqlfilters) {
678  $errormessage = '';
679  $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
680  if ($errormessage) {
681  print dol_escape_htmltag($errormessage);
682  }
683  }
684  $sql .= " GROUP BY ";
685  foreach ($search_xaxis as $key => $val) {
686  if (preg_match('/\-year$/', $val)) {
687  $tmpval = preg_replace('/\-year$/', '', $val);
688  $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
689  } elseif (preg_match('/\-month$/', $val)) {
690  $tmpval = preg_replace('/\-month$/', '', $val);
691  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
692  } elseif (preg_match('/\-day$/', $val)) {
693  $tmpval = preg_replace('/\-day$/', '', $val);
694  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
695  } else {
696  $sql .= $val.", ";
697  }
698  }
699  foreach ($search_groupby as $key => $val) {
700  if (preg_match('/\-year$/', $val)) {
701  $tmpval = preg_replace('/\-year$/', '', $val);
702  $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
703  } elseif (preg_match('/\-month$/', $val)) {
704  $tmpval = preg_replace('/\-month$/', '', $val);
705  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
706  } elseif (preg_match('/\-day$/', $val)) {
707  $tmpval = preg_replace('/\-day$/', '', $val);
708  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
709  } else {
710  $sql .= $val.', ';
711  }
712  }
713  $sql = preg_replace('/,\s*$/', '', $sql);
714  $sql .= ' ORDER BY ';
715  foreach ($search_xaxis as $key => $val) {
716  if (preg_match('/\-year$/', $val)) {
717  $tmpval = preg_replace('/\-year$/', '', $val);
718  $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
719  } elseif (preg_match('/\-month$/', $val)) {
720  $tmpval = preg_replace('/\-month$/', '', $val);
721  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
722  } elseif (preg_match('/\-day$/', $val)) {
723  $tmpval = preg_replace('/\-day$/', '', $val);
724  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
725  } else {
726  $sql .= $val.', ';
727  }
728  }
729  foreach ($search_groupby as $key => $val) {
730  if (preg_match('/\-year$/', $val)) {
731  $tmpval = preg_replace('/\-year$/', '', $val);
732  $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
733  } elseif (preg_match('/\-month$/', $val)) {
734  $tmpval = preg_replace('/\-month$/', '', $val);
735  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
736  } elseif (preg_match('/\-day$/', $val)) {
737  $tmpval = preg_replace('/\-day$/', '', $val);
738  $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
739  } else {
740  $sql .= $val.', ';
741  }
742  }
743  $sql = preg_replace('/,\s*$/', '', $sql);
744 }
745 //print $sql;
746 
747 $legend = array();
748 foreach ($search_measures as $key => $val) {
749  $legend[] = $langs->trans($arrayofmesures[$val]['label']);
750 }
751 
752 $useagroupby = (is_array($search_groupby) && count($search_groupby));
753 //var_dump($useagroupby);
754 //var_dump($arrayofvaluesforgroupby);
755 
756 // Execute the SQL request
757 $totalnbofrecord = 0;
758 $data = array();
759 if ($sql) {
760  $resql = $db->query($sql);
761  if (!$resql) {
762  dol_print_error($db);
763  }
764 
765  $ifetch = 0;
766  $xi = 0;
767  $oldlabeltouse = '';
768  while ($obj = $db->fetch_object($resql)) {
769  $ifetch++;
770  if ($useagroupby) {
771  $xval = $search_xaxis[0];
772  $fieldforxkey = 'x_0';
773  $xlabel = $obj->$fieldforxkey;
774  $xvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $xval);
775 
776  // Define $xlabel
777  if (!empty($object->fields[$xvalwithoutprefix]['arrayofkeyval'])) {
778  $xlabel = $object->fields[$xvalwithoutprefix]['arrayofkeyval'][$obj->$fieldforxkey];
779  }
780  $labeltouse = (($xlabel || $xlabel == '0') ? dol_trunc($xlabel, 20, 'middle') : ($xlabel === '' ? $langs->transnoentitiesnoconv("Empty") : $langs->transnoentitiesnoconv("NotDefined")));
781 
782  if ($oldlabeltouse && ($labeltouse != $oldlabeltouse)) {
783  $xi++; // Increase $xi
784  }
785  //var_dump($labeltouse.' '.$oldlabeltouse.' '.$xi);
786  $oldlabeltouse = $labeltouse;
787 
788  /* Example of value for $arrayofvaluesforgroupby
789  * array (size=1)
790  * 'g_0' =>
791  * array (size=6)
792  * 0 => string '0' (length=1)
793  * '' => string 'Empty' (length=5)
794  * '__NULL__' => string 'Not defined' (length=11)
795  * 'done' => string 'done' (length=4)
796  * 'processing' => string 'processing' (length=10)
797  * 'undeployed' => string 'undeployed' (length=10)
798  */
799  foreach ($search_measures as $key => $val) {
800  $gi = 0;
801  foreach ($search_groupby as $gkey) {
802  //var_dump('*** Fetch #'.$ifetch.' for labeltouse='.$labeltouse.' measure number '.$key.' and group g_'.$gi);
803  //var_dump($arrayofvaluesforgroupby);
804  foreach ($arrayofvaluesforgroupby['g_'.$gi] as $gvaluepossiblekey => $gvaluepossiblelabel) {
805  $ykeysuffix = $gvaluepossiblelabel;
806  $gvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $gval);
807 
808  $fieldfory = 'y_'.$key;
809  $fieldforg = 'g_'.$gi;
810  $fieldforybis = 'y_'.$key.'_'.$ykeysuffix;
811  //var_dump('gvaluepossiblekey='.$gvaluepossiblekey.' gvaluepossiblelabel='.$gvaluepossiblelabel.' ykeysuffix='.$ykeysuffix.' gval='.$gval.' gvalwithoutsuffix='.$gvalwithoutprefix);
812  //var_dump('fieldforg='.$fieldforg.' obj->$fieldforg='.$obj->$fieldforg.' fieldfory='.$fieldfory.' obj->$fieldfory='.$obj->$fieldfory.' fieldforybis='.$fieldforybis);
813 
814  if (!is_array($data[$xi])) {
815  $data[$xi] = array();
816  }
817 
818  if (!array_key_exists('label', $data[$xi])) {
819  $data[$xi] = array();
820  $data[$xi]['label'] = $labeltouse;
821  }
822 
823  $objfieldforg = $obj->$fieldforg;
824  if (is_null($objfieldforg)) {
825  $objfieldforg = '__NULL__';
826  }
827 
828  if ($gvaluepossiblekey == '0') { // $gvaluepossiblekey can have type int or string. So we create a special if, used when value is '0'
829  //var_dump($objfieldforg.' == \'0\' -> '.($objfieldforg == '0'));
830  if ($objfieldforg == '0') {
831  // The record we fetch is for this group
832  $data[$xi][$fieldforybis] = $obj->$fieldfory;
833  } elseif (!isset($data[$xi][$fieldforybis])) {
834  // The record we fetch is not for this group
835  $data[$xi][$fieldforybis] = '0';
836  }
837  } else {
838  //var_dump((string) $objfieldforg.' === '.(string) $gvaluepossiblekey.' -> '.((string) $objfieldforg === (string) $gvaluepossiblekey));
839  if ((string) $objfieldforg === (string) $gvaluepossiblekey) {
840  // The record we fetch is for this group
841  $data[$xi][$fieldforybis] = $obj->$fieldfory;
842  } elseif (!isset($data[$xi][$fieldforybis])) {
843  // The record we fetch is not for this group
844  $data[$xi][$fieldforybis] = '0';
845  }
846  }
847  }
848  //var_dump($data[$xi]);
849  $gi++;
850  }
851  }
852  } else { // No group by
853  $xval = $search_xaxis[0];
854  $fieldforxkey = 'x_0';
855  $xlabel = $obj->$fieldforxkey;
856  $xvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $xval);
857 
858  // Define $xlabel
859  if (!empty($object->fields[$xvalwithoutprefix]['arrayofkeyval'])) {
860  $xlabel = $object->fields[$xvalwithoutprefix]['arrayofkeyval'][$obj->$fieldforxkey];
861  }
862 
863  $labeltouse = (($xlabel || $xlabel == '0') ? dol_trunc($xlabel, 20, 'middle') : ($xlabel === '' ? $langs->trans("Empty") : $langs->trans("NotDefined")));
864  $xarrayforallseries = array('label' => $labeltouse);
865  foreach ($search_measures as $key => $val) {
866  $fieldfory = 'y_'.$key;
867  $xarrayforallseries[$fieldfory] = $obj->$fieldfory;
868  }
869  $data[$xi] = $xarrayforallseries;
870  $xi++;
871  }
872  }
873 
874  $totalnbofrecord = count($data);
875 }
876 //var_dump($data);
877 
878 
879 print '<div class="customreportsoutput'.($totalnbofrecord ? '' : ' customreportsoutputnotdata').'">';
880 
881 
882 if ($mode == 'grid') {
883  // TODO
884 }
885 
886 if ($mode == 'graph') {
887  $WIDTH = '80%';
888  $HEIGHT = 200;
889 
890  // Show graph
891  $px1 = new DolGraph();
892  $mesg = $px1->isGraphKo();
893  if (!$mesg) {
894  //var_dump($legend);
895  //var_dump($data);
896  $px1->SetData($data);
897  unset($data);
898 
899  $arrayoftypes = array();
900  foreach ($search_measures as $key => $val) {
901  $arrayoftypes[] = $search_graph;
902  }
903 
904  $px1->SetLegend($legend);
905  $px1->SetMinValue($px1->GetFloorMinValue());
906  $px1->SetMaxValue($px1->GetCeilMaxValue());
907  $px1->SetWidth($WIDTH);
908  $px1->SetHeight($HEIGHT);
909  $px1->SetYLabel($langs->trans("Y"));
910  $px1->SetShading(3);
911  $px1->SetHorizTickIncrement(1);
912  $px1->SetCssPrefix("cssboxes");
913  $px1->SetType($arrayoftypes);
914  $px1->mode = 'depth';
915  $px1->SetTitle('');
916 
917  $dir = $conf->user->dir_temp;
918  dol_mkdir($dir);
919  $filenamenb = $dir.'/customreport_'.$object->element.'.png';
920  $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=user&file=customreport_'.$object->element.'.png';
921 
922  $px1->draw($filenamenb, $fileurlnb);
923 
924  $texttoshow = $langs->trans("NoRecordFound");
925  if (!GETPOSTISSET('search_measures') || !GETPOSTISSET('search_xaxis')) {
926  $texttoshow = $langs->trans("SelectYourGraphOptionsFirst");
927  }
928 
929  print $px1->show($totalnbofrecord ? 0 : $texttoshow);
930  }
931 }
932 
933 if ($sql) {
934  // Show admin info
935  print '<br>'.info_admin($langs->trans("SQLUsedForExport").':<br> '.$sql, 0, 0, 1, '', 'TechnicalInformation');
936 }
937 
938 print '<div>';
939 
940 if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) {
941  print dol_get_fiche_end();
942 }
943 
944 // End of page
945 llxFooter();
946 
947 $db->close();
948 
949 
950 
951 
952 
964 function fillArrayOfMeasures($object, $tablealias, $labelofobject, &$arrayofmesures, $level = 0, &$count = 0)
965 {
966  global $langs, $extrafields, $db;
967 
968  if ($level > 10) { // Protection against infinite loop
969  return $arrayofmesures;
970  }
971 
972  if ($level == 0) {
973  // Add the count of record only for the main/first level object. Parents are necessarly unique for each record.
974  $arrayofmesures[$tablealias.'.count'] = array(
975  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': Count',
976  'position' => 0,
977  'table' => $object->table_element
978  );
979  }
980 
981  // Add main fields of object
982  foreach ($object->fields as $key => $val) {
983  if (!empty($val['isameasure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1, 1, '1'))) {
984  $position = (empty($val['position']) ? 0 : intVal($val['position']));
985  $arrayofmesures[$tablealias.'.'.$key.'-sum'] = array(
986  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$langs->trans("Sum").')</span>',
987  'position' => ($position + ($count * 100000)).'.1',
988  'table' => $object->table_element
989  );
990  $arrayofmesures[$tablealias.'.'.$key.'-average'] = array(
991  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$langs->trans("Average").')</span>',
992  'position' => ($position + ($count * 100000)).'.2',
993  'table' => $object->table_element
994  );
995  $arrayofmesures[$tablealias.'.'.$key.'-min'] = array(
996  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$langs->trans("Minimum").')</span>',
997  'position' => ($position + ($count * 100000)).'.3',
998  'table' => $object->table_element
999  );
1000  $arrayofmesures[$tablealias.'.'.$key.'-max'] = array(
1001  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$langs->trans("Maximum").')</span>',
1002  'position' => ($position + ($count * 100000)).'.4',
1003  'table' => $object->table_element
1004  );
1005  }
1006  }
1007  // Add extrafields to Measures
1008  if (!empty($object->isextrafieldmanaged)) {
1009  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
1010  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'))) {
1011  $position = (!empty($val['position']) ? $val['position'] : 0);
1012  $arrayofmesures[$tablealias.'e.'.$key.'-sum'] = array(
1013  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' <span class="opacitymedium">('.$langs->trans("Sum").')</span>',
1014  'position' => ($position+($count * 100000)).'.1',
1015  'table' => $object->table_element
1016  );
1017  $arrayofmesures[$tablealias.'e.'.$key.'-average'] = array(
1018  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' <span class="opacitymedium">('.$langs->trans("Average").')</span>',
1019  'position' => ($position+($count * 100000)).'.2',
1020  'table' => $object->table_element
1021  );
1022  $arrayofmesures[$tablealias.'e.'.$key.'-min'] = array(
1023  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' <span class="opacitymedium">('.$langs->trans("Minimum").')</span>',
1024  'position' => ($position+($count * 100000)).'.3',
1025  'table' => $object->table_element
1026  );
1027  $arrayofmesures[$tablealias.'e.'.$key.'-max'] = array(
1028  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' <span class="opacitymedium">('.$langs->trans("Maximum").')</span>',
1029  'position' => ($position+($count * 100000)).'.4',
1030  'table' => $object->table_element
1031  );
1032  }
1033  }
1034  }
1035  // Add fields for parent objects
1036  foreach ($object->fields as $key => $val) {
1037  if (preg_match('/^[^:]+:[^:]+:/', $val['type'])) {
1038  $tmptype = explode(':', $val['type'], 4);
1039  if ($tmptype[0] == 'integer' && $tmptype[1] && $tmptype[2]) {
1040  $newobject = $tmptype[1];
1041  dol_include_once($tmptype[2]);
1042  if (class_exists($newobject)) {
1043  $tmpobject = new $newobject($db);
1044  //var_dump($key); var_dump($tmpobject->element); var_dump($val['label']); var_dump($tmptype); var_dump('t-'.$key);
1045  $count++;
1046  $arrayofmesures = fillArrayOfMeasures($tmpobject, $tablealias.'__'.$key, $langs->trans($val['label']), $arrayofmesures, $level + 1, $count);
1047  } else {
1048  print 'For property '.$object->element.'->'.$key.', type="'.$val['type'].'": Failed to find class '.$newobject." in file ".$tmptype[2]."<br>\n";
1049  }
1050  }
1051  }
1052  }
1053 
1054  return $arrayofmesures;
1055 }
1056 
1057 
1069 function fillArrayOfXAxis($object, $tablealias, $labelofobject, &$arrayofxaxis, $level = 0, &$count = 0)
1070 {
1071  global $langs, $extrafields, $db;
1072 
1073  if ($level > 10) { // Protection against infinite loop
1074  return $arrayofxaxis;
1075  }
1076 
1077  if ($level >= 2) {
1078  return $arrayofxaxis;
1079  }
1080 
1081  $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);
1082  $MM = substr($langs->trans("Month"), 0, 1).substr($langs->trans("Month"), 0, 1);
1083  $DD = substr($langs->trans("Day"), 0, 1).substr($langs->trans("Day"), 0, 1);
1084  $HH = substr($langs->trans("Hour"), 0, 1).substr($langs->trans("Hour"), 0, 1);
1085  $MI = substr($langs->trans("Minute"), 0, 1).substr($langs->trans("Minute"), 0, 1);
1086  $SS = substr($langs->trans("Second"), 0, 1).substr($langs->trans("Second"), 0, 1);
1087 
1088  // Add main fields of object
1089  foreach ($object->fields as $key => $val) {
1090  if (empty($val['measure'])) {
1091  if (in_array($key, array(
1092  'id', 'ref_ext', 'rowid', 'entity', 'last_main_doc', 'logo', 'logo_squarred', 'extraparams',
1093  'parent', 'photo', 'socialnetworks', 'webservices_url', 'webservices_key'))) {
1094  continue;
1095  }
1096  if (isset($val['enabled']) && !dol_eval($val['enabled'], 1, 1, '1')) {
1097  continue;
1098  }
1099  if (isset($val['visible']) && !dol_eval($val['visible'], 1, 1, '1')) {
1100  continue;
1101  }
1102  if (preg_match('/^fk_/', $key) && !preg_match('/^fk_statu/', $key)) {
1103  continue;
1104  }
1105  if (preg_match('/^pass/', $key)) {
1106  continue;
1107  }
1108  if (in_array($val['type'], array('html', 'text'))) {
1109  continue;
1110  }
1111  if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
1112  $position = (empty($val['position']) ? 0 : intVal($val['position']));
1113  $arrayofxaxis[$tablealias.'.'.$key.'-year'] = array(
1114  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.')</span>',
1115  'position' => ($position + ($count * 100000)).'.1',
1116  'table' => $object->table_element
1117  );
1118  $arrayofxaxis[$tablealias.'.'.$key.'-month'] = array(
1119  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.'-'.$MM.')</span>',
1120  'position' => ($position + ($count * 100000)).'.2',
1121  'table' => $object->table_element
1122  );
1123  $arrayofxaxis[$tablealias.'.'.$key.'-day'] = array(
1124  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.'-'.$MM.'-'.$DD.')</span>',
1125  'position' => ($position + ($count * 100000)).'.3',
1126  'table' => $object->table_element
1127  );
1128  } else {
1129  $position = (empty($val['position']) ? 0 : intVal($val['position']));
1130  $arrayofxaxis[$tablealias.'.'.$key] = array(
1131  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']),
1132  'position' => ($position + ($count * 100000)),
1133  'table' => $object->table_element
1134  );
1135  }
1136  }
1137  }
1138 
1139  // Add extrafields to X-Axis
1140  if (!empty($object->isextrafieldmanaged)) {
1141  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
1142  if ($extrafields->attributes[$object->table_element]['type'][$key] == 'separate') {
1143  continue;
1144  }
1145  if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key])) {
1146  continue;
1147  }
1148  $arrayofxaxis[$tablealias.'e.'.$key] = array(
1149  'label' => img_picto('', $object->picto, 'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]),
1150  'position' => 1000 + (int) $extrafields->attributes[$object->table_element]['pos'][$key] + ($count * 100000),
1151  'table' => $object->table_element
1152  );
1153  }
1154  }
1155 
1156  // Add fields for parent objects
1157  foreach ($object->fields as $key => $val) {
1158  if (preg_match('/^[^:]+:[^:]+:/', $val['type'])) {
1159  $tmptype = explode(':', $val['type'], 4);
1160  if ($tmptype[0] == 'integer' && $tmptype[1] && $tmptype[2]) {
1161  $newobject = $tmptype[1];
1162  dol_include_once($tmptype[2]);
1163  if (class_exists($newobject)) {
1164  $tmpobject = new $newobject($db);
1165  //var_dump($key); var_dump($tmpobject->element); var_dump($val['label']); var_dump($tmptype); var_dump('t-'.$key);
1166  $count++;
1167  $arrayofxaxis = fillArrayOfXAxis($tmpobject, $tablealias.'__'.$key, $langs->trans($val['label']), $arrayofxaxis, $level + 1, $count);
1168  } else {
1169  print 'For property '.$object->element.'->'.$key.', type="'.$val['type'].'": Failed to find class '.$newobject." in file ".$tmptype[2]."<br>\n";
1170  }
1171  }
1172  }
1173  }
1174 
1175  return $arrayofxaxis;
1176 }
1177 
1178 
1190 function fillArrayOfGroupBy($object, $tablealias, $labelofobject, &$arrayofgroupby, $level = 0, &$count = 0)
1191 {
1192  global $langs, $extrafields, $db;
1193 
1194  if ($level > 10) { // Protection against infinite loop
1195  return $arrayofgroupby;
1196  }
1197 
1198  if ($level >= 2) {
1199  return $arrayofgroupby;
1200  }
1201 
1202  $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);
1203  $MM = substr($langs->trans("Month"), 0, 1).substr($langs->trans("Month"), 0, 1);
1204  $DD = substr($langs->trans("Day"), 0, 1).substr($langs->trans("Day"), 0, 1);
1205  $HH = substr($langs->trans("Hour"), 0, 1).substr($langs->trans("Hour"), 0, 1);
1206  $MI = substr($langs->trans("Minute"), 0, 1).substr($langs->trans("Minute"), 0, 1);
1207  $SS = substr($langs->trans("Second"), 0, 1).substr($langs->trans("Second"), 0, 1);
1208 
1209  // Add main fields of object
1210  foreach ($object->fields as $key => $val) {
1211  if (empty($val['isameasure'])) {
1212  if (in_array($key, array(
1213  'id', 'ref_ext', 'rowid', 'entity', 'last_main_doc', 'logo', 'logo_squarred', 'extraparams',
1214  'parent', 'photo', 'socialnetworks', 'webservices_url', 'webservices_key'))) {
1215  continue;
1216  }
1217  if (isset($val['enabled']) && !dol_eval($val['enabled'], 1, 1, '1')) {
1218  continue;
1219  }
1220  if (isset($val['visible']) && !dol_eval($val['visible'], 1, 1, '1')) {
1221  continue;
1222  }
1223  if (preg_match('/^fk_/', $key) && !preg_match('/^fk_statu/', $key)) {
1224  continue;
1225  }
1226  if (preg_match('/^pass/', $key)) {
1227  continue;
1228  }
1229  if (in_array($val['type'], array('html', 'text'))) {
1230  continue;
1231  }
1232  if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
1233  $position = (empty($val['position']) ? 0 : intVal($val['position']));
1234  $arrayofgroupby[$tablealias.'.'.$key.'-year'] = array(
1235  'label' => img_picto('', $object->picto,
1236  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.')</span>', 'position' => ($position + ($count * 100000)).'.1',
1237  'table' => $object->table_element
1238  );
1239  $arrayofgroupby[$tablealias.'.'.$key.'-month'] = array(
1240  'label' => img_picto('', $object->picto,
1241  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.'-'.$MM.')</span>', 'position' => ($position + ($count * 100000)).'.2',
1242  'table' => $object->table_element
1243  );
1244  $arrayofgroupby[$tablealias.'.'.$key.'-day'] = array(
1245  'label' => img_picto('', $object->picto,
1246  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']).' <span class="opacitymedium">('.$YYYY.'-'.$MM.'-'.$DD.')</span>', 'position' => ($position + ($count * 100000)).'.3',
1247  'table' => $object->table_element
1248  );
1249  } else {
1250  $position = (empty($val['position']) ? 0 : intVal($val['position']));
1251  $arrayofgroupby[$tablealias.'.'.$key] = array(
1252  'label' => img_picto('', $object->picto,
1253  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($val['label']), 'position' => ($position + ($count * 100000)),
1254  'table' => $object->table_element
1255  );
1256  }
1257  }
1258  }
1259 
1260  // Add extrafields to Group by
1261  if (!empty($object->isextrafieldmanaged)) {
1262  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
1263  if ($extrafields->attributes[$object->table_element]['type'][$key] == 'separate') {
1264  continue;
1265  }
1266  if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key])) {
1267  continue;
1268  }
1269  $arrayofgroupby[$tablealias.'e.'.$key] = array(
1270  'label' => img_picto('', $object->picto,
1271  'class="pictofixedwidth"').' '.$labelofobject.': '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]), 'position' => 1000 + (int) $extrafields->attributes[$object->table_element]['pos'][$key] + ($count * 100000),
1272  'table' => $object->table_element
1273  );
1274  }
1275  }
1276 
1277  // Add fields for parent objects
1278  foreach ($object->fields as $key => $val) {
1279  if (preg_match('/^[^:]+:[^:]+:/', $val['type'])) {
1280  $tmptype = explode(':', $val['type'], 4);
1281  if ($tmptype[0] == 'integer' && $tmptype[1] && $tmptype[2]) {
1282  $newobject = $tmptype[1];
1283  dol_include_once($tmptype[2]);
1284  if (class_exists($newobject)) {
1285  $tmpobject = new $newobject($db);
1286  //var_dump($key); var_dump($tmpobject->element); var_dump($val['label']); var_dump($tmptype); var_dump('t-'.$key);
1287  $count++;
1288  $arrayofgroupby = fillArrayOfGroupBy($tmpobject, $tablealias.'__'.$key, $langs->trans($val['label']), $arrayofgroupby, $level + 1, $count);
1289  } else {
1290  print 'For property '.$object->element.'->'.$key.', type="'.$val['type'].'": Failed to find class '.$newobject." in file ".$tmptype[2]."<br>\n";
1291  }
1292  }
1293  }
1294  }
1295 
1296  return $arrayofgroupby;
1297 }
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
fillArrayOfGroupBy($object, $tablealias, $labelofobject, &$arrayofgroupby, $level=0, &$count=0)
Fill arrayofgrupby for an object.
fillArrayOfMeasures($object, $tablealias, $labelofobject, &$arrayofmesures, $level=0, &$count=0)
Fill arrayofmesures for an object.
fillArrayOfXAxis($object, $tablealias, $labelofobject, &$arrayofxaxis, $level=0, &$count=0)
Fill arrayofmesures for an object.
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
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.
forgeSQLFromUniversalSearchCriteria($filter, &$error='')
forgeSQLFromUniversalSearchCriteria
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.