dolibarr 19.0.3
permonth.php
Go to the documentation of this file.
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@capnetworks.com>
5 * Copyright (C) 2010 François Legastelois <flegastelois@teclib.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
27require "../../main.inc.php";
28require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
29require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
30require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
31require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
32require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
35require_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
36
37// Load translation files required by the page
38$langs->loadLangs(array('projects', 'users', 'companies'));
39
40$action = GETPOST('action', 'aZ09');
41$mode = GETPOST("mode", 'alpha');
42$id = GETPOST('id', 'int');
43$taskid = GETPOST('taskid', 'int');
44
45$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'perweekcard';
46
47$mine = 0;
48if ($mode == 'mine') {
49 $mine = 1;
50}
51
52$projectid = GETPOSTISSET("id") ? GETPOST("id", "int", 1) : GETPOST("projectid", "int");
53
54$hookmanager->initHooks(array('timesheetpermonthcard'));
55
56// Security check
57$socid = 0;
58// For external user, no check is done on company because readability is managed by public status of project and assignement.
59// if ($user->socid > 0) $socid=$user->socid;
60$result = restrictedArea($user, 'projet', $projectid);
61
62$now = dol_now();
63
64$year = GETPOST('reyear', 'int') ? GETPOST('reyear', 'int') : (GETPOST("year", 'int') ? GETPOST("year", "int") : date("Y"));
65$month = GETPOST('remonth', 'int') ? GETPOST('remonth', 'int') : (GETPOST("month", 'int') ? GETPOST("month", "int") : date("m"));
66$day = GETPOST('reday', 'int') ? GETPOST('reday', 'int') : (GETPOST("day", 'int') ? GETPOST("day", "int") : date("d"));
67$week = GETPOST("week", "int") ? GETPOST("week", "int") : date("W");
68
69$day = (int) $day;
70
71//$search_categ = GETPOST("search_categ", 'alpha');
72$search_usertoprocessid = GETPOST('search_usertoprocessid', 'int');
73$search_task_ref = GETPOST('search_task_ref', 'alpha');
74$search_task_label = GETPOST('search_task_label', 'alpha');
75$search_project_ref = GETPOST('search_project_ref', 'alpha');
76$search_thirdparty = GETPOST('search_thirdparty', 'alpha');
77$search_declared_progress = GETPOST('search_declared_progress', 'alpha');
78
79$sortfield = GETPOST('sortfield', 'aZ09comma');
80$sortorder = GETPOST('sortorder', 'aZ09comma');
81
82$startdayarray = dol_get_prev_month($month, $year);
83
84$prev = $startdayarray;
85$prev_year = $prev['year'];
86$prev_month = $prev['month'];
87$prev_day = 1;
88
89$next = dol_get_next_month($month, $year);
90$next_year = $next['year'];
91$next_month = $next['month'];
92$next_day = 1;
93$TWeek = getWeekNumbersOfMonth($month, $year);
94$firstdaytoshow = dol_mktime(0, 0, 0, $month, 1, $year);
95$TFirstDays = getFirstDayOfEachWeek($TWeek, $year);
96$TFirstDays[reset($TWeek)] = '01'; //first day of month
97$TLastDays = getLastDayOfEachWeek($TWeek, $year);
98$TLastDays[end($TWeek)] = date("t", strtotime($year.'-'.$month.'-'.$day)); //last day of month
99if (empty($search_usertoprocessid) || $search_usertoprocessid == $user->id) {
100 $usertoprocess = $user;
101 $search_usertoprocessid = $usertoprocess->id;
102} elseif ($search_usertoprocessid > 0) {
103 $usertoprocess = new User($db);
104 $usertoprocess->fetch($search_usertoprocessid);
105 $search_usertoprocessid = $usertoprocess->id;
106} else {
107 $usertoprocess = new User($db);
108}
109
110$object = new Task($db);
111
112// Extra fields
113$extrafields = new ExtraFields($db);
114
115// fetch optionals attributes and labels
116$extrafields->fetch_name_optionals_label($object->table_element);
117
118// Definition of fields for list
119$arrayfields = array();
120/*$arrayfields=array(
121 // Project
122 'p.opp_amount'=>array('label'=>$langs->trans("OpportunityAmountShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>103),
123 'p.fk_opp_status'=>array('label'=>$langs->trans("OpportunityStatusShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>104),
124 'p.opp_percent'=>array('label'=>$langs->trans("OpportunityProbabilityShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>105),
125 'p.budget_amount'=>array('label'=>$langs->trans("Budget"), 'checked'=>0, 'position'=>110),
126 'p.usage_bill_time'=>array('label'=>$langs->trans("BillTimeShort"), 'checked'=>0, 'position'=>115),
127 );*/
128$arrayfields['t.planned_workload'] = array('label'=>'PlannedWorkload', 'checked'=>1, 'enabled'=>1, 'position'=>5);
129$arrayfields['t.progress'] = array('label'=>'ProgressDeclared', 'checked'=>1, 'enabled'=>1, 'position'=>10);
130$arrayfields['timeconsumed'] = array('label'=>'TimeConsumed', 'checked'=>1, 'enabled'=>1, 'position'=>15);
131/*foreach($object->fields as $key => $val)
132 {
133 // If $val['visible']==0, then we never show the field
134 if (!empty($val['visible'])) $arrayfields['t.'.$key]=array('label'=>$val['label'], 'checked'=>(($val['visible']<0)?0:1), 'enabled'=>$val['enabled'], 'position'=>$val['position']);
135 }*/
136// Definition of fields for list
137// Extra fields
138if (!empty($extrafields->attributes['projet_task']['label']) && is_array($extrafields->attributes['projet_task']['label']) && count($extrafields->attributes['projet_task']['label']) > 0) {
139 foreach ($extrafields->attributes['projet_task']['label'] as $key => $val) {
140 if (!empty($extrafields->attributes['projet_task']['list'][$key])) {
141 $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]));
142 }
143 }
144}
145$arrayfields = dol_sort_array($arrayfields, 'position');
146
147$search_array_options = array();
148$search_array_options_project = $extrafields->getOptionalsFromPost('projet', '', 'search_');
149$search_array_options_task = $extrafields->getOptionalsFromPost('projet_task', '', 'search_task_');
150
151$error = 0;
152
153
154/*
155 * Actions
156 */
157$parameters = array('id' => $id, 'taskid' => $taskid, 'projectid' => $projectid, 'TWeek' => $TWeek, 'TFirstDays' => $TFirstDays, 'TLastDays' => $TLastDays);
158$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
159if ($reshook < 0) {
160 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
161}
162
163// Purge criteria
164if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
165 $action = '';
166 //$search_categ = '';
167 $search_usertoprocessid = $user->id;
168 $search_task_ref = '';
169 $search_task_label = '';
170 $search_project_ref = '';
171 $search_thirdparty = '';
172 $search_declared_progress = '';
173
174 $search_array_options_project = array();
175 $search_array_options_task = array();
176
177 // We redefine $usertoprocess
178 $usertoprocess = $user;
179}
180if (GETPOST("button_search_x", 'alpha') || GETPOST("button_search.x", 'alpha') || GETPOST("button_search", 'alpha')) {
181 $action = '';
182}
183
184if (GETPOST('submitdateselect')) {
185 if (GETPOST('remonth', 'int') && GETPOST('reday', 'int') && GETPOST('reyear', 'int')) {
186 $daytoparse = dol_mktime(0, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
187 }
188
189 $action = '';
190}
191
192include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
193
194if ($action == 'addtime' && $user->hasRight('projet', 'lire') && GETPOST('assigntask') && GETPOST('formfilteraction') != 'listafterchangingselectedfields') {
195 $action = 'assigntask';
196
197 if ($taskid > 0) {
198 $result = $object->fetch($taskid, $ref);
199 if ($result < 0) {
200 $error++;
201 }
202 } else {
203 setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Task")), null, 'errors');
204 $error++;
205 }
206 if (!GETPOST('type')) {
207 setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
208 $error++;
209 }
210
211 if (!$error) {
212 $idfortaskuser = $usertoprocess->id;
213 $result = $object->add_contact($idfortaskuser, GETPOST("type"), 'internal');
214
215 if ($result >= 0 || $result == -2) { // Contact add ok or already contact of task
216 // 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)
217 $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';
218 $sql .= ' AND ec.fk_socpeople = '.((int) $idfortaskuser)." AND ec.element_id = ".((int) $object->fk_project)." AND tc.element = 'project' AND source = 'internal'";
219 $resql = $db->query($sql);
220 if ($resql) {
221 $obj = $db->fetch_object($resql);
222 if (!$obj) { // User is not already linked to project, so we will create link to first type
223 $project = new Project($db);
224 $project->fetch($object->fk_project);
225 // Get type
226 $listofprojcontact = $project->liste_type_contact('internal');
227
228 if (count($listofprojcontact)) {
229 $tmparray = array_keys($listofprojcontact);
230 $typeforprojectcontact = reset($tmparray);
231 $result = $project->add_contact($idfortaskuser, $typeforprojectcontact, 'internal');
232 }
233 }
234 } else {
235 dol_print_error($db);
236 }
237 }
238 }
239
240 if ($result < 0) {
241 $error++;
242 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
243 $langs->load("errors");
244 setEventMessages($langs->trans("ErrorTaskAlreadyAssigned"), null, 'warnings');
245 } else {
246 setEventMessages($object->error, $object->errors, 'errors');
247 }
248 }
249
250 if (!$error) {
251 setEventMessages("TaskAssignedToEnterTime", null);
252 $taskid = 0;
253 }
254
255 $action = '';
256}
257
258if ($action == 'addtime' && $user->hasRight('projet', 'lire') && GETPOST('formfilteraction') != 'listafterchangingselectedfields') {
259 $timetoadd = GETPOST('task');
260 if (empty($timetoadd)) {
261 setEventMessages($langs->trans("ErrorTimeSpentIsEmpty"), null, 'errors');
262 } else {
263 foreach ($timetoadd as $tmptaskid => $tmpvalue) { // Loop on each task
264 $updateoftaskdone = 0;
265 foreach ($tmpvalue as $key => $val) { // Loop on each day
266 $amountoadd = $timetoadd[$tmptaskid][$key];
267 if (!empty($amountoadd)) {
268 $tmpduration = explode(':', $amountoadd);
269 $newduration = 0;
270 if (!empty($tmpduration[0])) {
271 $newduration += ($tmpduration[0] * 3600);
272 }
273 if (!empty($tmpduration[1])) {
274 $newduration += ($tmpduration[1] * 60);
275 }
276 if (!empty($tmpduration[2])) {
277 $newduration += ($tmpduration[2]);
278 }
279
280 if ($newduration > 0) {
281 $object->fetch($tmptaskid);
282
283 if (GETPOSTISSET($tmptaskid.'progress')) {
284 $object->progress = GETPOST($tmptaskid.'progress', 'int');
285 } else {
286 unset($object->progress);
287 }
288
289 $object->timespent_duration = $newduration;
290 $object->timespent_fk_user = $usertoprocess->id;
291 $object->timespent_date = dol_time_plus_duree($firstdaytoshow, $key, 'd');
292 $object->timespent_datehour = $object->timespent_date;
293 $object->timespent_note = $object->description;
294
295 $result = $object->addTimeSpent($user);
296 if ($result < 0) {
297 setEventMessages($object->error, $object->errors, 'errors');
298 $error++;
299 break;
300 }
301
302 $updateoftaskdone++;
303 }
304 }
305 }
306
307 if (!$updateoftaskdone) { // Check to update progress if no update were done on task.
308 $object->fetch($tmptaskid);
309 //var_dump($object->progress);
310 //var_dump(GETPOST($tmptaskid . 'progress', 'int')); exit;
311 if ($object->progress != GETPOST($tmptaskid.'progress', 'int')) {
312 $object->progress = GETPOST($tmptaskid.'progress', 'int');
313 $result = $object->update($user);
314 if ($result < 0) {
315 setEventMessages($object->error, $object->errors, 'errors');
316 $error++;
317 break;
318 }
319 }
320 }
321 }
322
323 if (!$error) {
324 setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
325
326 $param = '';
327 $param .= ($mode ? '&mode='.urlencode($mode) : '');
328 $param .= ($projectid ? 'id='.urlencode($projectid) : '');
329 $param .= ($search_usertoprocessid ? '&search_usertoprocessid='.urlencode($search_usertoprocessid) : '');
330 $param .= ($day ? '&day='.urlencode($day) : '').($month ? '&month='.urlencode($month) : '').($year ? '&year='.urlencode($year) : '');
331 $param .= ($search_project_ref ? '&search_project_ref='.urlencode($search_project_ref) : '');
332 $param .= ($search_usertoprocessid > 0 ? '&search_usertoprocessid='.urlencode($search_usertoprocessid) : '');
333 $param .= ($search_thirdparty ? '&search_thirdparty='.urlencode($search_thirdparty) : '');
334 $param .= ($search_declared_progress ? '&search_declared_progress='.urlencode($search_declared_progress) : '');
335 $param .= ($search_task_ref ? '&search_task_ref='.urlencode($search_task_ref) : '');
336 $param .= ($search_task_label ? '&search_task_label='.urlencode($search_task_label) : '');
337
338 /*$search_array_options=$search_array_options_project;
339 $search_options_pattern='search_options_';
340 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
341 */
342
343 $search_array_options = $search_array_options_task;
344 $search_options_pattern = 'search_task_options_';
345 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
346
347 // Redirect to avoid submit twice on back
348 header('Location: '.$_SERVER["PHP_SELF"].'?'.$param);
349 exit;
350 }
351 }
352}
353
354
355
356/*
357 * View
358 */
359
360$form = new Form($db);
361$formother = new FormOther($db);
362$formcompany = new FormCompany($db);
363$formproject = new FormProjets($db);
364$projectstatic = new Project($db);
365$project = new Project($db);
366$taskstatic = new Task($db);
367$thirdpartystatic = new Societe($db);
368$holiday = new Holiday($db);
369
370$title = $langs->trans("TimeSpent");
371
372$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
373//var_dump($projectsListId);
374if ($id) {
375 $project->fetch($id);
376 $project->fetch_thirdparty();
377}
378
379$onlyopenedproject = 1; // or -1
380$morewherefilter = '';
381
382if ($search_project_ref) {
383 $morewherefilter .= natural_search(array("p.ref", "p.title"), $search_project_ref);
384}
385if ($search_task_ref) {
386 $morewherefilter .= natural_search("t.ref", $search_task_ref);
387}
388if ($search_task_label) {
389 $morewherefilter .= natural_search(array("t.ref", "t.label"), $search_task_label);
390}
391if ($search_thirdparty) {
392 $morewherefilter .= natural_search("s.nom", $search_thirdparty);
393}
394if ($search_declared_progress) {
395 $morewherefilter .= natural_search("t.progress", $search_declared_progress, 1);
396}
397
398$sql = &$morewherefilter;
399
400/*$search_array_options = $search_array_options_project;
401 $extrafieldsobjectprefix='efp.';
402 $search_options_pattern='search_options_';
403 $extrafieldsobjectkey='projet';
404 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
405 */
406$search_array_options = $search_array_options_task;
407$extrafieldsobjectprefix = 'efpt.';
408$search_options_pattern = 'search_task_options_';
409$extrafieldsobjectkey = 'projet_task';
410include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
411
412$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.
413if ($morewherefilter) { // Get all task without any filter, so we can show total of time spent for not visible tasks
414 $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.
415}
416$projectsrole = $taskstatic->getUserRolesForProjectsOrTasks($usertoprocess, null, ($project->id ? $project->id : 0), 0, $onlyopenedproject);
417$tasksrole = $taskstatic->getUserRolesForProjectsOrTasks(null, $usertoprocess, ($project->id ? $project->id : 0), 0, $onlyopenedproject);
418//var_dump($tasksarray);
419//var_dump($projectsrole);
420//var_dump($taskrole);
421
422
423llxHeader("", $title, "", '', '', '', array('/core/js/timesheet.js'));
424
425//print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num, '', 'project');
426
427$param = '';
428$param .= ($mode ? '&mode='.urlencode($mode) : '');
429$param .= ($search_project_ref ? '&search_project_ref='.urlencode($search_project_ref) : '');
430$param .= ($search_usertoprocessid > 0 ? '&search_usertoprocessid='.urlencode($search_usertoprocessid) : '');
431$param .= ($search_thirdparty ? '&search_thirdparty='.urlencode($search_thirdparty) : '');
432$param .= ($search_task_ref ? '&search_task_ref='.urlencode($search_task_ref) : '');
433$param .= ($search_task_label ? '&search_task_label='.urlencode($search_task_label) : '');
434
435$search_array_options = $search_array_options_project;
436$search_options_pattern = 'search_options_';
437include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
438
439$search_array_options = $search_array_options_task;
440$search_options_pattern = 'search_task_options_';
441include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
442
443// Show navigation bar
444$nav = '<a class="inline-block valignmiddle" href="?year='.$prev_year."&month=".$prev_month."&day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n";
445$nav .= ' <span id="month_name">'.dol_print_date(dol_mktime(0, 0, 0, $month, 1, $year), "%Y").", ".$langs->trans(date('F', mktime(0, 0, 0, $month, 10)))." </span>\n";
446$nav .= '<a class="inline-block valignmiddle" href="?year='.$next_year."&month=".$next_month."&day=".$next_day.$param.'">'.img_next($langs->trans("Next"))."</a>\n";
447$nav .= ' '.$form->selectDate(-1, '', 0, 0, 2, "addtime", 1, 1).' ';
448$nav .= ' <button type="submit" name="submitdateselect" value="x" class="bordertransp nobordertransp button_search_x"><span class="fa fa-search"></span></button>';
449
450$picto = 'clock';
451
452print '<form name="addtime" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
453print '<input type="hidden" name="token" value="'.newToken().'">';
454print '<input type="hidden" name="action" value="addtime">';
455print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
456print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
457print '<input type="hidden" name="mode" value="'.$mode.'">';
458print '<input type="hidden" name="day" value="'.$day.'">';
459print '<input type="hidden" name="month" value="'.$month.'">';
460print '<input type="hidden" name="year" value="'.$year.'">';
461
462$head = project_timesheet_prepare_head($mode, $usertoprocess);
463print dol_get_fiche_head($head, 'inputpermonth', $langs->trans('TimeSpent'), -1, $picto);
464
465// Show description of content
466print '<div class="hideonsmartphone opacitymedium">';
467if ($mine || ($usertoprocess->id == $user->id)) {
468 print $langs->trans("MyTasksDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
469} else {
470 if (empty($usertoprocess->id) || $usertoprocess->id < 0) {
471 if ($user->hasRight('projet', 'all', 'lire') && !$socid) {
472 print $langs->trans("ProjectsDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
473 } else {
474 print $langs->trans("ProjectsPublicTaskDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
475 }
476 }
477}
478if ($mine || ($usertoprocess->id == $user->id)) {
479 print $langs->trans("OnlyYourTaskAreVisible").'<br>';
480} else {
481 print $langs->trans("AllTaskVisibleButEditIfYouAreAssigned").'<br>';
482}
483print '</div>';
484
485print dol_get_fiche_end();
486
487print '<div class="'.($conf->dol_optimize_smallscreen ? 'center centpercent' : 'floatright right').'">'.$nav.'</div>'; // We move this before the assign to components so, the default submit button is not the assign to.
488
489print '<div class="colorbacktimesheet valignmiddle'.($conf->dol_optimize_smallscreen ? ' center' : ' float').'">';
490$titleassigntask = $langs->transnoentities("AssignTaskToMe");
491if ($usertoprocess->id != $user->id) {
492 $titleassigntask = $langs->transnoentities("AssignTaskToUser", $usertoprocess->getFullName($langs));
493}
494print '<div class="taskiddiv inline-block">';
495print img_picto('', 'projecttask', 'class="pictofixedwidth"');
496$formproject->selectTasks($socid ? $socid : -1, $taskid, 'taskid', 32, 0, '-- '.$langs->trans("ChooseANotYetAssignedTask").' --', 1, 0, 0, 'widthcentpercentminusx');
497print '</div>';
498print ' ';
499print $formcompany->selectTypeContact($object, '', 'type', 'internal', 'position', 0, 'maxwidth150onsmartphone');
500print '<input type="submit" class="button valignmiddle smallonsmartphone small" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">';
501print '</div>';
502
503print '<div class="clearboth" style="padding-bottom: 20px;"></div>';
504
505
506$moreforfilter = '';
507
508// Filter on categories
509/*
510if (isModEnabled("categorie")) {
511 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
512 $moreforfilter.='<div class="divsearchfield">';
513 $moreforfilter.=$langs->trans('ProjectCategories'). ': ';
514 $moreforfilter.=$formother->select_categories('project', $search_categ, 'search_categ', 1, 1, 'maxwidth300');
515 $moreforfilter.='</div>';
516}*/
517
518// If the user can view user other than himself
519$moreforfilter .= '<div class="divsearchfield">';
520$moreforfilter .= '<div class="inline-block hideonsmartphone"></div>';
521$includeonly = 'hierarchyme';
522if (!$user->hasRight('user', 'user', 'lire')) {
523 $includeonly = array($user->id);
524}
525$moreforfilter .= img_picto($langs->trans('Filter').' '.$langs->trans('User'), 'user', 'class="paddingright pictofixedwidth"').$form->select_dolusers($search_usertoprocessid ? $search_usertoprocessid : $usertoprocess->id, 'search_usertoprocessid', $user->hasRight('user', 'user', 'lire') ? 0 : 0, null, 0, $includeonly, null, 0, 0, 0, '', 0, '', 'maxwidth200');
526$moreforfilter .= '</div>';
527
528if (!getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
529 $moreforfilter .= '<div class="divsearchfield">';
530 $moreforfilter .= '<div class="inline-block"></div>';
531 $moreforfilter .= img_picto($langs->trans('Filter').' '.$langs->trans('Project'), 'project', 'class="paddingright pictofixedwidth"').'<input type="text" name="search_project_ref" class="maxwidth100" value="'.dol_escape_htmltag($search_project_ref).'">';
532 $moreforfilter .= '</div>';
533
534 $moreforfilter .= '<div class="divsearchfield">';
535 $moreforfilter .= '<div class="inline-block"></div>';
536 $moreforfilter .= img_picto($langs->trans('Filter').' '.$langs->trans('ThirdParty'), 'company', 'class="paddingright pictofixedwidth"').'<input type="text" name="search_thirdparty" class="maxwidth100" value="'.dol_escape_htmltag($search_thirdparty).'">';
537 $moreforfilter .= '</div>';
538}
539
540if (!empty($moreforfilter)) {
541 print '<div class="liste_titre liste_titre_bydiv centpercent">';
542 print $moreforfilter;
543 $parameters = array();
544 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
545 print $hookmanager->resPrint;
546 print '</div>';
547}
548
549print '<div class="div-table-responsive">';
550
551print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'" id="tablelines3">'."\n";
552
553print '<tr class="liste_titre_filter">';
554if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
555 print '<td class="liste_titre"><input type="text" size="4" name="search_project_ref" value="'.dol_escape_htmltag($search_project_ref).'"></td>';
556}
557if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
558 print '<td class="liste_titre"><input type="text" size="4" name="search_thirdparty" value="'.dol_escape_htmltag($search_thirdparty).'"></td>';
559}
560print '<td class="liste_titre"><input type="text" size="4" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
561print '<td class="liste_titre"></td>';
562print '<td class="liste_titre right"><input type="text" size="4" name="search_declared_progress" value="'.dol_escape_htmltag($search_declared_progress).'"></td>';
563print '<td class="liste_titre"></td>';
564print '<td class="liste_titre"></td>';
565foreach ($TWeek as $week_number) {
566 print '<td class="liste_titre"></td>';
567}
568// Action column
569print '<td class="liste_titre nowrap" align="right">';
570$searchpicto = $form->showFilterAndCheckAddButtons(0);
571print $searchpicto;
572print '</td>';
573print "</tr>\n";
574
575print '<tr class="liste_titre">';
576if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
577 print '<td>'.$langs->trans("Project").'</td>';
578}
579if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
580 print '<td>'.$langs->trans("ThirdParty").'</td>';
581}
582print '<td>'.$langs->trans("Task").'</td>';
583print '<td align="right" class="leftborder plannedworkload maxwidth75">'.$langs->trans("PlannedWorkload").'</td>';
584print '<td align="right" class="maxwidth75">'.$langs->trans("ProgressDeclared").'</td>';
585/*print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpent").'</td>';
586 if ($usertoprocess->id == $user->id) print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpentByYou").'</td>';
587 else print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpentByUser").'</td>';*/
588print '<td class="right maxwidth100">'.$langs->trans("TimeSpentSmall").'<br>';
589print '<span class="nowraponall">';
590print '<span class="opacitymedium nopadding userimg"><img alt="Photo" class="photouserphoto userphoto" src="'.DOL_URL_ROOT.'/theme/common/everybody.png"></span>';
591print '<span class="opacitymedium paddingleft">'.$langs->trans("EverybodySmall").'</span>';
592print '</span>';
593print '</td>';
594print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpentSmall").($usertoprocess->firstname ? '<br><span class="nowraponall">'.$usertoprocess->getNomUrl(-2).'<span class="opacitymedium paddingleft">'.dol_trunc($usertoprocess->firstname, 10).'</span></span>' : '').'</td>';
595
596foreach ($TWeek as $week_number) {
597 print '<td width="6%" class="center bold hide">'.$langs->trans("Week").' '.$week_number.'<br>('.$TFirstDays[$week_number].'...'.$TLastDays[$week_number].')</td>';
598}
599print '<td></td>';
600print "</tr>\n";
601
602$colspan = 5;
603
604
605// Get if user is available or not for each day
606$isavailable = array();
607// TODO See code into perweek.php to initialize isavailable array
608
609// By default, we can edit only tasks we are assigned to
610$restrictviewformytask = ((!isset($conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED)) ? 2 : $conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED);
611if (count($tasksarray) > 0) {
612 //var_dump($tasksarray); // contains only selected tasks
613 //var_dump($tasksarraywithoutfilter); // contains all tasks (if there is a filter, not defined if no filter)
614 //var_dump($tasksrole);
615
616 $j = 0;
617 $level = 0;
618 $totalforvisibletasks = projectLinesPerMonth($j, $firstdaytoshow, $usertoprocess, 0, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restrictviewformytask, $isavailable, 0, $TWeek);
619 //var_dump($totalforvisibletasks);
620
621 // Show total for all other tasks
622
623 // Calculate total for all tasks
624 $listofdistinctprojectid = array(); // List of all distinct projects
625 if (!empty($tasksarraywithoutfilter) && is_array($tasksarraywithoutfilter) && count($tasksarraywithoutfilter)) {
626 foreach ($tasksarraywithoutfilter as $tmptask) {
627 $listofdistinctprojectid[$tmptask->fk_project] = $tmptask->fk_project;
628 }
629 }
630 //var_dump($listofdistinctprojectid);
631 $totalforeachweek = array();
632 foreach ($listofdistinctprojectid as $tmpprojectid) {
633 $projectstatic->id = $tmpprojectid;
634 $projectstatic->loadTimeSpentMonth($firstdaytoshow, 0, $usertoprocess->id); // Load time spent from table element_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week
635 foreach ($TWeek as $weekNb) {
636 $totalforeachweek[$weekNb] += $projectstatic->monthWorkLoad[$weekNb];
637 }
638 }
639
640 //var_dump($totalforeachday);
641 //var_dump($totalforvisibletasks);
642
643 // Is there a diff between selected/filtered tasks and all tasks ?
644 $isdiff = 0;
645 if (count($totalforeachweek)) {
646 foreach ($TWeek as $weekNb) {
647 $timeonothertasks = ($totalforeachweek[$weekNb] - $totalforvisibletasks[$weekNb]);
648 if ($timeonothertasks) {
649 $isdiff = 1;
650 break;
651 }
652 }
653 }
654
655 // 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
656 if ($isdiff) {
657 print '<tr class="oddeven othertaskwithtime">';
658 print '<td colspan="'.$colspan.'" class="opacitymedium">';
659 print $langs->trans("OtherFilteredTasks");
660 print '</td>';
661 foreach ($TWeek as $weekNb) {
662 print '<td class="center hide">';
663
664 $timeonothertasks = ($totalforeachweek[$weekNb] - $totalforvisibletasks[$weekNb]);
665 if ($timeonothertasks) {
666 print '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center smallpadd width40" disabled="" id="timespent[-1]['.$weekNb.']" name="task[-1]['.$weekNb.']" value="';
667 print convertSecondToTime($timeonothertasks, 'allhourmin');
668 print '"></span>';
669 }
670 print '</td>';
671 }
672 print ' <td class="liste_total"></td>';
673 print '</tr>';
674 }
675
676 if ($conf->use_javascript_ajax) {
677 print '<tr class="liste_total">';
678 print '<td class="liste_total" colspan="'.$colspan.'">';
679 print $langs->trans("Total");
680 print '<span class="opacitymediumbycolor"> - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong></span>';
681 print '</td>';
682
683 foreach ($TWeek as $weekNb) {
684 print '<td class="liste_total hide'.$weekNb.'" align="center"><div class="totalDay'.$weekNb.'">'.convertSecondToTime($totalforvisibletasks[$weekNb], 'allhourmin').'</div></td>';
685 }
686 print '<td class="liste_total center"><div class="totalDayAll">&nbsp;</div></td>
687 </tr>';
688 }
689} else {
690 print '<tr><td colspan="15"><span class="opacitymedium">'.$langs->trans("NoAssignedTasks").'</span></td></tr>';
691}
692print "</table>";
693print '</div>';
694
695print '<input type="hidden" id="numberOfLines" name="numberOfLines" value="'.count($tasksarray).'"/>'."\n";
696print '<input type="hidden" id="numberOfFirstLine" name="numberOfFirstLine" value="'.(reset($TWeek)).'"/>'."\n";
697
698print $form->buttonsSaveCancel("Save", '');
699
700print '</form>'."\n\n";
701
702$modeinput = 'hours';
703
704if ($conf->use_javascript_ajax) {
705 print "\n<!-- JS CODE TO ENABLE Tooltips on all object with class classfortooltip -->\n";
706 print '<script type="text/javascript">'."\n";
707 print "jQuery(document).ready(function () {\n";
708 print ' jQuery(".timesheetalreadyrecorded").tooltip({
709 show: { collision: "flipfit", effect:\'toggle\', delay:50 },
710 hide: { effect:\'toggle\', delay: 50 },
711 tooltipClass: "mytooltip",
712 content: function () {
713 return \''.dol_escape_js($langs->trans("TimeAlreadyRecorded", $usertoprocess->getFullName($langs))).'\';
714 }
715 });'."\n";
716
717 foreach ($TWeek as $week_number) {
718 print " updateTotal(".((int) $week_number).", '".dol_escape_js($modeinput)."');";
719 }
720 print "\n});\n";
721 print '</script>';
722}
723
724// End of page
725llxFooter();
726$db->close();
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:55
Class to manage standard extra fields.
Class to build HTML component for third parties management Only common components are here.
Class to manage generation of HTML components Only common components must be here.
Classe permettant la generation de composants html autre Only common components are here.
Class to manage building of HTML components.
Class of the module paid holiday.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage tasks.
Class to manage Dolibarr users.
dol_get_prev_month($month, $year)
Return previous month.
Definition date.lib.php:513
getLastDayOfEachWeek($TWeek, $year)
Return array of last day of weeks.
getWeekNumbersOfMonth($month, $year)
Return array of week numbers.
getFirstDayOfEachWeek($TWeek, $year)
Return array of first day of weeks.
dol_get_next_month($month, $year)
Return next month.
Definition date.lib.php:532
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:125
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:243
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_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
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.
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...
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
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...
img_previous($titlealt='default', $moreatt='')
Show previous logo.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
img_next($titlealt='default', $moreatt='')
Show next logo.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
projectLinesPerMonth(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak=0, $TWeek=array())
Output a task line into a perday intput mode.
project_timesheet_prepare_head($mode, $fuser=null)
Prepare array with list of tabs.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.