dolibarr 25.0.0-alpha
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("Contracts");
113$dir = $conf->contract->dir_temp;
114
115
116llxHeader('', $title, '', '', 0, 0, '', '', '', 'mod-contract page-stats');
117
118$page = 0;
119$param = '';
120$sortfield = '';
121$sortorder = '';
122$massactionbutton = '';
123$num = 0;
124$nbtotalofrecords = $langs->trans("Statistics");
125$limit = 0;
126
127$urlnew = DOL_URL_ROOT.'/contrat/card.php?action=create';
128if (!empty($socid)) {
129 $urlnew .= '&socid='.$socid;
130}
131
132$newcardbutton = '';
133$newcardbutton .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/contrat/list.php?mode=common', '', 1, array('morecss' => 'reposition'));
134$newcardbutton .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', DOL_URL_ROOT.'/contrat/list.php?mode=kanban', '', 1, array('morecss' => 'reposition'));
135$newcardbutton .= dolGetButtonTitle($langs->trans('Statistics'), '', 'fa fa-chart-bar imgforviewmode', DOL_URL_ROOT.'/contrat/stats/index.php', '', 2, array('morecss' => 'reposition'));
136$newcardbutton .= dolGetButtonTitleSeparator();
137$newcardbutton .= dolGetButtonTitle($langs->trans('NewContractSubscription'), '', 'fa fa-plus-circle', $urlnew, '', $user->hasRight('contrat', 'creer'));
138
139print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, $picto, 0, $newcardbutton, '', $limit, 0, 0, 1);
140
141dol_mkdir($dir);
142
143$stats = new ContratStats($db, $socid, $mode, ($userid > 0 ? $userid : 0), ($typent_id > 0 ? $typent_id : 0), ($categ_id > 0 ? $categ_id : 0));
144
145if ($object_status != '' && $object_status >= -1) {
146 $stats->where .= ' AND c.statut IN ('.$db->sanitize($object_status).')';
147}
148
149
150
151// Build graphic number of object
152$data = $stats->getNbByMonthWithPrevYear($endyear, $startyear);
153
154//var_dump($data);
155// $data = array(array('Lib',val1,val2,val3),...)
156
157
158$fileurlnb = '';
159if (!$user->hasRight('societe', 'client', 'voir')) {
160 $filenamenb = $dir.'/contractsnbinyear-'.$user->id.'-'.$year.'.png';
161 $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=contractstats&file=contractsnbinyear-'.$user->id.'-'.$year.'.png';
162} else {
163 $filenamenb = $dir.'/contractsnbinyear-'.$year.'.png';
164 $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=contractstats&file=contractsnbinyear-'.$year.'.png';
165}
166
167$px1 = new DolGraph();
168$mesg = $px1->isGraphKo();
169if (!$mesg) {
170 $px1->SetData($data);
171 $i = $startyear;
172 $legend = array();
173 while ($i <= $endyear) {
174 $legend[] = $i;
175 $i++;
176 }
177 $px1->SetLegend($legend);
178 $px1->SetMaxValue($px1->GetCeilMaxValue());
179 $px1->SetMinValue(min(0, $px1->GetFloorMinValue()));
180 $px1->SetWidth($WIDTH);
181 $px1->SetHeight($HEIGHT);
182 $px1->SetYLabel($langs->trans("NbOfContracts"));
183 $px1->SetShading(3);
184 $px1->SetHorizTickIncrement(1);
185 $px1->mode = 'depth';
186 $px1->SetTitle($langs->trans("NumberOfContractsByMonth"));
187
188 $px1->draw($filenamenb, $fileurlnb);
189}
190
191// Build graphic amount of object
192$data = $stats->getAmountByMonthWithPrevYear($endyear, $startyear);
193//var_dump($data);
194// $data = array(array('Lib',val1,val2,val3),...)
195
196$fileurlamount = '';
197if (!$user->hasRight('societe', 'client', 'voir')) {
198 $filenameamount = $dir.'/contractsamountinyear-'.$user->id.'-'.$year.'.png';
199 $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=contractstats&file=contractsamountinyear-'.$user->id.'-'.$year.'.png';
200} else {
201 $filenameamount = $dir.'/contractsamountinyear-'.$year.'.png';
202 $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=contractstats&file=contractsamountinyear-'.$year.'.png';
203}
204
205$px2 = new DolGraph();
206$mesg = $px2->isGraphKo();
207if (!$mesg) {
208 $px2->SetData($data);
209 $i = $startyear;
210 $legend = array();
211 while ($i <= $endyear) {
212 $legend[] = $i;
213 $i++;
214 }
215 $px2->SetLegend($legend);
216 $px2->SetMaxValue($px2->GetCeilMaxValue());
217 $px2->SetMinValue(min(0, $px2->GetFloorMinValue()));
218 $px2->SetWidth($WIDTH);
219 $px2->SetHeight($HEIGHT);
220 $px2->SetYLabel($langs->trans("AmountOfServices"));
221 $px2->SetShading(3);
222 $px2->SetHorizTickIncrement(1);
223 $px2->mode = 'depth';
224 $px2->SetTitle($langs->trans("AmountOfServicesByMonthHT"));
225
226 $px2->draw($filenameamount, $fileurlamount);
227}
228
229
230
231// Show array
232$data = $stats->getAllByYear();
233$arrayyears = array();
234foreach ($data as $val) {
235 if (!empty($val['year'])) {
236 $arrayyears[$val['year']] = $val['year'];
237 }
238}
239if (!count($arrayyears)) {
240 $arrayyears[$nowyear] = $nowyear;
241}
242
243$h = 0;
244$head = array();
245$head[$h][0] = DOL_URL_ROOT.'/contrat/stats/index.php?mode='.$mode;
246$head[$h][1] = $langs->trans("ByMonthYear");
247$head[$h][2] = 'byyear';
248$h++;
249
250$type = 'contract_stats';
251
252
253complete_head_from_modules($conf, $langs, null, $head, $h, $type);
254
255print dol_get_fiche_head($head, 'byyear', '', -1);
256
257
258print '<div class="fichecenter"><div class="fichethirdleft">';
259
260
261// Show filter box
262print '<form name="stats" method="POST" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
263print '<input type="hidden" name="token" value="'.newToken().'">';
264print '<input type="hidden" name="mode" value="'.$mode.'">';
265
266print '<table class="noborder centpercent">';
267print '<tr class="liste_titre"><td class="liste_titre" colspan="2">'.$langs->trans("Filter").'</td></tr>';
268// Company
269print '<tr><td class="left">'.$langs->trans("ThirdParty").'</td><td class="left">';
270$filter = '';
271if ($mode == 'customer') {
272 $filter = '(s.client:IN:1,2,3)';
273}
274if ($mode == 'supplier') {
275 $filter = '(s.fournisseur:=:1)';
276}
277print img_picto('', 'company', 'class="pictofixedwidth"');
278print $form->select_company($socid, 'socid', $filter, 1, 0, 0, array(), 0, 'widthcentpercentminusx maxwidth300');
279print '</td></tr>';
280// ThirdParty Type
281print '<tr><td>'.$langs->trans("ThirdPartyType").'</td><td>';
282$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.
283print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, 1, 0, 0, '', 0, 0, 0, $sortparam_typent, '', 1);
284if ($user->admin) {
285 print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
286}
287print '</td></tr>';
288// Category
289$cat_type = 0;
290$cat_label = '';
291if ($mode == 'customer') {
292 $cat_type = Categorie::TYPE_CUSTOMER;
293 $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer"));
294}
295if ($mode == 'supplier') {
296 $cat_type = Categorie::TYPE_SUPPLIER;
297 $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Supplier"));
298}
299print '<tr><td>'.$cat_label.'</td><td>';
300print img_picto('', 'category', 'class="pictofixedwidth"');
301print $formother->select_categories($cat_type, $categ_id, 'categ_id', 0, 1, 'widthcentpercentminusx maxwidth300');
302print '</td></tr>';
303// User
304print '<tr><td>'.$langs->trans("CreatedBy").'</td><td>';
305print img_picto('', 'user', 'class="pictofixedwidth"');
306print $form->select_dolusers($userid, 'userid', 1, null, 0, '', '', '0', 0, 0, '', 0, '', 'widthcentpercentminusx maxwidth300');
307// Status
308print '<tr><td>'.$langs->trans("Status").'</td><td>';
309
310$liststatus = array(
311 Contrat::STATUS_DRAFT => $langs->trans("ContractStatusDraft"),
312 Contrat::STATUS_VALIDATED => $langs->trans("ContractStatusValidated"),
313 Contrat::STATUS_CLOSED => $langs->trans("ContractStatusClosed"),
314);
315print $form->selectarray('object_status', $liststatus, GETPOST('object_status', 'intcomma'), -4);
316
317
318print '</td></tr>';
319// Year
320print '<tr><td class="left">'.$langs->trans("Year").'</td><td class="left">';
321if (!in_array($year, $arrayyears)) {
322 $arrayyears[$year] = $year;
323}
324if (!in_array($nowyear, $arrayyears)) {
325 $arrayyears[$nowyear] = $nowyear;
326}
327arsort($arrayyears);
328print img_picto('', 'calendar', 'class="pictofixedwidth"');
329print $form->selectarray('year', $arrayyears, $year, 0, 0, 0, '', 0, 0, 0, '', 'width75');
330print '</td></tr>';
331print '<tr><td align="center" colspan="2"><input type="submit" class="button small" name="submit" value="'.$langs->trans("Refresh").'"></td></tr>';
332print '</table>';
333print '</form>';
334print '<br><br>';
335
336
337print '<div class="div-table-responsive-no-min">';
338print '<table class="noborder centpercent">';
339print '<tr class="liste_titre" height="24">';
340print '<td class="center">'.$langs->trans("Year").'</td>';
341print '<td class="right">'.$langs->trans("NbOfContracts").'</td>';
342print '<td class="right">%</td>';
343print '<td class="right">'.$langs->trans("AmountTotal").'</td>';
344print '<td class="right">%</td>';
345print '<td class="right">'.$langs->trans("AmountAverage").'</td>';
346print '<td class="right">%</td>';
347print '</tr>';
348
349$oldyear = 0;
350foreach ($data as $val) {
351 $year = $val['year'];
352 while (!empty($year) && $oldyear > (int) $year + 1) { // If we have empty year
353 $oldyear--;
354
355 print '<tr class="oddeven" height="24">';
356 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>';
357 print '<td class="right">0</td>';
358 print '<td class="right"></td>';
359 print '<td class="right">0</td>';
360 print '<td class="right"></td>';
361 print '<td class="right">0</td>';
362 print '<td class="right"></td>';
363 print '</tr>';
364 }
365
366
367 print '<tr class="oddeven" height="24">';
368 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>';
369 print '<td class="right">'.$val['nb'].'</td>';
370 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>';
371 print '<td class="right">'.price(price2num($val['total'], 'MT'), 1).'</td>';
372 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>';
373 print '<td class="right">'.price(price2num($val['avg'], 'MT'), 1).'</td>';
374 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>';
375 print '</tr>';
376 $oldyear = $year;
377}
378
379print '</table>';
380print '</div>';
381
382
383print '</div><div class="fichetwothirdright">';
384
385
386// Show graphs
387print '<table class="border centpercent"><tr class="pair nohover"><td align="center">';
388if ($mesg) {
389 print $mesg;
390} else {
391 print $px1->show();
392 print "<br>\n";
393 print $px2->show();
394}
395print '</td></tr></table>';
396
397
398print '</div></div>';
399print '<div class="clearboth"></div>';
400
401print dol_get_fiche_end();
402
403// End of page
404llxFooter();
405$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)
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 '.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
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, $nodefault=0)
Return value of a param into GET or POST supervariable.
dolGetButtonTitleSeparator($moreClass="")
Add space between dolGetButtonTitle.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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).
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
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.