dolibarr 21.0.0-beta
perday.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2010 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2010 François Legastelois <flegastelois@teclib.com>
6 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
7 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
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
48// Load translation files required by the page
49$langs->loadLangs(array('projects', 'users', 'companies'));
50
51$action = GETPOST('action', 'aZ09');
52$mode = GETPOST("mode", 'alpha');
53$id = GETPOSTINT('id');
54$taskid = GETPOSTINT('taskid');
55
56$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'timespent';
57
58$mine = 0;
59if ($mode == 'mine') {
60 $mine = 1;
61}
62
63$projectid = GETPOSTISSET("id") ? GETPOSTINT("id", 1) : GETPOSTINT("projectid");
64
65$hookmanager->initHooks(array('timesheetperdaycard'));
66
67// Security check
68$socid = 0;
69// For external user, no check is done on company because readability is managed by public status of project and assignment.
70//if ($user->socid > 0) $socid=$user->socid;
71$result = restrictedArea($user, 'projet', $projectid);
72
73$now = dol_now();
74
75$year = GETPOSTINT('reyear') ? GETPOSTINT('reyear') : (GETPOSTINT("year") ? GETPOSTINT("year") : (GETPOSTINT("addtimeyear") ? GETPOSTINT("addtimeyear") : date("Y")));
76$month = GETPOSTINT('remonth') ? GETPOSTINT('remonth') : (GETPOSTINT("month") ? GETPOSTINT("month") : (GETPOSTINT("addtimemonth") ? GETPOSTINT("addtimemonth") : date("m")));
77$day = GETPOSTINT('reday') ? GETPOSTINT('reday') : (GETPOSTINT("day") ? GETPOSTINT("day") : (GETPOSTINT("addtimeday") ? GETPOSTINT("addtimeday") : date("d")));
78$week = GETPOSTINT("week") ? GETPOSTINT("week") : date("W");
79
80$day = (int) $day;
81
82//$search_categ = GETPOST("search_categ", 'alpha');
83$search_usertoprocessid = GETPOSTINT('search_usertoprocessid');
84$search_task_ref = GETPOST('search_task_ref', 'alpha');
85$search_task_label = GETPOST('search_task_label', 'alpha');
86$search_project_ref = GETPOST('search_project_ref', 'alpha');
87$search_thirdparty = GETPOST('search_thirdparty', 'alpha');
88$search_declared_progress = GETPOST('search_declared_progress', 'alpha');
89
90$sortfield = GETPOST('sortfield', 'aZ09comma');
91$sortorder = GETPOST('sortorder', 'aZ09comma');
92
93$monthofday = GETPOST('addtimemonth');
94$dayofday = GETPOST('addtimeday');
95$yearofday = GETPOST('addtimeyear');
96
97//var_dump(GETPOST('remonth'));
98//var_dump(GETPOST('button_search_x'));
99//var_dump(GETPOST('button_addtime'));
100
101$daytoparse = $now;
102if ($year && $month && $day) {
103 $daytoparse = dol_mktime(0, 0, 0, $month, $day, $year); // this are value submitted after submit of action 'submitdateselect'
104} elseif ($yearofday && $monthofday && $dayofday) {
105 $daytoparse = dol_mktime(0, 0, 0, $monthofday, $dayofday, $yearofday); // xxxofday is value of day after submit action 'addtime'
106}
107
108$daytoparsegmt = dol_now('gmt');
109if ($yearofday && $monthofday && $dayofday) {
110 $daytoparsegmt = dol_mktime(0, 0, 0, $monthofday, $dayofday, $yearofday, 'gmt');
111} elseif ($year && $month && $day) { // xxxofday is value of day after submit action 'addtime'
112 $daytoparsegmt = dol_mktime(0, 0, 0, $month, $day, $year, 'gmt');
113} // this are value submitted after submit of action 'submitdateselect'
114
115if (empty($search_usertoprocessid) || $search_usertoprocessid == $user->id) {
116 $usertoprocess = $user;
117 $search_usertoprocessid = $usertoprocess->id;
118} elseif ($search_usertoprocessid > 0) {
119 $usertoprocess = new User($db);
120 $usertoprocess->fetch($search_usertoprocessid);
121 $search_usertoprocessid = $usertoprocess->id;
122} else {
123 $usertoprocess = new User($db);
124}
125
126$object = new Task($db);
127$project = new Project($db);
128
129// Extra fields
130$extrafields = new ExtraFields($db);
131
132// fetch optionals attributes and labels
133$extrafields->fetch_name_optionals_label($object->table_element);
134
135// Definition of fields for list
136$arrayfields = array();
137$arrayfields['t.planned_workload'] = array('label' => 'PlannedWorkload', 'checked' => 1, 'enabled' => 1, 'position' => 0);
138$arrayfields['t.progress'] = array('label' => 'ProgressDeclared', 'checked' => 1, 'enabled' => 1, 'position' => 0);
139$arrayfields['timeconsumed'] = array('label' => 'TimeConsumed', 'checked' => 1, 'enabled' => 1, 'position' => 15);
140/*$arrayfields=array(
141 // Project
142 'p.opp_amount'=>array('label'=>$langs->trans("OpportunityAmountShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>103),
143 'p.fk_opp_status'=>array('label'=>$langs->trans("OpportunityStatusShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>104),
144 'p.opp_percent'=>array('label'=>$langs->trans("OpportunityProbabilityShort"), 'checked'=>0, 'enabled'=>($conf->global->PROJECT_USE_OPPORTUNITIES?1:0), 'position'=>105),
145 'p.budget_amount'=>array('label'=>$langs->trans("Budget"), 'checked'=>0, 'position'=>110),
146 'p.usage_bill_time'=>array('label'=>$langs->trans("BillTimeShort"), 'checked'=>0, 'position'=>115),
147 );
148 */
149// Extra fields
150if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
151 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
152 if (!empty($extrafields->attributes[$object->table_element]['list'][$key])) {
153 $arrayfields["efpt.".$key] = array('label' => $extrafields->attributes[$object->table_element]['label'][$key], 'checked' => (($extrafields->attributes[$object->table_element]['list'][$key] < 0) ? 0 : 1), 'position' => $extrafields->attributes[$object->table_element]['pos'][$key], 'enabled' => (abs((int) $extrafields->attributes[$object->table_element]['list'][$key]) != 3 && $extrafields->attributes[$object->table_element]['perms'][$key]));
154 }
155 }
156}
157$arrayfields = dol_sort_array($arrayfields, 'position');
158
159
160$search_array_options_project = $extrafields->getOptionalsFromPost($project->table_element, '', 'search_');
161$search_array_options_task = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_task_');
162
163
164/*
165 * Actions
166 */
167$error = 0;
168$parameters = array('id' => $id, 'taskid' => $taskid, 'projectid' => $projectid);
169$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
170if ($reshook < 0) {
171 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
172}
173// Purge criteria
174if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
175 $action = '';
176 //$search_categ = '';
177 $search_usertoprocessid = $user->id;
178 $search_task_ref = '';
179 $search_task_label = '';
180 $search_project_ref = '';
181 $search_thirdparty = '';
182 $search_declared_progress = '';
183
184 $search_array_options_project = array();
185 $search_array_options_task = array();
186
187 // We redefine $usertoprocess
188 $usertoprocess = $user;
189}
190if (GETPOST("button_search_x", 'alpha') || GETPOST("button_search.x", 'alpha') || GETPOST("button_search", 'alpha')) {
191 $action = '';
192}
193
194if (GETPOST('submitdateselect')) {
195 if (GETPOSTINT('remonth') && GETPOSTINT('reday') && GETPOSTINT('reyear')) {
196 $daytoparse = dol_mktime(0, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
197 }
198
199 $action = '';
200}
201
202include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
203
204if ($action == 'addtime' && $user->hasRight('projet', 'lire') && GETPOST('assigntask') && GETPOST('formfilteraction') != 'listafterchangingselectedfields') {
205 $action = 'assigntask';
206
207 if ($taskid > 0) {
208 $result = $object->fetch($taskid, $ref);
209 if ($result < 0) {
210 $error++;
211 }
212 } else {
213 setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Task")), null, 'errors');
214 $error++;
215 }
216 if (!GETPOST('type')) {
217 setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
218 $error++;
219 }
220 if (!$error) {
221 $idfortaskuser = $usertoprocess->id;
222 $result = $object->add_contact($idfortaskuser, GETPOST("type"), 'internal');
223
224 if ($result >= 0 || $result == -2) { // Contact add ok or already contact of task
225 // 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)
226 $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';
227 $sql .= ' AND ec.fk_socpeople = '.((int) $idfortaskuser)." AND ec.element_id = ".((int) $object->fk_project)." AND tc.element = 'project' AND source = 'internal'";
228 $resql = $db->query($sql);
229 if ($resql) {
230 $obj = $db->fetch_object($resql);
231 if (!$obj) { // User is not already linked to project, so we will create link to first type
232 $project = new Project($db);
233 $project->fetch($object->fk_project);
234 // Get type
235 $listofprojcontact = $project->liste_type_contact('internal');
236
237 if (count($listofprojcontact)) {
238 $tmparray = array_keys($listofprojcontact);
239 $typeforprojectcontact = reset($tmparray);
240 $result = $project->add_contact($idfortaskuser, $typeforprojectcontact, 'internal');
241 }
242 }
243 } else {
244 dol_print_error($db);
245 }
246 }
247 }
248
249 if ($result < 0) {
250 $error++;
251 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
252 $langs->load("errors");
253 setEventMessages($langs->trans("ErrorTaskAlreadyAssigned"), null, 'warnings');
254 } else {
255 setEventMessages($object->error, $object->errors, 'errors');
256 }
257 }
258
259 if (!$error) {
260 setEventMessages("TaskAssignedToEnterTime", null);
261 $taskid = 0;
262 }
263
264 $action = '';
265}
266
267if ($action == 'addtime' && $user->hasRight('projet', 'lire') && GETPOST('formfilteraction') != 'listafterchangingselectedfields') {
268 $timespent_duration = array();
269
270 if (is_array($_POST)) {
271 foreach ($_POST as $key => $time) {
272 if (intval($time) > 0) {
273 $matches = array();
274 // Hours or minutes of duration
275 if (preg_match("/([0-9]+)duration(hour|min)/", $key, $matches)) {
276 $id = $matches[1];
277 if ($id > 0) {
278 // We store HOURS in seconds
279 if ($matches[2] == 'hour') {
280 $timespent_duration[$id] += (int) $time * 60 * 60;
281 }
282
283 // We store MINUTES in seconds
284 if ($matches[2] == 'min') {
285 $timespent_duration[$id] += (int) $time * 60;
286 }
287 }
288 }
289 }
290 }
291 }
292
293 if (count($timespent_duration) > 0) {
294 foreach ($timespent_duration as $key => $val) {
295 $object->fetch($key);
296 $taskid = $object->id;
297
298 if (GETPOSTISSET($taskid.'progress')) {
299 $object->progress = GETPOSTINT($taskid.'progress');
300 } else {
301 unset($object->progress);
302 }
303
304 $object->timespent_duration = $val;
305 $object->timespent_fk_user = $usertoprocess->id;
306 $object->timespent_note = GETPOST($key.'note');
307 if (GETPOSTINT($key."hour") != '' && GETPOSTINT($key."hour") >= 0) { // If hour was entered
308 $object->timespent_datehour = dol_mktime(GETPOSTINT($key."hour"), GETPOSTINT($key."min"), 0, $monthofday, $dayofday, $yearofday);
309 $object->timespent_withhour = 1;
310 } else {
311 $object->timespent_datehour = dol_mktime(12, 0, 0, $monthofday, $dayofday, $yearofday);
312 }
313 $object->timespent_date = $object->timespent_datehour;
314
315 if ($object->timespent_date > 0) {
316 $result = $object->addTimeSpent($user);
317 } else {
318 setEventMessages("ErrorBadDate", null, 'errors');
319 $error++;
320 break;
321 }
322
323 if ($result < 0) {
324 setEventMessages($object->error, $object->errors, 'errors');
325 $error++;
326 break;
327 }
328 }
329
330 if (!$error) {
331 setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
332
333 // Redirect to avoid submit twice on back
334 header('Location: '.$_SERVER["PHP_SELF"].'?'.($projectid ? 'id='.$projectid : '').($search_usertoprocessid ? '&search_usertoprocessid='.urlencode((string) $search_usertoprocessid) : '').($mode ? '&mode='.$mode : '').'&year='.$yearofday.'&month='.$monthofday.'&day='.$dayofday);
335 exit;
336 }
337 } else {
338 setEventMessages($langs->trans("ErrorTimeSpentIsEmpty"), null, 'errors');
339 }
340}
341
342
343
344/*
345 * View
346 */
347
348$form = new Form($db);
349$formother = new FormOther($db);
350$formcompany = new FormCompany($db);
351$formproject = new FormProjets($db);
352$projectstatic = new Project($db);
353$project = new Project($db);
354$taskstatic = new Task($db);
355$thirdpartystatic = new Societe($db);
356$holiday = new Holiday($db);
357
358$prev = dol_getdate($daytoparse - (24 * 3600));
359$prev_year = $prev['year'];
360$prev_month = $prev['mon'];
361$prev_day = $prev['mday'];
362
363$next = dol_getdate($daytoparse + (24 * 3600));
364$next_year = $next['year'];
365$next_month = $next['mon'];
366$next_day = $next['mday'];
367
368$title = $langs->trans("TimeSpent");
369
370$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
371
372if ($id) {
373 $project->fetch($id);
374 $project->fetch_thirdparty();
375}
376
377$onlyopenedproject = 1; // or -1
378$morewherefilter = '';
379
380if ($search_project_ref) {
381 $morewherefilter .= natural_search(array("p.ref", "p.title"), $search_project_ref);
382}
383if ($search_task_ref) {
384 $morewherefilter .= natural_search("t.ref", $search_task_ref);
385}
386if ($search_task_label) {
387 $morewherefilter .= natural_search(array("t.ref", "t.label"), $search_task_label);
388}
389if ($search_thirdparty) {
390 $morewherefilter .= natural_search("s.nom", $search_thirdparty);
391}
392if ($search_declared_progress) {
393 $morewherefilter .= natural_search("t.progress", $search_declared_progress, 1);
394}
395
396$sql = &$morewherefilter;
397
398/*$search_array_options = $search_array_options_project;
399$extrafieldsobjectprefix='efp.';
400$search_options_pattern='search_options_';
401$extrafieldsobjectkey='projet';
402include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
403*/
404$search_array_options = $search_array_options_task;
405$extrafieldsobjectprefix = 'efpt.';
406$search_options_pattern = 'search_task_options_';
407$extrafieldsobjectkey = 'projet_task';
408include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
409
410$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 task of opened project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later.
411
412$tasksarraywithoutfilter = array();
413if ($morewherefilter) { // Get all task without any filter, so we can show total of time spent for not visible tasks
414 $tasksarraywithoutfilter = $taskstatic->getTasksArray(null, null, ($project->id ? $project->id : 0), $socid, 0, '', $onlyopenedproject, '', ($search_usertoprocessid ? $search_usertoprocessid : 0)); // We want to see all task of opened project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later.
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
419llxHeader('', $title, '', '', 0, 0, array('/core/js/timesheet.js'), '', '', 'mod-project project-activity page-activity_perday');
420
421//print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num, '', 'project');
422
423$param = '';
424$param .= ($mode ? '&mode='.urlencode($mode) : '');
425$param .= ($search_project_ref ? '&search_project_ref='.urlencode($search_project_ref) : '');
426$param .= ($search_usertoprocessid > 0 ? '&search_usertoprocessid='.urlencode((string) $search_usertoprocessid) : '');
427$param .= ($search_thirdparty ? '&search_thirdparty='.urlencode($search_thirdparty) : '');
428$param .= ($search_task_ref ? '&search_task_ref='.urlencode($search_task_ref) : '');
429$param .= ($search_task_label ? '&search_task_label='.urlencode($search_task_label) : '');
430
431/*
432$search_array_options = $search_array_options_project;
433$search_options_pattern='search_options_';
434include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
435*/
436
437$search_array_options = $search_array_options_task;
438$search_options_pattern = 'search_task_options_';
439include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
440
441// Show navigation bar
442$nav = '<a class="inline-block valignmiddle" href="?year='.$prev_year."&month=".$prev_month."&day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n";
443$nav .= dol_print_date(dol_mktime(0, 0, 0, $month, $day, $year), "%a").' ';
444$nav .= ' <span id="month_name">'.dol_print_date(dol_mktime(0, 0, 0, $month, $day, $year), "day")." </span>\n";
445$nav .= '<a class="inline-block valignmiddle" href="?year='.$next_year."&month=".$next_month."&day=".$next_day.$param.'">'.img_next($langs->trans("Next"))."</a>\n";
446$nav .= ' '.$form->selectDate(-1, '', 0, 0, 2, "addtime", 1, ($conf->dol_optimize_smallscreen ? 0 : 1)).' ';
447$nav .= ' <button type="submit" name="button_search_x" value="x" class="bordertransp nobordertransp button_search"><span class="fa fa-search"></span></button>';
448
449$picto = 'clock';
450
451print '<form name="addtime" method="POST" action="'.$_SERVER["PHP_SELF"].($project->id > 0 ? '?id='.$project->id : '').'">';
452print '<input type="hidden" name="token" value="'.newToken().'">';
453print '<input type="hidden" name="action" value="addtime">';
454print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
455print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
456print '<input type="hidden" name="mode" value="'.$mode.'">';
457$tmp = dol_getdate($daytoparse);
458print '<input type="hidden" name="addtimeyear" value="'.$tmp['year'].'">';
459print '<input type="hidden" name="addtimemonth" value="'.$tmp['mon'].'">';
460print '<input type="hidden" name="addtimeday" value="'.$tmp['mday'].'">';
461
462$head = project_timesheet_prepare_head($mode, $usertoprocess);
463print dol_get_fiche_head($head, 'inputperday', $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
487
488print '<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.
489
490print '<div class="colorbacktimesheet valignmiddle'.($conf->dol_optimize_smallscreen ? ' center' : ' float').'">';
491$titleassigntask = $langs->transnoentities("AssignTaskToMe");
492if ($usertoprocess->id != $user->id) {
493 $titleassigntask = $langs->transnoentities("AssignTaskToUser", $usertoprocess->getFullName($langs));
494}
495print '<div class="taskiddiv inline-block">';
496print img_picto('', 'projecttask', 'class="pictofixedwidth"');
497$formproject->selectTasks($socid ? $socid : -1, $taskid, 'taskid', 32, 0, '-- '.$langs->trans("ChooseANotYetAssignedTask").' --', 1, 0, 0, 'widthcentpercentminusx', '', 'all', $usertoprocess);
498print '</div>';
499print ' ';
500print $formcompany->selectTypeContact($object, '', 'type', 'internal', 'position', 0, 'maxwidth150onsmartphone');
501print '<input type="submit" class="button valignmiddle smallonsmartphone small" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">';
502print '</div>';
503
504print '<div class="clearboth" style="padding-bottom: 20px;"></div>';
505
506
507$moreforfilter = '';
508
509// Filter on categories
510/*if (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$includeonly = 'hierarchyme';
520if (!$user->hasRight('user', 'user', 'lire')) {
521 $includeonly = array($user->id);
522}
523$selecteduser = $search_usertoprocessid ? $search_usertoprocessid : $usertoprocess->id;
524$moreforfiltertmp = $form->select_dolusers($selecteduser, 'search_usertoprocessid', 0, null, 0, $includeonly, '', 0, 0, 0, '', 0, '', 'maxwidth200');
525if ($form->num > 1 || empty($conf->dol_optimize_smallscreen)) {
526 $moreforfilter .= '<div class="divsearchfield">';
527 $moreforfilter .= '<div class="inline-block hideonsmartphone"></div>';
528 $moreforfilter .= img_picto($langs->trans('Filter').' '.$langs->trans('User'), 'user', 'class="paddingright pictofixedwidth"');
529 $moreforfilter .= $moreforfiltertmp;
530 $moreforfilter .= '</div>';
531} else {
532 $moreforfilter .= '<input type="hidden" name="search_usertoprocessid" value="'.$selecteduser.'">';
533}
534
535if (!getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
536 $moreforfilter .= '<div class="divsearchfield">';
537 $moreforfilter .= '<div class="inline-block"></div>';
538 $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).'">';
539 $moreforfilter .= '</div>';
540
541 $moreforfilter .= '<div class="divsearchfield">';
542 $moreforfilter .= '<div class="inline-block"></div>';
543 $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).'">';
544 $moreforfilter .= '</div>';
545}
546
547if (!empty($moreforfilter)) {
548 print '<div class="liste_titre liste_titre_bydiv centpercent">';
549 print $moreforfilter;
550 $parameters = array();
551 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
552 print $hookmanager->resPrint;
553 print '</div>';
554}
555
556$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
557$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
558
559// This must be after the $selectedfields
560$addcolspan = 0;
561if (!empty($arrayfields['t.planned_workload']['checked'])) {
562 $addcolspan++;
563}
564if (!empty($arrayfields['t.progress']['checked'])) {
565 $addcolspan++;
566}
567foreach ($arrayfields as $key => $val) {
568 if ($val['checked'] && substr($key, 0, 5) == 'efpt.') {
569 $addcolspan++;
570 }
571}
572
573print '<div class="div-table-responsive">';
574print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'" id="tablelines3">'."\n";
575
576print '<tr class="liste_titre_filter">';
577if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
578 print '<td class="liste_titre"><input type="text" size="4" name="search_project_ref" value="'.dol_escape_htmltag($search_project_ref).'"></td>';
579}
580if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
581 print '<td class="liste_titre"><input type="text" size="4" name="search_thirdparty" value="'.dol_escape_htmltag($search_thirdparty).'"></td>';
582}
583print '<td class="liste_titre"><input type="text" size="4" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
584// TASK fields
585$search_options_pattern = 'search_task_options_';
586$extrafieldsobjectkey = 'projet_task';
587$extrafieldsobjectprefix = 'efpt.';
588include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
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}
599print '<td class="liste_titre"></td>';
600print '<td class="liste_titre"></td>';
601print '<td class="liste_titre"></td>';
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 '<th>'.$langs->trans("Project").'</th>';
612}
613if (getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT')) {
614 print '<th>'.$langs->trans("ThirdParty").'</th>';
615}
616print '<th>'.$langs->trans("Task").'</th>';
617// TASK fields
618$extrafieldsobjectkey = 'projet_task';
619$extrafieldsobjectprefix = 'efpt.';
620include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
621if (!empty($arrayfields['t.planned_workload']['checked'])) {
622 print '<th class="leftborder plannedworkload minwidth75 maxwidth100 right" title="'.dol_escape_htmltag($langs->trans("PlannedWorkload")).'">'.$form->textwithpicto($langs->trans("PlannedWorkloadShort"), $langs->trans("PlannedWorkload")).'</th>';
623}
624if (!empty($arrayfields['t.progress']['checked'])) {
625 print '<th class="right minwidth75 maxwidth100 title="'.dol_escape_htmltag($langs->trans("ProgressDeclared")).'">'.$langs->trans("ProgressDeclared").'</th>';
626}
627if (!empty($arrayfields['timeconsumed']['checked'])) {
628 print '<th class="right maxwidth100">'.$langs->trans("TimeSpentSmall").'<br>';
629 print '<span class="nowraponall">';
630 print '<span class="opacitymedium nopadding userimg"><img alt="Photo" class="photouserphoto userphoto" src="'.DOL_URL_ROOT.'/theme/common/everybody.png"></span>';
631 print '<span class="opacitymedium paddingleft">'.$langs->trans("EverybodySmall").'</span>';
632 print '</span>';
633 print '</th>';
634 print '<th class="right maxwidth75 maxwidth100">'.$langs->trans("TimeSpentSmall").($usertoprocess->firstname ? '<br><span class="nowraponall">'.$usertoprocess->getNomUrl(-2).'<span class="opacitymedium paddingleft">'.dol_trunc($usertoprocess->firstname, 10).'</span></span>' : '').'</th>';
635}
636print '<th class="center leftborder">'.$langs->trans("HourStart").'</td>';
637
638// By default, we can edit only tasks we are assigned to
639$restrictviewformytask = getDolGlobalInt('PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED', 2);
640
641$numendworkingday = 0;
642$numstartworkingday = 0;
643// Get if user is available or not for each day
644$isavailable = array();
645
646// Assume from Monday to Friday if conf empty or badly formed
647$numstartworkingday = 1;
648$numendworkingday = 5;
649
650if (getDolGlobalString('MAIN_DEFAULT_WORKING_DAYS')) {
651 $tmparray = explode('-', getDolGlobalString('MAIN_DEFAULT_WORKING_DAYS'));
652 if (count($tmparray) >= 2) {
653 $numstartworkingday = $tmparray[0];
654 $numendworkingday = $tmparray[1];
655 }
656}
657
658$statusofholidaytocheck = Holiday::STATUS_APPROVED;
659$isavailablefordayanduser = $holiday->verifDateHolidayForTimestamp($usertoprocess->id, $daytoparse, $statusofholidaytocheck); // $daytoparse is a date with hours = 0
660$isavailable[$daytoparse] = $isavailablefordayanduser; // in projectLinesPerWeek later, we are using $firstdaytoshow and dol_time_plus_duree to loop on each day
661
662$test = num_public_holiday($daytoparsegmt, $daytoparsegmt + 86400, $mysoc->country_code);
663if ($test) {
664 $isavailable[$daytoparse] = array('morning' => false, 'afternoon' => false, 'morning_reason' => 'public_holiday', 'afternoon_reason' => 'public_holiday');
665}
666
667$tmparray = dol_getdate($daytoparse, true); // detail of current day
668// For monday, must be 0 for monday if MAIN_START_WEEK = 1, must be 1 for monday if MAIN_START_WEEK = 0
669$idw = ($tmparray['wday'] - (!getDolGlobalString('MAIN_START_WEEK') ? 0 : 1));
670// numstartworkingday and numendworkingday are default start and end date of working days (1 means sunday if MAIN_START_WEEK is 0, 1 means monday if MAIN_START_WEEK is 1)
671$cssweekend = '';
672if ((($idw + 1) < $numstartworkingday) || (($idw + 1) > $numendworkingday)) { // This is a day is not inside the setup of working days, so we use a week-end css.
673 $cssweekend = 'weekend';
674}
675
676$tmpday = dol_time_plus_duree($daytoparse, $idw, 'd');
677
678$cssonholiday = '';
679if (!$isavailable[$daytoparse]['morning'] && !$isavailable[$daytoparse]['afternoon']) {
680 $cssonholiday .= 'onholidayallday ';
681} elseif (!$isavailable[$daytoparse]['morning']) {
682 $cssonholiday .= 'onholidaymorning ';
683} elseif (!$isavailable[$daytoparse]['afternoon']) {
684 $cssonholiday .= 'onholidayafternoon ';
685}
686
687print '<th class="center'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">'.$langs->trans("Duration").'</th>';
688print '<th class="center">'.$langs->trans("Note").'</th>';
689//print '<td class="center"></td>';
690print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
691
692print "</tr>\n";
693
694$colspan = 2 + (!getDolGlobalString('PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT') ? 0 : 2);
695
696if ($conf->use_javascript_ajax && count($tasksarray) >= getDolGlobalInt('NBLINES_TO_DUPLICATE_TOTAL_TIMESPENT_ON_TOP', 10)) {
697 print '<tr class="liste_total hideonsmartphone">';
698 print '<td class="liste_total" colspan="'.($colspan - 1 + $addcolspan).'">';
699 print $langs->trans("Total");
700 print '</td>';
701 if (!empty($arrayfields['timeconsumed']['checked'])) {
702 print '<td class="liste_total"></td>';
703 print '<td class="liste_total"></td>';
704 }
705 print '<td class="liste_total leftborder">';
706 //print ' - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong>';
707 print '</td>';
708
709 print '<td class="liste_total center'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'"><div class="totalDay0">&nbsp;</div></td>';
710
711 print '<td class="liste_total"></td>';
712 print '<td class="liste_total"></td>';
713 print '</tr>';
714}
715
716
717if (count($tasksarray) > 0) {
718 //var_dump($tasksarray); // contains only selected tasks
719 //var_dump($tasksarraywithoutfilter); // contains all tasks (if there is a filter, not defined if no filter)
720 //var_dump($tasksrole);
721
722 $j = 0;
723 $level = 0;
724 $totalforvisibletasks = projectLinesPerDay($j, 0, $usertoprocess, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restrictviewformytask, $daytoparse, $isavailable, 0, $arrayfields, $extrafields);
725 //var_dump($totalforvisibletasks);
726
727 // Show total for all other tasks
728
729 // Calculate total for all tasks
730 $listofdistinctprojectid = array(); // List of all distinct projects
731 if (!empty($tasksarraywithoutfilter) && is_array($tasksarraywithoutfilter) && count($tasksarraywithoutfilter)) {
732 foreach ($tasksarraywithoutfilter as $tmptask) {
733 $listofdistinctprojectid[$tmptask->fk_project] = $tmptask->fk_project;
734 }
735 }
736 //var_dump($listofdistinctprojectid);
737 $totalforeachday = array();
738 foreach ($listofdistinctprojectid as $tmpprojectid) {
739 $projectstatic->id = $tmpprojectid;
740 $projectstatic->loadTimeSpent($daytoparse, 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
741 for ($idw = 0; $idw < 7; $idw++) {
742 $tmpday = dol_time_plus_duree($daytoparse, $idw, 'd');
743 $totalforeachday[$tmpday] += $projectstatic->weekWorkLoad[$tmpday];
744 }
745 }
746 //var_dump($totalforeachday);
747
748 // Is there a diff between selected/filtered tasks and all tasks ?
749 $isdiff = 0;
750 if (count($totalforeachday)) {
751 $timeonothertasks = ($totalforeachday[$daytoparse] - $totalforvisibletasks[$daytoparse]);
752 if ($timeonothertasks) {
753 $isdiff = 1;
754 }
755 }
756
757 // 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
758 if ($isdiff) {
759 print '<tr class="oddeven othertaskwithtime">';
760 print '<td colspan="'.($colspan - 1).'" class="opacitymedium">';
761 print $langs->trans("OtherFilteredTasks");
762 print '</td>';
763 if (!empty($arrayfields['timeconsumed']['checked'])) {
764 print '<td class="liste_total"></td>';
765 print '<td class="liste_total"></td>';
766 }
767 print '<td class="leftborder"></td>';
768 print '<td class="right">';
769 $timeonothertasks = ($totalforeachday[$daytoparse] - $totalforvisibletasks[$daytoparse]);
770 //if ($timeonothertasks)
771 //{
772 print '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center width40" disabled="" id="timespent[-1][0]" name="task[-1][0]" value="';
773 if ($timeonothertasks) {
774 print convertSecondToTime($timeonothertasks, 'allhourmin');
775 }
776 print '"></span>';
777 //}
778 print '</td>';
779 print ' <td class="liste_total borderleft"></td>';
780 print ' <td class="liste_total"></td>';
781 print '</tr>';
782 }
783
784 if ($conf->use_javascript_ajax) {
785 print '<tr class="liste_total">';
786 print '<td class="liste_total" colspan="'.($colspan - 1 + $addcolspan).'">';
787 print $langs->trans("Total");
788 print '</td>';
789 if (!empty($arrayfields['timeconsumed']['checked'])) {
790 print '<td class="liste_total"></td>';
791 print '<td class="liste_total"></td>';
792 }
793 print '<td class="liste_total leftborder borderleft">';
794 //print ' - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong>';
795 print '</td>';
796
797 print '<td class="liste_total center'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'"><div class="totalDay0">&nbsp;</div></td>';
798
799 print '<td class="liste_total"></td>
800 <td class="liste_total"></td>
801 </tr>';
802 }
803} else {
804 print '<tr><td colspan="14"><span class="opacitymedium">'.$langs->trans("NoAssignedTasks").'</span></td></tr>';
805}
806print "</table>";
807print '</div>';
808
809print '<input type="hidden" id="numberOfLines" name="numberOfLines" value="'.count($tasksarray).'"/>'."\n";
810
811print '<div class="center">';
812print '<input type="submit" name="button_addtime" class="button button-save"'.(!empty($disabledtask) ? ' disabled' : '').' value="'.$langs->trans("Save").'">';
813print '</div>';
814
815print '</form>';
816
817if (!empty($conf->use_javascript_ajax)) {
818 $modeinput = 'hours';
819 print "\n<!-- JS CODE TO ENABLE Tooltips on all object with class classfortooltip -->\n";
820 print '<script type="text/javascript">'."\n";
821 print "jQuery(document).ready(function () {\n";
822 print " updateTotal(0, '".dol_escape_js($modeinput)."');\n";
823 print ' jQuery(".timesheetalreadyrecorded").tooltip({
824 show: { collision: "flipfit", effect:\'toggle\', delay:50 },
825 hide: { effect:\'toggle\', delay: 50 },
826 tooltipClass: "mytooltip",
827 content: function () {
828 return \''.dol_escape_js($langs->trans("TimeAlreadyRecorded", $usertoprocess->getFullName($langs))).'\';
829 }
830 });'."\n";
831 print " jQuery('.inputhour, .inputminute').bind('keyup', function(e) { updateTotal(0, '".dol_escape_js($modeinput)."') });";
832 print "\n});\n";
833 print '</script>';
834}
835
836// End of page
837llxFooter();
838$db->close();
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
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:71
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.
const STATUS_APPROVED
Approved.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage tasks.
Class to manage Dolibarr users.
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:244
num_public_holiday($timestampStart, $timestampEnd, $country_code='', $lastday=0, $includesaturday=-1, $includesunday=-1, $includefriday=-1, $includemonday=-1)
Return the number of non working days including Friday, Saturday and Sunday (or not) between 2 dates ...
Definition date.lib.php:769
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...
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
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...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak=0, $arrayfields=array(), $extrafields=null)
Output a task line into a pertime input 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.