dolibarr 24.0.0-beta
index.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2013 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 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
10 * Copyright (C) 2025 Charlene Benke <charlene@patas-monkey.com>
11 * Copyright (C) 2026 Alexandre Spangaro <alexandre@inovea-conseil.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 */
26
33// Load Dolibarr environment
34require '../../main.inc.php';
42require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
43require_once DOL_DOCUMENT_ROOT.'/contrat/class/contratstats.class.php';
44require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
45require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
46require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
47require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php';
48
51
52$mode = GETPOSTISSET("mode") ? GETPOST("mode", 'aZ09') : 'customer';
53
54$hookmanager->initHooks(array('contratstats', 'globalcard'));
55
56$usercanreadcustumerstatistic = $user->hasRight('commande', 'lire');
57$usercanreadsupplierstatistic = $user->hasRight('fournisseur', 'commande', 'lire');
58if (getDolGlobalInt('MAIN_NEED_EXPORT_PERMISSION_TO_READ_STATISTICS')) {
59 $usercanreadcustumerstatistic = $user->hasRight('commande', 'commande', 'export');
60 $usercanreadsupplierstatistic = $user->hasRight('fournisseur', 'commande', 'export');
61}
62if ($mode == 'customer' && !$usercanreadcustumerstatistic) {
64}
65if ($mode == 'supplier' && !$usercanreadsupplierstatistic) {
67}
68
69if ($mode == 'supplier') {
70 $object_status = GETPOST('object_status', 'array:int');
71 $object_status = implode(',', $object_status);
72} else {
73 $object_status = GETPOST('object_status', 'intcomma');
74}
75
76
77$typent_id = GETPOSTINT('typent_id');
78$categ_id = GETPOSTINT('categ_id');
79
80$userid = GETPOSTINT('userid');
81$socid = GETPOSTINT('socid');
82// Security check
83if ($user->socid > 0) {
84 $action = '';
85 $socid = $user->socid;
86}
87
88$parameters = array();
89$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
90if ($reshook < 0) {
91 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
92}
93
94$nowyear = (int) dol_print_date(dol_now('gmt'), "%Y", 'gmt');
95$year = GETPOSTINT('year') > 0 ? GETPOSTINT('year') : $nowyear;
96$startyear = $year - (!getDolGlobalInt('MAIN_STATS_GRAPHS_SHOW_N_YEARS') ? 2 : max(1, min(10, getDolGlobalInt('MAIN_STATS_GRAPHS_SHOW_N_YEARS'))));
97$endyear = $year;
98
99// Load translation files required by the page
100$langs->loadLangs(array('contracts', 'companies', 'other', 'suppliers'));
101
102
103/*
104 * View
105 */
106
107$form = new Form($db);
108$formcompany = new FormCompany($db);
109$formother = new FormOther($db);
110
111$picto = 'contract';
112$title = $langs->trans("ContractsStatistics");
113$dir = $conf->contract->dir_temp;
114
115
116
117llxHeader('', $title, '', '', 0, 0, '', '', '', 'mod-contract page-stats');
118
119$page = 0;
120$param = '';
121$sortfield = '';
122$sortorder = '';
123$massactionbutton = '';
124$num = 0;
125$nbtotalofrecords = $langs->trans("Statistics");
126$limit = 0;
127
128$urlnew = DOL_URL_ROOT.'/contrat/card.php?action=create';
129if (!empty($socid)) {
130 $urlnew .= '&socid='.$socid;
131}
132
133$newcardbutton = '';
134$newcardbutton .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/contrat/list.php?mode=common', '', 1, array('morecss' => 'reposition'));
135$newcardbutton .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', DOL_URL_ROOT.'/contrat/list.php?mode=kanban', '', 1, array('morecss' => 'reposition'));
136$newcardbutton .= dolGetButtonTitle($langs->trans('Statistics'), '', 'fa fa-chart-bar imgforviewmode', DOL_URL_ROOT.'/contrat/stats/index.php', '', 2, array('morecss' => 'reposition'));
137$newcardbutton .= dolGetButtonTitleSeparator();
138$newcardbutton .= dolGetButtonTitle($langs->trans('NewContractSubscription'), '', 'fa fa-plus-circle', $urlnew, '', $user->hasRight('contrat', 'creer'));
139
140print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, $picto, 0, $newcardbutton, '', $limit, 0, 0, 1);
141
142dol_mkdir($dir);
143
144$stats = new ContratStats($db, $socid, $mode, ($userid > 0 ? $userid : 0), ($typent_id > 0 ? $typent_id : 0), ($categ_id > 0 ? $categ_id : 0));
145
146if ($object_status != '' && $object_status >= -1) {
147 $stats->where .= ' AND c.statut IN ('.$db->sanitize($object_status).')';
148}
149
150
151
152// Build graphic number of object
153$data = $stats->getNbByMonthWithPrevYear($endyear, $startyear);
154
155//var_dump($data);
156// $data = array(array('Lib',val1,val2,val3),...)
157
158
159$fileurlnb = '';
160if (!$user->hasRight('societe', 'client', 'voir')) {
161 $filenamenb = $dir.'/contractsnbinyear-'.$user->id.'-'.$year.'.png';
162 $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=contractstats&file=contractsnbinyear-'.$user->id.'-'.$year.'.png';
163} else {
164 $filenamenb = $dir.'/contractsnbinyear-'.$year.'.png';
165 $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=contractstats&file=contractsnbinyear-'.$year.'.png';
166}
167
168$px1 = new DolGraph();
169$mesg = $px1->isGraphKo();
170if (!$mesg) {
171 $px1->SetData($data);
172 $i = $startyear;
173 $legend = array();
174 while ($i <= $endyear) {
175 $legend[] = $i;
176 $i++;
177 }
178 $px1->SetLegend($legend);
179 $px1->SetMaxValue($px1->GetCeilMaxValue());
180 $px1->SetMinValue(min(0, $px1->GetFloorMinValue()));
181 $px1->SetWidth($WIDTH);
182 $px1->SetHeight($HEIGHT);
183 $px1->SetYLabel($langs->trans("NbOfContracts"));
184 $px1->SetShading(3);
185 $px1->SetHorizTickIncrement(1);
186 $px1->mode = 'depth';
187 $px1->SetTitle($langs->trans("NumberOfContractsByMonth"));
188
189 $px1->draw($filenamenb, $fileurlnb);
190}
191
192// Build graphic amount of object
193$data = $stats->getAmountByMonthWithPrevYear($endyear, $startyear);
194//var_dump($data);
195// $data = array(array('Lib',val1,val2,val3),...)
196
197$fileurlamount = '';
198if (!$user->hasRight('societe', 'client', 'voir')) {
199 $filenameamount = $dir.'/contractsamountinyear-'.$user->id.'-'.$year.'.png';
200 $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=contractstats&file=contractsamountinyear-'.$user->id.'-'.$year.'.png';
201} else {
202 $filenameamount = $dir.'/contractsamountinyear-'.$year.'.png';
203 $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=contractstats&file=contractsamountinyear-'.$year.'.png';
204}
205
206$px2 = new DolGraph();
207$mesg = $px2->isGraphKo();
208if (!$mesg) {
209 $px2->SetData($data);
210 $i = $startyear;
211 $legend = array();
212 while ($i <= $endyear) {
213 $legend[] = $i;
214 $i++;
215 }
216 $px2->SetLegend($legend);
217 $px2->SetMaxValue($px2->GetCeilMaxValue());
218 $px2->SetMinValue(min(0, $px2->GetFloorMinValue()));
219 $px2->SetWidth($WIDTH);
220 $px2->SetHeight($HEIGHT);
221 $px2->SetYLabel($langs->trans("AmountOfServices"));
222 $px2->SetShading(3);
223 $px2->SetHorizTickIncrement(1);
224 $px2->mode = 'depth';
225 $px2->SetTitle($langs->trans("AmountOfServicesByMonthHT"));
226
227 $px2->draw($filenameamount, $fileurlamount);
228}
229
230
231
232
233
234// Show array
235$data = $stats->getAllByYear();
236$arrayyears = array();
237foreach ($data as $val) {
238 if (!empty($val['year'])) {
239 $arrayyears[$val['year']] = $val['year'];
240 }
241}
242if (!count($arrayyears)) {
243 $arrayyears[$nowyear] = $nowyear;
244}
245
246$h = 0;
247$head = array();
248$head[$h][0] = DOL_URL_ROOT.'/contrat/stats/index.php?mode='.$mode;
249$head[$h][1] = $langs->trans("ByMonthYear");
250$head[$h][2] = 'byyear';
251$h++;
252
253$type = 'contract_stats';
254
255
256complete_head_from_modules($conf, $langs, null, $head, $h, $type);
257
258print dol_get_fiche_head($head, 'byyear', '', -1);
259
260
261print '<div class="fichecenter"><div class="fichethirdleft">';
262
263
264// Show filter box
265print '<form name="stats" method="POST" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
266print '<input type="hidden" name="token" value="'.newToken().'">';
267print '<input type="hidden" name="mode" value="'.$mode.'">';
268
269print '<table class="noborder centpercent">';
270print '<tr class="liste_titre"><td class="liste_titre" colspan="2">'.$langs->trans("Filter").'</td></tr>';
271// Company
272print '<tr><td class="left">'.$langs->trans("ThirdParty").'</td><td class="left">';
273$filter = '';
274if ($mode == 'customer') {
275 $filter = '(s.client:IN:1,2,3)';
276}
277if ($mode == 'supplier') {
278 $filter = '(s.fournisseur:=:1)';
279}
280print img_picto('', 'company', 'class="pictofixedwidth"');
281print $form->select_company($socid, 'socid', $filter, 1, 0, 0, array(), 0, 'widthcentpercentminusx maxwidth300');
282print '</td></tr>';
283// ThirdParty Type
284print '<tr><td>'.$langs->trans("ThirdPartyType").'</td><td>';
285$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.
286print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, 1, 0, 0, '', 0, 0, 0, $sortparam_typent, '', 1);
287if ($user->admin) {
288 print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
289}
290print '</td></tr>';
291// Category
292$cat_type = 0;
293$cat_label = '';
294if ($mode == 'customer') {
295 $cat_type = Categorie::TYPE_CUSTOMER;
296 $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer"));
297}
298if ($mode == 'supplier') {
299 $cat_type = Categorie::TYPE_SUPPLIER;
300 $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Supplier"));
301}
302print '<tr><td>'.$cat_label.'</td><td>';
303print img_picto('', 'category', 'class="pictofixedwidth"');
304print $formother->select_categories($cat_type, $categ_id, 'categ_id', 0, 1, 'widthcentpercentminusx maxwidth300');
305print '</td></tr>';
306// User
307print '<tr><td>'.$langs->trans("CreatedBy").'</td><td>';
308print img_picto('', 'user', 'class="pictofixedwidth"');
309print $form->select_dolusers($userid, 'userid', 1, null, 0, '', '', '0', 0, 0, '', 0, '', 'widthcentpercentminusx maxwidth300');
310// Status
311print '<tr><td>'.$langs->trans("Status").'</td><td>';
312
313$liststatus = array(
314 Contrat::STATUS_DRAFT => $langs->trans("ContractStatusDraft"),
315 Contrat::STATUS_VALIDATED => $langs->trans("ContractStatusValidated"),
316 Contrat::STATUS_CLOSED => $langs->trans("ContractStatusClosed"),
317);
318print $form->selectarray('object_status', $liststatus, GETPOST('object_status', 'intcomma'), -4);
319
320
321print '</td></tr>';
322// Year
323print '<tr><td class="left">'.$langs->trans("Year").'</td><td class="left">';
324if (!in_array($year, $arrayyears)) {
325 $arrayyears[$year] = $year;
326}
327if (!in_array($nowyear, $arrayyears)) {
328 $arrayyears[$nowyear] = $nowyear;
329}
330arsort($arrayyears);
331print img_picto('', 'calendar', 'class="pictofixedwidth"');
332print $form->selectarray('year', $arrayyears, $year, 0, 0, 0, '', 0, 0, 0, '', 'width75');
333print '</td></tr>';
334print '<tr><td align="center" colspan="2"><input type="submit" class="button small" name="submit" value="'.$langs->trans("Refresh").'"></td></tr>';
335print '</table>';
336print '</form>';
337print '<br><br>';
338
339
340print '<div class="div-table-responsive-no-min">';
341print '<table class="noborder centpercent">';
342print '<tr class="liste_titre" height="24">';
343print '<td class="center">'.$langs->trans("Year").'</td>';
344print '<td class="right">'.$langs->trans("NbOfContracts").'</td>';
345print '<td class="right">%</td>';
346print '<td class="right">'.$langs->trans("AmountTotal").'</td>';
347print '<td class="right">%</td>';
348print '<td class="right">'.$langs->trans("AmountAverage").'</td>';
349print '<td class="right">%</td>';
350print '</tr>';
351
352$oldyear = 0;
353foreach ($data as $val) {
354 $year = $val['year'];
355 while (!empty($year) && $oldyear > (int) $year + 1) { // If we have empty year
356 $oldyear--;
357
358 print '<tr class="oddeven" height="24">';
359 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>';
360 print '<td class="right">0</td>';
361 print '<td class="right"></td>';
362 print '<td class="right">0</td>';
363 print '<td class="right"></td>';
364 print '<td class="right">0</td>';
365 print '<td class="right"></td>';
366 print '</tr>';
367 }
368
369
370 print '<tr class="oddeven" height="24">';
371 print '<td align="center"><a href="'.$_SERVER["PHP_SELF"].'?year='.$year.'&amp;mode='.$mode.($socid > 0 ? '&socid='.$socid : '').($userid > 0 ? '&userid='.$userid : '').'">'.$year.'</a></td>';
372 print '<td class="right">'.$val['nb'].'</td>';
373 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>';
374 print '<td class="right">'.price(price2num($val['total'], 'MT'), 1).'</td>';
375 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>';
376 print '<td class="right">'.price(price2num($val['avg'], 'MT'), 1).'</td>';
377 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>';
378 print '</tr>';
379 $oldyear = $year;
380}
381
382print '</table>';
383print '</div>';
384
385
386print '</div><div class="fichetwothirdright">';
387
388
389// Show graphs
390print '<table class="border centpercent"><tr class="pair nohover"><td align="center">';
391if ($mesg) {
392 print $mesg;
393} else {
394 print $px1->show();
395 print "<br>\n";
396 print $px2->show();
397}
398print '</td></tr></table>';
399
400
401print '</div></div>';
402print '<div class="clearboth"></div>';
403
404print dol_get_fiche_end();
405
406// End of page
407llxFooter();
408$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 manage contract statistics.
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 to help generate other html components Only common components are here.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
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.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $selectlimitsuffix=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
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.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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).
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.
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.