dolibarr 21.0.0-alpha
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 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
30// Load Dolibarr environment
31require '../../../main.inc.php';
32require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php';
33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
35require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
36require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facturestats.class.php';
37if (isModEnabled('category')) {
38 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
39}
40
43
44// Load translation files required by the page
45$langs->loadLangs(array('bills', 'companies', 'other'));
46
47$mode = GETPOST("mode") ? GETPOST("mode") : 'customer';
48
49$hookmanager->initHooks(array('invoicestats', 'globalcard'));
50
51if ($mode == 'customer' && !$user->hasRight('facture', 'lire')) {
53}
54if ($mode == 'supplier' && !$user->hasRight('fournisseur', 'facture', 'lire')) {
56}
57
58$object_status = GETPOST('object_status', 'intcomma');
59$typent_id = GETPOSTINT('typent_id');
60$categ_id = GETPOSTINT('categ_id');
61
62$userid = GETPOSTINT('userid');
63$socid = GETPOSTINT('socid');
64$select_categ_categ_id = GETPOST('select_categ_categ_id', 'array');
65// Security check
66if ($user->socid > 0) {
67 $action = '';
68 $socid = $user->socid;
69}
70
71$parameters = array();
72$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
73if ($reshook < 0) {
74 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
75}
76
77$nowyear = dol_print_date(dol_now('gmt'), "%Y", 'gmt');
78$year = GETPOST('year') > 0 ? GETPOSTINT('year') : $nowyear;
79$startyear = $year - (!getDolGlobalString('MAIN_STATS_GRAPHS_SHOW_N_YEARS') ? 2 : max(1, min(10, getDolGlobalString('MAIN_STATS_GRAPHS_SHOW_N_YEARS'))));
80$endyear = $year;
81
82
83/*
84 * View
85 */
86if (isModEnabled('category')) {
87 $langs->load('categories');
88}
89$form = new Form($db);
90$formcompany = new FormCompany($db);
91$formother = new FormOther($db);
92
93llxHeader();
94
95$picto = 'bill';
96$title = $langs->trans("BillsStatistics");
97$dir = $conf->facture->dir_temp;
98
99if ($mode == 'supplier') {
100 $picto = 'supplier_invoice';
101 $title = $langs->trans("BillsStatisticsSuppliers");
102 $dir = $conf->fournisseur->facture->dir_temp;
103}
104
105
106print load_fiche_titre($title, '', $picto);
107
108dol_mkdir($dir);
109
110$stats = new FactureStats($db, $socid, $mode, ($userid > 0 ? $userid : 0), ($typent_id > 0 ? $typent_id : 0), ($categ_id > 0 ? $categ_id : 0));
111if ($mode == 'customer') {
112 if ($object_status != '' && $object_status >= 0) {
113 $stats->where .= ' AND f.fk_statut IN ('.$db->sanitize($object_status).')';
114 }
115 if (is_array($select_categ_categ_id) && !empty($select_categ_categ_id)) {
116 $stats->from .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_societe as cat ON (f.fk_soc = cat.fk_soc)';
117 $stats->where .= ' AND cat.fk_categorie IN ('.$db->sanitize(implode(',', $select_categ_categ_id)).')';
118 }
119}
120if ($mode == 'supplier') {
121 if ($object_status != '' && $object_status >= 0) {
122 $stats->where .= ' AND f.fk_statut IN ('.$db->sanitize($object_status).')';
123 }
124 if (is_array($select_categ_categ_id) && !empty($select_categ_categ_id)) {
125 $stats->from .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_fournisseur as cat ON (f.fk_soc = cat.fk_soc)';
126 $stats->where .= ' AND cat.fk_categorie IN ('.$db->sanitize(implode(',', $select_categ_categ_id)).')';
127 }
128}
129
130// Build graphic number of object
131// $data = array(array('Lib',val1,val2,val3),...)
132$data = $stats->getNbByMonthWithPrevYear($endyear, $startyear);
133//var_dump($data);
134
135$filenamenb = $dir."/invoicesnbinyear-".$year.".png";
136if ($mode == 'customer') {
137 $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=billstats&file=invoicesnbinyear-'.$year.'.png';
138}
139if ($mode == 'supplier') {
140 $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=billstatssupplier&file=invoicesnbinyear-'.$year.'.png';
141}
142
143$px1 = new DolGraph();
144$mesg = $px1->isGraphKo();
145if (!$mesg) {
146 $px1->SetData($data);
147 $i = $startyear;
148 $legend = array();
149 while ($i <= $endyear) {
150 $legend[] = $i;
151 $i++;
152 }
153 $px1->SetLegend($legend);
154 $px1->SetMaxValue($px1->GetCeilMaxValue());
155 $px1->SetWidth($WIDTH);
156 $px1->SetHeight($HEIGHT);
157 $px1->SetYLabel($langs->trans("NumberOfBills"));
158 $px1->SetShading(3);
159 $px1->SetHorizTickIncrement(1);
160 $px1->mode = 'depth';
161 $px1->SetTitle($langs->trans("NumberOfBillsByMonth"));
162
163 $px1->draw($filenamenb, $fileurlnb);
164}
165
166// Build graphic amount of object
167$data = $stats->getAmountByMonthWithPrevYear($endyear, $startyear);
168//var_dump($data);
169// $data = array(array('Lib',val1,val2,val3),...)
170
171$filenameamount = $dir."/invoicesamountinyear-".$year.".png";
172if ($mode == 'customer') {
173 $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=billstats&amp;file=invoicesamountinyear-'.$year.'.png';
174}
175if ($mode == 'supplier') {
176 $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=billstatssupplier&amp;file=invoicesamountinyear-'.$year.'.png';
177}
178
179$px2 = new DolGraph();
180$mesg = $px2->isGraphKo();
181if (!$mesg) {
182 $px2->SetData($data);
183 $i = $startyear;
184 $legend = array();
185 while ($i <= $endyear) {
186 $legend[] = $i;
187 $i++;
188 }
189 $px2->SetLegend($legend);
190 $px2->SetMaxValue($px2->GetCeilMaxValue());
191 $px2->SetMinValue(min(0, $px2->GetFloorMinValue()));
192 $px2->SetWidth($WIDTH);
193 $px2->SetHeight($HEIGHT);
194 $px2->SetYLabel($langs->trans("AmountOfBills"));
195 $px2->SetShading(3);
196 $px2->SetHorizTickIncrement(1);
197 $px2->mode = 'depth';
198 $px2->SetTitle($langs->trans("AmountOfBillsByMonthHT"));
199
200 $px2->draw($filenameamount, $fileurlamount);
201}
202
203
204$data = $stats->getAverageByMonthWithPrevYear($endyear, $startyear);
205
206if (!$user->hasRight('societe', 'client', 'voir')) {
207 $filename_avg = $dir.'/ordersaverage-'.$user->id.'-'.$year.'.png';
208 if ($mode == 'customer') {
209 $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstats&file=ordersaverage-'.$user->id.'-'.$year.'.png';
210 }
211 if ($mode == 'supplier') {
212 $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstatssupplier&file=ordersaverage-'.$user->id.'-'.$year.'.png';
213 }
214} else {
215 $filename_avg = $dir.'/ordersaverage-'.$year.'.png';
216 if ($mode == 'customer') {
217 $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstats&file=ordersaverage-'.$year.'.png';
218 }
219 if ($mode == 'supplier') {
220 $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstatssupplier&file=ordersaverage-'.$year.'.png';
221 }
222}
223
224$px3 = new DolGraph();
225$mesg = $px3->isGraphKo();
226if (!$mesg) {
227 $px3->SetData($data);
228 $i = $startyear;
229 $legend = array();
230 while ($i <= $endyear) {
231 $legend[] = $i;
232 $i++;
233 }
234 $px3->SetLegend($legend);
235 $px3->SetYLabel($langs->trans("AmountAverage"));
236 $px3->SetMaxValue($px3->GetCeilMaxValue());
237 $px3->SetMinValue($px3->GetFloorMinValue());
238 $px3->SetWidth($WIDTH);
239 $px3->SetHeight($HEIGHT);
240 $px3->SetShading(3);
241 $px3->SetHorizTickIncrement(1);
242 $px3->mode = 'depth';
243 $px3->SetTitle($langs->trans("AmountAverage"));
244
245 $px3->draw($filename_avg, $fileurl_avg);
246}
247
248
249// Show array
250$data = $stats->getAllByYear();
251$arrayyears = array();
252foreach ($data as $val) {
253 $arrayyears[$val['year']] = $val['year'];
254}
255if (!count($arrayyears)) {
256 $arrayyears[$nowyear] = $nowyear;
257}
258
259
260$h = 0;
261$head = array();
262$head[$h][0] = DOL_URL_ROOT.'/compta/facture/stats/index.php?mode='.urlencode($mode);
263$head[$h][1] = $langs->trans("ByMonthYear");
264$head[$h][2] = 'byyear';
265$h++;
266
267if ($mode == 'customer') {
268 $type = 'invoice_stats';
269}
270if ($mode == 'supplier') {
271 $type = 'supplier_invoice_stats';
272}
273
274complete_head_from_modules($conf, $langs, null, $head, $h, $type);
275
276print dol_get_fiche_head($head, 'byyear', '', -1);
277
278print '<div class="fichecenter"><div class="fichethirdleft">';
279
280
281// Show filter box
282print '<form name="stats" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
283print '<input type="hidden" name="token" value="'.newToken().'">';
284print '<input type="hidden" name="mode" value="'.$mode.'">';
285
286print '<table class="noborder centpercent">';
287print '<tr class="liste_titre"><td class="liste_titre" colspan="2">'.$langs->trans("Filter").'</td></tr>';
288// Company
289print '<tr><td>'.$langs->trans("ThirdParty").'</td><td>';
290$filter = '';
291if ($mode == 'customer') {
292 $filter = '(s.client:IN:1,2,3)';
293}
294if ($mode == 'supplier') {
295 $filter = '(s.fournisseur:=:1)';
296}
297print img_picto('', 'company', 'class="pictofixedwidth"');
298print $form->select_company($socid, 'socid', $filter, 1, 0, 0, array(), 0, 'widthcentpercentminusx maxwidth300');
299print '</td></tr>';
300
301// ThirdParty Type
302print '<tr><td>'.$langs->trans("ThirdPartyType").'</td><td>';
303$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.
304print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, 1, 0, 0, '', 0, 0, 0, $sortparam_typent, '', 1);
305if ($user->admin) {
306 print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
307}
308print '</td></tr>';
309
310// Category
311if (isModEnabled('category')) {
312 if ($mode == 'customer') {
313 $cat_type = Categorie::TYPE_CUSTOMER;
314 $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer"));
315 }
316 if ($mode == 'supplier') {
317 $cat_type = Categorie::TYPE_SUPPLIER;
318 $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Supplier"));
319 }
320 print '<tr><td>'.$cat_label.'</td><td>';
321 $cate_arbo = $form->select_all_categories($cat_type, null, 'parent', null, null, 1);
322 print img_picto('', 'category', 'class="pictofixedwidth"');
323 print $form->multiselectarray('select_categ_categ_id', $cate_arbo, GETPOST('select_categ_categ_id', 'array'), 0, 0, 'widthcentpercentminusx maxwidth300');
324 //print $formother->select_categories($cat_type, $categ_id, 'categ_id', true);
325 print '</td></tr>';
326}
327
328// User
329print '<tr><td>'.$langs->trans("CreatedBy").'</td><td>';
330print img_picto('', 'user', 'class="pictofixedwidth"');
331print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', 0, 0, 0, '', 0, '', 'widthcentpercentminusx maxwidth300');
332print '</td></tr>';
333// Status
334print '<tr><td>'.$langs->trans("Status").'</td><td>';
335if ($mode == 'customer') {
336 $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"));
337 print $form->selectarray('object_status', $liststatus, $object_status, 1);
338}
339if ($mode == 'supplier') {
340 $liststatus = array('0' => $langs->trans("BillStatusDraft"), '1' => $langs->trans("BillStatusNotPaid"), '2' => $langs->trans("BillStatusPaid"));
341 print $form->selectarray('object_status', $liststatus, $object_status, 1);
342}
343print '</td></tr>';
344// Year
345print '<tr><td>'.$langs->trans("Year").'</td><td>';
346if (!in_array($year, $arrayyears)) {
347 $arrayyears[$year] = $year;
348}
349if (!in_array($nowyear, $arrayyears)) {
350 $arrayyears[$nowyear] = $nowyear;
351}
352arsort($arrayyears);
353print $form->selectarray('year', $arrayyears, $year, 0, 0, 0, '', 0, 0, 0, '', 'width75');
354print '</td></tr>';
355print '<tr><td class="center" colspan="2"><input type="submit" name="submit" class="button small" value="'.$langs->trans("Refresh").'"></td></tr>';
356print '</table>';
357print '</form>';
358print '<br><br>';
359
360print '<div class="div-table-responsive-no-min">';
361print '<table class="noborder centpercent">';
362print '<tr class="liste_titre" height="24">';
363print '<td class="center">'.$langs->trans("Year").'</td>';
364print '<td class="right">'.$langs->trans("NumberOfBills").'</td>';
365print '<td class="right">%</td>';
366print '<td class="right">'.$langs->trans("AmountTotal").'</td>';
367print '<td class="right">%</td>';
368print '<td class="right">'.$langs->trans("AmountAverage").'</td>';
369print '<td class="right">%</td>';
370print '</tr>';
371
372$oldyear = 0;
373foreach ($data as $val) {
374 $year = (int) $val['year'];
375 while ($year && $oldyear > $year + 1) { // If we have empty year
376 $oldyear--;
377
378 print '<tr class="oddeven" height="24">';
379 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>';
380 print '<td class="right">0</td>';
381 print '<td class="right"></td>';
382 print '<td class="right amount">0</td>';
383 print '<td class="right"></td>';
384 print '<td class="right amount">0</td>';
385 print '<td class="right"></td>';
386 print '</tr>';
387 }
388
389 if ($mode == 'supplier') {
390 $greennb = (empty($val['nb_diff']) || $val['nb_diff'] <= 0);
391 $greentotal = (empty($val['total_diff']) || $val['total_diff'] <= 0);
392 $greenavg = (empty($val['avg_diff']) || $val['avg_diff'] <= 0);
393 } else {
394 $greennb = (empty($val['nb_diff']) || $val['nb_diff'] >= 0);
395 $greentotal = (empty($val['total_diff']) || $val['total_diff'] >= 0);
396 $greenavg = (empty($val['avg_diff']) || $val['avg_diff'] >= 0);
397 }
398
399 print '<tr class="oddeven" height="24">';
400 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>';
401 print '<td class="right">'.$val['nb'].'</td>';
402 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>';
403 print '<td class="right"><span class="amount">'.price(price2num($val['total'], 'MT'), 1).'</span></td>';
404 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>';
405 print '<td class="right"><span class="amount">'.price(price2num($val['avg'], 'MT'), 1).'</span></td>';
406 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>';
407 print '</tr>';
408 $oldyear = $year;
409}
410
411print '</table>';
412print '</div>';
413
414print '</div><div class="fichetwothirdright">';
415
416
417// Show graphs
418print '<table class="border centpercent"><tr class="pair nohover"><td align="center">';
419if ($mesg) {
420 print $mesg;
421} else {
422 print $px1->show();
423 print "<br>\n";
424 print $px2->show();
425 print "<br>\n";
426 print $px3->show();
427}
428print '</td></tr></table>';
429
430
431print '</div></div>';
432print '<div class="clearboth"></div>';
433
434
435print dol_get_fiche_end();
436
437// End of page
438llxFooter();
439$db->close();
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:70
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.
Class permettant la generation de composants html autre Only common components are here.
llxFooter()
Footer empty.
Definition document.php:107
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
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)
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)
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_now($mode='auto')
Return date for now.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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).
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.