1<?php
2/* Copyright (C) 2001-2004	Rodolphe Quiedeville	<rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2020	Laurent Destailleur		<eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2017	Regis Houssin			<regis.houssin@inodbox.com>
5 * Copyright (C) 2011-2012	Juanjo Menent			<jmenent@2byte.es>
6 * Copyright (C) 2015		Marcos García			<marcosgdf@gmail.com>
7 * Copyright (C) 2021		Frédéric France			<frederic.france@netlogic.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
23/**
24 *	\file       htdocs/index.php
25 *	\brief      Dolibarr home page
26 */
27
28
29define('CSRFCHECK_WITH_TOKEN', 1);	// We force need to use a token to login when making a POST
30
31require 'main.inc.php';
32require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
33
34// If not defined, we select menu "home"
35$_GET['mainmenu'] = GETPOST('mainmenu', 'aZ09') ? GETPOST('mainmenu', 'aZ09') : 'home';
36$action = GETPOST('action', 'aZ09');
37
38$hookmanager->initHooks(array('index'));
39
40
41/*
42 * Actions
43 */
44
45// Check if company name is defined (first install)
46if (!isset($conf->global->MAIN_INFO_SOCIETE_NOM) || empty($conf->global->MAIN_INFO_SOCIETE_NOM)) {
47	header("Location: ".DOL_URL_ROOT."/admin/index.php?mainmenu=home&leftmenu=setup&mesg=setupnotcomplete");
48	exit;
49}
50if (count($conf->modules) <= (empty($conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING) ? 1 : $conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING)) {	// If only user module enabled
51	header("Location: ".DOL_URL_ROOT."/admin/index.php?mainmenu=home&leftmenu=setup&mesg=setupnotcomplete");
52	exit;
53}
54if (GETPOST('addbox')) {	// Add box (when submit is done from a form when ajax disabled)
55	require_once DOL_DOCUMENT_ROOT.'/core/class/infobox.class.php';
56	$zone = GETPOST('areacode', 'int');
57	$userid = GETPOST('userid', 'int');
58	$boxorder = GETPOST('boxorder', 'aZ09');
59	$boxorder .= GETPOST('boxcombo', 'aZ09');
60
61	$result = InfoBox::saveboxorder($db, $zone, $boxorder, $userid);
62	if ($result > 0) {
63		setEventMessages($langs->trans("BoxAdded"), null);
64	}
65}
66
67
68/*
69 * View
70 */
71
72if (!isset($form) || !is_object($form)) {
73	$form = new Form($db);
74}
75
76// Title
77$title = $langs->trans("HomeArea").' - Dolibarr '.DOL_VERSION;
78if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
79	$title = $langs->trans("HomeArea").' - '.$conf->global->MAIN_APPLICATION_TITLE;
80}
81
82llxHeader('', $title);
83
84
85$resultboxes = FormOther::getBoxesArea($user, "0"); // Load $resultboxes (selectboxlist + boxactivated + boxlista + boxlistb)
86
87
88print load_fiche_titre('&nbsp;', $resultboxes['selectboxlist'], '', 0, '', 'titleforhome');
89
90if (!empty($conf->global->MAIN_MOTD)) {
91	$conf->global->MAIN_MOTD = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', '<br>', $conf->global->MAIN_MOTD);
92	if (!empty($conf->global->MAIN_MOTD)) {
93		$substitutionarray = getCommonSubstitutionArray($langs);
94		complete_substitutions_array($substitutionarray, $langs);
95		$texttoshow = make_substitutions($conf->global->MAIN_MOTD, $substitutionarray, $langs);
96
97		print "\n<!-- Start of welcome text -->\n";
98		print '<table width="100%" class="notopnoleftnoright"><tr><td>';
99		print dol_htmlentitiesbr($texttoshow);
100		print '</td></tr></table><br>';
101		print "\n<!-- End of welcome text -->\n";
102	}
103}
104
105/*
106 * Show security warnings
107 */
108
109// Security warning repertoire install existe (si utilisateur admin)
110if ($user->admin && empty($conf->global->MAIN_REMOVE_INSTALL_WARNING)) {
111	$message = '';
112
113	// Check if install lock file is present
114	$lockfile = DOL_DATA_ROOT.'/install.lock';
115	if (!empty($lockfile) && !file_exists($lockfile) && is_dir(DOL_DOCUMENT_ROOT."/install")) {
116		$langs->load("errors");
117		//if (! empty($message)) $message.='<br>';
118		$message .= info_admin($langs->trans("WarningLockFileDoesNotExists", DOL_DATA_ROOT).' '.$langs->trans("WarningUntilDirRemoved", DOL_DOCUMENT_ROOT."/install"), 0, 0, '1', 'clearboth');
119	}
120
121	// Conf files must be in read only mode
122	if (is_writable($conffile)) {
123		$langs->load("errors");
124		//$langs->load("other");
125		//if (! empty($message)) $message.='<br>';
126		$message .= info_admin($langs->transnoentities("WarningConfFileMustBeReadOnly").' '.$langs->trans("WarningUntilDirRemoved", DOL_DOCUMENT_ROOT."/install"), 0, 0, '1', 'clearboth');
127	}
128
129	if ($message) {
130		print $message;
131		//$message.='<br>';
132		//print info_admin($langs->trans("WarningUntilDirRemoved",DOL_DOCUMENT_ROOT."/install"));
133	}
134}
135
136/*
137 * Dashboard Dolibarr states (statistics)
138 * Hidden for external users
139 */
140
141$boxstatItems = array();
142$boxstatFromHook = '';
143
144// Load translation files required by page
145$langs->loadLangs(array('commercial', 'bills', 'orders', 'contracts'));
146
147// Dolibarr Working Board with weather
148
149if (empty($conf->global->MAIN_DISABLE_GLOBAL_WORKBOARD)) {
150	$showweather = (empty($conf->global->MAIN_DISABLE_METEO) || $conf->global->MAIN_DISABLE_METEO == 2) ? 1 : 0;
151
152	//Array that contains all WorkboardResponse classes to process them
153	$dashboardlines = array();
154
155	// Do not include sections without management permission
156	require_once DOL_DOCUMENT_ROOT.'/core/class/workboardresponse.class.php';
157
158	// Number of actions to do (late)
159	if (!empty($conf->agenda->enabled) && $user->rights->agenda->myactions->read) {
160		include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
161		$board = new ActionComm($db);
162		$dashboardlines[$board->element] = $board->load_board($user);
163	}
164
165	// Number of project opened
166	if (!empty($conf->projet->enabled) && $user->rights->projet->lire) {
167		include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
168		$board = new Project($db);
169		$dashboardlines[$board->element] = $board->load_board($user);
170	}
171
172	// Number of tasks to do (late)
173	if (!empty($conf->projet->enabled) && empty($conf->global->PROJECT_HIDE_TASKS) && $user->rights->projet->lire) {
174		include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
175		$board = new Task($db);
176		$dashboardlines[$board->element] = $board->load_board($user);
177	}
178
179	// Number of commercial proposals open (expired)
180	if (!empty($conf->propal->enabled) && $user->rights->propale->lire) {
181		include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
182		$board = new Propal($db);
183		$dashboardlines[$board->element.'_opened'] = $board->load_board($user, "opened");
184		// Number of commercial proposals CLOSED signed (billed)
185		$dashboardlines[$board->element.'_signed'] = $board->load_board($user, "signed");
186	}
187
188	// Number of commercial proposals open (expired)
189	if (!empty($conf->supplier_proposal->enabled) && $user->rights->supplier_proposal->lire) {
190		include_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
191		$board = new SupplierProposal($db);
192		$dashboardlines[$board->element.'_opened'] = $board->load_board($user, "opened");
193		// Number of commercial proposals CLOSED signed (billed)
194		$dashboardlines[$board->element.'_signed'] = $board->load_board($user, "signed");
195	}
196
197	// Number of customer orders a deal
198	if (!empty($conf->commande->enabled) && $user->rights->commande->lire) {
199		include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
200		$board = new Commande($db);
201		$dashboardlines[$board->element] = $board->load_board($user);
202	}
203
204	// Number of suppliers orders a deal
205	if (!empty($conf->supplier_order->enabled) && $user->rights->fournisseur->commande->lire) {
206		include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
207		$board = new CommandeFournisseur($db);
208		$dashboardlines[$board->element.'_opened'] = $board->load_board($user, "opened");
209		$dashboardlines[$board->element.'_awaiting'] = $board->load_board($user, 'awaiting');
210	}
211
212	// Number of contract / services enabled (delayed)
213	if (!empty($conf->contrat->enabled) && $user->rights->contrat->lire) {
214		include_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
215		$board = new Contrat($db);
216		$dashboardlines[$board->element.'_inactive'] = $board->load_board($user, "inactive");
217		// Number of active services (expired)
218		$dashboardlines[$board->element.'_active'] = $board->load_board($user, "active");
219	}
220
221	// Number of tickets open
222	if (!empty($conf->ticket->enabled) && $user->rights->ticket->read) {
223		include_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
224		$board = new Ticket($db);
225		$dashboardlines[$board->element.'_opened'] = $board->load_board($user, "opened");
226		// Number of active services (expired)
227		//$dashboardlines[$board->element.'_active'] = $board->load_board($user, "active");
228	}
229
230	// Number of invoices customers (paid)
231	if (!empty($conf->facture->enabled) && $user->rights->facture->lire) {
232		include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
233		$board = new Facture($db);
234		$dashboardlines[$board->element] = $board->load_board($user);
235	}
236
237	// Number of supplier invoices (paid)
238	if (!empty($conf->supplier_invoice->enabled) && !empty($user->rights->fournisseur->facture->lire)) {
239		include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
240		$board = new FactureFournisseur($db);
241		$dashboardlines[$board->element] = $board->load_board($user);
242	}
243
244	// Number of transactions to conciliate
245	if (!empty($conf->banque->enabled) && $user->rights->banque->lire && !$user->socid) {
246		include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
247		$board = new Account($db);
248		$nb = $board->countAccountToReconcile(); // Get nb of account to reconciliate
249		if ($nb > 0) {
250			$dashboardlines[$board->element] = $board->load_board($user);
251		}
252	}
253
254	// Number of cheque to send
255	if (!empty($conf->banque->enabled) && $user->rights->banque->lire && !$user->socid && empty($conf->global->BANK_DISABLE_CHECK_DEPOSIT)) {
256		include_once DOL_DOCUMENT_ROOT.'/compta/paiement/cheque/class/remisecheque.class.php';
257		$board = new RemiseCheque($db);
258		$dashboardlines[$board->element] = $board->load_board($user);
259	}
260
261	// Number of foundation members
262	if (!empty($conf->adherent->enabled) && $user->rights->adherent->lire && !$user->socid) {
263		include_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
264		$board = new Adherent($db);
265		$dashboardlines[$board->element.'_shift'] = $board->load_board($user, 'shift');
266		$dashboardlines[$board->element.'_expired'] = $board->load_board($user, 'expired');
267	}
268
269	// Number of expense reports to approve
270	if (!empty($conf->expensereport->enabled) && $user->rights->expensereport->approve) {
271		include_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
272		$board = new ExpenseReport($db);
273		$dashboardlines[$board->element.'_toapprove'] = $board->load_board($user, 'toapprove');
274	}
275
276	// Number of expense reports to pay
277	if (!empty($conf->expensereport->enabled) && $user->rights->expensereport->to_paid) {
278		include_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
279		$board = new ExpenseReport($db);
280		$dashboardlines[$board->element.'_topay'] = $board->load_board($user, 'topay');
281	}
282
283	// Number of holidays to approve
284	if (!empty($conf->holiday->enabled) && $user->rights->holiday->approve) {
285		include_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
286		$board = new Holiday($db);
287		$dashboardlines[$board->element] = $board->load_board($user);
288	}
289
290	$object = new stdClass();
291	$parameters = array();
292	$action = '';
293	$reshook = $hookmanager->executeHooks(
294		'addOpenElementsDashboardLine',
295		$parameters,
296		$object,
297		$action
298	); // Note that $action and $object may have been modified by some hooks
299	if ($reshook == 0) {
300		$dashboardlines = array_merge($dashboardlines, $hookmanager->resArray);
301	}
302
303	/* Open object dashboard */
304	$dashboardgroup = array(
305		'action' =>
306			array(
307				'groupName' => 'Agenda',
308				'stats' => array('action'),
309			),
310		'project' =>
311			array(
312				'groupName' => 'Projects',
313				'globalStatsKey' => 'projects',
314				'stats' => array('project', 'project_task'),
315			),
316		'propal' =>
317			array(
318				'groupName' => 'Proposals',
319				'globalStatsKey' => 'proposals',
320				'stats' =>
321					array('propal_opened', 'propal_signed'),
322			),
323		'commande' =>
324			array(
325				'groupName' => 'Orders',
326				'globalStatsKey' => 'orders',
327				'stats' =>
328					array('commande'),
329			),
330		'facture' =>
331			array(
332				'groupName' => 'Invoices',
333				'globalStatsKey' => 'invoices',
334				'stats' =>
335					array('facture'),
336			),
337		'supplier_proposal' =>
338			array(
339				'lang' => 'supplier_proposal',
340				'groupName' => 'SupplierProposals',
341				'globalStatsKey' => 'askprice',
342				'stats' =>
343					array('supplier_proposal_opened', 'supplier_proposal_signed'),
344			),
345		'order_supplier' =>
346			array(
347				'groupName' => 'SuppliersOrders',
348				'globalStatsKey' => 'supplier_orders',
349				'stats' =>
350					array('order_supplier_opened', 'order_supplier_awaiting'),
351			),
352		'invoice_supplier' =>
353			array(
354				'groupName' => 'BillsSuppliers',
355				'globalStatsKey' => 'supplier_invoices',
356				'stats' =>
357					array('invoice_supplier'),
358			),
359		'contrat' =>
360			array(
361				'groupName' => 'Contracts',
362				'globalStatsKey' => 'Contracts',
363				'stats' =>
364				array('contrat_inactive', 'contrat_active'),
365			),
366		'ticket' =>
367			array(
368				'groupName' => 'Tickets',
369				'globalStatsKey' => 'ticket',
370				'stats' =>
371					array('ticket_opened'),
372			),
373		'bank_account' =>
374			array(
375				'groupName' => 'BankAccount',
376				'stats' =>
377					array('bank_account', 'chequereceipt'),
378			),
379		'member' =>
380			array(
381				'groupName' => 'Members',
382				'globalStatsKey' => 'members',
383				'stats' =>
384					array('member_shift', 'member_expired'),
385			),
386		'expensereport' =>
387			array(
388				'groupName' => 'ExpenseReport',
389				'globalStatsKey' => 'expensereports',
390				'stats' =>
391					array('expensereport_toapprove', 'expensereport_topay'),
392			),
393		'holiday' =>
394			array(
395				'groupName' => 'Holidays',
396				'globalStatsKey' => 'holidays',
397				'stats' =>
398					array('holiday'),
399			),
400	);
401
402	$object = new stdClass();
403	$parameters = array(
404		'dashboardgroup' => $dashboardgroup
405	);
406	$reshook = $hookmanager->executeHooks('addOpenElementsDashboardGroup', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
407	if ($reshook == 0) {
408		$dashboardgroup = array_merge($dashboardgroup, $hookmanager->resArray);
409	}
410
411
412	// Calculate total nb of late
413	$totallate = $totaltodo = 0;
414
415	//Remove any invalid response
416	//load_board can return an integer if failed or WorkboardResponse if OK
417	$valid_dashboardlines = array();
418	foreach ($dashboardlines as $workboardid => $tmp) {
419		if ($tmp instanceof WorkboardResponse) {
420			$tmp->id = $workboardid; // Complete the object to add its id into its name
421			$valid_dashboardlines[$workboardid] = $tmp;
422		}
423	}
424
425	// We calculate $totallate. Must be defined before start of next loop because it is show in first fetch on next loop
426	foreach ($valid_dashboardlines as $board) {
427		if ($board->nbtodolate > 0) {
428			$totaltodo += $board->nbtodo;
429			$totallate += $board->nbtodolate;
430		}
431	}
432
433	$openedDashBoardSize = 'info-box-sm'; // use sm by default
434	foreach ($dashboardgroup as $dashbordelement) {
435		if (is_array($dashbordelement['stats']) && count($dashbordelement['stats']) > 2) {
436			$openedDashBoardSize = ''; // use default info box size : big
437			break;
438		}
439	}
440
441	$totalLateNumber = $totallate;
442	$totallatePercentage = ((!empty($totaltodo)) ? round($totallate / $totaltodo * 100, 2) : 0);
443	if (!empty($conf->global->MAIN_USE_METEO_WITH_PERCENTAGE)) {
444		$totallate = $totallatePercentage;
445	}
446
447	$boxwork = '';
448	$boxwork .= '<div class="box">';
449	$boxwork .= '<table summary="'.dol_escape_htmltag($langs->trans("WorkingBoard")).'" class="noborder boxtable boxtablenobottom boxworkingboard centpercent">'."\n";
450	$boxwork .= '<tr class="liste_titre">';
451	$boxwork .= '<th class="liste_titre"><div class="inline-block valignmiddle">'.$langs->trans("DolibarrWorkBoard").'</div>';
452	if ($showweather) {
453		if ($totallate > 0) {
454			$text = $langs->transnoentitiesnoconv("WarningYouHaveAtLeastOneTaskLate").' ('.$langs->transnoentitiesnoconv(
455				"NActionsLate",
456				$totallate.(!empty($conf->global->MAIN_USE_METEO_WITH_PERCENTAGE) ? '%' : '')
457			).')';
458		} else {
459			$text = $langs->transnoentitiesnoconv("NoItemLate");
460		}
461		$text .= '. '.$langs->transnoentitiesnoconv("LateDesc");
462		//$text.=$form->textwithpicto('',$langs->trans("LateDesc"));
463		$options = 'height="24px" style="float: right"';
464		$boxwork .= showWeather($totallate, $text, $options, 'inline-block valignmiddle');
465	}
466	$boxwork .= '</th>';
467	$boxwork .= '</tr>'."\n";
468
469	// Show dashboard
470	$nbworkboardempty = 0;
471	$isIntopOpenedDashBoard = $globalStatInTopOpenedDashBoard = array();
472	if (!empty($valid_dashboardlines)) {
473		$openedDashBoard = '';
474
475		$boxwork .= '<tr class="nobottom nohover"><td class="tdboxstats nohover flexcontainer centpercent"><div style="display: flex: flex-wrap: wrap">';
476
477		foreach ($dashboardgroup as $groupKey => $groupElement) {
478			$boards = array();
479			if (empty($conf->global->MAIN_DISABLE_NEW_OPENED_DASH_BOARD)) {
480				foreach ($groupElement['stats'] as $infoKey) {
481					if (!empty($valid_dashboardlines[$infoKey])) {
482						$boards[] = $valid_dashboardlines[$infoKey];
483						$isIntopOpenedDashBoard[] = $infoKey;
484					}
485				}
486			}
487
488			if (!empty($boards)) {
489				if (!empty($groupElement['lang'])) {
490					$langs->load($groupElement['lang']);
491				}
492				$groupName = $langs->trans($groupElement['groupName']);
493				$groupKeyLowerCase = strtolower($groupKey);
494				$nbTotalForGroup = 0;
495
496				// global stats
497				$globalStatsKey = false;
498				if (!empty($groupElement['globalStatsKey']) && empty($groupElement['globalStats'])) { // can be filled by hook
499					$globalStatsKey = $groupElement['globalStatsKey'];
500					$groupElement['globalStats'] = array();
501
502					if (isset($keys) && is_array($keys) && in_array($globalStatsKey, $keys)) {
503						// get key index of stats used in $includes, $classes, $keys, $icons, $titres, $links
504						$keyIndex = array_search($globalStatsKey, $keys);
505
506						$classe = (!empty($classes[$keyIndex]) ? $classes[$keyIndex] : '');
507						if (isset($boardloaded[$classe]) && is_object($boardloaded[$classe])) {
508							$groupElement['globalStats']['total'] = $boardloaded[$classe]->nb[$globalStatsKey] ? $boardloaded[$classe]->nb[$globalStatsKey] : 0;
509							$nbTotal = floatval($groupElement['globalStats']['total']);
510							if ($nbTotal >= 10000) {
511								$nbTotal = round($nbTotal / 1000, 2).'k';
512							}
513							$groupElement['globalStats']['text'] = $langs->trans('Total').' : '.$langs->trans($titres[$keyIndex]).' ('.$groupElement['globalStats']['total'].')';
514							$groupElement['globalStats']['total'] = $nbTotal;
515							$groupElement['globalStats']['link'] = $links[$keyIndex];
516						}
517					}
518				}
519
520				$openedDashBoard .= '<div class="box-flex-item"><div class="box-flex-item-with-margin">'."\n";
521				$openedDashBoard .= '	<div class="info-box '.$openedDashBoardSize.'">'."\n";
522				$openedDashBoard .= '		<span class="info-box-icon bg-infobox-'.$groupKeyLowerCase.'">'."\n";
523				$openedDashBoard .= '		<i class="fa fa-dol-'.$groupKeyLowerCase.'"></i>'."\n";
524
525				// Show the span for the total of record
526				if (!empty($groupElement['globalStats'])) {
527					$globalStatInTopOpenedDashBoard[] = $globalStatsKey;
528					$openedDashBoard .= '<span class="info-box-icon-text" title="'.$groupElement['globalStats']['text'].'">'.$nbTotal.'</span>';
529				}
530
531				$openedDashBoard .= '</span>'."\n";
532				$openedDashBoard .= '<div class="info-box-content">'."\n";
533
534				$openedDashBoard .= '<div class="info-box-title" title="'.strip_tags($groupName).'">'.$groupName.'</div>'."\n";
535				$openedDashBoard .= '<div class="info-box-lines">'."\n";
536
537				foreach ($boards as $board) {
538					$openedDashBoard .= '<div class="info-box-line">';
539
540					if (!empty($board->labelShort)) {
541						$infoName = '<span title="'.$board->label.'">'.$board->labelShort.'</span>';
542					} else {
543						$infoName = $board->label;
544					}
545
546					$textLateTitle = $langs->trans("NActionsLate", $board->nbtodolate);
547					$textLateTitle .= ' ('.$langs->trans("Late").' = '.$langs->trans("DateReference").' > '.$langs->trans("DateToday").' '.(ceil($board->warning_delay) >= 0 ? '+' : '').ceil($board->warning_delay).' '.$langs->trans("days").')';
548
549					if ($board->id == 'bank_account') {
550						$textLateTitle .= '<br><span class="opacitymedium">'.$langs->trans("IfYouDontReconcileDisableProperty", $langs->transnoentitiesnoconv("Conciliable")).'</span>';
551					}
552
553					$textLate = '';
554					if ($board->nbtodolate > 0) {
555						$textLate .= '<span title="'.dol_escape_htmltag($textLateTitle).'" class="classfortooltip badge badge-warning">';
556						$textLate .= '<i class="fa fa-exclamation-triangle"></i> '.$board->nbtodolate;
557						$textLate .= '</span>';
558					}
559
560					$nbtodClass = '';
561					if ($board->nbtodo > 0) {
562						$nbtodClass = 'badge badge-info';
563					}
564
565					$openedDashBoard .= '			<a href="'.$board->url.'" class="info-box-text info-box-text-a">'.$infoName.' : <span class="'.$nbtodClass.' classfortooltip" title="'.$board->label.'" >'.$board->nbtodo.'</span>';
566					if ($textLate) {
567						if ($board->url_late) {
568							$openedDashBoard .= '</a>';
569							$openedDashBoard .= ' <a href="'.$board->url_late.'" class="info-box-text info-box-text-a paddingleft">';
570						} else {
571							$openedDashBoard .= ' ';
572						}
573						$openedDashBoard .= $textLate;
574					}
575					$openedDashBoard .= '</a>'."\n";
576
577					if ($board->total > 0 && !empty($conf->global->MAIN_WORKBOARD_SHOW_TOTAL_WO_TAX)) {
578						$openedDashBoard .= '<a href="'.$board->url.'" class="info-box-text">'.$langs->trans('Total').' : '.price($board->total).'</a>';
579					}
580					$openedDashBoard .= '</div>'."\n";
581				}
582
583				// TODO Add hook here to add more "info-box-line"
584
585				$openedDashBoard .= '		</div><!-- /.info-box-lines --></div><!-- /.info-box-content -->'."\n";
586				$openedDashBoard .= '	</div><!-- /.info-box -->'."\n";
587				$openedDashBoard .= '</div><!-- /.box-flex-item-with-margin -->'."\n";
588				$openedDashBoard .= '</div><!-- /.box-flex-item -->'."\n";
589				$openedDashBoard .= "\n";
590			}
591		}
592
593		if ($showweather && !empty($isIntopOpenedDashBoard)) {
594			$appendClass = (!empty($conf->global->MAIN_DISABLE_METEO) && $conf->global->MAIN_DISABLE_METEO == 2 ? ' hideonsmartphone' : '');
595			$weather = getWeatherStatus($totallate);
596
597			$text = '';
598			if ($totallate > 0) {
599				$text = $langs->transnoentitiesnoconv("WarningYouHaveAtLeastOneTaskLate").' ('.$langs->transnoentitiesnoconv(
600					"NActionsLate",
601					$totallate.(!empty($conf->global->MAIN_USE_METEO_WITH_PERCENTAGE) ? '%' : '')
602				).')';
603			} else {
604				$text = $langs->transnoentitiesnoconv("NoItemLate");
605			}
606			$text .= '. '.$langs->transnoentitiesnoconv("LateDesc");
607
608			$weatherDashBoard = '<div class="box-flex-item '.$appendClass.'"><div class="box-flex-item-with-margin">'."\n";
609			$weatherDashBoard .= '	<div class="info-box '.$openedDashBoardSize.' info-box-weather info-box-weather-level'.$weather->level.'">'."\n";
610			$weatherDashBoard .= '		<span class="info-box-icon">';
611			$weatherDashBoard .= img_weather('', $weather->level, '', 0, 'valignmiddle width50');
612			$weatherDashBoard .= '       </span>'."\n";
613			$weatherDashBoard .= '		<div class="info-box-content">'."\n";
614			$weatherDashBoard .= '			<div class="info-box-title">'.$langs->trans('GlobalOpenedElemView').'</div>'."\n";
615
616			if ($totallatePercentage > 0 && !empty($conf->global->MAIN_USE_METEO_WITH_PERCENTAGE)) {
617				$weatherDashBoard .= '			<span class="info-box-number">'.$langs->transnoentitiesnoconv(
618					"NActionsLate",
619					price($totallatePercentage).'%'
620				).'</span>'."\n";
621				$weatherDashBoard .= '			<span class="progress-description">'.$langs->trans(
622					'NActionsLate',
623					$totalLateNumber
624				).'</span>'."\n";
625			} else {
626				$weatherDashBoard .= '			<span class="info-box-number">'.$langs->transnoentitiesnoconv(
627					"NActionsLate",
628					$totalLateNumber
629				).'</span>'."\n";
630				if ($totallatePercentage > 0) {
631					$weatherDashBoard .= '			<span class="progress-description">'.$langs->trans(
632						'NActionsLate',
633						price($totallatePercentage).'%'
634					).'</span>'."\n";
635				}
636			}
637
638			$weatherDashBoard .= '		</div><!-- /.info-box-content -->'."\n";
639			$weatherDashBoard .= '	</div><!-- /.info-box -->'."\n";
640			$weatherDashBoard .= '</div><!-- /.box-flex-item-with-margin -->'."\n";
641			$weatherDashBoard .= '</div><!-- /.box-flex-item -->'."\n";
642			$weatherDashBoard .= "\n";
643
644			$openedDashBoard = $weatherDashBoard.$openedDashBoard;
645		}
646
647		if (!empty($isIntopOpenedDashBoard)) {
648			for ($i = 1; $i <= 10; $i++) {
649				$openedDashBoard .= '<div class="box-flex-item filler"></div>';
650			}
651		}
652
653		$nbworkboardcount = 0;
654		foreach ($valid_dashboardlines as $infoKey => $board) {
655			if (in_array($infoKey, $isIntopOpenedDashBoard)) {
656				// skip if info is present on top
657				continue;
658			}
659
660			if (empty($board->nbtodo)) {
661				$nbworkboardempty++;
662			}
663			$nbworkboardcount++;
664
665
666			$textlate = $langs->trans("NActionsLate", $board->nbtodolate);
667			$textlate .= ' ('.$langs->trans("Late").' = '.$langs->trans("DateReference").' > '.$langs->trans("DateToday").' '.(ceil($board->warning_delay) >= 0 ? '+' : '').ceil($board->warning_delay).' '.$langs->trans("days").')';
668
669
670			$boxwork .= '<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats130 boxstatsborder">';
671			$boxwork .= '<div class="boxstatscontent">';
672			$boxwork .= '<span class="boxstatstext" title="'.dol_escape_htmltag($board->label).'">'.$board->img.' <span>'.$board->label.'</span></span><br>';
673			$boxwork .= '<a class="valignmiddle dashboardlineindicator" href="'.$board->url.'"><span class="dashboardlineindicator'.(($board->nbtodo == 0) ? ' dashboardlineok' : '').'">'.$board->nbtodo.'</span></a>';
674			if ($board->total > 0 && !empty($conf->global->MAIN_WORKBOARD_SHOW_TOTAL_WO_TAX)) {
675				$boxwork .= '&nbsp;/&nbsp;<a class="valignmiddle dashboardlineindicator" href="'.$board->url.'"><span class="dashboardlineindicator'.(($board->nbtodo == 0) ? ' dashboardlineok' : '').'">'.price($board->total).'</span></a>';
676			}
677			$boxwork .= '</div>';
678			if ($board->nbtodolate > 0) {
679				$boxwork .= '<div class="dashboardlinelatecoin nowrap">';
680				$boxwork .= '<a title="'.dol_escape_htmltag($textlate).'" class="valignmiddle dashboardlineindicatorlate'.($board->nbtodolate > 0 ? ' dashboardlineko' : ' dashboardlineok').'" href="'.((!$board->url_late) ? $board->url : $board->url_late).'">';
681				//$boxwork .= img_picto($textlate, "warning_white", 'class="valigntextbottom"').'';
682				$boxwork .= img_picto(
683					$textlate,
684					"warning_white",
685					'class="inline-block hideonsmartphone valigntextbottom"'
686				).'';
687				$boxwork .= '<span class="dashboardlineindicatorlate'.($board->nbtodolate > 0 ? ' dashboardlineko' : ' dashboardlineok').'">';
688				$boxwork .= $board->nbtodolate;
689				$boxwork .= '</span>';
690				$boxwork .= '</a>';
691				$boxwork .= '</div>';
692			}
693			$boxwork .= '</div></div>';
694			$boxwork .= "\n";
695		}
696
697		$boxwork .= '<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
698		$boxwork .= '<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
699		$boxwork .= '<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
700		$boxwork .= '<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
701
702		$boxwork .= '</div>';
703		$boxwork .= '</td></tr>';
704	} else {
705		$boxwork .= '<tr class="nohover">';
706		$boxwork .= '<td class="nohover valignmiddle opacitymedium">';
707		$boxwork .= $langs->trans("NoOpenedElementToProcess");
708		$boxwork .= '</td>';
709		$boxwork .= '</tr>';
710	}
711
712	$boxwork .= '</td></tr>';
713
714	$boxwork .= '</table>'; // End table array of working board
715	$boxwork .= '</div>';
716
717	if (!empty($isIntopOpenedDashBoard)) {
718		print '<div class="fichecenter">';
719		print '<div class="opened-dash-board-wrap"><div class="box-flex-container">'.$openedDashBoard.'</div></div>';
720		print '</div>';
721	}
722}
723
724
725print '<div class="clearboth"></div>';
726
727print '<div class="fichecenter fichecenterbis">';
728
729
730/*
731 * Show widgets (boxes)
732 */
733
734$boxlist = '<div class="twocolumns">';
735
736$boxlist .= '<div class="firstcolumn fichehalfleft boxhalfleft" id="boxhalfleft">';
737if (!empty($nbworkboardcount)) {
738	$boxlist .= $boxwork;
739}
740
741$boxlist .= $resultboxes['boxlista'];
742
743$boxlist .= '</div>';
744
745$boxlist .= '<div class="secondcolumn fichehalfright boxhalfright" id="boxhalfright">';
746
747$boxlist .= $resultboxes['boxlistb'];
748
749$boxlist .= '</div>';
750$boxlist .= "\n";
751
752$boxlist .= '</div>';
753
754
755print $boxlist;
756
757print '</div>';
758
759//print 'mem='.memory_get_usage().' - '.memory_get_peak_usage();
760
761// End of page
762llxFooter();
763$db->close();
764
765
766/**
767 *  Show weather logo. Logo to show depends on $totallate and values for
768 *  $conf->global->MAIN_METEO_LEVELx
769 *
770 *  @param      int     $totallate      Nb of element late
771 *  @param      string  $text           Text to show on logo
772 *  @param      string  $options        More parameters on img tag
773 *  @param      string  $morecss        More CSS
774 *  @return     string                  Return img tag of weather
775 */
776function showWeather($totallate, $text, $options, $morecss = '')
777{
778	global $conf;
779
780	$weather = getWeatherStatus($totallate);
781	return img_weather($text, $weather->picto, $options, 0, $morecss);
782}
783
784
785/**
786 *  get weather level
787 *  $conf->global->MAIN_METEO_LEVELx
788 *
789 *  @param      int     $totallate      Nb of element late
790 *  @return     stdClass                Return img tag of weather
791 */
792function getWeatherStatus($totallate)
793{
794	global $conf;
795
796	$weather = new stdClass();
797	$weather->picto = '';
798
799	$offset = 0;
800	$factor = 10; // By default
801
802	$used_conf = empty($conf->global->MAIN_USE_METEO_WITH_PERCENTAGE) ? 'MAIN_METEO_LEVEL' : 'MAIN_METEO_PERCENTAGE_LEVEL';
803
804	$level0 = $offset;
805	$weather->level = 0;
806	if (!empty($conf->global->{$used_conf.'0'})) {
807		$level0 = $conf->global->{$used_conf.'0'};
808	}
809	$level1 = $offset + 1 * $factor;
810	if (!empty($conf->global->{$used_conf.'1'})) {
811		$level1 = $conf->global->{$used_conf.'1'};
812	}
813	$level2 = $offset + 2 * $factor;
814	if (!empty($conf->global->{$used_conf.'2'})) {
815		$level2 = $conf->global->{$used_conf.'2'};
816	}
817	$level3 = $offset + 3 * $factor;
818	if (!empty($conf->global->{$used_conf.'3'})) {
819		$level3 = $conf->global->{$used_conf.'3'};
820	}
821
822	if ($totallate <= $level0) {
823		$weather->picto = 'weather-clear.png';
824		$weather->level = 0;
825	} elseif ($totallate <= $level1) {
826		$weather->picto = 'weather-few-clouds.png';
827		$weather->level = 1;
828	} elseif ($totallate <= $level2) {
829		$weather->picto = 'weather-clouds.png';
830		$weather->level = 2;
831	} elseif ($totallate <= $level3) {
832		$weather->picto = 'weather-many-clouds.png';
833		$weather->level = 3;
834	} else {
835		$weather->picto = 'weather-storm.png';
836		$weather->level = 4;
837	}
838
839	return $weather;
840}
841