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