diff --git a/htdocs/core/class/dolgraph.class.php b/htdocs/core/class/dolgraph.class.php index 2ebb0f9e2b6..ccdd5931366 100644 --- a/htdocs/core/class/dolgraph.class.php +++ b/htdocs/core/class/dolgraph.class.php @@ -970,18 +970,32 @@ class DolGraph //if ($nblot > 2) $firstlot = ($nblot - 2); // We limit nblot to 2 because jflot can't manage more than 2 bars on same x $i = $firstlot; - $serie = array(); + $serie = array(); $arrayofgroupslegend = array(); while ($i < $nblot) // Loop on each serie { - $values = array(); // Array with horizontal y values (specific values of a serie) for each abscisse x + $values = array(); // Array with horizontal y values (specific values of a serie) for each abscisse x (with x=0,1,2,...) $serie[$i] = ""; - + //var_dump($this->data);exit; // Fill array $values $x = 0; foreach ($this->data as $valarray) // Loop on each x { - $legends[$x] = $valarray[0]; - $values[$x] = (is_numeric($valarray[$i + 1]) ? $valarray[$i + 1] : null); + $legends[$x] = (array_key_exists('label', $valarray) ? $valarray['label'] : $valarray[0]); + $array_of_ykeys = array_keys($valarray); + $alabelexists = 1; + $tmpykey = explode('_', ($array_of_ykeys[$i+($alabelexists ? 1 : 0)]), 3); + if (! empty($tmpykey[2])) { // This is a group by array + $tmpvalue = (array_key_exists('y_'.$tmpykey[1].'_'.$tmpykey[2], $valarray) ? $valarray['y_'.$tmpykey[1].'_'.$tmpykey[2]] : $valarray[$i + 1]); + $values[$x] = (is_numeric($tmpvalue) ? $tmpvalue : null); + $arrayofgroupslegend[$i] = array( + 'stacknum'=> $tmpykey[1], + 'legend' => $this->Legend[$tmpykey[1]], + 'legendwithgroup' => $this->Legend[$tmpykey[1]].' - '.$tmpykey[2] + ); + } else { + $tmpvalue = (array_key_exists('y_'.$i, $valarray) ? $valarray['y_'.$i] : $valarray[$i + 1]); + $values[$x] = (is_numeric($tmpvalue) ? $tmpvalue : null); + } $x++; } @@ -993,7 +1007,7 @@ class DolGraph } } - unset($values); + $values = null; // Free mem $i++; } $tag = dol_escape_htmltag(dol_string_unaccent(dol_string_nospecial(basename($file), '_', array('-', '.')))); @@ -1129,9 +1143,14 @@ class DolGraph if (!isset($this->type[$firstlot]) || $this->type[$firstlot] == 'bars') $type = 'bar'; if (isset($this->type[$firstlot]) && ($this->type[$firstlot] == 'lines' || $this->type[$firstlot] == 'linesnopoint')) $type = 'line'; - $this->stringtoshow .= ' - var options = { maintainAspectRatio: false, aspectRatio: 2.5 }; + $this->stringtoshow .= 'var options = { maintainAspectRatio: false, aspectRatio: 2.5'; + if (count($arrayofgroupslegend) > 0) { + $this->stringtoshow .= ', scales: {xAxes: [{ stacked: true, }], yAxes: [{ stacked: true }] }'; + } + $this->stringtoshow .= '};'; + + $this->stringtoshow .= ' var ctx = document.getElementById("canvas_'.$tag.'").getContext("2d"); var chart = new Chart(ctx, { // The type of chart we want to create @@ -1149,24 +1168,59 @@ class DolGraph $i++; } + //var_dump($arrayofgroupslegend); + $this->stringtoshow .= '], datasets: ['; - $i = 0; + + $i = 0; $iinstack = 0; + $oldstacknum = -1; while ($i < $nblot) // Loop on each serie { - $color = 'rgb('.$this->datacolor[$i][0].', '.$this->datacolor[$i][1].', '.$this->datacolor[$i][2].')'; - //$color = (!empty($data['seriescolor']) ? json_encode($data['seriescolor']) : json_encode($datacolor)); + if (count($arrayofgroupslegend[$i]) > 0) { // We used a 'group by' + // If we change the stack + $newcolor = $this->datacolor[$arrayofgroupslegend[$i]['stacknum']]; + if ($oldstacknum == -1 || $arrayofgroupslegend[$i]['stacknum'] != $oldstacknum) { + $iinstack = 0; + //var_dump('iinstack='.$iinstack.' - '.colorArrayToHex($newcolor)); + } else { + // Change color with offset of $$iinstack + //var_dump($newcolor); + $ratio = max(-90, -10 * $iinstack); + $brightnessratio = min(90, 20 * $iinstack); + $newcolor = array_values(colorHexToRgb(colorAgressiveness(colorArrayToHex($newcolor), $ratio, $brightnessratio), false, true)); + //var_dump($ratio.' '.$brightnessratio); + //var_dump($newcolor); + } + $oldstacknum = $arrayofgroupslegend[$i]['stacknum']; - if ($i > 0) $this->stringtoshow .= ', '."\n"; - $this->stringtoshow .= '{'."\n"; - $this->stringtoshow .= 'label: "'.$this->Legend[$i].'",'; + $color = 'rgb('.$newcolor[0].', '.$newcolor[1].', '.$newcolor[2].', 0.9)'; + $bordercolor = 'rgb('.$newcolor[0].', '.$newcolor[1].', '.$newcolor[2].')'; + $textoflegend = $arrayofgroupslegend[$i]['legendwithgroup']; + + } else { + $color = 'rgb('.$this->datacolor[$i][0].', '.$this->datacolor[$i][1].', '.$this->datacolor[$i][2].', 0.9)'; + $bordercolor = $color; + //$color = (!empty($data['seriescolor']) ? json_encode($data['seriescolor']) : json_encode($datacolor)); + $textoflegend = $this->Legend[$i]; + } + + if ($i > 0) $this->stringtoshow .= ', '; + $this->stringtoshow .= "\n"; + $this->stringtoshow .= '{'; + $this->stringtoshow .= 'dolibarrinfo: \'y_'.$i.'\', '; + $this->stringtoshow .= 'label: \''.dol_escape_js(dol_string_nohtmltag($textoflegend)).'\', '; $this->stringtoshow .= 'pointStyle: \''.($this->type[$i] == 'linesnopoint' ? 'line' : 'circle').'\', '; $this->stringtoshow .= 'fill: '.($type == 'bar' ? 'true' : 'false').', '; - $this->stringtoshow .= 'borderColor: \''.$color.'\', '; + $this->stringtoshow .= 'borderWidth: \'1\', '; + $this->stringtoshow .= 'borderColor: \''.$bordercolor.'\', '; $this->stringtoshow .= 'backgroundColor: \''.$color.'\', '; - $this->stringtoshow .= ' data: ['.$serie[$i].']'; + if ($arrayofgroupslegend[$i]) $this->stringtoshow .= 'stack: \''.$arrayofgroupslegend[$i]['stacknum'].'\', '; + $this->stringtoshow .= 'data: ['.$serie[$i].']'; $this->stringtoshow .= '}'."\n"; + $i++; + $iinstack++; } $this->stringtoshow .= ']'."\n"; $this->stringtoshow .= '}'."\n"; diff --git a/htdocs/core/customreports.php b/htdocs/core/customreports.php index 5ad3e7d8e02..7c3e0233c66 100644 --- a/htdocs/core/customreports.php +++ b/htdocs/core/customreports.php @@ -108,9 +108,6 @@ elseif (is_array($hookmanager->resArray)) { $arrayoftype[$key] = $val; } } - if (!empty($hookmanager->resArray['modenotusedforlist'])) { // Show objecttype selection even if objecttype is set - $modenotusedforlist = $hookmanager->resArray['modenotusedforlist']; - } } if ($objecttype) { @@ -145,6 +142,22 @@ $search_array_options = $extrafields->getOptionalsFromPost($object->table_elemen $search_component_params = array(''); +$MAXUNIQUEVALFORGROUP = 20; +$MAXMEASURESINBARGRAPH = 20; +$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); +$MM=substr($langs->trans("Month"), 0, 1).substr($langs->trans("Month"), 0, 1); +$DD=substr($langs->trans("Day"), 0, 1).substr($langs->trans("Day"), 0, 1); +$HH=substr($langs->trans("Hour"), 0, 1).substr($langs->trans("Hour"), 0, 1); +$MI=substr($langs->trans("Minute"), 0, 1).substr($langs->trans("Minute"), 0, 1); +$SS=substr($langs->trans("Second"), 0, 1).substr($langs->trans("Second"), 0, 1); + +$arrayofmesures = array('t.count'=>'Count'); +$arrayofxaxis = array(); +$arrayofgroupby = array(); +$arrayofyaxis = array(); +$arrayofvaluesforgroupby = array(); + + /* * Actions @@ -175,17 +188,72 @@ if ($action == 'viewgraph') { $search_xaxis = array(0 => $search_xaxis[0]); } if (count($search_groupby) >= 2) { - setEventMessages($langs->trans("OnlyOneFieldForGroupByIsPossible"), null, 'warnings'); - $search_groupby = array(0 => $search_groupb[0]); + setEventMessages($langs->trans("ErrorOnlyOneFieldForGroupByIsPossible"), null, 'warnings'); + $search_groupby = array(0 => $search_groupby[0]); } if (!count($search_xaxis)) { setEventMessages($langs->trans("AtLeastOneXAxisIsRequired"), null, 'warnings'); - } elseif ($mode == 'graph' && $search_graph == 'bars' && count($search_measures) > 3) { - setEventMessages($langs->trans("GraphInBarsAreLimitedTo3Measures"), null, 'warnings'); + } elseif ($mode == 'graph' && $search_graph == 'bars' && count($search_measures) > $MAXMEASURESINBARGRAPH) { + $langs->load("errors"); + setEventMessages($langs->trans("GraphInBarsAreLimitedToNMeasures", $MAXMEASURESINBARGRAPH), null, 'warnings'); $search_graph = 'lines'; } } + +// Get all possible values of fields when a 'group by' is set and save this into $arrayofvaluesforgroupby +if (is_array($search_groupby) && count($search_groupby)) { + foreach($search_groupby as $gkey => $gval) { + $gvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $gval); + + if (preg_match('/\-year$/', $search_groupby[$gkey])) { + $tmpval = preg_replace('/\-year$/', '', $search_groupby[$gkey]); + $fieldtocount .= 'DATE_FORMAT('.$tmpval.", '%Y')"; + } elseif (preg_match('/\-month$/', $search_groupby[$gkey])) { + $tmpval = preg_replace('/\-month$/', '', $search_groupby[$gkey]); + $fieldtocount .= 'DATE_FORMAT('.$tmpval.", '%Y-%m')"; + } elseif (preg_match('/\-day$/', $search_groupby[$gkey])) { + $tmpval = preg_replace('/\-day$/', '', $search_groupby[$gkey]); + $fieldtocount .= 'DATE_FORMAT('.$tmpval.", '%Y-%m-%d')"; + } else { + $fieldtocount = $search_groupby[$gkey]; + } + + $sql = 'SELECT DISTINCT '.$fieldtocount.' as val'; + $sql.= ' FROM '.MAIN_DB_PREFIX.$object->table_element.' as t'; + // TODO Add the where here + + $sql.= ' LIMIT '.($MAXUNIQUEVALFORGROUP + 1); + $resql = $db->query($sql); + if (!$resql) { + dol_print_error($db); + } + + while ($obj = $db->fetch_object($resql)) { + $valuetranslated = $obj->val; + if (!empty($object->fields[$gvalwithoutprefix]['arrayofkeyval'])) { + $valuetranslated = $object->fields[$gvalwithoutprefix]['arrayofkeyval'][$obj->val]; + } + + $arrayofvaluesforgroupby['g_'.$gkey][$obj->val] = $valuetranslated; + } + asort($arrayofvaluesforgroupby['g_'.$gkey]); + + if (count($arrayofvaluesforgroupby['g_'.$gkey]) > $MAXUNIQUEVALFORGROUP) { + $langs->load("errors"); + //var_dump($gkey.' '.$gval.' '.$gvalwithoutprefix); + $gvalwithoutprefix = preg_replace('/\-(year|month|day)/', '', $gvalwithoutprefix); + $labeloffield = $langs->transnoentitiesnoconv($object->fields[$gvalwithoutprefix]['label']); + setEventMessages($langs->trans("ErrorTooManyDifferentValueForSelectedGroupBy", $MAXUNIQUEVALFORGROUP, $labeloffield), null, 'warnings'); + $search_groupby = array(); + } + + $db->free($resql); + } +} +//var_dump($arrayofvaluesforgroupby);exit; + + $tmparray = dol_getdate(dol_now()); $endyear = $tmparray['year']; $endmonth = $tmparray['mon']; @@ -194,12 +262,6 @@ $startyear = $endyear - 2; $param = ''; -$arrayofmesures = array('t.count'=>'Count'); -$arrayofxaxis = array(); -$arrayofgroupby = array(); -$arrayofyaxis = array(); -$arrayofvaluesforgroupby = array(); - print '
'; - -// Get all possible values of fields when a group by is set -if (is_array($search_groupby) && count($search_groupby)) { - $sql = 'SELECT DISTINCT '.$search_groupby[0].' as val FROM '.MAIN_DB_PREFIX.$object->table_element.' as t'; - $resql = $db->query($sql); - if (!$resql) { - dol_print_error($db); - } - - while ($obj = $db->fetch_object($resql)) { - $arrayofvaluesforgroupby[$obj->val] = $obj->val; - } -} - // Generate the SQL request $sql = ''; if (!empty($search_measures) && !empty($search_xaxis)) @@ -426,15 +474,15 @@ if (!empty($search_measures) && !empty($search_xaxis)) foreach ($search_groupby as $key => $val) { if (preg_match('/\-year$/', $val)) { $tmpval = preg_replace('/\-year$/', '', $val); - $sql .= 'DATE_FORMAT('.$tmpval.", '%Y'), "; + $sql .= 'DATE_FORMAT('.$tmpval.", '%Y') as g_".$key.', '; } elseif (preg_match('/\-month$/', $val)) { $tmpval = preg_replace('/\-month$/', '', $val); - $sql .= 'DATE_FORMAT('.$tmpval.", '%Y-%m'), "; + $sql .= 'DATE_FORMAT('.$tmpval.", '%Y-%m') as g_".$key.', '; } elseif (preg_match('/\-day$/', $val)) { $tmpval = preg_replace('/\-day$/', '', $val); - $sql .= 'DATE_FORMAT('.$tmpval.", '%Y-%m-%d'), "; + $sql .= 'DATE_FORMAT('.$tmpval.", '%Y-%m-%d') as g_".$key.', '; } - else $sql .= $val.', '; + else $sql .= $val.' as g_'.$key.', '; } foreach ($search_measures as $key => $val) { if ($val == 't.count') $sql .= 'COUNT(t.'.$fieldid.') as y_'.$key.', '; @@ -519,9 +567,22 @@ if (!empty($search_measures) && !empty($search_xaxis)) } else $sql .= $val.', '; } + foreach ($search_groupby as $key => $val) { + if (preg_match('/\-year$/', $val)) { + $tmpval = preg_replace('/\-year$/', '', $val); + $sql .= 'DATE_FORMAT('.$tmpval.", '%Y'), "; + } elseif (preg_match('/\-month$/', $val)) { + $tmpval = preg_replace('/\-month$/', '', $val); + $sql .= 'DATE_FORMAT('.$tmpval.", '%Y-%m'), "; + } elseif (preg_match('/\-day$/', $val)) { + $tmpval = preg_replace('/\-day$/', '', $val); + $sql .= 'DATE_FORMAT('.$tmpval.", '%Y-%m-%d'), "; + } + else $sql .= $val.', '; + } $sql = preg_replace('/,\s*$/', '', $sql); } - +//print $sql; $legend = array(); foreach ($search_measures as $key => $val) { @@ -537,27 +598,74 @@ if ($sql) { dol_print_error($db); } + $xi = 0; $oldlabeltouse = ''; while ($obj = $db->fetch_object($resql)) { - // $this->data = array(array(0=>'labelxA',1=>yA1,...,n=>yAn), array('labelxB',yB1,...yBn)); // or when there is n series to show for each x - foreach ($search_xaxis as $xkey => $xval) { - $fieldforxkey = 'x_'.$xkey; - $xlabel = $obj->$fieldforxkey; - $xvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $xval); - if (!empty($object->fields[$xvalwithoutprefix]['arrayofkeyval'])) { - $xlabel = $object->fields[$xvalwithoutprefix]['arrayofkeyval'][$obj->$fieldforxkey]; - } - $xarray = array(0 => (($xlabel || $xlabel == '0') ? dol_trunc($xlabel, 20, 'middle') : $langs->trans("NotDefined"))); - foreach ($search_measures as $key => $val) { - $fieldfory = 'y_'.$key; - $xarray[] = $obj->$fieldfory; - } - $data[] = $xarray; - } + if (is_array($search_groupby) && count($search_groupby)) { + $xval = 'x_0'; + $fieldforxkey = 'x_0'; + $xlabel = $obj->$fieldforxkey; + $xvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $xval); + if (!empty($object->fields[$xvalwithoutprefix]['arrayofkeyval'])) { + $xlabel = $object->fields[$xvalwithoutprefix]['arrayofkeyval'][$obj->$fieldforxkey]; + } + $labeltouse = (($xlabel || $xlabel == '0') ? dol_trunc($xlabel, 20, 'middle') : ($xlabel === '' ? $langs->trans("Empty") : $langs->trans("NotDefined"))); + + if ($oldlabeltouse && ($labeltouse != $oldlabeltouse)) { + $xi++; // Increase $xi + } + //var_dump($labeltouse.' '.$oldlabeltouse.' '.$xi); + $oldlabeltouse = $labeltouse; + + foreach ($search_measures as $key => $val) { + $gi = 0; + foreach ($search_groupby as $gkey) { + //var_dump($arrayofvaluesforgroupby['g_'.$gi]);exit; + foreach($arrayofvaluesforgroupby['g_'.$gi] as $gvaluepossiblekey => $gvaluepossibleval) { + $ykeysuffix = $gvaluepossibleval; + $gvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $gval); + + //var_dump('For measure '.$key.' g_'.$gi.' gvaluepossiblekey='.$gvaluepossiblekey.' gvaluepossibleval='.$gvaluepossibleval.' '.$ykeysuffix.' '.$gval.' '.$gvalwithoutprefix); + $fieldfory = 'y_'.$key; + $fieldforg = 'g_'.$gi; + $fieldforybis = 'y_'.$key.'_'.$ykeysuffix; + + if (! array_key_exists('label', $data[$xi])) { + $data[$xi] = array(); + $data[$xi]['label'] = $labeltouse; + } + + if ($obj->$fieldforg == $gvaluepossiblekey) { + $data[$xi][$fieldforybis] = $obj->$fieldfory; + } + elseif (! isset($data[$xi][$fieldforybis])) { + $data[$xi][$fieldforybis] = '0'; + } + } + $gi++; + } + } + } else { // No group by + $xval = 'x_0'; + $fieldforxkey = 'x_0'; + $xlabel = $obj->$fieldforxkey; + $xvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $xval); + if (!empty($object->fields[$xvalwithoutprefix]['arrayofkeyval'])) { + $xlabel = $object->fields[$xvalwithoutprefix]['arrayofkeyval'][$obj->$fieldforxkey]; + } + $labeltouse = (($xlabel || $xlabel == '0') ? dol_trunc($xlabel, 20, 'middle') : ($xlabel === '' ? $langs->trans("Empty") : $langs->trans("NotDefined"))); + $xarrayforallseries = array('label' => $labeltouse); + foreach ($search_measures as $key => $val) { + $fieldfory = 'y_'.$key; + $xarrayforallseries[$fieldfory] = $obj->$fieldfory; + } + $data[$xi] = $xarrayforallseries; + $xi++; + } } $totalnbofrecord = count($data); } - +//var_dump($data); print '