Debug statistics of project module

This commit is contained in:
Laurent Destailleur 2015-07-05 22:04:30 +02:00
parent 089056f024
commit 8eb4a208ce
9 changed files with 235 additions and 70 deletions

View File

@ -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);
}
}

View File

@ -1,6 +1,6 @@
<?php
/* Copyright (c) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (c) 2004-2013 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (c) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
*
* 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.='<div style="font-size:8pt;text-align:center;padding:2px;color:white;">';
if ($urltemp) $this->stringtoshow.='<a style="color: #FFFFFF;" border="0" href="'.$urltemp.'">';
$this->stringtoshow.='\'+';
$this->stringtoshow.=($showlegend?'':'label+\'<br/>\'+'); // Hide label if already shown in legend
$this->stringtoshow.=($showpointvalue?'number+':'');
$this->stringtoshow.=($showpercent?'\'<br/>\'+percent+\'%\'+':'');
$this->stringtoshow.='\'';
if ($urltemp) $this->stringtoshow.='</a>';
$this->stringtoshow.='</div>\';
},
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.='<div style="font-size:8pt;text-align:center;padding:2px;color:black;">';
if ($urltemp) $this->stringtoshow.='<a style="color: #FFFFFF;" border="0" href="'.$urltemp.'">';
$this->stringtoshow.='\'+';
$this->stringtoshow.=($showlegend?'':'label+\' \'+'); // Hide label if already shown in legend
$this->stringtoshow.=($showpointvalue?'number+':'');
$this->stringtoshow.=($showpercent?'\'<br/>\'+percent+\'%\'+':'');
$this->stringtoshow.='\'';
if ($urltemp) $this->stringtoshow.='</a>';
$this->stringtoshow.='</div>\';
},
background: {
opacity: 0.0,
color: \'#000000\'
}
}
}
},
zoom: {
interactive: true
interactive: true
},
pan: {
interactive: true
interactive: true
},';
if (count($datacolor))
{

View File

@ -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 '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">';
print '<div style="font-size:8pt;text-align:center;padding:2px;color:black;">';
if ($url) print '<a style="color: #FFFFFF;" border="0" href="'.$url.'=">';
print '\'+'.($showlegend?'number':'label+\'<br/>\'+number');
print '\'+'.($showlegend?'number':'label+\' \'+number');
if (! empty($showpercent)) print '+\'<br/>\'+percent+\'%\'';
print '+\'';
if ($url) print '</a>';
print '</div>\';
},
background: {
opacity: 0.5,
opacity: 0.0,
color: \'#000000\'
}
},
}
}
},

View File

@ -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 '<ul'.(empty($pere['rowid'])?' id="treeData"':'').'>'; $ulprinted++; }
print "\n".'<li>';
print "\n".'<li '.($tab[$x]['statut']?' class="liuseractive"':'class="liuserdisabled"').'>';
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 '<ul'.(empty($pere['rowid'])?' id="treeData"':'').'>'; $ulprinted++; }
print "\n".'<li>';
print "\n".'<li '.($tab[$x]['statut']?' class="liuseractive"':'class="liuserdisabled"').'>';
print $tab[$x]['entry'];
// And now we search all its sons of lower level
tree_recur($tab,$tab[$x],$rang+1);

View File

@ -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
OpportunityTotalAmount=Opportunities total amount
OpportunityPonderatedAmount=Opportunities weighted amount
OppStatusPROSP=Prospection
OppStatusQUAL=Qualification
OppStatusPROPO=Proposal
OppStatusNEGO=Negociation
OppStatusPENDING=Pending
OppStatusWIN=Won
OppStatusLOST=Lost

View File

@ -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 '<br>';
return $res;
}
/**
* Return amount of elements by month for several years
*

View File

@ -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 "<tr ".$bc[$var].">";
print '<td>'.$labelstatus.'</td>';
print '<td align="right"><a href="list.php?statut='.$status.'">'.(isset($vals[$status])?$vals[$status]:0).'</a></td>';
print '<td align="right"><a href="list.php?statut='.$status.'">'.price((isset($valsamount[$status])?(float) $valsamount[$status]:0), 0, '', 1, -1, -1, $conf->currency).'</a></td>';
print "</tr>\n";
}
}
@ -185,12 +191,13 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES))
{
print '<tr class="impair"><td align="center" colspan="2">';
$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 '</td></tr>';
}
//if ($totalinprocess != $total)
//print '<tr class="liste_total"><td>'.$langs->trans("Total").' ('.$langs->trans("CustomersOrdersRunning").')</td><td align="right">'.$totalinprocess.'</td></tr>';
print '<tr class="liste_total"><td>'.$langs->trans("Total").'</td><td align="right">'.$total.'</td></tr>';
print '<tr class="liste_total"><td>'.$langs->trans("OpportunityTotalAmount").'</td><td align="right">'.price($totalamount, 0, '', 1, -1, -1, $conf->currency).'</td></tr>';
print '<tr class="liste_total"><td>'.$langs->trans("OpportunityPonderatedAmount").'</td><td align="right">'.price($ponderated_opp_amount, 0, '', 1, -1, -1, $conf->currency).'</td></tr>';
print "</table><br>";
}
else

View File

@ -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 '</div><div class="fichetwothirdright"><div class="ficheaddleft">';
$stringtoshow.= '<table class="border" width="100%"><tr valign="top"><td align="center">';
if ($mesg) { print $mesg; }
else {
if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES))
{
$stringtoshow.= $px->show();
$stringtoshow.= "<br>\n";
}
$stringtoshow.= $px1->show();
$stringtoshow.= "<br>\n";
if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES))
{
$stringtoshow.= $px->show();
$stringtoshow.= "<br>\n";
$stringtoshow.= $px2->show();
$stringtoshow.= "<br>\n";
$stringtoshow.= $px3->show();

View File

@ -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'=>'<table class="nobordernopadding centpercent"><tr><td>'.$li.'</td><td align="right">'.$userstatic->getLibStatut(5).'</td></tr></table>'
'statut'=>$val['statut'],
'entry'=>'<table class="nobordernopadding centpercent"><tr><td class="'.($val['statut']?'usertdenabled':'usertddisabled').'">'.$li.'</td><td align="right" class="'.($val['statut']?'usertdenabled':'usertddisabled').'">'.$userstatic->getLibStatut(5).'</td></tr></table>'
);
}
/*print $langs->trans("Status").': ';
print $form->selectarray('search_statut', array('-1'=>'','0'=>$langs->trans('Disabled'),'1'=>$langs->trans('Enabled')),$search_statut);
*/
print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">'."\n";
$param="search_statut=".$search_statut;
print '<table class="liste nohover" width="100%">';
print '<tr class="liste_titre">';
@ -132,7 +138,7 @@ print '<td>&nbsp;</td>';
print '<td>&nbsp;</td>';
// Status
print '<td align="right">';
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 '</td>';
print '<td class="liste_titre" align="right"><input type="image" class="liste_titre" name="button_search" src="'.img_picto($langs->trans("Search"),'search.png','','',1).'" value="'.dol_escape_htmltag($langs->trans("Search")).'" title="'.dol_escape_htmltag($langs->trans("Search")).'">';
print '<input type="image" class="liste_titre" name="button_removefilter" src="'.img_picto($langs->trans("Search"),'searchclear.png','','',1).'" value="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'" title="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'">';
@ -165,7 +171,19 @@ else
}
print "</table>";
print "</form>\n";
//
/*print '<script type="text/javascript" language="javascript">
jQuery(document).ready(function() {
function init_myfunc()
{
jQuery(".usertddisabled").hide();
}
init_myfunc();
});
</script>';
*/
llxFooter();