dolibarr 23.0.3
index.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2012 Marcos García <marcosgdf@gmail.com>
6 * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
7 * Copyright (C) 2020 Maxime DEMAREST <maxime@indelog.fr>
8 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 */
24
31// Load Dolibarr environment
32require '../../../main.inc.php';
33require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propalestats.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php';
35require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
36require_once DOL_DOCUMENT_ROOT.'/core/class/html.formpropal.class.php';
37require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
38require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
39
50
51$mode = GETPOSTISSET("mode") ? GETPOST("mode", 'aZ09') : 'customer';
52
53$hookmanager->initHooks(array('propalstats', 'globalcard'));
54
55$object_status = GETPOST('object_status', 'intcomma');
56$typent_id = GETPOSTINT('typent_id');
57$categ_id = GETPOSTINT('categ_id');
58$select_categ_propal_id=GETPOST('select_categ_propal_id', 'array');
59
60$userid = GETPOSTINT('userid');
61$socid = GETPOSTINT('socid');
62// Security check
63if ($user->socid > 0) {
64 $action = '';
65 $socid = $user->socid;
66}
67
68$parameters = array();
69$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
70if ($reshook < 0) {
71 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
72}
73
74$nowyear = dol_print_date(dol_now('gmt'), "%Y", 'gmt');
75$year = GETPOST('year') > 0 ? GETPOSTINT('year') : $nowyear;
76$startyear = $year - (!getDolGlobalString('MAIN_STATS_GRAPHS_SHOW_N_YEARS') ? 2 : max(1, min(10, getDolGlobalString('MAIN_STATS_GRAPHS_SHOW_N_YEARS'))));
77$endyear = $year;
78
79// Load translation files required by the page
80$langs->loadLangs(array('orders', 'companies', 'other', 'suppliers', 'supplier_proposal'));
81
82if ($mode == 'customer' && !$user->hasRight('propal', 'lire')) {
84}
85if ($mode == 'supplier' && !$user->hasRight('supplier_proposal', 'lire')) {
87}
88
89
90/*
91 * View
92 */
93
94$form = new Form($db);
95$formpropal = new FormPropal($db);
96$formcompany = new FormCompany($db);
97$formother = new FormOther($db);
98
99$langs->loadLangs(array('propal', 'other', 'companies'));
100
101$picto = 'propal';
102$title = $langs->trans("ProposalsStatistics");
103$dir = $conf->propal->dir_temp;
104$cat_type = Categorie::TYPE_CUSTOMER;
105$cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer"));
106
107if ($mode == 'supplier') {
108 $picto = 'supplier_proposal';
109 $title = $langs->trans("ProposalsStatisticsSuppliers");
110 $dir = $conf->supplier_proposal->dir_temp;
111 $cat_type = Categorie::TYPE_SUPPLIER;
112 $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Supplier"));
113}
114
115llxHeader('', $title);
116
117print load_fiche_titre($title, '', $picto);
118
119
120dol_mkdir($dir);
121
122
123$stats = new PropaleStats($db, $socid, ($userid > 0 ? $userid : 0), $mode, ($typent_id > 0 ? $typent_id : 0), ($categ_id > 0 ? $categ_id : 0));
124if ($object_status != '' && $object_status >= 0) {
125 $stats->where .= ' AND p.fk_statut IN ('.$db->sanitize($object_status).')';
126}
127
128// Build graphic number of object
129$data = $stats->getNbByMonthWithPrevYear($endyear, $startyear);
130// $data = array(array('Lib',val1,val2,val3),...)
131if ($mode == 'customer') {
132 if (is_array($select_categ_propal_id) && !empty($select_categ_propal_id)) {
133 $stats->from .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_propal as cat ON (p.rowid = cat.fk_propal)';
134 $stats->where .= ' AND cat.fk_categorie IN ('.$db->sanitize(implode(',', $select_categ_propal_id)).')';
135 }
136}
137if ($mode == 'supplier') {
138 if (is_array($select_categ_propal_id) && !empty($select_categ_propal_id)) {
139 $stats->from .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_supplier_proposal as cat ON (p.rowid = cat.fk_supplier_proposal)';
140 $stats->where .= ' AND cat.fk_categorie IN ('.$db->sanitize(implode(',', $select_categ_propal_id)).')';
141 }
142}
143
144if (!$user->hasRight('societe', 'client', 'voir')) {
145 $filenamenb = $dir.'/proposalsnbinyear-'.$user->id.'-'.$year.'.png';
146 $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=propalstats&file=proposalsnbinyear-'.$user->id.'-'.$year.'.png';
147} else {
148 $filenamenb = $dir.'/proposalsnbinyear-'.$year.'.png';
149 $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=propalstats&file=proposalsnbinyear-'.$year.'.png';
150}
151
152$px1 = new DolGraph();
153$mesg = $px1->isGraphKo();
154if (!$mesg) {
155 $px1->SetData($data);
156 $i = $startyear;
157 $legend = array();
158 while ($i <= $endyear) {
159 $legend[] = $i;
160 $i++;
161 }
162 $px1->SetLegend($legend);
163 $px1->SetMaxValue($px1->GetCeilMaxValue());
164 $px1->SetMinValue(min(0, $px1->GetFloorMinValue()));
165 $px1->SetWidth($WIDTH);
166 $px1->SetHeight($HEIGHT);
167 $px1->SetYLabel($langs->trans("NbOfProposals"));
168 $px1->SetShading(3);
169 $px1->SetHorizTickIncrement(1);
170 $px1->mode = 'depth';
171 $px1->SetTitle($langs->trans("NumberOfProposalsByMonth"));
172
173 $px1->draw($filenamenb, $fileurlnb);
174}
175
176// Build graphic amount of object
177$data = $stats->getAmountByMonthWithPrevYear($endyear, $startyear, 0);
178// $data = array(array('Lib',val1,val2,val3),...)
179
180if (!$user->hasRight('societe', 'client', 'voir')) {
181 $filenameamount = $dir.'/proposalsamountinyear-'.$user->id.'-'.$year.'.png';
182 $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=propalstats&file=proposalsamountinyear-'.$user->id.'-'.$year.'.png';
183} else {
184 $filenameamount = $dir.'/proposalsamountinyear-'.$year.'.png';
185 $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=propalstats&file=proposalsamountinyear-'.$year.'.png';
186}
187
188$px2 = new DolGraph();
189$mesg = $px2->isGraphKo();
190if (!$mesg) {
191 $px2->SetData($data);
192 $i = $startyear;
193 $legend = array();
194 while ($i <= $endyear) {
195 $legend[] = $i;
196 $i++;
197 }
198 $px2->SetLegend($legend);
199 $px2->SetMaxValue($px2->GetCeilMaxValue());
200 $px2->SetMinValue(min(0, $px2->GetFloorMinValue()));
201 $px2->SetWidth($WIDTH);
202 $px2->SetHeight($HEIGHT);
203 $px2->SetYLabel($langs->trans("AmountOfProposals"));
204 $px2->SetShading(3);
205 $px2->SetHorizTickIncrement(1);
206 $px2->mode = 'depth';
207 $px2->SetTitle($langs->trans("AmountOfProposalsByMonthHT"));
208
209 $px2->draw($filenameamount, $fileurlamount);
210}
211
212$data = $stats->getAverageByMonthWithPrevYear($endyear, $startyear);
213
214$fileurl_avg = '';
215if (!$user->hasRight('societe', 'client', 'voir')) {
216 $filename_avg = $dir.'/ordersaverage-'.$user->id.'-'.$year.'.png';
217 if ($mode == 'customer') {
218 $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstats&file=ordersaverage-'.$user->id.'-'.$year.'.png';
219 }
220 if ($mode == 'supplier') {
221 $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstatssupplier&file=ordersaverage-'.$user->id.'-'.$year.'.png';
222 }
223} else {
224 $filename_avg = $dir.'/ordersaverage-'.$year.'.png';
225 if ($mode == 'customer') {
226 $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstats&file=ordersaverage-'.$year.'.png';
227 }
228 if ($mode == 'supplier') {
229 $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstatssupplier&file=ordersaverage-'.$year.'.png';
230 }
231}
232
233$px3 = new DolGraph();
234$mesg = $px3->isGraphKo();
235if (!$mesg) {
236 $px3->SetData($data);
237 $i = $startyear;
238 $legend = array();
239 while ($i <= $endyear) {
240 $legend[] = $i;
241 $i++;
242 }
243 $px3->SetLegend($legend);
244 $px3->SetYLabel($langs->trans("AmountAverage"));
245 $px3->SetMaxValue($px3->GetCeilMaxValue());
246 $px3->SetMinValue((int) $px3->GetFloorMinValue());
247 $px3->SetWidth($WIDTH);
248 $px3->SetHeight($HEIGHT);
249 $px3->SetShading(3);
250 $px3->SetHorizTickIncrement(1);
251 $px3->mode = 'depth';
252 $px3->SetTitle($langs->trans("AmountAverage"));
253
254 $px3->draw($filename_avg, $fileurl_avg);
255}
256
257
258// Show array
259$data = $stats->getAllByYear();
260$arrayyears = array();
261foreach ($data as $val) {
262 if (!empty($val['year'])) {
263 $arrayyears[$val['year']] = $val['year'];
264 }
265}
266if (!count($arrayyears)) {
267 $arrayyears[$nowyear] = $nowyear;
268}
269
270
271$h = 0;
272$head = array();
273$head[$h][0] = DOL_URL_ROOT.'/comm/propal/stats/index.php';
274$head[$h][1] = $langs->trans("ByMonthYear");
275$head[$h][2] = 'byyear';
276$h++;
277
278complete_head_from_modules($conf, $langs, null, $head, $h, 'propal_stats');
279
280print dol_get_fiche_head($head, 'byyear', '', -1);
281
282
283print '<div class="fichecenter"><div class="fichethirdleft">';
284
285
286// Show filter box
287print '<form name="stats" method="POST" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
288print '<input type="hidden" name="token" value="'.newToken().'">';
289print '<input type="hidden" name="mode" value="'.$mode.'">';
290
291print '<table class="noborder centpercent">';
292print '<tr class="liste_titre"><td class="liste_titre" colspan="2">'.$langs->trans("Filter").'</td></tr>';
293// Company
294print '<tr><td class="left">'.$langs->trans("ThirdParty").'</td><td class="left">';
295print img_picto('', 'company', 'class="pictofixedwidth"');
296$filter = '(s.client:IN:1,2,3)';
297print $form->select_company($socid, 'socid', $filter, 1, 0, 0, array(), 0, 'widthcentpercentminusx maxwidth300', '');
298print '</td></tr>';
299// ThirdParty Type
300print '<tr><td>'.$langs->trans("ThirdPartyType").'</td><td>';
301$sortparam_typent = (!getDolGlobalString('SOCIETE_SORT_ON_TYPEENT') ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT); // NONE means we keep sort of original array, so we sort on position. ASC, means next function will sort on label.
302print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, 1, 0, 0, '', 0, 0, 0, $sortparam_typent, '', 1);
303if ($user->admin) {
304 print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
305}
306print '</td></tr>';
307// Category
308print '<tr><td>'.$cat_label.'</td><td>';
309print img_picto('', 'category', 'class="pictofixedwidth"');
310print $formother->select_categories($cat_type, $categ_id, 'categ_id', 0, 1, 'widthcentpercentminusx maxwidth300');
311print '</td></tr>';
312
313if (isModEnabled('category')) {
314 $cat_type = '';
315 $cat_label = '';
316 if ($mode == 'customer') {
317 $cat_type = Categorie::TYPE_PROPOSAL;
318 $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Proposals"));
319 }
320 if ($mode == 'supplier') {
321 $cat_type = Categorie::TYPE_SUPPLIER_PROPOSAL;
322 $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("SupplierProposals"));
323 }
324 print '<tr><td>'.$cat_label.'</td><td>';
325 $cate_arbo = $form->select_all_categories($cat_type, '', 'parent', 0, 0, 1);
326 print img_picto('', 'category', 'class="pictofixedwidth"');
327 print $form->multiselectarray('select_categ_propal_id', $cate_arbo, GETPOST('select_categ_propal_id', 'array'), 0, 0, 'widthcentpercentminusx maxwidth300');
328 //print $formother->select_categories($cat_type, $categ_id, 'categ_id', true);
329 print '</td></tr>';
330}
331// User
332print '<tr><td>'.$langs->trans("CreatedBy").'</td><td>';
333print img_picto('', 'user', 'class="pictofixedwidth"');
334print $form->select_dolusers($userid, 'userid', 1, null, 0, '', '', '0', 0, 0, '', 0, '', 'widthcentpercentminusx maxwidth300');
335print '</td></tr>';
336// Status
337print '<tr><td>'.$langs->trans("Status").'</td><td>';
338$formpropal->selectProposalStatus(($object_status != '' ? $object_status : -1), 0, 0, 1, $mode, 'object_status');
339print '</td></tr>';
340// Year
341print '<tr><td>'.$langs->trans("Year").'</td><td>';
342if (!in_array($year, $arrayyears)) {
343 $arrayyears[$year] = $year;
344}
345if (!in_array($nowyear, $arrayyears)) {
346 $arrayyears[$nowyear] = $nowyear;
347}
348arsort($arrayyears);
349print img_picto('', 'calendar', 'class="pictofixedwidth"');
350print $form->selectarray('year', $arrayyears, $year, 0, 0, 0, '', 0, 0, 0, '', 'width75');
351print '</td></tr>';
352print '<tr><td align="center" colspan="2"><input type="submit" name="submit" class="button small" value="'.$langs->trans("Refresh").'"></td></tr>';
353print '</table>';
354print '</form>';
355print '<br><br>';
356
357print '<div class="div-table-responsive-no-min">';
358print '<table class="noborder centpercent">';
359print '<tr class="liste_titre" height="24">';
360print '<td class="center">'.$langs->trans("Year").'</td>';
361print '<td class="right">'.$langs->trans("NbOfProposals").'</td>';
362print '<td class="right">%</td>';
363print '<td class="right">'.$langs->trans("AmountTotal").'</td>';
364print '<td class="right">%</td>';
365print '<td class="right">'.$langs->trans("AmountAverage").'</td>';
366print '<td class="right">%</td>';
367print '</tr>';
368
369$oldyear = 0;
370foreach ($data as $val) {
371 $year = $val['year'];
372 while (!empty($year) && $oldyear > (int) $year + 1) { // If we have empty year
373 $oldyear--;
374
375 print '<tr class="oddeven" height="24">';
376 print '<td align="center"><a href="'.$_SERVER["PHP_SELF"].'?year='.$oldyear.'&amp;mode='.$mode.($socid > 0 ? '&socid='.$socid : '').($userid > 0 ? '&userid='.$userid : '').'">'.$oldyear.'</a></td>';
377 print '<td class="right">0</td>';
378 print '<td class="right"></td>';
379 print '<td class="right">0</td>';
380 print '<td class="right"></td>';
381 print '<td class="right">0</td>';
382 print '<td class="right"></td>';
383 print '</tr>';
384 }
385 print '<tr class="oddeven" height="24">';
386 print '<td align="center"><a href="'.$_SERVER["PHP_SELF"].'?year='.$year.($socid > 0 ? '&socid='.$socid : '').($userid > 0 ? '&userid='.$userid : '').'">'.$year.'</a></td>';
387 print '<td class="right">'.$val['nb'].'</td>';
388 print '<td class="right opacitylow" style="'.((!isset($val['nb_diff']) || $val['nb_diff'] >= 0) ? 'color: green;' : 'color: red;').'">'.(isset($val['nb_diff']) ? round($val['nb_diff']) : "0").'%</td>';
389 print '<td class="right">'.price(price2num($val['total'], 'MT'), 1).'</td>';
390 print '<td class="right opacitylow" style="'.((!isset($val['total_diff']) || $val['total_diff'] >= 0) ? 'color: green;' : 'color: red;').'">'.(isset($val['total_diff']) ? round($val['total_diff']) : "0").'%</td>';
391 print '<td class="right">'.price(price2num($val['avg'], 'MT'), 1).'</td>';
392 print '<td class="right opacitylow" style="'.((!isset($val['avg_diff']) || $val['avg_diff'] >= 0) ? 'color: green;' : 'color: red;').'">'.(isset($val['avg_diff']) ? round($val['avg_diff']) : "0").'%</td>';
393 print '</tr>';
394 $oldyear = $year;
395}
396
397print '</table>';
398print '</div>';
399
400print '</div><div class="fichetwothirdright">';
401
402
403// Show graphs
404print '<table class="border centpercent"><tr class="pair nohover"><td align="center">';
405if ($mesg) {
406 print $mesg;
407} else {
408 print $px1->show();
409 print "<br>\n";
410 print $px2->show();
411 print "<br>\n";
412 print $px3->show();
413}
414print '</td></tr></table>';
415
416
417print '</div></div>';
418print '<div class="clearboth"></div>';
419
420
421print dol_get_fiche_end();
422
423// End of page
424llxFooter();
425$db->close();
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Class to build graphs.
static getDefaultGraphSizeForStats($direction, $defaultsize='')
getDefaultGraphSizeForStats
Class to build HTML component for third parties management Only common components are here.
Class to manage generation of HTML components Only common components must be here.
Class permettant la generation de composants html autre Only common components are here.
Class to manage generation of HTML components for proposal management.
Class to manage proposals statistics.
dol_now($mode='gmt')
Return date for now.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.