dolibarr  13.0.2
perday.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2016 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 
28 require "../../main.inc.php";
29 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
30 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
31 require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
32 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
33 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
36 require_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') : 'perdaycard';
47 
48 $mine = 0;
49 if ($mode == 'mine') $mine = 1;
50 
51 $projectid = isset($_GET["id"]) ? GETPOST("id", "int", 1) : GETPOST("projectid", "int");
52 
53 $hookmanager->initHooks(array('timesheetperdaycard'));
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") : (GETPOST("addtimeyear", "int") ?GETPOST("addtimeyear", "int") : date("Y")));
68 $month = GETPOST('remonth', 'int') ?GETPOST('remonth', 'int') : (GETPOST("month", "int") ?GETPOST("month", "int") : (GETPOST("addtimemonth", "int") ?GETPOST("addtimemonth", "int") : date("m")));
69 $day = GETPOST('reday', 'int') ?GETPOST('reday', 'int') : (GETPOST("day", "int") ?GETPOST("day", "int") : (GETPOST("addtimeday", "int") ?GETPOST("addtimeday", "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 $monthofday = GETPOST('addtimemonth');
83 $dayofday = GETPOST('addtimeday');
84 $yearofday = GETPOST('addtimeyear');
85 
86 $daytoparse = $now;
87 if ($yearofday && $monthofday && $dayofday) $daytoparse = dol_mktime(0, 0, 0, $monthofday, $dayofday, $yearofday); // xxxofday is value of day after submit action 'addtime'
88 elseif ($year && $month && $day) $daytoparse = dol_mktime(0, 0, 0, $month, $day, $year); // this are value submited after submit of action 'submitdateselect'
89 
90 
91 if (empty($search_usertoprocessid) || $search_usertoprocessid == $user->id)
92 {
93  $usertoprocess = $user;
94  $search_usertoprocessid = $usertoprocess->id;
95 } elseif ($search_usertoprocessid > 0)
96 {
97  $usertoprocess = new User($db);
98  $usertoprocess->fetch($search_usertoprocessid);
99  $search_usertoprocessid = $usertoprocess->id;
100 } else {
101  $usertoprocess = new User($db);
102 }
103 
104 $object = new Task($db);
105 $project = new Project($db);
106 
107 // Extra fields
108 $extrafields = new ExtraFields($db);
109 
110 // fetch optionals attributes and labels
111 $extrafields->fetch_name_optionals_label($object->table_element);
112 
113 // Definition of fields for list
114 $arrayfields = array();
115 $arrayfields['t.planned_workload'] = array('label'=>'PlannedWorkload', 'checked'=>1, 'enabled'=>1, 'position'=>0);
116 $arrayfields['t.progress'] = array('label'=>'ProgressDeclared', 'checked'=>1, 'enabled'=>1, 'position'=>0);
117 /*$arrayfields=array(
118  // Project
119  'p.opp_amount'=>array('label'=>$langs->trans("OpportunityAmountShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>103),
120  'p.fk_opp_status'=>array('label'=>$langs->trans("OpportunityStatusShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>104),
121  'p.opp_percent'=>array('label'=>$langs->trans("OpportunityProbabilityShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>105),
122  'p.budget_amount'=>array('label'=>$langs->trans("Budget"), 'checked'=>0, 'position'=>110),
123  'p.usage_bill_time'=>array('label'=>$langs->trans("BillTimeShort"), 'checked'=>0, 'position'=>115),
124  );
125  */
126 // Extra fields
127 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0)
128 {
129  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val)
130  {
131  if (!empty($extrafields->attributes[$object->table_element]['list'][$key]))
132  $arrayfields["efpt.".$key] = array('label'=>$extrafields->attributes[$object->table_element]['label'][$key], 'checked'=>(($extrafields->attributes[$object->table_element]['list'][$key] < 0) ? 0 : 1), 'position'=>$extrafields->attributes[$object->table_element]['pos'][$key], 'enabled'=>(abs((int) $extrafields->attributes[$object->table_element]['list'][$key]) != 3 && $extrafields->attributes[$object->table_element]['perms'][$key]));
133  }
134 }
135 $arrayfields = dol_sort_array($arrayfields, 'position');
136 
137 
138 $search_array_options_project = $extrafields->getOptionalsFromPost($project->table_element, '', 'search_');
139 $search_array_options_task = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_task_');
140 
141 
142 /*
143  * Actions
144  */
145 
146 $parameters = array('id' => $id, 'taskid' => $taskid, 'projectid' => $projectid);
147 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
148 if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
149 // Purge criteria
150 if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers
151 {
152  $action = '';
153  $search_categ = '';
154  $search_usertoprocessid = $user->id;
155  $search_task_ref = '';
156  $search_task_label = '';
157  $search_project_ref = '';
158  $search_thirdparty = '';
159  $search_declared_progress = '';
160 
161  $search_array_options_project = array();
162  $search_array_options_task = array();
163 
164  // We redefine $usertoprocess
165  $usertoprocess = $user;
166 }
167 if (GETPOST("button_search_x", 'alpha') || GETPOST("button_search.x", 'alpha') || GETPOST("button_search", 'alpha'))
168 {
169  $action = '';
170 }
171 
172 if (GETPOST('submitdateselect'))
173 {
174  if (GETPOST('remonth', 'int') && GETPOST('reday', 'int') && GETPOST('reyear', 'int'))
175  {
176  $daytoparse = dol_mktime(0, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
177  }
178 
179  $action = '';
180 }
181 
182 include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
183 
184 if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask') && GETPOST('formfilteraction') != 'listafterchangingselectedfields')
185 {
186  $action = 'assigntask';
187 
188  if ($taskid > 0)
189  {
190  $result = $object->fetch($taskid, $ref);
191  if ($result < 0) $error++;
192  } else {
193  setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Task")), '', 'errors');
194  $error++;
195  }
196  if (!GETPOST('type'))
197  {
198  setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), '', 'errors');
199  $error++;
200  }
201  if (!$error)
202  {
203  $idfortaskuser = $usertoprocess->id;
204  $result = $object->add_contact($idfortaskuser, GETPOST("type"), 'internal');
205 
206  if ($result >= 0 || $result == -2) // Contact add ok or already contact of task
207  {
208  // 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)
209  $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';
210  $sql .= ' AND ec.fk_socpeople = '.$idfortaskuser." AND ec.element_id = '.$object->fk_project.' AND tc.element = 'project' AND source = 'internal'";
211  $resql = $db->query($sql);
212  if ($resql)
213  {
214  $obj = $db->fetch_object($resql);
215  if (!$obj) // User is not already linked to project, so we will create link to first type
216  {
217  $project = new Project($db);
218  $project->fetch($object->fk_project);
219  // Get type
220  $listofprojcontact = $project->liste_type_contact('internal');
221 
222  if (count($listofprojcontact))
223  {
224  $typeforprojectcontact = reset(array_keys($listofprojcontact));
225  $result = $project->add_contact($idfortaskuser, $typeforprojectcontact, 'internal');
226  }
227  }
228  } else {
229  dol_print_error($db);
230  }
231  }
232  }
233 
234  if ($result < 0)
235  {
236  $error++;
237  if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS')
238  {
239  $langs->load("errors");
240  setEventMessages($langs->trans("ErrorTaskAlreadyAssigned"), null, 'warnings');
241  } else {
242  setEventMessages($object->error, $object->errors, 'errors');
243  }
244  }
245 
246  if (!$error)
247  {
248  setEventMessages("TaskAssignedToEnterTime", null);
249  $taskid = 0;
250  }
251 
252  $action = '';
253 }
254 
255 if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('formfilteraction') != 'listafterchangingselectedfields')
256 {
257  $timespent_duration = array();
258 
259  if (is_array($_POST))
260  {
261  foreach ($_POST as $key => $time)
262  {
263  if (intval($time) > 0)
264  {
265  $matches = array();
266  // Hours or minutes of duration
267  if (preg_match("/([0-9]+)duration(hour|min)/", $key, $matches))
268  {
269  $id = $matches[1];
270  if ($id > 0)
271  {
272  // We store HOURS in seconds
273  if ($matches[2] == 'hour') $timespent_duration[$id] += $time * 60 * 60;
274 
275  // We store MINUTES in seconds
276  if ($matches[2] == 'min') $timespent_duration[$id] += $time * 60;
277  }
278  }
279  }
280  }
281  }
282 
283  if (count($timespent_duration) > 0)
284  {
285  foreach ($timespent_duration as $key => $val)
286  {
287  $object->fetch($key);
288  $taskid = $object->id;
289 
290  if (GETPOSTISSET($taskid.'progress')) $object->progress = GETPOST($taskid.'progress', 'int');
291  else unset($object->progress);
292 
293  $object->timespent_duration = $val;
294  $object->timespent_fk_user = $usertoprocess->id;
295  $object->timespent_note = GETPOST($key.'note');
296  if (GETPOST($key."hour", 'int') != '' && GETPOST($key."hour", 'int') >= 0) // If hour was entered
297  {
298  $object->timespent_datehour = dol_mktime(GETPOST($key."hour", 'int'), GETPOST($key."min", 'int'), 0, $monthofday, $dayofday, $yearofday);
299  $object->timespent_withhour = 1;
300  } else {
301  $object->timespent_datehour = dol_mktime(12, 0, 0, $monthofday, $dayofday, $yearofday);
302  }
303  $object->timespent_date = $object->timespent_datehour;
304 
305  if ($object->timespent_date > 0)
306  {
307  $result = $object->addTimeSpent($user);
308  } else {
309  setEventMessages("ErrorBadDate", null, 'errors');
310  $error++;
311  break;
312  }
313 
314  if ($result < 0)
315  {
316  setEventMessages($object->error, $object->errors, 'errors');
317  $error++;
318  break;
319  }
320  }
321 
322  if (!$error)
323  {
324  setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
325 
326  // Redirect to avoid submit twice on back
327  header('Location: '.$_SERVER["PHP_SELF"].'?'.($projectid ? 'id='.$projectid : '').($search_usertoprocessid ? '&search_usertoprocessid='.$search_usertoprocessid : '').($mode ? '&mode='.$mode : '').'&year='.$yearofday.'&month='.$monthofday.'&day='.$dayofday);
328  exit;
329  }
330  } else {
331  setEventMessages($langs->trans("ErrorTimeSpentIsEmpty"), null, 'errors');
332  }
333 }
334 
335 
336 
337 /*
338  * View
339  */
340 
341 $form = new Form($db);
342 $formother = new FormOther($db);
343 $formcompany = new FormCompany($db);
344 $formproject = new FormProjets($db);
345 $projectstatic = new Project($db);
346 $project = new Project($db);
347 $taskstatic = new Task($db);
348 $thirdpartystatic = new Societe($db);
349 $holiday = new Holiday($db);
350 
351 $prev = dol_getdate($daytoparse - (24 * 3600));
352 $prev_year = $prev['year'];
353 $prev_month = $prev['mon'];
354 $prev_day = $prev['mday'];
355 
356 $next = dol_getdate($daytoparse + (24 * 3600));
357 $next_year = $next['year'];
358 $next_month = $next['mon'];
359 $next_day = $next['mday'];
360 
361 $title = $langs->trans("TimeSpent");
362 
363 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertoprocess, (empty($usertoprocess->id) ? 2 : 0), 1); // Return all project i have permission on. I want my tasks and some of my task may be on a public projet that is not my project
364 
365 if ($id)
366 {
367  $project->fetch($id);
368  $project->fetch_thirdparty();
369 }
370 
371 $onlyopenedproject = 1; // or -1
372 $morewherefilter = '';
373 
374 if ($search_project_ref) $morewherefilter .= natural_search(array("p.ref", "p.title"), $search_project_ref);
375 if ($search_task_ref) $morewherefilter .= natural_search("t.ref", $search_task_ref);
376 if ($search_task_label) $morewherefilter .= natural_search(array("t.ref", "t.label"), $search_task_label);
377 if ($search_thirdparty) $morewherefilter .= natural_search("s.nom", $search_thirdparty);
378 if ($search_declared_progress) $morewherefilter .= natural_search("t.progress", $search_declared_progress, 1);
379 
380 $sql = &$morewherefilter;
381 
382 /*$search_array_options = $search_array_options_project;
383 $extrafieldsobjectprefix='efp.';
384 $search_options_pattern='search_options_';
385 $extrafieldsobjectkey='projet';
386 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
387 */
388 $search_array_options = $search_array_options_task;
389 $extrafieldsobjectprefix = 'efpt.';
390 $search_options_pattern = 'search_task_options_';
391 $extrafieldsobjectkey = 'projet_task';
392 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
393 
394 $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 task of opened project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later.
395 if ($morewherefilter) // Get all task without any filter, so we can show total of time spent for not visible tasks
396 {
397  $tasksarraywithoutfilter = $taskstatic->getTasksArray(0, 0, ($project->id ? $project->id : 0), $socid, 0, '', $onlyopenedproject, '', ($search_usertoprocessid ? $search_usertoprocessid : 0)); // We want to see all task of opened project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later.
398 }
399 $projectsrole = $taskstatic->getUserRolesForProjectsOrTasks($usertoprocess, 0, ($project->id ? $project->id : 0), 0, $onlyopenedproject);
400 $tasksrole = $taskstatic->getUserRolesForProjectsOrTasks(0, $usertoprocess, ($project->id ? $project->id : 0), 0, $onlyopenedproject);
401 //var_dump($usertoprocess);
402 //var_dump($projectsrole);
403 //var_dump($taskrole);
404 
405 llxHeader("", $title, "", '', '', '', array('/core/js/timesheet.js'));
406 
407 //print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num, '', 'project');
408 
409 $param = '';
410 $param .= ($mode ? '&mode='.urlencode($mode) : '');
411 $param .= ($search_project_ref ? '&search_project_ref='.urlencode($search_project_ref) : '');
412 $param .= ($search_usertoprocessid ? '&search_usertoprocessid='.urlencode($search_usertoprocessid) : '');
413 $param .= ($search_thirdparty ? '&search_thirdparty='.urlencode($search_thirdparty) : '');
414 $param .= ($search_task_ref ? '&search_task_ref='.urlencode($search_task_ref) : '');
415 $param .= ($search_task_label ? '&search_task_label='.urlencode($search_task_label) : '');
416 
417 /*$search_array_options=$search_array_options_project;
418 $search_options_pattern='search_options_';
419 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
420 */
421 
422 $search_array_options = $search_array_options_task;
423 $search_options_pattern = 'search_task_options_';
424 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
425 
426 // Show navigation bar
427 $nav = '<a class="inline-block valignmiddle" href="?year='.$prev_year."&amp;month=".$prev_month."&amp;day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n";
428 $nav .= dol_print_date(dol_mktime(0, 0, 0, $month, $day, $year), "%A").' ';
429 $nav .= " <span id=\"month_name\">".dol_print_date(dol_mktime(0, 0, 0, $month, $day, $year), "day")." </span>\n";
430 $nav .= '<a class="inline-block valignmiddle" href="?year='.$next_year."&amp;month=".$next_month."&amp;day=".$next_day.$param.'">'.img_next($langs->trans("Next"))."</a>\n";
431 //$nav .= " &nbsp; (<a href=\"?year=".$nowyear."&amp;month=".$nowmonth."&amp;day=".$nowday.$param."\">".$langs->trans("Today")."</a>)";
432 $nav .= ' '.$form->selectDate(-1, '', 0, 0, 2, "addtime", 1, 1).' ';
433 //$nav .= ' <input type="submit" name="submitdateselect" class="button valignmiddle" value="'.$langs->trans("Refresh").'">';
434 $nav .= ' <button type="submit" name="button_search_x" value="x" class="bordertransp"><span class="fa fa-search"></span></button>';
435 
436 $picto = 'clock';
437 
438 print '<form name="addtime" method="POST" action="'.$_SERVER["PHP_SELF"].($project->id > 0 ? '?id='.$project->id : '').'">';
439 print '<input type="hidden" name="token" value="'.newToken().'">';
440 print '<input type="hidden" name="action" value="addtime">';
441 print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
442 print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
443 print '<input type="hidden" name="mode" value="'.$mode.'">';
444 $tmp = dol_getdate($daytoparse);
445 print '<input type="hidden" name="addtimeyear" value="'.$tmp['year'].'">';
446 print '<input type="hidden" name="addtimemonth" value="'.$tmp['mon'].'">';
447 print '<input type="hidden" name="addtimeday" value="'.$tmp['mday'].'">';
448 
449 $head = project_timesheet_prepare_head($mode, $usertoprocess);
450 print dol_get_fiche_head($head, 'inputperday', $langs->trans('TimeSpent'), -1, $picto);
451 
452 // Show description of content
453 print '<div class="hideonsmartphone opacitymedium">';
454 if ($mine || ($usertoprocess->id == $user->id)) print $langs->trans("MyTasksDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
455 else {
456  if (empty($usertoprocess->id) || $usertoprocess->id < 0)
457  {
458  if ($user->rights->projet->all->lire && !$socid) print $langs->trans("ProjectsDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
459  else print $langs->trans("ProjectsPublicTaskDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
460  }
461 }
462 if ($mine || ($usertoprocess->id == $user->id))
463 {
464  print $langs->trans("OnlyYourTaskAreVisible").'<br>';
465 } else {
466  print $langs->trans("AllTaskVisibleButEditIfYouAreAssigned").'<br>';
467 }
468 print '</div>';
469 
470 print dol_get_fiche_end();
471 
472 
473 print '<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.
474 
475 print '<div class="colorbacktimesheet float valignmiddle">';
476 $titleassigntask = $langs->transnoentities("AssignTaskToMe");
477 if ($usertoprocess->id != $user->id) $titleassigntask = $langs->transnoentities("AssignTaskToUser", $usertoprocess->getFullName($langs));
478 print '<div class="taskiddiv inline-block">';
479 print img_picto('', 'projecttask');
480 $formproject->selectTasks($socid ? $socid : -1, $taskid, 'taskid', 32, 0, '-- '.$langs->trans("ChooseANotYetAssignedTask").' --', 1, 0, 0, '', '', 'all', $usertoprocess);
481 print '</div>';
482 print ' ';
483 print $formcompany->selectTypeContact($object, '', 'type', 'internal', 'rowid', 0, 'maxwidth150onsmartphone');
484 print '<input type="submit" class="button valignmiddle" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">';
485 print '</div>';
486 
487 print '<div class="clearboth" style="padding-bottom: 20px;"></div>';
488 
489 
490 $moreforfilter = '';
491 
492 // Filter on categories
493 /*if (! empty($conf->categorie->enabled))
494 {
495  require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
496  $moreforfilter.='<div class="divsearchfield">';
497  $moreforfilter.=$langs->trans('ProjectCategories'). ': ';
498  $moreforfilter.=$formother->select_categories('project', $search_categ, 'search_categ', 1, 1, 'maxwidth300');
499  $moreforfilter.='</div>';
500 }*/
501 
502 // If the user can view user other than himself
503 $moreforfilter .= '<div class="divsearchfield">';
504 $moreforfilter .= '<div class="inline-block hideonsmartphone"></div>';
505 $includeonly = 'hierarchyme';
506 if (empty($user->rights->user->user->lire)) $includeonly = array($user->id);
507 $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 marginleftonly');
508 $moreforfilter .= '</div>';
509 
510 if (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT))
511 {
512  $moreforfilter .= '<div class="divsearchfield">';
513  $moreforfilter .= '<div class="inline-block"></div>';
514  $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).'">';
515  $moreforfilter .= '</div>';
516 
517  $moreforfilter .= '<div class="divsearchfield">';
518  $moreforfilter .= '<div class="inline-block"></div>';
519  $moreforfilter .= img_picto($langs->trans('ThirdParty'), 'company').'<input type="text" size="4" name="search_thirdparty" class="marginleftonly" value="'.dol_escape_htmltag($search_thirdparty).'">';
520  $moreforfilter .= '</div>';
521 }
522 
523 if (!empty($moreforfilter))
524 {
525  print '<div class="liste_titre liste_titre_bydiv centpercent">';
526  print $moreforfilter;
527  $parameters = array();
528  $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
529  print $hookmanager->resPrint;
530  print '</div>';
531 }
532 
533 $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
534 $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
535 
536 // This must be after the $selectedfields
537 $addcolspan = 0;
538 if (!empty($arrayfields['t.planned_workload']['checked'])) $addcolspan++;
539 if (!empty($arrayfields['t.progress']['checked'])) $addcolspan++;
540 foreach ($arrayfields as $key => $val)
541 {
542  if ($val['checked'] && substr($key, 0, 5) == 'efpt.') $addcolspan++;
543 }
544 
545 print '<div class="div-table-responsive">';
546 print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'" id="tablelines3">'."\n";
547 
548 print '<tr class="liste_titre_filter">';
549 if (!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>';
550 if (!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>';
551 print '<td class="liste_titre"><input type="text" size="4" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
552 // TASK fields
553 $search_options_pattern = 'search_task_options_';
554 $extrafieldsobjectkey = 'projet_task';
555 $extrafieldsobjectprefix = 'efpt.';
556 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
557 print '<td class="liste_titre"></td>';
558 if (!empty($arrayfields['t.planned_workload']['checked']))
559 {
560  print '<td class="liste_titre right"><input type="text" size="4" name="search_declared_progress" value="'.dol_escape_htmltag($search_declared_progress).'"></td>';
561 }
562 if (!empty($arrayfields['t.progress']['checked']))
563 {
564  print '<td class="liste_titre"></td>';
565 }
566 print '<td class="liste_titre"></td>';
567 print '<td class="liste_titre"></td>';
568 print '<td class="liste_titre"></td>';
569 print '<td class="liste_titre"></td>';
570 // Action column
571 print '<td class="liste_titre nowrap right">';
572 $searchpicto = $form->showFilterAndCheckAddButtons(0);
573 print $searchpicto;
574 print '</td>';
575 print "</tr>\n";
576 
577 print '<tr class="liste_titre">';
578 if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) print '<th>'.$langs->trans("Project").'</th>';
579 if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) print '<th>'.$langs->trans("ThirdParty").'</th>';
580 print '<th>'.$langs->trans("Task").'</th>';
581 // TASK fields
582 $extrafieldsobjectkey = 'projet_task';
583 $extrafieldsobjectprefix = 'efpt.';
584 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
585 if (!empty($arrayfields['t.planned_workload']['checked']))
586 {
587  print '<th class="right leftborder plannedworkload maxwidth100">'.$langs->trans("PlannedWorkload").'</th>';
588 }
589 if (!empty($arrayfields['t.progress']['checked']))
590 {
591  print '<th class="right maxwidth100">'.$langs->trans("ProgressDeclared").'</th>';
592 }
593 /*print '<td class="right maxwidth100">'.$langs->trans("TimeSpent").'</td>';
594 if ($usertoprocess->id == $user->id) print '<td class="right maxwidth100">'.$langs->trans("TimeSpentByYou").'</td>';
595 else print '<td class="right maxwidth100">'.$langs->trans("TimeSpentByUser").'</td>';*/
596 print '<th class="right maxwidth100">'.$langs->trans("TimeSpent").'<br><span class="opacitymedium">'.$langs->trans("Everybody").'</span></th>';
597 print '<th class="right maxwidth100">'.$langs->trans("TimeSpent").($usertoprocess->firstname ? '<br><span class="opacitymedium">'.dol_trunc($usertoprocess->firstname, 10).'</span>' : '').'</th>';
598 print '<th class="center leftborder">'.$langs->trans("HourStart").'</td>';
599 
600 // By default, we can edit only tasks we are assigned to
601 $restrictviewformytask = ((!isset($conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED)) ? 2 : $conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED);
602 
603 // Get if user is available or not for each day
604 $isavailable = array();
605 if (!empty($conf->global->MAIN_DEFAULT_WORKING_DAYS))
606 {
607  $tmparray = explode('-', $conf->global->MAIN_DEFAULT_WORKING_DAYS);
608  if (count($tmparray) >= 2)
609  {
610  $numstartworkingday = $tmparray[0];
611  $numendworkingday = $tmparray[1];
612  }
613 }
614 
615 $statusofholidaytocheck = Holiday::STATUS_APPROVED;
616 $isavailablefordayanduser = $holiday->verifDateHolidayForTimestamp($usertoprocess->id, $daytoparse, $statusofholidaytocheck); // $daytoparse is a date with hours = 0
617 $isavailable[$daytoparse] = $isavailablefordayanduser; // in projectLinesPerWeek later, we are using $firstdaytoshow and dol_time_plus_duree to loop on each day
618 
619 $test = num_public_holiday($daytoparse, $daytoparse + 86400, $mysoc->country_code);
620 if ($test) $isavailable[$daytoparse] = array('morning'=>false, 'afternoon'=>false, 'morning_reason'=>'public_holiday', 'afternoon_reason'=>'public_holiday');
621 
622 $tmparray = dol_getdate($daytoparse, true); // detail of current day
623 // For monday, must be 0 for monday if MAIN_START_WEEK = 1, must be 1 for monday if MAIN_START_WEEK = 0
624 $idw = ($tmparray['wday'] - (empty($conf->global->MAIN_START_WEEK) ? 0 : 1));
625 // numstartworkingday and numendworkingday are default start and end date of working days (1 means sunday if MAIN_START_WEEK is 0, 1 means monday if MAIN_START_WEEK is 1)
626 $cssweekend = '';
627 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.
628 {
629  $cssweekend = 'weekend';
630 }
631 
632 $tmpday = dol_time_plus_duree($daytoparse, $idw, 'd');
633 
634 $cssonholiday = '';
635 if (!$isavailable[$daytoparse]['morning'] && !$isavailable[$daytoparse]['afternoon']) $cssonholiday .= 'onholidayallday ';
636 elseif (!$isavailable[$daytoparse]['morning']) $cssonholiday .= 'onholidaymorning ';
637 elseif (!$isavailable[$daytoparse]['afternoon']) $cssonholiday .= 'onholidayafternoon ';
638 
639 print '<th class="center'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">'.$langs->trans("Duration").'</th>';
640 print '<th class="center">'.$langs->trans("Note").'</th>';
641 //print '<td class="center"></td>';
642 print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
643 
644 print "</tr>\n";
645 
646 $colspan = 4 + (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : 2);
647 
648 if ($conf->use_javascript_ajax)
649 {
650  print '<tr class="liste_total">';
651  print '<td class="liste_total" colspan="'.($colspan - 1 + $addcolspan).'">';
652  print $langs->trans("Total");
653  print '</td>';
654  print '<td class="liste_total leftborder">';
655  //print ' - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong>';
656  print '</td>';
657 
658  print '<td class="liste_total center'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'"><div class="totalDay0">&nbsp;</div></td>';
659 
660  print '<td class="liste_total"></td>';
661  print '<td class="liste_total"></td>';
662  print '</tr>';
663 }
664 
665 
666 if (count($tasksarray) > 0)
667 {
668  //var_dump($tasksarray); // contains only selected tasks
669  //var_dump($tasksarraywithoutfilter); // contains all tasks (if there is a filter, not defined if no filter)
670  //var_dump($tasksrole);
671 
672  $j = 0;
673  $level = 0;
674  $totalforvisibletasks = projectLinesPerDay($j, 0, $usertoprocess, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restrictviewformytask, $daytoparse, $isavailable, 0, $arrayfields, $extrafields);
675  //var_dump($totalforvisibletasks);
676 
677  // Show total for all other tasks
678 
679  // Calculate total for all tasks
680  $listofdistinctprojectid = array(); // List of all distinct projects
681  if (is_array($tasksarraywithoutfilter) && count($tasksarraywithoutfilter))
682  {
683  foreach ($tasksarraywithoutfilter as $tmptask)
684  {
685  $listofdistinctprojectid[$tmptask->fk_project] = $tmptask->fk_project;
686  }
687  }
688  //var_dump($listofdistinctprojectid);
689  $totalforeachday = array();
690  foreach ($listofdistinctprojectid as $tmpprojectid)
691  {
692  $projectstatic->id = $tmpprojectid;
693  $projectstatic->loadTimeSpent($daytoparse, 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
694  for ($idw = 0; $idw < 7; $idw++)
695  {
696  $tmpday = dol_time_plus_duree($daytoparse, $idw, 'd');
697  $totalforeachday[$tmpday] += $projectstatic->weekWorkLoad[$tmpday];
698  }
699  }
700  //var_dump($totalforeachday);
701 
702  // Is there a diff between selected/filtered tasks and all tasks ?
703  $isdiff = 0;
704  if (count($totalforeachday))
705  {
706  $timeonothertasks = ($totalforeachday[$daytoparse] - $totalforvisibletasks[$daytoparse]);
707  if ($timeonothertasks)
708  {
709  $isdiff = 1;
710  }
711  }
712 
713  // 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
714  if ($isdiff)
715  {
716  print '<tr class="oddeven othertaskwithtime">';
717  print '<td colspan="'.($colspan - 1).'" class="opacitymedium">';
718  print $langs->trans("OtherFilteredTasks");
719  print '</td>';
720  print '<td class="leftborder"></td>';
721  print '<td class="center">';
722  $timeonothertasks = ($totalforeachday[$daytoparse] - $totalforvisibletasks[$daytoparse]);
723  //if ($timeonothertasks)
724  //{
725  print '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center" size="2" disabled="" id="timespent[-1][0]" name="task[-1][0]" value="';
726  if ($timeonothertasks) print convertSecondToTime($timeonothertasks, 'allhourmin');
727  print '"></span>';
728  //}
729  print '</td>';
730  print ' <td class="liste_total"></td>';
731  print ' <td class="liste_total"></td>';
732  print '</tr>';
733  }
734 
735  if ($conf->use_javascript_ajax)
736  {
737  print '<tr class="liste_total">';
738  print '<td class="liste_total" colspan="'.($colspan - 1 + $addcolspan).'">';
739  print $langs->trans("Total");
740  print '</td>';
741  print '<td class="liste_total leftborder">';
742  //print ' - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong>';
743  print '</td>';
744 
745  print '<td class="liste_total center'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'"><div class="totalDay0">&nbsp;</div></td>';
746 
747  print '<td class="liste_total"></td>
748  <td class="liste_total"></td>
749  </tr>';
750  }
751 } else {
752  print '<tr><td colspan="14"><span class="opacitymedium">'.$langs->trans("NoAssignedTasks").'</span></td></tr>';
753 }
754 print "</table>";
755 print '</div>';
756 
757 print '<input type="hidden" id="numberOfLines" name="numberOfLines" value="'.count($tasksarray).'"/>'."\n";
758 
759 print '<div class="center">';
760 print '<input type="submit" class="button button-save"'.($disabledtask ? ' disabled' : '').' value="'.$langs->trans("Save").'">';
761 print '</div>';
762 
763 print '</form>';
764 
765 $modeinput = 'hours';
766 
767 if ($conf->use_javascript_ajax)
768 {
769  print "\n<!-- JS CODE TO ENABLE Tooltips on all object with class classfortooltip -->\n";
770  print '<script type="text/javascript">'."\n";
771  print "jQuery(document).ready(function () {\n";
772  print ' jQuery(".timesheetalreadyrecorded").tooltip({
773  show: { collision: "flipfit", effect:\'toggle\', delay:50 },
774  hide: { effect:\'toggle\', delay: 50 },
775  tooltipClass: "mytooltip",
776  content: function () {
777  return \''.dol_escape_js($langs->trans("TimeAlreadyRecorded", $usertoprocess->getFullName($langs))).'\';
778  }
779  });'."\n";
780 
781  print ' updateTotal(0,\''.$modeinput.'\');';
782  print "\n});\n";
783  print '</script>';
784 }
785 
786 // End of page
787 llxFooter();
788 $db->close();
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Class of the module paid holiday.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm= 'auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
dol_now($mode= 'auto')
Return date for now.
Class to manage Dolibarr users.
Definition: user.class.php:44
projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak=0, $arrayfields=array(), $extrafields=null)
Output a task line into a pertime intput mode.
llxHeader()
Empty header.
Definition: wrapper.php:45
Class to build HTML component for third parties management Only common components are here...
Class to manage standard extra fields.
setEventMessages($mesg, $mesgs, $style= 'mesgs', $messagekey= '')
Set event messages in dol_events session object.
Class to manage generation of HTML components Only common components must be here.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname.
Class to manage third parties objects (customers, suppliers, prospects...)
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
Class to manage projects.
Class to manage building of HTML components.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt= '', $morecss= '', $marginleftonlyshort=2)
Show picto whatever it&#39;s its name (generic function)
Classe permettant la generation de composants html autre Only common components are here...
dol_getdate($timestamp, $fast=false, $forcetimezone= '')
Return an array with locale date info.
restrictedArea($user, $features, $objectid=0, $tableandshare= '', $feature2= '', $dbt_keyfield= 'fk_soc', $dbt_select= 'rowid', $isdraft=0)
Check permissions of a user to show a page and an object.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
const STATUS_APPROVED
Approved.
num_public_holiday($timestampStart, $timestampEnd, $country_code= '', $lastday=0, $includesaturday=-1, $includesunday=-1)
Return the number of non working days including saturday and sunday (or not) between 2 dates in times...
Definition: date.lib.php:647
print $_SERVER["PHP_SELF"]
Edit parameters.
img_next($titlealt= 'default', $moreatt= '')
Show next logo.
dol_sort_array(&$array, $index, $order= 'asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
dol_get_fiche_head($links=array(), $active= '', $title= '', $notab=0, $picto= '', $pictoisfullpath=0, $morehtmlright= '', $morecss= '', $limittoshow=0, $moretabssuffix= '')
Show tabs of a record.
print
Draft customers invoices.
Definition: index.php:89
Class to manage tasks.
Definition: task.class.php:35
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
img_previous($titlealt= 'default', $moreatt= '')
Show previous logo.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_get_fiche_end($notab=0)
Return tab footer of a card.
project_timesheet_prepare_head($mode, $fuser=null)
Prepare array with list of tabs.
dol_time_plus_duree($time, $duration_value, $duration_unit)
Add a delay to a date.
Definition: date.lib.php:114
if(!defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN'
Draft customers invoices.
convertSecondToTime($iSecond, $format= 'all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition: date.lib.php:180
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $keepmoretags= '', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...