dolibarr 19.0.4
box_funnel_of_prospection.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2012-2014 Charles-François BENKE <charles.fr@benke.fr>
3 * Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
4 * Copyright (C) 2015 Frederic France <frederic.france@free.fr>
5 * Copyright (C) 2016 Juan José Menent <jmenent@2byte.es>
6 * Copyright (C) 2020 Pierre Ardoin <mapiolca@me.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
27include_once DOL_DOCUMENT_ROOT."/core/boxes/modules_boxes.php";
28
29
34{
35 public $boxcode = "FunnelOfProspection";
36 public $boximg = "object_projectpub";
37 public $boxlabel = "BoxTitleFunnelOfProspection";
38 public $depends = array("projet");
39
40 public $version = 'development';
41
45 public $db;
46
47 public $param;
48
49 public $info_box_head = array();
50 public $info_box_contents = array();
51
58 public function __construct($db, $param = '')
59 {
60 global $user, $langs;
61
62 // Load translation files required by the page
63 $langs->loadLangs(array('boxes', 'projects'));
64
65 $this->db = $db;
66
67 $this->enabled = (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 1 ? 1 : 0); // Not enabled by default, still need some work
68 //$this->enabled = 1;
69
70 $this->hidden = empty($user->rights->projet->lire);
71 }
72
79 public function loadBox($max = 5)
80 {
81 global $conf;
82
83 // default values
84 $badgeStatus0 = '#cbd3d3'; // draft
85 $badgeStatus1 = '#bc9526'; // validated
86 $badgeStatus1b = '#bc9526'; // validated
87 $badgeStatus2 = '#9c9c26'; // approved
88 $badgeStatus3 = '#bca52b';
89 $badgeStatus4 = '#25a580'; // Color ok
90 $badgeStatus4b = '#25a580'; // Color ok
91 $badgeStatus5 = '#cad2d2';
92 $badgeStatus6 = '#cad2d2';
93 $badgeStatus7 = '#baa32b';
94 $badgeStatus8 = '#993013';
95 $badgeStatus9 = '#e7f0f0';
96 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/theme_vars.inc.php')) {
97 include DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/theme_vars.inc.php';
98 }
99 $listofoppstatus = array();
100 $listofopplabel = array();
101 $listofoppcode = array();
102 $colorseriesstat = array();
103 $sql = "SELECT cls.rowid, cls.code, cls.percent, cls.label";
104 $sql .= " FROM ".MAIN_DB_PREFIX."c_lead_status as cls";
105 $sql .= " WHERE active=1";
106 $sql .= " AND cls.code <> 'LOST'";
107 $sql .= " AND cls.code <> 'WON'";
108 $sql .= $this->db->order('cls.rowid', 'ASC');
109 $resql = $this->db->query($sql);
110 if ($resql) {
111 $num = $this->db->num_rows($resql);
112 $i = 0;
113
114 while ($i < $num) {
115 $objp = $this->db->fetch_object($resql);
116 $listofoppstatus[$objp->rowid] = $objp->percent;
117 $listofopplabel[$objp->rowid] = $objp->label;
118 $listofoppcode[$objp->rowid] = $objp->code;
119 switch ($objp->code) {
120 case 'PROSP':
121 $colorseriesstat[$objp->rowid] = '-'.$badgeStatus0;
122 break;
123 case 'QUAL':
124 $colorseriesstat[$objp->rowid] = '-'.$badgeStatus1;
125 break;
126 case 'PROPO':
127 $colorseriesstat[$objp->rowid] = $badgeStatus1;
128 break;
129 case 'NEGO':
130 $colorseriesstat[$objp->rowid] = $badgeStatus4;
131 break;
132 default:
133 break;
134 }
135 $i++;
136 }
137 } else {
138 dol_print_error($this->db);
139 }
140
141 global $conf, $user, $langs;
142 $this->max = $max;
143
144 $this->info_box_head = array(
145 'text' => $langs->trans("Statistics").' - '.$langs->trans("BoxTitleFunnelOfProspection"),
146 'nbcol' => '2',
147 'graph' => '1'
148 );
149
150 if ($user->hasRight('projet', 'lire') || getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
151 $sql = "SELECT p.fk_opp_status as opp_status, cls.code, COUNT(p.rowid) as nb, SUM(p.opp_amount) as opp_amount, SUM(p.opp_amount * p.opp_percent) as ponderated_opp_amount";
152 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p, ".MAIN_DB_PREFIX."c_lead_status as cls";
153 $sql .= " WHERE p.entity IN (".getEntity('project').")";
154 $sql .= " AND p.fk_opp_status = cls.rowid";
155 $sql .= " AND p.fk_statut = 1"; // Opend projects only
156 $sql .= " AND cls.code NOT IN ('LOST', 'WON')";
157 $sql .= " GROUP BY p.fk_opp_status, cls.code";
158 $resql = $this->db->query($sql);
159
160 $form = new Form($this->db);
161 if ($resql) {
162 $num = $this->db->num_rows($resql);
163 $i = 0;
164
165 $totalnb = 0;
166 $totaloppnb = 0;
167 $totalamount = 0;
168 $ponderated_opp_amount = 0;
169 $valsnb = array();
170 $valsamount = array();
171 $dataseries = array();
172
173 while ($i < $num) {
174 $obj = $this->db->fetch_object($resql);
175 if ($obj) {
176 $valsnb[$obj->opp_status] = $obj->nb;
177 $valsamount[$obj->opp_status] = $obj->opp_amount;
178 $totalnb += $obj->nb;
179 if ($obj->opp_status) {
180 $totaloppnb += $obj->nb;
181 }
182 if (!in_array($obj->code, array('WON', 'LOST'))) {
183 $totalamount += $obj->opp_amount;
184 $ponderated_opp_amount += $obj->ponderated_opp_amount;
185 }
186 }
187 $i++;
188 }
189 $this->db->free($resql);
190 $ponderated_opp_amount = $ponderated_opp_amount / 100;
191
192 $stringtoprint = '';
193 $stringtoprint .= '<div class="div-table-responsive-no-min ">';
194 $listofstatus = array_keys($listofoppstatus);
195 $liststatus = array();
196 $data = array('');
197 $customlabels = array();
198 $total = 0;
199 foreach ($listofstatus as $status) {
200 $customlabel = '';
201 $labelStatus = '';
202 if ($status != 7) {
203 $code = dol_getIdFromCode($this->db, $status, 'c_lead_status', 'rowid', 'code');
204 if ($code) {
205 $labelStatus = $langs->transnoentitiesnoconv("OppStatus".$code);
206 }
207 if (empty($labelStatus)) {
208 $labelStatus = $listofopplabel[$status];
209 }
210 $amount = (isset($valsamount[$status]) ? (float) $valsamount[$status] : 0);
211 $data[] = $amount;
212 $customlabel = $amount;
213 $liststatus[] = $labelStatus;
214 if (!$conf->use_javascript_ajax) {
215 $stringtoprint .= '<tr class="oddeven">';
216 $stringtoprint .= '<td>'.$labelStatus.'</td>';
217 $stringtoprint .= '<td class="nowraponall right amount"><a href="list.php?statut='.$status.'">'.price((isset($valsamount[$status]) ? (float) $valsamount[$status] : 0), 0, '', 1, -1, -1, $conf->currency).'</a></td>';
218 $stringtoprint .= "</tr>\n";
219 }
220 }
221 $customlabels[] = $customlabel;
222 }
223 $dataseries[] = $data;
224 if ($conf->use_javascript_ajax) {
225 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php';
226 $dolgraph = new DolGraph();
227 $dolgraph->SetMinValue(0);
228 $dolgraph->SetData($dataseries);
229 $dolgraph->SetLegend($liststatus);
230 $dolgraph->setHideXValues(true);
231 $dolgraph->SetDataColor(array_values($colorseriesstat));
232 //$dolgraph->setBorderColor(array_values($bordercolorseries));
233 $dolgraph->setShowLegend(2);
234 if (!empty($conf->dol_optimize_smallscreen)) {
235 $dolgraph->SetWidth(320);
236 }
237 $dolgraph->setShowPercent(1);
238 $dolgraph->setMirrorGraphValues(true);
239 $dolgraph->setBorderWidth(2);
240 $dolgraph->setBorderSkip('false');
241 $dolgraph->SetType(array('horizontalbars'));
242 $dolgraph->SetHeight('200');
243 $dolgraph->SetWidth('600');
244 $dolgraph->setTooltipsTitles($liststatus);
245 $dolgraph->setTooltipsLabels($customlabels);
246 $dolgraph->mode = 'depth';
247 $dolgraph->draw('idgraphleadfunnel');
248 $stringtoprint .= $dolgraph->show($totaloppnb ? 0 : 1);
249 }
250 $stringtoprint .= '</div>';
251
252 $line = 0;
253 /*$this->info_box_contents[$line][] = array(
254 'tr' => 'class="nohover left "',
255 'text' => ''
256 );
257 $this->info_box_contents[$line][] = array(
258 'tr' => 'class="nohover left "',
259 'text' => ''
260 );
261 $line++;*/
262 $this->info_box_contents[$line][] = array(
263 'tr' => '',
264 'td' => 'class="center nopaddingleftimp nopaddingrightimp" colspan="2"',
265 'text' => $stringtoprint
266 );
267 $line++;
268 $this->info_box_contents[$line][] = array(
269 'tr' => 'class="oddeven"',
270 'td' => 'class="left "',
271 'maxlength' => 500,
272 'text' => $langs->trans("OpportunityTotalAmount").' ('.$langs->trans("WonLostExcluded").')'
273 );
274 $this->info_box_contents[$line][] = array(
275 'tr' => 'class="oddeven"',
276 'td' => 'class="nowraponall right amount"',
277 'maxlength' => 500,
278 'text' => price($totalamount, 0, '', 1, -1, -1, $conf->currency)
279 );
280 $line++;
281 $this->info_box_contents[$line][] = array(
282 'tr' => 'class="oddeven"',
283 'td' => 'class="left "',
284 'maxlength' => 500,
285 'text' => $form->textwithpicto($langs->trans("OpportunityPonderatedAmount").' ('.$langs->trans("WonLostExcluded").')', $langs->trans("OpportunityPonderatedAmountDesc"), 1)
286
287 );
288 $this->info_box_contents[$line][] = array(
289 'td' => 'class="nowraponall right amount"',
290 'maxlength' => 500,
291 'text' => price(price2num($ponderated_opp_amount, 'MT'), 0, '', 1, -1, -1, $conf->currency)
292 );
293 } else {
294 $this->info_box_contents[0][0] = array(
295 'td' => 'class="center"',
296 'text' => '<span class="opacitymedium">'.$langs->trans("NoRecordedCustomers").'</span>'
297 );
298 }
299 } else {
300 $this->info_box_contents[0][0] = array(
301 'td' => '',
302 'text' => $langs->trans("ReadPermissionNotAllowed")
303 );
304 }
305 }
306
315 public function showBox($head = null, $contents = null, $nooutput = 0)
316 {
317 return parent::showBox($this->info_box_head, $this->info_box_contents, $nooutput);
318 }
319}
Class to build graphs.
Class to manage generation of HTML components Only common components must be here.
Class ModeleBoxes.
Class to manage the box to show funnel of prospections.
showBox($head=null, $contents=null, $nooutput=0)
Method to show box.
__construct($db, $param='')
Constructor.
loadBox($max=5)
Load data for box to show them later.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.