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