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