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(' ', $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 .= ' / <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