diff --git a/htdocs/core/class/html.formprojet.class.php b/htdocs/core/class/html.formprojet.class.php index 498604d9307..4f65d5327d1 100644 --- a/htdocs/core/class/html.formprojet.class.php +++ b/htdocs/core/class/html.formprojet.class.php @@ -539,9 +539,10 @@ class FormProjets * @param int $showempty Add an empty line * @param int $useshortlabel Use short label * @param int $showallnone Add choice "All" and "None" + * @param int $showpercent Show default probability for status * @return int|string The HTML select list of element or '' if nothing or -1 if KO */ - function selectOpportunityStatus($htmlname, $preselected=0, $showempty=1, $useshortlabel=0, $showallnone=0) + function selectOpportunityStatus($htmlname, $preselected=0, $showempty=1, $useshortlabel=0, $showallnone=0, $showpercent=0) { global $conf, $langs; @@ -557,7 +558,7 @@ class FormProjets $i = 0; if ($num > 0) { - $sellist = ''; if ($showempty) $sellist.= ''; if ($showallnone) $sellist.= ''; if ($showallnone) $sellist.= ''; @@ -565,7 +566,7 @@ class FormProjets { $obj = $this->db->fetch_object($resql); - $sellist .=''; diff --git a/htdocs/install/mysql/migration/3.9.0-4.0.0.sql b/htdocs/install/mysql/migration/3.9.0-4.0.0.sql index 911e8c957d3..f2b3ff181cc 100644 --- a/htdocs/install/mysql/migration/3.9.0-4.0.0.sql +++ b/htdocs/install/mysql/migration/3.9.0-4.0.0.sql @@ -38,3 +38,5 @@ ALTER TABLE llx_cronjob MODIFY COLUMN unitfrequency varchar(255) NOT NULL DEFAUL ALTER TABLE llx_facture ADD INDEX idx_facture_fk_statut (fk_statut); +UPDATE llx_projet as p set p.opp_percent = (SELECT percent FROM llx_c_lead_status as cls WHERE cls.rowid = p.fk_opp_status) WHERE p.opp_percent IS NULL AND p.fk_opp_status IS NOT NULL; + \ No newline at end of file diff --git a/htdocs/langs/en_US/projects.lang b/htdocs/langs/en_US/projects.lang index 95d6b7fe55f..97f19aebdab 100644 --- a/htdocs/langs/en_US/projects.lang +++ b/htdocs/langs/en_US/projects.lang @@ -132,6 +132,8 @@ TaskModifiedInDolibarr=Task %s modified TaskDeletedInDolibarr=Task %s deleted OpportunityStatus=Opportunity status OpportunityStatusShort=Opp. status +OpportunityProbability=Opportunity probability +OpportunityProbabilityShort=Opp. probab. OpportunityAmount=Opportunity amount OpportunityAmountShort=Opp. amount ##### Types de contacts ##### @@ -182,7 +184,7 @@ YouCanCompleteRef=If you want to complete the ref with some information (to use OpenedProjectsByThirdparties=Opened projects by thirdparties OpportunityTotalAmount=Opportunities total amount OpportunityPonderatedAmount=Opportunities weighted amount -OpportunityPonderatedAmountDesc=Opportunities amount weighted with probability (depending on status of opportunity) +OpportunityPonderatedAmountDesc=Opportunities amount weighted with probability OppStatusPROSP=Prospection OppStatusQUAL=Qualification OppStatusPROPO=Proposal diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index 2266f012964..66baf0c650d 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -42,6 +42,7 @@ $backtopage=GETPOST('backtopage','alpha'); $cancel=GETPOST('cancel','alpha'); $status=GETPOST('status','int'); $opp_status=GETPOST('opp_status','int'); +$opp_percent=price2num(GETPOST('opp_percent','alpha')); if ($id == '' && $ref == '' && ($action != "create" && $action != "add" && $action != "update" && ! $_POST["cancel"])) accessforbidden(); @@ -145,6 +146,7 @@ if (empty($reshook)) $object->date_end=$date_end; $object->statuts = $status; $object->opp_status = $opp_status; + $object->opp_percent = $opp_percent; // Fill array 'array_options' with data from add form $ret = $extrafields->setOptionalsFromPost($extralabels,$object); @@ -232,7 +234,8 @@ if (empty($reshook)) if (isset($_POST['opp_amount'])) $object->opp_amount = price2num(GETPOST('opp_amount')); if (isset($_POST['budget_amount'])) $object->budget_amount= price2num(GETPOST('budget_amount')); if (isset($_POST['opp_status'])) $object->opp_status = $opp_status; - + if (isset($_POST['opp_percent'])) $object->opp_percent = $opp_percent; + // Fill array 'array_options' with data from add form $ret = $extrafields->setOptionalsFromPost($extralabels,$object); if ($ret < 0) $error++; @@ -505,6 +508,13 @@ if ($action == 'create' && $user->rights->projet->creer) print $formproject->selectOpportunityStatus('opp_status',$object->opp_status); print ''; + // Opportunity probability + print ''.$langs->trans("OpportunityProbability").''; + print ' %'; + print ''; + print ''; + print ''; + // Opportunity amount print ''.$langs->trans("OpportunityAmount").''; print ''; @@ -544,7 +554,23 @@ if ($action == 'create' && $user->rights->projet->creer) print ''; print ''; - + + // Change probability from status + print ''; } else { @@ -670,15 +696,20 @@ else print ''; print ''; + // Opportunity probability + print ''.$langs->trans("OpportunityProbability").''; + print ' %'; + print ''; + // Opportunity amount print ''.$langs->trans("OpportunityAmount").''; - print ''; + print ''; print ''; } // Budget print ''.$langs->trans("Budget").''; - print ''; + print ''; print ''; // Description @@ -750,15 +781,20 @@ else if ($code) print $langs->trans("OppStatus".$code); print ''; + // Opportunity percent + print ''.$langs->trans("OpportunityProbability").''; + if (strcmp($object->opp_percent,'')) print price($object->opp_percent,'',$langs,1,0).' %'; + print ''; + // Opportunity Amount print ''.$langs->trans("OpportunityAmount").''; - if (strcmp($object->opp_amount,'')) print price($object->opp_amount,'',$langs,0,0,0,$conf->currency); + if (strcmp($object->opp_amount,'')) print price($object->opp_amount,'',$langs,1,0,0,$conf->currency); print ''; } // Budget print ''.$langs->trans("Budget").''; - if (strcmp($object->budget_amount, '')) print price($object->budget_amount,'',$langs,0,0,0,$conf->currency); + if (strcmp($object->budget_amount, '')) print price($object->budget_amount,'',$langs,1,0,0,$conf->currency); print ''; // Description @@ -788,7 +824,24 @@ else print ''; - + // Change probability from status + print ''; + + /* * Boutons actions */ diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index a0a6bd7ae94..bf08da2231e 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -231,11 +231,12 @@ class Project extends CommonObject global $langs, $conf; $error=0; - + // Clean parameters $this->title = trim($this->title); $this->description = trim($this->description); if ($this->opp_amount < 0) $this->opp_amount=''; + if ($this->opp_percent < 0) $this->opp_percent=''; if (dol_strlen(trim($this->ref)) > 0) { @@ -247,7 +248,7 @@ class Project extends CommonObject $sql.= ", description = '" . $this->db->escape($this->description) . "'"; $sql.= ", fk_soc = " . ($this->socid > 0 ? $this->socid : "null"); $sql.= ", fk_statut = " . $this->statut; - $sql.= ", fk_opp_status = " . ($this->opp_status > 0 ? $this->opp_status : 'null'); + $sql.= ", fk_opp_status = " . ((is_numeric($this->opp_status) && $this->opp_status != '') ? $this->opp_status : 'null'); $sql.= ", opp_percent = " . ((is_numeric($this->opp_percent) && $this->opp_percent != '') ? $this->opp_percent : 'null'); $sql.= ", public = " . ($this->public ? 1 : 0); $sql.= ", datec=" . ($this->date_c != '' ? "'".$this->db->idate($this->date_c)."'" : 'null'); diff --git a/htdocs/projet/graph_opportunities.inc.php b/htdocs/projet/graph_opportunities.inc.php index 6cae34bddfa..558bd7307ee 100644 --- a/htdocs/projet/graph_opportunities.inc.php +++ b/htdocs/projet/graph_opportunities.inc.php @@ -1,7 +1,7 @@ global->PROJECT_USE_OPPORTUNITIES)) { - $sql = "SELECT COUNT(p.rowid) as nb, SUM(p.opp_amount) as opp_amount, p.fk_opp_status as opp_status"; + $sql = "SELECT COUNT(p.rowid) as nb, SUM(p.opp_amount) as opp_amount, SUM(p.opp_amount * p.opp_percent) as ponderated_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"; @@ -9,6 +9,7 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) if ($socid) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; $sql.= " GROUP BY p.fk_opp_status"; $resql = $db->query($sql); + if ($resql) { $num = $db->num_rows($resql); @@ -32,7 +33,7 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) $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); + $ponderated_opp_amount+=$obj->ponderated_opp_amount; } $total+=$row[0]; } @@ -40,6 +41,8 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) } $db->free($resql); + $ponderated_opp_amount = $ponderated_opp_amount / 100; + print ''; print ''."\n"; $var=true; @@ -53,7 +56,7 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) if (empty($labelstatus)) $labelstatus=$listofopplabel[$status]; //$labelstatus .= ' ('.$langs->trans("Coeff").': '.price2num($listofoppstatus[$status]).')'; - $labelstatus .= ' - '.price2num($listofoppstatus[$status]).'%'; + //$labelstatus .= ' - '.price2num($listofoppstatus[$status]).'%'; $dataseries[]=array('label'=>$labelstatus,'data'=>(isset($valsamount[$status])?(float) $valsamount[$status]:0)); if (! $conf->use_javascript_ajax) @@ -75,7 +78,7 @@ if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) //if ($totalinprocess != $total) //print ''; print ''; - print ''; + print ''; print "
'.$langs->trans("Statistics").' - '.$langs->trans("OpportunitiesStatusForOpenedProjects").'
'.$langs->trans("Total").' ('.$langs->trans("CustomersOrdersRunning").')'.$totalinprocess.'
'.$langs->trans("OpportunityTotalAmount").''.price($totalamount, 0, '', 1, -1, -1, $conf->currency).'
'.$langs->trans("OpportunityPonderatedAmount").''.price($ponderated_opp_amount, 0, '', 1, -1, -1, $conf->currency).'
'.$langs->trans("OpportunityPonderatedAmount").''.price(price2num($ponderated_opp_amount,'MT'), 0, '', 1, -1, -1, $conf->currency).'

"; } else diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index b5fb7e31666..7eea03111ee 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004-2015 Laurent Destailleur + * Copyright (C) 2004-2016 Laurent Destailleur * Copyright (C) 2005 Marc Bariley / Ocebo * Copyright (C) 2005-2010 Regis Houssin * Copyright (C) 2013 Cédric Salvador @@ -70,6 +70,7 @@ $search_year=GETPOST("search_year"); $search_all=GETPOST("search_all"); $search_status=GETPOST("search_status",'int'); $search_opp_status=GETPOST("search_opp_status",'alpha'); +$search_opp_percent=GETPOST("search_opp_percent",'alpha'); $search_public=GETPOST("search_public",'int'); $search_user=GETPOST('search_user','int'); $search_sale=GETPOST('search_sale','int'); @@ -127,8 +128,9 @@ $arrayfields=array( 'p.datee'=>array('label'=>$langs->trans("DateEnd"), 'checked'=>1, 'position'=>101), 'p.public'=>array('label'=>$langs->trans("Visibility"), 'checked'=>1, 'position'=>102), 'p.opp_amount'=>array('label'=>$langs->trans("OpportunityAmountShort"), 'checked'=>1, 'enabled'=>$conf->global->PROJECT_USE_OPPORTUNITIES, 'position'=>103), - 'p.fk_opp_status'=>array('label'=>$langs->trans("OpportunityStatusShort"), 'checked'=>1, 'enabled'=>$conf->global->PROJECT_USE_OPPORTUNITIES, 'position'=>104), - 'p.datec'=>array('label'=>$langs->trans("DateCreationShort"), 'checked'=>0, 'position'=>500), + 'p.fk_opp_status'=>array('label'=>$langs->trans("OpportunityStatusShort"), 'checked'=>1, 'enabled'=>$conf->global->PROJECT_USE_OPPORTUNITIES, 'position'=>104), + 'p.opp_percent'=>array('label'=>$langs->trans("OpportunityProbabilityShort"), 'checked'=>1, 'enabled'=>$conf->global->PROJECT_USE_OPPORTUNITIES, 'position'=>105), + 'p.datec'=>array('label'=>$langs->trans("DateCreationShort"), 'checked'=>0, 'position'=>500), 'p.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500), 'p.fk_statut'=>array('label'=>$langs->trans("Status"), 'checked'=>1, 'position'=>1000), ); @@ -208,7 +210,7 @@ if (count($listofprojectcontacttype) == 0) $listofprojectcontacttype[0]='0'; $distinct='DISTINCT'; // We add distinct until we are added a protection to be sure a contact of a project and task is only once. $sql = "SELECT ".$distinct." p.rowid as projectid, p.ref, p.title, p.fk_statut, p.fk_opp_status, p.public, p.fk_user_creat"; -$sql.= ", p.datec as date_creation, p.dateo as date_start, p.datee as date_end, p.opp_amount, p.tms as date_update"; +$sql.= ", p.datec as date_creation, p.dateo as date_start, p.datee as date_end, p.opp_amount, p.opp_percent, p.tms as date_update"; $sql.= ", s.nom as name, s.rowid as socid"; $sql.= ", cls.code as opp_status_code"; // Add fields for extrafields @@ -311,6 +313,7 @@ if ($resql) if ($search_societe != '') $param.='&search_societe='.$search_societe; if ($search_status >= 0) $param.='&search_status='.$search_status; if ((is_numeric($search_opp_status) && $search_opp_status >= 0) || in_array($search_opp_status, array('all','none'))) $param.='&search_opp_status='.urlencode($search_opp_status); + if ((is_numeric($search_opp_percent) && $search_opp_percent >= 0) || in_array($search_opp_percent, array('all','none'))) $param.='&search_opp_percent='.urlencode($search_opp_percent); if ($search_public != '') $param.='&search_public='.$search_public; if ($search_user > 0) $param.='&search_user='.$search_user; if ($search_sale > 0) $param.='&search_sale='.$search_sale; @@ -392,7 +395,8 @@ if ($resql) if (! empty($arrayfields['p.datee']['checked'])) print_liste_field_titre($arrayfields['p.datee']['label'],$_SERVER["PHP_SELF"],"p.datee","",$param,'align="center"',$sortfield,$sortorder); if (! empty($arrayfields['p.public']['checked'])) print_liste_field_titre($arrayfields['p.public']['label'],$_SERVER["PHP_SELF"],"p.public","",$param,"",$sortfield,$sortorder); if (! empty($arrayfields['p.opp_amount']['checked'])) print_liste_field_titre($arrayfields['p.opp_amount']['label'],$_SERVER["PHP_SELF"],'p.opp_amount',"",$param,'align="right"',$sortfield,$sortorder); - if (! empty($arrayfields['p.fk_opp_status']['checked'])) print_liste_field_titre($arrayfields['p.fk_opp_status']['label'],$_SERVER["PHP_SELF"],'p.fk_opp_status',"",$param,'align="center"',$sortfield,$sortorder); + if (! empty($arrayfields['p.fk_opp_status']['checked'])) print_liste_field_titre($arrayfields['p.fk_opp_status']['label'],$_SERVER["PHP_SELF"],'p.fk_opp_status',"",$param,'align="center"',$sortfield,$sortorder); + if (! empty($arrayfields['p.opp_percent']['checked'])) print_liste_field_titre($arrayfields['p.opp_percent']['label'],$_SERVER["PHP_SELF"],'p.opp_percent',"",$param,'align="right"',$sortfield,$sortorder); // Extra fields if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) { @@ -475,6 +479,11 @@ if ($resql) print $formproject->selectOpportunityStatus('search_opp_status',$search_opp_status,1,1,1); print ''; } + if (! empty($arrayfields['p.opp_percent']['checked'])) + { + print ''; + print ''; + } // Extra fields if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) { @@ -559,7 +568,7 @@ if ($resql) } print ''; } - // Sales Rapresentatives + // Sales Representatives if (! empty($arrayfields['commercial']['checked'])) { print ''; @@ -623,7 +632,7 @@ if ($resql) if (! empty($arrayfields['p.opp_amount']['checked'])) { print ''; - if ($obj->opp_status_code) print price($obj->opp_amount, 1, '', 1, - 1, - 1, $conf->currency); + if ($obj->opp_status_code) print price($obj->opp_amount, 1, '', 1, -1, -1, $conf->currency); print ''; } if (! empty($arrayfields['p.fk_opp_status']['checked'])) @@ -632,6 +641,12 @@ if ($resql) if ($obj->opp_status_code) print $langs->trans("OppStatusShort".$obj->opp_status_code); print ''; } + if (! empty($arrayfields['p.opp_percent']['checked'])) + { + print ''; + if ($obj->opp_percent) print price($obj->opp_percent, 1, '', 1, 0).'%'; + print ''; + } // Extra fields if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) {