dolibarr 21.0.0-alpha
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 += (int) ((float) $tmpduration[0] * 3600);
275 }
276 if (!empty($tmpduration[1])) {
277 $newduration += (int) ((float) $tmpduration[1] * 60);
278 }
279 if (!empty($tmpduration[2])) {
280 $newduration += ((int) $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$tasksarraywithoutfilter = array(); // Default
416
417$tasksarray = $taskstatic->getTasksArray(null, null, ($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.
418if ($morewherefilter) { // Get all task without any filter, so we can show total of time spent for not visible tasks
419 $tasksarraywithoutfilter = $taskstatic->getTasksArray(null, null, ($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.
420}
421$projectsrole = $taskstatic->getUserRolesForProjectsOrTasks($usertoprocess, null, ($project->id ? $project->id : 0), 0, $onlyopenedproject);
422$tasksrole = $taskstatic->getUserRolesForProjectsOrTasks(null, $usertoprocess, ($project->id ? $project->id : 0), 0, $onlyopenedproject);
423//var_dump($tasksarray);
424//var_dump($projectsrole);
425//var_dump($taskrole);
426
427
428llxHeader('', $title, '', '', 0, 0, array('/core/js/timesheet.js'), '', '', 'mod-project project-activity page-activity_permonth');
429
430//print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num, '', 'project');
431
432$param = '';
433$param .= ($mode ? '&mode='.urlencode($mode) : '');
434$param .= ($search_project_ref ? '&search_project_ref='.urlencode($search_project_ref) : '');
435$param .= ($search_usertoprocessid > 0 ? '&search_usertoprocessid='.urlencode($search_usertoprocessid) : '');
436$param .= ($search_thirdparty ? '&search_thirdparty='.urlencode($search_thirdparty) : '');
437$param .= ($search_task_ref ? '&search_task_ref='.urlencode($search_task_ref) : '');
438$param .= ($search_task_label ? '&search_task_label='.urlencode($search_task_label) : '');
439
440$search_array_options = $search_array_options_project;
441$search_options_pattern = 'search_options_';
442include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
443
444$search_array_options = $search_array_options_task;
445$search_options_pattern = 'search_task_options_';
446include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
447
448// Show navigation bar
449$nav = '<a class="inline-block valignmiddle" href="?year='.$prev_year."&month=".$prev_month."&day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n";
450$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";
451$nav .= '<a class="inline-block valignmiddle" href="?year='.$next_year."&month=".$next_month."&day=".$next_day.$param.'">'.img_next($langs->trans("Next"))."</a>\n";
452$nav .= ' '.$form->selectDate(-1, '', 0, 0, 2, "addtime", 1, ($conf->dol_optimize_smallscreen ? 0 : 1)).' ';
453$nav .= ' <button type="submit" name="submitdateselect" value="x" class="bordertransp nobordertransp button_search_x"><span class="fa fa-search"></span></button>';
454
455$picto = 'clock';
456
457print '<form name="addtime" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
458print '<input type="hidden" name="token" value="'.newToken().'">';
459print '<input type="hidden" name="action" value="addtime">';
460print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
461print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
462print '<input type="hidden" name="mode" value="'.$mode.'">';
463print '<input type="hidden" name="day" value="'.$day.'">';
464print '<input type="hidden" name="month" value="'.$month.'">';
465print '<input type="hidden" name="year" value="'.$year.'">';
466
467$head = project_timesheet_prepare_head($mode, $usertoprocess);
468print dol_get_fiche_head($head, 'inputpermonth', $langs->trans('TimeSpent'), -1, $picto);
469
470// Show description of content
471print '<div class="hideonsmartphone opacitymedium">';
472if ($mine || ($usertoprocess->id == $user->id)) {
473 print $langs->trans("MyTasksDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
474} else {
475 if (empty($usertoprocess->id) || $usertoprocess->id < 0) {
476 if ($user->hasRight('projet', 'all', 'lire') && !$socid) {
477 print $langs->trans("ProjectsDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
478 } else {
479 print $langs->trans("ProjectsPublicTaskDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
480 }
481 }
482}
483if ($mine || ($usertoprocess->id == $user->id)) {
484 print $langs->trans("OnlyYourTaskAreVisible").'<br>';
485} else {
486 print $langs->trans("AllTaskVisibleButEditIfYouAreAssigned").'<br>';
487}
488print '</div>';
489
490print dol_get_fiche_end();
491
492print '<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.
493
494print '<div class="colorbacktimesheet valignmiddle'.($conf->dol_optimize_smallscreen ? ' center' : ' float').'">';
495$titleassigntask = $langs->transnoentities("AssignTaskToMe");
496if ($usertoprocess->id != $user->id) {
497 $titleassigntask = $langs->transnoentities("AssignTaskToUser", $usertoprocess->getFullName($langs));
498}
499print '<div class="taskiddiv inline-block">';
500print img_picto('', 'projecttask', 'class="pictofixedwidth"');
501$formproject->selectTasks($socid ? $socid : -1, $taskid, 'taskid', 32, 0, '-- '.$langs->trans("ChooseANotYetAssignedTask").' --', 1, 0, 0, 'widthcentpercentminusx', '', 'all', $usertoprocess);
502print '</div>';
503print ' ';
504print $formcompany->selectTypeContact($object, '', 'type', 'internal', 'position', 0, 'maxwidth150onsmartphone');
505print '<input type="submit" class="button valignmiddle smallonsmartphone small" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">';
506print '</div>';
507
508print '<div class="clearboth" style="padding-bottom: 20px;"></div>';
509
510
511$moreforfilter = '';
512
513// Filter on categories
514/*
515if (isModEnabled("categorie")) {
516 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
517 $moreforfilter.='<div class="divsearchfield">';
518 $moreforfilter.=$langs->trans('ProjectCategories'). ': ';
519 $moreforfilter.=$formother->select_categories('project', $search_categ, 'search_categ', 1, 1, 'maxwidth300');
520 $moreforfilter.='</div>';
521}*/
522
523// If the user can view user other than himself
524$includeonly = 'hierarchyme';
525if (!$user->hasRight('user', 'user', 'lire')) {
526 $includeonly = array($user->id);
527}
528$selecteduser = $search_usertoprocessid ? $search_usertoprocessid : $usertoprocess->id;
529$moreforfiltertmp = $form->select_dolusers($selecteduser, 'search_usertoprocessid', 0, null, 0, $includeonly, array(), 0, 0, 0, '', 0, '', 'maxwidth200');
530if ($form->num > 1 || empty($conf->dol_optimize_smallscreen)) {
531 $moreforfilter .= '<div class="divsearchfield">';
532 $moreforfilter .= '<div class="inline-block hideonsmartphone"></div>';
533 $moreforfilter .= img_picto($langs->trans('Filter').' '.$langs->trans('User'), 'user', 'class="paddingright pictofixedwidth"');
534 $moreforfilter .= $moreforfiltertmp;
535 $moreforfilter .= '</div>';
536} else {
537 $moreforfilter .= '<input type="hidden" name="search_usertoprocessid" value="'.$selecteduser.'">';
538}
539
540if (!getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
541 $moreforfilter .= '<div class="divsearchfield">';
542 $moreforfilter .= '<div class="inline-block"></div>';
543 $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).'">';
544 $moreforfilter .= '</div>';
545
546 $moreforfilter .= '<div class="divsearchfield">';
547 $moreforfilter .= '<div class="inline-block"></div>';
548 $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).'">';
549 $moreforfilter .= '</div>';
550}
551
552if (!empty($moreforfilter)) {
553 print '<div class="liste_titre liste_titre_bydiv centpercent">';
554 print $moreforfilter;
555 $parameters = array();
556 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
557 print $hookmanager->resPrint;
558 print '</div>';
559}
560
561$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
562
563$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
564
565// This must be after the $selectedfields
566$addcolspan = 0;
567if (!empty($arrayfields['t.planned_workload']['checked'])) {
568 $addcolspan++;
569}
570if (!empty($arrayfields['t.progress']['checked'])) {
571 $addcolspan++;
572}
573foreach ($arrayfields as $key => $val) {
574 if ($val['checked'] && substr($key, 0, 5) == 'efpt.') {
575 $addcolspan++;
576 }
577}
578
579print '<div class="div-table-responsive">';
580
581print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'" id="tablelines3">'."\n";
582
583print '<tr class="liste_titre_filter">';
584if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
585 print '<td class="liste_titre"><input type="text" size="4" name="search_project_ref" value="'.dol_escape_htmltag($search_project_ref).'"></td>';
586}
587if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
588 print '<td class="liste_titre"><input type="text" size="4" name="search_thirdparty" value="'.dol_escape_htmltag($search_thirdparty).'"></td>';
589}
590print '<td class="liste_titre"><input type="text" size="4" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
591if (!empty($arrayfields['t.planned_workload']['checked'])) {
592 print '<td class="liste_titre"></td>';
593}
594if (!empty($arrayfields['t.progress']['checked'])) {
595 print '<td class="liste_titre right"><input type="text" size="4" name="search_declared_progress" value="'.dol_escape_htmltag($search_declared_progress).'"></td>';
596}
597if (!empty($arrayfields['timeconsumed']['checked'])) {
598 print '<td class="liste_titre"></td>';
599 print '<td class="liste_titre"></td>';
600}
601foreach ($TWeek as $week_number) {
602 print '<td class="liste_titre"></td>';
603}
604// Action column
605print '<td class="liste_titre nowrap right">';
606$searchpicto = $form->showFilterAndCheckAddButtons(0);
607print $searchpicto;
608print '</td>';
609print "</tr>\n";
610
611print '<tr class="liste_titre">';
612if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
613 print '<td>'.$langs->trans("Project").'</td>';
614}
615if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
616 print '<td>'.$langs->trans("ThirdParty").'</td>';
617}
618print '<td>'.$langs->trans("Task").'</td>';
619if (!empty($arrayfields['t.planned_workload']['checked'])) {
620 print '<td align="right" class="leftborder plannedworkload maxwidth75">'.$form->textwithpicto($langs->trans("PlannedWorkloadShort"), $langs->trans("PlannedWorkload")).'</td>';
621}
622if (!empty($arrayfields['t.progress']['checked'])) {
623 print '<td class="right maxwidth75">'.$langs->trans("ProgressDeclared").'</td>';
624}
625if (!empty($arrayfields['timeconsumed']['checked'])) {
626 print '<td class="right maxwidth100">'.$langs->trans("TimeSpentSmall").'<br>';
627 print '<span class="nowraponall">';
628 print '<span class="opacitymedium nopadding userimg"><img alt="Photo" class="photouserphoto userphoto" src="'.DOL_URL_ROOT.'/theme/common/everybody.png"></span>';
629 print '<span class="opacitymedium paddingleft">'.$langs->trans("EverybodySmall").'</span>';
630 print '</span>';
631 print '</td>';
632 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>';
633}
634foreach ($TWeek as $week_number) {
635 print '<td width="6%" class="center bold hide">'.$langs->trans("WeekShort").' '.$week_number.'<br>('.$TFirstDays[$week_number].'...'.$TLastDays[$week_number].')</td>';
636}
637
638//print '<td></td>';
639print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
640
641print "</tr>\n";
642
643$colspan = 1;
644
645
646// Get if user is available or not for each day
647$isavailable = array();
648// TODO See code into perweek.php to initialize isavailable array
649
650// By default, we can edit only tasks we are assigned to
651$restrictviewformytask = getDolGlobalInt('PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED', 2);
652if (count($tasksarray) > 0) {
653 //var_dump($tasksarray); // contains only selected tasks
654 //var_dump($tasksarraywithoutfilter); // contains all tasks (if there is a filter, not defined if no filter)
655 //var_dump($tasksrole);
656
657 $j = 0;
658 $level = 0;
659 $totalforvisibletasks = projectLinesPerMonth($j, $firstdaytoshow, $usertoprocess, 0, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restrictviewformytask, $isavailable, 0, $TWeek, $arrayfields);
660 //var_dump($totalforvisibletasks);
661
662 // Show total for all other tasks
663
664 // Calculate total for all tasks
665 $listofdistinctprojectid = array(); // List of all distinct projects
666 if (!empty($tasksarraywithoutfilter) && is_array($tasksarraywithoutfilter) && count($tasksarraywithoutfilter)) {
667 foreach ($tasksarraywithoutfilter as $tmptask) {
668 $listofdistinctprojectid[$tmptask->fk_project] = $tmptask->fk_project;
669 }
670 }
671 //var_dump($listofdistinctprojectid);
672 $totalforeachweek = array();
673 '@phan-var-force array<string,int> $totalforeachweek';
674
675 foreach ($listofdistinctprojectid as $tmpprojectid) {
676 $projectstatic->id = $tmpprojectid;
677 $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
678 foreach ($TWeek as $weekNb) {
679 $totalforeachweek[$weekNb] += $projectstatic->monthWorkLoad[$weekNb];
680 }
681 }
682
683 //var_dump($totalforeachday);
684 //var_dump($totalforvisibletasks);
685
686 // Is there a diff between selected/filtered tasks and all tasks ?
687 $isdiff = 0;
688 if (count($totalforeachweek)) {
689 foreach ($TWeek as $weekNb) {
690 $timeonothertasks = ($totalforeachweek[$weekNb] - $totalforvisibletasks[$weekNb]);
691 if ($timeonothertasks) {
692 $isdiff = 1;
693 break;
694 }
695 }
696 }
697
698 // 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
699 if ($isdiff) {
700 print '<tr class="oddeven othertaskwithtime">';
701 print '<td colspan="'.$colspan.'" class="opacitymedium">';
702 print $langs->trans("OtherFilteredTasks");
703 print '</td>';
704 if (!empty($arrayfields['t.planned_workload']['checked'])) {
705 print '<td class="liste_total"></td>';
706 }
707 if (!empty($arrayfields['t.progress']['checked'])) {
708 print '<td class="liste_total"></td>';
709 }
710 if (!empty($arrayfields['timeconsumed']['checked'])) {
711 print '<td class="liste_total"></td>';
712 print '<td class="liste_total"></td>';
713 }
714 $j = 0;
715 foreach ($TWeek as $weekNb) {
716 $j++;
717 print '<td class="center hide'.($j <= 1 ? ' borderleft' : '').'">';
718
719 $timeonothertasks = ($totalforeachweek[$weekNb] - $totalforvisibletasks[$weekNb]);
720 if ($timeonothertasks) {
721 print '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center smallpadd width40" disabled="" id="timespent[-1]['.$weekNb.']" name="task[-1]['.$weekNb.']" value="';
722 print convertSecondToTime($timeonothertasks, 'allhourmin');
723 print '"></span>';
724 }
725 print '</td>';
726 }
727 print ' <td class="liste_total"></td>';
728 print '</tr>';
729 }
730
731 if ($conf->use_javascript_ajax) {
732 print '<tr class="liste_total">';
733 print '<td class="liste_total" colspan="'.($colspan + $addcolspan).'">';
734 print $langs->trans("Total");
735 print '<span class="opacitymediumbycolor"> - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong></span>';
736 print '</td>';
737 if (!empty($arrayfields['timeconsumed']['checked'])) {
738 print '<td class="liste_total"></td>';
739 print '<td class="liste_total"></td>';
740 }
741
742 $j = 0;
743 foreach ($TWeek as $weekNb) {
744 $j++;
745 print '<td class="liste_total hide'.$weekNb.' center'.($j <= 1 ? ' borderleft' : '').'"><div class="totalDay'.$weekNb.'">'.convertSecondToTime($totalforvisibletasks[$weekNb], 'allhourmin').'</div></td>';
746 }
747 print '<td class="liste_total center"><div class="totalDayAll">&nbsp;</div></td>
748 </tr>';
749 }
750} else {
751 print '<tr><td colspan="15"><span class="opacitymedium">'.$langs->trans("NoAssignedTasks").'</span></td></tr>';
752}
753print "</table>";
754print '</div>';
755
756print '<input type="hidden" id="numberOfLines" name="numberOfLines" value="'.count($tasksarray).'"/>'."\n";
757print '<input type="hidden" id="numberOfFirstLine" name="numberOfFirstLine" value="'.(reset($TWeek)).'"/>'."\n";
758
759print $form->buttonsSaveCancel("Save", '');
760
761print '</form>'."\n\n";
762
763$modeinput = 'hours';
764
765if ($conf->use_javascript_ajax) {
766 print "\n<!-- JS CODE TO ENABLE Tooltips on all object with class classfortooltip -->\n";
767 print '<script type="text/javascript">'."\n";
768 print "jQuery(document).ready(function () {\n";
769 print ' jQuery(".timesheetalreadyrecorded").tooltip({
770 show: { collision: "flipfit", effect:\'toggle\', delay:50 },
771 hide: { effect:\'toggle\', delay: 50 },
772 tooltipClass: "mytooltip",
773 content: function () {
774 return \''.dol_escape_js($langs->trans("TimeAlreadyRecorded", $usertoprocess->getFullName($langs))).'\';
775 }
776 });'."\n";
777
778 foreach ($TWeek as $week_number) {
779 print " updateTotal(".((int) $week_number).", '".dol_escape_js($modeinput)."');";
780 }
781 print "\n});\n";
782 print '</script>';
783}
784
785// End of page
786llxFooter();
787$db->close();
$id
Definition account.php:39
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($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:70
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:514
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:533
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...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
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.
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 a 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.