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