1<?php 2/* Copyright (C) 2006-2015 Laurent Destailleur <eldy@users.sourceforge.net> 3 * Copyright (C) 2010 Regis Houssin <regis.houssin@inodbox.com> 4 * Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es> 5 * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <https://www.gnu.org/licenses/>. 19 * or see https://www.gnu.org/ 20 */ 21 22/** 23 * \file htdocs/core/lib/project.lib.php 24 * \brief Functions used by project module 25 * \ingroup project 26 */ 27require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; 28 29 30/** 31 * Prepare array with list of tabs 32 * 33 * @param Project $project Object related to tabs 34 * @param string $moreparam More param on url 35 * @return array Array of tabs to show 36 */ 37function project_prepare_head(Project $project, $moreparam = '') 38{ 39 global $db, $langs, $conf, $user; 40 41 $h = 0; 42 $head = array(); 43 44 $head[$h][0] = DOL_URL_ROOT.'/projet/card.php?id='.((int) $project->id).($moreparam ? '&'.$moreparam : ''); 45 $head[$h][1] = $langs->trans("Project"); 46 $head[$h][2] = 'project'; 47 $h++; 48 $nbContacts = 0; 49 // Enable caching of project count Contacts 50 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php'; 51 $cachekey = 'count_contacts_project_'.$project->id; 52 $dataretrieved = dol_getcache($cachekey); 53 54 if (!is_null($dataretrieved)) { 55 $nbContacts = $dataretrieved; 56 } else { 57 $nbContacts = count($project->liste_contact(-1, 'internal')) + count($project->liste_contact(-1, 'external')); 58 dol_setcache($cachekey, $nbContacts, 120); // If setting cache fails, this is not a problem, so we do not test result. 59 } 60 $head[$h][0] = DOL_URL_ROOT.'/projet/contact.php?id='.((int) $project->id).($moreparam ? '&'.$moreparam : ''); 61 $head[$h][1] = $langs->trans("ProjectContact"); 62 if ($nbContacts > 0) { 63 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbContacts.'</span>'; 64 } 65 $head[$h][2] = 'contact'; 66 $h++; 67 68 if (empty($conf->global->PROJECT_HIDE_TASKS)) { 69 // Then tab for sub level of projet, i mean tasks 70 $nbTasks = 0; 71 // Enable caching of project count Tasks 72 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php'; 73 $cachekey = 'count_tasks_project_'.$project->id; 74 $dataretrieved = dol_getcache($cachekey); 75 76 if (!is_null($dataretrieved)) { 77 $nbTasks = $dataretrieved; 78 } else { 79 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; 80 $taskstatic = new Task($db); 81 $nbTasks = count($taskstatic->getTasksArray(0, 0, $project->id, 0, 0)); 82 dol_setcache($cachekey, $nbTasks, 120); // If setting cache fails, this is not a problem, so we do not test result. 83 } 84 $head[$h][0] = DOL_URL_ROOT.'/projet/tasks.php?id='.((int) $project->id).($moreparam ? '&'.$moreparam : ''); 85 $head[$h][1] = $langs->trans("Tasks"); 86 if ($nbTasks > 0) { 87 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbTasks).'</span>'; 88 } 89 $head[$h][2] = 'tasks'; 90 $h++; 91 92 $nbTimeSpent = 0; 93 // Enable caching of project count Timespent 94 $cachekey = 'count_timespent_project_'.$project->id; 95 $dataretrieved = dol_getcache($cachekey); 96 if (!is_null($dataretrieved)) { 97 $nbTimeSpent = $dataretrieved; 98 } else { 99 $sql = "SELECT t.rowid"; 100 //$sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."user as u"; 101 //$sql .= " WHERE t.fk_user = u.rowid AND t.fk_task = pt.rowid"; 102 $sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t, ".MAIN_DB_PREFIX."projet_task as pt"; 103 $sql .= " WHERE t.fk_task = pt.rowid"; 104 $sql .= " AND pt.fk_projet =".((int) $project->id); 105 $resql = $db->query($sql); 106 if ($resql) { 107 $obj = $db->fetch_object($resql); 108 if ($obj) { 109 $nbTimeSpent = 1; 110 dol_setcache($cachekey, $nbTimeSpent, 120); // If setting cache fails, this is not a problem, so we do not test result. 111 } 112 } else { 113 dol_print_error($db); 114 } 115 } 116 117 $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/time.php?withproject=1&projectid='.((int) $project->id).($moreparam ? '&'.$moreparam : ''); 118 $head[$h][1] = $langs->trans("TimeSpent"); 119 if ($nbTimeSpent > 0) { 120 $head[$h][1] .= '<span class="badge marginleftonlyshort">...</span>'; 121 } 122 $head[$h][2] = 'timespent'; 123 $h++; 124 } 125 126 if (((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled)) 127 || !empty($conf->propal->enabled) || !empty($conf->commande->enabled) 128 || !empty($conf->facture->enabled) || !empty($conf->contrat->enabled) 129 || !empty($conf->ficheinter->enabled) || !empty($conf->agenda->enabled) || !empty($conf->deplacement->enabled) || !empty($conf->stock->enabled)) { 130 $nbElements = 0; 131 // Enable caching of thirdrparty count Contacts 132 $cachekey = 'count_elements_project_'.$project->id; 133 $dataretrieved = dol_getcache($cachekey); 134 if (!is_null($dataretrieved)) { 135 $nbElements = $dataretrieved; 136 } else { 137 if (!empty($conf->stock->enabled)) { 138 $nbElements += $project->getElementCount('stock', 'entrepot', 'fk_project'); 139 } 140 if (!empty($conf->propal->enabled)) { 141 $nbElements += $project->getElementCount('propal', 'propal'); 142 } 143 if (!empty($conf->commande->enabled)) { 144 $nbElements += $project->getElementCount('order', 'commande'); 145 } 146 if (!empty($conf->facture->enabled)) { 147 $nbElements += $project->getElementCount('invoice', 'facture'); 148 } 149 if (!empty($conf->facture->enabled)) { 150 $nbElements += $project->getElementCount('invoice_predefined', 'facture_rec'); 151 } 152 if (!empty($conf->supplier_proposal->enabled)) { 153 $nbElements += $project->getElementCount('proposal_supplier', 'supplier_proposal'); 154 } 155 if (!empty($conf->supplier_order->enabled)) { 156 $nbElements += $project->getElementCount('order_supplier', 'commande_fournisseur'); 157 } 158 if (!empty($conf->supplier_invoice->enabled)) { 159 $nbElements += $project->getElementCount('invoice_supplier', 'facture_fourn'); 160 } 161 if (!empty($conf->contrat->enabled)) { 162 $nbElements += $project->getElementCount('contract', 'contrat'); 163 } 164 if (!empty($conf->ficheinter->enabled)) { 165 $nbElements += $project->getElementCount('intervention', 'fichinter'); 166 } 167 if (!empty($conf->expedition->enabled)) { 168 $nbElements += $project->getElementCount('shipping', 'expedition'); 169 } 170 if (!empty($conf->mrp->enabled)) { 171 $nbElements += $project->getElementCount('mrp', 'mrp_mo', 'fk_project'); 172 } 173 if (!empty($conf->deplacement->enabled)) { 174 $nbElements += $project->getElementCount('trip', 'deplacement'); 175 } 176 if (!empty($conf->expensereport->enabled)) { 177 $nbElements += $project->getElementCount('expensereport', 'expensereport'); 178 } 179 if (!empty($conf->don->enabled)) { 180 $nbElements += $project->getElementCount('donation', 'don'); 181 } 182 if (!empty($conf->loan->enabled)) { 183 $nbElements += $project->getElementCount('loan', 'loan'); 184 } 185 if (!empty($conf->tax->enabled)) { 186 $nbElements += $project->getElementCount('chargesociales', 'chargesociales'); 187 } 188 if (!empty($conf->projet->enabled)) { 189 $nbElements += $project->getElementCount('project_task', 'projet_task'); 190 } 191 if (!empty($conf->stock->enabled)) { 192 $nbElements += $project->getElementCount('stock_mouvement', 'stock'); 193 } 194 if (!empty($conf->salaries->enabled)) { 195 $nbElements += $project->getElementCount('salaries', 'payment_salary'); 196 } 197 if (!empty($conf->banque->enabled)) { 198 $nbElements += $project->getElementCount('variouspayment', 'payment_various'); 199 } 200 dol_setcache($cachekey, $nbElements, 120); // If setting cache fails, this is not a problem, so we do not test result. 201 } 202 $head[$h][0] = DOL_URL_ROOT.'/projet/element.php?id='.$project->id; 203 $head[$h][1] = $langs->trans("ProjectOverview"); 204 if ($nbElements > 0) { 205 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbElements.'</span>'; 206 } 207 $head[$h][2] = 'element'; 208 $h++; 209 } 210 211 if ($conf->eventorganization->enabled && !empty($project->usage_organize_event)) { 212 $langs->load('eventorganization'); 213 $head[$h][0] = DOL_URL_ROOT . '/eventorganization/conferenceorbooth_list.php?projectid=' . $project->id; 214 $head[$h][1] = $langs->trans("EventOrganization"); 215 216 // Enable caching of conf or booth count 217 $nbConfOrBooth = 0; 218 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php'; 219 $cachekey = 'count_conferenceorbooth_'.$project->id; 220 $dataretrieved = dol_getcache($cachekey); 221 if (!is_null($dataretrieved)) { 222 $nbConfOrBooth = $dataretrieved; 223 } else { 224 require_once DOL_DOCUMENT_ROOT.'/eventorganization/class/conferenceorbooth.class.php'; 225 $conforbooth=new ConferenceOrBooth($db); 226 $result = $conforbooth->fetchAll('', '', 0, 0, array('t.fk_project'=>$project->id)); 227 //, 228 if (!is_array($result) && $result<0) { 229 setEventMessages($conforbooth->error, $conforbooth->errors, 'errors'); 230 } else { 231 $nbConfOrBooth = count($result); 232 } 233 dol_setcache($cachekey, $nbConfOrBooth, 120); // If setting cache fails, this is not a problem, so we do not test result. 234 } 235 if ($nbConfOrBooth > 0) { 236 $head[$h][1] .= '<span class="badge marginleftonlyshort">' . $nbConfOrBooth . '</span>'; 237 } 238 $head[$h][2] = 'eventorganisation'; 239 $h++; 240 } 241 242 // Show more tabs from modules 243 // Entries must be declared in modules descriptor with line 244 // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab 245 // $this->tabs = array('entity:-tabname); to remove a tab 246 complete_head_from_modules($conf, $langs, $project, $head, $h, 'project'); 247 248 249 if (empty($conf->global->MAIN_DISABLE_NOTES_TAB)) { 250 $nbNote = 0; 251 if (!empty($project->note_private)) { 252 $nbNote++; 253 } 254 if (!empty($project->note_public)) { 255 $nbNote++; 256 } 257 $head[$h][0] = DOL_URL_ROOT.'/projet/note.php?id='.$project->id; 258 $head[$h][1] = $langs->trans('Notes'); 259 if ($nbNote > 0) { 260 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbNote.'</span>'; 261 } 262 $head[$h][2] = 'notes'; 263 $h++; 264 } 265 266 // Attached files and Links 267 $totalAttached = 0; 268 // Enable caching of thirdrparty count attached files and links 269 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php'; 270 $cachekey = 'count_attached_project_'.$project->id; 271 $dataretrieved = dol_getcache($cachekey); 272 if (!is_null($dataretrieved)) { 273 $totalAttached = $dataretrieved; 274 } else { 275 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; 276 require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; 277 $upload_dir = $conf->projet->dir_output."/".dol_sanitizeFileName($project->ref); 278 $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); 279 $nbLinks = Link::count($db, $project->element, $project->id); 280 $totalAttached = $nbFiles + $nbLinks; 281 dol_setcache($cachekey, $totalAttached, 120); // If setting cache fails, this is not a problem, so we do not test result. 282 } 283 $head[$h][0] = DOL_URL_ROOT.'/projet/document.php?id='.$project->id; 284 $head[$h][1] = $langs->trans('Documents'); 285 if (($totalAttached) > 0) { 286 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($totalAttached).'</span>'; 287 } 288 $head[$h][2] = 'document'; 289 $h++; 290 291 // Manage discussion 292 if (!empty($conf->global->PROJECT_ALLOW_COMMENT_ON_PROJECT)) { 293 $nbComments = 0; 294 // Enable caching of thirdrparty count attached files and links 295 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php'; 296 $cachekey = 'count_attached_project_'.$project->id; 297 $dataretrieved = dol_getcache($cachekey); 298 if (!is_null($dataretrieved)) { 299 $nbComments = $dataretrieved; 300 } else { 301 $nbComments = $project->getNbComments(); 302 dol_setcache($cachekey, $nbComments, 120); // If setting cache fails, this is not a problem, so we do not test result. 303 } 304 $head[$h][0] = DOL_URL_ROOT.'/projet/comment.php?id='.$project->id; 305 $head[$h][1] = $langs->trans("CommentLink"); 306 if ($nbComments > 0) { 307 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbComments.'</span>'; 308 } 309 $head[$h][2] = 'project_comment'; 310 $h++; 311 } 312 313 $head[$h][0] = DOL_URL_ROOT.'/projet/info.php?id='.$project->id; 314 $head[$h][1] .= $langs->trans("Events"); 315 if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { 316 $head[$h][1] .= '/'; 317 $head[$h][1] .= $langs->trans("Agenda"); 318 } 319 $head[$h][2] = 'agenda'; 320 $h++; 321 322 complete_head_from_modules($conf, $langs, $project, $head, $h, 'project', 'remove'); 323 324 return $head; 325} 326 327 328/** 329 * Prepare array with list of tabs 330 * 331 * @param Object $object Object related to tabs 332 * @return array Array of tabs to show 333 */ 334function task_prepare_head($object) 335{ 336 global $db, $langs, $conf, $user; 337 $h = 0; 338 $head = array(); 339 340 $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/task.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : ''); 341 $head[$h][1] = $langs->trans("Task"); 342 $head[$h][2] = 'task_task'; 343 $h++; 344 345 $nbContact = count($object->liste_contact(-1, 'internal')) + count($object->liste_contact(-1, 'external')); 346 $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/contact.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : ''); 347 $head[$h][1] = $langs->trans("TaskRessourceLinks"); 348 if ($nbContact > 0) { 349 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbContact.'</span>'; 350 } 351 $head[$h][2] = 'task_contact'; 352 $h++; 353 354 // Is there timespent ? 355 $nbTimeSpent = 0; 356 $sql = "SELECT t.rowid"; 357 //$sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."user as u"; 358 //$sql .= " WHERE t.fk_user = u.rowid AND t.fk_task = pt.rowid"; 359 $sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t"; 360 $sql .= " WHERE t.fk_task =".$object->id; 361 $resql = $db->query($sql); 362 if ($resql) { 363 $obj = $db->fetch_object($resql); 364 if ($obj) { 365 $nbTimeSpent = 1; 366 } 367 } else { 368 dol_print_error($db); 369 } 370 371 $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/time.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : ''); 372 $head[$h][1] = $langs->trans("TimeSpent"); 373 if ($nbTimeSpent > 0) { 374 $head[$h][1] .= '<span class="badge marginleftonlyshort">...</span>'; 375 } 376 $head[$h][2] = 'task_time'; 377 $h++; 378 379 // Show more tabs from modules 380 // Entries must be declared in modules descriptor with line 381 // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab 382 // $this->tabs = array('entity:-tabname); to remove a tab 383 complete_head_from_modules($conf, $langs, $object, $head, $h, 'task'); 384 385 if (empty($conf->global->MAIN_DISABLE_NOTES_TAB)) { 386 $nbNote = 0; 387 if (!empty($object->note_private)) { 388 $nbNote++; 389 } 390 if (!empty($object->note_public)) { 391 $nbNote++; 392 } 393 $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/note.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : ''); 394 $head[$h][1] = $langs->trans('Notes'); 395 if ($nbNote > 0) { 396 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbNote.'</span>'; 397 } 398 $head[$h][2] = 'task_notes'; 399 $h++; 400 } 401 402 $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/document.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : ''); 403 $filesdir = $conf->projet->dir_output."/".dol_sanitizeFileName($object->project->ref).'/'.dol_sanitizeFileName($object->ref); 404 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; 405 include_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; 406 $nbFiles = count(dol_dir_list($filesdir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); 407 $nbLinks = Link::count($db, $object->element, $object->id); 408 $head[$h][1] = $langs->trans('Documents'); 409 if (($nbFiles + $nbLinks) > 0) { 410 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbFiles + $nbLinks).'</span>'; 411 } 412 $head[$h][2] = 'task_document'; 413 $h++; 414 415 // Manage discussion 416 if (!empty($conf->global->PROJECT_ALLOW_COMMENT_ON_TASK)) { 417 $nbComments = $object->getNbComments(); 418 $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/comment.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : ''); 419 $head[$h][1] = $langs->trans("CommentLink"); 420 if ($nbComments > 0) { 421 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbComments.'</span>'; 422 } 423 $head[$h][2] = 'task_comment'; 424 $h++; 425 } 426 427 complete_head_from_modules($conf, $langs, $object, $head, $h, 'task', 'remove'); 428 429 return $head; 430} 431 432/** 433 * Prepare array with list of tabs 434 * 435 * @param string $mode Mode 436 * @param string $fuser Filter on user 437 * @return array Array of tabs to show 438 */ 439function project_timesheet_prepare_head($mode, $fuser = null) 440{ 441 global $langs, $conf, $user; 442 $h = 0; 443 $head = array(); 444 445 $h = 0; 446 447 $param = ''; 448 $param .= ($mode ? '&mode='.$mode : ''); 449 if (is_object($fuser) && $fuser->id > 0 && $fuser->id != $user->id) { 450 $param .= '&search_usertoprocessid='.$fuser->id; 451 } 452 453 if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERMONTH)) { 454 $head[$h][0] = DOL_URL_ROOT."/projet/activity/permonth.php".($param ? '?'.$param : ''); 455 $head[$h][1] = $langs->trans("InputPerMonth"); 456 $head[$h][2] = 'inputpermonth'; 457 $h++; 458 } 459 460 if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERWEEK)) { 461 $head[$h][0] = DOL_URL_ROOT."/projet/activity/perweek.php".($param ? '?'.$param : ''); 462 $head[$h][1] = $langs->trans("InputPerWeek"); 463 $head[$h][2] = 'inputperweek'; 464 $h++; 465 } 466 467 if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERTIME)) { 468 $head[$h][0] = DOL_URL_ROOT."/projet/activity/perday.php".($param ? '?'.$param : ''); 469 $head[$h][1] = $langs->trans("InputPerDay"); 470 $head[$h][2] = 'inputperday'; 471 $h++; 472 } 473 474 /*if ($conf->global->MAIN_FEATURES_LEVEL >= 2) 475 { 476 $head[$h][0] = DOL_URL_ROOT."/projet/activity/perline.php".($param?'?'.$param:''); 477 $head[$h][1] = $langs->trans("InputDetail"); 478 $head[$h][2] = 'inputperline'; 479 $h++; 480 }*/ 481 482 complete_head_from_modules($conf, $langs, null, $head, $h, 'project_timesheet'); 483 484 complete_head_from_modules($conf, $langs, null, $head, $h, 'project_timesheet', 'remove'); 485 486 return $head; 487} 488 489 490/** 491 * Prepare array with list of tabs 492 * 493 * @return array Array of tabs to show 494 */ 495function project_admin_prepare_head() 496{ 497 global $langs, $conf, $user; 498 $h = 0; 499 $head = array(); 500 501 $h = 0; 502 503 $head[$h][0] = DOL_URL_ROOT."/projet/admin/project.php"; 504 $head[$h][1] = $langs->trans("Projects"); 505 $head[$h][2] = 'project'; 506 $h++; 507 508 complete_head_from_modules($conf, $langs, null, $head, $h, 'project_admin'); 509 510 $head[$h][0] = DOL_URL_ROOT."/projet/admin/project_extrafields.php"; 511 $head[$h][1] = $langs->trans("ExtraFieldsProject"); 512 $head[$h][2] = 'attributes'; 513 $h++; 514 515 $head[$h][0] = DOL_URL_ROOT.'/projet/admin/project_task_extrafields.php'; 516 $head[$h][1] = $langs->trans("ExtraFieldsProjectTask"); 517 $head[$h][2] = 'attributes_task'; 518 $h++; 519 520 if (! empty($conf->global->MAIN_FEATURES_LEVEL) && $conf->global->MAIN_FEATURES_LEVEL >= 2) { 521 $langs->load("members"); 522 523 $head[$h][0] = DOL_URL_ROOT.'/projet/admin/website.php'; 524 $head[$h][1] = $langs->trans("BlankSubscriptionForm"); 525 $head[$h][2] = 'website'; 526 $h++; 527 } 528 529 complete_head_from_modules($conf, $langs, null, $head, $h, 'project_admin', 'remove'); 530 531 return $head; 532} 533 534 535/** 536 * Show task lines with a particular parent 537 * 538 * @param string $inc Line number (start to 0, then increased by recursive call) 539 * @param string $parent Id of parent project to show (0 to show all) 540 * @param Task[] $lines Array of lines 541 * @param int $level Level (start to 0, then increased/decrease by recursive call), or -1 to show all level in order of $lines without the recursive groupment feature. 542 * @param string $var Color 543 * @param int $showproject Show project columns 544 * @param int $taskrole Array of roles of user for each tasks 545 * @param int $projectsListId List of id of project allowed to user (string separated with comma) 546 * @param int $addordertick Add a tick to move task 547 * @param int $projectidfortotallink 0 or Id of project to use on total line (link to see all time consumed for project) 548 * @param string $filterprogresscalc filter text 549 * @param string $showbilltime Add the column 'TimeToBill' and 'TimeBilled' 550 * @param array $arrayfields Array with displayed coloumn information 551 * @return int Nb of tasks shown 552 */ 553function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$taskrole, $projectsListId = '', $addordertick = 0, $projectidfortotallink = 0, $filterprogresscalc = '', $showbilltime = 0, $arrayfields = array()) 554{ 555 global $user, $langs, $conf, $db, $hookmanager; 556 global $projectstatic, $taskstatic, $extrafields; 557 558 $lastprojectid = 0; 559 560 $projectsArrayId = explode(',', $projectsListId); 561 if ($filterprogresscalc !== '') { 562 foreach ($lines as $key => $line) { 563 if (!empty($line->planned_workload) && !empty($line->duration)) { 564 $filterprogresscalc = str_replace(' = ', ' == ', $filterprogresscalc); 565 if (!eval($filterprogresscalc)) { 566 unset($lines[$key]); 567 } 568 } 569 } 570 $lines = array_values($lines); 571 } 572 $numlines = count($lines); 573 574 // We declare counter as global because we want to edit them into recursive call 575 global $total_projectlinesa_spent, $total_projectlinesa_planned, $total_projectlinesa_spent_if_planned, $total_projectlinesa_declared_if_planned, $total_projectlinesa_tobill, $total_projectlinesa_billed; 576 577 if ($level == 0) { 578 $total_projectlinesa_spent = 0; 579 $total_projectlinesa_planned = 0; 580 $total_projectlinesa_spent_if_planned = 0; 581 $total_projectlinesa_declared_if_planned = 0; 582 $total_projectlinesa_tobill = 0; 583 $total_projectlinesa_billed = 0; 584 } 585 586 for ($i = 0; $i < $numlines; $i++) { 587 if ($parent == 0 && $level >= 0) { 588 $level = 0; // if $level = -1, we dont' use sublevel recursion, we show all lines 589 } 590 591 // Process line 592 // print "i:".$i."-".$lines[$i]->fk_project.'<br>'; 593 594 if ($lines[$i]->fk_parent == $parent || $level < 0) { // if $level = -1, we dont' use sublevel recursion, we show all lines 595 // Show task line. 596 $showline = 1; 597 $showlineingray = 0; 598 599 // If there is filters to use 600 if (is_array($taskrole)) { 601 // If task not legitimate to show, search if a legitimate task exists later in tree 602 if (!isset($taskrole[$lines[$i]->id]) && $lines[$i]->id != $lines[$i]->fk_parent) { 603 // So search if task has a subtask legitimate to show 604 $foundtaskforuserdeeper = 0; 605 searchTaskInChild($foundtaskforuserdeeper, $lines[$i]->id, $lines, $taskrole); 606 //print '$foundtaskforuserpeeper='.$foundtaskforuserdeeper.'<br>'; 607 if ($foundtaskforuserdeeper > 0) { 608 $showlineingray = 1; // We will show line but in gray 609 } else { 610 $showline = 0; // No reason to show line 611 } 612 } 613 } else { 614 // Caller did not ask to filter on tasks of a specific user (this probably means he want also tasks of all users, into public project 615 // or into all other projects if user has permission to). 616 if (empty($user->rights->projet->all->lire)) { 617 // User is not allowed on this project and project is not public, so we hide line 618 if (!in_array($lines[$i]->fk_project, $projectsArrayId)) { 619 // Note that having a user assigned to a task into a project user has no permission on, should not be possible 620 // because assignement on task can be done only on contact of project. 621 // If assignement was done and after, was removed from contact of project, then we can hide the line. 622 $showline = 0; 623 } 624 } 625 } 626 627 if ($showline) { 628 // Break on a new project 629 if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) { 630 $var = !$var; 631 $lastprojectid = $lines[$i]->fk_project; 632 } 633 634 print '<tr class="oddeven" id="row-'.$lines[$i]->id.'">'."\n"; 635 636 $projectstatic->id = $lines[$i]->fk_project; 637 $projectstatic->ref = $lines[$i]->projectref; 638 $projectstatic->public = $lines[$i]->public; 639 $projectstatic->title = $lines[$i]->projectlabel; 640 $projectstatic->usage_bill_time = $lines[$i]->usage_bill_time; 641 $projectstatic->status = $lines[$i]->projectstatus; 642 643 $taskstatic->id = $lines[$i]->id; 644 $taskstatic->ref = $lines[$i]->ref; 645 $taskstatic->label = ($taskrole[$lines[$i]->id] ? $langs->trans("YourRole").': '.$taskrole[$lines[$i]->id] : ''); 646 $taskstatic->projectstatus = $lines[$i]->projectstatus; 647 $taskstatic->progress = $lines[$i]->progress; 648 $taskstatic->fk_statut = $lines[$i]->status; 649 $taskstatic->date_start = $lines[$i]->date_start; 650 $taskstatic->date_end = $lines[$i]->date_end; 651 $taskstatic->datee = $lines[$i]->date_end; // deprecated 652 $taskstatic->planned_workload = $lines[$i]->planned_workload; 653 $taskstatic->duration_effective = $lines[$i]->duration; 654 655 656 if ($showproject) { 657 // Project ref 658 print "<td>"; 659 //if ($showlineingray) print '<i>'; 660 if ($lines[$i]->public || in_array($lines[$i]->fk_project, $projectsArrayId) || !empty($user->rights->projet->all->lire)) { 661 print $projectstatic->getNomUrl(1); 662 } else { 663 print $projectstatic->getNomUrl(1, 'nolink'); 664 } 665 //if ($showlineingray) print '</i>'; 666 print "</td>"; 667 668 // Project status 669 print '<td>'; 670 $projectstatic->statut = $lines[$i]->projectstatus; 671 print $projectstatic->getLibStatut(2); 672 print "</td>"; 673 } 674 675 // Ref of task 676 if (count($arrayfields) > 0 && !empty($arrayfields['t.ref']['checked'])) { 677 print '<td class="nowraponall">'; 678 if ($showlineingray) { 679 print '<i>'.img_object('', 'projecttask').' '.$lines[$i]->ref.'</i>'; 680 } else { 681 print $taskstatic->getNomUrl(1, 'withproject'); 682 } 683 print '</td>'; 684 } 685 686 // Title of task 687 if (count($arrayfields) > 0 && !empty($arrayfields['t.label']['checked'])) { 688 print '<td>'; 689 if ($showlineingray) { 690 print '<i>'; 691 } 692 //else print '<a href="'.DOL_URL_ROOT.'/projet/tasks/task.php?id='.$lines[$i]->id.'&withproject=1">'; 693 for ($k = 0; $k < $level; $k++) { 694 print '<div class="marginleftonly">'; 695 } 696 print $lines[$i]->label; 697 for ($k = 0; $k < $level; $k++) { 698 print '</div>'; 699 } 700 if ($showlineingray) { 701 print '</i>'; 702 } 703 //else print '</a>'; 704 print "</td>\n"; 705 } 706 707 if (count($arrayfields) > 0 && !empty($arrayfields['t.description']['checked'])) { 708 print "<td>"; 709 print $lines[$i]->description; 710 print "</td>\n"; 711 } 712 713 // Date start 714 if (count($arrayfields) > 0 && !empty($arrayfields['t.dateo']['checked'])) { 715 print '<td class="center">'; 716 print dol_print_date($lines[$i]->date_start, 'dayhour'); 717 print '</td>'; 718 } 719 720 // Date end 721 if (count($arrayfields) > 0 && !empty($arrayfields['t.datee']['checked'])) { 722 print '<td class="center">'; 723 print dol_print_date($lines[$i]->date_end, 'dayhour'); 724 if ($taskstatic->hasDelay()) { 725 print img_warning($langs->trans("Late")); 726 } 727 print '</td>'; 728 } 729 730 $plannedworkloadoutputformat = 'allhourmin'; 731 $timespentoutputformat = 'allhourmin'; 732 if (!empty($conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT)) { 733 $plannedworkloadoutputformat = $conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT; 734 } 735 if (!empty($conf->global->PROJECT_TIMES_SPENT_FORMAT)) { 736 $timespentoutputformat = $conf->global->PROJECT_TIME_SPENT_FORMAT; 737 } 738 739 // Planned Workload (in working hours) 740 if (count($arrayfields) > 0 && !empty($arrayfields['t.planned_workload']['checked'])) { 741 print '<td class="right">'; 742 $fullhour = convertSecondToTime($lines[$i]->planned_workload, $plannedworkloadoutputformat); 743 $workingdelay = convertSecondToTime($lines[$i]->planned_workload, 'all', 86400, 7); // TODO Replace 86400 and 7 to take account working hours per day and working day per weeks 744 if ($lines[$i]->planned_workload != '') { 745 print $fullhour; 746 // TODO Add delay taking account of working hours per day and working day per week 747 //if ($workingdelay != $fullhour) print '<br>('.$workingdelay.')'; 748 } 749 //else print '--:--'; 750 print '</td>'; 751 } 752 753 // Time spent 754 if (count($arrayfields) > 0 && !empty($arrayfields['t.duration_effective']['checked'])) { 755 print '<td class="right">'; 756 if ($showlineingray) { 757 print '<i>'; 758 } else { 759 print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.($showproject ? '' : '&withproject=1').'">'; 760 } 761 if ($lines[$i]->duration) { 762 print convertSecondToTime($lines[$i]->duration, $timespentoutputformat); 763 } else { 764 print '--:--'; 765 } 766 if ($showlineingray) { 767 print '</i>'; 768 } else { 769 print '</a>'; 770 } 771 print '</td>'; 772 } 773 774 // Progress calculated (Note: ->duration is time spent) 775 if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_calculated']['checked'])) { 776 print '<td class="right">'; 777 if ($lines[$i]->planned_workload || $lines[$i]->duration) { 778 if ($lines[$i]->planned_workload) { 779 print round(100 * $lines[$i]->duration / $lines[$i]->planned_workload, 2).' %'; 780 } else { 781 print '<span class="opacitymedium">'.$langs->trans('WorkloadNotDefined').'</span>'; 782 } 783 } 784 print '</td>'; 785 } 786 787 // Progress declared 788 if (count($arrayfields) > 0 && !empty($arrayfields['t.progress']['checked'])) { 789 print '<td class="right">'; 790 if ($lines[$i]->progress != '') { 791 print getTaskProgressBadge($taskstatic); 792 } 793 print '</td>'; 794 } 795 796 // resume 797 if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_summary']['checked'])) { 798 print '<td class="right">'; 799 if ($lines[$i]->progress != '' && $lines[$i]->duration) { 800 print getTaskProgressView($taskstatic, false, false); 801 } 802 print '</td>'; 803 } 804 805 if ($showbilltime) { 806 // Time not billed 807 if (count($arrayfields) > 0 && !empty($arrayfields['t.tobill']['checked'])) { 808 print '<td class="right">'; 809 if ($lines[$i]->usage_bill_time) { 810 print convertSecondToTime($lines[$i]->tobill, 'allhourmin'); 811 $total_projectlinesa_tobill += $lines[$i]->tobill; 812 } else { 813 print '<span class="opacitymedium">'.$langs->trans("NA").'</span>'; 814 } 815 print '</td>'; 816 } 817 818 // Time billed 819 if (count($arrayfields) > 0 && !empty($arrayfields['t.billed']['checked'])) { 820 print '<td class="right">'; 821 if ($lines[$i]->usage_bill_time) { 822 print convertSecondToTime($lines[$i]->billed, 'allhourmin'); 823 $total_projectlinesa_billed += $lines[$i]->billed; 824 } else { 825 print '<span class="opacitymedium">'.$langs->trans("NA").'</span>'; 826 } 827 print '</td>'; 828 } 829 } 830 831 // Contacts of tasks. Disabled, because available by default just after 832 /* 833 if (!empty($conf->global->PROJECT_SHOW_CONTACTS_IN_LIST)) { 834 print '<td>'; 835 foreach (array('internal', 'external') as $source) { 836 $tab = $lines[$i]->liste_contact(-1, $source); 837 $num = count($tab); 838 if (!empty($num)) { 839 foreach ($tab as $contacttask) { 840 //var_dump($contacttask); 841 if ($source == 'internal') { 842 $c = new User($db); 843 } else { 844 $c = new Contact($db); 845 } 846 $c->fetch($contacttask['id']); 847 print $c->getNomUrl(1).' ('.$contacttask['libelle'].')<br>'; 848 } 849 } 850 } 851 print '</td>'; 852 }*/ 853 854 // Contacts of task 855 if (count($arrayfields) > 0 && !empty($arrayfields['c.assigned']['checked'])) { 856 print '<td class="center">'; 857 foreach (array('internal', 'external') as $source) { 858 $tab = $lines[$i]->liste_contact(-1, $source); 859 $num = count($tab); 860 if (!empty($num)) { 861 foreach ($tab as $contacttask) { 862 //var_dump($contacttask); 863 if ($source == 'internal') { 864 $c = new User($db); 865 } else { 866 $c = new Contact($db); 867 } 868 $c->fetch($contacttask['id']); 869 if (!empty($c->photo)) { 870 print $c->getNomUrl(-2).' '; 871 } else { 872 if (get_class($c) == 'User') { 873 print $c->getNomUrl(2, '', 0, 0, 24, 1);//.' '; 874 } else { 875 print $c->getNomUrl(2);//.' '; 876 } 877 } 878 } 879 } 880 } 881 print '</td>'; 882 } 883 884 // Extra fields 885 $extrafieldsobjectkey = $taskstatic->table_element; 886 $obj = $lines[$i]; 887 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; 888 // Fields from hook 889 $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$lines[$i]); 890 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook 891 print $hookmanager->resPrint; 892 893 // Tick to drag and drop 894 print '<td class="tdlineupdown center"></td>'; 895 896 print "</tr>\n"; 897 898 if (!$showlineingray) { 899 $inc++; 900 } 901 902 if ($level >= 0) { // Call sublevels 903 $level++; 904 if ($lines[$i]->id) { 905 projectLinesa($inc, $lines[$i]->id, $lines, $level, $var, $showproject, $taskrole, $projectsListId, $addordertick, $projectidfortotallink, $filterprogresscalc, $showbilltime, $arrayfields); 906 } 907 $level--; 908 } 909 910 $total_projectlinesa_spent += $lines[$i]->duration; 911 $total_projectlinesa_planned += $lines[$i]->planned_workload; 912 if ($lines[$i]->planned_workload) { 913 $total_projectlinesa_spent_if_planned += $lines[$i]->duration; 914 } 915 if ($lines[$i]->planned_workload) { 916 $total_projectlinesa_declared_if_planned += $lines[$i]->planned_workload * $lines[$i]->progress / 100; 917 } 918 } 919 } else { 920 //$level--; 921 } 922 } 923 924 if (($total_projectlinesa_planned > 0 || $total_projectlinesa_spent > 0 || $total_projectlinesa_tobill > 0 || $total_projectlinesa_billed > 0) 925 && $level <= 0) { 926 print '<tr class="liste_total nodrag nodrop">'; 927 print '<td class="liste_total">'.$langs->trans("Total").'</td>'; 928 if ($showproject) { 929 print '<td></td><td></td>'; 930 } 931 if (count($arrayfields) > 0 && !empty($arrayfields['t.label']['checked'])) { 932 print '<td></td>'; 933 } 934 if (count($arrayfields) > 0 && !empty($arrayfields['t.dateo']['checked'])) { 935 print '<td></td>'; 936 } 937 if (count($arrayfields) > 0 && !empty($arrayfields['t.datee']['checked'])) { 938 print '<td></td>'; 939 } 940 if (count($arrayfields) > 0 && !empty($arrayfields['t.planned_workload']['checked'])) { 941 print '<td class="nowrap liste_total right">'; 942 print convertSecondToTime($total_projectlinesa_planned, 'allhourmin'); 943 print '</td>'; 944 } 945 if (count($arrayfields) > 0 && !empty($arrayfields['t.duration_effective']['checked'])) { 946 print '<td class="nowrap liste_total right">'; 947 if ($projectidfortotallink > 0) { 948 print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?projectid='.$projectidfortotallink.($showproject ? '' : '&withproject=1').'">'; 949 } 950 print convertSecondToTime($total_projectlinesa_spent, 'allhourmin'); 951 if ($projectidfortotallink > 0) { 952 print '</a>'; 953 } 954 print '</td>'; 955 } 956 957 if ($total_projectlinesa_planned) { 958 $totalAverageDeclaredProgress = round(100 * $total_projectlinesa_declared_if_planned / $total_projectlinesa_planned, 2); 959 $totalCalculatedProgress = round(100 * $total_projectlinesa_spent / $total_projectlinesa_planned, 2); 960 961 // this conf is actually hidden, by default we use 10% for "be carefull or warning" 962 $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10; 963 964 // define progress color according to time spend vs workload 965 $progressBarClass = 'progress-bar-info'; 966 $badgeClass = 'badge '; 967 968 if ($totalCalculatedProgress > $totalAverageDeclaredProgress) { 969 $progressBarClass = 'progress-bar-danger'; 970 $badgeClass .= 'badge-danger'; 971 } elseif ($totalCalculatedProgress * $warningRatio >= $totalAverageDeclaredProgress) { // warning if close at 1% 972 $progressBarClass = 'progress-bar-warning'; 973 $badgeClass .= 'badge-warning'; 974 } else { 975 $progressBarClass = 'progress-bar-success'; 976 $badgeClass .= 'badge-success'; 977 } 978 } 979 980 // Computed progress 981 if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_calculated']['checked'])) { 982 print '<td class="nowrap liste_total right">'; 983 if ($total_projectlinesa_planned) { 984 print $totalCalculatedProgress.' %'; 985 } 986 print '</td>'; 987 } 988 989 // Declared progress 990 if (count($arrayfields) > 0 && !empty($arrayfields['t.progress']['checked'])) { 991 print '<td class="nowrap liste_total right">'; 992 if ($total_projectlinesa_planned) { 993 print '<span class="'.$badgeClass.'" >'.$totalAverageDeclaredProgress.' %</span>'; 994 } 995 print '</td>'; 996 } 997 998 999 // resume 1000 if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_summary']['checked'])) { 1001 print '<td class="right">'; 1002 if ($total_projectlinesa_planned) { 1003 print '</span>'; 1004 print ' <div class="progress sm" title="'.$totalAverageDeclaredProgress.'%" >'; 1005 print ' <div class="progress-bar '.$progressBarClass.'" style="width: '.$totalAverageDeclaredProgress.'%"></div>'; 1006 print ' </div>'; 1007 print '</div>'; 1008 } 1009 print '</td>'; 1010 } 1011 1012 if ($showbilltime) { 1013 if (count($arrayfields) > 0 && !empty($arrayfields['t.tobill']['checked'])) { 1014 print '<td class="nowrap liste_total right">'; 1015 print convertSecondToTime($total_projectlinesa_tobill, 'allhourmin'); 1016 print '</td>'; 1017 } 1018 if (count($arrayfields) > 0 && !empty($arrayfields['t.billed']['checked'])) { 1019 print '<td class="nowrap liste_total right">'; 1020 print convertSecondToTime($total_projectlinesa_billed, 'allhourmin'); 1021 print '</td>'; 1022 } 1023 } 1024 // Contacts of task for backward compatibility, 1025 if (!empty($conf->global->PROJECT_SHOW_CONTACTS_IN_LIST)) { 1026 print '<td></td>'; 1027 } 1028 // Contacts of task 1029 if (count($arrayfields) > 0 && !empty($arrayfields['c.assigned']['checked'])) { 1030 print '<td></td>'; 1031 } 1032 print '<td class=""></td>'; 1033 print '</tr>'; 1034 } 1035 1036 return $inc; 1037} 1038 1039 1040/** 1041 * Output a task line into a pertime intput mode 1042 * 1043 * @param string $inc Line number (start to 0, then increased by recursive call) 1044 * @param string $parent Id of parent task to show (0 to show all) 1045 * @param User|null $fuser Restrict list to user if defined 1046 * @param Task[] $lines Array of lines 1047 * @param int $level Level (start to 0, then increased/decrease by recursive call) 1048 * @param string $projectsrole Array of roles user has on project 1049 * @param string $tasksrole Array of roles user has on task 1050 * @param string $mine Show only task lines I am assigned to 1051 * @param int $restricteditformytask 0=No restriction, 1=Enable add time only if task is a task i am affected to 1052 * @param int $preselectedday Preselected day 1053 * @param array $isavailable Array with data that say if user is available for several days for morning and afternoon 1054 * @param int $oldprojectforbreak Old project id of last project break 1055 * @return array Array with time spent for $fuser for each day of week on tasks in $lines and substasks 1056 */ 1057function projectLinesPerAction(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak = 0) 1058{ 1059 global $conf, $db, $user, $langs; 1060 global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic; 1061 1062 $lastprojectid = 0; 1063 $totalforeachline = array(); 1064 $workloadforid = array(); 1065 $lineswithoutlevel0 = array(); 1066 1067 $numlines = count($lines); 1068 1069 // Create a smaller array with sublevels only to be used later. This increase dramatically performances. 1070 if ($parent == 0) { // Always and only if at first level 1071 for ($i = 0; $i < $numlines; $i++) { 1072 if ($lines[$i]->fk_task_parent) { 1073 $lineswithoutlevel0[] = $lines[$i]; 1074 } 1075 } 1076 } 1077 1078 if (empty($oldprojectforbreak)) { 1079 $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 to start break , -1 no break 1080 } 1081 1082 //dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0)); 1083 for ($i = 0; $i < $numlines; $i++) { 1084 if ($parent == 0) { 1085 $level = 0; 1086 } 1087 1088 //if ($lines[$i]->fk_task_parent == $parent) 1089 //{ 1090 // If we want all or we have a role on task, we show it 1091 if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) { 1092 //dol_syslog("projectLinesPerWeek Found line ".$i.", a qualified task (i have role or want to show all tasks) with id=".$lines[$i]->id." project id=".$lines[$i]->fk_project); 1093 1094 // Break on a new project 1095 if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) { 1096 $lastprojectid = $lines[$i]->fk_project; 1097 if ($preselectedday) { 1098 $projectstatic->id = $lines[$i]->fk_project; 1099 } 1100 } 1101 1102 if (empty($workloadforid[$projectstatic->id])) { 1103 if ($preselectedday) { 1104 $projectstatic->loadTimeSpent($preselectedday, 0, $fuser->id); // Load time spent from table projet_task_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week 1105 $workloadforid[$projectstatic->id] = 1; 1106 } 1107 } 1108 1109 $projectstatic->id = $lines[$i]->fk_project; 1110 $projectstatic->ref = $lines[$i]->project_ref; 1111 $projectstatic->title = $lines[$i]->project_label; 1112 $projectstatic->public = $lines[$i]->public; 1113 $projectstatic->status = $lines[$i]->project_status; 1114 1115 $taskstatic->id = $lines[$i]->task_id; 1116 $taskstatic->ref = ($lines[$i]->task_ref ? $lines[$i]->task_ref : $lines[$i]->task_id); 1117 $taskstatic->label = $lines[$i]->task_label; 1118 $taskstatic->date_start = $lines[$i]->date_start; 1119 $taskstatic->date_end = $lines[$i]->date_end; 1120 1121 $thirdpartystatic->id = $lines[$i]->socid; 1122 $thirdpartystatic->name = $lines[$i]->thirdparty_name; 1123 $thirdpartystatic->email = $lines[$i]->thirdparty_email; 1124 1125 if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) { 1126 print '<tr class="oddeven trforbreak nobold">'."\n"; 1127 print '<td colspan="11">'; 1128 print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]); 1129 if ($projectstatic->title) { 1130 print ' - '; 1131 print $projectstatic->title; 1132 } 1133 print '</td>'; 1134 print '</tr>'; 1135 } 1136 1137 if ($oldprojectforbreak != -1) { 1138 $oldprojectforbreak = $projectstatic->id; 1139 } 1140 1141 print '<tr class="oddeven">'."\n"; 1142 1143 // User 1144 /* 1145 print '<td class="nowrap">'; 1146 print $fuser->getNomUrl(1, 'withproject', 'time'); 1147 print '</td>'; 1148 */ 1149 1150 // Project 1151 print "<td>"; 1152 if ($oldprojectforbreak == -1) { 1153 print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]); 1154 print '<br>'.$projectstatic->title; 1155 } 1156 print "</td>"; 1157 1158 // Thirdparty 1159 print '<td class="tdoverflowmax100">'; 1160 if ($thirdpartystatic->id > 0) { 1161 print $thirdpartystatic->getNomUrl(1, 'project', 10); 1162 } 1163 print '</td>'; 1164 1165 // Ref 1166 print '<td>'; 1167 print '<!-- Task id = '.$lines[$i]->id.' -->'; 1168 for ($k = 0; $k < $level; $k++) { 1169 print " "; 1170 } 1171 print $taskstatic->getNomUrl(1, 'withproject', 'time'); 1172 // Label task 1173 print '<br>'; 1174 for ($k = 0; $k < $level; $k++) { 1175 print " "; 1176 } 1177 print $taskstatic->label; 1178 //print "<br>"; 1179 //for ($k = 0 ; $k < $level ; $k++) print " "; 1180 //print get_date_range($lines[$i]->date_start,$lines[$i]->date_end,'',$langs,0); 1181 print "</td>\n"; 1182 1183 // Date 1184 print '<td class="center">'; 1185 print dol_print_date($lines[$i]->timespent_datehour, 'day'); 1186 print '</td>'; 1187 1188 $disabledproject = 1; 1189 $disabledtask = 1; 1190 //print "x".$lines[$i]->fk_project; 1191 //var_dump($lines[$i]); 1192 //var_dump($projectsrole[$lines[$i]->fk_project]); 1193 // If at least one role for project 1194 if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) { 1195 $disabledproject = 0; 1196 $disabledtask = 0; 1197 } 1198 // If $restricteditformytask is on and I have no role on task, i disable edit 1199 if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) { 1200 $disabledtask = 1; 1201 } 1202 1203 // Hour 1204 print '<td class="nowrap center">'; 1205 print dol_print_date($lines[$i]->timespent_datehour, 'hour'); 1206 print '</td>'; 1207 1208 $cssonholiday = ''; 1209 if (!$isavailable[$preselectedday]['morning'] && !$isavailable[$preselectedday]['afternoon']) { 1210 $cssonholiday .= 'onholidayallday '; 1211 } elseif (!$isavailable[$preselectedday]['morning']) { 1212 $cssonholiday .= 'onholidaymorning '; 1213 } elseif (!$isavailable[$preselectedday]['afternoon']) { 1214 $cssonholiday .= 'onholidayafternoon '; 1215 } 1216 1217 // Duration 1218 print '<td class="duration'.($cssonholiday ? ' '.$cssonholiday : '').' center">'; 1219 1220 $dayWorkLoad = $lines[$i]->timespent_duration; 1221 $totalforeachline[$preselectedday] += $lines[$i]->timespent_duration; 1222 1223 $alreadyspent = ''; 1224 if ($dayWorkLoad > 0) { 1225 $alreadyspent = convertSecondToTime($lines[$i]->timespent_duration, 'allhourmin'); 1226 } 1227 1228 print convertSecondToTime($lines[$i]->timespent_duration, 'allhourmin'); 1229 1230 $modeinput = 'hours'; 1231 1232 print '<script type="text/javascript">'; 1233 print "jQuery(document).ready(function () {\n"; 1234 print " jQuery('.inputhour, .inputminute').bind('keyup', function(e) { updateTotal(0, '".$modeinput."') });"; 1235 print "})\n"; 1236 print '</script>'; 1237 1238 print '</td>'; 1239 1240 // Note 1241 print '<td class="center">'; 1242 print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask ? ' disabled="disabled"' : '').'>'; 1243 print $lines[$i]->timespent_note; 1244 print '</textarea>'; 1245 print '</td>'; 1246 1247 // Warning 1248 print '<td class="right">'; 1249 /*if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("UserIsNotContactOfProject")); 1250 elseif ($disabledtask) 1251 { 1252 $titleassigntask = $langs->trans("AssignTaskToMe"); 1253 if ($fuser->id != $user->id) $titleassigntask = $langs->trans("AssignTaskToUser", '...'); 1254 1255 print $form->textwithpicto('',$langs->trans("TaskIsNotAssignedToUser", $titleassigntask)); 1256 }*/ 1257 print '</td>'; 1258 1259 print "</tr>\n"; 1260 } 1261 //} 1262 //else 1263 //{ 1264 //$level--; 1265 //} 1266 } 1267 1268 return $totalforeachline; 1269} 1270 1271 1272/** 1273 * Output a task line into a pertime intput mode 1274 * 1275 * @param string $inc Line number (start to 0, then increased by recursive call) 1276 * @param string $parent Id of parent task to show (0 to show all) 1277 * @param User|null $fuser Restrict list to user if defined 1278 * @param Task[] $lines Array of lines 1279 * @param int $level Level (start to 0, then increased/decrease by recursive call) 1280 * @param string $projectsrole Array of roles user has on project 1281 * @param string $tasksrole Array of roles user has on task 1282 * @param string $mine Show only task lines I am assigned to 1283 * @param int $restricteditformytask 0=No restriction, 1=Enable add time only if task is assigned to me, 2=Enable add time only if tasks is assigned to me and hide others 1284 * @param int $preselectedday Preselected day 1285 * @param array $isavailable Array with data that say if user is available for several days for morning and afternoon 1286 * @param int $oldprojectforbreak Old project id of last project break 1287 * @param array $arrayfields Array of additional column 1288 * @param Extrafields $extrafields Object extrafields 1289 * @return array Array with time spent for $fuser for each day of week on tasks in $lines and substasks 1290 */ 1291function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak = 0, $arrayfields = array(), $extrafields = null) 1292{ 1293 global $conf, $db, $user, $langs; 1294 global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic; 1295 1296 $lastprojectid = 0; 1297 $totalforeachday = array(); 1298 $workloadforid = array(); 1299 $lineswithoutlevel0 = array(); 1300 1301 $numlines = count($lines); 1302 1303 // Create a smaller array with sublevels only to be used later. This increase dramatically performances. 1304 if ($parent == 0) { // Always and only if at first level 1305 for ($i = 0; $i < $numlines; $i++) { 1306 if ($lines[$i]->fk_task_parent) { 1307 $lineswithoutlevel0[] = $lines[$i]; 1308 } 1309 } 1310 } 1311 1312 if (empty($oldprojectforbreak)) { 1313 $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 to start break , -1 no break 1314 } 1315 1316 //dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0)); 1317 for ($i = 0; $i < $numlines; $i++) { 1318 if ($parent == 0) { 1319 $level = 0; 1320 } 1321 1322 if ($lines[$i]->fk_task_parent == $parent) { 1323 $obj = &$lines[$i]; // To display extrafields 1324 1325 // If we want all or we have a role on task, we show it 1326 if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) { 1327 //dol_syslog("projectLinesPerWeek Found line ".$i.", a qualified task (i have role or want to show all tasks) with id=".$lines[$i]->id." project id=".$lines[$i]->fk_project); 1328 1329 if ($restricteditformytask == 2 && empty($tasksrole[$lines[$i]->id])) { // we have no role on task and we request to hide such cases 1330 continue; 1331 } 1332 1333 // Break on a new project 1334 if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) { 1335 $lastprojectid = $lines[$i]->fk_project; 1336 if ($preselectedday) { 1337 $projectstatic->id = $lines[$i]->fk_project; 1338 } 1339 } 1340 1341 if (empty($workloadforid[$projectstatic->id])) { 1342 if ($preselectedday) { 1343 $projectstatic->loadTimeSpent($preselectedday, 0, $fuser->id); // Load time spent from table projet_task_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week 1344 $workloadforid[$projectstatic->id] = 1; 1345 } 1346 } 1347 1348 $projectstatic->id = $lines[$i]->fk_project; 1349 $projectstatic->ref = $lines[$i]->projectref; 1350 $projectstatic->title = $lines[$i]->projectlabel; 1351 $projectstatic->public = $lines[$i]->public; 1352 $projectstatic->status = $lines[$i]->projectstatus; 1353 1354 $taskstatic->id = $lines[$i]->id; 1355 $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id); 1356 $taskstatic->label = $lines[$i]->label; 1357 $taskstatic->date_start = $lines[$i]->date_start; 1358 $taskstatic->date_end = $lines[$i]->date_end; 1359 1360 $thirdpartystatic->id = $lines[$i]->socid; 1361 $thirdpartystatic->name = $lines[$i]->thirdparty_name; 1362 $thirdpartystatic->email = $lines[$i]->thirdparty_email; 1363 1364 if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) { 1365 $addcolspan = 0; 1366 if (!empty($arrayfields['t.planned_workload']['checked'])) { 1367 $addcolspan++; 1368 } 1369 if (!empty($arrayfields['t.progress']['checked'])) { 1370 $addcolspan++; 1371 } 1372 foreach ($arrayfields as $key => $val) { 1373 if ($val['checked'] && substr($key, 0, 5) == 'efpt.') { 1374 $addcolspan++; 1375 } 1376 } 1377 1378 print '<tr class="oddeven trforbreak nobold">'."\n"; 1379 print '<td colspan="'.(7 + $addcolspan).'">'; 1380 print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]); 1381 if ($thirdpartystatic->id > 0) { 1382 print ' - '.$thirdpartystatic->getNomUrl(1); 1383 } 1384 if ($projectstatic->title) { 1385 print ' - '; 1386 print '<span class="secondary">'.$projectstatic->title.'</span>'; 1387 } 1388 /* 1389 $colspan=5+(empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:2); 1390 print '<table class="">'; 1391 1392 print '<tr class="liste_titre">'; 1393 1394 // PROJECT fields 1395 if (! empty($arrayfields['p.fk_opp_status']['checked'])) print_liste_field_titre($arrayfields['p.fk_opp_status']['label'], $_SERVER["PHP_SELF"], 'p.fk_opp_status', "", $param, '', $sortfield, $sortorder, 'center '); 1396 if (! empty($arrayfields['p.opp_amount']['checked'])) print_liste_field_titre($arrayfields['p.opp_amount']['label'], $_SERVER["PHP_SELF"], 'p.opp_amount', "", $param, '', $sortfield, $sortorder, 'right '); 1397 if (! empty($arrayfields['p.opp_percent']['checked'])) print_liste_field_titre($arrayfields['p.opp_percent']['label'], $_SERVER["PHP_SELF"], 'p.opp_percent', "", $param, '', $sortfield, $sortorder, 'right '); 1398 if (! empty($arrayfields['p.budget_amount']['checked'])) print_liste_field_titre($arrayfields['p.budget_amount']['label'], $_SERVER["PHP_SELF"], 'p.budget_amount', "", $param, '', $sortfield, $sortorder, 'right '); 1399 if (! empty($arrayfields['p.usage_bill_time']['checked'])) print_liste_field_titre($arrayfields['p.usage_bill_time']['label'], $_SERVER["PHP_SELF"], 'p.usage_bill_time', "", $param, '', $sortfield, $sortorder, 'right '); 1400 1401 $extrafieldsobjectkey='projet'; 1402 $extrafieldsobjectprefix='efp.'; 1403 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; 1404 1405 print '</tr>'; 1406 print '<tr>'; 1407 1408 // PROJECT fields 1409 if (! empty($arrayfields['p.fk_opp_status']['checked'])) 1410 { 1411 print '<td class="nowrap">'; 1412 $code = dol_getIdFromCode($db, $lines[$i]->fk_opp_status, 'c_lead_status', 'rowid', 'code'); 1413 if ($code) print $langs->trans("OppStatus".$code); 1414 print "</td>\n"; 1415 } 1416 if (! empty($arrayfields['p.opp_amount']['checked'])) 1417 { 1418 print '<td class="nowrap">'; 1419 print price($lines[$i]->opp_amount, 0, $langs, 1, 0, -1, $conf->currency); 1420 print "</td>\n"; 1421 } 1422 if (! empty($arrayfields['p.opp_percent']['checked'])) 1423 { 1424 print '<td class="nowrap">'; 1425 print price($lines[$i]->opp_percent, 0, $langs, 1, 0).' %'; 1426 print "</td>\n"; 1427 } 1428 if (! empty($arrayfields['p.budget_amount']['checked'])) 1429 { 1430 print '<td class="nowrap">'; 1431 print price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency); 1432 print "</td>\n"; 1433 } 1434 if (! empty($arrayfields['p.usage_bill_time']['checked'])) 1435 { 1436 print '<td class="nowrap">'; 1437 print yn($lines[$i]->usage_bill_time); 1438 print "</td>\n"; 1439 } 1440 1441 $extrafieldsobjectkey='projet'; 1442 $extrafieldsobjectprefix='efp.'; 1443 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; 1444 1445 print '</tr>'; 1446 print '</table>'; 1447 1448 */ 1449 print '</td>'; 1450 print '</tr>'; 1451 } 1452 1453 if ($oldprojectforbreak != -1) { 1454 $oldprojectforbreak = $projectstatic->id; 1455 } 1456 1457 print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n"; 1458 1459 // User 1460 /* 1461 print '<td class="nowrap">'; 1462 print $fuser->getNomUrl(1, 'withproject', 'time'); 1463 print '</td>'; 1464 */ 1465 1466 // Project 1467 if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) { 1468 print "<td>"; 1469 if ($oldprojectforbreak == -1) { 1470 print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]); 1471 } 1472 print "</td>"; 1473 } 1474 1475 // Thirdparty 1476 if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) { 1477 print '<td class="tdoverflowmax100">'; 1478 if ($thirdpartystatic->id > 0) { 1479 print $thirdpartystatic->getNomUrl(1, 'project', 10); 1480 } 1481 print '</td>'; 1482 } 1483 1484 // Ref 1485 print '<td>'; 1486 print '<!-- Task id = '.$lines[$i]->id.' -->'; 1487 for ($k = 0; $k < $level; $k++) { 1488 print '<div class="marginleftonly">'; 1489 } 1490 print $taskstatic->getNomUrl(1, 'withproject', 'time'); 1491 // Label task 1492 print '<br>'; 1493 print '<span class="opacitymedium">'.$taskstatic->label.'</a>'; 1494 for ($k = 0; $k < $level; $k++) { 1495 print "</div>"; 1496 } 1497 print "</td>\n"; 1498 1499 // TASK extrafields 1500 $extrafieldsobjectkey = 'projet_task'; 1501 $extrafieldsobjectprefix = 'efpt.'; 1502 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; 1503 1504 // Planned Workload 1505 if (!empty($arrayfields['t.planned_workload']['checked'])) { 1506 print '<td class="leftborder plannedworkload right">'; 1507 if ($lines[$i]->planned_workload) { 1508 print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin'); 1509 } else { 1510 print '--:--'; 1511 } 1512 print '</td>'; 1513 } 1514 1515 // Progress declared % 1516 if (!empty($arrayfields['t.progress']['checked'])) { 1517 print '<td class="right">'; 1518 print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress'); 1519 print '</td>'; 1520 } 1521 1522 if (!empty($arrayfields['timeconsumed']['checked'])) { 1523 // Time spent by everybody 1524 print '<td class="right">'; 1525 // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consummed by user 1526 if ($lines[$i]->duration) { 1527 print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">'; 1528 print convertSecondToTime($lines[$i]->duration, 'allhourmin'); 1529 print '</a>'; 1530 } else { 1531 print '--:--'; 1532 } 1533 print "</td>\n"; 1534 1535 // Time spent by user 1536 print '<td class="right">'; 1537 $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id); 1538 if ($tmptimespent['total_duration']) { 1539 print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin'); 1540 } else { 1541 print '--:--'; 1542 } 1543 print "</td>\n"; 1544 } 1545 1546 $disabledproject = 1; 1547 $disabledtask = 1; 1548 //print "x".$lines[$i]->fk_project; 1549 //var_dump($lines[$i]); 1550 //var_dump($projectsrole[$lines[$i]->fk_project]); 1551 // If at least one role for project 1552 if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) { 1553 $disabledproject = 0; 1554 $disabledtask = 0; 1555 } 1556 // If $restricteditformytask is on and I have no role on task, i disable edit 1557 if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) { 1558 $disabledtask = 1; 1559 } 1560 1561 // Form to add new time 1562 print '<td class="nowrap leftborder center">'; 1563 $tableCell = $form->selectDate($preselectedday, $lines[$i]->id, 1, 1, 2, "addtime", 0, 0, $disabledtask); 1564 print $tableCell; 1565 print '</td>'; 1566 1567 $cssonholiday = ''; 1568 if (!$isavailable[$preselectedday]['morning'] && !$isavailable[$preselectedday]['afternoon']) { 1569 $cssonholiday .= 'onholidayallday '; 1570 } elseif (!$isavailable[$preselectedday]['morning']) { 1571 $cssonholiday .= 'onholidaymorning '; 1572 } elseif (!$isavailable[$preselectedday]['afternoon']) { 1573 $cssonholiday .= 'onholidayafternoon '; 1574 } 1575 1576 global $daytoparse; 1577 $tmparray = dol_getdate($daytoparse, true); // detail of current day 1578 1579 $idw = ($tmparray['wday'] - (empty($conf->global->MAIN_START_WEEK) ? 0 : 1)); 1580 global $numstartworkingday, $numendworkingday; 1581 $cssweekend = ''; 1582 if ((($idw + 1) < $numstartworkingday) || (($idw + 1) > $numendworkingday)) { // This is a day is not inside the setup of working days, so we use a week-end css. 1583 $cssweekend = 'weekend'; 1584 } 1585 1586 // Duration 1587 print '<td class="center duration'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">'; 1588 $dayWorkLoad = $projectstatic->weekWorkLoadPerTask[$preselectedday][$lines[$i]->id]; 1589 $totalforeachday[$preselectedday] += $dayWorkLoad; 1590 1591 $alreadyspent = ''; 1592 if ($dayWorkLoad > 0) { 1593 $alreadyspent = convertSecondToTime($dayWorkLoad, 'allhourmin'); 1594 } 1595 1596 $idw = 0; 1597 1598 $tableCell = ''; 1599 $tableCell .= '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center" size="2" disabled id="timespent['.$inc.']['.$idw.']" name="task['.$lines[$i]->id.']['.$idw.']" value="'.$alreadyspent.'"></span>'; 1600 $tableCell .= '<span class="hideonsmartphone"> + </span>'; 1601 //$tableCell.=' '; 1602 $tableCell .= $form->select_duration($lines[$i]->id.'duration', '', $disabledtask, 'text', 0, 1); 1603 //$tableCell.=' <input type="submit" class="button"'.($disabledtask?' disabled':'').' value="'.$langs->trans("Add").'">'; 1604 print $tableCell; 1605 1606 $modeinput = 'hours'; 1607 1608 print '<script type="text/javascript">'; 1609 print "jQuery(document).ready(function () {\n"; 1610 print " jQuery('.inputhour, .inputminute').bind('keyup', function(e) { updateTotal(0, '".$modeinput."') });"; 1611 print "})\n"; 1612 print '</script>'; 1613 1614 print '</td>'; 1615 1616 // Note 1617 print '<td class="center">'; 1618 print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask ? ' disabled="disabled"' : '').'>'; 1619 print '</textarea>'; 1620 print '</td>'; 1621 1622 // Warning 1623 print '<td class="right">'; 1624 if ((!$lines[$i]->public) && $disabledproject) { 1625 print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject")); 1626 } elseif ($disabledtask) { 1627 $titleassigntask = $langs->trans("AssignTaskToMe"); 1628 if ($fuser->id != $user->id) { 1629 $titleassigntask = $langs->trans("AssignTaskToUser", '...'); 1630 } 1631 1632 print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask)); 1633 } 1634 print '</td>'; 1635 1636 print "</tr>\n"; 1637 } 1638 1639 $inc++; 1640 $level++; 1641 if ($lines[$i]->id > 0) { 1642 //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level); 1643 //var_dump($totalforeachday); 1644 $ret = projectLinesPerDay($inc, $lines[$i]->id, $fuser, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $preselectedday, $isavailable, $oldprojectforbreak, $arrayfields, $extrafields); 1645 //var_dump('ret with parent='.$lines[$i]->id.' level='.$level); 1646 //var_dump($ret); 1647 foreach ($ret as $key => $val) { 1648 $totalforeachday[$key] += $val; 1649 } 1650 //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks'); 1651 //var_dump($totalforeachday); 1652 } 1653 $level--; 1654 } else { 1655 //$level--; 1656 } 1657 } 1658 1659 return $totalforeachday; 1660} 1661 1662 1663/** 1664 * Output a task line into a perday intput mode 1665 * 1666 * @param string $inc Line output identificator (start to 0, then increased by recursive call) 1667 * @param int $firstdaytoshow First day to show 1668 * @param User|null $fuser Restrict list to user if defined 1669 * @param string $parent Id of parent task to show (0 to show all) 1670 * @param Task[] $lines Array of lines (list of tasks but we will show only if we have a specific role on task) 1671 * @param int $level Level (start to 0, then increased/decrease by recursive call) 1672 * @param string $projectsrole Array of roles user has on project 1673 * @param string $tasksrole Array of roles user has on task 1674 * @param string $mine Show only task lines I am assigned to 1675 * @param int $restricteditformytask 0=No restriction, 1=Enable add time only if task is assigned to me, 2=Enable add time only if tasks is assigned to me and hide others 1676 * @param array $isavailable Array with data that say if user is available for several days for morning and afternoon 1677 * @param int $oldprojectforbreak Old project id of last project break 1678 * @param array $arrayfields Array of additional column 1679 * @param Extrafields $extrafields Object extrafields 1680 * @return array Array with time spent for $fuser for each day of week on tasks in $lines and substasks 1681 */ 1682function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak = 0, $arrayfields = array(), $extrafields = null) 1683{ 1684 global $conf, $db, $user, $langs; 1685 global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic; 1686 1687 $numlines = count($lines); 1688 1689 $lastprojectid = 0; 1690 $workloadforid = array(); 1691 $totalforeachday = array(); 1692 $lineswithoutlevel0 = array(); 1693 1694 // Create a smaller array with sublevels only to be used later. This increase dramatically performances. 1695 if ($parent == 0) { // Always and only if at first level 1696 for ($i = 0; $i < $numlines; $i++) { 1697 if ($lines[$i]->fk_task_parent) { 1698 $lineswithoutlevel0[] = $lines[$i]; 1699 } 1700 } 1701 } 1702 1703 //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0)); 1704 1705 if (empty($oldprojectforbreak)) { 1706 $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 = start break, -1 = never break 1707 } 1708 1709 for ($i = 0; $i < $numlines; $i++) { 1710 if ($parent == 0) { 1711 $level = 0; 1712 } 1713 1714 if ($lines[$i]->fk_task_parent == $parent) { 1715 $obj = &$lines[$i]; // To display extrafields 1716 1717 // If we want all or we have a role on task, we show it 1718 if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) { 1719 //dol_syslog("projectLinesPerWeek Found line ".$i.", a qualified task (i have role or want to show all tasks) with id=".$lines[$i]->id." project id=".$lines[$i]->fk_project); 1720 1721 if ($restricteditformytask == 2 && empty($tasksrole[$lines[$i]->id])) { // we have no role on task and we request to hide such cases 1722 continue; 1723 } 1724 1725 // Break on a new project 1726 if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) { 1727 $lastprojectid = $lines[$i]->fk_project; 1728 $projectstatic->id = $lines[$i]->fk_project; 1729 } 1730 1731 //var_dump('--- '.$level.' '.$firstdaytoshow.' '.$fuser->id.' '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]); 1732 //var_dump($projectstatic->weekWorkLoadPerTask); 1733 if (empty($workloadforid[$projectstatic->id])) { 1734 $projectstatic->loadTimeSpent($firstdaytoshow, 0, $fuser->id); // Load time spent from table projet_task_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week 1735 $workloadforid[$projectstatic->id] = 1; 1736 } 1737 //var_dump($projectstatic->weekWorkLoadPerTask); 1738 //var_dump('--- '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]); 1739 1740 $projectstatic->id = $lines[$i]->fk_project; 1741 $projectstatic->ref = $lines[$i]->projectref; 1742 $projectstatic->title = $lines[$i]->projectlabel; 1743 $projectstatic->public = $lines[$i]->public; 1744 $projectstatic->thirdparty_name = $lines[$i]->thirdparty_name; 1745 $projectstatic->status = $lines[$i]->projectstatus; 1746 1747 $taskstatic->id = $lines[$i]->id; 1748 $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id); 1749 $taskstatic->label = $lines[$i]->label; 1750 $taskstatic->date_start = $lines[$i]->date_start; 1751 $taskstatic->date_end = $lines[$i]->date_end; 1752 1753 $thirdpartystatic->id = $lines[$i]->thirdparty_id; 1754 $thirdpartystatic->name = $lines[$i]->thirdparty_name; 1755 $thirdpartystatic->email = $lines[$i]->thirdparty_email; 1756 1757 if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) { 1758 $addcolspan = 0; 1759 if (!empty($arrayfields['t.planned_workload']['checked'])) { 1760 $addcolspan++; 1761 } 1762 if (!empty($arrayfields['t.progress']['checked'])) { 1763 $addcolspan++; 1764 } 1765 foreach ($arrayfields as $key => $val) { 1766 if ($val['checked'] && substr($key, 0, 5) == 'efpt.') { 1767 $addcolspan++; 1768 } 1769 } 1770 1771 print '<tr class="oddeven trforbreak nobold">'."\n"; 1772 print '<td colspan="'.(11 + $addcolspan).'">'; 1773 print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]); 1774 if ($thirdpartystatic->id > 0) { 1775 print ' - '.$thirdpartystatic->getNomUrl(1); 1776 } 1777 if ($projectstatic->title) { 1778 print ' - '; 1779 print '<span class="secondary">'.$projectstatic->title.'</span>'; 1780 } 1781 1782 /*$colspan=5+(empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:2); 1783 print '<table class="">'; 1784 1785 print '<tr class="liste_titre">'; 1786 1787 // PROJECT fields 1788 if (! empty($arrayfields['p.fk_opp_status']['checked'])) print_liste_field_titre($arrayfields['p.fk_opp_status']['label'], $_SERVER["PHP_SELF"], 'p.fk_opp_status', "", $param, '', $sortfield, $sortorder, 'center '); 1789 if (! empty($arrayfields['p.opp_amount']['checked'])) print_liste_field_titre($arrayfields['p.opp_amount']['label'], $_SERVER["PHP_SELF"], 'p.opp_amount', "", $param, '', $sortfield, $sortorder, 'right '); 1790 if (! empty($arrayfields['p.opp_percent']['checked'])) print_liste_field_titre($arrayfields['p.opp_percent']['label'], $_SERVER["PHP_SELF"], 'p.opp_percent', "", $param, '', $sortfield, $sortorder, 'right '); 1791 if (! empty($arrayfields['p.budget_amount']['checked'])) print_liste_field_titre($arrayfields['p.budget_amount']['label'], $_SERVER["PHP_SELF"], 'p.budget_amount', "", $param, '', $sortfield, $sortorder, 'right '); 1792 if (! empty($arrayfields['p.usage_bill_time']['checked'])) print_liste_field_titre($arrayfields['p.usage_bill_time']['label'], $_SERVER["PHP_SELF"], 'p.usage_bill_time', "", $param, '', $sortfield, $sortorder, 'right '); 1793 1794 $extrafieldsobjectkey='projet'; 1795 $extrafieldsobjectprefix='efp.'; 1796 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; 1797 1798 print '</tr>'; 1799 print '<tr>'; 1800 1801 // PROJECT fields 1802 if (! empty($arrayfields['p.fk_opp_status']['checked'])) 1803 { 1804 print '<td class="nowrap">'; 1805 $code = dol_getIdFromCode($db, $lines[$i]->fk_opp_status, 'c_lead_status', 'rowid', 'code'); 1806 if ($code) print $langs->trans("OppStatus".$code); 1807 print "</td>\n"; 1808 } 1809 if (! empty($arrayfields['p.opp_amount']['checked'])) 1810 { 1811 print '<td class="nowrap">'; 1812 print price($lines[$i]->opp_amount, 0, $langs, 1, 0, -1, $conf->currency); 1813 print "</td>\n"; 1814 } 1815 if (! empty($arrayfields['p.opp_percent']['checked'])) 1816 { 1817 print '<td class="nowrap">'; 1818 print price($lines[$i]->opp_percent, 0, $langs, 1, 0).' %'; 1819 print "</td>\n"; 1820 } 1821 if (! empty($arrayfields['p.budget_amount']['checked'])) 1822 { 1823 print '<td class="nowrap">'; 1824 print price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency); 1825 print "</td>\n"; 1826 } 1827 if (! empty($arrayfields['p.usage_bill_time']['checked'])) 1828 { 1829 print '<td class="nowrap">'; 1830 print yn($lines[$i]->usage_bill_time); 1831 print "</td>\n"; 1832 } 1833 1834 $extrafieldsobjectkey='projet'; 1835 $extrafieldsobjectprefix='efp.'; 1836 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; 1837 1838 print '</tr>'; 1839 print '</table>'; 1840 */ 1841 1842 print '</td>'; 1843 print '</tr>'; 1844 } 1845 1846 if ($oldprojectforbreak != -1) { 1847 $oldprojectforbreak = $projectstatic->id; 1848 } 1849 1850 print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n"; 1851 1852 // User 1853 /* 1854 print '<td class="nowrap">'; 1855 print $fuser->getNomUrl(1, 'withproject', 'time'); 1856 print '</td>'; 1857 */ 1858 1859 // Project 1860 if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) { 1861 print '<td class="nowrap">'; 1862 if ($oldprojectforbreak == -1) { 1863 print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]); 1864 } 1865 print "</td>"; 1866 } 1867 1868 // Thirdparty 1869 if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) { 1870 print '<td class="tdoverflowmax100">'; 1871 if ($thirdpartystatic->id > 0) { 1872 print $thirdpartystatic->getNomUrl(1, 'project'); 1873 } 1874 print '</td>'; 1875 } 1876 1877 // Ref 1878 print '<td class="nowrap">'; 1879 print '<!-- Task id = '.$lines[$i]->id.' -->'; 1880 for ($k = 0; $k < $level; $k++) { 1881 print '<div class="marginleftonly">'; 1882 } 1883 print $taskstatic->getNomUrl(1, 'withproject', 'time'); 1884 // Label task 1885 print '<br>'; 1886 print '<span class="opacitymedium">'.$taskstatic->label.'</span>'; 1887 for ($k = 0; $k < $level; $k++) { 1888 print "</div>"; 1889 } 1890 print "</td>\n"; 1891 1892 // TASK extrafields 1893 $extrafieldsobjectkey = 'projet_task'; 1894 $extrafieldsobjectprefix = 'efpt.'; 1895 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; 1896 1897 // Planned Workload 1898 if (!empty($arrayfields['t.planned_workload']['checked'])) { 1899 print '<td class="leftborder plannedworkload right">'; 1900 if ($lines[$i]->planned_workload) { 1901 print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin'); 1902 } else { 1903 print '--:--'; 1904 } 1905 print '</td>'; 1906 } 1907 1908 if (!empty($arrayfields['t.progress']['checked'])) { 1909 // Progress declared % 1910 print '<td class="right">'; 1911 print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress'); 1912 print '</td>'; 1913 } 1914 1915 if (!empty($arrayfields['timeconsumed']['checked'])) { 1916 // Time spent by everybody 1917 print '<td class="right">'; 1918 // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consummed by user 1919 if ($lines[$i]->duration) { 1920 print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">'; 1921 print convertSecondToTime($lines[$i]->duration, 'allhourmin'); 1922 print '</a>'; 1923 } else { 1924 print '--:--'; 1925 } 1926 print "</td>\n"; 1927 1928 // Time spent by user 1929 print '<td class="right">'; 1930 $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id); 1931 if ($tmptimespent['total_duration']) { 1932 print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin'); 1933 } else { 1934 print '--:--'; 1935 } 1936 print "</td>\n"; 1937 } 1938 1939 $disabledproject = 1; 1940 $disabledtask = 1; 1941 //print "x".$lines[$i]->fk_project; 1942 //var_dump($lines[$i]); 1943 //var_dump($projectsrole[$lines[$i]->fk_project]); 1944 // If at least one role for project 1945 if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) { 1946 $disabledproject = 0; 1947 $disabledtask = 0; 1948 } 1949 // If $restricteditformytask is on and I have no role on task, i disable edit 1950 if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) { 1951 $disabledtask = 1; 1952 } 1953 1954 //var_dump($projectstatic->weekWorkLoadPerTask); 1955 1956 // Fields to show current time 1957 $tableCell = ''; 1958 $modeinput = 'hours'; 1959 for ($idw = 0; $idw < 7; $idw++) { 1960 $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd'); 1961 1962 $cssonholiday = ''; 1963 if (!$isavailable[$tmpday]['morning'] && !$isavailable[$tmpday]['afternoon']) { 1964 $cssonholiday .= 'onholidayallday '; 1965 } elseif (!$isavailable[$tmpday]['morning']) { 1966 $cssonholiday .= 'onholidaymorning '; 1967 } elseif (!$isavailable[$tmpday]['afternoon']) { 1968 $cssonholiday .= 'onholidayafternoon '; 1969 } 1970 1971 $tmparray = dol_getdate($tmpday); 1972 $dayWorkLoad = $projectstatic->weekWorkLoadPerTask[$tmpday][$lines[$i]->id]; 1973 $totalforeachday[$tmpday] += $dayWorkLoad; 1974 1975 $alreadyspent = ''; 1976 if ($dayWorkLoad > 0) { 1977 $alreadyspent = convertSecondToTime($dayWorkLoad, 'allhourmin'); 1978 } 1979 $alttitle = $langs->trans("AddHereTimeSpentForDay", $tmparray['day'], $tmparray['mon']); 1980 1981 global $numstartworkingday, $numendworkingday; 1982 $cssweekend = ''; 1983 if (($idw + 1 < $numstartworkingday) || ($idw + 1 > $numendworkingday)) { // This is a day is not inside the setup of working days, so we use a week-end css. 1984 $cssweekend = 'weekend'; 1985 } 1986 1987 $tableCell = '<td class="center hide'.$idw.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">'; 1988 //$tableCell .= 'idw='.$idw.' '.$conf->global->MAIN_START_WEEK.' '.$numstartworkingday.'-'.$numendworkingday; 1989 $placeholder = ''; 1990 if ($alreadyspent) { 1991 $tableCell .= '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center smallpadd" size="2" disabled id="timespent['.$inc.']['.$idw.']" name="task['.$lines[$i]->id.']['.$idw.']" value="'.$alreadyspent.'"></span>'; 1992 //$placeholder=' placeholder="00:00"'; 1993 //$tableCell.='+'; 1994 } 1995 $tableCell .= '<input type="text" alt="'.($disabledtask ? '' : $alttitle).'" title="'.($disabledtask ? '' : $alttitle).'" '.($disabledtask ? 'disabled' : $placeholder).' class="center smallpadd" size="2" id="timeadded['.$inc.']['.$idw.']" name="task['.$lines[$i]->id.']['.$idw.']" value="" cols="2" maxlength="5"'; 1996 $tableCell .= ' onkeypress="return regexEvent(this,event,\'timeChar\')"'; 1997 $tableCell .= ' onkeyup="updateTotal('.$idw.',\''.$modeinput.'\')"'; 1998 $tableCell .= ' onblur="regexEvent(this,event,\''.$modeinput.'\'); updateTotal('.$idw.',\''.$modeinput.'\')" />'; 1999 $tableCell .= '</td>'; 2000 print $tableCell; 2001 } 2002 2003 // Warning 2004 print '<td class="right">'; 2005 if ((!$lines[$i]->public) && $disabledproject) { 2006 print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject")); 2007 } elseif ($disabledtask) { 2008 $titleassigntask = $langs->trans("AssignTaskToMe"); 2009 if ($fuser->id != $user->id) { 2010 $titleassigntask = $langs->trans("AssignTaskToUser", '...'); 2011 } 2012 2013 print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask)); 2014 } 2015 print '</td>'; 2016 2017 print "</tr>\n"; 2018 } 2019 2020 // Call to show task with a lower level (task under the current task) 2021 $inc++; 2022 $level++; 2023 if ($lines[$i]->id > 0) { 2024 //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level); 2025 //var_dump($totalforeachday); 2026 $ret = projectLinesPerWeek($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $arrayfields, $extrafields); 2027 //var_dump('ret with parent='.$lines[$i]->id.' level='.$level); 2028 //var_dump($ret); 2029 foreach ($ret as $key => $val) { 2030 $totalforeachday[$key] += $val; 2031 } 2032 //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks'); 2033 //var_dump($totalforeachday); 2034 } 2035 $level--; 2036 } else { 2037 //$level--; 2038 } 2039 } 2040 2041 return $totalforeachday; 2042} 2043 2044/** 2045 * Output a task line into a perday intput mode 2046 * 2047 * @param string $inc Line output identificator (start to 0, then increased by recursive call) 2048 * @param int $firstdaytoshow First day to show 2049 * @param User|null $fuser Restrict list to user if defined 2050 * @param string $parent Id of parent task to show (0 to show all) 2051 * @param Task[] $lines Array of lines (list of tasks but we will show only if we have a specific role on task) 2052 * @param int $level Level (start to 0, then increased/decrease by recursive call) 2053 * @param string $projectsrole Array of roles user has on project 2054 * @param string $tasksrole Array of roles user has on task 2055 * @param string $mine Show only task lines I am assigned to 2056 * @param int $restricteditformytask 0=No restriction, 1=Enable add time only if task is a task i am affected to 2057 * @param array $isavailable Array with data that say if user is available for several days for morning and afternoon 2058 * @param int $oldprojectforbreak Old project id of last project break 2059 * @param array $TWeek Array of week numbers 2060 * @return array Array with time spent for $fuser for each day of week on tasks in $lines and substasks 2061 */ 2062function projectLinesPerMonth(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak = 0, $TWeek = array()) 2063{ 2064 global $conf, $db, $user, $langs; 2065 global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic; 2066 2067 $numlines = count($lines); 2068 2069 $lastprojectid = 0; 2070 $workloadforid = array(); 2071 $totalforeachweek = array(); 2072 $lineswithoutlevel0 = array(); 2073 2074 // Create a smaller array with sublevels only to be used later. This increase dramatically performances. 2075 if ($parent == 0) { // Always and only if at first level 2076 for ($i = 0; $i < $numlines; $i++) { 2077 if ($lines[$i]->fk_task_parent) { 2078 $lineswithoutlevel0[] = $lines[$i]; 2079 } 2080 } 2081 } 2082 2083 //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0)); 2084 2085 if (empty($oldprojectforbreak)) { 2086 $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 = start break, -1 = never break 2087 } 2088 2089 for ($i = 0; $i < $numlines; $i++) { 2090 if ($parent == 0) { 2091 $level = 0; 2092 } 2093 2094 if ($lines[$i]->fk_task_parent == $parent) { 2095 // If we want all or we have a role on task, we show it 2096 if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) { 2097 //dol_syslog("projectLinesPerWeek Found line ".$i.", a qualified task (i have role or want to show all tasks) with id=".$lines[$i]->id." project id=".$lines[$i]->fk_project); 2098 2099 // Break on a new project 2100 if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) { 2101 $lastprojectid = $lines[$i]->fk_project; 2102 $projectstatic->id = $lines[$i]->fk_project; 2103 } 2104 2105 //var_dump('--- '.$level.' '.$firstdaytoshow.' '.$fuser->id.' '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]); 2106 //var_dump($projectstatic->weekWorkLoadPerTask); 2107 if (empty($workloadforid[$projectstatic->id])) { 2108 $projectstatic->loadTimeSpentMonth($firstdaytoshow, 0, $fuser->id); // Load time spent from table projet_task_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week 2109 $workloadforid[$projectstatic->id] = 1; 2110 } 2111 //var_dump($projectstatic->weekWorkLoadPerTask); 2112 //var_dump('--- '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]); 2113 2114 $projectstatic->id = $lines[$i]->fk_project; 2115 $projectstatic->ref = $lines[$i]->projectref; 2116 $projectstatic->title = $lines[$i]->projectlabel; 2117 $projectstatic->public = $lines[$i]->public; 2118 $projectstatic->thirdparty_name = $lines[$i]->thirdparty_name; 2119 $projectstatic->status = $lines[$i]->projectstatus; 2120 2121 $taskstatic->id = $lines[$i]->id; 2122 $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id); 2123 $taskstatic->label = $lines[$i]->label; 2124 $taskstatic->date_start = $lines[$i]->date_start; 2125 $taskstatic->date_end = $lines[$i]->date_end; 2126 2127 $thirdpartystatic->id = $lines[$i]->thirdparty_id; 2128 $thirdpartystatic->name = $lines[$i]->thirdparty_name; 2129 $thirdpartystatic->email = $lines[$i]->thirdparty_email; 2130 2131 if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) { 2132 print '<tr class="oddeven trforbreak nobold">'."\n"; 2133 print '<td colspan="'.(6 + count($TWeek)).'">'; 2134 print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]); 2135 if ($thirdpartystatic->id > 0) { 2136 print ' - '.$thirdpartystatic->getNomUrl(1); 2137 } 2138 if ($projectstatic->title) { 2139 print ' - '; 2140 print '<span class="secondary">'.$projectstatic->title.'</span>'; 2141 } 2142 print '</td>'; 2143 print '</tr>'; 2144 } 2145 2146 if ($oldprojectforbreak != -1) { 2147 $oldprojectforbreak = $projectstatic->id; 2148 } 2149 print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n"; 2150 2151 // User 2152 /* 2153 print '<td class="nowrap">'; 2154 print $fuser->getNomUrl(1, 'withproject', 'time'); 2155 print '</td>'; 2156 */ 2157 2158 // Project 2159 /*print '<td class="nowrap">'; 2160 if ($oldprojectforbreak == -1) print $projectstatic->getNomUrl(1,'',0,$langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]); 2161 print "</td>";*/ 2162 2163 // Thirdparty 2164 /*print '<td class="tdoverflowmax100">'; 2165 if ($thirdpartystatic->id > 0) print $thirdpartystatic->getNomUrl(1, 'project'); 2166 print '</td>';*/ 2167 2168 // Ref 2169 print '<td class="nowrap">'; 2170 print '<!-- Task id = '.$lines[$i]->id.' -->'; 2171 for ($k = 0; $k < $level; $k++) { 2172 print '<div class="marginleftonly">'; 2173 } 2174 print $taskstatic->getNomUrl(1, 'withproject', 'time'); 2175 // Label task 2176 print '<br>'; 2177 print '<span class="opacitymedium">'.$taskstatic->label.'</span>'; 2178 for ($k = 0; $k < $level; $k++) { 2179 print "</div>"; 2180 } 2181 print "</td>\n"; 2182 2183 // Planned Workload 2184 print '<td class="leftborder plannedworkload right">'; 2185 if ($lines[$i]->planned_workload) { 2186 print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin'); 2187 } else { 2188 print '--:--'; 2189 } 2190 print '</td>'; 2191 2192 // Progress declared % 2193 print '<td class="right">'; 2194 print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress'); 2195 print '</td>'; 2196 2197 // Time spent by everybody 2198 print '<td class="right">'; 2199 // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consummed by user 2200 if ($lines[$i]->duration) { 2201 print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">'; 2202 print convertSecondToTime($lines[$i]->duration, 'allhourmin'); 2203 print '</a>'; 2204 } else { 2205 print '--:--'; 2206 } 2207 print "</td>\n"; 2208 2209 // Time spent by user 2210 print '<td class="right">'; 2211 $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id); 2212 if ($tmptimespent['total_duration']) { 2213 print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin'); 2214 } else { 2215 print '--:--'; 2216 } 2217 print "</td>\n"; 2218 2219 $disabledproject = 1; 2220 $disabledtask = 1; 2221 //print "x".$lines[$i]->fk_project; 2222 //var_dump($lines[$i]); 2223 //var_dump($projectsrole[$lines[$i]->fk_project]); 2224 // If at least one role for project 2225 if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) { 2226 $disabledproject = 0; 2227 $disabledtask = 0; 2228 } 2229 // If $restricteditformytask is on and I have no role on task, i disable edit 2230 if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) { 2231 $disabledtask = 1; 2232 } 2233 2234 //var_dump($projectstatic->weekWorkLoadPerTask); 2235 //TODO 2236 // Fields to show current time 2237 $tableCell = ''; 2238 $modeinput = 'hours'; 2239 $TFirstDay = getFirstDayOfEachWeek($TWeek, date('Y', $firstdaytoshow)); 2240 $TFirstDay[reset($TWeek)] = 1; 2241 foreach ($TFirstDay as &$fday) { 2242 $fday--; 2243 } 2244 foreach ($TWeek as $weekNb) { 2245 $weekWorkLoad = $projectstatic->monthWorkLoadPerTask[$weekNb][$lines[$i]->id]; 2246 $totalforeachweek[$weekNb] += $weekWorkLoad; 2247 2248 $alreadyspent = ''; 2249 if ($weekWorkLoad > 0) { 2250 $alreadyspent = convertSecondToTime($weekWorkLoad, 'allhourmin'); 2251 } 2252 $alttitle = $langs->trans("AddHereTimeSpentForWeek", $weekNb); 2253 2254 2255 $tableCell = '<td class="center hide weekend">'; 2256 $placeholder = ''; 2257 if ($alreadyspent) { 2258 $tableCell .= '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center smallpadd" size="2" disabled id="timespent['.$inc.']['.((int) $weekNb).']" name="task['.$lines[$i]->id.']['.$weekNb.']" value="'.$alreadyspent.'"></span>'; 2259 //$placeholder=' placeholder="00:00"'; 2260 //$tableCell.='+'; 2261 } 2262 2263 $tableCell .= '<input type="text" alt="'.($disabledtask ? '' : $alttitle).'" title="'.($disabledtask ? '' : $alttitle).'" '.($disabledtask ? 'disabled' : $placeholder).' class="center smallpadd" size="2" id="timeadded['.$inc.']['.((int) $weekNb).']" name="task['.$lines[$i]->id.']['.$TFirstDay[$weekNb].']" value="" cols="2" maxlength="5"'; 2264 $tableCell .= ' onkeypress="return regexEvent(this,event,\'timeChar\')"'; 2265 $tableCell .= ' onkeyup="updateTotal('.$weekNb.',\''.$modeinput.'\')"'; 2266 $tableCell .= ' onblur="regexEvent(this,event,\''.$modeinput.'\'); updateTotal('.$weekNb.',\''.$modeinput.'\')" />'; 2267 $tableCell .= '</td>'; 2268 print $tableCell; 2269 } 2270 2271 // Warning 2272 print '<td class="right">'; 2273 if ((!$lines[$i]->public) && $disabledproject) { 2274 print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject")); 2275 } elseif ($disabledtask) { 2276 $titleassigntask = $langs->trans("AssignTaskToMe"); 2277 if ($fuser->id != $user->id) { 2278 $titleassigntask = $langs->trans("AssignTaskToUser", '...'); 2279 } 2280 2281 print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask)); 2282 } 2283 print '</td>'; 2284 2285 print "</tr>\n"; 2286 } 2287 2288 // Call to show task with a lower level (task under the current task) 2289 $inc++; 2290 $level++; 2291 if ($lines[$i]->id > 0) { 2292 //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level); 2293 //var_dump($totalforeachday); 2294 $ret = projectLinesPerMonth($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $TWeek); 2295 //var_dump('ret with parent='.$lines[$i]->id.' level='.$level); 2296 //var_dump($ret); 2297 foreach ($ret as $key => $val) { 2298 $totalforeachweek[$key] += $val; 2299 } 2300 //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks'); 2301 //var_dump($totalforeachday); 2302 } 2303 $level--; 2304 } else { 2305 //$level--; 2306 } 2307 } 2308 2309 return $totalforeachweek; 2310} 2311 2312 2313/** 2314 * Search in task lines with a particular parent if there is a task for a particular user (in taskrole) 2315 * 2316 * @param string $inc Counter that count number of lines legitimate to show (for return) 2317 * @param int $parent Id of parent task to start 2318 * @param array $lines Array of all tasks 2319 * @param string $taskrole Array of task filtered on a particular user 2320 * @return int 1 if there is 2321 */ 2322function searchTaskInChild(&$inc, $parent, &$lines, &$taskrole) 2323{ 2324 //print 'Search in line with parent id = '.$parent.'<br>'; 2325 $numlines = count($lines); 2326 for ($i = 0; $i < $numlines; $i++) { 2327 // Process line $lines[$i] 2328 if ($lines[$i]->fk_parent == $parent && $lines[$i]->id != $lines[$i]->fk_parent) { 2329 // If task is legitimate to show, no more need to search deeper 2330 if (isset($taskrole[$lines[$i]->id])) { 2331 //print 'Found a legitimate task id='.$lines[$i]->id.'<br>'; 2332 $inc++; 2333 return $inc; 2334 } 2335 2336 searchTaskInChild($inc, $lines[$i]->id, $lines, $taskrole); 2337 //print 'Found inc='.$inc.'<br>'; 2338 2339 if ($inc > 0) { 2340 return $inc; 2341 } 2342 } 2343 } 2344 2345 return $inc; 2346} 2347 2348/** 2349 * Return HTML table with list of projects and number of opened tasks 2350 * 2351 * @param DoliDB $db Database handler 2352 * @param Form $form Object form 2353 * @param int $socid Id thirdparty 2354 * @param int $projectsListId Id of project I have permission on 2355 * @param int $mytasks Limited to task I am contact to 2356 * @param int $status -1=No filter on statut, 0 or 1 = Filter on status 2357 * @param array $listofoppstatus List of opportunity status 2358 * @param array $hiddenfields List of info to not show ('projectlabel', 'declaredprogress', '...', ) 2359 * @return void 2360 */ 2361function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks = 0, $status = -1, $listofoppstatus = array(), $hiddenfields = array()) 2362{ 2363 global $langs, $conf, $user; 2364 global $theme_datacolor; 2365 2366 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; 2367 2368 $listofstatus = array_keys($listofoppstatus); 2369 2370 if (is_array($listofstatus) && !empty($conf->global->USE_COLOR_FOR_PROSPECTION_STATUS)) { 2371 // Define $themeColorId and array $statusOppList for each $listofstatus 2372 $themeColorId = 0; 2373 $statusOppList = array(); 2374 foreach ($listofstatus as $oppStatus) { 2375 $oppStatusCode = dol_getIdFromCode($db, $oppStatus, 'c_lead_status', 'rowid', 'code'); 2376 if ($oppStatusCode) { 2377 $statusOppList[$oppStatus]['code'] = $oppStatusCode; 2378 $statusOppList[$oppStatus]['color'] = isset($theme_datacolor[$themeColorId]) ? implode(', ', $theme_datacolor[$themeColorId]) : ''; 2379 } 2380 $themeColorId++; 2381 } 2382 } 2383 2384 $projectstatic = new Project($db); 2385 $thirdpartystatic = new Societe($db); 2386 2387 $sortfield = ''; 2388 $sortorder = ''; 2389 $project_year_filter = 0; 2390 2391 $title = $langs->trans("Projects"); 2392 if (strcmp($status, '') && $status >= 0) { 2393 $title = $langs->trans("Projects").' '.$langs->trans($projectstatic->statuts_long[$status]); 2394 } 2395 2396 $arrayidtypeofcontact = array(); 2397 2398 print '<div class="div-table-responsive-no-min">'; 2399 print '<table class="noborder centpercent">'; 2400 2401 $sql = " FROM ".MAIN_DB_PREFIX."projet as p"; 2402 if ($mytasks) { 2403 $sql .= ", ".MAIN_DB_PREFIX."projet_task as t"; 2404 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec"; 2405 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc"; 2406 } else { 2407 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t ON p.rowid = t.fk_projet"; 2408 } 2409 $sql .= " WHERE p.entity IN (".getEntity('project').")"; 2410 $sql .= " AND p.rowid IN (".$db->sanitize($projectsListId).")"; 2411 if ($socid) { 2412 $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")"; 2413 } 2414 if ($mytasks) { 2415 $sql .= " AND p.rowid = t.fk_projet"; 2416 $sql .= " AND ec.element_id = t.rowid"; 2417 $sql .= " AND ec.fk_socpeople = ".((int) $user->id); 2418 $sql .= " AND ec.fk_c_type_contact = ctc.rowid"; // Replace the 2 lines with ec.fk_c_type_contact in $arrayidtypeofcontact 2419 $sql .= " AND ctc.element = 'project_task'"; 2420 } 2421 if ($status >= 0) { 2422 $sql .= " AND p.fk_statut = ".(int) $status; 2423 } 2424 if (!empty($conf->global->PROJECT_LIMIT_YEAR_RANGE)) { 2425 $project_year_filter = GETPOST("project_year_filter"); 2426 //Check if empty or invalid year. Wildcard ignores the sql check 2427 if ($project_year_filter != "*") { 2428 if (empty($project_year_filter) || !ctype_digit($project_year_filter)) { 2429 $project_year_filter = date("Y"); 2430 } 2431 $sql .= " AND (p.dateo IS NULL OR p.dateo <= ".$db->idate(dol_get_last_day($project_year_filter, 12, false)).")"; 2432 $sql .= " AND (p.datee IS NULL OR p.datee >= ".$db->idate(dol_get_first_day($project_year_filter, 1, false)).")"; 2433 } 2434 } 2435 2436 // Get id of project we must show tasks 2437 $arrayidofprojects = array(); 2438 $sql1 = "SELECT p.rowid as projectid"; 2439 $sql1 .= $sql; 2440 $resql = $db->query($sql1); 2441 if ($resql) { 2442 $i = 0; 2443 $num = $db->num_rows($resql); 2444 while ($i < $num) { 2445 $objp = $db->fetch_object($resql); 2446 $arrayidofprojects[$objp->projectid] = $objp->projectid; 2447 $i++; 2448 } 2449 } else { 2450 dol_print_error($db); 2451 } 2452 if (empty($arrayidofprojects)) { 2453 $arrayidofprojects[0] = -1; 2454 } 2455 2456 // Get list of project with calculation on tasks 2457 $sql2 = "SELECT p.rowid as projectid, p.ref, p.title, p.fk_soc,"; 2458 $sql2 .= " s.rowid as socid, s.nom as socname, s.name_alias,"; 2459 $sql2 .= " s.code_client, s.code_compta, s.client,"; 2460 $sql2 .= " s.code_fournisseur, s.code_compta_fournisseur, s.fournisseur,"; 2461 $sql2 .= " s.logo, s.email, s.entity,"; 2462 $sql2 .= " p.fk_user_creat, p.public, p.fk_statut as status, p.fk_opp_status as opp_status, p.opp_percent, p.opp_amount,"; 2463 $sql2 .= " p.dateo, p.datee,"; 2464 $sql2 .= " COUNT(t.rowid) as nb, SUM(t.planned_workload) as planned_workload, SUM(t.planned_workload * t.progress / 100) as declared_progess_workload"; 2465 $sql2 .= " FROM ".MAIN_DB_PREFIX."projet as p"; 2466 $sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = p.fk_soc"; 2467 $sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t ON p.rowid = t.fk_projet"; 2468 $sql2 .= " WHERE p.rowid IN (".$db->sanitize(join(',', $arrayidofprojects)).")"; 2469 $sql2 .= " GROUP BY p.rowid, p.ref, p.title, p.fk_soc, s.rowid, s.nom, s.name_alias, s.code_client, s.code_compta, s.client, s.code_fournisseur, s.code_compta_fournisseur, s.fournisseur,"; 2470 $sql2 .= " s.logo, s.email, s.entity, p.fk_user_creat, p.public, p.fk_statut, p.fk_opp_status, p.opp_percent, p.opp_amount, p.dateo, p.datee"; 2471 $sql2 .= " ORDER BY p.title, p.ref"; 2472 2473 $resql = $db->query($sql2); 2474 if ($resql) { 2475 $total_task = 0; 2476 $total_opp_amount = 0; 2477 $ponderated_opp_amount = 0; 2478 2479 $num = $db->num_rows($resql); 2480 $i = 0; 2481 2482 print '<tr class="liste_titre">'; 2483 print_liste_field_titre($title.'<a href="'.DOL_URL_ROOT.'/projet/list.php?search_status='.((int) $status).'"><span class="badge marginleftonlyshort">'.$num.'</span></a>', $_SERVER["PHP_SELF"], "", "", "", "", $sortfield, $sortorder); 2484 print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "", "", "", "", $sortfield, $sortorder); 2485 if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) { 2486 if (!in_array('prospectionstatus', $hiddenfields)) { 2487 print_liste_field_titre("OpportunityStatus", "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'center '); 2488 } 2489 print_liste_field_titre($form->textwithpicto($langs->trans("Amount"), $langs->trans("OpportunityAmount").' ('.$langs->trans("Tooltip").' = '.$langs->trans("OpportunityWeightedAmount").')'), "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'right '); 2490 //print_liste_field_titre('OpportunityWeightedAmount', '', '', '', '', 'align="right"', $sortfield, $sortorder); 2491 } 2492 if (empty($conf->global->PROJECT_HIDE_TASKS)) { 2493 print_liste_field_titre("Tasks", "", "", "", "", 'align="right"', $sortfield, $sortorder); 2494 if (!in_array('plannedworkload', $hiddenfields)) { 2495 print_liste_field_titre("PlannedWorkload", "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'right '); 2496 } 2497 if (!in_array('declaredprogress', $hiddenfields)) { 2498 print_liste_field_titre("%", "", "", "", "", '', $sortfield, $sortorder, 'right ', $langs->trans("ProgressDeclared")); 2499 } 2500 } 2501 if (!in_array('projectstatus', $hiddenfields)) { 2502 print_liste_field_titre("Status", "", "", "", "", '', $sortfield, $sortorder, 'right '); 2503 } 2504 print "</tr>\n"; 2505 2506 $total_plannedworkload = 0; 2507 $total_declaredprogressworkload = 0; 2508 while ($i < $num) { 2509 $objp = $db->fetch_object($resql); 2510 2511 $projectstatic->id = $objp->projectid; 2512 $projectstatic->user_author_id = $objp->fk_user_creat; 2513 $projectstatic->public = $objp->public; 2514 2515 // Check is user has read permission on project 2516 $userAccess = $projectstatic->restrictedProjectArea($user); 2517 if ($userAccess >= 0) { 2518 $projectstatic->ref = $objp->ref; 2519 $projectstatic->status = $objp->status; 2520 $projectstatic->title = $objp->title; 2521 $projectstatic->datee = $db->jdate($objp->datee); 2522 $projectstatic->dateo = $db->jdate($objp->dateo); 2523 2524 print '<tr class="oddeven">'; 2525 2526 print '<td class="tdoverflowmax150">'; 2527 print $projectstatic->getNomUrl(1, '', 0, '', '-', 0, -1, 'nowraponall'); 2528 if (!in_array('projectlabel', $hiddenfields)) { 2529 print '<br><span class="opacitymedium">'.dol_trunc($objp->title, 24).'</span>'; 2530 } 2531 print '</td>'; 2532 2533 print '<td class="nowraponall tdoverflowmax100">'; 2534 if ($objp->fk_soc > 0) { 2535 $thirdpartystatic->id = $objp->socid; 2536 $thirdpartystatic->name = $objp->socname; 2537 //$thirdpartystatic->name_alias = $objp->name_alias; 2538 //$thirdpartystatic->code_client = $objp->code_client; 2539 $thirdpartystatic->code_compta = $objp->code_compta; 2540 $thirdpartystatic->client = $objp->client; 2541 //$thirdpartystatic->code_fournisseur = $objp->code_fournisseur; 2542 $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur; 2543 $thirdpartystatic->fournisseur = $objp->fournisseur; 2544 $thirdpartystatic->logo = $objp->logo; 2545 $thirdpartystatic->email = $objp->email; 2546 $thirdpartystatic->entity = $objp->entity; 2547 print $thirdpartystatic->getNomUrl(1); 2548 } 2549 print '</td>'; 2550 2551 if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) { 2552 if (!in_array('prospectionstatus', $hiddenfields)) { 2553 print '<td class="center tdoverflowmax75">'; 2554 // Because color of prospection status has no meaning yet, it is used if hidden constant is set 2555 if (empty($conf->global->USE_COLOR_FOR_PROSPECTION_STATUS)) { 2556 $oppStatusCode = dol_getIdFromCode($db, $objp->opp_status, 'c_lead_status', 'rowid', 'code'); 2557 if ($langs->trans("OppStatus".$oppStatusCode) != "OppStatus".$oppStatusCode) { 2558 print $langs->trans("OppStatus".$oppStatusCode); 2559 } 2560 } else { 2561 if (isset($statusOppList[$objp->opp_status])) { 2562 $oppStatusCode = $statusOppList[$objp->opp_status]['code']; 2563 $oppStatusColor = $statusOppList[$objp->opp_status]['color']; 2564 } else { 2565 $oppStatusCode = dol_getIdFromCode($db, $objp->opp_status, 'c_lead_status', 'rowid', 'code'); 2566 $oppStatusColor = ''; 2567 } 2568 if ($oppStatusCode) { 2569 if (!empty($oppStatusColor)) { 2570 print '<a href="'.dol_buildpath('/projet/list.php?search_opp_status='.$objp->opp_status, 1).'" style="display: inline-block; width: 4px; border: 5px solid rgb('.$oppStatusColor.'); border-radius: 2px;" title="'.$langs->trans("OppStatus".$oppStatusCode).'"></a>'; 2571 } else { 2572 print '<a href="'.dol_buildpath('/projet/list.php?search_opp_status='.$objp->opp_status, 1).'" title="'.$langs->trans("OppStatus".$oppStatusCode).'">'.$oppStatusCode.'</a>'; 2573 } 2574 } 2575 } 2576 print '</td>'; 2577 } 2578 2579 print '<td class="right">'; 2580 if ($objp->opp_percent && $objp->opp_amount) { 2581 $opp_weighted_amount = $objp->opp_percent * $objp->opp_amount / 100; 2582 $alttext = $langs->trans("OpportunityWeightedAmount").' '.price($opp_weighted_amount, 0, '', 1, -1, 0, $conf->currency); 2583 $ponderated_opp_amount += price2num($opp_weighted_amount); 2584 } 2585 if ($objp->opp_amount) { 2586 print '<span class="amount" title="'.$alttext.'">'.$form->textwithpicto(price($objp->opp_amount, 0, '', 1, -1, 0), $alttext).'</span>'; 2587 } 2588 print '</td>'; 2589 } 2590 2591 if (empty($conf->global->PROJECT_HIDE_TASKS)) { 2592 print '<td class="right">'.$objp->nb.'</td>'; 2593 2594 $plannedworkload = $objp->planned_workload; 2595 $total_plannedworkload += $plannedworkload; 2596 if (!in_array('plannedworkload', $hiddenfields)) { 2597 print '<td class="right">'.($plannedworkload ?convertSecondToTime($plannedworkload) : '').'</td>'; 2598 } 2599 if (!in_array('declaredprogress', $hiddenfields)) { 2600 $declaredprogressworkload = $objp->declared_progess_workload; 2601 $total_declaredprogressworkload += $declaredprogressworkload; 2602 print '<td class="right">'; 2603 //print $objp->planned_workload.'-'.$objp->declared_progess_workload."<br>"; 2604 print ($plannedworkload ?round(100 * $declaredprogressworkload / $plannedworkload, 0).'%' : ''); 2605 print '</td>'; 2606 } 2607 } 2608 2609 if (!in_array('projectstatus', $hiddenfields)) { 2610 print '<td class="right">'; 2611 print $projectstatic->getLibStatut(3); 2612 print '</td>'; 2613 } 2614 2615 print "</tr>\n"; 2616 2617 $total_task = $total_task + $objp->nb; 2618 $total_opp_amount = $total_opp_amount + $objp->opp_amount; 2619 } 2620 2621 $i++; 2622 } 2623 2624 print '<tr class="liste_total">'; 2625 print '<td>'.$langs->trans("Total")."</td><td></td>"; 2626 if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) { 2627 if (!in_array('prospectionstatus', $hiddenfields)) { 2628 print '<td class="liste_total"></td>'; 2629 } 2630 print '<td class="liste_total right">'; 2631 //$form->textwithpicto(price($ponderated_opp_amount, 0, '', 1, -1, -1, $conf->currency), $langs->trans("OpportunityPonderatedAmountDesc"), 1); 2632 print $form->textwithpicto(price($total_opp_amount, 0, '', 1, -1, 0), $langs->trans("OpportunityPonderatedAmountDesc").' : '.price($ponderated_opp_amount, 0, '', 1, -1, 0, $conf->currency)); 2633 print '</td>'; 2634 } 2635 if (empty($conf->global->PROJECT_HIDE_TASKS)) { 2636 print '<td class="liste_total right">'.$total_task.'</td>'; 2637 if (!in_array('plannedworkload', $hiddenfields)) { 2638 print '<td class="liste_total right">'.($total_plannedworkload ?convertSecondToTime($total_plannedworkload) : '').'</td>'; 2639 } 2640 if (!in_array('declaredprogress', $hiddenfields)) { 2641 print '<td class="liste_total right">'.($total_plannedworkload ?round(100 * $total_declaredprogressworkload / $total_plannedworkload, 0).'%' : '').'</td>'; 2642 } 2643 } 2644 if (!in_array('projectstatus', $hiddenfields)) { 2645 print '<td class="liste_total"></td>'; 2646 } 2647 print '</tr>'; 2648 2649 $db->free($resql); 2650 } else { 2651 dol_print_error($db); 2652 } 2653 2654 print "</table>"; 2655 print '</div>'; 2656 2657 if (!empty($conf->global->PROJECT_LIMIT_YEAR_RANGE)) { 2658 //Add the year filter input 2659 print '<form method="get" action="'.$_SERVER["PHP_SELF"].'">'; 2660 print '<table width="100%">'; 2661 print '<tr>'; 2662 print '<td>'.$langs->trans("Year").'</td>'; 2663 print '<td class="right"><input type="text" size="4" class="flat" name="project_year_filter" value="'.$project_year_filter.'"/>'; 2664 print "</tr>\n"; 2665 print '</table></form>'; 2666 } 2667} 2668 2669/** 2670 * @param Task $task the task object 2671 * @param bool|string $label true = auto, false = dont display, string = replace output 2672 * @param bool|string $progressNumber true = auto, false = dont display, string = replace output 2673 * @param bool $hideOnProgressNull hide if progress is null 2674 * @param bool $spaced used to add space at bottom (made by css) 2675 * @return string 2676 * @see getTaskProgressBadge() 2677 */ 2678function getTaskProgressView($task, $label = true, $progressNumber = true, $hideOnProgressNull = false, $spaced = false) 2679{ 2680 global $langs, $conf; 2681 2682 $out = ''; 2683 2684 $plannedworkloadoutputformat = 'allhourmin'; 2685 $timespentoutputformat = 'allhourmin'; 2686 if (!empty($conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT)) { 2687 $plannedworkloadoutputformat = $conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT; 2688 } 2689 if (!empty($conf->global->PROJECT_TIMES_SPENT_FORMAT)) { 2690 $timespentoutputformat = $conf->global->PROJECT_TIME_SPENT_FORMAT; 2691 } 2692 2693 if (empty($task->progress) && !empty($hideOnProgressNull)) { 2694 return ''; 2695 } 2696 2697 $spaced = !empty($spaced) ? 'spaced' : ''; 2698 2699 $diff = ''; 2700 2701 // define progress color according to time spend vs workload 2702 $progressBarClass = 'progress-bar-info'; 2703 $progressCalculated = 0; 2704 if ($task->planned_workload) { 2705 $progressCalculated = round(100 * floatval($task->duration_effective) / floatval($task->planned_workload), 2); 2706 2707 // this conf is actually hidden, by default we use 10% for "be carefull or warning" 2708 $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10; 2709 2710 $diffTitle = '<br>'.$langs->trans('ProgressDeclared').' : '.$task->progress.($task->progress ? '%' : ''); 2711 $diffTitle .= '<br>'.$langs->trans('ProgressCalculated').' : '.$progressCalculated.($progressCalculated ? '%' : ''); 2712 2713 //var_dump($progressCalculated.' '.$warningRatio.' '.$task->progress.' '.floatval($task->progress * $warningRatio)); 2714 if (floatval($progressCalculated) > floatval($task->progress * $warningRatio)) { 2715 $progressBarClass = 'progress-bar-danger'; 2716 $title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress - $progressCalculated).' '.$langs->trans("point")); 2717 $diff = '<span class="text-danger classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-down"></i> '.($task->progress - $progressCalculated).'%</span>'; 2718 } elseif (floatval($progressCalculated) > floatval($task->progress)) { // warning if close at 10% 2719 $progressBarClass = 'progress-bar-warning'; 2720 $title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress - $progressCalculated).' '.$langs->trans("point")); 2721 $diff = '<span class="text-warning classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-left"></i> '.($task->progress - $progressCalculated).'%</span>'; 2722 } else { 2723 $progressBarClass = 'progress-bar-success'; 2724 $title = $langs->trans('TheReportedProgressIsMoreThanTheCalculatedProgressionByX', ($task->progress - $progressCalculated).' '.$langs->trans("point")); 2725 $diff = '<span class="text-success classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-up"></i> '.($task->progress - $progressCalculated).'%</span>'; 2726 } 2727 } 2728 2729 $out .= '<div class="progress-group">'; 2730 2731 if ($label !== false) { 2732 $out .= ' <span class="progress-text">'; 2733 2734 if ($label !== true) { 2735 $out .= $label; // replace label by param 2736 } else { 2737 $out .= $task->getNomUrl(1).' '.dol_htmlentities($task->label); 2738 } 2739 $out .= ' </span>'; 2740 } 2741 2742 2743 if ($progressNumber !== false) { 2744 $out .= ' <span class="progress-number">'; 2745 if ($progressNumber !== true) { 2746 $out .= $progressNumber; // replace label by param 2747 } else { 2748 if ($task->hasDelay()) { 2749 $out .= img_warning($langs->trans("Late")).' '; 2750 } 2751 2752 $url = DOL_URL_ROOT.'/projet/tasks/time.php?id='.$task->id; 2753 2754 $out .= !empty($diff) ? $diff.' ' : ''; 2755 $out .= '<a href="'.$url.'" >'; 2756 $out .= '<b title="'.$langs->trans('TimeSpent').'" >'; 2757 if ($task->duration_effective) { 2758 $out .= convertSecondToTime($task->duration_effective, $timespentoutputformat); 2759 } else { 2760 $out .= '--:--'; 2761 } 2762 $out .= '</b>'; 2763 $out .= '</a>'; 2764 2765 $out .= ' / '; 2766 2767 $out .= '<a href="'.$url.'" >'; 2768 $out .= '<span title="'.$langs->trans('PlannedWorkload').'" >'; 2769 if ($task->planned_workload) { 2770 $out .= convertSecondToTime($task->planned_workload, $plannedworkloadoutputformat); 2771 } else { 2772 $out .= '--:--'; 2773 } 2774 $out .= '</a>'; 2775 } 2776 $out .= ' </span>'; 2777 } 2778 2779 2780 $out .= '</span>'; 2781 $out .= ' <div class="progress sm '.$spaced.'">'; 2782 $diffval = floatval($task->progress) - floatval($progressCalculated); 2783 if ($diffval >= 0) { 2784 // good 2785 $out .= ' <div class="progress-bar '.$progressBarClass.'" style="width: '.floatval($task->progress).'%" title="'.floatval($task->progress).'%">'; 2786 if (!empty($task->progress)) { 2787 $out .= ' <div class="progress-bar progress-bar-consumed" style="width: '.floatval($progressCalculated / $task->progress * 100).'%" title="'.floatval($progressCalculated).'%"></div>'; 2788 } 2789 $out .= ' </div>'; 2790 } else { 2791 // bad 2792 $out .= ' <div class="progress-bar progress-bar-consumed" style="width: '.floatval($progressCalculated).'%" title="'.floatval($progressCalculated).'%">'; 2793 $out .= ' <div class="progress-bar '.$progressBarClass.'" style="width: '.($task->progress ? floatval($task->progress / $progressCalculated * 100).'%' : '1px').'" title="'.floatval($task->progress).'%"></div>'; 2794 $out .= ' </div>'; 2795 } 2796 $out .= ' </div>'; 2797 $out .= '</div>'; 2798 2799 2800 2801 return $out; 2802} 2803/** 2804 * @param Task $task the task object 2805 * @param string $label empty = auto (progress), string = replace output 2806 * @param string $tooltip empty = auto , string = replace output 2807 * @return string 2808 * @see getTaskProgressView() 2809 */ 2810function getTaskProgressBadge($task, $label = '', $tooltip = '') 2811{ 2812 global $conf, $langs; 2813 2814 $out = ''; 2815 $badgeClass = ''; 2816 if ($task->progress != '') { 2817 // TODO : manage 100% 2818 2819 // define color according to time spend vs workload 2820 $badgeClass = 'badge '; 2821 if ($task->planned_workload) { 2822 $progressCalculated = round(100 * floatval($task->duration_effective) / floatval($task->planned_workload), 2); 2823 2824 // this conf is actually hidden, by default we use 10% for "be carefull or warning" 2825 $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10; 2826 2827 if (floatval($progressCalculated) > floatval($task->progress * $warningRatio)) { 2828 $badgeClass .= 'badge-danger'; 2829 if (empty($tooltip)) { 2830 $tooltip = $task->progress.'% < '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%'; 2831 } 2832 } elseif (floatval($progressCalculated) > floatval($task->progress)) { // warning if close at 10% 2833 $badgeClass .= 'badge-warning'; 2834 if (empty($tooltip)) { 2835 $tooltip = $task->progress.'% < '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%'; 2836 } 2837 } else { 2838 $badgeClass .= 'badge-success'; 2839 if (empty($tooltip)) { 2840 $tooltip = $task->progress.'% >= '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%'; 2841 } 2842 } 2843 } 2844 } 2845 2846 $title = ''; 2847 if (!empty($tooltip)) { 2848 $badgeClass .= ' classfortooltip'; 2849 $title = 'title="'.dol_htmlentities($tooltip).'"'; 2850 } 2851 2852 if (empty($label)) { 2853 $label = $task->progress.' %'; 2854 } 2855 2856 if (!empty($label)) { 2857 $out = '<span class="'.$badgeClass.'" '.$title.' >'.$label.'</span>'; 2858 } 2859 2860 return $out; 2861} 2862