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