dolibarr  16.0.1
time.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2006-2021 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2010-2012 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2018 Ferran Marcet <fmarcet@2byte.es>
7  * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
8  * Copyright (C) 2019-2021 Christophe Battarel <christophe@altairis.fr>
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 
30 require '../../main.inc.php';
31 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
32 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
35 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
36 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
38 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formintervention.class.php';
39 
40 // Load translation files required by the page
41 $langsLoad=array('projects', 'bills', 'orders');
42 if (!empty($conf->eventorganization->enabled)) {
43  $langsLoad[]='eventorganization';
44 }
45 
46 $langs->loadLangs($langsLoad);
47 
48 $action = GETPOST('action', 'alpha');
49 $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists)
50 $confirm = GETPOST('confirm', 'alpha');
51 $cancel = GETPOST('cancel', 'alpha');
52 $toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list
53 $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'timespentlist'; // To manage different context of search
54 $backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page
55 $optioncss = GETPOST('optioncss', 'alpha');
56 
57 $id = GETPOST('id', 'int');
58 $projectid = GETPOST('projectid', 'int');
59 $ref = GETPOST('ref', 'alpha');
60 $withproject = GETPOST('withproject', 'int');
61 $project_ref = GETPOST('project_ref', 'alpha');
62 $tab = GETPOST('tab', 'aZ09');
63 
64 $search_day = GETPOST('search_day', 'int');
65 $search_month = GETPOST('search_month', 'int');
66 $search_year = GETPOST('search_year', 'int');
67 $search_datehour = '';
68 $search_datewithhour = '';
69 $search_note = GETPOST('search_note', 'alpha');
70 $search_duration = GETPOST('search_duration', 'int');
71 $search_value = GETPOST('search_value', 'int');
72 $search_task_ref = GETPOST('search_task_ref', 'alpha');
73 $search_task_label = GETPOST('search_task_label', 'alpha');
74 $search_user = GETPOST('search_user', 'int');
75 $search_valuebilled = GETPOST('search_valuebilled', 'int');
76 
77 $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
78 $sortfield = GETPOST('sortfield', 'aZ09comma');
79 $sortorder = GETPOST('sortorder', 'aZ09comma');
80 $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
81 if (empty($page) || $page == -1) {
82  $page = 0;
83 } // If $page is not defined, or '' or -1
84 $offset = $limit * $page;
85 $pageprev = $page - 1;
86 $pagenext = $page + 1;
87 if (!$sortfield) {
88  $sortfield = 't.task_date,t.task_datehour,t.rowid';
89 }
90 if (!$sortorder) {
91  $sortorder = 'DESC,DESC,DESC';
92 }
93 
94 $childids = $user->getAllChildIds(1);
95 
96 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
97 //$object = new TaskTime($db);
98 $hookmanager->initHooks(array('projecttasktime', 'globalcard'));
99 
100 $object = new Task($db);
101 $extrafields = new ExtraFields($db);
102 $projectstatic = new Project($db);
103 
104 // fetch optionals attributes and labels
105 $extrafields->fetch_name_optionals_label($projectstatic->table_element);
106 $extrafields->fetch_name_optionals_label($object->table_element);
107 
108 // Load task
109 if ($id > 0 || $ref) {
110  $object->fetch($id, $ref);
111 }
112 
113 
114 // Security check
115 $socid = 0;
116 //if ($user->socid > 0) $socid = $user->socid; // For external user, no check is done on company because readability is managed by public status of project and assignement.
117 if (!$user->rights->projet->lire) {
118  accessforbidden();
119 }
120 
121 if ($object->fk_project > 0) {
122  restrictedArea($user, 'projet', $object->fk_project, 'projet&project');
123 } else {
124  restrictedArea($user, 'projet', null, 'projet&project');
125  // We check user has permission to see all tasks of all users
126  if (empty($projectid) && !$user->hasRight('projet', 'all', 'lire')) {
127  $search_user = $user->id;
128  }
129 }
130 
131 
132 
133 /*
134  * Actions
135  */
136 
137 if (GETPOST('cancel', 'alpha')) {
138  $action = '';
139 }
140 if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend' && $massaction != 'confirm_generateinvoice' && $massaction != 'confirm_generateinter') {
141  $massaction = '';
142 }
143 
144 $parameters = array('socid'=>$socid, 'projectid'=>$projectid);
145 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
146 if ($reshook < 0) {
147  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
148 }
149 
150 include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
151 
152 // Purge search criteria
153 if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
154  $search_day = '';
155  $search_month = '';
156  $search_year = '';
157  $search_date = '';
158  $search_datehour = '';
159  $search_datewithhour = '';
160  $search_note = '';
161  $search_duration = '';
162  $search_value = '';
163  $search_date_creation = '';
164  $search_date_update = '';
165  $search_task_ref = '';
166  $search_task_label = '';
167  $search_user = 0;
168  $search_valuebilled = '';
169  $toselect = array();
170  $search_array_options = array();
171  $action = '';
172 }
173 
174 if ($action == 'addtimespent' && $user->rights->projet->time) {
175  $error = 0;
176 
177  $timespent_durationhour = GETPOST('timespent_durationhour', 'int');
178  $timespent_durationmin = GETPOST('timespent_durationmin', 'int');
179  if (empty($timespent_durationhour) && empty($timespent_durationmin)) {
180  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Duration")), null, 'errors');
181  $error++;
182  }
183  if (!GETPOST("userid", 'int')) {
184  $langs->load("errors");
185  setEventMessages($langs->trans('ErrorUserNotAssignedToTask'), null, 'errors');
186  $error++;
187  }
188 
189  if (!$error) {
190  if ($id || $ref) {
191  $object->fetch($id, $ref);
192  } else {
193  if (!GETPOST('taskid', 'int') || GETPOST('taskid', 'int') < 0) {
194  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Task")), null, 'errors');
195  $action = 'createtime';
196  $error++;
197  } else {
198  $object->fetch(GETPOST('taskid', 'int'));
199  }
200  }
201 
202  if (!$error) {
203  $object->fetch_projet();
204 
205  if (empty($object->project->statut)) {
206  setEventMessages($langs->trans("ProjectMustBeValidatedFirst"), null, 'errors');
207  $action = 'createtime';
208  $error++;
209  } else {
210  $object->timespent_note = GETPOST("timespent_note", 'alpha');
211  if (GETPOST('progress', 'int') > 0) {
212  $object->progress = GETPOST('progress', 'int'); // If progress is -1 (not defined), we do not change value
213  }
214  $object->timespent_duration = GETPOSTINT("timespent_durationhour") * 60 * 60; // We store duration in seconds
215  $object->timespent_duration += (GETPOSTINT('timespent_durationmin') ? GETPOSTINT('timespent_durationmin') : 0) * 60; // We store duration in seconds
216  if (GETPOST("timehour") != '' && GETPOST("timehour") >= 0) { // If hour was entered
217  $object->timespent_date = dol_mktime(GETPOST("timehour", 'int'), GETPOST("timemin", 'int'), 0, GETPOST("timemonth", 'int'), GETPOST("timeday", 'int'), GETPOST("timeyear", 'int'));
218  $object->timespent_withhour = 1;
219  } else {
220  $object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timemonth", 'int'), GETPOST("timeday", 'int'), GETPOST("timeyear", 'int'));
221  }
222  $object->timespent_fk_user = GETPOST("userid", 'int');
223  $result = $object->addTimeSpent($user);
224  if ($result >= 0) {
225  setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
226  } else {
227  setEventMessages($langs->trans($object->error), null, 'errors');
228  $error++;
229  }
230  }
231  }
232  } else {
233  if (empty($id)) {
234  $action = 'createtime';
235  } else {
236  $action = 'createtime';
237  }
238  }
239 }
240 
241 if (($action == 'updateline' || $action == 'updatesplitline') && !$cancel && $user->rights->projet->lire) {
242  $error = 0;
243 
244  if (!GETPOST("new_durationhour") && !GETPOST("new_durationmin")) {
245  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Duration")), null, 'errors');
246  $error++;
247  }
248 
249  if (!$error) {
250  if (GETPOST('taskid', 'int') != $id) { // GETPOST('taskid') is id of new task
251  $id_temp = GETPOST('taskid', 'int'); // should not overwrite $id
252 
253 
254  $object->fetchTimeSpent(GETPOST('lineid', 'int'));
255 
256  $result = 0;
257  if (in_array($object->timespent_fk_user, $childids) || $user->rights->projet->all->creer) {
258  $result = $object->delTimeSpent($user);
259  }
260 
261  $object->fetch($id_temp, $ref);
262 
263  $object->timespent_note = GETPOST("timespent_note_line", "alphanohtml");
264  $object->timespent_old_duration = GETPOST("old_duration", "int");
265  $object->timespent_duration = GETPOSTINT("new_durationhour") * 60 * 60; // We store duration in seconds
266  $object->timespent_duration += (GETPOSTINT("new_durationmin") ? GETPOSTINT('new_durationmin') : 0) * 60; // We store duration in seconds
267  if (GETPOST("timelinehour") != '' && GETPOST("timelinehour") >= 0) { // If hour was entered
268  $object->timespent_date = dol_mktime(GETPOST("timelinehour"), GETPOST("timelinemin"), 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear"));
269  $object->timespent_withhour = 1;
270  } else {
271  $object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear"));
272  }
273  $object->timespent_fk_user = GETPOST("userid_line", 'int');
274 
275  $result = 0;
276  if (in_array($object->timespent_fk_user, $childids) || $user->rights->projet->all->creer) {
277  $result = $object->addTimeSpent($user);
278  }
279 
280  if ($result >= 0) {
281  setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
282  } else {
283  setEventMessages($langs->trans($object->error), null, 'errors');
284  $error++;
285  }
286  } else {
287  $object->fetch($id, $ref);
288 
289  $object->timespent_id = GETPOST("lineid", 'int');
290  $object->timespent_note = GETPOST("timespent_note_line", "alphanohtml");
291  $object->timespent_old_duration = GETPOST("old_duration", "int");
292  $object->timespent_duration = GETPOSTINT("new_durationhour") * 60 * 60; // We store duration in seconds
293  $object->timespent_duration += (GETPOSTINT("new_durationmin") ? GETPOSTINT('new_durationmin') : 0) * 60; // We store duration in seconds
294  if (GETPOST("timelinehour") != '' && GETPOST("timelinehour") >= 0) { // If hour was entered
295  $object->timespent_date = dol_mktime(GETPOST("timelinehour", 'int'), GETPOST("timelinemin", 'int'), 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int'));
296  $object->timespent_withhour = 1;
297  } else {
298  $object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int'));
299  }
300  $object->timespent_fk_user = GETPOST("userid_line", 'int');
301 
302  $result = 0;
303  if (in_array($object->timespent_fk_user, $childids) || $user->rights->projet->all->creer) {
304  $result = $object->updateTimeSpent($user);
305 
306  if ($result >= 0) {
307  setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
308  } else {
309  setEventMessages($langs->trans($object->error), null, 'errors');
310  $error++;
311  }
312  }
313  }
314  } else {
315  $action = '';
316  }
317 }
318 
319 if ($action == 'confirm_deleteline' && $confirm == "yes" && $user->rights->projet->supprimer) {
320  $object->fetchTimeSpent(GETPOST('lineid', 'int')); // load properties like $object->timespent_id
321 
322  if (in_array($object->timespent_fk_user, $childids) || $user->rights->projet->all->creer) {
323  $result = $object->delTimeSpent($user); // delete line with $object->timespent_id
324 
325  if ($result < 0) {
326  $langs->load("errors");
327  setEventMessages($langs->trans($object->error), null, 'errors');
328  $error++;
329  $action = '';
330  } else {
331  setEventMessages($langs->trans("RecordDeleted"), null, 'mesgs');
332  }
333  }
334 }
335 
336 // Retrieve First Task ID of Project if withprojet is on to allow project prev next to work
337 if (!empty($project_ref) && !empty($withproject)) {
338  if ($projectstatic->fetch(0, $project_ref) > 0) {
339  $tasksarray = $object->getTasksArray(0, 0, $projectstatic->id, $socid, 0);
340  if (count($tasksarray) > 0) {
341  $id = $tasksarray[0]->id;
342  } else {
343  header("Location: ".DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.($withproject ? '&withproject=1' : '').(empty($mode) ? '' : '&mode='.$mode));
344  exit;
345  }
346  }
347 }
348 
349 // To show all time lines for project
350 $projectidforalltimes = 0;
351 if (GETPOST('projectid', 'int') > 0) {
352  $projectidforalltimes = GETPOST('projectid', 'int');
353 
354  $result = $projectstatic->fetch($projectidforalltimes);
355  if (!empty($projectstatic->socid)) {
356  $projectstatic->fetch_thirdparty();
357  }
358  $res = $projectstatic->fetch_optionals();
359 } elseif (GETPOST('project_ref', 'alpha')) {
360  $projectstatic->fetch(0, GETPOST('project_ref', 'alpha'));
361  $projectidforalltimes = $projectstatic->id;
362  $withproject = 1;
363 } elseif ($id > 0) {
364  $object->fetch($id);
365  $result = $projectstatic->fetch($object->fk_project);
366 }
367 // If not task selected and no project selected
368 if ($id <= 0 && $projectidforalltimes == 0) {
369  $allprojectforuser = $user->id;
370 }
371 
372 if ($action == 'confirm_generateinvoice') {
373  if (!empty($projectstatic->socid)) {
374  $projectstatic->fetch_thirdparty();
375  }
376 
377  if (!($projectstatic->thirdparty->id > 0)) {
378  setEventMessages($langs->trans("ThirdPartyRequiredToGenerateInvoice"), null, 'errors');
379  } else {
380  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
381  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
382  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
383 
384  $tmpinvoice = new Facture($db);
385  $tmptimespent = new Task($db);
386  $tmpproduct = new Product($db);
387  $fuser = new User($db);
388 
389  $db->begin();
390  $idprod = GETPOST('productid', 'int');
391  $generateinvoicemode = GETPOST('generateinvoicemode', 'string');
392  $invoiceToUse = GETPOST('invoiceid', 'int');
393 
394  $prodDurationHours = 1.0;
395  if ($idprod > 0) {
396  $tmpproduct->fetch($idprod);
397 
398  if (empty($tmpproduct->duration_value)) {
399  $error++;
400  $langs->load("errors");
401  setEventMessages($langs->trans("ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice"), null, 'errors');
402  }
403 
404  if ($tmpproduct->duration_unit == 'i') {
405  $prodDurationHours = 1. / 60;
406  }
407  if ($tmpproduct->duration_unit == 'h') {
408  $prodDurationHours = 1.;
409  }
410  if ($tmpproduct->duration_unit == 'd') {
411  $prodDurationHours = 24.;
412  }
413  if ($tmpproduct->duration_unit == 'w') {
414  $prodDurationHours = 24. * 7;
415  }
416  if ($tmpproduct->duration_unit == 'm') {
417  $prodDurationHours = 24. * 30;
418  }
419  if ($tmpproduct->duration_unit == 'y') {
420  $prodDurationHours = 24. * 365;
421  }
422  $prodDurationHours *= $tmpproduct->duration_value;
423 
424  $dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
425 
426  $pu_ht = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
427  $txtva = $dataforprice['tva_tx'];
428  $localtax1 = $dataforprice['localtax1'];
429  $localtax2 = $dataforprice['localtax2'];
430  } else {
431  $prodDurationHours = 1;
432 
433  $pu_ht = 0;
434  $txtva = get_default_tva($mysoc, $projectstatic->thirdparty);
435  $localtax1 = get_default_localtax($mysoc, $projectstatic->thirdparty, 1);
436  $localtax2 = get_default_localtax($mysoc, $projectstatic->thirdparty, 2);
437  }
438 
439  $tmpinvoice->socid = $projectstatic->thirdparty->id;
440  $tmpinvoice->date = dol_mktime(GETPOST('rehour', 'int'), GETPOST('remin', 'int'), GETPOST('resec', 'int'), GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
441  $tmpinvoice->fk_project = $projectstatic->id;
442 
443  if ($invoiceToUse) {
444  $tmpinvoice->fetch($invoiceToUse);
445  } else {
446  $result = $tmpinvoice->create($user);
447  if ($result <= 0) {
448  $error++;
449  setEventMessages($tmpinvoice->error, $tmpinvoice->errors, 'errors');
450  }
451  }
452 
453  if (!$error) {
454  if ($generateinvoicemode == 'onelineperuser') {
455  $arrayoftasks = array();
456  foreach ($toselect as $key => $value) {
457  // Get userid, timepent
458  $object->fetchTimeSpent($value);
459  $arrayoftasks[$object->timespent_fk_user]['timespent'] += $object->timespent_duration;
460  $arrayoftasks[$object->timespent_fk_user]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm);
461  }
462 
463  foreach ($arrayoftasks as $userid => $value) {
464  $fuser->fetch($userid);
465  //$pu_ht = $value['timespent'] * $fuser->thm;
466  $username = $fuser->getFullName($langs);
467 
468  // Define qty per hour
469  $qtyhour = $value['timespent'] / 3600;
470  $qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
471 
472  // If no unit price known
473  if (empty($pu_ht)) {
474  $pu_ht = price2num($value['totalvaluetodivideby3600'] / 3600, 'MU');
475  }
476 
477  // Add lines
478  $lineid = $tmpinvoice->addline($langs->trans("TimeSpentForInvoice", $username).' : '.$qtyhourtext, $pu_ht, round($qtyhour / $prodDurationHours, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0));
479 
480  // Update lineid into line of timespent
481  $sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
482  $sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).') AND fk_user = '.((int) $userid);
483  $result = $db->query($sql);
484  if (!$result) {
485  $error++;
486  setEventMessages($db->lasterror(), null, 'errors');
487  break;
488  }
489  }
490  } elseif ($generateinvoicemode == 'onelineperperiod') { // One line for each time spent line
491  $arrayoftasks = array();
492  $withdetail=GETPOST('detail_time_duration', 'alpha');
493  foreach ($toselect as $key => $value) {
494  // Get userid, timepent
495  $object->fetchTimeSpent($value);
496  // $object->id is the task id
497  $ftask = new Task($db);
498  $ftask->fetch($object->id);
499 
500  $fuser->fetch($object->timespent_fk_user);
501  $username = $fuser->getFullName($langs);
502 
503  $arrayoftasks[$object->timespent_id]['timespent'] = $object->timespent_duration;
504  $arrayoftasks[$object->timespent_id]['totalvaluetodivideby3600'] = $object->timespent_duration * $object->timespent_thm;
505  $arrayoftasks[$object->timespent_id]['note'] = $ftask->ref.' - '.$ftask->label.' - '.$username.($object->timespent_note ? ' - '.$object->timespent_note : ''); // TODO Add user name in note
506  if (!empty($withdetail)) {
507  if (!empty($conf->fckeditor->enabled) && !empty($conf->global->FCKEDITOR_ENABLE_DETAILS)) {
508  $arrayoftasks[$object->timespent_id]['note'] .= "<br/>";
509  } else {
510  $arrayoftasks[$object->timespent_id]['note'] .= "\n";
511  }
512 
513  if (!empty($object->timespent_withhour)) {
514  $arrayoftasks[$object->timespent_id]['note'] .= $langs->trans("Date") . ': ' . dol_print_date($object->timespent_datehour);
515  } else {
516  $arrayoftasks[$object->timespent_id]['note'] .= $langs->trans("Date") . ': ' . dol_print_date($object->timespent_date);
517  }
518  $arrayoftasks[$object->timespent_id]['note'] .= ' - '.$langs->trans("Duration").': '.convertSecondToTime($object->timespent_duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
519  }
520  $arrayoftasks[$object->timespent_id]['user'] = $object->timespent_fk_user;
521  }
522 
523  foreach ($arrayoftasks as $timespent_id => $value) {
524  $userid = $value['user'];
525  //$pu_ht = $value['timespent'] * $fuser->thm;
526 
527  // Define qty per hour
528  $qtyhour = $value['timespent'] / 3600;
529 
530  // If no unit price known
531  if (empty($pu_ht)) {
532  $pu_ht = price2num($value['totalvaluetodivideby3600'] / 3600, 'MU');
533  }
534 
535  // Add lines
536  $lineid = $tmpinvoice->addline($value['note'], $pu_ht, round($qtyhour / $prodDurationHours, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0));
537  //var_dump($lineid);exit;
538 
539  // Update lineid into line of timespent
540  $sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
541  $sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).') AND fk_user = '.((int) $userid);
542  $result = $db->query($sql);
543  if (!$result) {
544  $error++;
545  setEventMessages($db->lasterror(), null, 'errors');
546  break;
547  }
548  }
549  } elseif ($generateinvoicemode == 'onelinepertask') { // One line for each different task
550  $arrayoftasks = array();
551  foreach ($toselect as $key => $value) {
552  // Get userid, timepent
553  $object->fetchTimeSpent($value); // Call method to get list of timespent for a timespent line id (We use the utiliy method found into Task object)
554  // $object->id is now the task id
555  $arrayoftasks[$object->id]['timespent'] += $object->timespent_duration;
556  $arrayoftasks[$object->id]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm);
557  }
558 
559  foreach ($arrayoftasks as $task_id => $value) {
560  $ftask = new Task($db);
561  $ftask->fetch($task_id);
562  // Define qty per hour
563  $qtyhour = $value['timespent'] / 3600;
564  $qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
565 
566  if ($idprod > 0) {
567  // If a product is defined, we msut use the $prodDurationHours and $pu_ht of product (already set previously).
568  $pu_ht_for_task = $pu_ht;
569  // If we want to reuse the value of timespent (so use same price than cost price)
570  if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) {
571  $pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours;
572  }
573  $pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours;
574  } else {
575  // If not product used, we use the hour unit for duration and unit price.
576  $pu_ht_for_task = 0;
577  // If we want to reuse the value of timespent (so use same price than cost price)
578  if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) {
579  $pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU');
580  }
581  $pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU');
582  }
583 
584  // Add lines
585  $date_start = '';
586  $date_end = '';
587  $lineName = $ftask->ref.' - '.$ftask->label;
588  $lineid = $tmpinvoice->addline($lineName, $pu_ht_for_task, price2num($qtyhour / $prodDurationHours, 'MS'), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0), 0, $date_start, $date_end, 0, 0, '', 'HT', 0, 1, -1, 0, '', 0, 0, null, $pa_ht);
589  if ($lineid < 0) {
590  $error++;
591  setEventMessages($tmpinvoice->error, $tmpinvoice->errors, 'errors');
592  break;
593  }
594 
595  if (!$error) {
596  // Update lineid into line of timespent
597  $sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
598  $sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).')';
599  $result = $db->query($sql);
600  if (!$result) {
601  $error++;
602  setEventMessages($db->lasterror(), null, 'errors');
603  break;
604  }
605  }
606  }
607  }
608  }
609 
610  if (!$error) {
611  $urltoinvoice = $tmpinvoice->getNomUrl(0);
612  $mesg = $langs->trans("InvoiceGeneratedFromTimeSpent", '{s1}');
613  $mesg = str_replace('{s1}', $urltoinvoice, $mesg);
614  setEventMessages($mesg, null, 'mesgs');
615 
616  //var_dump($tmpinvoice);
617 
618  $db->commit();
619  } else {
620  $db->rollback();
621  }
622  }
623 }
624 
625 if ($action == 'confirm_generateinter') {
626  $langs->load('interventions');
627 
628  if (!empty($projectstatic->socid)) $projectstatic->fetch_thirdparty();
629 
630  if (!($projectstatic->thirdparty->id > 0)) {
631  setEventMessages($langs->trans("ThirdPartyRequiredToGenerateIntervention"), null, 'errors');
632  } else {
633  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
634  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
635  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
636 
637 
638  require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
639  $tmpinter = new Fichinter($db);
640  $tmptimespent = new Task($db);
641  $fuser = new User($db);
642 
643  $db->begin();
644  $interToUse = GETPOST('interid', 'int');
645 
646 
647  $tmpinter->socid = $projectstatic->thirdparty->id;
648  $tmpinter->date = dol_mktime(GETPOST('rehour', 'int'), GETPOST('remin', 'int'), GETPOST('resec', 'int'), GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
649  $tmpinter->fk_project = $projectstatic->id;
650  $tmpinter->description = $projectstatic->title . ( ! empty($projectstatic->description) ? '-' . $projectstatic->label : '' );
651 
652  if ($interToUse) {
653  $tmpinter->fetch($interToUse);
654  } else {
655  $result = $tmpinter->create($user);
656  if ($result <= 0) {
657  $error++;
658  setEventMessages($tmpinter->error, $tmpinter->errors, 'errors');
659  }
660  }
661 
662  if (!$error) {
663  $arrayoftasks = array();
664  foreach ($toselect as $key => $value) {
665  // Get userid, timespent
666  $object->fetchTimeSpent($value);
667  // $object->id is the task id
668  $arrayoftasks[$object->timespent_id]['id'] = $object->id;
669  $arrayoftasks[$object->timespent_id]['timespent'] = $object->timespent_duration;
670  $arrayoftasks[$object->timespent_id]['totalvaluetodivideby3600'] = $object->timespent_duration * $object->timespent_thm;
671  $arrayoftasks[$object->timespent_id]['note'] = $object->timespent_note;
672  $arrayoftasks[$object->timespent_id]['date'] = date('Y-m-d H:i:s', $object->timespent_datehour);
673  }
674 
675  foreach ($arrayoftasks as $timespent_id => $value) {
676  $ftask = new Task($db);
677  $ftask->fetch($value['id']);
678  // Define qty per hour
679  $qtyhour = $value['timespent'] / 3600;
680  $qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
681 
682  // Add lines
683  $lineid = $tmpinter->addline($user, $tmpinter->id, $ftask->label . ( ! empty($value['note']) ? ' - ' . $value['note'] : '' ), $value['date'], $value['timespent']);
684  }
685  }
686 
687  if (!$error) {
688  $urltointer = $tmpinter->getNomUrl(0);
689  $mesg = $langs->trans("InterventionGeneratedFromTimeSpent", '{s1}');
690  $mesg = str_replace('{s1}', $urltointer, $mesg);
691  setEventMessages($mesg, null, 'mesgs');
692 
693  //var_dump($tmpinvoice);
694 
695  $db->commit();
696  } else {
697  $db->rollback();
698  }
699  }
700 }
701 
702 /*
703  * View
704  */
705 
706 $arrayofselected = is_array($toselect) ? $toselect : array();
707 
708 llxHeader("", $langs->trans("Task"));
709 
710 $form = new Form($db);
711 $formother = new FormOther($db);
712 $formproject = new FormProjets($db);
713 $userstatic = new User($db);
714 
715 if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser > 0) {
716  /*
717  * Fiche projet en mode visu
718  */
719  if ($projectidforalltimes > 0) {
720  $result = $projectstatic->fetch($projectidforalltimes);
721  if (!empty($projectstatic->socid)) {
722  $projectstatic->fetch_thirdparty();
723  }
724  $res = $projectstatic->fetch_optionals();
725  } elseif ($object->fetch($id, $ref) >= 0) {
726  if (!empty($conf->global->PROJECT_ALLOW_COMMENT_ON_TASK) && method_exists($object, 'fetchComments') && empty($object->comments)) {
727  $object->fetchComments();
728  }
729  $result = $projectstatic->fetch($object->fk_project);
730  if (!empty($conf->global->PROJECT_ALLOW_COMMENT_ON_PROJECT) && method_exists($projectstatic, 'fetchComments') && empty($projectstatic->comments)) {
731  $projectstatic->fetchComments();
732  }
733  if (!empty($projectstatic->socid)) {
734  $projectstatic->fetch_thirdparty();
735  }
736  $res = $projectstatic->fetch_optionals();
737 
738  $object->project = clone $projectstatic;
739  }
740 
741  $userRead = $projectstatic->restrictedProjectArea($user, 'read');
742  $linktocreatetime = '';
743 
744  if ($projectstatic->id > 0) {
745  if ($withproject) {
746  // Tabs for project
747  if (empty($id) || $tab == 'timespent') {
748  $tab = 'timespent';
749  } else {
750  $tab = 'tasks';
751  }
752 
753  $head = project_prepare_head($projectstatic);
754  print dol_get_fiche_head($head, $tab, $langs->trans("Project"), -1, ($projectstatic->public ? 'projectpub' : 'project'));
755 
756  $param = ((!empty($mode) && $mode == 'mine') ? '&mode=mine' : '');
757  if ($search_user) {
758  $param .= '&search_user='.((int) $search_user);
759  }
760  if ($search_month) {
761  $param .= '&search_month='.((int) $search_month);
762  }
763  if ($search_year) {
764  $param .= '&search_year='.((int) $search_year);
765  }
766 
767  // Project card
768 
769  $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
770 
771  $morehtmlref = '<div class="refidno">';
772  // Title
773  $morehtmlref .= $projectstatic->title;
774  // Thirdparty
775  if (!empty($projectstatic->thirdparty->id) && $projectstatic->thirdparty->id > 0) {
776  $morehtmlref .= '<br>'.$langs->trans('ThirdParty').' : '.$projectstatic->thirdparty->getNomUrl(1, 'project');
777  }
778  $morehtmlref .= '</div>';
779 
780  // Define a complementary filter for search of next/prev ref.
781  if (empty($user->rights->projet->all->lire)) {
782  $objectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 0);
783  $projectstatic->next_prev_filter = " rowid IN (".$db->sanitize(count($objectsListId) ?join(',', array_keys($objectsListId)) : '0').")";
784  }
785 
786  dol_banner_tab($projectstatic, 'project_ref', $linkback, 1, 'ref', 'ref', $morehtmlref, $param);
787 
788  print '<div class="fichecenter">';
789  print '<div class="fichehalfleft">';
790  print '<div class="underbanner clearboth"></div>';
791 
792  print '<table class="border tableforfield centpercent">';
793 
794  // Usage
795  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES) || empty($conf->global->PROJECT_HIDE_TASKS) || isModEnabled('eventorganization')) {
796  print '<tr><td class="tdtop">';
797  print $langs->trans("Usage");
798  print '</td>';
799  print '<td>';
800  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
801  print '<input type="checkbox" disabled name="usage_opportunity"'.(GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_opportunity ? ' checked="checked"' : '')).'"> ';
802  $htmltext = $langs->trans("ProjectFollowOpportunity");
803  print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
804  print '<br>';
805  }
806  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
807  print '<input type="checkbox" disabled name="usage_task"'.(GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_task ? ' checked="checked"' : '')).'"> ';
808  $htmltext = $langs->trans("ProjectFollowTasks");
809  print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
810  print '<br>';
811  }
812  if (empty($conf->global->PROJECT_HIDE_TASKS) && !empty($conf->global->PROJECT_BILL_TIME_SPENT)) {
813  print '<input type="checkbox" disabled name="usage_bill_time"'.(GETPOSTISSET('usage_bill_time') ? (GETPOST('usage_bill_time', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_bill_time ? ' checked="checked"' : '')).'"> ';
814  $htmltext = $langs->trans("ProjectBillTimeDescription");
815  print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
816  print '<br>';
817  }
818  if (isModEnabled('eventorganization')) {
819  print '<input type="checkbox" disabled name="usage_organize_event"'.(GETPOSTISSET('usage_organize_event') ? (GETPOST('usage_organize_event', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_organize_event ? ' checked="checked"' : '')).'"> ';
820  $htmltext = $langs->trans("EventOrganizationDescriptionLong");
821  print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
822  }
823  print '</td></tr>';
824  }
825 
826  // Visibility
827  print '<tr><td class="titlefield">'.$langs->trans("Visibility").'</td><td>';
828  if ($projectstatic->public) {
829  print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
830  print $langs->trans('SharedProject');
831  } else {
832  print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
833  print $langs->trans('PrivateProject');
834  }
835  print '</td></tr>';
836 
837  // Date start - end
838  print '<tr><td>'.$langs->trans("DateStart").' - '.$langs->trans("DateEnd").'</td><td>';
839  $start = dol_print_date($projectstatic->date_start, 'day');
840  print ($start ? $start : '?');
841  $end = dol_print_date($projectstatic->date_end, 'day');
842  print ' - ';
843  print ($end ? $end : '?');
844  if ($projectstatic->hasDelay()) {
845  print img_warning("Late");
846  }
847  print '</td></tr>';
848 
849  // Budget
850  print '<tr><td>'.$langs->trans("Budget").'</td><td>';
851  if (strcmp($projectstatic->budget_amount, '')) {
852  print '<span class="amount">'.price($projectstatic->budget_amount, '', $langs, 1, 0, 0, $conf->currency).'</span>';
853  }
854  print '</td></tr>';
855 
856  // Other attributes
857  $cols = 2;
858  //include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
859 
860  print '</table>';
861 
862  print '</div>';
863  print '<div class="fichehalfright">';
864  print '<div class="underbanner clearboth"></div>';
865 
866  print '<table class="border tableforfield centpercent">';
867 
868  // Description
869  print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>';
870  print nl2br($projectstatic->description);
871  print '</td></tr>';
872 
873  // Categories
874  if (isModEnabled('categorie')) {
875  print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
876  print $form->showCategories($projectstatic->id, 'project', 1);
877  print "</td></tr>";
878  }
879 
880  print '</table>';
881 
882  print '</div>';
883  print '</div>';
884 
885  print '<div class="clearboth"></div>';
886 
887  print dol_get_fiche_end();
888 
889  print '<br>';
890  }
891 
892  // Link to create time
893  $linktocreatetimeBtnStatus = 0;
894  $linktocreatetimeUrl = '';
895  $linktocreatetimeHelpText = '';
896  if (!empty($user->rights->projet->time)) {
897  if ($projectstatic->public || $userRead > 0) {
898  $linktocreatetimeBtnStatus = 1;
899 
900  if (!empty($projectidforalltimes)) {
901  // We are on tab 'Time Spent' of project
902  $backtourl = $_SERVER['PHP_SELF'].'?projectid='.$projectstatic->id.($withproject ? '&withproject=1' : '');
903  $linktocreatetimeUrl = $_SERVER['PHP_SELF'].'?'.($withproject ? 'withproject=1' : '').'&projectid='.$projectstatic->id.'&action=createtime&token='.newToken().$param.'&backtopage='.urlencode($backtourl);
904  } else {
905  // We are on tab 'Time Spent' of task
906  $backtourl = $_SERVER['PHP_SELF'].'?id='.$object->id.($withproject ? '&withproject=1' : '');
907  $linktocreatetimeUrl = $_SERVER['PHP_SELF'].'?'.($withproject ? 'withproject=1' : '').($object->id > 0 ? '&id='.$object->id : '&projectid='.$projectstatic->id).'&action=createtime&token='.newToken().$param.'&backtopage='.urlencode($backtourl);
908  }
909  } else {
910  $linktocreatetimeBtnStatus = -2;
911  $linktocreatetimeHelpText = $langs->trans("NotOwnerOfProject");
912  }
913  } else {
914  $linktocreatetimeBtnStatus = -2;
915  $linktocreatetimeHelpText = $langs->trans("NotEnoughPermissions");
916  }
917 
918  $paramsbutton = array('morecss'=>'reposition');
919  $linktocreatetime = dolGetButtonTitle($langs->trans('AddTimeSpent'), $linktocreatetimeHelpText, 'fa fa-plus-circle', $linktocreatetimeUrl, '', $linktocreatetimeBtnStatus, $paramsbutton);
920  }
921 
922  $massactionbutton = '';
923  $arrayofmassactions = array();
924 
925  if ($projectstatic->id > 0) {
926  // If we are on a given project.
927  if ($projectstatic->usage_bill_time) {
928  $arrayofmassactions = array(
929  'generateinvoice'=>$langs->trans("GenerateBill"),
930  //'builddoc'=>$langs->trans("PDFMerge"),
931  );
932  }
933  if ( ! empty($conf->ficheinter->enabled) && $user->rights->ficheinter->creer) {
934  $langs->load("interventions");
935  $arrayofmassactions['generateinter'] = $langs->trans("GenerateInter");
936  }
937  }
938  //if ($user->rights->projet->creer) $arrayofmassactions['predelete']='<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete");
939  if (in_array($massaction, array('presend', 'predelete', 'generateinvoice', 'generateinter'))) {
940  $arrayofmassactions = array();
941  }
942  $massactionbutton = $form->selectMassAction('', $arrayofmassactions);
943 
944  // Show section with information of task. If id of task is not defined and project id defined, then $projectidforalltimes is not empty.
945  if (empty($projectidforalltimes) && empty($allprojectforuser)) {
946  $head = task_prepare_head($object);
947  print dol_get_fiche_head($head, 'task_time', $langs->trans("Task"), -1, 'projecttask', 0, '', 'reposition');
948 
949  if ($action == 'deleteline') {
950  print $form->formconfirm($_SERVER["PHP_SELF"]."?".($object->id > 0 ? "id=".$object->id : 'projectid='.$projectstatic->id).'&lineid='.GETPOST("lineid", 'int').($withproject ? '&withproject=1' : ''), $langs->trans("DeleteATimeSpent"), $langs->trans("ConfirmDeleteATimeSpent"), "confirm_deleteline", '', '', 1);
951  }
952 
953  $param = ($withproject ? '&withproject=1' : '');
954  $linkback = $withproject ? '<a href="'.DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.'">'.$langs->trans("BackToList").'</a>' : '';
955 
956  if (!GETPOST('withproject') || empty($projectstatic->id)) {
957  $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1);
958  $object->next_prev_filter = " fk_projet IN (".$db->sanitize($projectsListId).")";
959  } else {
960  $object->next_prev_filter = " fk_projet = ".$projectstatic->id;
961  }
962 
963  $morehtmlref = '';
964 
965  // Project
966  if (empty($withproject)) {
967  $morehtmlref .= '<div class="refidno">';
968  $morehtmlref .= $langs->trans("Project").': ';
969  $morehtmlref .= $projectstatic->getNomUrl(1);
970  $morehtmlref .= '<br>';
971 
972  // Third party
973  $morehtmlref .= $langs->trans("ThirdParty").': ';
974  if (!empty($projectstatic->thirdparty) && is_object($projectstatic->thirdparty)) {
975  $morehtmlref .= $projectstatic->thirdparty->getNomUrl(1);
976  }
977  $morehtmlref .= '</div>';
978  }
979 
980  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, $param);
981 
982  print '<div class="fichecenter">';
983  print '<div class="fichehalfleft">';
984 
985  print '<div class="underbanner clearboth"></div>';
986  print '<table class="border centpercent tableforfield">';
987 
988  // Task parent
989  print '<tr><td>'.$langs->trans("ChildOfTask").'</td><td>';
990  if ($object->fk_task_parent > 0) {
991  $tasktmp = new Task($db);
992  $tasktmp->fetch($object->fk_task_parent);
993  print $tasktmp->getNomUrl(1);
994  }
995  print '</td></tr>';
996 
997  // Date start - Date end
998  print '<tr><td class="titlefield">'.$langs->trans("DateStart").' - '.$langs->trans("Deadline").'</td><td>';
999  $start = dol_print_date($object->date_start, 'dayhour');
1000  print ($start ? $start : '?');
1001  $end = dol_print_date($object->date_end, 'dayhour');
1002  print ' - ';
1003  print ($end ? $end : '?');
1004  if ($object->hasDelay()) {
1005  print img_warning("Late");
1006  }
1007  print '</td></tr>';
1008 
1009  // Planned workload
1010  print '<tr><td>'.$langs->trans("PlannedWorkload").'</td><td>';
1011  if ($object->planned_workload) {
1012  print convertSecondToTime($object->planned_workload, 'allhourmin');
1013  }
1014  print '</td></tr>';
1015 
1016  print '</table>';
1017  print '</div>';
1018 
1019  print '<div class="fichehalfright">';
1020 
1021  print '<div class="underbanner clearboth"></div>';
1022  print '<table class="border tableforfield centpercent">';
1023 
1024  // Progress declared
1025  print '<tr><td class="titlefield">'.$langs->trans("ProgressDeclared").'</td><td>';
1026  print $object->progress != '' ? $object->progress.' %' : '';
1027  print '</td></tr>';
1028 
1029  // Progress calculated
1030  print '<tr><td>'.$langs->trans("ProgressCalculated").'</td><td>';
1031  if ($object->planned_workload) {
1032  $tmparray = $object->getSummaryOfTimeSpent();
1033  if ($tmparray['total_duration'] > 0) {
1034  print round($tmparray['total_duration'] / $object->planned_workload * 100, 2).' %';
1035  } else {
1036  print '0 %';
1037  }
1038  } else {
1039  print '<span class="opacitymedium">'.$langs->trans("WorkloadNotDefined").'</span>';
1040  }
1041  print '</td>';
1042 
1043  print '</tr>';
1044 
1045  print '</table>';
1046 
1047  print '</div>';
1048 
1049  print '</div>';
1050  print '<div class="clearboth"></div>';
1051 
1052  print dol_get_fiche_end();
1053  }
1054 
1055 
1056  if ($projectstatic->id > 0 || $allprojectforuser > 0) {
1057  if ($action == 'deleteline' && !empty($projectidforalltimes)) {
1058  print $form->formconfirm($_SERVER["PHP_SELF"]."?".($object->id > 0 ? "id=".$object->id : 'projectid='.$projectstatic->id).'&lineid='.GETPOST('lineid', 'int').($withproject ? '&withproject=1' : ''), $langs->trans("DeleteATimeSpent"), $langs->trans("ConfirmDeleteATimeSpent"), "confirm_deleteline", '', '', 1);
1059  }
1060 
1061  // Initialize technical object to manage hooks. Note that conf->hooks_modules contains array
1062  $hookmanager->initHooks(array('tasktimelist'));
1063 
1064  $formconfirm = '';
1065 
1066  if ($action == 'deleteline' && !empty($projectidforalltimes)) {
1067  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?".($object->id > 0 ? "id=".$object->id : 'projectid='.$projectstatic->id).'&lineid='.GETPOST('lineid', 'int').($withproject ? '&withproject=1' : ''), $langs->trans("DeleteATimeSpent"), $langs->trans("ConfirmDeleteATimeSpent"), "confirm_deleteline", '', '', 1);
1068  }
1069 
1070  // Call Hook formConfirm
1071  $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid, "projectstatic" => $projectstatic, "withproject" => $withproject);
1072  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1073  if (empty($reshook)) {
1074  $formconfirm .= $hookmanager->resPrint;
1075  } elseif ($reshook > 0) {
1076  $formconfirm = $hookmanager->resPrint;
1077  }
1078 
1079  // Print form confirm
1080  print $formconfirm;
1081 
1082  // Definition of fields for list
1083  $arrayfields = array();
1084  $arrayfields['t.task_date'] = array('label'=>$langs->trans("Date"), 'checked'=>1);
1085  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
1086  $arrayfields['t.task_ref'] = array('label'=>$langs->trans("RefTask"), 'checked'=>1);
1087  $arrayfields['t.task_label'] = array('label'=>$langs->trans("LabelTask"), 'checked'=>1);
1088  }
1089  $arrayfields['author'] = array('label'=>$langs->trans("By"), 'checked'=>1);
1090  $arrayfields['t.note'] = array('label'=>$langs->trans("Note"), 'checked'=>1);
1091  $arrayfields['t.task_duration'] = array('label'=>$langs->trans("Duration"), 'checked'=>1);
1092  $arrayfields['value'] = array('label'=>$langs->trans("Value"), 'checked'=>1, 'enabled'=>(empty($conf->salaries->enabled) ? 0 : 1));
1093  $arrayfields['valuebilled'] = array('label'=>$langs->trans("Billed"), 'checked'=>1, 'enabled'=>(((!empty($conf->global->PROJECT_HIDE_TASKS) || empty($conf->global->PROJECT_BILL_TIME_SPENT)) ? 0 : 1) && $projectstatic->usage_bill_time));
1094  // Extra fields
1095  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php';
1096 
1097  $arrayfields = dol_sort_array($arrayfields, 'position');
1098 
1099  $param = '';
1100  if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
1101  $param .= '&contextpage='.urlencode($contextpage);
1102  }
1103  if ($limit > 0 && $limit != $conf->liste_limit) {
1104  $param .= '&limit='.urlencode($limit);
1105  }
1106  if ($search_month > 0) {
1107  $param .= '&search_month='.urlencode($search_month);
1108  }
1109  if ($search_year > 0) {
1110  $param .= '&search_year='.urlencode($search_year);
1111  }
1112  if ($search_user > 0) {
1113  $param .= '&search_user='.urlencode($search_user);
1114  }
1115  if ($search_task_ref != '') {
1116  $param .= '&search_task_ref='.urlencode($search_task_ref);
1117  }
1118  if ($search_task_label != '') {
1119  $param .= '&search_task_label='.urlencode($search_task_label);
1120  }
1121  if ($search_note != '') {
1122  $param .= '&search_note='.urlencode($search_note);
1123  }
1124  if ($search_duration != '') {
1125  $param .= '&amp;search_field2='.urlencode($search_duration);
1126  }
1127  if ($optioncss != '') {
1128  $param .= '&optioncss='.urlencode($optioncss);
1129  }
1130  /*
1131  // Add $param from extra fields
1132  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
1133  */
1134  if ($id) {
1135  $param .= '&id='.urlencode($id);
1136  }
1137  if ($projectid) {
1138  $param .= '&projectid='.urlencode($projectid);
1139  }
1140  if ($withproject) {
1141  $param .= '&withproject='.urlencode($withproject);
1142  }
1143  // Add $param from hooks
1144  $parameters = array();
1145  $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook
1146  $param .= $hookmanager->resPrint;
1147 
1148  print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
1149  if ($optioncss != '') {
1150  print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
1151  }
1152  print '<input type="hidden" name="token" value="'.newToken().'">';
1153  print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
1154  if ($action == 'editline') {
1155  print '<input type="hidden" name="action" value="updateline">';
1156  } elseif ($action == 'splitline') {
1157  print '<input type="hidden" name="action" value="updatesplitline">';
1158  } elseif ($action == 'createtime' && $user->rights->projet->time) {
1159  print '<input type="hidden" name="action" value="addtimespent">';
1160  } elseif ($massaction == 'generateinvoice' && $user->rights->facture->lire) {
1161  print '<input type="hidden" name="action" value="confirm_generateinvoice">';
1162  } elseif ($massaction == 'generateinter' && $user->rights->ficheinter->lire) {
1163  print '<input type="hidden" name="action" value="confirm_generateinter">';
1164  } else {
1165  print '<input type="hidden" name="action" value="list">';
1166  }
1167  print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
1168  print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
1169 
1170  print '<input type="hidden" name="id" value="'.$id.'">';
1171  print '<input type="hidden" name="projectid" value="'.$projectidforalltimes.'">';
1172  print '<input type="hidden" name="withproject" value="'.$withproject.'">';
1173  print '<input type="hidden" name="tab" value="'.$tab.'">';
1174  print '<input type="hidden" name="page_y" value="">';
1175 
1176  // Form to convert time spent into invoice
1177  if ($massaction == 'generateinvoice') {
1178  if ($projectstatic->thirdparty->id > 0) {
1179  print '<table class="noborder centerpercent">';
1180  print '<tr>';
1181  print '<td class="titlefield">';
1182  print $langs->trans('DateInvoice');
1183  print '</td>';
1184  print '<td>';
1185  print $form->selectDate('', '', '', '', '', '', 1, 1);
1186  print '</td>';
1187  print '</tr>';
1188 
1189  print '<tr>';
1190  print '<td>';
1191  print $langs->trans('Mode');
1192  print '</td>';
1193  print '<td>';
1194  $tmparray = array(
1195  'onelineperuser'=>'OneLinePerUser',
1196  'onelinepertask'=>'OneLinePerTask',
1197  'onelineperperiod'=>'OneLinePerTimeSpentLine',
1198  );
1199  print $form->selectarray('generateinvoicemode', $tmparray, 'onelineperuser', 0, 0, 0, '', 1);
1200  print "\n".'<script type="text/javascript">';
1201  print '
1202  $(document).ready(function () {
1203  setDetailVisibility();
1204  $("#generateinvoicemode").change(function() {
1205  setDetailVisibility();
1206  });
1207  function setDetailVisibility() {
1208  generateinvoicemode = $("#generateinvoicemode option:selected").val();
1209  if (generateinvoicemode=="onelineperperiod") {
1210  $("#detail_time_duration").show();
1211  } else {
1212  $("#detail_time_duration").hide();
1213  }
1214  }
1215  });
1216  ';
1217  print '</script>'."\n";
1218  print '<span style="display:none" id="detail_time_duration"><input type="checkbox" value="detail" name="detail_time_duration"/>'.$langs->trans('AddDetailDateAndDuration').'</span>';
1219  print '</td>';
1220  print '</tr>';
1221 
1222  if ($conf->service->enabled) {
1223  print '<tr>';
1224  print '<td>';
1225  print $langs->trans('ServiceToUseOnLines');
1226  print '</td>';
1227  print '<td>';
1228  $form->select_produits('', 'productid', '1', 0, $projectstatic->thirdparty->price_level, 1, 2, '', 0, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500');
1229  print '</td>';
1230  print '</tr>';
1231  }
1232 
1233  print '<tr>';
1234  print '<td class="titlefield">';
1235  print $langs->trans('InvoiceToUse');
1236  print '</td>';
1237  print '<td>';
1238  $form->selectInvoice('invoice', '', 'invoiceid', 24, 0, $langs->trans('NewInvoice'), 1, 0, 0, 'maxwidth500', '', 'all');
1239  print '</td>';
1240  print '</tr>';
1241  /*print '<tr>';
1242  print '<td>';
1243  print $langs->trans('ValidateInvoices');
1244  print '</td>';
1245  print '<td>';
1246  print $form->selectyesno('validate_invoices', 0, 1);
1247  print '</td>';
1248  print '</tr>';*/
1249  print '</table>';
1250 
1251  print '<br>';
1252  print '<div class="center">';
1253  print '<input type="submit" class="button" id="createbills" name="createbills" value="'.$langs->trans('GenerateBill').'"> ';
1254  print '<input type="submit" class="button button-cancel" id="cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
1255  print '</div>';
1256  print '<br>';
1257  } else {
1258  print '<div class="warning">'.$langs->trans("ThirdPartyRequiredToGenerateInvoice").'</div>';
1259  print '<div class="center">';
1260  print '<input type="submit" class="button button-cancel" id="cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
1261  print '</div>';
1262  $massaction = '';
1263  }
1264  } elseif ($massaction == 'generateinter') {
1265  // Form to convert time spent into invoice
1266  print '<input type="hidden" name="massaction" value="confirm_createinter">';
1267 
1268  if ($projectstatic->thirdparty->id > 0) {
1269  print '<br>';
1270  print '<table class="noborder centpercent">';
1271  print '<tr>';
1272  print '<td class="titlefield">';
1273  print img_picto('', 'intervention', 'class="pictofixedwidth"').$langs->trans('InterToUse');
1274  print '</td>';
1275  print '<td>';
1276  $forminter = new FormIntervention($db);
1277  print $forminter->select_interventions($projectstatic->thirdparty->id, '', 'interid', 24, $langs->trans('NewInter'), true);
1278  print '</td>';
1279  print '</tr>';
1280  print '</table>';
1281 
1282  print '<div class="center">';
1283  print '<input type="submit" class="button" id="createinter" name="createinter" value="'.$langs->trans('GenerateInter').'"> ';
1284  print '<input type="submit" class="button" id="cancel" name="cancel" value="'.$langs->trans('Cancel').'">';
1285  print '</div>';
1286  print '<br>';
1287  } else {
1288  print '<div class="warning">'.$langs->trans("ThirdPartyRequiredToGenerateIntervention").'</div>';
1289  print '<div class="center">';
1290  print '<input type="submit" class="button" id="cancel" name="cancel" value="'.$langs->trans('Cancel').'">';
1291  print '</div>';
1292  $massaction = '';
1293  }
1294  }
1295 
1296  // Allow Pre-Mass-Action hook (eg for confirmation dialog)
1297  $parameters = array(
1298  'toselect' => $toselect,
1299  'uploaddir' => isset($uploaddir) ? $uploaddir : null
1300  );
1301 
1302  $reshook = $hookmanager->executeHooks('doPreMassActions', $parameters, $object, $action);
1303  if ($reshook < 0) {
1304  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1305  } else {
1306  print $hookmanager->resPrint;
1307  }
1308 
1309  /*
1310  * List of time spent
1311  */
1312  $tasks = array();
1313 
1314  $sql = "SELECT t.rowid, t.fk_task, t.task_date, t.task_datehour, t.task_date_withhour, t.task_duration, t.fk_user, t.note, t.thm,";
1315  $sql .= " pt.ref, pt.label, pt.fk_projet,";
1316  $sql .= " u.lastname, u.firstname, u.login, u.photo, u.statut as user_status,";
1317  $sql .= " il.fk_facture as invoice_id, inv.fk_statut,";
1318  // Add fields from hooks
1319  $parameters = array();
1320  $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook
1321  $sql .= preg_replace('/^,/', '', $hookmanager->resPrint);
1322  $sql = preg_replace('/,\s*$/', '', $sql);
1323  $sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t";
1324  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facturedet as il ON il.rowid = t.invoice_line_id";
1325  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as inv ON inv.rowid = il.fk_facture";
1326  // Add table from hooks
1327  $parameters = array();
1328  $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook
1329  $sql .= $hookmanager->resPrint;
1330  $sql .= ", ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."user as u";
1331  $sql .= " WHERE t.fk_user = u.rowid AND t.fk_task = pt.rowid";
1332 
1333  if (empty($projectidforalltimes) && empty($allprojectforuser)) {
1334  // Limit on one task
1335  $sql .= " AND t.fk_task =".((int) $object->id);
1336  } elseif (!empty($projectidforalltimes)) {
1337  // Limit on one project
1338  $sql .= " AND pt.fk_projet IN (".$db->sanitize($projectidforalltimes).")";
1339  } elseif (!empty($allprojectforuser)) {
1340  // Limit on on user
1341  if (empty($search_user)) {
1342  $search_user = $user->id;
1343  }
1344  $sql .= " AND t.fk_user = ".((int) $search_user);
1345  }
1346 
1347  if ($search_note) {
1348  $sql .= natural_search('t.note', $search_note);
1349  }
1350  if ($search_task_ref) {
1351  $sql .= natural_search('pt.ref', $search_task_ref);
1352  }
1353  if ($search_task_label) {
1354  $sql .= natural_search('pt.label', $search_task_label);
1355  }
1356  if ($search_user > 0) {
1357  $sql .= natural_search('t.fk_user', $search_user, 2);
1358  }
1359  if ($search_valuebilled == '1') {
1360  $sql .= ' AND t.invoice_id > 0';
1361  }
1362  if ($search_valuebilled == '0') {
1363  $sql .= ' AND (t.invoice_id = 0 OR t.invoice_id IS NULL)';
1364  }
1365 
1366  $sql .= dolSqlDateFilter('t.task_datehour', $search_day, $search_month, $search_year);
1367 
1368  // Add where from hooks
1369  $parameters = array();
1370  $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
1371  $sql .= $hookmanager->resPrint;
1372  $sql .= $db->order($sortfield, $sortorder);
1373 
1374  // Count total nb of records
1375  $nbtotalofrecords = '';
1376  if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
1377  $resql = $db->query($sql);
1378 
1379  if (! $resql) {
1380  dol_print_error($db);
1381  exit;
1382  }
1383 
1384  $nbtotalofrecords = $db->num_rows($resql);
1385  if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0
1386  $page = 0;
1387  $offset = 0;
1388  }
1389  }
1390  // if total of record found is smaller than limit, no need to do paging and to restart another select with limits set.
1391  if (is_numeric($nbtotalofrecords) && $limit > $nbtotalofrecords) {
1392  $num = $nbtotalofrecords;
1393  } else {
1394  $sql .= $db->plimit($limit + 1, $offset);
1395 
1396  $resql = $db->query($sql);
1397  if (!$resql) {
1398  dol_print_error($db);
1399  exit;
1400  }
1401 
1402  $num = $db->num_rows($resql);
1403  }
1404 
1405  if ($num >= 0) {
1406  if (!empty($projectidforalltimes)) {
1407  print '<!-- List of time spent for project -->'."\n";
1408 
1409  $title = $langs->trans("ListTaskTimeUserProject");
1410 
1411  print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'clock', 0, $linktocreatetime, '', $limit, 0, 0, 1);
1412  } else {
1413  print '<!-- List of time spent -->'."\n";
1414 
1415  $title = $langs->trans("ListTaskTimeForTask");
1416 
1417  print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'clock', 0, $linktocreatetime, '', $limit, 0, 0, 1);
1418  }
1419 
1420  $i = 0;
1421  while ($i < $num) {
1422  $row = $db->fetch_object($resql);
1423  $tasks[$i] = $row;
1424  $i++;
1425  }
1426  $db->free($resql);
1427  } else {
1428  dol_print_error($db);
1429  }
1430 
1431  /*
1432  * Form to add a new line of time spent
1433  */
1434  if ($action == 'createtime' && $user->rights->projet->time) {
1435  print '<!-- table to add time spent -->'."\n";
1436  if (!empty($id)) {
1437  print '<input type="hidden" name="taskid" value="'.$id.'">';
1438  }
1439 
1440  print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
1441  print '<table class="noborder nohover centpercent">';
1442 
1443  print '<tr class="liste_titre">';
1444  print '<td>'.$langs->trans("Date").'</td>';
1445  if (!empty($allprojectforuser)) {
1446  print '<td>'.$langs->trans("Project").'</td>';
1447  }
1448  if (empty($id)) {
1449  print '<td>'.$langs->trans("Task").'</td>';
1450  }
1451  print '<td>'.$langs->trans("By").'</td>';
1452  print '<td>'.$langs->trans("Note").'</td>';
1453  print '<td>'.$langs->trans("NewTimeSpent").'</td>';
1454  print '<td>'.$langs->trans("ProgressDeclared").'</td>';
1455  if (empty($conf->global->PROJECT_HIDE_TASKS) && !empty($conf->global->PROJECT_BILL_TIME_SPENT)) {
1456  print '<td></td>';
1457  }
1458  // Hook fields
1459  $parameters = array('mode' => 'create');
1460  $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
1461  print $hookmanager->resPrint;
1462  print '<td></td>';
1463  print "</tr>\n";
1464 
1465  print '<tr class="oddeven nohover">';
1466 
1467  // Date
1468  print '<td class="maxwidthonsmartphone">';
1469  $newdate = '';
1470  print $form->selectDate($newdate, 'time', ($conf->browser->layout == 'phone' ? 2 : 1), 1, 2, "timespent_date", 1, 0);
1471  print '</td>';
1472 
1473  if (!empty($allprojectforuser)) {
1474  print '<td>';
1475  // Add project selector
1476  print '</td>';
1477  }
1478 
1479  // Task
1480  $nboftasks = 0;
1481  if (empty($id)) {
1482  print '<td class="maxwidthonsmartphone">';
1483  $nboftasks = $formproject->selectTasks(-1, GETPOST('taskid', 'int'), 'taskid', 0, 0, 1, 1, 0, 0, 'maxwidth300', $projectstatic->id, 'progress');
1484  print '</td>';
1485  }
1486 
1487  // Contributor
1488  print '<td class="maxwidthonsmartphone nowraponall">';
1489  $contactsofproject = $projectstatic->getListContactId('internal');
1490  if (count($contactsofproject) > 0) {
1491  print img_object('', 'user', 'class="hideonsmartphone"');
1492  if (in_array($user->id, $contactsofproject)) {
1493  $userid = $user->id;
1494  } else {
1495  $userid = $contactsofproject[0];
1496  }
1497 
1498  if ($projectstatic->public) {
1499  $contactsofproject = array();
1500  }
1501  print $form->select_dolusers((GETPOST('userid', 'int') ? GETPOST('userid', 'int') : $userid), 'userid', 0, '', 0, '', $contactsofproject, 0, 0, 0, '', 0, $langs->trans("ResourceNotAssignedToProject"), 'maxwidth250');
1502  } else {
1503  if ($nboftasks) {
1504  print img_error($langs->trans('FirstAddRessourceToAllocateTime')).' '.$langs->trans('FirstAddRessourceToAllocateTime');
1505  }
1506  }
1507  print '</td>';
1508 
1509  // Note
1510  print '<td>';
1511  print '<textarea name="timespent_note" class="maxwidth100onsmartphone" rows="'.ROWS_2.'">'.(GETPOST('timespent_note') ? GETPOST('timespent_note') : '').'</textarea>';
1512  print '</td>';
1513 
1514  // Duration - Time spent
1515  print '<td class="nowraponall">';
1516  $durationtouse = (GETPOST('timespent_duration') ? GETPOST('timespent_duration') : '');
1517  if (GETPOSTISSET('timespent_durationhour') || GETPOSTISSET('timespent_durationmin')) {
1518  $durationtouse = (GETPOST('timespent_durationhour') * 3600 + GETPOST('timespent_durationmin') * 60);
1519  }
1520  print $form->select_duration('timespent_duration', $durationtouse, 0, 'text');
1521  print '</td>';
1522 
1523  // Progress declared
1524  print '<td class="nowrap">';
1525  print $formother->select_percent(GETPOST('progress') ?GETPOST('progress') : $object->progress, 'progress', 0, 5, 0, 100, 1);
1526  print '</td>';
1527 
1528  // Invoiced
1529  if (empty($conf->global->PROJECT_HIDE_TASKS) && !empty($conf->global->PROJECT_BILL_TIME_SPENT)) {
1530  print '<td>';
1531  print '</td>';
1532  }
1533 
1534  // Fields from hook
1535  $parameters = array('mode' => 'create');
1536  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
1537  print $hookmanager->resPrint;
1538 
1539  print '<td class="center">';
1540  $form->buttonsSaveCancel();
1541  print '<input type="submit" name="save" class="button buttongen marginleftonly margintoponlyshort marginbottomonlyshort button-add" value="'.$langs->trans("Add").'">';
1542  print '<input type="submit" name="cancel" class="button buttongen marginleftonly margintoponlyshort marginbottomonlyshort button-cancel" value="'.$langs->trans("Cancel").'">';
1543  print '</td></tr>';
1544 
1545  print '</table>';
1546  print '</div>';
1547 
1548  print '<br>';
1549  }
1550 
1551  $moreforfilter = '';
1552 
1553  $parameters = array();
1554  $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
1555  if (empty($reshook)) {
1556  $moreforfilter .= $hookmanager->resPrint;
1557  } else {
1558  $moreforfilter = $hookmanager->resPrint;
1559  }
1560 
1561  if (!empty($moreforfilter)) {
1562  print '<div class="liste_titre liste_titre_bydiv centpercent">';
1563  print $moreforfilter;
1564  print '</div>';
1565  }
1566 
1567  $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
1568  $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
1569  $selectedfields .= (is_array($arrayofmassactions) && count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : '');
1570 
1571  print '<div class="div-table-responsive">';
1572  print '<table class="tagtable nobottomiftotal liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
1573 
1574  // Fields title search
1575  print '<tr class="liste_titre_filter">';
1576  // Date
1577  if (!empty($arrayfields['t.task_date']['checked'])) {
1578  print '<td class="liste_titre">';
1579  if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) {
1580  print '<input class="flat valignmiddle" type="text" size="1" maxlength="2" name="search_day" value="'.$search_day.'">';
1581  }
1582  print '<input class="flat valignmiddle" type="text" size="1" maxlength="2" name="search_month" value="'.$search_month.'">';
1583  print $formother->selectyear($search_year, 'search_year', 1, 20, 5);
1584  print '</td>';
1585  }
1586  if (!empty($allprojectforuser)) {
1587  print '<td class="liste_titre"></td>';
1588  }
1589  // Task
1590  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
1591  if (!empty($arrayfields['t.task_ref']['checked'])) {
1592  print '<td class="liste_titre"><input type="text" class="flat maxwidth100" name="search_task_ref" value="'.dol_escape_htmltag($search_task_ref).'"></td>';
1593  }
1594  if (!empty($arrayfields['t.task_label']['checked'])) {
1595  print '<td class="liste_titre"><input type="text" class="flat maxwidth100" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
1596  }
1597  }
1598  // Author
1599  if (!empty($arrayfields['author']['checked'])) {
1600  print '<td class="liste_titre">'.$form->select_dolusers(($search_user > 0 ? $search_user : -1), 'search_user', 1, null, 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth250').'</td>';
1601  }
1602  // Note
1603  if (!empty($arrayfields['t.note']['checked'])) {
1604  print '<td class="liste_titre"><input type="text" class="flat maxwidth100" name="search_note" value="'.dol_escape_htmltag($search_note).'"></td>';
1605  }
1606  // Duration
1607  if (!empty($arrayfields['t.task_duration']['checked'])) {
1608  print '<td class="liste_titre right"></td>';
1609  }
1610  // Value in main currency
1611  if (!empty($arrayfields['value']['checked'])) {
1612  print '<td class="liste_titre"></td>';
1613  }
1614  // Value billed
1615  if (!empty($arrayfields['valuebilled']['checked'])) {
1616  print '<td class="liste_titre center">'.$form->selectyesno('search_valuebilled', $search_valuebilled, 1, false, 1).'</td>';
1617  }
1618 
1619  /*
1620  // Extra fields
1621  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
1622  */
1623  // Fields from hook
1624  $parameters = array('arrayfields'=>$arrayfields);
1625  $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
1626  print $hookmanager->resPrint;
1627  // Action column
1628  print '<td class="liste_titre center">';
1629  $searchpicto = $form->showFilterButtons();
1630  print $searchpicto;
1631  print '</td>';
1632  print '</tr>'."\n";
1633 
1634  print '<tr class="liste_titre">';
1635  if (!empty($arrayfields['t.task_date']['checked'])) {
1636  print_liste_field_titre($arrayfields['t.task_date']['label'], $_SERVER['PHP_SELF'], 't.task_date,t.task_datehour,t.rowid', '', $param, '', $sortfield, $sortorder);
1637  }
1638  if (!empty($allprojectforuser)) {
1639  print_liste_field_titre("Project", $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder);
1640  }
1641  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
1642  if (!empty($arrayfields['t.task_ref']['checked'])) {
1643  print_liste_field_titre($arrayfields['t.task_ref']['label'], $_SERVER['PHP_SELF'], 'pt.ref', '', $param, '', $sortfield, $sortorder);
1644  }
1645  if (!empty($arrayfields['t.task_label']['checked'])) {
1646  print_liste_field_titre($arrayfields['t.task_label']['label'], $_SERVER['PHP_SELF'], 'pt.label', '', $param, '', $sortfield, $sortorder);
1647  }
1648  }
1649  if (!empty($arrayfields['author']['checked'])) {
1650  print_liste_field_titre($arrayfields['author']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder);
1651  }
1652  if (!empty($arrayfields['t.note']['checked'])) {
1653  print_liste_field_titre($arrayfields['t.note']['label'], $_SERVER['PHP_SELF'], 't.note', '', $param, '', $sortfield, $sortorder);
1654  }
1655  if (!empty($arrayfields['t.task_duration']['checked'])) {
1656  print_liste_field_titre($arrayfields['t.task_duration']['label'], $_SERVER['PHP_SELF'], 't.task_duration', '', $param, '', $sortfield, $sortorder, 'right ');
1657  }
1658  if (!empty($arrayfields['value']['checked'])) {
1659  print_liste_field_titre($arrayfields['value']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
1660  }
1661  if (!empty($arrayfields['valuebilled']['checked'])) {
1662  print_liste_field_titre($arrayfields['valuebilled']['label'], $_SERVER['PHP_SELF'], 'il.total_ht', '', $param, '', $sortfield, $sortorder, 'center ', $langs->trans("SelectLinesOfTimeSpentToInvoice"));
1663  }
1664  /*
1665  // Extra fields
1666  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1667  */
1668  // Hook fields
1669  $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
1670  $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
1671  print $hookmanager->resPrint;
1672  print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'width="80"', $sortfield, $sortorder, 'center maxwidthsearch ');
1673  print "</tr>\n";
1674 
1675  $tasktmp = new Task($db);
1676  $tmpinvoice = new Facture($db);
1677 
1678  $i = 0;
1679 
1680  $total = 0;
1681  $totalvalue = 0;
1682  $totalarray = array();
1683  foreach ($tasks as $task_time) {
1684  if ($i >= $limit) {
1685  break;
1686  }
1687 
1688  $date1 = $db->jdate($task_time->task_date);
1689  $date2 = $db->jdate($task_time->task_datehour);
1690 
1691  print '<tr class="oddeven">';
1692 
1693  // Date
1694  if (!empty($arrayfields['t.task_date']['checked'])) {
1695  print '<td class="nowrap">';
1696  if ($action == 'editline' && GETPOST('lineid', 'int') == $task_time->rowid) {
1697  if (empty($task_time->task_date_withhour)) {
1698  print $form->selectDate(($date2 ? $date2 : $date1), 'timeline', 3, 3, 2, "timespent_date", 1, 0);
1699  } else {
1700  print $form->selectDate(($date2 ? $date2 : $date1), 'timeline', 1, 1, 2, "timespent_date", 1, 0);
1701  }
1702  } else {
1703  print dol_print_date(($date2 ? $date2 : $date1), ($task_time->task_date_withhour ? 'dayhour' : 'day'));
1704  }
1705  print '</td>';
1706  if (!$i) {
1707  $totalarray['nbfield']++;
1708  }
1709  }
1710 
1711  // Project ref
1712  if (!empty($allprojectforuser)) {
1713  print '<td class="nowraponall">';
1714  if (empty($conf->cache['project'][$task_time->fk_projet])) {
1715  $tmpproject = new Project($db);
1716  $tmpproject->fetch($task_time->fk_projet);
1717  $conf->cache['project'][$task_time->fk_projet] = $tmpproject;
1718  } else {
1719  $tmpproject = $conf->cache['project'][$task_time->fk_projet];
1720  }
1721  print $tmpproject->getNomUrl(1);
1722  print '</td>';
1723  if (!$i) {
1724  $totalarray['nbfield']++;
1725  }
1726  }
1727 
1728  // Task ref
1729  if (!empty($arrayfields['t.task_ref']['checked'])) {
1730  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
1731  print '<td class="nowrap">';
1732  if ($action == 'editline' && GETPOST('lineid', 'int') == $task_time->rowid) {
1733  $formproject->selectTasks(-1, GETPOST('taskid', 'int') ? GETPOST('taskid', 'int') : $task_time->fk_task, 'taskid', 0, 0, 1, 1, 0, 0, 'maxwidth300', $projectstatic->id, '');
1734  } else {
1735  $tasktmp->id = $task_time->fk_task;
1736  $tasktmp->ref = $task_time->ref;
1737  $tasktmp->label = $task_time->label;
1738  print $tasktmp->getNomUrl(1, 'withproject', 'time');
1739  }
1740  print '</td>';
1741  if (!$i) {
1742  $totalarray['nbfield']++;
1743  }
1744  }
1745  } elseif ($action !== 'createtime') {
1746  print '<input type="hidden" name="taskid" value="'.$id.'">';
1747  }
1748 
1749  // Task label
1750  if (!empty($arrayfields['t.task_label']['checked'])) {
1751  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
1752  print '<td class="nowrap tdoverflowmax300" title="'.dol_escape_htmltag($task_time->label).'">';
1753  print dol_escape_htmltag($task_time->label);
1754  print '</td>';
1755  if (!$i) {
1756  $totalarray['nbfield']++;
1757  }
1758  }
1759  }
1760 
1761  // By User
1762  if (!empty($arrayfields['author']['checked'])) {
1763  print '<td class="tdoverflowmax100">';
1764  if ($action == 'editline' && GETPOST('lineid', 'int') == $task_time->rowid) {
1765  if (empty($object->id)) {
1766  $object->fetch($id);
1767  }
1768  $contactsoftask = $object->getListContactId('internal');
1769  if (!in_array($task_time->fk_user, $contactsoftask)) {
1770  $contactsoftask[] = $task_time->fk_user;
1771  }
1772  if (count($contactsoftask) > 0) {
1773  print img_object('', 'user', 'class="hideonsmartphone"');
1774  print $form->select_dolusers($task_time->fk_user, 'userid_line', 0, '', 0, '', $contactsoftask, '0', 0, 0, '', 0, '', 'maxwidth200');
1775  } else {
1776  print img_error($langs->trans('FirstAddRessourceToAllocateTime')).$langs->trans('FirstAddRessourceToAllocateTime');
1777  }
1778  } else {
1779  $userstatic->id = $task_time->fk_user;
1780  $userstatic->lastname = $task_time->lastname;
1781  $userstatic->firstname = $task_time->firstname;
1782  $userstatic->photo = $task_time->photo;
1783  $userstatic->statut = $task_time->user_status;
1784  print $userstatic->getNomUrl(-1);
1785  }
1786  print '</td>';
1787  if (!$i) {
1788  $totalarray['nbfield']++;
1789  }
1790  }
1791 
1792  // Note
1793  if (!empty($arrayfields['t.note']['checked'])) {
1794  print '<td class="small">';
1795  if ($action == 'editline' && GETPOST('lineid', 'int') == $task_time->rowid) {
1796  print '<textarea name="timespent_note_line" width="95%" rows="'.ROWS_1.'">'.dol_escape_htmltag($task_time->note, 0, 1).'</textarea>';
1797  } else {
1798  print dol_nl2br($task_time->note);
1799  }
1800  print '</td>';
1801  if (!$i) {
1802  $totalarray['nbfield']++;
1803  }
1804  } elseif ($action == 'editline' && GETPOST('lineid', 'int') == $task_time->rowid) {
1805  print '<input type="hidden" name="timespent_note_line" value="'.dol_escape_htmltag($task_time->note, 0, 1).'">';
1806  }
1807 
1808  // Time spent
1809  if (!empty($arrayfields['t.task_duration']['checked'])) {
1810  print '<td class="right nowraponall">';
1811  if ($action == 'editline' && GETPOST('lineid', 'int') == $task_time->rowid) {
1812  print '<input type="hidden" name="old_duration" value="'.$task_time->task_duration.'">';
1813  print $form->select_duration('new_duration', $task_time->task_duration, 0, 'text');
1814  } else {
1815  print convertSecondToTime($task_time->task_duration, 'allhourmin');
1816  }
1817  print '</td>';
1818  if (!$i) {
1819  $totalarray['nbfield']++;
1820  }
1821  if (!$i) {
1822  $totalarray['pos'][$totalarray['nbfield']] = 't.task_duration';
1823  }
1824  $totalarray['val']['t.task_duration'] += $task_time->task_duration;
1825  if (!$i) {
1826  $totalarray['totaldurationfield'] = $totalarray['nbfield'];
1827  }
1828  $totalarray['totalduration'] += $task_time->task_duration;
1829  }
1830 
1831  // Value spent
1832  if (!empty($arrayfields['value']['checked'])) {
1833  $langs->load("salaries");
1834  $value = price2num($task_time->thm * $task_time->task_duration / 3600, 'MT', 1);
1835 
1836  print '<td class="nowraponall right">';
1837  print '<span class="amount" title="'.$langs->trans("THM").': '.price($task_time->thm).'">';
1838  print price($value, 1, $langs, 1, -1, -1, $conf->currency);
1839  print '</span>';
1840  print '</td>';
1841  if (!$i) {
1842  $totalarray['nbfield']++;
1843  }
1844  if (!$i) {
1845  $totalarray['pos'][$totalarray['nbfield']] = 'value';
1846  }
1847  $totalarray['val']['value'] += $value;
1848  if (!$i) {
1849  $totalarray['totalvaluefield'] = $totalarray['nbfield'];
1850  }
1851  $totalarray['totalvalue'] += $value;
1852  }
1853 
1854  // Invoiced
1855  if (!empty($arrayfields['valuebilled']['checked'])) {
1856  print '<td class="center">'; // invoice_id and invoice_line_id
1857  if (empty($conf->global->PROJECT_HIDE_TASKS) && !empty($conf->global->PROJECT_BILL_TIME_SPENT)) {
1858  if ($projectstatic->usage_bill_time) {
1859  if ($task_time->invoice_id) {
1860  $result = $tmpinvoice->fetch($task_time->invoice_id);
1861  if ($result > 0) {
1862  print $tmpinvoice->getNomUrl(1);
1863  }
1864  } else {
1865  print $langs->trans("No");
1866  }
1867  } else {
1868  print '<span class="opacitymedium">'.$langs->trans("NA").'</span>';
1869  }
1870  }
1871  print '</td>';
1872  if (!$i) {
1873  $totalarray['nbfield']++;
1874  }
1875  }
1876 
1877  /*
1878  // Extra fields
1879  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1880  */
1881 
1882  // Fields from hook
1883  $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$task_time, 'i'=>$i, 'totalarray'=>&$totalarray);
1884  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
1885  print $hookmanager->resPrint;
1886 
1887  // Action column
1888  print '<td class="center nowraponall">';
1889  if (($action == 'editline' || $action == 'splitline') && GETPOST('lineid', 'int') == $task_time->rowid) {
1890  print '<input type="hidden" name="lineid" value="'.GETPOST('lineid', 'int').'">';
1891  print '<input type="submit" class="button buttongen margintoponlyshort marginbottomonlyshort button-save" name="save" value="'.$langs->trans("Save").'">';
1892  print ' ';
1893  print '<input type="submit" class="button buttongen margintoponlyshort marginbottomonlyshort button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
1894  } elseif ($user->hasRight('projet', 'time') || $user->hasRight('projet', 'all', 'creer')) { // Read project and enter time consumed on assigned tasks
1895  if ($task_time->fk_user == $user->id || in_array($task_time->fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) {
1896  if (getDolGlobalString('MAIN_FEATURES_LEVEL') >= 2) {
1897  print '&nbsp;';
1898  print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=splitline&token='.newToken().'&lineid='.$task_time->rowid.$param.((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '').'">';
1899  print img_split('', 'class="pictofixedwidth"');
1900  print '</a>';
1901  }
1902 
1903  print '<a class="reposition editfielda" href="'.$_SERVER["PHP_SELF"].'?id='.$task_time->fk_task.'&action=editline&token='.newToken().'&lineid='.$task_time->rowid.$param.((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '').'">';
1904  print img_edit('default', 0, 'class="pictofixedwidth paddingleft"');
1905  print '</a>';
1906 
1907  print '<a class="reposition paddingleft" href="'.$_SERVER["PHP_SELF"].'?id='.$task_time->fk_task.'&action=deleteline&token='.newToken().'&lineid='.$task_time->rowid.$param.((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '').'">';
1908  print img_delete('default', 'class="pictodelete paddingleft"');
1909  print '</a>';
1910 
1911  if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1912  $selected = 0;
1913  if (in_array($task_time->rowid, $arrayofselected)) {
1914  $selected = 1;
1915  }
1916  print '&nbsp;';
1917  print '<input id="cb'.$task_time->rowid.'" class="flat checkforselect marginleftonly" type="checkbox" name="toselect[]" value="'.$task_time->rowid.'"'.($selected ? ' checked="checked"' : '').'>';
1918  }
1919  }
1920  }
1921  print '</td>';
1922  if (!$i) {
1923  $totalarray['nbfield']++;
1924  }
1925 
1926  print "</tr>\n";
1927 
1928 
1929  // Add line to split
1930 
1931  if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
1932  print '<tr class="oddeven">';
1933 
1934  // Date
1935  if (!empty($arrayfields['t.task_date']['checked'])) {
1936  print '<td class="nowrap">';
1937  if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
1938  if (empty($task_time->task_date_withhour)) {
1939  print $form->selectDate(($date2 ? $date2 : $date1), 'timeline', 3, 3, 2, "timespent_date", 1, 0);
1940  } else {
1941  print $form->selectDate(($date2 ? $date2 : $date1), 'timeline', 1, 1, 2, "timespent_date", 1, 0);
1942  }
1943  } else {
1944  print dol_print_date(($date2 ? $date2 : $date1), ($task_time->task_date_withhour ? 'dayhour' : 'day'));
1945  }
1946  print '</td>';
1947  }
1948 
1949  // Project ref
1950  if (!empty($allprojectforuser)) {
1951  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
1952  print '<td class="nowrap">';
1953  print '</td>';
1954  }
1955  }
1956 
1957  // Task ref
1958  if (!empty($arrayfields['t.task_ref']['checked'])) {
1959  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
1960  print '<td class="nowrap">';
1961  $tasktmp->id = $task_time->fk_task;
1962  $tasktmp->ref = $task_time->ref;
1963  $tasktmp->label = $task_time->label;
1964  print $tasktmp->getNomUrl(1, 'withproject', 'time');
1965  print '</td>';
1966  }
1967  }
1968 
1969  // Task label
1970  if (!empty($arrayfields['t.task_label']['checked'])) {
1971  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
1972  print '<td class="tdoverflowmax300" title="'.dol_escape_htmltag($task_time->label).'">';
1973  print dol_escape_htmltag($task_time->label);
1974  print '</td>';
1975  }
1976  }
1977 
1978  // User
1979  if (!empty($arrayfields['author']['checked'])) {
1980  print '<td>';
1981  if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
1982  if (empty($object->id)) {
1983  $object->fetch($id);
1984  }
1985  $contactsoftask = $object->getListContactId('internal');
1986  if (!in_array($task_time->fk_user, $contactsoftask)) {
1987  $contactsoftask[] = $task_time->fk_user;
1988  }
1989  if (count($contactsoftask) > 0) {
1990  print img_object('', 'user', 'class="hideonsmartphone"');
1991  print $form->select_dolusers($task_time->fk_user, 'userid_line', 0, '', 0, '', $contactsoftask);
1992  } else {
1993  print img_error($langs->trans('FirstAddRessourceToAllocateTime')).$langs->trans('FirstAddRessourceToAllocateTime');
1994  }
1995  } else {
1996  $userstatic->id = $task_time->fk_user;
1997  $userstatic->lastname = $task_time->lastname;
1998  $userstatic->firstname = $task_time->firstname;
1999  $userstatic->photo = $task_time->photo;
2000  $userstatic->statut = $task_time->user_status;
2001  print $userstatic->getNomUrl(-1);
2002  }
2003  print '</td>';
2004  }
2005 
2006  // Note
2007  if (!empty($arrayfields['t.note']['checked'])) {
2008  print '<td class="tdoverflowmax300">';
2009  if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
2010  print '<textarea name="timespent_note_line" width="95%" rows="'.ROWS_1.'">'.dol_escape_htmltag($task_time->note, 0, 1).'</textarea>';
2011  } else {
2012  print dol_nl2br($task_time->note);
2013  }
2014  print '</td>';
2015  } elseif ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
2016  print '<input type="hidden" name="timespent_note_line" rows="'.ROWS_1.'" value="'.dol_escape_htmltag($task_time->note, 0, 1).'">';
2017  }
2018 
2019  // Time spent
2020  if (!empty($arrayfields['t.task_duration']['checked'])) {
2021  print '<td class="right">';
2022  if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
2023  print '<input type="hidden" name="old_duration" value="'.$task_time->task_duration.'">';
2024  print $form->select_duration('new_duration', $task_time->task_duration, 0, 'text');
2025  } else {
2026  print convertSecondToTime($task_time->task_duration, 'allhourmin');
2027  }
2028  print '</td>';
2029  }
2030 
2031  // Value spent
2032  if (!empty($arrayfields['value']['checked'])) {
2033  print '<td class="right">';
2034  print '<span class="amount">';
2035  $value = price2num($task_time->thm * $task_time->task_duration / 3600, 'MT', 1);
2036  print price($value, 1, $langs, 1, -1, -1, $conf->currency);
2037  print '</span>';
2038  print '</td>';
2039  }
2040 
2041  // Value billed
2042  if (!empty($arrayfields['valuebilled']['checked'])) {
2043  print '<td class="right">';
2044  $valuebilled = price2num($task_time->total_ht, '', 1);
2045  if (isset($task_time->total_ht)) {
2046  print price($valuebilled, 1, $langs, 1, -1, -1, $conf->currency);
2047  }
2048  print '</td>';
2049  }
2050 
2051  /*
2052  // Extra fields
2053  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
2054  */
2055 
2056  // Fields from hook
2057  $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$task_time, 'mode' => 'split1');
2058  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
2059  print $hookmanager->resPrint;
2060 
2061  // Action column
2062  print '<td class="center nowraponall">';
2063  print '</td>';
2064 
2065  print "</tr>\n";
2066 
2067 
2068  // Line for second dispatching
2069 
2070  print '<tr class="oddeven">';
2071 
2072  // Date
2073  if (!empty($arrayfields['t.task_date']['checked'])) {
2074  print '<td class="nowrap">';
2075  if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
2076  if (empty($task_time->task_date_withhour)) {
2077  print $form->selectDate(($date2 ? $date2 : $date1), 'timeline_2', 3, 3, 2, "timespent_date", 1, 0);
2078  } else {
2079  print $form->selectDate(($date2 ? $date2 : $date1), 'timeline_2', 1, 1, 2, "timespent_date", 1, 0);
2080  }
2081  } else {
2082  print dol_print_date(($date2 ? $date2 : $date1), ($task_time->task_date_withhour ? 'dayhour' : 'day'));
2083  }
2084  print '</td>';
2085  }
2086 
2087  // Project ref
2088  if (!empty($allprojectforuser)) {
2089  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2090  print '<td class="nowrap">';
2091  print '</td>';
2092  }
2093  }
2094 
2095  // Task ref
2096  if (!empty($arrayfields['t.task_ref']['checked'])) {
2097  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2098  print '<td class="nowrap">';
2099  $tasktmp->id = $task_time->fk_task;
2100  $tasktmp->ref = $task_time->ref;
2101  $tasktmp->label = $task_time->label;
2102  print $tasktmp->getNomUrl(1, 'withproject', 'time');
2103  print '</td>';
2104  }
2105  }
2106 
2107  // Task label
2108  if (!empty($arrayfields['t.task_label']['checked'])) {
2109  if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2110  print '<td class="nowrap">';
2111  print $task_time->label;
2112  print '</td>';
2113  }
2114  }
2115 
2116  // User
2117  if (!empty($arrayfields['author']['checked'])) {
2118  print '<td>';
2119  if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
2120  if (empty($object->id)) {
2121  $object->fetch($id);
2122  }
2123  $contactsoftask = $object->getListContactId('internal');
2124  if (!in_array($task_time->fk_user, $contactsoftask)) {
2125  $contactsoftask[] = $task_time->fk_user;
2126  }
2127  if (count($contactsoftask) > 0) {
2128  print img_object('', 'user', 'class="hideonsmartphone"');
2129  print $form->select_dolusers($task_time->fk_user, 'userid_line_2', 0, '', 0, '', $contactsoftask);
2130  } else {
2131  print img_error($langs->trans('FirstAddRessourceToAllocateTime')).$langs->trans('FirstAddRessourceToAllocateTime');
2132  }
2133  } else {
2134  $userstatic->id = $task_time->fk_user;
2135  $userstatic->lastname = $task_time->lastname;
2136  $userstatic->firstname = $task_time->firstname;
2137  $userstatic->photo = $task_time->photo;
2138  $userstatic->statut = $task_time->user_status;
2139  print $userstatic->getNomUrl(-1);
2140  }
2141  print '</td>';
2142  }
2143 
2144  // Note
2145  if (!empty($arrayfields['t.note']['checked'])) {
2146  print '<td class="small tdoverflowmax300"">';
2147  if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
2148  print '<textarea name="timespent_note_line_2" width="95%" rows="'.ROWS_1.'">'.dol_escape_htmltag($task_time->note, 0, 1).'</textarea>';
2149  } else {
2150  print dol_nl2br($task_time->note);
2151  }
2152  print '</td>';
2153  } elseif ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
2154  print '<input type="hidden" name="timespent_note_line_2" value="'.dol_escape_htmltag($task_time->note, 0, 1).'">';
2155  }
2156 
2157  // Time spent
2158  if (!empty($arrayfields['t.task_duration']['checked'])) {
2159  print '<td class="right">';
2160  if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) {
2161  print '<input type="hidden" name="old_duration_2" value="0">';
2162  print $form->select_duration('new_duration_2', 0, 0, 'text');
2163  } else {
2164  print convertSecondToTime($task_time->task_duration, 'allhourmin');
2165  }
2166  print '</td>';
2167  }
2168 
2169  // Value spent
2170  if (!empty($arrayfields['value']['checked'])) {
2171  print '<td class="right">';
2172  print '<span class="amount">';
2173  $value = 0;
2174  print price($value, 1, $langs, 1, -1, -1, $conf->currency);
2175  print '</span>';
2176  print '</td>';
2177  }
2178 
2179  // Value billed
2180  if (!empty($arrayfields['valuebilled']['checked'])) {
2181  print '<td class="right">';
2182  $valuebilled = price2num($task_time->total_ht, '', 1);
2183  if (isset($task_time->total_ht)) {
2184  print '<span class="amount">';
2185  print price($valuebilled, 1, $langs, 1, -1, -1, $conf->currency);
2186  print '</span>';
2187  }
2188  print '</td>';
2189  }
2190 
2191  /*
2192  // Extra fields
2193  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
2194  */
2195 
2196  // Fields from hook
2197  $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$task_time, 'mode' => 'split2');
2198  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
2199  print $hookmanager->resPrint;
2200 
2201  // Action column
2202  print '<td class="center nowraponall">';
2203  print '</td>';
2204 
2205  print "</tr>\n";
2206  }
2207 
2208  $i++;
2209  }
2210 
2211  // Show total line
2212  //include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php';
2213  if (isset($totalarray['totaldurationfield']) || isset($totalarray['totalvaluefield'])) {
2214  print '<tr class="liste_total">';
2215  $i = 0;
2216  while ($i < $totalarray['nbfield']) {
2217  $i++;
2218  if ($i == 1) {
2219  if ($num < $limit && empty($offset)) {
2220  print '<td class="left">'.$langs->trans("Total").'</td>';
2221  } else {
2222  print '<td class="left">'.$langs->trans("Totalforthispage").'</td>';
2223  }
2224  } elseif ($totalarray['totaldurationfield'] == $i) {
2225  print '<td class="right">'.convertSecondToTime($totalarray['totalduration'], 'allhourmin').'</td>';
2226  } elseif ($totalarray['totalvaluefield'] == $i) {
2227  print '<td class="right">'.price($totalarray['totalvalue']).'</td>';
2228  //} elseif ($totalarray['totalvaluebilledfield'] == $i) { print '<td class="center">'.price($totalarray['totalvaluebilled']).'</td>';
2229  } else {
2230  print '<td></td>';
2231  }
2232  }
2233  print '</tr>';
2234  }
2235 
2236  if (!count($tasks)) {
2237  $totalnboffields = 1;
2238  foreach ($arrayfields as $value) {
2239  if ($value['checked']) {
2240  $totalnboffields++;
2241  }
2242  }
2243  print '<tr class="oddeven"><td colspan="'.$totalnboffields.'">';
2244  print '<span class="opacitymedium">'.$langs->trans("None").'</span>';
2245  print '</td></tr>';
2246  }
2247 
2248  $parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql);
2249  $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook
2250  print $hookmanager->resPrint;
2251 
2252  print "</table>";
2253  print '</div>';
2254  print "</form>";
2255  }
2256 }
2257 
2258 // End of page
2259 llxFooter();
2260 $db->close();
dolSqlDateFilter($datefield, $day_date, $month_date, $year_date, $excludefirstand=0, $gm=false)
Generate a SQL string to make a filter into a range (for second of date until last second of date)...
Definition: date.lib.php:334
project_prepare_head(Project $project, $moreparam= '')
Prepare array with list of tabs.
Definition: project.lib.php:38
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
img_edit($titlealt= 'default', $float=0, $other= '')
Show logo editer/modifier fiche.
if($cancel &&!$id) if($action== 'add'&&!$cancel) if($action== 'delete') if($id) $form
Actions.
Definition: card.php:142
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...
dolGetButtonTitle($label, $helpText= '', $iconClass= 'fa fa-file', $url= '', $id= '', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
Class to manage generation of HTML components for contract module.
Class to manage products or services.
Class to manage interventions.
Class to manage Dolibarr users.
Definition: user.class.php:44
if(!function_exists('utf8_encode')) if(!function_exists('utf8_decode')) getDolGlobalString($key, $default= '')
Return dolibarr global constant string value.
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOCSRFCHECK')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:59
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags= '', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...
img_warning($titlealt= 'default', $moreatt= '', $morecss= 'pictowarning')
Show warning logo.
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...
Class to manage standard extra fields.
setEventMessages($mesg, $mesgs, $style= 'mesgs', $messagekey= '')
Set event messages in dol_events session object.
img_error($titlealt= 'default')
Show error logo.
print_barre_liste($titre, $page, $file, $options= '', $sortfield= '', $sortorder= '', $morehtmlcenter= '', $num=-1, $totalnboflines= '', $picto= 'generic', $pictoisfullpath=0, $morehtmlright= '', $morecss= '', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow= '')
Print a title with navigation controls for pagination.
Class to manage generation of HTML components Only common components must be here.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form...
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod=0)
Function that return localtax of a product line (according to seller, buyer and product vat rate) Si ...
Class to manage projects.
price2num($amount, $rounding= '', $option=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
Class to manage building of HTML components.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt= '', $morecss= '', $marginleftonlyshort=2)
Show picto whatever it&#39;s its name (generic function)
Classe permettant la generation de composants html autre Only common components are here...
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
accessforbidden($message= '', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program Calling this function terminate execution ...
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...
restrictedArea($user, $features, $objectid=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.
if(isModEnabled('facture')&&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur')&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)&&$user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice')&&$user->rights->supplier_invoice->lire)) if(isModEnabled('don')&&!empty($user->rights->don->lire)) if(isModEnabled('tax')&&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture')&&isModEnabled('commande')&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
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...
dol_get_fiche_head($links=array(), $active= '', $title= '', $notab=0, $picto= '', $pictoisfullpath=0, $morehtmlright= '', $morecss= '', $limittoshow=0, $moretabssuffix= '')
Show tabs of a record.
Class to manage tasks.
Definition: task.class.php:37
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_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
newToken()
Return the value of token currently saved into session with name &#39;newtoken&#39;.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
isModEnabled($module)
Is Dolibarr module enabled.
Class to manage invoices.
dol_banner_tab($object, $paramid, $morehtml= '', $shownav=1, $fieldid= 'rowid', $fieldref= 'ref', $morehtmlref= '', $moreparam= '', $nodbprefix=0, $morehtmlleft= '', $morehtmlstatus= '', $onlybanner=0, $morehtmlright= '')
Show tab footer of a card.
llxFooter()
Empty footer.
Definition: wrapper.php:73
img_delete($titlealt= 'default', $other= 'class="pictodelete"', $morecss= '')
Show delete logo.
img_split($titlealt= 'default', $other= 'class="pictosplit"')
Show split logo.
$formconfirm
if ($action == &#39;delbookkeepingyear&#39;) {
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:236
task_prepare_head($object)
Prepare array with list of tabs.