1<?php 2/* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org> 3 * Copyright (C) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net> 4 * Copyright (C) 2005-2010 Regis Houssin <regis.houssin@inodbox.com> 5 * Copyright (C) 2010 François Legastelois <flegastelois@teclib.com> 6 * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22/** 23 * \file htdocs/projet/activity/perweek.php 24 * \ingroup projet 25 * \brief List activities of tasks (per week entry) 26 */ 27 28require "../../main.inc.php"; 29require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; 30require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; 31require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php'; 32require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; 33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; 34require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; 35require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; 36require_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php'; 37 38// Load translation files required by the page 39$langs->loadLangs(array('projects', 'users', 'companies')); 40 41$action = GETPOST('action', 'aZ09'); 42$mode = GETPOST("mode", 'alpha'); 43$id = GETPOST('id', 'int'); 44$taskid = GETPOST('taskid', 'int'); 45 46$contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'perweekcard'; 47 48$mine = 0; 49if ($mode == 'mine') $mine = 1; 50 51$projectid = isset($_GET["id"]) ? GETPOST("id", "int", 1) : GETPOST("projectid", "int"); 52 53$hookmanager->initHooks(array('timesheetperweekcard')); 54 55// Security check 56$socid = 0; 57// For external user, no check is done on company because readability is managed by public status of project and assignement. 58// if ($user->socid > 0) $socid=$user->socid; 59$result = restrictedArea($user, 'projet', $projectid); 60 61$now = dol_now(); 62$nowtmp = dol_getdate($now); 63$nowday = $nowtmp['mday']; 64$nowmonth = $nowtmp['mon']; 65$nowyear = $nowtmp['year']; 66 67$year = GETPOST('reyear', 'int') ?GETPOST('reyear', 'int') : (GETPOST("year", 'int') ?GETPOST("year", "int") : date("Y")); 68$month = GETPOST('remonth', 'int') ?GETPOST('remonth', 'int') : (GETPOST("month", 'int') ?GETPOST("month", "int") : date("m")); 69$day = GETPOST('reday', 'int') ?GETPOST('reday', 'int') : (GETPOST("day", 'int') ?GETPOST("day", "int") : date("d")); 70$week = GETPOST("week", "int") ?GETPOST("week", "int") : date("W"); 71 72$day = (int) $day; 73 74$search_categ = GETPOST("search_categ", 'alpha'); 75$search_usertoprocessid = GETPOST('search_usertoprocessid', 'int'); 76$search_task_ref = GETPOST('search_task_ref', 'alpha'); 77$search_task_label = GETPOST('search_task_label', 'alpha'); 78$search_project_ref = GETPOST('search_project_ref', 'alpha'); 79$search_thirdparty = GETPOST('search_thirdparty', 'alpha'); 80$search_declared_progress = GETPOST('search_declared_progress', 'alpha'); 81 82$startdayarray = dol_get_first_day_week($day, $month, $year); 83 84$prev = $startdayarray; 85$prev_year = $prev['prev_year']; 86$prev_month = $prev['prev_month']; 87$prev_day = $prev['prev_day']; 88$first_day = $prev['first_day']; 89$first_month = $prev['first_month']; 90$first_year = $prev['first_year']; 91$week = $prev['week']; 92 93$next = dol_get_next_week($first_day, $week, $first_month, $first_year); 94$next_year = $next['year']; 95$next_month = $next['month']; 96$next_day = $next['day']; 97 98// Define firstdaytoshow and lastdaytoshow (warning: lastdaytoshow is last second to show + 1) 99$firstdaytoshow = dol_mktime(0, 0, 0, $first_month, $first_day, $first_year); 100$lastdaytoshow = dol_time_plus_duree($firstdaytoshow, 7, 'd'); 101 102if (empty($search_usertoprocessid) || $search_usertoprocessid == $user->id) 103{ 104 $usertoprocess = $user; 105 $search_usertoprocessid = $usertoprocess->id; 106} elseif ($search_usertoprocessid > 0) 107{ 108 $usertoprocess = new User($db); 109 $usertoprocess->fetch($search_usertoprocessid); 110 $search_usertoprocessid = $usertoprocess->id; 111} else { 112 $usertoprocess = new User($db); 113} 114 115$object = new Task($db); 116 117// Extra fields 118$extrafields = new ExtraFields($db); 119 120// fetch optionals attributes and labels 121$extrafields->fetch_name_optionals_label($object->table_element); 122 123$arrayfields = array(); 124/*$arrayfields=array( 125 // Project 126 'p.opp_amount'=>array('label'=>$langs->trans("OpportunityAmountShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>103), 127 'p.fk_opp_status'=>array('label'=>$langs->trans("OpportunityStatusShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>104), 128 'p.opp_percent'=>array('label'=>$langs->trans("OpportunityProbabilityShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>105), 129 'p.budget_amount'=>array('label'=>$langs->trans("Budget"), 'checked'=>0, 'position'=>110), 130 'p.usage_bill_time'=>array('label'=>$langs->trans("BillTimeShort"), 'checked'=>0, 'position'=>115), 131);*/ 132$arrayfields['t.planned_workload'] = array('label'=>'PlannedWorkload', 'checked'=>1, 'enabled'=>1, 'position'=>0); 133$arrayfields['t.progress'] = array('label'=>'ProgressDeclared', 'checked'=>1, 'enabled'=>1, 'position'=>0); 134/*foreach($object->fields as $key => $val) 135{ 136 // If $val['visible']==0, then we never show the field 137 if (! empty($val['visible'])) $arrayfields['t.'.$key]=array('label'=>$val['label'], 'checked'=>(($val['visible']<0)?0:1), 'enabled'=>$val['enabled'], 'position'=>$val['position']); 138}*/ 139// Definition of fields for list 140// Extra fields 141if (is_array($extrafields->attributes['projet_task']['label']) && count($extrafields->attributes['projet_task']['label']) > 0) 142{ 143 foreach ($extrafields->attributes['projet_task']['label'] as $key => $val) 144 { 145 if (!empty($extrafields->attributes['projet_task']['list'][$key])) 146 $arrayfields["efpt.".$key] = array('label'=>$extrafields->attributes['projet_task']['label'][$key], 'checked'=>(($extrafields->attributes['projet_task']['list'][$key] < 0) ? 0 : 1), 'position'=>$extrafields->attributes['projet_task']['pos'][$key], 'enabled'=>(abs((int) $extrafields->attributes['projet_task']['list'][$key]) != 3 && $extrafields->attributes['projet_task']['perms'][$key])); 147 } 148} 149$arrayfields = dol_sort_array($arrayfields, 'position'); 150 151$search_array_options = array(); 152$search_array_options_project = $extrafields->getOptionalsFromPost('projet', '', 'search_'); 153$search_array_options_task = $extrafields->getOptionalsFromPost('projet_task', '', 'search_task_'); 154 155 156 157/* 158 * Actions 159 */ 160 161$parameters = array('id' => $id, 'taskid' => $taskid, 'projectid' => $projectid); 162$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks 163if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); 164// Purge criteria 165if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers 166{ 167 $action = ''; 168 $search_categ = ''; 169 $search_usertoprocessid = $user->id; 170 $search_task_ref = ''; 171 $search_task_label = ''; 172 $search_project_ref = ''; 173 $search_thirdparty = ''; 174 $search_declared_progress = ''; 175 176 $search_array_options_project = array(); 177 $search_array_options_task = array(); 178 179 // We redefine $usertoprocess 180 $usertoprocess = $user; 181} 182if (GETPOST("button_search_x", 'alpha') || GETPOST("button_search.x", 'alpha') || GETPOST("button_search", 'alpha')) 183{ 184 $action = ''; 185} 186 187if (GETPOST('submitdateselect')) 188{ 189 $daytoparse = dol_mktime(0, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear')); 190 191 $action = ''; 192} 193 194include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; 195 196if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask') && GETPOST('formfilteraction') != 'listafterchangingselectedfields') 197{ 198 $action = 'assigntask'; 199 200 if ($taskid > 0) 201 { 202 $result = $object->fetch($taskid, $ref); 203 if ($result < 0) $error++; 204 } else { 205 setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Task")), '', 'errors'); 206 $error++; 207 } 208 if (!GETPOST('type')) 209 { 210 setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), '', 'errors'); 211 $error++; 212 } 213 214 if (!$error) 215 { 216 $idfortaskuser = $usertoprocess->id; 217 $result = $object->add_contact($idfortaskuser, GETPOST("type"), 'internal'); 218 219 if ($result >= 0 || $result == -2) // Contact add ok or already contact of task 220 { 221 // Test if we are already contact of the project (should be rare but sometimes we can add as task contact without being contact of project, like when admin user has been removed from contact of project) 222 $sql = 'SELECT ec.rowid FROM '.MAIN_DB_PREFIX.'element_contact as ec, '.MAIN_DB_PREFIX.'c_type_contact as tc WHERE tc.rowid = ec.fk_c_type_contact'; 223 $sql .= ' AND ec.fk_socpeople = '.((int) $idfortaskuser)." AND ec.element_id = ".((int) $object->fk_project)." AND tc.element = 'project' AND source = 'internal'"; 224 $resql = $db->query($sql); 225 if ($resql) 226 { 227 $obj = $db->fetch_object($resql); 228 if (!$obj) // User is not already linked to project, so we will create link to first type 229 { 230 $project = new Project($db); 231 $project->fetch($object->fk_project); 232 // Get type 233 $listofprojcontact = $project->liste_type_contact('internal'); 234 235 if (count($listofprojcontact)) 236 { 237 $typeforprojectcontact = reset(array_keys($listofprojcontact)); 238 $result = $project->add_contact($idfortaskuser, $typeforprojectcontact, 'internal'); 239 } 240 } 241 } else { 242 dol_print_error($db); 243 } 244 } 245 } 246 247 if ($result < 0) 248 { 249 $error++; 250 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') 251 { 252 $langs->load("errors"); 253 setEventMessages($langs->trans("ErrorTaskAlreadyAssigned"), null, 'warnings'); 254 } else { 255 setEventMessages($object->error, $object->errors, 'errors'); 256 } 257 } 258 259 if (!$error) 260 { 261 setEventMessages("TaskAssignedToEnterTime", null); 262 $taskid = 0; 263 } 264 265 $action = ''; 266} 267 268if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('formfilteraction') != 'listafterchangingselectedfields') 269{ 270 $timetoadd = $_POST['task']; 271 if (empty($timetoadd)) 272 { 273 setEventMessages($langs->trans("ErrorTimeSpentIsEmpty"), null, 'errors'); 274 } else { 275 foreach ($timetoadd as $taskid => $value) // Loop on each task 276 { 277 $updateoftaskdone = 0; 278 foreach ($value as $key => $val) // Loop on each day 279 { 280 $amountoadd = $timetoadd[$taskid][$key]; 281 if (!empty($amountoadd)) 282 { 283 $tmpduration = explode(':', $amountoadd); 284 $newduration = 0; 285 if (!empty($tmpduration[0])) $newduration += ($tmpduration[0] * 3600); 286 if (!empty($tmpduration[1])) $newduration += ($tmpduration[1] * 60); 287 if (!empty($tmpduration[2])) $newduration += ($tmpduration[2]); 288 289 if ($newduration > 0) 290 { 291 $object->fetch($taskid); 292 293 if (GETPOSTISSET($taskid.'progress')) $object->progress = GETPOST($taskid.'progress', 'int'); 294 else unset($object->progress); 295 296 $object->timespent_duration = $newduration; 297 $object->timespent_fk_user = $usertoprocess->id; 298 $object->timespent_date = dol_time_plus_duree($firstdaytoshow, $key, 'd'); 299 $object->timespent_datehour = $object->timespent_date; 300 $object->timespent_note = $object->description; 301 302 $result = $object->addTimeSpent($user); 303 if ($result < 0) 304 { 305 setEventMessages($object->error, $object->errors, 'errors'); 306 $error++; 307 break; 308 } 309 310 $updateoftaskdone++; 311 } 312 } 313 } 314 315 if (!$updateoftaskdone) // Check to update progress if no update were done on task. 316 { 317 $object->fetch($taskid); 318 //var_dump($object->progress);var_dump(GETPOST($taskid . 'progress', 'int')); exit; 319 if ($object->progress != GETPOST($taskid.'progress', 'int')) 320 { 321 $object->progress = GETPOST($taskid.'progress', 'int'); 322 $result = $object->update($user); 323 if ($result < 0) 324 { 325 setEventMessages($object->error, $object->errors, 'errors'); 326 $error++; 327 break; 328 } 329 } 330 } 331 } 332 333 if (!$error) 334 { 335 setEventMessages($langs->trans("RecordSaved"), null, 'mesgs'); 336 337 $param = ''; 338 $param .= ($mode ? '&mode='.urlencode($mode) : ''); 339 $param .= ($projectid ? 'id='.urlencode($projectid) : ''); 340 $param .= ($search_usertoprocessid ? '&search_usertoprocessid='.urlencode($search_usertoprocessid) : ''); 341 $param .= ($day ? '&day='.urlencode($day) : '').($month ? '&month='.urlencode($month) : '').($year ? '&year='.urlencode($year) : ''); 342 $param .= ($search_project_ref ? '&search_project_ref='.urlencode($search_project_ref) : ''); 343 $param .= ($search_usertoprocessid > 0 ? '&search_usertoprocessid='.urlencode($search_usertoprocessid) : ''); 344 $param .= ($search_thirdparty ? '&search_thirdparty='.urlencode($search_thirdparty) : ''); 345 $param .= ($search_declared_progress ? '&search_declared_progress='.urlencode($search_declared_progress) : ''); 346 $param .= ($search_task_ref ? '&search_task_ref='.urlencode($search_task_ref) : ''); 347 $param .= ($search_task_label ? '&search_task_label='.urlencode($search_task_label) : ''); 348 349 /*$search_array_options=$search_array_options_project; 350 $search_options_pattern='search_options_'; 351 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; 352 */ 353 354 $search_array_options = $search_array_options_task; 355 $search_options_pattern = 'search_task_options_'; 356 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; 357 358 // Redirect to avoid submit twice on back 359 header('Location: '.$_SERVER["PHP_SELF"].'?'.$param); 360 exit; 361 } 362 } 363} 364 365 366/* 367 * View 368 */ 369 370$form = new Form($db); 371$formother = new FormOther($db); 372$formcompany = new FormCompany($db); 373$formproject = new FormProjets($db); 374$projectstatic = new Project($db); 375$project = new Project($db); 376$taskstatic = new Task($db); 377$thirdpartystatic = new Societe($db); 378$holiday = new Holiday($db); 379 380$title = $langs->trans("TimeSpent"); 381 382$projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertoprocess, (empty($usertoprocess->id) ? 2 : 0), 1); // Return all project i have permission on (assigned to me+public). I want my tasks and some of my task may be on a public projet that is not my project 383//var_dump($projectsListId); 384if ($id) 385{ 386 $project->fetch($id); 387 $project->fetch_thirdparty(); 388} 389 390$onlyopenedproject = 1; // or -1 391$morewherefilter = ''; 392 393if ($search_project_ref) $morewherefilter .= natural_search(array("p.ref", "p.title"), $search_project_ref); 394if ($search_task_ref) $morewherefilter .= natural_search("t.ref", $search_task_ref); 395if ($search_task_label) $morewherefilter .= natural_search(array("t.ref", "t.label"), $search_task_label); 396if ($search_thirdparty) $morewherefilter .= natural_search("s.nom", $search_thirdparty); 397if ($search_declared_progress) $morewherefilter .= natural_search("t.progress", $search_declared_progress, 1); 398 399$sql = &$morewherefilter; 400 401/*$search_array_options = $search_array_options_project; 402$extrafieldsobjectprefix='efp.'; 403$search_options_pattern='search_options_'; 404$extrafieldsobjectkey='projet'; 405include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; 406*/ 407$search_array_options = $search_array_options_task; 408$extrafieldsobjectprefix = 'efpt.'; 409$search_options_pattern = 'search_task_options_'; 410$extrafieldsobjectkey = 'projet_task'; 411include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; 412 413$tasksarray = $taskstatic->getTasksArray(0, 0, ($project->id ? $project->id : 0), $socid, 0, $search_project_ref, $onlyopenedproject, $morewherefilter, ($search_usertoprocessid ? $search_usertoprocessid : 0), 0, $extrafields); // We want to see all tasks of open project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later. 414if ($morewherefilter) // Get all task without any filter, so we can show total of time spent for not visible tasks 415{ 416 $tasksarraywithoutfilter = $taskstatic->getTasksArray(0, 0, ($project->id ? $project->id : 0), $socid, 0, '', $onlyopenedproject, '', ($search_usertoprocessid ? $search_usertoprocessid : 0)); // We want to see all tasks of open project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later. 417} 418$projectsrole = $taskstatic->getUserRolesForProjectsOrTasks($usertoprocess, 0, ($project->id ? $project->id : 0), 0, $onlyopenedproject); 419$tasksrole = $taskstatic->getUserRolesForProjectsOrTasks(0, $usertoprocess, ($project->id ? $project->id : 0), 0, $onlyopenedproject); 420//var_dump($tasksarray); 421//var_dump($projectsrole); 422//var_dump($taskrole); 423 424 425llxHeader("", $title, "", '', '', '', array('/core/js/timesheet.js')); 426 427//print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num, '', 'project'); 428 429$param = ''; 430$param .= ($mode ? '&mode='.urlencode($mode) : ''); 431$param .= ($search_project_ref ? '&search_project_ref='.urlencode($search_project_ref) : ''); 432$param .= ($search_usertoprocessid > 0 ? '&search_usertoprocessid='.urlencode($search_usertoprocessid) : ''); 433$param .= ($search_thirdparty ? '&search_thirdparty='.urlencode($search_thirdparty) : ''); 434$param .= ($search_task_ref ? '&search_task_ref='.urlencode($search_task_ref) : ''); 435$param .= ($search_task_label ? '&search_task_label='.urlencode($search_task_label) : ''); 436 437$search_array_options = $search_array_options_project; 438$search_options_pattern = 'search_options_'; 439include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; 440 441$search_array_options = $search_array_options_task; 442$search_options_pattern = 'search_task_options_'; 443include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; 444 445// Show navigation bar 446$nav = '<a class="inline-block valignmiddle" href="?year='.$prev_year."&month=".$prev_month."&day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n"; 447$nav .= " <span id=\"month_name\">".dol_print_date(dol_mktime(0, 0, 0, $first_month, $first_day, $first_year), "%Y").", ".$langs->trans("WeekShort")." ".$week." </span>\n"; 448$nav .= '<a class="inline-block valignmiddle" href="?year='.$next_year."&month=".$next_month."&day=".$next_day.$param.'">'.img_next($langs->trans("Next"))."</a>\n"; 449//$nav .= " (<a href=\"?year=".$nowyear."&month=".$nowmonth."&day=".$nowday.$param."\">".$langs->trans("Today")."</a>)"; 450$nav .= ' '.$form->selectDate(-1, '', 0, 0, 2, "addtime", 1, 1).' '; 451//$nav .= ' <input type="submit" name="submitdateselect" class="button" value="'.$langs->trans("Refresh").'">'; 452$nav .= ' <button type="submit" name="submitdateselect" value="x" class="bordertransp"><span class="fa fa-search"></span></button>'; 453 454$picto = 'clock'; 455 456print '<form name="addtime" method="POST" action="'.$_SERVER["PHP_SELF"].'">'; 457print '<input type="hidden" name="token" value="'.newToken().'">'; 458print '<input type="hidden" name="action" value="addtime">'; 459print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">'; 460print '<input type="hidden" name="contextpage" value="'.$contextpage.'">'; 461print '<input type="hidden" name="mode" value="'.$mode.'">'; 462print '<input type="hidden" name="day" value="'.$day.'">'; 463print '<input type="hidden" name="month" value="'.$month.'">'; 464print '<input type="hidden" name="year" value="'.$year.'">'; 465 466$head = project_timesheet_prepare_head($mode, $usertoprocess); 467print dol_get_fiche_head($head, 'inputperweek', $langs->trans('TimeSpent'), -1, $picto); 468 469// Show description of content 470print '<div class="hideonsmartphone opacitymedium">'; 471if ($mine || ($usertoprocess->id == $user->id)) print $langs->trans("MyTasksDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>'; 472else { 473 if (empty($usertoprocess->id) || $usertoprocess->id < 0) 474 { 475 if ($user->rights->projet->all->lire && !$socid) print $langs->trans("ProjectsDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>'; 476 else print $langs->trans("ProjectsPublicTaskDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>'; 477 } 478} 479if ($mine || ($usertoprocess->id == $user->id)) 480{ 481 print $langs->trans("OnlyYourTaskAreVisible").'<br>'; 482} else { 483 print $langs->trans("AllTaskVisibleButEditIfYouAreAssigned").'<br>'; 484} 485print '</div>'; 486 487print dol_get_fiche_end(); 488 489print '<div class="floatright right'.($conf->dol_optimize_smallscreen ? ' centpercent' : '').'">'.$nav.'</div>'; // We move this before the assign to components so, the default submit button is not the assign to. 490 491print '<div class="colorbacktimesheet float valignmiddle">'; 492$titleassigntask = $langs->transnoentities("AssignTaskToMe"); 493if ($usertoprocess->id != $user->id) $titleassigntask = $langs->transnoentities("AssignTaskToUser", $usertoprocess->getFullName($langs)); 494print '<div class="taskiddiv inline-block">'; 495print img_picto('', 'projecttask'); 496$formproject->selectTasks($socid ? $socid : -1, $taskid, 'taskid', 32, 0, '-- '.$langs->trans("ChooseANotYetAssignedTask").' --', 1, 0, 0, '', '', 'all', $usertoprocess); 497print '</div>'; 498print ' '; 499print $formcompany->selectTypeContact($object, '', 'type', 'internal', 'rowid', 0, 'maxwidth150onsmartphone'); 500print '<input type="submit" class="button valignmiddle" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">'; 501print '</div>'; 502 503print '<div class="clearboth" style="padding-bottom: 20px;"></div>'; 504 505 506$startday = dol_mktime(12, 0, 0, $startdayarray['first_month'], $startdayarray['first_day'], $startdayarray['first_year']); 507 508// Get if user is available or not for each day 509$isavailable = array(); 510if (!empty($conf->global->MAIN_DEFAULT_WORKING_DAYS)) 511{ 512 $tmparray = explode('-', $conf->global->MAIN_DEFAULT_WORKING_DAYS); 513 if (count($tmparray) >= 2) 514 { 515 $numstartworkingday = $tmparray[0]; 516 $numendworkingday = $tmparray[1]; 517 } 518} 519 520for ($idw = 0; $idw < 7; $idw++) 521{ 522 $dayinloopfromfirstdaytoshow = dol_time_plus_duree($firstdaytoshow, $idw, 'd'); // $firstdaytoshow is a date with hours = 0 523 $dayinloop = dol_time_plus_duree($startday, $idw, 'd'); 524 525 // Useless because $dayinloopwithouthours should be same than $dayinloopfromfirstdaytoshow 526 //$tmparray = dol_getdate($dayinloop); 527 //$dayinloopwithouthours=dol_mktime(0, 0, 0, $tmparray['mon'], $tmparray['mday'], $tmparray['year']); 528 //print dol_print_date($dayinloop, 'dayhour').' '; 529 //print dol_print_date($dayinloopwithouthours, 'dayhour').' '; 530 //print dol_print_date($dayinloopfromfirstdaytoshow, 'dayhour').'<br>'; 531 532 $statusofholidaytocheck = Holiday::STATUS_APPROVED; 533 534 $isavailablefordayanduser = $holiday->verifDateHolidayForTimestamp($usertoprocess->id, $dayinloopfromfirstdaytoshow, $statusofholidaytocheck); 535 $isavailable[$dayinloopfromfirstdaytoshow] = $isavailablefordayanduser; // in projectLinesPerWeek later, we are using $firstdaytoshow and dol_time_plus_duree to loop on each day 536 537 $test = num_public_holiday($dayinloopfromfirstdaytoshow, $dayinloopfromfirstdaytoshow + 86400, $mysoc->country_code); 538 if ($test) $isavailable[$dayinloopfromfirstdaytoshow] = array('morning'=>false, 'afternoon'=>false, 'morning_reason'=>'public_holiday', 'afternoon_reason'=>'public_holiday'); 539} 540//var_dump($isavailable); 541 542 543 544$moreforfilter = ''; 545 546// Filter on categories 547/* 548if (! empty($conf->categorie->enabled)) 549{ 550 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php'; 551 $moreforfilter.='<div class="divsearchfield">'; 552 $moreforfilter.=$langs->trans('ProjectCategories'). ': '; 553 $moreforfilter.=$formother->select_categories('project', $search_categ, 'search_categ', 1, 1, 'maxwidth300'); 554 $moreforfilter.='</div>'; 555}*/ 556 557// If the user can view user other than himself 558$moreforfilter .= '<div class="divsearchfield">'; 559$moreforfilter .= '<div class="inline-block hideonsmartphone"></div>'; 560$includeonly = 'hierarchyme'; 561if (empty($user->rights->user->user->lire)) $includeonly = array($user->id); 562$moreforfilter .= img_picto($langs->trans('User'), 'user').$form->select_dolusers($search_usertoprocessid ? $search_usertoprocessid : $usertoprocess->id, 'search_usertoprocessid', $user->rights->user->user->lire ? 0 : 0, null, 0, $includeonly, null, 0, 0, 0, '', 0, '', 'maxwidth200'); 563$moreforfilter .= '</div>'; 564 565if (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) 566{ 567 $moreforfilter .= '<div class="divsearchfield">'; 568 $moreforfilter .= '<div class="inline-block"></div>'; 569 $moreforfilter .= img_picto($langs->trans('Project'), 'project').'<input type="text" size="4" name="search_project_ref" class="marginleftonly" value="'.dol_escape_htmltag($search_project_ref).'">'; 570 $moreforfilter .= '</div>'; 571 572 $moreforfilter .= '<div class="divsearchfield">'; 573 $moreforfilter .= '<div class="inline-block"></div>'; 574 $moreforfilter .= img_picto($langs->trans('ThirdParty'), 'company').'<input type="text" size="4" name="search_thirdparty" class="marginleftonly" value="'.dol_escape_htmltag($search_thirdparty).'">'; 575 $moreforfilter .= '</div>'; 576} 577 578if (!empty($moreforfilter)) 579{ 580 print '<div class="liste_titre liste_titre_bydiv centpercent">'; 581 print $moreforfilter; 582 $parameters = array(); 583 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook 584 print $hookmanager->resPrint; 585 print '</div>'; 586} 587 588 589$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; 590 591$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields 592 593// This must be after the $selectedfields 594$addcolspan = 0; 595if (!empty($arrayfields['t.planned_workload']['checked'])) $addcolspan++; 596if (!empty($arrayfields['t.progress']['checked'])) $addcolspan++; 597foreach ($arrayfields as $key => $val) 598{ 599 if ($val['checked'] && substr($key, 0, 5) == 'efpt.') $addcolspan++; 600} 601 602print '<div class="div-table-responsive">'; 603print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'" id="tablelines3">'."\n"; 604 605print '<tr class="liste_titre_filter">'; 606if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) print '<td class="liste_titre"><input type="text" size="4" name="search_project_ref" value="'.dol_escape_htmltag($search_project_ref).'"></td>'; 607if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) print '<td class="liste_titre"><input type="text" size="4" name="search_thirdparty" value="'.dol_escape_htmltag($search_thirdparty).'"></td>'; 608print '<td class="liste_titre"><input type="text" size="4" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>'; 609// TASK fields 610$search_options_pattern = 'search_task_options_'; 611$extrafieldsobjectkey = 'projet_task'; 612$extrafieldsobjectprefix = 'efpt.'; 613include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; 614print '<td class="liste_titre"></td>'; 615if (!empty($arrayfields['t.planned_workload']['checked'])) 616{ 617 print '<td class="liste_titre right"><input type="text" size="4" name="search_declared_progress" value="'.dol_escape_htmltag($search_declared_progress).'"></td>'; 618} 619if (!empty($arrayfields['t.progress']['checked'])) 620{ 621 print '<td class="liste_titre"></td>'; 622} 623print '<td class="liste_titre"></td>'; 624for ($idw = 0; $idw < 7; $idw++) 625{ 626 print '<td class="liste_titre"></td>'; 627} 628// Action column 629print '<td class="liste_titre nowrap right">'; 630$searchpicto = $form->showFilterAndCheckAddButtons(0); 631print $searchpicto; 632print '</td>'; 633print "</tr>\n"; 634 635print '<tr class="liste_titre">'; 636if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) print '<th>'.$langs->trans("Project").'</th>'; 637if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) print '<th>'.$langs->trans("ThirdParty").'</th>'; 638print '<th>'.$langs->trans("Task").'</th>'; 639// TASK fields 640$extrafieldsobjectkey = 'projet_task'; 641$extrafieldsobjectprefix = 'efpt.'; 642include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; 643if (!empty($arrayfields['t.planned_workload']['checked'])) 644{ 645 print '<th class="leftborder plannedworkload maxwidth75 right">'.$langs->trans("PlannedWorkload").'</th>'; 646} 647if (!empty($arrayfields['t.progress']['checked'])) 648{ 649 print '<th class="maxwidth75 right">'.$langs->trans("ProgressDeclared").'</th>'; 650} 651/*print '<td class="maxwidth75 right">'.$langs->trans("TimeSpent").'</td>'; 652 if ($usertoprocess->id == $user->id) print '<td class="maxwidth75 right">'.$langs->trans("TimeSpentByYou").'</td>'; 653 else print '<td class="maxwidth75 right">'.$langs->trans("TimeSpentByUser").'</td>';*/ 654print '<th class="maxwidth75 right">'.$langs->trans("TimeSpent").'<br><span class="opacitymedium">'.$langs->trans("Everybody").'</span></th>'; 655print '<th class="maxwidth75 right">'.$langs->trans("TimeSpent").($usertoprocess->firstname ? '<br><span class="opacitymedium">'.dol_trunc($usertoprocess->firstname, 10).'</span>' : '').'</th>'; 656 657for ($idw = 0; $idw < 7; $idw++) 658{ 659 $dayinloopfromfirstdaytoshow = dol_time_plus_duree($firstdaytoshow, $idw, 'd'); // $firstdaytoshow is a date with hours = 0 660 $dayinloop = dol_time_plus_duree($startday, $idw, 'd'); 661 662 $cssweekend = ''; 663 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. 664 { 665 $cssweekend = 'weekend'; 666 } 667 668 $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd'); 669 670 $cssonholiday = ''; 671 if (!$isavailable[$tmpday]['morning'] && !$isavailable[$tmpday]['afternoon']) $cssonholiday .= 'onholidayallday '; 672 elseif (!$isavailable[$tmpday]['morning']) $cssonholiday .= 'onholidaymorning '; 673 elseif (!$isavailable[$tmpday]['afternoon']) $cssonholiday .= 'onholidayafternoon '; 674 675 print '<th width="6%" align="center" class="bold hide'.$idw.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">'.dol_print_date($dayinloopfromfirstdaytoshow, '%a').'<br>'.dol_print_date($dayinloopfromfirstdaytoshow, 'dayreduceformat').'</th>'; 676} 677//print '<td></td>'; 678print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); 679 680 681print "</tr>\n"; 682 683$colspan = 3 + (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : 2); 684 685if ($conf->use_javascript_ajax) 686{ 687 print '<tr class="liste_total">'; 688 print '<td class="liste_total" colspan="'.($colspan + $addcolspan).'">'; 689 print $langs->trans("Total"); 690 print '<span class="opacitymediumbycolor"> - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong></span>'; 691 print '</td>'; 692 693 for ($idw = 0; $idw < 7; $idw++) 694 { 695 $cssweekend = ''; 696 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. 697 { 698 $cssweekend = 'weekend'; 699 } 700 701 $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd'); 702 703 $cssonholiday = ''; 704 if (!$isavailable[$tmpday]['morning'] && !$isavailable[$tmpday]['afternoon']) $cssonholiday .= 'onholidayallday '; 705 elseif (!$isavailable[$tmpday]['morning']) $cssonholiday .= 'onholidaymorning '; 706 elseif (!$isavailable[$tmpday]['afternoon']) $cssonholiday .= 'onholidayafternoon '; 707 print '<td class="liste_total hide'.$idw.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'" align="center"><div class="totalDay'.$idw.'"> </div></td>'; 708 } 709 print '<td class="liste_total center"><div class="totalDayAll"> </div></td>'; 710 print '</tr>'; 711} 712 713 714 715// By default, we can edit only tasks we are assigned to 716$restrictviewformytask = ((!isset($conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED)) ? 2 : $conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED); 717if (count($tasksarray) > 0) 718{ 719 //var_dump($tasksarray); // contains only selected tasks 720 //var_dump($tasksarraywithoutfilter); // contains all tasks (if there is a filter, not defined if no filter) 721 //var_dump($tasksrole); 722 723 $j = 0; 724 $level = 0; 725 $totalforvisibletasks = projectLinesPerWeek($j, $firstdaytoshow, $usertoprocess, 0, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restrictviewformytask, $isavailable, 0, $arrayfields, $extrafields); 726 //var_dump($totalforvisibletasks); 727 728 // Show total for all other tasks 729 730 // Calculate total for all tasks 731 $listofdistinctprojectid = array(); // List of all distinct projects 732 if (is_array($tasksarraywithoutfilter) && count($tasksarraywithoutfilter)) 733 { 734 foreach ($tasksarraywithoutfilter as $tmptask) 735 { 736 $listofdistinctprojectid[$tmptask->fk_project] = $tmptask->fk_project; 737 } 738 } 739 //var_dump($listofdistinctprojectid); 740 $totalforeachday = array(); 741 foreach ($listofdistinctprojectid as $tmpprojectid) 742 { 743 $projectstatic->id = $tmpprojectid; 744 $projectstatic->loadTimeSpent($firstdaytoshow, 0, $usertoprocess->id); // Load time spent from table projet_task_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week 745 for ($idw = 0; $idw < 7; $idw++) 746 { 747 $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd'); 748 $totalforeachday[$tmpday] += $projectstatic->weekWorkLoad[$tmpday]; 749 } 750 } 751 752 //var_dump($totalforeachday); 753 //var_dump($totalforvisibletasks); 754 755 // Is there a diff between selected/filtered tasks and all tasks ? 756 $isdiff = 0; 757 if (count($totalforeachday)) 758 { 759 for ($idw = 0; $idw < 7; $idw++) 760 { 761 $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd'); 762 $timeonothertasks = ($totalforeachday[$tmpday] - $totalforvisibletasks[$tmpday]); 763 if ($timeonothertasks) 764 { 765 $isdiff = 1; 766 break; 767 } 768 } 769 } 770 771 // There is a diff between total shown on screen and total spent by user, so we add a line with all other cumulated time of user 772 if ($isdiff) 773 { 774 print '<tr class="oddeven othertaskwithtime">'; 775 print '<td colspan="'.($colspan + $addcolspan).'" class="opacitymedium">'; 776 print $langs->trans("OtherFilteredTasks"); 777 print '</td>'; 778 for ($idw = 0; $idw < 7; $idw++) 779 { 780 $cssweekend = ''; 781 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. 782 { 783 $cssweekend = 'weekend'; 784 } 785 786 print '<td class="center hide'.$idw.' '.($cssweekend ? ' '.$cssweekend : '').'">'; 787 $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd'); 788 $timeonothertasks = ($totalforeachday[$tmpday] - $totalforvisibletasks[$tmpday]); 789 if ($timeonothertasks) 790 { 791 print '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center smallpadd" size="2" disabled="" id="timespent[-1]['.$idw.']" name="task[-1]['.$idw.']" value="'; 792 print convertSecondToTime($timeonothertasks, 'allhourmin'); 793 print '"></span>'; 794 } 795 print '</td>'; 796 } 797 print ' <td class="liste_total"></td>'; 798 print '</tr>'; 799 } 800 801 if ($conf->use_javascript_ajax) 802 { 803 print '<tr class="liste_total"> 804 <td class="liste_total" colspan="'.($colspan + $addcolspan).'">'; 805 print $langs->trans("Total"); 806 print '<span class="opacitymediumbycolor"> - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong></span>'; 807 print '</td>'; 808 809 for ($idw = 0; $idw < 7; $idw++) { 810 $cssweekend = ''; 811 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. 812 { 813 $cssweekend = 'weekend'; 814 } 815 816 $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd'); 817 818 $cssonholiday = ''; 819 if (!$isavailable[$tmpday]['morning'] && !$isavailable[$tmpday]['afternoon']) $cssonholiday .= 'onholidayallday '; 820 elseif (!$isavailable[$tmpday]['morning']) $cssonholiday .= 'onholidaymorning '; 821 elseif (!$isavailable[$tmpday]['afternoon']) $cssonholiday .= 'onholidayafternoon '; 822 823 print '<td class="liste_total hide'.$idw.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'" align="center"><div class="totalDay'.$idw.'"> </div></td>'; 824 } 825 print '<td class="liste_total center"><div class="totalDayAll"> </div></td> 826 </tr>'; 827 } 828} else { 829 print '<tr><td colspan="15"><span class="opacitymedium">'.$langs->trans("NoAssignedTasks").'</span></td></tr>'; 830} 831print "</table>"; 832print '</div>'; 833 834print '<input type="hidden" id="numberOfLines" name="numberOfLines" value="'.count($tasksarray).'"/>'."\n"; 835 836print '<div class="center">'; 837print '<input type="submit" class="button button-save" name="save" value="'.dol_escape_htmltag($langs->trans("Save")).'">'; 838print '</div>'; 839 840print '</form>'."\n\n"; 841 842$modeinput = 'hours'; 843 844if ($conf->use_javascript_ajax) 845{ 846 print "\n<!-- JS CODE TO ENABLE Tooltips on all object with class classfortooltip -->\n"; 847 print '<script type="text/javascript">'."\n"; 848 print "jQuery(document).ready(function () {\n"; 849 print ' jQuery(".timesheetalreadyrecorded").tooltip({ 850 show: { collision: "flipfit", effect:\'toggle\', delay:50 }, 851 hide: { effect:\'toggle\', delay: 50 }, 852 tooltipClass: "mytooltip", 853 content: function () { 854 return \''.dol_escape_js($langs->trans("TimeAlreadyRecorded", $usertoprocess->getFullName($langs))).'\'; 855 } 856 });'."\n"; 857 858 $idw = 0; 859 while ($idw < 7) 860 { 861 print ' updateTotal('.$idw.',\''.$modeinput.'\');'; 862 $idw++; 863 } 864 print "\n});\n"; 865 print '</script>'; 866} 867 868// End of page 869llxFooter(); 870$db->close(); 871