Browse Source

Work on the generic Graphic Reporting tool

Laurent Destailleur 5 years ago
parent
commit
52c236570b

+ 70 - 16
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";

+ 166 - 58
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 '<form method="post" action="'.$_SERVER['PHP_SELF'].'">';
 print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
 print '<input type="hidden" name="action" value="viewgraph">';
@@ -277,9 +339,9 @@ foreach ($object->fields as $key => $val) {
 		if (preg_match('/^pass/', $key)) continue;
 		if (in_array($val['type'], array('html', 'text'))) continue;
 		if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
-			$arrayofgroupby['t.'.$key.'-year'] = array('label' => $langs->trans($val['label']).' ('.$langs->trans("Year").')', 'position' => $val['position'].'-y');
-			$arrayofgroupby['t.'.$key.'-month'] = array('label' => $langs->trans($val['label']).' ('.$langs->trans("Month").')', 'position' => $val['position'].'-m');
-			$arrayofgroupby['t.'.$key.'-day'] = array('label' => $langs->trans($val['label']).' ('.$langs->trans("Day").')', 'position' => $val['position'].'-d');
+			$arrayofgroupby['t.'.$key.'-year'] = array('label' => $langs->trans($val['label']).' ('.$YYYY.')', 'position' => $val['position'].'-y');
+			$arrayofgroupby['t.'.$key.'-month'] = array('label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.')', 'position' => $val['position'].'-m');
+			$arrayofgroupby['t.'.$key.'-day'] = array('label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.'-'.$DD.')', 'position' => $val['position'].'-d');
 		} else {
 			$arrayofgroupby['t.'.$key] = array('label' => $val['label'], 'position' => (int) $val['position']);
 		}
@@ -316,9 +378,9 @@ foreach ($object->fields as $key => $val) {
         if (preg_match('/^pass/', $key)) continue;
         if (in_array($val['type'], array('html', 'text'))) continue;
         if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
-            $arrayofxaxis['t.'.$key.'-year'] = array('label' => $langs->trans($val['label']).' ('.$langs->trans("Year").')', 'position' => $val['position'].'-y');
-            $arrayofxaxis['t.'.$key.'-month'] = array('label' => $langs->trans($val['label']).' ('.$langs->trans("Month").')', 'position' => $val['position'].'-m');
-            $arrayofxaxis['t.'.$key.'-day'] = array('label' => $langs->trans($val['label']).' ('.$langs->trans("Day").')', 'position' => $val['position'].'-d');
+        	$arrayofxaxis['t.'.$key.'-year'] = array('label' => $langs->trans($val['label']).' ('.$YYYY.')', 'position' => $val['position'].'-y');
+            $arrayofxaxis['t.'.$key.'-month'] = array('label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.')', 'position' => $val['position'].'-m');
+            $arrayofxaxis['t.'.$key.'-day'] = array('label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.'-'.$DD.')', 'position' => $val['position'].'-d');
         } else {
             $arrayofxaxis['t.'.$key] = array('label' => $val['label'], 'position' => (int) $val['position']);
         }
@@ -350,9 +412,9 @@ if ($mode == 'grid') {
             if (preg_match('/^fk_/', $key)) continue;
             if (in_array($val['type'], array('html', 'text'))) continue;
             if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
-                $arrayofyaxis['t.'.$key.'-year'] = array('label' => $langs->trans($val['label']).' ('.$langs->trans("Year").')', 'position' => $val['position']);
-                $arrayofyaxis['t.'.$key.'-month'] = array('label' => $langs->trans($val['label']).' ('.$langs->trans("Month").')', 'position' => $val['position']);
-                $arrayofyaxis['t.'.$key.'-day'] = array('label' => $langs->trans($val['label']).' ('.$langs->trans("Day").')', 'position' => $val['position']);
+            	$arrayofyaxis['t.'.$key.'-year'] = array('label' => $langs->trans($val['label']).' ('.$YYYY.')', 'position' => $val['position']);
+                $arrayofyaxis['t.'.$key.'-month'] = array('label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.')', 'position' => $val['position']);
+                $arrayofyaxis['t.'.$key.'-day'] = array('label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.'-'.$DD.')', 'position' => $val['position']);
             } else {
                 $arrayofyaxis['t.'.$key] = array('label' => $val['label'], 'position' => (int) $val['position']);
             }
@@ -389,20 +451,6 @@ print '</div>';
 print '</div>';
 print '</form>';
 
-
-// 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 '<div class="customreportsoutput'.($totalnbofrecord ? '' : ' customreportsoutputnotdata').'">';
 
@@ -569,7 +677,7 @@ if ($mode == 'grid') {
 if ($mode == 'graph') {
     $WIDTH = '80%';
     $HEIGHT = 200;
-    var_dump($data);
+
     // Show graph
     $px1 = new DolGraph();
     $mesg = $px1->isGraphKo();

+ 1 - 1
htdocs/core/lib/functions2.lib.php

@@ -2377,7 +2377,7 @@ function colorLighten($hex, $percent)
 /**
  * @param string 	$hex 			color in hex
  * @param float 	$alpha 			0 to 1 to add alpha channel
- * @param bool 		$returnArray	Array set to 1 to return an array instead of string
+ * @param bool 		$returnArray	true=return an array instead, false=return string
  * @return string|array				String or array
  */
 function colorHexToRgb($hex, $alpha = false, $returnArray = false)

+ 2 - 0
htdocs/langs/en_US/errors.lang

@@ -233,6 +233,8 @@ ErrorLanguageMandatoryIfPageSetAsTranslationOfAnother=Error, language is mandato
 ErrorLanguageOfTranslatedPageIsSameThanThisPage=Error, language of translated page is same than this one. 
 ErrorBatchNoFoundForProductInWarehouse=No lot/serial found for product "%s" in warehouse "%s".
 ErrorBatchNoFoundEnoughQuantityForProductInWarehouse=No enough quantity for this lot/serial for product "%s" in warehouse "%s".
+ErrorOnlyOneFieldForGroupByIsPossible=Only 1 field for the 'Group by' is possible (others are discarded)
+ErrorTooManyDifferentValueForSelectedGroupBy=Too many different value (more than <b>%s</b>) for field '<b>%s</b>' to use it as a 'Group by' for graphics. Group By field has been removed. May be you wanted to use it as an X-Axis
 # Warnings
 WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup.
 WarningPasswordSetWithNoAccount=A password was set for this member. However, no user account was created. So this password is stored but can't be used to login to Dolibarr. It may be used by an external module/interface but if you don't need to define any login nor password for a member, you can disable option "Manage a login for each member" from Member module setup. If you need to manage a login but don't need any password, you can keep this field empty to avoid this warning. Note: Email can also be used as a login if the member is linked to a user.

+ 1 - 1
htdocs/langs/en_US/other.lang

@@ -30,7 +30,7 @@ PreviousYearOfInvoice=Previous year of invoice date
 NextYearOfInvoice=Following year of invoice date
 DateNextInvoiceBeforeGen=Date of next invoice (before generation)
 DateNextInvoiceAfterGen=Date of next invoice (after generation)
-GraphInBarsAreLimitedTo3Measures=Grapics are limited to 3 measures in 'Bars' mode. The mode 'Lines' was automatically selected instead.
+GraphInBarsAreLimitedToNMeasures=Grapics are limited to %s measures in 'Bars' mode. The mode 'Lines' was automatically selected instead.
 OnlyOneFieldForXAxisIsPossible=Only 1 field is currently possible as X-Axis. Only the first selected field has been selected.
 AtLeastOneMeasureIsRequired=At least 1 field for measure is required
 AtLeastOneXAxisIsRequired=At least 1 field for X-Axis is required