dolibarr  19.0.0-dev
index.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (c) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2012 Marcos García <marcosgdf@gmail.com>
5  * Copyright (C) 2013 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
7  * Copyright (C) 2020 Maxime DEMAREST <maxime@indelog.fr>
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 
29 // Load Dolibarr environment
30 require '../../../main.inc.php';
31 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php';
32 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facturestats.class.php';
36 if (isModEnabled('categorie')) {
37  require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
38 }
39 
41 $HEIGHT = DolGraph::getDefaultGraphSizeForStats('height');
42 
43 // Load translation files required by the page
44 $langs->loadLangs(array('bills', 'companies', 'other'));
45 
46 $mode = GETPOST("mode") ? GETPOST("mode") : 'customer';
47 if ($mode == 'customer' && !$user->hasRight('facture', 'lire')) {
49 }
50 if ($mode == 'supplier' && empty($user->rights->fournisseur->facture->lire)) {
52 }
53 
54 $object_status = GETPOST('object_status', 'intcomma');
55 $typent_id = GETPOST('typent_id', 'int');
56 $categ_id = GETPOST('categ_id', 'categ_id');
57 
58 $userid = GETPOST('userid', 'int');
59 $socid = GETPOST('socid', 'int');
60 $custcats = GETPOST('custcats', 'array');
61 // Security check
62 if ($user->socid > 0) {
63  $action = '';
64  $socid = $user->socid;
65 }
66 
67 $nowyear = dol_print_date(dol_now('gmt'), "%Y", 'gmt');
68 $year = GETPOST('year') > 0 ? GETPOST('year', 'int') : $nowyear;
69 $startyear = $year - (empty($conf->global->MAIN_STATS_GRAPHS_SHOW_N_YEARS) ? 2 : max(1, min(10, $conf->global->MAIN_STATS_GRAPHS_SHOW_N_YEARS)));
70 $endyear = $year;
71 
72 
73 /*
74  * View
75  */
76 if (isModEnabled('categorie')) {
77  $langs->load('categories');
78 }
79 $form = new Form($db);
80 $formcompany = new FormCompany($db);
81 $formother = new FormOther($db);
82 
83 llxHeader();
84 
85 $picto = 'bill';
86 $title = $langs->trans("BillsStatistics");
87 $dir = $conf->facture->dir_temp;
88 
89 if ($mode == 'supplier') {
90  $picto = 'supplier_invoice';
91  $title = $langs->trans("BillsStatisticsSuppliers");
92  $dir = $conf->fournisseur->facture->dir_temp;
93 }
94 
95 
96 print load_fiche_titre($title, '', $picto);
97 
98 dol_mkdir($dir);
99 
100 $stats = new FactureStats($db, $socid, $mode, ($userid > 0 ? $userid : 0), ($typent_id > 0 ? $typent_id : 0), ($categ_id > 0 ? $categ_id : 0));
101 if ($mode == 'customer') {
102  if ($object_status != '' && $object_status >= 0) {
103  $stats->where .= ' AND f.fk_statut IN ('.$db->sanitize($object_status).')';
104  }
105  if (is_array($custcats) && !empty($custcats)) {
106  $stats->from .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_societe as cat ON (f.fk_soc = cat.fk_soc)';
107  $stats->where .= ' AND cat.fk_categorie IN ('.$db->sanitize(implode(',', $custcats)).')';
108  }
109 }
110 if ($mode == 'supplier') {
111  if ($object_status != '' && $object_status >= 0) {
112  $stats->where .= ' AND f.fk_statut IN ('.$db->sanitize($object_status).')';
113  }
114  if (is_array($custcats) && !empty($custcats)) {
115  $stats->from .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_fournisseur as cat ON (f.fk_soc = cat.fk_soc)';
116  $stats->where .= ' AND cat.fk_categorie IN ('.$db->sanitize(implode(',', $custcats)).')';
117  }
118 }
119 
120 // Build graphic number of object
121 // $data = array(array('Lib',val1,val2,val3),...)
122 $data = $stats->getNbByMonthWithPrevYear($endyear, $startyear);
123 //var_dump($data);
124 
125 $filenamenb = $dir."/invoicesnbinyear-".$year.".png";
126 if ($mode == 'customer') {
127  $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=billstats&file=invoicesnbinyear-'.$year.'.png';
128 }
129 if ($mode == 'supplier') {
130  $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=billstatssupplier&file=invoicesnbinyear-'.$year.'.png';
131 }
132 
133 $px1 = new DolGraph();
134 $mesg = $px1->isGraphKo();
135 if (!$mesg) {
136  $px1->SetData($data);
137  $i = $startyear;
138  $legend = array();
139  while ($i <= $endyear) {
140  $legend[] = $i;
141  $i++;
142  }
143  $px1->SetLegend($legend);
144  $px1->SetMaxValue($px1->GetCeilMaxValue());
145  $px1->SetWidth($WIDTH);
146  $px1->SetHeight($HEIGHT);
147  $px1->SetYLabel($langs->trans("NumberOfBills"));
148  $px1->SetShading(3);
149  $px1->SetHorizTickIncrement(1);
150  $px1->mode = 'depth';
151  $px1->SetTitle($langs->trans("NumberOfBillsByMonth"));
152 
153  $px1->draw($filenamenb, $fileurlnb);
154 }
155 
156 // Build graphic amount of object
157 $data = $stats->getAmountByMonthWithPrevYear($endyear, $startyear);
158 //var_dump($data);
159 // $data = array(array('Lib',val1,val2,val3),...)
160 
161 $filenameamount = $dir."/invoicesamountinyear-".$year.".png";
162 if ($mode == 'customer') {
163  $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=billstats&amp;file=invoicesamountinyear-'.$year.'.png';
164 }
165 if ($mode == 'supplier') {
166  $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=billstatssupplier&amp;file=invoicesamountinyear-'.$year.'.png';
167 }
168 
169 $px2 = new DolGraph();
170 $mesg = $px2->isGraphKo();
171 if (!$mesg) {
172  $px2->SetData($data);
173  $i = $startyear;
174  $legend = array();
175  while ($i <= $endyear) {
176  $legend[] = $i;
177  $i++;
178  }
179  $px2->SetLegend($legend);
180  $px2->SetMaxValue($px2->GetCeilMaxValue());
181  $px2->SetMinValue(min(0, $px2->GetFloorMinValue()));
182  $px2->SetWidth($WIDTH);
183  $px2->SetHeight($HEIGHT);
184  $px2->SetYLabel($langs->trans("AmountOfBills"));
185  $px2->SetShading(3);
186  $px2->SetHorizTickIncrement(1);
187  $px2->mode = 'depth';
188  $px2->SetTitle($langs->trans("AmountOfBillsByMonthHT"));
189 
190  $px2->draw($filenameamount, $fileurlamount);
191 }
192 
193 
194 $data = $stats->getAverageByMonthWithPrevYear($endyear, $startyear);
195 
196 if (empty($user->rights->societe->client->voir) || $user->socid) {
197  $filename_avg = $dir.'/ordersaverage-'.$user->id.'-'.$year.'.png';
198  if ($mode == 'customer') {
199  $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstats&file=ordersaverage-'.$user->id.'-'.$year.'.png';
200  }
201  if ($mode == 'supplier') {
202  $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstatssupplier&file=ordersaverage-'.$user->id.'-'.$year.'.png';
203  }
204 } else {
205  $filename_avg = $dir.'/ordersaverage-'.$year.'.png';
206  if ($mode == 'customer') {
207  $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstats&file=ordersaverage-'.$year.'.png';
208  }
209  if ($mode == 'supplier') {
210  $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstatssupplier&file=ordersaverage-'.$year.'.png';
211  }
212 }
213 
214 $px3 = new DolGraph();
215 $mesg = $px3->isGraphKo();
216 if (!$mesg) {
217  $px3->SetData($data);
218  $i = $startyear;
219  $legend = array();
220  while ($i <= $endyear) {
221  $legend[] = $i;
222  $i++;
223  }
224  $px3->SetLegend($legend);
225  $px3->SetYLabel($langs->trans("AmountAverage"));
226  $px3->SetMaxValue($px3->GetCeilMaxValue());
227  $px3->SetMinValue($px3->GetFloorMinValue());
228  $px3->SetWidth($WIDTH);
229  $px3->SetHeight($HEIGHT);
230  $px3->SetShading(3);
231  $px3->SetHorizTickIncrement(1);
232  $px3->mode = 'depth';
233  $px3->SetTitle($langs->trans("AmountAverage"));
234 
235  $px3->draw($filename_avg, $fileurl_avg);
236 }
237 
238 
239 // Show array
240 $data = $stats->getAllByYear();
241 $arrayyears = array();
242 foreach ($data as $val) {
243  $arrayyears[$val['year']] = $val['year'];
244 }
245 if (!count($arrayyears)) {
246  $arrayyears[$nowyear] = $nowyear;
247 }
248 
249 
250 $h = 0;
251 $head = array();
252 $head[$h][0] = DOL_URL_ROOT.'/compta/facture/stats/index.php?mode='.urlencode($mode);
253 $head[$h][1] = $langs->trans("ByMonthYear");
254 $head[$h][2] = 'byyear';
255 $h++;
256 
257 if ($mode == 'customer') {
258  $type = 'invoice_stats';
259 }
260 if ($mode == 'supplier') {
261  $type = 'supplier_invoice_stats';
262 }
263 
264 complete_head_from_modules($conf, $langs, null, $head, $h, $type);
265 
266 print dol_get_fiche_head($head, 'byyear', $langs->trans("Statistics"), -1);
267 
268 print '<div class="fichecenter"><div class="fichethirdleft">';
269 
270 
271 // Show filter box
272 print '<form name="stats" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
273 print '<input type="hidden" name="token" value="'.newToken().'">';
274 print '<input type="hidden" name="mode" value="'.$mode.'">';
275 
276 print '<table class="noborder centpercent">';
277 print '<tr class="liste_titre"><td class="liste_titre" colspan="2">'.$langs->trans("Filter").'</td></tr>';
278 // Company
279 print '<tr><td>'.$langs->trans("ThirdParty").'</td><td>';
280 $filter = '';
281 if ($mode == 'customer') {
282  $filter = '(s.client:IN:1,2,3)';
283 }
284 if ($mode == 'supplier') {
285  $filter = '(s.fournisseur:=:1)';
286 }
287 print img_picto('', 'company', 'class="pictofixedwidth"');
288 print $form->select_company($socid, 'socid', $filter, 1, 0, 0, array(), 0, 'widthcentpercentminusx maxwidth300');
289 print '</td></tr>';
290 
291 // ThirdParty Type
292 print '<tr><td>'.$langs->trans("ThirdPartyType").'</td><td>';
293 $sortparam_typent = (empty($conf->global->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.
294 print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, 1, 0, 0, '', 0, 0, 0, $sortparam_typent, '', 1);
295 if ($user->admin) {
296  print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
297 }
298 print '</td></tr>';
299 
300 // Category
301 if (isModEnabled('categorie')) {
302  if ($mode == 'customer') {
303  $cat_type = Categorie::TYPE_CUSTOMER;
304  $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer"));
305  }
306  if ($mode == 'supplier') {
307  $cat_type = Categorie::TYPE_SUPPLIER;
308  $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Supplier"));
309  }
310  print '<tr><td>'.$cat_label.'</td><td>';
311  $cate_arbo = $form->select_all_categories($cat_type, null, 'parent', null, null, 1);
312  print img_picto('', 'category', 'class="pictofixedwidth"');
313  print $form->multiselectarray('custcats', $cate_arbo, GETPOST('custcats', 'array'), 0, 0, 'widthcentpercentminusx maxwidth300');
314  //print $formother->select_categories($cat_type, $categ_id, 'categ_id', true);
315  print '</td></tr>';
316 }
317 
318 // User
319 print '<tr><td>'.$langs->trans("CreatedBy").'</td><td>';
320 print img_picto('', 'user', 'class="pictofixedwidth"');
321 print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', 0, 0, 0, '', 0, '', 'widthcentpercentminusx maxwidth300');
322 print '</td></tr>';
323 // Status
324 print '<tr><td>'.$langs->trans("Status").'</td><td>';
325 if ($mode == 'customer') {
326  $liststatus = array('0'=>$langs->trans("BillStatusDraft"), '1'=>$langs->trans("BillStatusNotPaid"), '2'=>$langs->trans("BillStatusPaid"), '1,2'=>$langs->trans("BillStatusNotPaid").' / '.$langs->trans("BillStatusPaid"), '3'=>$langs->trans("BillStatusCanceled"));
327  print $form->selectarray('object_status', $liststatus, $object_status, 1);
328 }
329 if ($mode == 'supplier') {
330  $liststatus = array('0'=>$langs->trans("BillStatusDraft"), '1'=>$langs->trans("BillStatusNotPaid"), '2'=>$langs->trans("BillStatusPaid"));
331  print $form->selectarray('object_status', $liststatus, $object_status, 1);
332 }
333 print '</td></tr>';
334 // Year
335 print '<tr><td>'.$langs->trans("Year").'</td><td>';
336 if (!in_array($year, $arrayyears)) {
337  $arrayyears[$year] = $year;
338 }
339 if (!in_array($nowyear, $arrayyears)) {
340  $arrayyears[$nowyear] = $nowyear;
341 }
342 arsort($arrayyears);
343 print $form->selectarray('year', $arrayyears, $year, 0, 0, 0, '', 0, 0, 0, '', 'width75');
344 print '</td></tr>';
345 print '<tr><td class="center" colspan="2"><input type="submit" name="submit" class="button small" value="'.$langs->trans("Refresh").'"></td></tr>';
346 print '</table>';
347 print '</form>';
348 print '<br><br>';
349 
350 print '<div class="div-table-responsive-no-min">';
351 print '<table class="noborder centpercent">';
352 print '<tr class="liste_titre" height="24">';
353 print '<td class="center">'.$langs->trans("Year").'</td>';
354 print '<td class="right">'.$langs->trans("NumberOfBills").'</td>';
355 print '<td class="right">%</td>';
356 print '<td class="right">'.$langs->trans("AmountTotal").'</td>';
357 print '<td class="right">%</td>';
358 print '<td class="right">'.$langs->trans("AmountAverage").'</td>';
359 print '<td class="right">%</td>';
360 print '</tr>';
361 
362 $oldyear = 0;
363 foreach ($data as $val) {
364  $year = $val['year'];
365  while ($year && $oldyear > $year + 1) { // If we have empty year
366  $oldyear--;
367 
368  print '<tr class="oddeven" height="24">';
369  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>';
370  print '<td class="right">0</td>';
371  print '<td class="right"></td>';
372  print '<td class="right amount">0</td>';
373  print '<td class="right"></td>';
374  print '<td class="right amount">0</td>';
375  print '<td class="right"></td>';
376  print '</tr>';
377  }
378 
379  if ($mode == 'supplier') {
380  $greennb = (empty($val['nb_diff']) || $val['nb_diff'] <= 0);
381  $greentotal = (empty($val['total_diff']) || $val['total_diff'] <= 0);
382  $greenavg = (empty($val['avg_diff']) || $val['avg_diff'] <= 0);
383  } else {
384  $greennb = (empty($val['nb_diff']) || $val['nb_diff'] >= 0);
385  $greentotal = (empty($val['total_diff']) || $val['total_diff'] >= 0);
386  $greenavg = (empty($val['avg_diff']) || $val['avg_diff'] >= 0);
387  }
388 
389  print '<tr class="oddeven" height="24">';
390  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>';
391  print '<td class="right">'.$val['nb'].'</td>';
392  print '<td class="right opacitylow" style="'.($greennb ? 'color: green;' : 'color: red;').'">'.(!empty($val['nb_diff']) && $val['nb_diff'] < 0 ? '' : '+').round(!empty($val['nb_diff']) ? $val['nb_diff'] : 0).'%</td>';
393  print '<td class="right"><span class="amount">'.price(price2num($val['total'], 'MT'), 1).'</span></td>';
394  print '<td class="right opacitylow" style="'.($greentotal ? 'color: green;' : 'color: red;').'">'.( !empty($val['total_diff']) && $val['total_diff'] < 0 ? '' : '+').round(!empty($val['total_diff']) ? $val['total_diff'] : 0).'%</td>';
395  print '<td class="right"><span class="amount">'.price(price2num($val['avg'], 'MT'), 1).'</span></td>';
396  print '<td class="right opacitylow" style="'.($greenavg ? 'color: green;' : 'color: red;').'">'.(!empty($val['avg_diff']) && $val['avg_diff'] < 0 ? '' : '+').round(!empty($val['avg_diff']) ? $val['avg_diff'] : 0).'%</td>';
397  print '</tr>';
398  $oldyear = $year;
399 }
400 
401 print '</table>';
402 print '</div>';
403 
404 print '</div><div class="fichetwothirdright">';
405 
406 
407 // Show graphs
408 print '<table class="border centpercent"><tr class="pair nohover"><td align="center">';
409 if ($mesg) {
410  print $mesg;
411 } else {
412  print $px1->show();
413  print "<br>\n";
414  print $px2->show();
415  print "<br>\n";
416  print $px3->show();
417 }
418 print '</td></tr></table>';
419 
420 
421 print '</div></div>';
422 print '<div class="clearboth"></div>';
423 
424 
425 print dol_get_fiche_end();
426 
427 // End of page
428 llxFooter();
429 $db->close();
Class to build graphs.
static getDefaultGraphSizeForStats($direction, $defaultsize='')
getDefaultGraphSizeForStats
Class to manage stats for invoices (customer and supplier)
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.
Classe permettant la generation de composants html autre Only common components are here.
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
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.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
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).
isModEnabled($module)
Is Dolibarr module enabled.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
llxFooter()
Footer empty.
Definition: index.php:71
if(!defined('NOTOKENRENEWAL')) if(!defined('NOLOGIN')) if(!defined('NOCSRFCHECK')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) if(!defined('NOIPCHECK')) if(!defined('NOBROWSERNOTIF')) llxHeader()
Header empty.
Definition: index.php:63
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.