dolibarr  17.0.4
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->rights->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 // We use select_thirdparty_list instead of select_company so we can use $filter and share same code for customer and supplier.
269 $filter = '';
270 if ($mode == 'customer') {
271  $filter = 's.client in (1,2,3)';
272 }
273 if ($mode == 'supplier') {
274  $filter = 's.fournisseur = 1';
275 }
276 
277 print '<div class="fichecenter"><div class="fichethirdleft">';
278 
279 
280 // Show filter box
281 print '<form name="stats" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
282 print '<input type="hidden" name="token" value="'.newToken().'">';
283 print '<input type="hidden" name="mode" value="'.$mode.'">';
284 
285 print '<table class="noborder centpercent">';
286 print '<tr class="liste_titre"><td class="liste_titre" colspan="2">'.$langs->trans("Filter").'</td></tr>';
287 // Company
288 print '<tr><td>'.$langs->trans("ThirdParty").'</td><td>';
289 print img_picto('', 'company', 'class="pictofixedwidth"');
290 print $form->select_company($socid, 'socid', $filter, 1, 0, 0, array(), 0, 'widthcentpercentminusx maxwidth300');
291 print '</td></tr>';
292 
293 // ThirdParty Type
294 print '<tr><td>'.$langs->trans("ThirdPartyType").'</td><td>';
295 $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.
296 print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, 1, 0, 0, '', 0, 0, 0, $sortparam_typent, '', 1);
297 if ($user->admin) {
298  print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
299 }
300 print '</td></tr>';
301 
302 // Category
303 if (isModEnabled('categorie')) {
304  if ($mode == 'customer') {
305  $cat_type = Categorie::TYPE_CUSTOMER;
306  $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer"));
307  }
308  if ($mode == 'supplier') {
309  $cat_type = Categorie::TYPE_SUPPLIER;
310  $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Supplier"));
311  }
312  print '<tr><td>'.$cat_label.'</td><td>';
313  $cate_arbo = $form->select_all_categories($cat_type, null, 'parent', null, null, 1);
314  print img_picto('', 'category', 'class="pictofixedwidth"');
315  print $form->multiselectarray('custcats', $cate_arbo, GETPOST('custcats', 'array'), 0, 0, 'widthcentpercentminusx maxwidth300');
316  //print $formother->select_categories($cat_type, $categ_id, 'categ_id', true);
317  print '</td></tr>';
318 }
319 
320 // User
321 print '<tr><td>'.$langs->trans("CreatedBy").'</td><td>';
322 print img_picto('', 'user', 'class="pictofixedwidth"');
323 print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', 0, 0, 0, '', 0, '', 'widthcentpercentminusx maxwidth300');
324 print '</td></tr>';
325 // Status
326 print '<tr><td>'.$langs->trans("Status").'</td><td>';
327 if ($mode == 'customer') {
328  $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"));
329  print $form->selectarray('object_status', $liststatus, $object_status, 1);
330 }
331 if ($mode == 'supplier') {
332  $liststatus = array('0'=>$langs->trans("BillStatusDraft"), '1'=>$langs->trans("BillStatusNotPaid"), '2'=>$langs->trans("BillStatusPaid"));
333  print $form->selectarray('object_status', $liststatus, $object_status, 1);
334 }
335 print '</td></tr>';
336 // Year
337 print '<tr><td>'.$langs->trans("Year").'</td><td>';
338 if (!in_array($year, $arrayyears)) {
339  $arrayyears[$year] = $year;
340 }
341 if (!in_array($nowyear, $arrayyears)) {
342  $arrayyears[$nowyear] = $nowyear;
343 }
344 arsort($arrayyears);
345 print $form->selectarray('year', $arrayyears, $year, 0, 0, 0, '', 0, 0, 0, '', 'width75');
346 print '</td></tr>';
347 print '<tr><td class="center" colspan="2"><input type="submit" name="submit" class="button small" value="'.$langs->trans("Refresh").'"></td></tr>';
348 print '</table>';
349 print '</form>';
350 print '<br><br>';
351 
352 print '<div class="div-table-responsive-no-min">';
353 print '<table class="noborder centpercent">';
354 print '<tr class="liste_titre" height="24">';
355 print '<td class="center">'.$langs->trans("Year").'</td>';
356 print '<td class="right">'.$langs->trans("NumberOfBills").'</td>';
357 print '<td class="right">%</td>';
358 print '<td class="right">'.$langs->trans("AmountTotal").'</td>';
359 print '<td class="right">%</td>';
360 print '<td class="right">'.$langs->trans("AmountAverage").'</td>';
361 print '<td class="right">%</td>';
362 print '</tr>';
363 
364 $oldyear = 0;
365 foreach ($data as $val) {
366  $year = $val['year'];
367  while ($year && $oldyear > $year + 1) { // If we have empty year
368  $oldyear--;
369 
370  print '<tr class="oddeven" height="24">';
371  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>';
372  print '<td class="right">0</td>';
373  print '<td class="right"></td>';
374  print '<td class="right amount">0</td>';
375  print '<td class="right"></td>';
376  print '<td class="right amount">0</td>';
377  print '<td class="right"></td>';
378  print '</tr>';
379  }
380 
381  if ($mode == 'supplier') {
382  $greennb = (empty($val['nb_diff']) || $val['nb_diff'] <= 0);
383  $greentotal = (empty($val['total_diff']) || $val['total_diff'] <= 0);
384  $greenavg = (empty($val['avg_diff']) || $val['avg_diff'] <= 0);
385  } else {
386  $greennb = (empty($val['nb_diff']) || $val['nb_diff'] >= 0);
387  $greentotal = (empty($val['total_diff']) || $val['total_diff'] >= 0);
388  $greenavg = (empty($val['avg_diff']) || $val['avg_diff'] >= 0);
389  }
390 
391  print '<tr class="oddeven" height="24">';
392  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>';
393  print '<td class="right">'.$val['nb'].'</td>';
394  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>';
395  print '<td class="right"><span class="amount">'.price(price2num($val['total'], 'MT'), 1).'</span></td>';
396  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>';
397  print '<td class="right"><span class="amount">'.price(price2num($val['avg'], 'MT'), 1).'</span></td>';
398  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>';
399  print '</tr>';
400  $oldyear = $year;
401 }
402 
403 print '</table>';
404 print '</div>';
405 
406 print '</div><div class="fichetwothirdright">';
407 
408 
409 // Show graphs
410 print '<table class="border centpercent"><tr class="pair nohover"><td align="center">';
411 if ($mesg) {
412  print $mesg;
413 } else {
414  print $px1->show();
415  print "<br>\n";
416  print $px2->show();
417  print "<br>\n";
418  print $px3->show();
419 }
420 print '</td></tr></table>';
421 
422 
423 print '</div></div>';
424 print '<div style="clear:both"></div>';
425 
426 
427 print dol_get_fiche_end();
428 
429 // End of page
430 llxFooter();
431 $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='')
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.