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
22/**
23 *	\file       htdocs/projet/activity/perday.php
24 *	\ingroup    projet
25 *	\brief      List activities of tasks (per day 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') : 'perdaycard';
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('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;
87if ($yearofday && $monthofday && $dayofday) $daytoparse = dol_mktime(0, 0, 0, $monthofday, $dayofday, $yearofday); // xxxofday is value of day after submit action 'addtime'
88elseif ($year && $month && $day) $daytoparse = dol_mktime(0, 0, 0, $month, $day, $year); // this are value submited after submit of action 'submitdateselect'
89
90
91if (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
127if (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
148if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
149// Purge criteria
150if (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}
167if (GETPOST("button_search_x", 'alpha') || GETPOST("button_search.x", 'alpha') || GETPOST("button_search", 'alpha'))
168{
169	$action = '';
170}
171
172if (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
182include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
183
184if ($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 = '.((int) $idfortaskuser)." AND ec.element_id = ".((int) $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
255if ($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
365if ($id)
366{
367	$project->fetch($id);
368	$project->fetch_thirdparty();
369}
370
371$onlyopenedproject = 1; // or -1
372$morewherefilter = '';
373
374if ($search_project_ref) $morewherefilter .= natural_search(array("p.ref", "p.title"), $search_project_ref);
375if ($search_task_ref)    $morewherefilter .= natural_search("t.ref", $search_task_ref);
376if ($search_task_label)  $morewherefilter .= natural_search(array("t.ref", "t.label"), $search_task_label);
377if ($search_thirdparty)  $morewherefilter .= natural_search("s.nom", $search_thirdparty);
378if ($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';
386include 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';
392include 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.
395if ($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
405llxHeader("", $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_';
419include 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_';
424include 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
438print '<form name="addtime" method="POST" action="'.$_SERVER["PHP_SELF"].($project->id > 0 ? '?id='.$project->id : '').'">';
439print '<input type="hidden" name="token" value="'.newToken().'">';
440print '<input type="hidden" name="action" value="addtime">';
441print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
442print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
443print '<input type="hidden" name="mode" value="'.$mode.'">';
444$tmp = dol_getdate($daytoparse);
445print '<input type="hidden" name="addtimeyear" value="'.$tmp['year'].'">';
446print '<input type="hidden" name="addtimemonth" value="'.$tmp['mon'].'">';
447print '<input type="hidden" name="addtimeday" value="'.$tmp['mday'].'">';
448
449$head = project_timesheet_prepare_head($mode, $usertoprocess);
450print dol_get_fiche_head($head, 'inputperday', $langs->trans('TimeSpent'), -1, $picto);
451
452// Show description of content
453print '<div class="hideonsmartphone opacitymedium">';
454if ($mine || ($usertoprocess->id == $user->id)) print $langs->trans("MyTasksDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
455else {
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}
462if ($mine || ($usertoprocess->id == $user->id))
463{
464	print $langs->trans("OnlyYourTaskAreVisible").'<br>';
465} else {
466	print $langs->trans("AllTaskVisibleButEditIfYouAreAssigned").'<br>';
467}
468print '</div>';
469
470print dol_get_fiche_end();
471
472
473print '<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
475print '<div class="colorbacktimesheet float valignmiddle">';
476$titleassigntask = $langs->transnoentities("AssignTaskToMe");
477if ($usertoprocess->id != $user->id) $titleassigntask = $langs->transnoentities("AssignTaskToUser", $usertoprocess->getFullName($langs));
478print '<div class="taskiddiv inline-block">';
479print img_picto('', 'projecttask');
480$formproject->selectTasks($socid ? $socid : -1, $taskid, 'taskid', 32, 0, '-- '.$langs->trans("ChooseANotYetAssignedTask").' --', 1, 0, 0, '', '', 'all', $usertoprocess);
481print '</div>';
482print ' ';
483print $formcompany->selectTypeContact($object, '', 'type', 'internal', 'rowid', 0, 'maxwidth150onsmartphone');
484print '<input type="submit" class="button valignmiddle" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">';
485print '</div>';
486
487print '<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';
506if (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
510if (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
523if (!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;
538if (!empty($arrayfields['t.planned_workload']['checked'])) $addcolspan++;
539if (!empty($arrayfields['t.progress']['checked'])) $addcolspan++;
540foreach ($arrayfields as $key => $val)
541{
542	if ($val['checked'] && substr($key, 0, 5) == 'efpt.') $addcolspan++;
543}
544
545print '<div class="div-table-responsive">';
546print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'" id="tablelines3">'."\n";
547
548print '<tr class="liste_titre_filter">';
549if (!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>';
550if (!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>';
551print '<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.';
556include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
557print '<td class="liste_titre"></td>';
558if (!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}
562if (!empty($arrayfields['t.progress']['checked']))
563{
564	print '<td class="liste_titre"></td>';
565}
566print '<td class="liste_titre"></td>';
567print '<td class="liste_titre"></td>';
568print '<td class="liste_titre"></td>';
569print '<td class="liste_titre"></td>';
570// Action column
571print '<td class="liste_titre nowrap right">';
572$searchpicto = $form->showFilterAndCheckAddButtons(0);
573print $searchpicto;
574print '</td>';
575print "</tr>\n";
576
577print '<tr class="liste_titre">';
578if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) print '<th>'.$langs->trans("Project").'</th>';
579if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) print '<th>'.$langs->trans("ThirdParty").'</th>';
580print '<th>'.$langs->trans("Task").'</th>';
581// TASK fields
582$extrafieldsobjectkey = 'projet_task';
583$extrafieldsobjectprefix = 'efpt.';
584include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
585if (!empty($arrayfields['t.planned_workload']['checked']))
586{
587	print '<th class="right leftborder plannedworkload maxwidth100">'.$langs->trans("PlannedWorkload").'</th>';
588}
589if (!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>';
594if ($usertoprocess->id == $user->id) print '<td class="right maxwidth100">'.$langs->trans("TimeSpentByYou").'</td>';
595else print '<td class="right maxwidth100">'.$langs->trans("TimeSpentByUser").'</td>';*/
596print '<th class="right maxwidth100">'.$langs->trans("TimeSpent").'<br><span class="opacitymedium">'.$langs->trans("Everybody").'</span></th>';
597print '<th class="right maxwidth100">'.$langs->trans("TimeSpent").($usertoprocess->firstname ? '<br><span class="opacitymedium">'.dol_trunc($usertoprocess->firstname, 10).'</span>' : '').'</th>';
598print '<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();
605if (!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);
620if ($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 = '';
627if ((($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 = '';
635if (!$isavailable[$daytoparse]['morning'] && !$isavailable[$daytoparse]['afternoon'])   $cssonholiday .= 'onholidayallday ';
636elseif (!$isavailable[$daytoparse]['morning'])   $cssonholiday .= 'onholidaymorning ';
637elseif (!$isavailable[$daytoparse]['afternoon']) $cssonholiday .= 'onholidayafternoon ';
638
639print '<th class="center'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">'.$langs->trans("Duration").'</th>';
640print '<th class="center">'.$langs->trans("Note").'</th>';
641//print '<td class="center"></td>';
642print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
643
644print "</tr>\n";
645
646$colspan = 4 + (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : 2);
647
648if ($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
666if (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}
754print "</table>";
755print '</div>';
756
757print '<input type="hidden" id="numberOfLines" name="numberOfLines" value="'.count($tasksarray).'"/>'."\n";
758
759print '<div class="center">';
760print '<input type="submit" class="button button-save"'.($disabledtask ? ' disabled' : '').' value="'.$langs->trans("Save").'">';
761print '</div>';
762
763print '</form>';
764
765$modeinput = 'hours';
766
767if ($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
787llxFooter();
788$db->close();
789