dolibarr 20.0.2
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
48 public function __construct($db, $param = '')
49 {
50 global $user, $langs;
51
52 // Load translation files required by the page
53 $langs->loadLangs(array('boxes', 'projects'));
54
55 $this->db = $db;
56
57 $this->enabled = (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 1 ? 1 : 0); // Not enabled by default, still need some work
58 //$this->enabled = 1;
59
60 $this->hidden = !$user->hasRight('projet', 'lire');
61 }
62
69 public function loadBox($max = 5)
70 {
71 global $conf;
72
73 // default values
74 $badgeStatus0 = '#cbd3d3'; // draft
75 $badgeStatus1 = '#bc9526'; // validated
76 $badgeStatus1b = '#bc9526'; // validated
77 $badgeStatus2 = '#9c9c26'; // approved
78 $badgeStatus3 = '#bca52b';
79 $badgeStatus4 = '#25a580'; // Color ok
80 $badgeStatus4b = '#25a580'; // Color ok
81 $badgeStatus5 = '#cad2d2';
82 $badgeStatus6 = '#cad2d2';
83 $badgeStatus7 = '#baa32b';
84 $badgeStatus8 = '#993013';
85 $badgeStatus9 = '#e7f0f0';
86 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/theme_vars.inc.php')) {
87 include DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/theme_vars.inc.php';
88 }
89 $listofoppstatus = array();
90 $listofopplabel = array();
91 $listofoppcode = array();
92 $colorseriesstat = array();
93 $sql = "SELECT cls.rowid, cls.code, cls.percent, cls.label";
94 $sql .= " FROM ".MAIN_DB_PREFIX."c_lead_status as cls";
95 $sql .= " WHERE active = 1";
96 $sql .= " AND cls.code <> 'LOST'";
97 $sql .= " AND cls.code <> 'WON'";
98 $sql .= $this->db->order('cls.rowid', 'ASC');
99 $resql = $this->db->query($sql);
100 if ($resql) {
101 $num = $this->db->num_rows($resql);
102 $i = 0;
103
104 while ($i < $num) {
105 $objp = $this->db->fetch_object($resql);
106 $listofoppstatus[$objp->rowid] = $objp->percent;
107 $listofopplabel[$objp->rowid] = $objp->label;
108 $listofoppcode[$objp->rowid] = $objp->code;
109 switch ($objp->code) {
110 case 'PROSP':
111 $colorseriesstat[$objp->rowid] = '-'.$badgeStatus0;
112 break;
113 case 'QUAL':
114 $colorseriesstat[$objp->rowid] = '-'.$badgeStatus1;
115 break;
116 case 'PROPO':
117 $colorseriesstat[$objp->rowid] = $badgeStatus1;
118 break;
119 case 'NEGO':
120 $colorseriesstat[$objp->rowid] = $badgeStatus4;
121 break;
122 default:
123 break;
124 }
125 $i++;
126 }
127 } else {
128 dol_print_error($this->db);
129 }
130
131 global $conf, $user, $langs;
132 $this->max = $max;
133
134 $this->info_box_head = array(
135 'text' => $langs->trans("Statistics").' - '.$langs->trans("BoxTitleFunnelOfProspection"),
136 'nbcol' => '2',
137 'graph' => '1'
138 );
139
140 if ($user->hasRight('projet', 'lire') || getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
141 $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";
142 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p, ".MAIN_DB_PREFIX."c_lead_status as cls";
143 $sql .= " WHERE p.entity IN (".getEntity('project').")";
144 $sql .= " AND p.fk_opp_status = cls.rowid";
145 $sql .= " AND p.fk_statut = 1"; // Opend projects only
146 $sql .= " AND cls.code NOT IN ('LOST', 'WON')";
147 $sql .= " GROUP BY p.fk_opp_status, cls.code";
148 $resql = $this->db->query($sql);
149
150 $form = new Form($this->db);
151 if ($resql) {
152 $num = $this->db->num_rows($resql);
153 $i = 0;
154
155 $totalnb = 0;
156 $totaloppnb = 0;
157 $totalamount = 0;
158 $ponderated_opp_amount = 0;
159 $valsnb = array();
160 $valsamount = array();
161 $dataseries = array();
162
163 while ($i < $num) {
164 $obj = $this->db->fetch_object($resql);
165 if ($obj) {
166 $valsnb[$obj->opp_status] = $obj->nb;
167 $valsamount[$obj->opp_status] = $obj->opp_amount;
168 $totalnb += $obj->nb;
169 if ($obj->opp_status) {
170 $totaloppnb += $obj->nb;
171 }
172 if (!in_array($obj->code, array('WON', 'LOST'))) {
173 $totalamount += $obj->opp_amount;
174 $ponderated_opp_amount += $obj->ponderated_opp_amount;
175 }
176 }
177 $i++;
178 }
179 $this->db->free($resql);
180 $ponderated_opp_amount = $ponderated_opp_amount / 100;
181
182 $stringtoprint = '';
183 $stringtoprint .= '<div class="div-table-responsive-no-min ">';
184 $listofstatus = array_keys($listofoppstatus);
185 $liststatus = array();
186 $data = array('');
187 $customlabels = array();
188 $total = 0;
189 $maxamount = 0;
190 foreach ($listofstatus as $status) {
191 $customlabel = '';
192 $labelStatus = '';
193 if ($status != 7) {
194 $code = dol_getIdFromCode($this->db, $status, 'c_lead_status', 'rowid', 'code');
195 if ($code) {
196 $labelStatus = $langs->transnoentitiesnoconv("OppStatus".$code);
197 }
198 if (empty($labelStatus)) {
199 $labelStatus = $listofopplabel[$status];
200 }
201 $amount = (isset($valsamount[$status]) ? (float) $valsamount[$status] : 0);
202 $customlabel = $amount."€";
203
204 $data[] = $amount;
205 $liststatus[] = $labelStatus;
206 if (!$conf->use_javascript_ajax) {
207 $stringtoprint .= '<tr class="oddeven">';
208 $stringtoprint .= '<td>'.$labelStatus.'</td>';
209 $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>';
210 $stringtoprint .= "</tr>\n";
211 }
212 $customlabels[] = $customlabel;
213 if ($maxamount < $amount) {
214 $maxamount = $amount;
215 }
216 }
217 }
218
219 // Permit to have a bar if value inferior to a certain value
220 $valuetoaddtomindata = $maxamount / 100;
221 foreach ($data as $key => $value) {
222 if ($value != "") {
223 $data[$key] = $valuetoaddtomindata + $value;
224 }
225 }
226
227 $dataseries[] = $data;
228 if ($conf->use_javascript_ajax) {
229 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php';
230 $dolgraph = new DolGraph();
231 $dolgraph->SetMinValue(0);
232 $dolgraph->SetData($dataseries);
233 $dolgraph->SetLegend($liststatus);
234 $dolgraph->setHideXValues(true);
235 $dolgraph->SetDataColor(array_values($colorseriesstat));
236 //$dolgraph->setBorderColor(array_values($bordercolorseries));
237 $dolgraph->setShowLegend(2);
238 if (!empty($conf->dol_optimize_smallscreen)) {
239 $dolgraph->SetWidth(320);
240 }
241 $dolgraph->setShowPercent(1);
242 $dolgraph->setMirrorGraphValues(true);
243 $dolgraph->setBorderWidth(2);
244 $dolgraph->setBorderSkip('false');
245 $dolgraph->SetType(array('horizontalbars'));
246 $dolgraph->SetHeight('200');
247 $dolgraph->SetWidth('600');
248 $dolgraph->setTooltipsTitles($liststatus);
249 $dolgraph->setTooltipsLabels($customlabels);
250 $dolgraph->mode = 'depth';
251 $dolgraph->draw('idgraphleadfunnel');
252 $stringtoprint .= $dolgraph->show($totaloppnb ? 0 : 1);
253 }
254 $stringtoprint .= '</div>';
255
256 $line = 0;
257 /*$this->info_box_contents[$line][] = array(
258 'tr' => 'class="nohover left "',
259 'text' => ''
260 );
261 $this->info_box_contents[$line][] = array(
262 'tr' => 'class="nohover left "',
263 'text' => ''
264 );
265 $line++;*/
266 $this->info_box_contents[$line][] = array(
267 'tr' => '',
268 'td' => 'class="center nopaddingleftimp nopaddingrightimp" colspan="2"',
269 'text' => $stringtoprint
270 );
271 $line++;
272 $this->info_box_contents[$line][] = array(
273 'tr' => 'class="oddeven"',
274 'td' => 'class="left "',
275 'maxlength' => 500,
276 'text' => $langs->trans("OpportunityTotalAmount").' ('.$langs->trans("WonLostExcluded").')'
277 );
278 $this->info_box_contents[$line][] = array(
279 'tr' => 'class="oddeven"',
280 'td' => 'class="nowraponall right amount"',
281 'maxlength' => 500,
282 'text' => price($totalamount, 0, '', 1, -1, -1, $conf->currency)
283 );
284 $line++;
285 $this->info_box_contents[$line][] = array(
286 'tr' => 'class="oddeven"',
287 'td' => 'class="left "',
288 'maxlength' => 500,
289 'text' => $form->textwithpicto($langs->trans("OpportunityPonderatedAmount").' ('.$langs->trans("WonLostExcluded").')', $langs->trans("OpportunityPonderatedAmountDesc"), 1)
290
291 );
292 $this->info_box_contents[$line][] = array(
293 'td' => 'class="nowraponall right amount"',
294 'maxlength' => 500,
295 'text' => price(price2num($ponderated_opp_amount, 'MT'), 0, '', 1, -1, -1, $conf->currency)
296 );
297 } else {
298 $this->info_box_contents[0][0] = array(
299 'td' => 'class="center"',
300 'text' => '<span class="opacitymedium">'.$langs->trans("NoRecordedCustomers").'</span>'
301 );
302 }
303 } else {
304 $this->info_box_contents[0][0] = array(
305 'td' => '',
306 'text' => $langs->trans("ReadPermissionNotAllowed")
307 );
308 }
309 }
310
319 public function showBox($head = null, $contents = null, $nooutput = 0)
320 {
321 return parent::showBox($this->info_box_head, $this->info_box_contents, $nooutput);
322 }
323}
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 '.
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.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.