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 .= " &nbsp; (<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.'">&nbsp;</div></td>';
708	}
709	print '<td class="liste_total center"><div class="totalDayAll">&nbsp;</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.'">&nbsp;</div></td>';
824		}
825				print '<td class="liste_total center"><div class="totalDayAll">&nbsp;</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