diff --git a/htdocs/core/boxes/box_graph_product_distribution.php b/htdocs/core/boxes/box_graph_product_distribution.php index b81bd2f9578..ca851961857 100644 --- a/htdocs/core/boxes/box_graph_product_distribution.php +++ b/htdocs/core/boxes/box_graph_product_distribution.php @@ -180,6 +180,7 @@ class box_graph_product_distribution extends ModeleBoxes //$px1->mode='depth'; $px1->SetType(array('pie')); $px1->SetTitle($langs->trans("BoxProductDistributionFor",$paramtitle,$langs->transnoentitiesnoconv("Invoices"))); + $px1->combine = 0.05; $px1->draw($filenamenb,$fileurlnb); } @@ -238,6 +239,7 @@ class box_graph_product_distribution extends ModeleBoxes //$px2->mode='depth'; $px2->SetType(array('pie')); $px2->SetTitle($langs->trans("BoxProductDistributionFor",$paramtitle,$langs->transnoentitiesnoconv("Proposals"))); + $px2->combine = 0.05; $px2->draw($filenamenb,$fileurlnb); } @@ -297,6 +299,8 @@ class box_graph_product_distribution extends ModeleBoxes //$px3->mode='depth'; $px3->SetType(array('pie')); $px3->SetTitle($langs->trans("BoxProductDistributionFor",$paramtitle,$langs->transnoentitiesnoconv("Orders"))); + $px3->combine = 0.05; + $px3->draw($filenamenb,$fileurlnb); } } diff --git a/htdocs/core/class/dolgraph.class.php b/htdocs/core/class/dolgraph.class.php index b65c5c8ede4..0b713de80ff 100644 --- a/htdocs/core/class/dolgraph.class.php +++ b/htdocs/core/class/dolgraph.class.php @@ -1,6 +1,6 @@ - * Copyright (c) 2004-2013 Laurent Destailleur + * Copyright (c) 2004-2015 Laurent Destailleur * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,7 +56,7 @@ class DolGraph var $showlegend=1; var $showpointvalue=1; var $showpercent=0; - + var $combine=0; // 0.05 if you want to combine records < 5% into "other" var $graph; // Objet Graph (Artichow, Phplot...) var $error; @@ -875,39 +875,43 @@ class DolGraph function plotWithOptions_'.$tag.'() { $.plot($("#placeholder_'.$tag.'"), d0, { - series: { - pie: { - show: true, - radius: 3/4, - label: { - show: true, - radius: 3/4, - formatter: function(label, series) { - var percent=Math.round(series.percent); - var number=series.data[0][1]; - return \''; - $this->stringtoshow.='
'; - if ($urltemp) $this->stringtoshow.=''; - $this->stringtoshow.='\'+'; - $this->stringtoshow.=($showlegend?'':'label+\'
\'+'); // Hide label if already shown in legend - $this->stringtoshow.=($showpointvalue?'number+':''); - $this->stringtoshow.=($showpercent?'\'
\'+percent+\'%\'+':''); - $this->stringtoshow.='\''; - if ($urltemp) $this->stringtoshow.='
'; - $this->stringtoshow.='
\'; - }, - background: { - opacity: 0.5, - color: \'#000000\' - } - } - } + series: { + pie: { + show: true, + radius: 0.8, + '.($this->combine ? ' + combine: { + threshold: '.$this->combine.' + },' : '') . ' + label: { + show: true, + radius: 0.9, + formatter: function(label, series) { + var percent=Math.round(series.percent); + var number=series.data[0][1]; + return \''; + $this->stringtoshow.='
'; + if ($urltemp) $this->stringtoshow.=''; + $this->stringtoshow.='\'+'; + $this->stringtoshow.=($showlegend?'':'label+\' \'+'); // Hide label if already shown in legend + $this->stringtoshow.=($showpointvalue?'number+':''); + $this->stringtoshow.=($showpercent?'\'
\'+percent+\'%\'+':''); + $this->stringtoshow.='\''; + if ($urltemp) $this->stringtoshow.='
'; + $this->stringtoshow.='
\'; + }, + background: { + opacity: 0.0, + color: \'#000000\' + } + } + } }, zoom: { - interactive: true + interactive: true }, pan: { - interactive: true + interactive: true },'; if (count($datacolor)) { diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 5d75d7ad5d6..8b9ca77f6a9 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1777,26 +1777,29 @@ function dol_print_graph($htmlid,$width,$height,$data,$showlegend=0,$type='pie', series: { pie: { show: true, - radius: 3/4, + radius: 0.8, + combine: { + threshold: 0.05 + }, label: { show: true, - radius: 3/4, + radius: 0.9, formatter: function(label, series) { var percent=Math.round(series.percent); var number=series.data[0][1]; return \''; - print '
'; + print '
'; if ($url) print ''; - print '\'+'.($showlegend?'number':'label+\'
\'+number'); + print '\'+'.($showlegend?'number':'label+\' \'+number'); if (! empty($showpercent)) print '+\'
\'+percent+\'%\''; print '+\''; if ($url) print '
'; print '
\'; }, background: { - opacity: 0.5, + opacity: 0.0, color: \'#000000\' - } + }, } } }, diff --git a/htdocs/core/lib/treeview.lib.php b/htdocs/core/lib/treeview.lib.php index 08fa63c52c6..5b1682c5494 100644 --- a/htdocs/core/lib/treeview.lib.php +++ b/htdocs/core/lib/treeview.lib.php @@ -144,7 +144,7 @@ function tree_recur($tab, $pere, $rang, $iddivjstree='iddivjstree') if ($tab[$x]['fk_menu'] != -1 && $tab[$x]['fk_menu'] == $pere['rowid']) { if (empty($ulprinted) && ! empty($pere['rowid'])) { print ''; $ulprinted++; } - print "\n".'
  • '; + print "\n".'
  • '; print $tab[$x]['entry']; // And now we search all its sons of lower level tree_recur($tab,$tab[$x],$rang+1); @@ -153,7 +153,7 @@ function tree_recur($tab, $pere, $rang, $iddivjstree='iddivjstree') elseif (! empty($tab[$x]['rowid']) && $tab[$x]['fk_menu'] == -1 && $tab[$x]['fk_mainmenu'] == $pere['mainmenu'] && $tab[$x]['fk_leftmenu'] == $pere['leftmenu']) { if (empty($ulprinted) && ! empty($pere['rowid'])) { print ''; $ulprinted++; } - print "\n".'
  • '; + print "\n".'
  • '; print $tab[$x]['entry']; // And now we search all its sons of lower level tree_recur($tab,$tab[$x],$rang+1); diff --git a/htdocs/langs/en_US/projects.lang b/htdocs/langs/en_US/projects.lang index 09ac5dd44a7..0aaac7816bd 100644 --- a/htdocs/langs/en_US/projects.lang +++ b/htdocs/langs/en_US/projects.lang @@ -165,7 +165,18 @@ ProjectOverview=Overview ManageTasks=Use projects to follow tasks and time ManageOpportunitiesStatus=Use projects to follow leads/opportinuties ProjectNbProjectByMonth=Nb of created projects by month +ProjectOppAmountOfProjectsByMonth=Amount of opportunities by month +ProjectWeightedOppAmountOfProjectsByMonth=Weighted amount of opportunities by month +ProjectOpenedProjectByOppStatus=Opened project/lead by opportunity status ProjectsStatistics=Statistics on projects/leads TaskAssignedToEnterTime=Task assigned. Entering time on this task should be possible. OpenedProjectsByThirdparties=Opened projects by thirdparties -OpportunityPonderatedAmount=Opportunities ponderated amount \ No newline at end of file +OpportunityTotalAmount=Opportunities total amount +OpportunityPonderatedAmount=Opportunities weighted amount +OppStatusPROSP=Prospection +OppStatusQUAL=Qualification +OppStatusPROPO=Proposal +OppStatusNEGO=Negociation +OppStatusPENDING=Pending +OppStatusWIN=Won +OppStatusLOST=Lost diff --git a/htdocs/projet/class/projectstats.class.php b/htdocs/projet/class/projectstats.class.php index 27335777db1..ae99bb14188 100644 --- a/htdocs/projet/class/projectstats.class.php +++ b/htdocs/projet/class/projectstats.class.php @@ -54,6 +54,7 @@ class ProjectStats extends Stats $sql .= " count(DISTINCT t.rowid), t.fk_opp_status"; $sql .= " FROM " . MAIN_DB_PREFIX . "projet as t"; $sql .= $this->buildWhere(); + $sql .= " AND t.fk_statut = 1"; $sql .= " GROUP BY t.fk_opp_status"; $result = array (); @@ -118,7 +119,7 @@ class ProjectStats extends Stats */ public function buildWhere() { $sqlwhere_str = ''; - $sqlwhere = array (); + $sqlwhere = array(); $sqlwhere[] = ' t.entity IN (' . getEntity('project') . ')'; @@ -192,6 +193,126 @@ class ProjectStats extends Stats return $res; } + + /** + * Return amount of elements by month for several years + * + * @param int $endyear Start year + * @param int $startyear End year + * @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save) + * @return array Array of values + */ + function getWeightedAmountByMonthWithPrevYear($endyear,$startyear,$cachedelay=0) + { + global $conf,$user,$langs; + + if ($startyear > $endyear) return -1; + + $datay=array(); + + // Search into cache + if (! empty($cachedelay)) + { + include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php'; + } + + $newpathofdestfile=$conf->user->dir_temp.'/'.get_class($this).'_'.__FUNCTION__.'_'.(empty($this->cachefilesuffix)?'':$this->cachefilesuffix.'_').$langs->defaultlang.'_user'.$user->id.'.cache'; + $newmask='0644'; + + $nowgmt = dol_now(); + + $foundintocache=0; + if ($cachedelay > 0) + { + $filedate=dol_filemtime($newpathofdestfile); + if ($filedate >= ($nowgmt - $cachedelay)) + { + $foundintocache=1; + + $this->_lastfetchdate[get_class($this).'_'.__FUNCTION__]=$filedate; + } + else + { + dol_syslog(get_class($this).'::'.__FUNCTION__." cache file ".$newpathofdestfile." is not found or older than now - cachedelay (".$nowgmt." - ".$cachedelay.") so we can't use it."); + } + } + + // Load file into $data + if ($foundintocache) // Cache file found and is not too old + { + dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate."."); + $data = json_decode(file_get_contents($newpathofdestfile), true); + } + else + { + $year=$startyear; + while($year <= $endyear) + { + $datay[$year] = $this->getWeightedAmountByMonth($year); + $year++; + } + + $data = array(); + // $data = array('xval'=>array(0=>xlabel,1=>yval1,2=>yval2...),...) + for ($i = 0 ; $i < 12 ; $i++) + { + $data[$i][]=$datay[$endyear][$i][0]; // set label + $year=$startyear; + while($year <= $endyear) + { + $data[$i][]=$datay[$year][$i][1]; // set yval for x=i + $year++; + } + } + } + + // Save cache file + if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) + { + dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk."); + if (! dol_is_dir($conf->user->dir_temp)) dol_mkdir($conf->user->dir_temp); + $fp = fopen($newpathofdestfile, 'w'); + if ($fp) + { + fwrite($fp, json_encode($data)); + fclose($fp); + if (! empty($conf->global->MAIN_UMASK)) $newmask=$conf->global->MAIN_UMASK; + @chmod($newpathofdestfile, octdec($newmask)); + } + else dol_syslog("Failed to write cache file", LOG_ERR); + $this->_lastfetchdate[get_class($this).'_'.__FUNCTION__]=$nowgmt; + } + + return $data; + } + + + /** + * Return the Project amount by month for a year + * + * @param int $year scan + * @return array with amount by month + */ + function getWeightedAmountByMonth($year) { + global $user; + + $this->yearmonth = $year; + + $sql = "SELECT date_format(t.datec,'%m') as dm, SUM(t.opp_amount)"; + $sql .= " FROM " . MAIN_DB_PREFIX . "projet as t"; + if (! $user->rights->societe->client->voir && ! $user->societe_id) + $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id; + $sql .= $this->buildWhere(); + $sql .= " GROUP BY dm"; + $sql .= $this->db->order('dm', 'DESC'); + $this->yearmonth=0; + + $res = $this->_getAmountByMonth($year, $sql); + // var_dump($res);print '
    '; + return $res; + } + /** * Return amount of elements by month for several years * diff --git a/htdocs/projet/index.php b/htdocs/projet/index.php index 264afb449f9..2625b1f8503 100644 --- a/htdocs/projet/index.php +++ b/htdocs/projet/index.php @@ -123,7 +123,7 @@ if (! empty($conf->projet->enabled) && $user->rights->projet->lire) if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) { - $sql = "SELECT count(p.rowid), p.fk_opp_status as status"; + $sql = "SELECT COUNT(p.rowid) as nb, SUM(p.opp_amount) as opp_amount, p.fk_opp_status as opp_status"; $sql.= " FROM ".MAIN_DB_PREFIX."projet as p"; $sql.= " WHERE p.entity = ".$conf->entity; $sql.= " AND p.fk_statut = 1"; @@ -136,20 +136,25 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) $num = $db->num_rows($resql); $i = 0; - $total=0; - $totalinprocess=0; + $totalnb=0; + $totalamount=0; + $ponderated_opp_amount=0; + $valsnb=array(); + $valsamount=array(); $dataseries=array(); - $vals=array(); // -1=Canceled, 0=Draft, 1=Validated, (2=Accepted/On process not managed for customer orders), 3=Closed (Sent/Received, billed or not) while ($i < $num) { - $row = $db->fetch_row($resql); - if ($row) + $obj = $db->fetch_object($resql); + if ($obj) { //if ($row[1]!=-1 && ($row[1]!=3 || $row[2]!=1)) { - $vals[$row[1]]=$row[0]; - $totalinprocess+=$row[0]; + $valsnb[$obj->opp_status]=$obj->nb; + $valsamount[$obj->opp_status]=$obj->opp_amount; + $totalnb+=$obj->nb; + $totalamount+=$obj->opp_amount; + $ponderated_opp_amount = $ponderated_opp_amount + price2num($listofoppstatus[$obj->opp_status] * $obj->opp_amount / 100); } $total+=$row[0]; } @@ -169,15 +174,16 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) if ($code) $labelstatus = $langs->trans("OppStatus".$code); if (empty($labelstatus)) $labelstatus=$listofopplabel[$status]; - $labelstatus .= ' ('.$langs->trans("Coeff").': '.$listofoppstatus[$status].')'; + //$labelstatus .= ' ('.$langs->trans("Coeff").': '.price2num($listofoppstatus[$status]).')'; + $labelstatus .= ' - '.price2num($listofoppstatus[$status]).'%'; - $dataseries[]=array('label'=>$labelstatus,'data'=>(isset($vals[$status])?(int) $vals[$status]:0)); + $dataseries[]=array('label'=>$labelstatus,'data'=>(isset($valsamount[$status])?(float) $valsamount[$status]:0)); if (! $conf->use_javascript_ajax) { $var=!$var; print ""; print ''.$labelstatus.''; - print ''.(isset($vals[$status])?$vals[$status]:0).''; + print ''.price((isset($valsamount[$status])?(float) $valsamount[$status]:0), 0, '', 1, -1, -1, $conf->currency).''; print "\n"; } } @@ -185,12 +191,13 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) { print ''; $data=array('series'=>$dataseries); - dol_print_graph('stats',400,180,$data,1,'pie',1); + dol_print_graph('stats',400,180,$data,1,'pie',0,''); print ''; } //if ($totalinprocess != $total) //print ''.$langs->trans("Total").' ('.$langs->trans("CustomersOrdersRunning").')'.$totalinprocess.''; - print ''.$langs->trans("Total").''.$total.''; + print ''.$langs->trans("OpportunityTotalAmount").''.price($totalamount, 0, '', 1, -1, -1, $conf->currency).''; + print ''.$langs->trans("OpportunityPonderatedAmount").''.price($ponderated_opp_amount, 0, '', 1, -1, -1, $conf->currency).''; print "
    "; } else diff --git a/htdocs/projet/stats/index.php b/htdocs/projet/stats/index.php index fdb272ed70e..04dd819054e 100644 --- a/htdocs/projet/stats/index.php +++ b/htdocs/projet/stats/index.php @@ -122,7 +122,7 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) $px->SetType(array ( 'pie' )); - $px->SetTitle($langs->trans('ProjectNbProjectByStatus')); + $px->SetTitle($langs->trans('ProjectOpenedProjectByOppStatus')); $result=$px->draw($filenamenb, $fileurlnb); if ($result<0) { setEventMessages($px->error, null, 'errors'); @@ -194,12 +194,12 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) $px2->SetMinValue(min(0,$px2->GetFloorMinValue())); $px2->SetWidth($WIDTH); $px2->SetHeight($HEIGHT); - $px2->SetYLabel($langs->trans("ProjectAmountOfProject")); + $px2->SetYLabel($langs->trans("ProjectOppAmountOfProjectsByMonth")); $px2->SetShading(3); $px2->SetHorizTickIncrement(1); $px2->SetPrecisionY(0); $px2->mode='depth'; - $px2->SetTitle($langs->trans("ProjectAmountOfProjectsByMonth")); + $px2->SetTitle($langs->trans("ProjectOppAmountOfProjectsByMonth")); $px2->draw($filenamenb,$fileurlnb); } @@ -208,7 +208,7 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) { // Build graphic with transformation rate - $data = $stats_project->getTransformRateByMonthWithPrevYear($endyear,$startyear); + $data = $stats_project->getWeightedAmountByMonthWithPrevYear($endyear,$startyear); //var_dump($data); // $data = array(array('Lib',val1,val2,val3),...) @@ -231,12 +231,12 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) $px3->SetMinValue(min(0,$px3->GetFloorMinValue())); $px3->SetWidth($WIDTH); $px3->SetHeight($HEIGHT); - $px3->SetYLabel($langs->trans("ProjectTransRateOfProject")); + $px3->SetYLabel($langs->trans("ProjectWeightedOppAmountOfProjectsByMonth")); $px3->SetShading(3); $px3->SetHorizTickIncrement(1); $px3->SetPrecisionY(0); $px3->mode='depth'; - $px3->SetTitle($langs->trans("ProjectTransRateOfProjectsByMonth")); + $px3->SetTitle($langs->trans("ProjectWeightedOppAmountOfProjectsByMonth")); $px3->draw($filenamenb,$fileurlnb); } @@ -340,15 +340,12 @@ print '
  • '; $stringtoshow.= '
    '; if ($mesg) { print $mesg; } else { - if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) - { - $stringtoshow.= $px->show(); - $stringtoshow.= "
    \n"; - } $stringtoshow.= $px1->show(); $stringtoshow.= "
    \n"; if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) { + $stringtoshow.= $px->show(); + $stringtoshow.= "
    \n"; $stringtoshow.= $px2->show(); $stringtoshow.= "
    \n"; $stringtoshow.= $px3->show(); diff --git a/htdocs/user/hierarchy.php b/htdocs/user/hierarchy.php index 2fc51e555ee..ccaf6687da9 100644 --- a/htdocs/user/hierarchy.php +++ b/htdocs/user/hierarchy.php @@ -48,6 +48,10 @@ $search_statut=GETPOST('search_statut','int'); if ($search_statut == '') $search_statut='1'; +if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter")) // Both test are required to be compatible with all browsers +{ + $search_statut=""; +} /* @@ -87,6 +91,7 @@ foreach($fulltree as $key => $val) $entity=$val['entity']; $entitystring=''; + // TODO Set of entitystring should be done with a hook if (is_object($mc)) { @@ -109,14 +114,15 @@ foreach($fulltree as $key => $val) $data[] = array( 'rowid'=>$val['rowid'], 'fk_menu'=>$val['fk_user'], - 'entry'=>'
    '.$li.''.$userstatic->getLibStatut(5).'
    ' + 'statut'=>$val['statut'], + 'entry'=>'
    '.$li.''.$userstatic->getLibStatut(5).'
    ' ); } -/*print $langs->trans("Status").': '; -print $form->selectarray('search_statut', array('-1'=>'','0'=>$langs->trans('Disabled'),'1'=>$langs->trans('Enabled')),$search_statut); -*/ +print '
    '."\n"; + +$param="search_statut=".$search_statut; print ''; print ''; @@ -132,7 +138,7 @@ print ''; print ''; // Status print ''; print '
      '; -print $form->selectarray('search_statut', array('-1'=>'','0'=>$langs->trans('Disabled'),'1'=>$langs->trans('Enabled')),$search_statut); +print $form->selectarray('search_statut', array('-1'=>'','1'=>$langs->trans('Enabled')),$search_statut); print ''; print ''; @@ -165,7 +171,19 @@ else } print "
    "; +print "
    \n"; +// +/*print ''; +*/ llxFooter();