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