dolibarr 25.0.0-alpha
time.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2006-2023 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-2025 Frédéric France <frederic.france@free.fr>
8 * Copyright (C) 2019-2021 Christophe Battarel <christophe@altairis.fr>
9 * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
10 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
11 * Copyright (C) 2024 Vincent de Grandpré <vincent@de-grandpre.quebec>
12 * Copyright (C) 2024 Solution Libre SAS <contact@solution-libre.fr>
13 * Copyright (C) 2026 Joachim Kueter <git-jk@bloxera.com>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 3 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <https://www.gnu.org/licenses/>.
27 */
28
35// Load Dolibarr environment
36require '../../main.inc.php';
45'
46@phan-var-force ?string $uploaddir
47';
48require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
49require_once DOL_DOCUMENT_ROOT . '/projet/class/task.class.php';
50require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
51require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
52require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
53require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
54require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
55require_once DOL_DOCUMENT_ROOT . '/core/class/html.formintervention.class.php';
56require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
57
58// Load translation files required by the page
59$langsLoad = array('projects', 'bills', 'orders', 'companies');
60if (isModEnabled('eventorganization')) {
61 $langsLoad[] = 'eventorganization';
62}
63
64$langs->loadLangs($langsLoad);
65
66$action = GETPOST('action', 'aZ09');
67$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists)
68$confirm = GETPOST('confirm', 'alpha');
69$cancel = GETPOST('cancel', 'alpha');
70$toselect = GETPOST('toselect', 'array:int'); // Array of ids of elements selected into a list
71$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'timespentlist'; // To manage different context of search
72$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page
73$optioncss = GETPOST('optioncss', 'alpha');
74$mode = GETPOST('mode', 'alpha');
75
76$id = GETPOSTINT('id'); // Id of task
77$ref = GETPOST('ref', 'alpha'); // Ref of task
78$projectid = GETPOSTINT('projectid'); // Id of project
79$lineid = GETPOSTINT('lineid'); // Id of time spent line
80$withproject = GETPOSTINT('withproject');
81$project_ref = GETPOST('project_ref', 'alpha');
82$tab = GETPOST('tab', 'aZ09');
83
84$search_day = GETPOSTINT('search_day');
85$search_month = GETPOSTINT('search_month');
86$search_year = GETPOSTINT('search_year');
87$search_date_startday = GETPOSTINT('search_date_startday');
88$search_date_startmonth = GETPOSTINT('search_date_startmonth');
89$search_date_startyear = GETPOSTINT('search_date_startyear');
90$search_date_endday = GETPOSTINT('search_date_endday');
91$search_date_endmonth = GETPOSTINT('search_date_endmonth');
92$search_date_endyear = GETPOSTINT('search_date_endyear');
93$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear); // Use tzserver
94$search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear);
95$search_note = GETPOST('search_note', 'alpha');
96$search_duration = GETPOST('search_duration', 'alpha');
97$search_task_ref = GETPOST('search_task_ref', 'alpha');
98$search_task_label = GETPOST('search_task_label', 'alpha');
99$search_user = GETPOST('search_user', 'intcomma');
100$search_valuebilled = GETPOST('search_valuebilled', 'intcomma');
101$search_product_ref = GETPOST('search_product_ref', 'alpha');
102$search_company = GETPOST('$search_company', 'alpha');
103$search_company_alias = GETPOST('$search_company_alias', 'alpha');
104$search_project_ref = GETPOST('$search_project_ref', 'alpha');
105$search_project_label = GETPOST('$search_project_label', 'alpha');
106$search_timespent_starthour = GETPOSTINT("search_timespent_duration_starthour");
107$search_timespent_startmin = GETPOSTINT("search_timespent_duration_startmin");
108$search_timespent_endhour = GETPOSTINT("search_timespent_duration_endhour");
109$search_timespent_endmin = GETPOSTINT("search_timespent_duration_endmin");
110
111$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
112$sortfield = GETPOST('sortfield', 'aZ09comma');
113$sortorder = GETPOST('sortorder', 'aZ09comma');
114$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
115if (empty($page) || $page == -1) {
116 $page = 0;
117} // If $page is not defined, or '' or -1
118$offset = $limit * $page;
119$pageprev = $page - 1;
120$pagenext = $page + 1;
121if (!$sortfield) {
122 $sortfield = 't.element_date,t.element_datehour,t.rowid';
123}
124if (!$sortorder) {
125 $sortorder = 'DESC,DESC,DESC';
126}
127
128$childids = $user->getAllChildIds(1);
129
130// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
131//$object = new TaskTime($db);
132$hookmanager->initHooks(array('projecttasktime', 'globalcard'));
133
134$object = new Task($db);
135$extrafields = new ExtraFields($db);
136$projectstatic = new Project($db);
137
138// fetch optionals attributes and labels
139$extrafields->fetch_name_optionals_label($projectstatic->table_element);
140$extrafields->fetch_name_optionals_label($object->table_element);
141
142$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
143
144// Load task
145if ($id > 0 || $ref) {
146 $object->fetch($id, $ref);
147 $id = $object->id; // So when doing a search from ref, id is also set correctly.
148}
149
150
151// Security check
152$socid = 0;
153//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 assignment.
154if (!$user->hasRight('projet', 'lire')) {
156}
157
158if ($object->fk_project > 0) {
159 restrictedArea($user, 'projet', $object->fk_project, 'projet&project');
160} else {
161 restrictedArea($user, 'projet', 0, 'projet&project');
162 // We check user has permission to see all tasks of all users
163 if (empty($projectid) && !$user->hasRight('projet', 'all', 'lire')) {
164 $search_user = $user->id;
165 }
166}
167
168
169/*
170 * Actions
171 */
172
173$error = 0;
174
175if (GETPOST('cancel', 'alpha')) {
176 $action = '';
177}
178if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend' && $massaction != 'confirm_generateinvoice' && $massaction != 'confirm_generateinter') {
179 $massaction = '';
180}
181
182$parameters = array('socid' => $socid, 'projectid' => $projectid);
183$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
184if ($reshook < 0) {
185 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
186}
187
188include DOL_DOCUMENT_ROOT . '/core/actions_changeselectedfields.inc.php';
189
190// Purge search criteria
191if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
192 $search_day = '';
193 $search_month = '';
194 $search_year = '';
195 $search_note = '';
196 $search_duration = '';
197 $search_date_startday = '';
198 $search_date_startmonth = '';
199 $search_date_startyear = '';
200 $search_date_endday = '';
201 $search_date_endmonth = '';
202 $search_date_endyear = '';
203 $search_date_start = '';
204 $search_date_end = '';
205 $search_task_ref = '';
206 $search_company = '';
207 $search_company_alias = '';
208 $search_project_ref = '';
209 $search_project_label = '';
210 $search_task_label = '';
211 $search_user = -1;
212 $search_valuebilled = '';
213 $search_product_ref = '';
214 $toselect = array();
215 $search_array_options = array();
216 $search_timespent_starthour = '';
217 $search_timespent_startmin = '';
218 $search_timespent_endhour = '';
219 $search_timespent_endmin = '';
220 $action = '';
221}
222
223if ($action == 'addtimespent' && $user->hasRight('projet', 'time')) {
224 $timespent_durationhour = GETPOSTINT('timespent_durationhour');
225 $timespent_durationmin = GETPOSTINT('timespent_durationmin');
226 if (empty($timespent_durationhour) && empty($timespent_durationmin)) {
227 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Duration")), null, 'errors');
228 $error++;
229 }
230 if (!GETPOSTINT("userid")) {
231 $langs->load("errors");
232 setEventMessages($langs->trans('ErrorUserNotAssignedToTask'), null, 'errors');
233 $error++;
234 }
235
236 if (!$error) {
237 if ($id || $ref) {
238 $object->fetch($id, $ref);
239 } else {
240 if (!GETPOSTINT('taskid') || GETPOSTINT('taskid') < 0) {
241 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Task")), null, 'errors');
242 $action = 'createtime';
243 $error++;
244 } else {
245 $object->fetch(GETPOSTINT('taskid'));
246 }
247 }
248
249 if (!$error) {
250 $object->fetchProject();
251
252 if (empty($object->project->status)) {
253 setEventMessages($langs->trans("ProjectMustBeValidatedFirst"), null, 'errors');
254 $action = 'createtime';
255 $error++;
256 } else {
257 $object->timespent_note = GETPOST("timespent_note", 'alpha');
258 if (GETPOSTINT('progress') > 0) {
259 $object->progress = GETPOSTINT('progress'); // If progress is -1 (not defined), we do not change value
260 }
261 $object->timespent_duration = GETPOSTINT("timespent_durationhour") * 60 * 60; // We store duration in seconds
262 $object->timespent_duration += (GETPOSTINT('timespent_durationmin') ? GETPOSTINT('timespent_durationmin') : 0) * 60; // We store duration in seconds
263 if (GETPOST("timehour") != '' && GETPOST("timehour") >= 0) { // If hour was entered
264 $object->timespent_date = dol_mktime(GETPOSTINT("timehour"), GETPOSTINT("timemin"), 0, GETPOSTINT("timemonth"), GETPOSTINT("timeday"), GETPOSTINT("timeyear"));
265 $object->timespent_withhour = 1;
266 } else {
267 $object->timespent_date = dol_mktime(12, 0, 0, GETPOSTINT("timemonth"), GETPOSTINT("timeday"), GETPOSTINT("timeyear"));
268 $object->timespent_withhour = 0;
269 }
270 $object->timespent_fk_user = GETPOSTINT("userid");
271 $object->timespent_fk_product = GETPOSTINT("fk_product");
272
273 $result = $object->addTimeSpent($user);
274
275 if ($result >= 0) {
276 setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
277 } else {
278 setEventMessages($langs->trans($object->error), null, 'errors');
279 $error++;
280 }
281 }
282 }
283 } else {
284 $action = 'createtime';
285 }
286}
287
288if (($action == 'updateline' || $action == 'updatesplitline') && !$cancel && $user->hasRight('projet', 'lire')) {
289 if (!GETPOST("new_durationhour") && !GETPOST("new_durationmin")) {
290 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Duration")), null, 'errors');
291 $error++;
292 }
293
294 //If timespent date is not provided in POST (for eg, because in list the column date is hidden) we keep the actual date
295 $timespent_date = dol_mktime(12, 0, 0, GETPOSTINT("timelinemonth"), GETPOSTINT("timelineday"), GETPOSTINT("timelineyear"));
296
297 if (!$error) {
298 if ($id && GETPOSTINT('taskid') != $id) { // GETPOSTINT('taskid') is the id of new task
299 $id_temp = GETPOSTINT('taskid'); // should not overwrite $id
300
301 $object->fetchTimeSpent($lineid);
302
303 $result = 0;
304
305 $object->fetch($id_temp, $ref);
306
307 $object->timespent_note = GETPOST("timespent_note_line", "alphanohtml");
308 $object->timespent_old_duration = GETPOSTINT("old_duration");
309 $object->timespent_duration = GETPOSTINT("new_durationhour") * 60 * 60; // We store duration in seconds
310 $object->timespent_duration += (GETPOSTINT("new_durationmin") ? GETPOSTINT('new_durationmin') : 0) * 60; // We store duration in seconds
311 if (GETPOST("timelinehour") != '' && GETPOST("timelinehour") >= 0 && !empty($timespent_date)) { // If hour was entered
312 $object->timespent_date = dol_mktime(GETPOSTINT("timelinehour"), GETPOSTINT("timelinemin"), 0, GETPOSTINT("timelinemonth"), GETPOSTINT("timelineday"), GETPOSTINT("timelineyear"));
313 $object->timespent_withhour = 1;
314 } elseif (!empty($timespent_date)) {
315 $object->timespent_date = $timespent_date;
316 $object->timespent_withhour = 0;
317 }
318 // If column "by" is hidden, no userid_line is posted; keep the existing fk_user instead of resetting it to 0.
319 if (GETPOSTISSET("userid_line")) {
320 $object->timespent_fk_user = GETPOSTINT("userid_line");
321 }
322 $object->timespent_fk_product = GETPOSTINT("fk_product");
323 $object->timespent_invoiceid = GETPOSTINT("invoiceid");
324 $object->timespent_invoicelineid = GETPOSTINT("invoicelineid");
325
326 $result = 0;
327 if (in_array($object->timespent_fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) {
328 $result = $object->updateTimeSpent($user);
329 if ($result >= 0) {
330 setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
331 } else {
332 setEventMessages($langs->trans($object->error), null, 'errors');
333 $error++;
334 }
335 }
336 } else {
337 $object->fetch($id, $ref); // $object is Task
338
339 $object->fetchTimeSpent(GETPOSTINT('lineid'));
340
341 $object->timespent_note = GETPOST("timespent_note_line", "alphanohtml");
342 $object->timespent_old_duration = GETPOSTINT("old_duration");
343 $object->timespent_duration = GETPOSTINT("new_durationhour") * 60 * 60; // We store duration in seconds
344 $object->timespent_duration += (GETPOSTINT("new_durationmin") ? GETPOSTINT('new_durationmin') : 0) * 60; // We store duration in seconds
345
346 if (GETPOST("timelinehour") != '' && GETPOST("timelinehour") >= 0) { // If hour was entered
347 $object->timespent_date = dol_mktime(12, 0, 0, GETPOSTINT("timelinemonth"), GETPOSTINT("timelineday"), GETPOSTINT("timelineyear"));
348 $object->timespent_datehour = dol_mktime(GETPOSTINT("timelinehour"), GETPOSTINT("timelinemin"), 0, GETPOSTINT("timelinemonth"), GETPOSTINT("timelineday"), GETPOSTINT("timelineyear"));
349 $object->timespent_withhour = 1;
350 } elseif (!empty($timespent_date)) {
351 $object->timespent_date = $timespent_date;
352 $object->timespent_datehour = $timespent_date;
353 $object->timespent_withhour = 0;
354 }
355
356 // If column "by" is hidden, no userid_line is posted; keep the existing fk_user instead of resetting it to 0.
357 if (GETPOSTISSET("userid_line")) {
358 $object->timespent_fk_user = GETPOSTINT("userid_line");
359 }
360 $object->timespent_fk_product = GETPOSTINT("fk_product");
361 $object->timespent_invoiceid = GETPOSTINT("invoiceid");
362 $object->timespent_invoicelineid = GETPOSTINT("invoicelineid");
363
364 $result = 0;
365
366 if (in_array($object->timespent_fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) {
367 $result = $object->updateTimeSpent($user);
368
369 if ($result >= 0) {
370 setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
371 } else {
372 setEventMessages($langs->trans($object->error), null, 'errors');
373 $error++;
374 }
375 }
376 }
377 } else {
378 $action = '';
379 }
380}
381
382if ($action == 'confirm_deleteline' && $confirm == "yes" && ($user->hasRight('projet', 'time') || $user->hasRight('projet', 'all', 'creer'))) {
383 $object->fetchTimeSpent(GETPOSTINT('lineid')); // load properties like $object->timespent_xxx
384
385 if (in_array($object->timespent_fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) {
386 $result = $object->delTimeSpent($user); // delete line with $object->timespent_id
387
388 if ($result < 0) {
389 $langs->load("errors");
390 setEventMessages($langs->trans($object->error), null, 'errors');
391 $error++;
392 $action = '';
393 } else {
394 setEventMessages($langs->trans("RecordDeleted"), null, 'mesgs');
395 }
396 }
397}
398
399// Retrieve First Task ID of Project if withproject is on to allow project prev next to work
400if (!empty($project_ref) && !empty($withproject)) {
401 if ($projectstatic->fetch(0, $project_ref) > 0) {
402 $tasksarray = $object->getTasksArray(null, null, $projectstatic->id, $socid, 0);
403 if (count($tasksarray) > 0) {
404 $id = $tasksarray[0]->id;
405 } else {
406 header("Location: " . DOL_URL_ROOT . '/projet/tasks.php?id=' . $projectstatic->id . ($withproject ? '&withproject=1' : '') . (empty($mode) ? '' : '&mode=' . $mode));
407 exit;
408 }
409 }
410}
411
412// To show all time lines for project
413$projectidforalltimes = 0;
414if (GETPOSTINT('projectid') > 0) {
415 $projectidforalltimes = GETPOSTINT('projectid');
416
417 $result = $projectstatic->fetch($projectidforalltimes);
418 if (!empty($projectstatic->socid)) {
419 $projectstatic->fetch_thirdparty();
420 }
421 $res = $projectstatic->fetch_optionals();
422
423 // Quick edit for project extrafields (pencil shown on the project summary of this page)
424 if ($action == 'update_extras' && $projectstatic->id > 0) { // Test on permission already done
425 $permissiontoeditextra = $user->hasRight('projet', 'creer');
426 if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$projectstatic->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
427 $permissiontoeditextra = dol_eval((string) $extrafields->attributes[$projectstatic->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
428 }
429
430 if ($permissiontoeditextra) {
431 $projectstatic->oldcopy = dol_clone($projectstatic, 2);
432
433 $attribute_name = GETPOST('attribute', 'aZ09');
434
435 // Fill array 'array_options' with data from update form
436 $ret = $extrafields->setOptionalsFromPost(null, $projectstatic, $attribute_name);
437 if ($ret < 0) {
438 $error++;
439 }
440
441 if (!$error) {
442 $result = $projectstatic->updateExtraField($attribute_name, 'PROJECT_MODIFY');
443 if ($result < 0) {
444 setEventMessages($projectstatic->error, $projectstatic->errors, 'errors');
445 $error++;
446 }
447 }
448 }
449
450 if ($error) {
451 $action = 'edit_extras';
452 }
453 }
454} elseif (GETPOST('project_ref', 'alpha')) {
455 $projectstatic->fetch(0, GETPOST('project_ref', 'alpha'));
456 $projectidforalltimes = $projectstatic->id;
457 $withproject = 1;
458} elseif ($id > 0) {
459 $object->fetch($id);
460 $result = $projectstatic->fetch($object->fk_project);
461}
462// If not task selected and no project selected
463$allprojectforuser = 0;
464
465if ($id <= 0 && $projectidforalltimes == 0) {
466 $allprojectforuser = $user->id;
467}
468
469if ($action == 'confirm_generateinvoice' && $user->hasRight('facture', 'creer')) {
470 if (!empty($projectstatic->socid)) {
471 $projectstatic->fetch_thirdparty();
472 }
473
474 if (!($projectstatic->thirdparty->id > 0)) {
475 setEventMessages($langs->trans("ThirdPartyRequiredToGenerateInvoice"), null, 'errors');
476 } else {
477 include_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
478 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
479 include_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
480
481 $tmpinvoice = new Facture($db);
482 $tmptimespent = new Task($db);
483 $tmpproduct = new Product($db);
484 $fuser = new User($db);
485 $remiseproject = price2num(GETPOST('remiseprojet', 'alphanohtml'));
486 $condidproject = GETPOSTINT('condidproject');
487
488 $db->begin();
489
490 $idprod = GETPOSTINT('productid');
491 $generateinvoicemode = GETPOST('generateinvoicemode', 'alphanohtml');
492 $invoiceToUse = GETPOSTINT('invoiceid');
493
494 $prodDurationHoursBase = 1.0;
495 $product_data_cache = array();
496 if ($idprod > 0) {
497 $result = $tmpproduct->fetch($idprod);
498 if ($result < 0) {
499 $error++;
500 setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
501 }
502
503 $prodDurationHoursBase = $tmpproduct->getProductDurationHours();
504 if ($prodDurationHoursBase < 0) {
505 $error++;
506 $langs->load("errors");
507 setEventMessages(null, $tmpproduct->errors, 'errors');
508 }
509
510 $dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
511
512 $pu_ht = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
513 $txtva = $dataforprice['tva_tx'];
514 $localtax1 = get_localtax($txtva, 1, $projectstatic->thirdparty);
515 $localtax2 = get_localtax($txtva, 2, $projectstatic->thirdparty);
516 } else {
517 $prodDurationHoursBase = 1;
518
519 $pu_ht = 0;
520 $txtva = get_default_tva($mysoc, $projectstatic->thirdparty);
521 $localtax1 = get_default_localtax($mysoc, $projectstatic->thirdparty, 1);
522 $localtax2 = get_default_localtax($mysoc, $projectstatic->thirdparty, 2);
523 }
524
525 $tmpinvoice->socid = $projectstatic->thirdparty->id;
526 $tmpinvoice->date = dol_mktime(GETPOSTINT('rehour'), GETPOSTINT('remin'), GETPOSTINT('resec'), GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
527 $tmpinvoice->fk_project = $projectstatic->id;
528 $tmpinvoice->cond_reglement_id = $condidproject;
529 $tmpinvoice->mode_reglement_id = $projectstatic->thirdparty->mode_reglement_id;
530 $tmpinvoice->fk_account = $projectstatic->thirdparty->fk_account;
531
532 if ($invoiceToUse) {
533 $tmpinvoice->fetch($invoiceToUse);
534 } else {
535 $result = $tmpinvoice->create($user);
536 if ($result <= 0) {
537 $error++;
538 setEventMessages($tmpinvoice->error, $tmpinvoice->errors, 'errors');
539 }
540 }
541
542 if (!$error) {
543 if ($generateinvoicemode == 'onelineperuser') { // 1 line per user (and per product)
544 $arrayoftasks = array();
545 foreach ($toselect as $key => $value) {
546 // Get userid, timepent
547 $object->fetchTimeSpent($value); // $value is ID of 1 line in timespent table
548 if (!array_key_exists($object->timespent_fk_user, $arrayoftasks)) {
549 $arrayoftasks[$object->timespent_fk_user] = [
550 (int) $object->timespent_fk_product => ['timespent' => 0, 'totalvaluetodivideby3600' => 0]
551 ];
552 }
553 $arrayoftasks[$object->timespent_fk_user][(int) $object->timespent_fk_product]['timespent'] += $object->timespent_duration;
554 $arrayoftasks[$object->timespent_fk_user][(int) $object->timespent_fk_product]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm);
555 }
556
557 foreach ($arrayoftasks as $userid => $data) { // @phan-suppress-current-line PhanEmptyForeach
558 $fuser->fetch($userid);
559 $username = $fuser->getFullName($langs);
560
561 foreach ($data as $fk_product => $timespent_data) {
562 // Define qty per hour
563 $qtyhour = $timespent_data['timespent'] / 3600;
564 $qtyhourtext = convertSecondToTime($timespent_data['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
565
566 // Set the unit price we want to sell the time, for this user
567 if (getDolGlobalInt('PROJECT_USE_REAL_COST_FOR_TIME_INVOICING')) {
568 // We set unit price to 0 to force the use of the rate saved during recording
569 $pu_ht = 0;
570 } elseif ($idprod <= 0) {
571 // We want to sell all the time spent with the last hourly rate of user
572 // -> but what about choice user selected ? add idprod test
573 $pu_ht = $fuser->thm;
574 }
575
576 // If no unit price known for user, we use the price recorded when recording timespent.
577 if (empty($pu_ht)) {
578 if ($timespent_data['timespent']) {
579 $pu_ht = price2num(($timespent_data['totalvaluetodivideby3600'] / $timespent_data['timespent']), 'MU');
580 }
581 }
582
583 // Add lines
584 $prodDurationHours = $prodDurationHoursBase;
585 $idprodline = $idprod;
586 $pu_htline = $pu_ht;
587 $txtvaline = $txtva;
588 $localtax1line = $localtax1;
589 $localtax2line = $localtax2;
590
591 // If a particular product/service was defined for the task
592 if (!empty($fk_product) && ($fk_product > 0) && ($fk_product !== $idprod)) {
593 if (!array_key_exists($fk_product, $product_data_cache)) {
594 $result = $tmpproduct->fetch($fk_product);
595 if ($result < 0) {
596 $error++;
597 setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
598 }
599 $prodDurationHours = $tmpproduct->getProductDurationHours();
600 if ($prodDurationHours < 0) {
601 $error++;
602 $langs->load("errors");
603 setEventMessages(null, $tmpproduct->errors, 'errors');
604 // Skip this entry: without it the loop reaches addline() and divides by the duration (#40805).
605 continue;
606 }
607
608 $dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
609
610 $pu_htline = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
611 $txtvaline = $dataforprice['tva_tx'];
612 $localtax1line = $dataforprice['localtax1'];
613 $localtax2line = $dataforprice['localtax2'];
614
615 $product_data_cache[$fk_product] = array('duration' => $prodDurationHours, 'dataforprice' => $dataforprice);
616 } else {
617 $prodDurationHours = $product_data_cache[$fk_product]['duration'];
618 $pu_htline = empty($product_data_cache[$fk_product]['dataforprice']['pu_ht']) ? 0 : $product_data_cache[$fk_product]['dataforprice']['pu_ht'];
619 $txtvaline = $product_data_cache[$fk_product]['dataforprice']['tva_tx'];
620 $localtax1line = $product_data_cache[$fk_product]['dataforprice']['localtax1'];
621 $localtax2line = $product_data_cache[$fk_product]['dataforprice']['localtax2'];
622 }
623 $idprodline = $fk_product;
624 }
625
626 // Add lines. Pass type=1 (service) explicitly so the invoice line is tagged
627 // as a service even when no product is bound to the time entry. Otherwise
628 // the default $type=0 leaks through and the PDF labels the operation as
629 // "Delivery of goods" instead of "Provision of services" (issue #34571).
630 $lineid = $tmpinvoice->addline($langs->trans("TimeSpentForInvoice").' - '.$username . ' : ' . $qtyhourtext, $pu_htline, round($qtyhour / $prodDurationHours, 2), $txtvaline, $localtax1line, $localtax2line, ($idprodline > 0 ? $idprodline : 0), (float) $remiseproject, '', '', 0, 0, 0, 'HT', 0, Product::TYPE_SERVICE);
631 if ($lineid < 0) {
632 $error++;
633 setEventMessages(null, $tmpinvoice->errors, 'errors');
634 }
635
636 // Update lineid into line of timespent
637 $sql = 'UPDATE '.MAIN_DB_PREFIX.'element_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
638 $sql .= ' WHERE rowid IN ('.$db->sanitize(implode(',', $toselect)).') AND fk_user = '.((int) $userid);
639 $result = $db->query($sql);
640 if (!$result) {
641 $error++;
642 setEventMessages($db->lasterror(), null, 'errors');
643 break;
644 }
645 }
646 }
647 } elseif ($generateinvoicemode == 'onelineperperiod') { // One line for each time spent line
648 $arrayoftasks = array();
649
650 $withdetail = GETPOST('detail_time_duration', 'alpha');
651 foreach ($toselect as $key => $value) {
652 // Get userid, timepent
653 $object->fetchTimeSpent($value);
654 // $object->id is the task id
655 $ftask = new Task($db);
656 $ftask->fetch($object->id);
657
658 $fuser->fetch($object->timespent_fk_user);
659 $username = $fuser->getFullName($langs);
660
661 $arrayoftasks[$object->timespent_id]['timespent'] = $object->timespent_duration;
662 $arrayoftasks[$object->timespent_id]['totalvaluetodivideby3600'] = $object->timespent_duration * $object->timespent_thm;
663 $arrayoftasks[$object->timespent_id]['note'] = $ftask->ref . ' - ' . $ftask->label . ' - ' . $username;
664 $arrayoftasks[$object->timespent_id]['note'] = dol_concatdesc($arrayoftasks[$object->timespent_id]['note'], $object->timespent_note);
665
666 if (!empty($withdetail)) {
667 if (!empty($object->timespent_withhour)) {
668 $arrayoftasks[$object->timespent_id]['note'] = dol_concatdesc($arrayoftasks[$object->timespent_id]['note'], $langs->trans("Date") . ': ' . dol_print_date($object->timespent_datehour));
669 } else {
670 $arrayoftasks[$object->timespent_id]['note'] = dol_concatdesc($arrayoftasks[$object->timespent_id]['note'], $langs->trans("Date") . ': ' . dol_print_date($object->timespent_date));
671 }
672 $arrayoftasks[$object->timespent_id]['note'] = dol_concatdesc($arrayoftasks[$object->timespent_id]['note'], $langs->trans("Duration") . ': ' . convertSecondToTime($object->timespent_duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY));
673 }
674 $arrayoftasks[$object->timespent_id]['user'] = $object->timespent_fk_user;
675 $arrayoftasks[$object->timespent_id]['fk_product'] = $object->timespent_fk_product;
676 }
677
678 $pu_ht_saved = $pu_ht; // Save the base unit price (price of the selected product/service if any, 0 otherwise)
679 foreach ($arrayoftasks as $timespent_id => $value) {
680 $pu_ht = $pu_ht_saved; // Reset for each line, so a line does not inherit the unit price computed for the previous one
681 $userid = $value['user'];
682 //$pu_ht = $value['timespent'] * $fuser->thm;
683
684 // Define qty per hour
685 $qtyhour = $value['timespent'] / 3600;
686
687 // If no unit price known
688 if (empty($pu_ht)) {
689 if ($value['timespent']) {
690 $pu_ht = price2num(($value['totalvaluetodivideby3600'] / $value['timespent']), 'MU');
691 }
692 }
693
694 // Add lines
695 $prodDurationHours = $prodDurationHoursBase;
696 $idprodline = $idprod;
697 $pu_htline = $pu_ht;
698 $txtvaline = $txtva;
699 $localtax1line = $localtax1;
700 $localtax2line = $localtax2;
701
702 if (!empty($value['fk_product']) && $value['fk_product'] !== $idprod) {
703 if (!array_key_exists($value['fk_product'], $product_data_cache)) {
704 $result = $tmpproduct->fetch($value['fk_product']);
705 if ($result < 0) {
706 $error++;
707 setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
708 }
709 $prodDurationHours = $tmpproduct->getProductDurationHours();
710 if ($prodDurationHours < 0) {
711 $error++;
712 $langs->load("errors");
713 setEventMessages(null, $tmpproduct->errors, 'errors');
714 // Skip this entry: without it the loop reaches addline() and divides by the duration (#40805).
715 continue;
716 }
717
718 $dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
719
720 $pu_htline = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
721 $txtvaline = $dataforprice['tva_tx'];
722 $localtax1line = $dataforprice['localtax1'];
723 $localtax2line = $dataforprice['localtax2'];
724
725 $product_data_cache[$value['fk_product']] = array('duration' => $prodDurationHours, 'dataforprice' => $dataforprice);
726 } else {
727 $prodDurationHours = $product_data_cache[$value['fk_product']]['duration'];
728 $pu_htline = empty($product_data_cache[$value['fk_product']]['dataforprice']['pu_ht']) ? 0 : $product_data_cache[$value['fk_product']]['dataforprice']['pu_ht'];
729 $txtvaline = $product_data_cache[$value['fk_product']]['dataforprice']['tva_tx'];
730 $localtax1line = $product_data_cache[$value['fk_product']]['dataforprice']['localtax1'];
731 $localtax2line = $product_data_cache[$value['fk_product']]['dataforprice']['localtax2'];
732 }
733 $idprodline = $value['fk_product'];
734 }
735 // Pass type=1 (service) explicitly so the invoice line is tagged as a service
736 // even when no product is bound to the time entry. Otherwise the default
737 // $type=0 leaks through and the PDF labels the operation as
738 // "Delivery of goods" instead of "Provision of services" (issue #34571).
739 $lineid = $tmpinvoice->addline($value['note'], $pu_htline, round($qtyhour / $prodDurationHours, 2), $txtvaline, $localtax1line, $localtax2line, ($idprodline > 0 ? $idprodline : 0), (float) $remiseproject, '', '', 0, 0, 0, 'HT', 0, Product::TYPE_SERVICE);
740 if ($lineid < 0) {
741 $error++;
742 setEventMessages(null, $tmpinvoice->errors, 'errors');
743 }
744 //var_dump($lineid);exit;
745
746 // Update lineid into line of timespent
747 $sql = 'UPDATE '.MAIN_DB_PREFIX.'element_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
748 $sql .= ' WHERE rowid = '.((int) $timespent_id).' AND fk_user = '.((int) $userid);
749 $result = $db->query($sql);
750 if (!$result) {
751 $error++;
752 setEventMessages($db->lasterror(), null, 'errors');
753 break;
754 }
755 }
756 } elseif ($generateinvoicemode == 'onelinepertask') { // One line for each different task
757 $arrayoftasks = array();
758 foreach ($toselect as $key => $value) {
759 // Get userid, timepent
760 $object->fetchTimeSpent($value); // Call method to get list of timespent for a timespent line id (We use the utility method found into Task object)
761 // $object->id is now the task id
762 $arrayoftasks[$object->id][(int) $object->timespent_fk_product]['timespent'] += $object->timespent_duration;
763 $arrayoftasks[$object->id][(int) $object->timespent_fk_product]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm);
764 }
765
766 foreach ($arrayoftasks as $task_id => $data) { // @phan-suppress-current-line PhanEmptyForeach
767 $ftask = new Task($db);
768 $ftask->fetch($task_id);
769
770 foreach ($data as $fk_product => $timespent_data) {
771 $qtyhour = $timespent_data['timespent'] / 3600;
772 $qtyhourtext = convertSecondToTime($timespent_data['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
773
774 // Add lines
775 $prodDurationHours = $prodDurationHoursBase;
776 $idprodline = $idprod;
777 $pu_htline = $pu_ht;
778 $txtvaline = $txtva;
779 $localtax1line = $localtax1;
780 $localtax2line = $localtax2;
781
782 if (!empty($fk_product) && $fk_product !== $idprod) {
783 if (!array_key_exists($fk_product, $product_data_cache)) {
784 $result = $tmpproduct->fetch($fk_product);
785 if ($result < 0) {
786 $error++;
787 setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
788 }
789 $prodDurationHours = $tmpproduct->getProductDurationHours();
790 if ($prodDurationHours < 0) {
791 $error++;
792 $langs->load("errors");
793 setEventMessages(null, $tmpproduct->errors, 'errors');
794 // Skip this entry: without it the loop reaches addline() and divides by the duration (#40805).
795 continue;
796 }
797
798 $dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
799
800 $pu_htline = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
801 $txtvaline = $dataforprice['tva_tx'];
802 $localtax1line = $dataforprice['localtax1'];
803 $localtax2line = $dataforprice['localtax2'];
804
805 $product_data_cache[$fk_product] = array('duration' => $prodDurationHours, 'dataforprice' => $dataforprice);
806 } else {
807 $prodDurationHours = $product_data_cache[$fk_product]['duration'];
808 $pu_htline = empty($product_data_cache[$fk_product]['dataforprice']['pu_ht']) ? 0 : $product_data_cache[$fk_product]['dataforprice']['pu_ht'];
809 $txtvaline = $product_data_cache[$fk_product]['dataforprice']['tva_tx'];
810 $localtax1line = $product_data_cache[$fk_product]['dataforprice']['localtax1'];
811 $localtax2line = $product_data_cache[$fk_product]['dataforprice']['localtax2'];
812 }
813 $idprodline = $fk_product;
814 }
815
816
817 if ($idprodline > 0) {
818 // If a product is defined, we msut use the $prodDurationHours and $pu_ht of product (already set previously).
819 $pu_ht_for_task = $pu_htline;
820 // If we want to reuse the value of timespent (so use same price than cost price)
821 if (getDolGlobalString('PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE')) {
822 $pu_ht_for_task = (float) price2num($timespent_data['totalvaluetodivideby3600'] / $timespent_data['timespent'], 'MU') * $prodDurationHours;
823 }
824 $pa_ht = (float) price2num($timespent_data['totalvaluetodivideby3600'] / $timespent_data['timespent'], 'MU') * $prodDurationHours;
825 } else {
826 // If not product used, we use the hour unit for duration and unit price.
827 $pu_ht_for_task = 0;
828 // If we want to reuse the value of timespent (so use same price than cost price)
829 if (getDolGlobalString('PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE')) {
830 $pu_ht_for_task = price2num($timespent_data['totalvaluetodivideby3600'] / $timespent_data['timespent'], 'MU');
831 }
832 $pa_ht = price2num($timespent_data['totalvaluetodivideby3600'] / $timespent_data['timespent'], 'MU');
833 }
834
835 // Add lines
836 $date_start = '';
837 $date_end = '';
838 $lineName = $ftask->ref . ' - ' . $ftask->label;
839 $lineid = $tmpinvoice->addline($lineName, (float) $pu_ht_for_task, (float) price2num($qtyhour / $prodDurationHours, 'MS'), $txtvaline, $localtax1line, $localtax2line, ($idprodline > 0 ? $idprodline : 0), (float) $remiseproject, $date_start, $date_end, 0, 0, 0, 'HT', 0, 1, -1, 0, '', 0, 0, 0, $pa_ht);
840 if ($lineid < 0) {
841 $error++;
842 setEventMessages($tmpinvoice->error, $tmpinvoice->errors, 'errors');
843 break;
844 }
845
846 if (!$error) {
847 // Update lineid into line of timespent
848 $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'element_time SET invoice_line_id = ' . ((int) $lineid) . ', invoice_id = ' . ((int) $tmpinvoice->id);
849 $sql .= ' WHERE rowid IN (' . $db->sanitize(implode(',', $toselect)) . ')';
850 $result = $db->query($sql);
851 if (!$result) {
852 $error++;
853 setEventMessages($db->lasterror(), null, 'errors');
854 break;
855 }
856 }
857 }
858 }
859 }
860 }
861
862 if (!$error) {
863 $urltoinvoice = $tmpinvoice->getNomUrl(0);
864 $mesg = $langs->trans("InvoiceGeneratedFromTimeSpent", '{s1}');
865 $mesg = str_replace('{s1}', $urltoinvoice, $mesg);
866 setEventMessages($mesg, null, 'mesgs');
867
868 $db->commit();
869 } else {
870 $db->rollback();
871 }
872 }
873}
874
875if ($action == 'confirm_generateinter' && $user->hasRight('fichinter', 'creer')) {
876 $langs->load('interventions');
877
878 if (!empty($projectstatic->socid)) {
879 $projectstatic->fetch_thirdparty();
880 }
881
882 if (!($projectstatic->thirdparty->id > 0)) {
883 setEventMessages($langs->trans("ThirdPartyRequiredToGenerateIntervention"), null, 'errors');
884 } else {
885 include_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
886 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
887 include_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
888
889
890 require_once DOL_DOCUMENT_ROOT . '/fichinter/class/fichinter.class.php';
891 $tmpinter = new Fichinter($db);
892 $tmptimespent = new Task($db);
893 $fuser = new User($db);
894
895 $db->begin();
896 $interToUse = GETPOSTINT('interid');
897
898
899 $tmpinter->socid = $projectstatic->thirdparty->id;
900 $tmpinter->date = dol_mktime(GETPOSTINT('rehour'), GETPOSTINT('remin'), GETPOSTINT('resec'), GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
901 $tmpinter->fk_project = $projectstatic->id;
902 $tmpinter->description = $projectstatic->title . (!empty($projectstatic->description) ? '-' . $projectstatic->label : '');
903
904 if ($interToUse) {
905 $tmpinter->fetch($interToUse);
906 } else {
907 $result = $tmpinter->create($user);
908 if ($result <= 0) {
909 $error++;
910 setEventMessages($tmpinter->error, $tmpinter->errors, 'errors');
911 }
912 }
913
914 if (!$error) {
915 $arrayoftasks = array();
916 foreach ($toselect as $key => $value) {
917 // Get userid, timespent
918 $object->fetchTimeSpent($value);
919 // $object->id is the task id
920 $arrayoftasks[$object->timespent_id]['id'] = $object->id;
921 $arrayoftasks[$object->timespent_id]['timespent'] = $object->timespent_duration;
922 $arrayoftasks[$object->timespent_id]['totalvaluetodivideby3600'] = $object->timespent_duration * $object->timespent_thm;
923 $arrayoftasks[$object->timespent_id]['note'] = $object->timespent_note;
924 $arrayoftasks[$object->timespent_id]['date'] = $object->timespent_datehour;
925 }
926
927 foreach ($arrayoftasks as $timespent_id => $value) {
928 $ftask = new Task($db);
929 $ftask->fetch($value['id']);
930 // Define qty per hour
931 $qtyhour = $value['timespent'] / 3600;
932 $qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
933
934 // Add lines
935 $lineid = $tmpinter->addline($user, $tmpinter->id, $ftask->label . (!empty($value['note']) ? ' - ' . $value['note'] : ''), (int) $value['date'], $value['timespent']);
936
937 if ($lineid > 0) {
938 // Link timespent to intervention
939 $timespent = new TimeSpent($db);
940 $timespent->fetch($timespent_id);
941 $timespent->intervention_id = $tmpinter->id;
942 $timespent->intervention_line_id = $lineid;
943 $result = $timespent->update($user);
944 if ($result < 0) {
945 $error++;
946 setEventMessages($timespent->error, $timespent->errors, 'errors');
947 }
948 }
949 }
950 }
951
952 if (!$error) {
953 $urltointer = $tmpinter->getNomUrl(0);
954 $mesg = $langs->trans("InterventionGeneratedFromTimeSpent", '{s1}');
955 $mesg = str_replace('{s1}', $urltointer, $mesg);
956 setEventMessages($mesg, null, 'mesgs');
957
958 //var_dump($tmpinvoice);
959
960 $db->commit();
961 } else {
962 $db->rollback();
963 }
964 }
965}
966
967
968/*
969 * View
970 */
971
972$form = new Form($db);
973$formother = new FormOther($db);
974$formproject = new FormProjets($db);
975$userstatic = new User($db);
976//$result = $projectstatic->fetch($object->fk_project);
977$arrayofselected = is_array($toselect) ? $toselect : array();
978
979$title = $object->ref . ' - ' . $langs->trans("TimeSpent");
980if (!empty($withproject)) {
981 $title .= ' | ' . $langs->trans("Project") . (!empty($projectstatic->ref) ? ': ' . $projectstatic->ref : '');
982}
983$help_url = '';
984
985llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-project project-tasks page-task_time');
986
987
988$param = ((!empty($mode) && $mode == 'mine') ? '&mode=mine' : '');
989if ($search_user) {
990 $param .= '&search_user=' . ((int) $search_user);
991}
992if ($search_month) {
993 $param .= '&search_month=' . ((int) $search_month);
994}
995if ($search_year) {
996 $param .= '&search_year=' . ((int) $search_year);
997}
998
999
1000if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser > 0) {
1001 // Project car in view mode
1002 if ($projectidforalltimes > 0) {
1003 $result = $projectstatic->fetch($projectidforalltimes);
1004 if (!empty($projectstatic->socid)) {
1005 $projectstatic->fetch_thirdparty();
1006 }
1007 $res = $projectstatic->fetch_optionals();
1008 } elseif ($object->fetch($id, $ref) > 0) {
1009 if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_TASK') && empty($object->comments)) {
1010 $object->fetchComments();
1011 }
1012 $result = $projectstatic->fetch($object->fk_project);
1013 if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_PROJECT') && method_exists($projectstatic, 'fetchComments') && empty($projectstatic->comments)) {
1014 $projectstatic->fetchComments();
1015 }
1016 if (!empty($projectstatic->socid)) {
1017 $projectstatic->fetch_thirdparty();
1018 }
1019 $res = $projectstatic->fetch_optionals();
1020
1021 $object->project = clone $projectstatic;
1022 }
1023
1024 $userRead = $projectstatic->restrictedProjectArea($user, 'read');
1025 $linktocreatetime = '';
1026
1027 if ($projectstatic->id > 0) {
1028 if ($withproject) {
1029 // Tabs for project
1030 if (empty($id) || $tab == 'timespent') {
1031 $tab = 'timespent';
1032 } else {
1033 $tab = 'tasks';
1034 }
1035
1036 $head = project_prepare_head($projectstatic);
1037 print dol_get_fiche_head($head, $tab, $langs->trans("Project"), -1, ($projectstatic->public ? 'projectpub' : 'project'));
1038
1039 // Project card
1040
1041 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
1042
1043 $morehtmlref = '<div class="refidno">';
1044 // Title
1045 $morehtmlref .= $projectstatic->title;
1046 // Thirdparty
1047 if (!empty($projectstatic->thirdparty->id) && $projectstatic->thirdparty->id > 0) {
1048 $morehtmlref .= '<br>' . $projectstatic->thirdparty->getNomUrl(1, 'project');
1049 }
1050 $morehtmlref .= '</div>';
1051
1052 // Define a complementary filter for search of next/prev ref.
1053 if (!$user->hasRight('projet', 'all', 'lire')) {
1054 $objectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 0);
1055 $projectstatic->next_prev_filter = "rowid:IN:" . $db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0');
1056 }
1057
1058 dol_banner_tab($projectstatic, 'project_ref', $linkback, 1, 'ref', 'ref', $morehtmlref, $param);
1059
1060 print '<div class="fichecenter">';
1061 print '<div class="fichehalfleft">';
1062 print '<div class="underbanner clearboth"></div>';
1063
1064 print '<table class="border tableforfield centpercent">';
1065
1066 // Usage
1067 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJECT_HIDE_TASKS') || isModEnabled('eventorganization')) {
1068 print '<tr><td class="tdtop">';
1069 print $langs->trans("Usage");
1070 print '</td>';
1071 print '<td>';
1072 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
1073 print '<input type="checkbox" disabled name="usage_opportunity"' . (GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_opportunity ? ' checked="checked"' : '')) . '"> ';
1074 $htmltext = $langs->trans("ProjectFollowOpportunity");
1075 print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
1076 print '<br>';
1077 }
1078 if (!getDolGlobalString('PROJECT_HIDE_TASKS')) {
1079 print '<input type="checkbox" disabled name="usage_task"' . (GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_task ? ' checked="checked"' : '')) . '"> ';
1080 $htmltext = $langs->trans("ProjectFollowTasks");
1081 print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
1082 print '<br>';
1083 }
1084 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
1085 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"' : '')) . '"> ';
1086 $htmltext = $langs->trans("ProjectBillTimeDescription");
1087 print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
1088 print '<br>';
1089 }
1090 if (isModEnabled('eventorganization')) {
1091 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"' : '')) . '"> ';
1092 $htmltext = $langs->trans("EventOrganizationDescriptionLong");
1093 print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
1094 }
1095 print '</td></tr>';
1096 }
1097
1098 // Budget
1099 print '<tr><td>' . $langs->trans("Budget") . '</td><td>';
1100 if (!is_null($projectstatic->budget_amount) && strcmp($projectstatic->budget_amount, '')) {
1101 print '<span class="amount">' . price($projectstatic->budget_amount, 0, $langs, 1, 0, 0, $conf->currency) . '</span>';
1102 }
1103 print '</td></tr>';
1104
1105 // Date start - end project
1106 print '<tr><td>' . $langs->trans("Dates") . '</td><td>';
1107 $start = dol_print_date($projectstatic->date_start, 'day');
1108 print($start ? $start : '?');
1109 $end = dol_print_date($projectstatic->date_end, 'day');
1110 print ' - ';
1111 print($end ? $end : '?');
1112 if ($projectstatic->hasDelay()) {
1113 print img_warning("Late");
1114 }
1115 print '</td></tr>';
1116
1117 // Visibility
1118 print '<tr><td class="titlefield">' . $langs->trans("Visibility") . '</td><td>';
1119 if ($projectstatic->public) {
1120 print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
1121 print $langs->trans('SharedProject');
1122 } else {
1123 print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
1124 print $langs->trans('PrivateProject');
1125 }
1126 print '</td></tr>';
1127
1128 // Other attributes
1129 $cols = 2;
1130 $savobject = $object;
1131 $object = $projectstatic;
1132 // On this page, the 'id' GET parameter is the task id, not the project id, so force the
1133 // edit link/form of the project extrafields to use 'projectid' instead, and keep 'withproject'
1134 // so the project summary (this whole block) stays visible after the edit link is followed.
1135 $forcefieldid = 'projectid';
1136 $moreparam = '&withproject=1';
1137 include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
1138 unset($forcefieldid, $moreparam);
1139 $object = $savobject;
1140
1141 print '</table>';
1142
1143 print '</div>';
1144 print '<div class="fichehalfright">';
1145 print '<div class="underbanner clearboth"></div>';
1146
1147 print '<table class="border tableforfield centpercent">';
1148
1149 // Categories
1150 if (isModEnabled('category')) {
1151 print '<tr><td class="valignmiddle">' . $langs->trans("Categories") . '</td><td>';
1152 print $form->showCategories($projectstatic->id, 'project', 1);
1153 print "</td></tr>";
1154 }
1155
1156 // Description
1157 print '<tr><td class="titlefield'.($projectstatic->description ? ' noborderbottom' : '').'" colspan="2">'.$langs->trans("Description").'</td></tr>';
1158 if ($projectstatic->description) {
1159 print '<tr><td class="nottitleforfield" colspan="2">';
1160 print '<div class="longmessagecut">';
1161 print dolPrintHTML($projectstatic->description);
1162 print '</div>';
1163 print '</td></tr>';
1164 }
1165
1166 print '</table>';
1167
1168 print '</div>';
1169 print '</div>';
1170
1171 print '<div class="clearboth"></div>';
1172
1173 print dol_get_fiche_end();
1174
1175 print '<br>';
1176 }
1177
1178 // Link to create time
1179 $linktocreatetimeBtnStatus = 0;
1180 $linktocreatetimeUrl = '';
1181 $linktocreatetimeHelpText = '';
1182 if ($user->hasRight('projet', 'time')) {
1183 if ($projectstatic->public || $userRead > 0) {
1184 $linktocreatetimeBtnStatus = 1;
1185
1186 if (!empty($projectidforalltimes)) {
1187 // We are on tab 'Time Spent' of project
1188 $backtourl = $_SERVER['PHP_SELF'] . '?projectid=' . $projectstatic->id . ($withproject ? '&withproject=1' : '');
1189 $linktocreatetimeUrl = $_SERVER['PHP_SELF'] . '?' . ($withproject ? 'withproject=1' : '') . '&projectid=' . $projectstatic->id . '&action=createtime&token=' . newToken() . $param . '&backtopage=' . urlencode($backtourl);
1190 } else {
1191 // We are on tab 'Time Spent' of task
1192 $backtourl = $_SERVER['PHP_SELF'] . '?id=' . $object->id . ($withproject ? '&withproject=1' : '');
1193 $linktocreatetimeUrl = $_SERVER['PHP_SELF'] . '?' . ($withproject ? 'withproject=1' : '') . ($object->id > 0 ? '&id=' . $object->id : '&projectid=' . $projectstatic->id) . '&action=createtime&token=' . newToken() . $param . '&backtopage=' . urlencode($backtourl);
1194 }
1195 } else {
1196 $linktocreatetimeBtnStatus = -2;
1197 $linktocreatetimeHelpText = $langs->trans("NotOwnerOfProject");
1198 }
1199 } else {
1200 $linktocreatetimeBtnStatus = -2;
1201 $linktocreatetimeHelpText = $langs->trans("NotEnoughPermissions");
1202 }
1203
1204 $paramsbutton = array('morecss' => 'reposition');
1205 $linktocreatetime = dolGetButtonTitle($langs->trans('AddTimeSpent'), $linktocreatetimeHelpText, 'fa fa-plus-circle', $linktocreatetimeUrl, '', $linktocreatetimeBtnStatus, $paramsbutton);
1206 }
1207
1208 $massactionbutton = '';
1209 $arrayofmassactions = array();
1210
1211 if ($projectstatic->id > 0) {
1212 // If we are on a given project.
1213 if ($projectstatic->usage_bill_time) {
1214 $arrayofmassactions = array(
1215 'generateinvoice' => $langs->trans("GenerateBill"),
1216 //'builddoc'=>$langs->trans("PDFMerge"),
1217 );
1218 }
1219 if (isModEnabled('intervention') && $user->hasRight('ficheinter', 'creer')) {
1220 $langs->load("interventions");
1221 $arrayofmassactions['generateinter'] = $langs->trans("GenerateInter");
1222 }
1223 }
1224 if (in_array($massaction, array('presend', 'predelete', 'generateinvoice', 'generateinter'))) {
1225 $arrayofmassactions = array();
1226 }
1227 $massactionbutton = $form->selectMassAction('', $arrayofmassactions);
1228
1229 $formconfirm = '';
1230
1231 // Task
1232
1233 // Show section with information of task. If id of task is not defined and project id defined, then $projectidforalltimes is not empty.
1234 if (empty($projectidforalltimes) && empty($allprojectforuser)) {
1235 $head = task_prepare_head($object);
1236 print dol_get_fiche_head($head, 'task_time', $langs->trans("Task"), -1, 'projecttask', 0, '', 'reposition');
1237
1238 $param = (GETPOST('withproject') ? '&withproject=1' : '');
1239 $linkback = GETPOST('withproject') ? '<a href="'.DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.'">'.$langs->trans("BackToList").'</a>' : '';
1240
1241 if ($action == 'deleteline') {
1242 $urlafterconfirm = $_SERVER["PHP_SELF"] . "?" . ($object->id > 0 ? "id=" . $object->id : 'projectid=' . $projectstatic->id) . '&lineid=' . GETPOSTINT("lineid") . $param;
1243 $formconfirm .= $form->formconfirm($urlafterconfirm, $langs->trans("DeleteATimeSpent"), $langs->trans("ConfirmDeleteATimeSpent"), "confirm_deleteline", '', '', 1);
1244 }
1245
1246 if (!GETPOST('withproject') || empty($projectstatic->id)) {
1247 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1);
1248 $object->next_prev_filter = "fk_projet:IN:" . $db->sanitize($projectsListId);
1249 } else {
1250 $object->next_prev_filter = "fk_projet:=:" . ((int) $projectstatic->id);
1251 }
1252
1253 $morehtmlref = '';
1254
1255 // Project
1256 if (empty($withproject)) {
1257 $morehtmlref .= '<div class="refidno">';
1258 $morehtmlref .= $langs->trans("Project") . ': ';
1259 $morehtmlref .= $projectstatic->getNomUrl(1);
1260 $morehtmlref .= '<br>';
1261
1262 // Third party
1263 $morehtmlref .= $langs->trans("ThirdParty") . ': ';
1264 if (!empty($projectstatic->thirdparty) && is_object($projectstatic->thirdparty)) {
1265 $morehtmlref .= $projectstatic->thirdparty->getNomUrl(1);
1266 }
1267 $morehtmlref .= '</div>';
1268 }
1269
1270 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, $param);
1271
1272 print '<div class="fichecenter">';
1273 print '<div class="fichehalfleft">';
1274
1275 print '<div class="underbanner clearboth"></div>';
1276 print '<table class="border centpercent tableforfield">';
1277
1278 // Task parent
1279 print '<tr><td>' . $langs->trans("ParentTask") . '</td><td>';
1280 if ($object->fk_task_parent > 0) {
1281 $tasktmp = new Task($db);
1282 $tasktmp->fetch($object->fk_task_parent);
1283 print $tasktmp->getNomUrl(1);
1284 }
1285 print '</td></tr>';
1286
1287 // Date start - Date end task
1288 print '<tr><td class="titlefield">' . $langs->trans("DateStart") . ' - ' . $langs->trans("Deadline") . '</td><td>';
1289 $start = dol_print_date($object->date_start, 'dayhour');
1290 print($start ? $start : '?');
1291 $end = dol_print_date($object->date_end, 'dayhour');
1292 print ' - ';
1293 print($end ? $end : '?');
1294 if ($object->hasDelay()) {
1295 print img_warning("Late");
1296 }
1297 print '</td></tr>';
1298
1299 // Planned workload
1300 print '<tr><td>' . $langs->trans("PlannedWorkload") . '</td><td>';
1301 if ($object->planned_workload) {
1302 print convertSecondToTime($object->planned_workload, 'allhourmin');
1303 }
1304 print '</td></tr>';
1305
1306 print '</table>';
1307 print '</div>';
1308
1309 print '<div class="fichehalfright">';
1310
1311 print '<div class="underbanner clearboth"></div>';
1312 print '<table class="border tableforfield centpercent">';
1313
1314 // Progress declared
1315 print '<tr><td class="titlefield">' . $langs->trans("ProgressDeclared") . '</td><td>';
1316 print $object->progress != '' ? $object->progress . ' %' : '';
1317 print '</td></tr>';
1318
1319 // Progress calculated
1320 print '<tr><td>' . $langs->trans("ProgressCalculated") . '</td><td>';
1321 if ($object->planned_workload) {
1322 $tmparray = $object->getSummaryOfTimeSpent();
1323 if ($tmparray['total_duration'] > 0) {
1324 print round($tmparray['total_duration'] / $object->planned_workload * 100, 2) . ' %';
1325 } else {
1326 print '0 %';
1327 }
1328 } else {
1329 print '<span class="opacitymedium">' . $langs->trans("WorkloadNotDefined") . '</span>';
1330 }
1331 print '</td>';
1332
1333 print '</tr>';
1334
1335 print '</table>';
1336
1337 print '</div>';
1338
1339 print '</div>';
1340 print '<div class="clearboth"></div>';
1341
1342 print dol_get_fiche_end();
1343 } else {
1344 if ($action == 'deleteline') {
1345 $urlafterconfirm = $_SERVER["PHP_SELF"] . "?" . ($projectstatic->id > 0 ? 'projectid=' . $projectstatic->id : ($object->id > 0 ? "id=" . $object->id : '')) . '&lineid=' . GETPOSTINT("lineid") . ($withproject ? '&withproject=1' : ''). "&contextpage=" . urlencode($contextpage).$param;
1346 $formconfirm .= $form->formconfirm($urlafterconfirm, $langs->trans("DeleteATimeSpent"), $langs->trans("ConfirmDeleteATimeSpent"), "confirm_deleteline", '', '', 1);
1347 }
1348 }
1349
1350 // Call Hook formConfirm
1351 $parameters = array('formConfirm' => $formconfirm, "projectstatic" => $projectstatic, "withproject" => $withproject);
1352 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1353 if (empty($reshook)) {
1354 $formconfirm .= $hookmanager->resPrint;
1355 } elseif ($reshook > 0) {
1356 $formconfirm = $hookmanager->resPrint;
1357 }
1358
1359
1360 if ($projectstatic->id > 0 || $allprojectforuser > 0) {
1361 // Initialize a technical object to manage hooks. Note that conf->hooks_modules contains array
1362 $hookmanager->initHooks(array('tasktimelist'));
1363
1364 // Print form confirm
1365 print $formconfirm;
1366
1367 // Definition of fields for list
1368 $arrayfields = array();
1369 $arrayfields['t.element_date'] = array('label' => $langs->trans("Date"), 'checked' => '1');
1370 $arrayfields['p.fk_soc'] = array('label' => $langs->trans("ThirdParty"), 'type' => 'integer:Societe:/societe/class/societe.class.php:1','checked' => '1');
1371 $arrayfields['s.name_alias'] = array('label' => $langs->trans("AliasNameShort"), 'type' => 'integer:Societe:/societe/class/societe.class.php:1');
1372 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
1373 if (! empty($allprojectforuser)) {
1374 $arrayfields['p.project_ref'] = ['label' => $langs->trans('RefProject'), 'checked' => '1'];
1375 $arrayfields['p.project_label'] = ['label' => $langs->trans('ProjectLabel'), 'checked' => '1'];
1376 }
1377 $arrayfields['t.element_ref'] = array('label' => $langs->trans("RefTask"), 'checked' => '1');
1378 $arrayfields['t.element_label'] = array('label' => $langs->trans("LabelTask"), 'checked' => '1');
1379 }
1380 $arrayfields['author'] = array('label' => $langs->trans("By"), 'checked' => '1');
1381 $arrayfields['t.note'] = array('label' => $langs->trans("Note"), 'checked' => '1');
1382 $arrayfields['t.tms'] = array('label' => $langs->trans("DateModification"), 'checked' => '0');
1383 if (isModEnabled('service') && !empty($projectstatic->thirdparty) && $projectstatic->thirdparty->id > 0 && $projectstatic->usage_bill_time) {
1384 $arrayfields['t.fk_product'] = array('label' => $langs->trans("Product"), 'checked' => '1');
1385 }
1386 $arrayfields['t.element_duration'] = array('label' => $langs->trans("Duration"), 'checked' => '1');
1387 $arrayfields['t.fk_product'] = array('label' => $langs->trans("Product"), 'checked' => '0', 'enabled' => (string) (int) (((getDolGlobalInt('PROJECT_HIDE_TASKS') || !getDolGlobalInt('PROJECT_BILL_TIME_SPENT')) ? 0 : 1) && $projectstatic->usage_bill_time));
1388 $arrayfields['value'] = array('label' => $langs->trans("Value"), 'checked' => '1', 'enabled' => (string) (int) isModEnabled("salaries"));
1389 $arrayfields['valuebilled'] = array('label' => $langs->trans("Billed"), 'checked' => '1', 'enabled' => (string) (int) (((getDolGlobalInt('PROJECT_HIDE_TASKS') || !getDolGlobalInt('PROJECT_BILL_TIME_SPENT')) ? 0 : 1) && $projectstatic->usage_bill_time));
1390 // Extra fields
1391 include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_list_array_fields.tpl.php';
1392
1393 $arrayfields = dol_sort_array($arrayfields, 'position');
1394
1395 $param = '';
1396 if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
1397 $param .= '&contextpage=' . urlencode($contextpage);
1398 }
1399 if ($limit > 0 && $limit != $conf->liste_limit) {
1400 $param .= '&limit='.((int) $limit);
1401 }
1402 if ($id > 0) {
1403 $param .= '&id='.((int) $id);
1404 }
1405 if ($search_month > 0) {
1406 $param .= '&search_month=' . urlencode((string) ($search_month));
1407 }
1408 if ($search_year > 0) {
1409 $param .= '&search_year=' . urlencode((string) ($search_year));
1410 }
1411 if (!empty($search_user)) { // We keep param if -1 because default value is forced to user id if not set
1412 $param .= '&search_user='.urlencode($search_user);
1413 }
1414 if ($search_task_ref != '') {
1415 $param .= '&search_task_ref=' . urlencode($search_task_ref);
1416 }
1417 if ($search_company != '') {
1418 $param .= '&search_company=' . urlencode($search_company);
1419 }
1420 if ($search_company_alias != '') {
1421 $param .= '&search_company_alias=' . urlencode($search_company_alias);
1422 }
1423 if ($search_project_ref != '') {
1424 $param .= '&search_project_ref=' . urlencode($search_project_ref);
1425 }
1426 if ($search_project_label != '') {
1427 $param .= '&search_project_label=' . urlencode($search_project_label);
1428 }
1429 if ($search_task_label != '') {
1430 $param .= '&search_task_label=' . urlencode($search_task_label);
1431 }
1432 if ($search_note != '') {
1433 $param .= '&search_note=' . urlencode($search_note);
1434 }
1435 if ($search_duration != '') {
1436 $param .= '&search_field2=' . urlencode((string) ($search_duration));
1437 }
1438 if ($optioncss != '') {
1439 $param .= '&optioncss=' . urlencode($optioncss);
1440 }
1441 if ($search_date_startday) {
1442 $param .= '&search_date_startday=' . urlencode((string) ($search_date_startday));
1443 }
1444 if ($search_date_startmonth) {
1445 $param .= '&search_date_startmonth=' . urlencode((string) ($search_date_startmonth));
1446 }
1447 if ($search_date_startyear) {
1448 $param .= '&search_date_startyear=' . urlencode((string) ($search_date_startyear));
1449 }
1450 if ($search_date_endday) {
1451 $param .= '&search_date_endday=' . urlencode((string) ($search_date_endday));
1452 }
1453 if ($search_date_endmonth) {
1454 $param .= '&search_date_endmonth=' . urlencode((string) ($search_date_endmonth));
1455 }
1456 if ($search_date_endyear) {
1457 $param .= '&search_date_endyear=' . urlencode((string) ($search_date_endyear));
1458 }
1459 if ($search_timespent_starthour) {
1460 $param .= '&search_timespent_duration_starthour=' . urlencode((string) ($search_timespent_starthour));
1461 }
1462 if ($search_timespent_startmin) {
1463 $param .= '&search_timespent_duration_startmin=' . urlencode((string) ($search_timespent_startmin));
1464 }
1465 if ($search_timespent_endhour) {
1466 $param .= '&search_timespent_duration_endhour=' . urlencode((string) ($search_timespent_endhour));
1467 }
1468 if ($search_timespent_endmin) {
1469 $param .= '&search_timespent_duration_endmin=' . urlencode((string) ($search_timespent_endmin));
1470 }
1471 // Add $param from extra fields
1472 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
1473 if ($id) {
1474 $param .= '&id=' . urlencode((string) ($id));
1475 }
1476 if ($projectid) {
1477 $param .= '&projectid=' . urlencode((string) ($projectid));
1478 }
1479 if ($withproject) {
1480 $param .= '&withproject=' . urlencode((string) ($withproject));
1481 }
1482 // Add $param from hooks
1483 $parameters = array('param' => &$param);
1484 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1485 $param .= $hookmanager->resPrint;
1486
1487 print '<form method="POST" action="' . $_SERVER["PHP_SELF"] . '">';
1488 if ($optioncss != '') {
1489 print '<input type="hidden" name="optioncss" value="' . $optioncss . '">';
1490 }
1491 print '<input type="hidden" name="token" value="' . newToken() . '">';
1492 print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
1493 if ($action == 'editline') {
1494 print '<input type="hidden" name="action" value="updateline">';
1495 } elseif ($action == 'splitline') {
1496 print '<input type="hidden" name="action" value="updatesplitline">';
1497 } elseif ($action == 'createtime' && $user->hasRight('projet', 'time')) {
1498 print '<input type="hidden" name="action" value="addtimespent">';
1499 } elseif ($massaction == 'generateinvoice' && $user->hasRight('facture', 'creer')) {
1500 print '<input type="hidden" name="action" value="confirm_generateinvoice">';
1501 } elseif ($massaction == 'generateinter' && $user->hasRight('ficheinter', 'creer')) {
1502 print '<input type="hidden" name="action" value="confirm_generateinter">';
1503 } else {
1504 print '<input type="hidden" name="action" value="list">';
1505 }
1506 print '<input type="hidden" name="sortfield" value="' . $sortfield . '">';
1507 print '<input type="hidden" name="sortorder" value="' . $sortorder . '">';
1508
1509 // Carry the task id through the filter submit so that the timespent list
1510 // stays scoped to the current task instead of falling back to the global view.
1511 print '<input type="hidden" name="id" value="' . ((int) $id) . '">';
1512 print '<input type="hidden" name="projectid" value="' . $projectidforalltimes . '">';
1513 print '<input type="hidden" name="withproject" value="' . $withproject . '">';
1514 print '<input type="hidden" name="tab" value="' . $tab . '">';
1515 print '<input type="hidden" name="page_y" value="">';
1516
1517 // Form to convert time spent into invoice
1518 if ($massaction == 'generateinvoice') {
1519 if (!empty($projectstatic->thirdparty) && $projectstatic->thirdparty->id > 0) {
1520 print '<table class="noborder centerpercent">';
1521 print '<tr>';
1522 print '<td class="titlefield">';
1523 print $langs->trans('DateInvoice');
1524 print '</td>';
1525 print '<td>';
1526 print $form->selectDate('', '', 0, 0, 0, '', 1, 1);
1527 print '</td>';
1528 print '</tr>';
1529
1530 print '<tr>';
1531 print '<td>';
1532 print $langs->trans('Mode');
1533 print '</td>';
1534 print '<td>';
1535 $tmparray = array(
1536 'onelineperuser' => 'OneLinePerUser',
1537 'onelinepertask' => 'OneLinePerTask',
1538 'onelineperperiod' => 'OneLinePerTimeSpentLine',
1539 );
1540 print $form->selectarray('generateinvoicemode', $tmparray, 'onelineperuser', 0, 0, 0, '', 1);
1541 print "\n" . '<script type="text/javascript">';
1542 print '
1543 $(document).ready(function () {
1544 setDetailVisibility();
1545 $("#generateinvoicemode").change(function() {
1546 setDetailVisibility();
1547 });
1548 function setDetailVisibility() {
1549 generateinvoicemode = $("#generateinvoicemode option:selected").val();
1550 if (generateinvoicemode=="onelineperperiod") {
1551 $("#detail_time_duration").show();
1552 } else {
1553 $("#detail_time_duration").hide();
1554 }
1555 }
1556 });
1557 ';
1558 print '</script>' . "\n";
1559 print '<span style="display:none" id="detail_time_duration"><input type="checkbox" value="detail" name="detail_time_duration"/>' . $langs->trans('AddDetailDateAndDuration') . '</span>';
1560 print '</td>';
1561 print '</tr>';
1562
1563 if (isModEnabled("service")) {
1564 print '<tr>';
1565 print '<td>';
1566 print $langs->trans('ServiceToUseOnLines');
1567 print '</td>';
1568 print '<td>';
1569 $form->select_produits(0, 'productid', 1, 0, $projectstatic->thirdparty->price_level, 1, 2, '', 0, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500');
1570 print '</td>';
1571 print '</tr>';
1572 }
1573 print '<tr>';
1574 print '<td class="titlefield">';
1575 print $langs->trans('InvoiceToUse');
1576 print '</td>';
1577 print '<td>';
1578 print $form->selectInvoiceForTimeProject($projectstatic->thirdparty->id, '', 'invoiceid', 24, 0, $langs->trans('NewInvoice'), 1, 0, 0, 'maxwidth500', '', 'all');
1579 print '</td>';
1580 print '</tr>';
1581 print '<tr>';
1582 print '<td class="titlefield">';
1583 print $langs->trans("CustomerRelativeDiscount");
1584 print '</td>';
1585 print '<td>';
1586 print '<input type="text" size="5" name="remiseproject" value="'.$projectstatic->thirdparty->remise_percent.'">%';
1587 print '</td>';
1588 print '</tr>';
1589 print '<tr class="newinvoicedetail">';
1590 print '<td class="titlefield">';
1591 print $langs->trans("PaymentConditions");
1592 print '</td>';
1593 print '<td>';
1594 print $form->getSelectConditionsPaiements((int) $projectstatic->thirdparty->cond_reglement_id, 'condidproject');
1595 print '</td>';
1596 print '</tr>';
1597 /*print '<tr>';
1598 print '<td>';
1599 print $langs->trans('ValidateInvoices');
1600 print '</td>';
1601 print '<td>';
1602 print $form->selectyesno('validate_invoices', 0, 1);
1603 print '</td>';
1604 print '</tr>';*/
1605 print '</table>';
1606
1607 print '<br>';
1608 print '<div class="center">';
1609 print '<input type="submit" class="button" id="createbills" name="createbills" value="' . $langs->trans('GenerateBill') . '"> ';
1610 print '<input type="submit" class="button button-cancel" id="cancel" name="cancel" value="' . $langs->trans("Cancel") . '">';
1611 print '</div>';
1612 print '<br>';
1613 } else {
1614 print '<div class="warning">' . $langs->trans("ThirdPartyRequiredToGenerateInvoice") . '</div>';
1615 print '<div class="center">';
1616 print '<input type="submit" class="button button-cancel" id="cancel" name="cancel" value="' . $langs->trans("Cancel") . '">';
1617 print '</div>';
1618 $massaction = '';
1619 }
1620 } elseif ($massaction == 'generateinter') {
1621 // Form to convert time spent into invoice
1622 print '<input type="hidden" name="massaction" value="confirm_createinter">';
1623
1624 if (!empty($projectstatic->thirdparty) && $projectstatic->thirdparty->id > 0) {
1625 print '<br>';
1626 print '<table class="noborder centpercent">';
1627 print '<tr>';
1628 print '<td class="titlefield">';
1629 print img_picto('', 'intervention', 'class="pictofixedwidth"') . $langs->trans('InterToUse');
1630 print '</td>';
1631 print '<td>';
1632 $forminter = new FormIntervention($db);
1633 print $forminter->select_interventions($projectstatic->thirdparty->id, 0, 'interid', 24, $langs->trans('NewInter'), true);
1634 print '</td>';
1635 print '</tr>';
1636 print '</table>';
1637
1638 print '<div class="center">';
1639 print '<input type="submit" class="button" id="createinter" name="createinter" value="' . $langs->trans('GenerateInter') . '"> ';
1640 print '<input type="submit" class="button" id="cancel" name="cancel" value="' . $langs->trans('Cancel') . '">';
1641 print '</div>';
1642 print '<br>';
1643 } else {
1644 print '<div class="warning">' . $langs->trans("ThirdPartyRequiredToGenerateIntervention") . '</div>';
1645 print '<div class="center">';
1646 print '<input type="submit" class="button" id="cancel" name="cancel" value="' . $langs->trans('Cancel') . '">';
1647 print '</div>';
1648 $massaction = '';
1649 }
1650 }
1651
1652 // Allow Pre-Mass-Action hook (eg for confirmation dialog)
1653 $parameters = array(
1654 'toselect' => $toselect,
1655 'uploaddir' => isset($uploaddir) ? $uploaddir : null
1656 );
1657
1658 $reshook = $hookmanager->executeHooks('doPreMassActions', $parameters, $object, $action);
1659 if ($reshook < 0) {
1660 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1661 } else {
1662 print $hookmanager->resPrint;
1663 }
1664
1665 /*
1666 * List of time spent
1667 */
1668 $tasks = array();
1669
1670 $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
1671 $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, $conf->main_checkbox_left_column); // This also change content of $arrayfields
1672
1673 // If project has usage "Bill time", we force visibility of field "billed"
1674 if ($projectstatic->usage_bill_time) {
1675 $arrayfields['valuebilled']['checked'] = 1;
1676 }
1677
1678 $sql = "SELECT t.rowid, t.fk_element, t.element_date, t.element_datehour, t.element_date_withhour, t.element_duration, t.fk_user, t.note, t.thm,";
1679 $sql .= " t.fk_product, t.invoice_line_id, t.import_key, t.datec, t.tms,";
1680 $sql .= " pt.rowid as taskid, pt.ref, pt.label, pt.fk_projet, pt.billable,";
1681 $sql .= " u.lastname, u.firstname, u.login, u.photo, u.gender, u.statut as user_status,";
1682 $sql .= " il.fk_facture as invoice_id, inv.fk_statut,";
1683 $sql .= " p.fk_soc, s.name_alias";
1684 if (!empty($extrafields->attributes['projet_task']['label'])) {
1685 foreach ($extrafields->attributes['projet_task']['label'] as $key => $val) {
1686 $sql .= ($extrafields->attributes['projet_task']['type'][$key] != 'separate' ? ",efpt.".$key." as options_".$key : '');
1687 }
1688 }
1689 // Add fields from hooks
1690 $parameters = array();
1691 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1692 $sql .= $hookmanager->resPrint;
1693 $sql = preg_replace('/,\s*$/', '', $sql);
1694
1695 $sqlfields = $sql; // $sql fields to remove for count total
1696
1697 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as t";
1698 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facturedet as il ON il.rowid = t.invoice_line_id";
1699 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as inv ON inv.rowid = il.fk_facture";
1700 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as prod ON prod.rowid = t.fk_product";
1701 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."projet_task as pt ON pt.rowid = t.fk_element";
1702 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task_extrafields as efpt ON pt.rowid = efpt.fk_object";
1703 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."projet as p ON p.rowid = pt.fk_projet";
1704 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON t.fk_user = u.rowid";
1705 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = p.fk_soc";
1706
1707 // Add table from hooks
1708 $parameters = array();
1709 $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1710 $sql .= $hookmanager->resPrint;
1711 $sql .= " WHERE elementtype = 'task'";
1712 $sql .= " AND p.entity IN (".getEntity('project').")";
1713 if (!$user->hasRight('projet', 'all', 'lire')) {
1714 // Get list of project id allowed to user (in a string list separated by comma)
1715 // TODO This may generate performance trouble when list of project is very large. Solution can be to complete $filterproj with filters on project.
1716 $filterproj = '';
1717 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, $user->socid > 0 ? $user->socid : 0, $filterproj);
1718 $sql .= " AND p.rowid IN (".$db->sanitize($projectsListId).")"; // public and assigned to, or restricted to company for external users
1719 }
1720 if (empty($projectidforalltimes) && empty($allprojectforuser)) {
1721 // Limit on one task
1722 $sql .= " AND t.fk_element =".((int) $object->id);
1723 } elseif (!empty($projectidforalltimes)) {
1724 // Limit on one project
1725 $sql .= " AND pt.fk_projet IN (" . $db->sanitize((string) $projectidforalltimes) . ")";
1726 } elseif (!empty($allprojectforuser)) {
1727 // Limit on on user
1728 if (empty($search_user) && !empty($arrayfields['author']['checked'])) {
1729 $search_user = $user->id;
1730 }
1731 if ($search_user > 0) {
1732 $sql .= " AND t.fk_user = " . ((int) $search_user);
1733 }
1734 }
1735
1736 if ($search_note) {
1737 $sql .= natural_search('t.note', $search_note);
1738 }
1739 if ($search_task_ref) {
1740 $sql .= natural_search('pt.ref', $search_task_ref);
1741 }
1742 if (empty($arrayfields['s.name_alias']['checked']) && $search_company) {
1743 $sql .= natural_search(array("s.nom", "s.name_alias"), $search_company);
1744 } else {
1745 if ($search_company) {
1746 $sql .= natural_search('s.nom', $search_company);
1747 }
1748 if ($search_company_alias) {
1749 $sql .= natural_search('s.name_alias', $search_company_alias);
1750 }
1751 }
1752 if ($search_project_ref) {
1753 $sql .= natural_search('p.ref', $search_project_ref);
1754 }
1755 if ($search_project_label) {
1756 $sql .= natural_search('p.title', $search_project_label);
1757 }
1758 if ($search_task_label) {
1759 $sql .= natural_search('pt.label', $search_task_label);
1760 }
1761 if ($search_user > 0) {
1762 $sql .= natural_search('t.fk_user', $search_user, 2);
1763 }
1764 if (!empty($search_product_ref)) {
1765 $sql .= natural_search('prod.ref', $search_product_ref);
1766 }
1767 if ($search_valuebilled == '1') {
1768 $sql .= ' AND t.invoice_id > 0';
1769 }
1770 if ($search_valuebilled == '0') {
1771 $sql .= ' AND (t.invoice_id = 0 OR t.invoice_id IS NULL)';
1772 }
1773
1774 if ($search_date_start) {
1775 $sql .= " AND t.element_date >= '".$db->idate($search_date_start)."'";
1776 }
1777 if ($search_date_end) {
1778 $sql .= " AND t.element_date <= '".$db->idate($search_date_end)."'";
1779 }
1780
1781 if (!empty($arrayfields['t.element_duration']['checked'])) {
1782 if ($search_timespent_starthour || $search_timespent_startmin) {
1783 $timespent_duration_start = $search_timespent_starthour * 60 * 60; // We store duration in seconds
1784 $timespent_duration_start += ($search_timespent_startmin ? $search_timespent_startmin : 0) * 60; // We store duration in seconds
1785 $sql .= " AND t.element_duration >= " . ((int) $timespent_duration_start);
1786 }
1787
1788 if ($search_timespent_endhour || $search_timespent_endmin) {
1789 $timespent_duration_end = $search_timespent_endhour * 60 * 60; // We store duration in seconds
1790 $timespent_duration_end += ($search_timespent_endmin ? $search_timespent_endmin : 0) * 60; // We store duration in seconds
1791 $sql .= " AND t.element_duration <= " . ((int) $timespent_duration_end);
1792 }
1793 }
1794
1795 $sql .= dolSqlDateFilter('t.element_datehour', $search_day, $search_month, $search_year);
1796
1797 // Add where from extra fields
1798 $extrafieldsobjectkey = 'projet_task';
1799 $extrafieldsobjectprefix = 'efpt.';
1800 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
1801
1802 // Add where from hooks
1803 $parameters = array();
1804 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1805 $sql .= $hookmanager->resPrint;
1806
1807 // Count total nb of records
1808 $nbtotalofrecords = '';
1809 if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
1810 /* The fast and low memory method to get and count full list converts the sql into a sql count */
1811 $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql);
1812 $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount);
1813 $resql = $db->query($sqlforcount);
1814 if ($resql) {
1815 $objforcount = $db->fetch_object($resql);
1816 $nbtotalofrecords = $objforcount->nbtotalofrecords;
1817 } else {
1818 dol_print_error($db);
1819 }
1820
1821 if (($page * $limit) > (int) $nbtotalofrecords) { // if total resultset is smaller than the paging size (filtering), goto and load page 0
1822 $page = 0;
1823 $offset = 0;
1824 }
1825 $db->free($resql);
1826 }
1827
1828 // Complete request and execute it with limit
1829 $sql .= $db->order($sortfield, $sortorder);
1830 if ($limit) {
1831 $sql .= $db->plimit($limit + 1, $offset);
1832 }
1833
1834 $resql = $db->query($sql);
1835 if (!$resql) {
1836 dol_print_error($db);
1837 exit;
1838 }
1839
1840 $num = $db->num_rows($resql);
1841
1842 if ($num >= 0) {
1843 if (!empty($projectidforalltimes)) {
1844 print '<!-- List of time spent for project -->' . "\n";
1845
1846 $title = $langs->trans("ListTaskTimeUserProject");
1847
1848 print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'clock', 0, $linktocreatetime, '', $limit, 0, 0, 1);
1849 } else {
1850 print '<!-- List of time spent -->' . "\n";
1851
1852 $title = $langs->trans("ListTaskTimeForTask");
1853
1854 print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'clock', 0, $linktocreatetime, '', $limit, 0, 0, 1);
1855 }
1856
1857 $i = 0;
1858 while ($i < $num) {
1859 $obj = $db->fetch_object($resql);
1860
1861 $tasks[$i] = $obj;
1862
1863 $i++;
1864 }
1865 $db->free($resql);
1866 } else {
1867 dol_print_error($db);
1868 }
1869
1870 /*
1871 * Form to add a new line of time spent
1872 */
1873 if ($action == 'createtime' && $user->hasRight('projet', 'time')) {
1874 print '<!-- table to add time spent -->' . "\n";
1875 if (!empty($id)) {
1876 print '<input type="hidden" name="taskid" value="' . $id . '">';
1877 }
1878
1879 print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you don't need reserved height for your table
1880 print '<table class="noborder nohover centpercent">';
1881
1882 print '<tr class="liste_titre">';
1883 print '<td>' . $langs->trans("Date") . '</td>';
1884 if (!empty($allprojectforuser)) {
1885 print '<td>' . $langs->trans("Project") . '</td>';
1886 }
1887 if (empty($id)) {
1888 print '<td>' . $langs->trans("Task") . '</td>';
1889 }
1890 print '<td>' . $langs->trans("By") . '</td>';
1891 print '<td>' . $langs->trans("Note") . '</td>';
1892 print '<td>' . $langs->trans("NewTimeSpent") . '</td>';
1893 print '<td>' . $langs->trans("ProgressDeclared") . '</td>';
1894 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
1895 print '<td></td>';
1896
1897 if (isModEnabled("service") && !empty($projectstatic->thirdparty) && $projectstatic->thirdparty->id > 0 && $projectstatic->usage_bill_time) {
1898 print '<td>'.$langs->trans("Product").'</td>';
1899 }
1900 }
1901 // Hook fields
1902 $parameters = array('mode' => 'create');
1903 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1904 print $hookmanager->resPrint;
1905 print '<td></td>';
1906 print "</tr>\n";
1907
1908 print '<tr class="oddeven nohover">';
1909
1910 // Date
1911 print '<td class="maxwidthonsmartphone">';
1912 $newdate = '';
1913 print $form->selectDate($newdate, 'time', ($conf->browser->layout == 'phone' ? 2 : 1), 1, 2, "timespent_date", 1, 0);
1914 print '</td>';
1915
1916 if (!empty($allprojectforuser)) {
1917 print '<td>';
1918 // Add project selector
1919 print '</td>';
1920 }
1921
1922 // Task
1923 $nboftasks = 0;
1924 if (empty($id)) {
1925 print '<td class="maxwidthonsmartphone">';
1926 $nboftasks = $formproject->selectTasks(-1, GETPOSTINT('taskid'), 'taskid', 0, 0, '1', 1, 0, 0, 'maxwidth300', (string) $projectstatic->id, 'progress');
1927 print '</td>';
1928 }
1929
1930 // Contributor
1931 print '<td class="maxwidthonsmartphone nowraponall">';
1932 $contactsofproject = $projectstatic->getListContactId('internal');
1933 if (count($contactsofproject) > 0) {
1934 print img_object('', 'user', 'class="hideonsmartphone"');
1935 if (in_array($user->id, $contactsofproject)) {
1936 $userid = $user->id;
1937 } else {
1938 $userid = $contactsofproject[0];
1939 }
1940
1941 if ($projectstatic->public) {
1942 $contactsofproject = array();
1943 }
1944 print $form->select_dolusers((GETPOSTINT('userid') ? GETPOSTINT('userid') : $userid), 'userid', 0, null, 0, '', $contactsofproject, '0', 0, 0, '', 0, $langs->trans("ResourceNotAssignedToProject"), 'minwidth150imp maxwidth200');
1945 } else {
1946 if ($nboftasks) {
1947 print img_error($langs->trans('FirstAddRessourceToAllocateTime')) . ' ' . $langs->trans('FirstAddRessourceToAllocateTime');
1948 }
1949 }
1950 print '</td>';
1951
1952 // Note
1953 print '<td>';
1954 print '<textarea name="timespent_note" class="maxwidth100onsmartphone" rows="' . ROWS_2 . '">' . (GETPOST('timespent_note') ? GETPOST('timespent_note') : '') . '</textarea>';
1955 print '</td>';
1956
1957 // Duration - Time spent
1958 print '<td class="nowraponall">';
1959 $durationtouse = (GETPOST('timespent_duration') ? GETPOST('timespent_duration') : '');
1960 if (GETPOSTISSET('timespent_durationhour') || GETPOSTISSET('timespent_durationmin')) {
1961 $durationtouse = ((int) GETPOST('timespent_durationhour') * 3600 + (int) GETPOST('timespent_durationmin') * 60);
1962 }
1963 print $form->select_duration('timespent_duration', $durationtouse, 0, 'text');
1964 print '</td>';
1965
1966 // Progress declared
1967 print '<td class="nowrap">';
1968 print $formother->select_percent(GETPOST('progress') ? GETPOST('progress') : $object->progress, 'progress', 0, 5, 0, 100, 1);
1969 print '</td>';
1970
1971 // Billed
1972 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
1973 print '<td>';
1974 print '</td>';
1975
1976 if (isModEnabled("service") && !empty($projectstatic->thirdparty) && $projectstatic->thirdparty->id > 0 && $projectstatic->usage_bill_time) {
1977 print '<td class="nowraponall">';
1978 print img_picto('', 'service');
1979 print $form->select_produits((GETPOSTISSET('fk_product') ? GETPOSTINT("fk_product") : ''), 'fk_product', 1, 0, $projectstatic->thirdparty->price_level, 1, 2, '', 1, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth150', ($user->hasRight('produit', 'lire') ? 0 : 1), '', null, 1);
1980 print '</td>';
1981 }
1982 }
1983
1984 // Fields from hook
1985 $parameters = array('mode' => 'create');
1986 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1987 print $hookmanager->resPrint;
1988
1989 print '<td class="center">';
1990 $form->buttonsSaveCancel();
1991 print '<input type="submit" name="save" class="button buttongen smallpaddingimp marginleftonly margintoponlyshort marginbottomonlyshort button-add reposition" value="'.$langs->trans("Add").'">';
1992 print '<input type="submit" name="cancel" class="button buttongen smallpaddingimp marginleftonly margintoponlyshort marginbottomonlyshort button-cancel" value="'.$langs->trans("Cancel").'">';
1993 print '</td></tr>';
1994
1995 print '</table>';
1996 print '</div>';
1997
1998 print '<br>';
1999 }
2000
2001 $moreforfilter = '';
2002
2003 $parameters = array();
2004 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2005 if (empty($reshook)) {
2006 $moreforfilter .= $hookmanager->resPrint;
2007 } else {
2008 $moreforfilter = $hookmanager->resPrint;
2009 }
2010
2011 if (!empty($moreforfilter)) {
2012 print '<div class="liste_titre liste_titre_bydiv centpercent">';
2013 print $moreforfilter;
2014 print '</div>';
2015 }
2016
2017 $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
2018 $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, $conf->main_checkbox_left_column); // This also change content of $arrayfields
2019 $selectedfields .= (is_array($arrayofmassactions) && count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : '');
2020
2021 // If project has usage "Bill time", we force visibility of field "billed"
2022 if ($projectstatic->usage_bill_time) {
2023 $arrayfields['valuebilled']['checked'] = 1;
2024 }
2025
2026 print '<!-- Liste of time spent -->'."\n";
2027 print '<div class="div-table-responsive">';
2028 print '<table class="tagtable nobottomiftotal liste' . ($moreforfilter ? " listwithfilterbefore" : "") . '">' . "\n";
2029
2030 // Fields title search
2031 // --------------------------------------------------------------------
2032 print '<tr class="liste_titre_filter">';
2033 // Action column
2034 if ($conf->main_checkbox_left_column) {
2035 print '<td class="liste_titre center">';
2036 $searchpicto = $form->showFilterButtons('left');
2037 print $searchpicto;
2038 print '</td>';
2039 }
2040 // Date
2041 if (!empty($arrayfields['t.element_date']['checked'])) {
2042 print '<td class="liste_titre left">';
2043 print '<div class="nowrapfordate paddingright">';
2044 print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
2045 print '</div>';
2046 print '<div class="nowrapfordate">';
2047 print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
2048 print '</div>';
2049 print '</td>';
2050 }
2051 // Thirdparty
2052 if (!empty($arrayfields['p.fk_soc']['checked'])) {
2053 print '<td class="liste_titre"><input type="text" class="flat maxwidth100" name="$search_company" value="' . dol_escape_htmltag($search_company) . '"></td>';
2054 }
2055
2056 // Thirdparty alias
2057 if (!empty($arrayfields['s.name_alias']['checked'])) {
2058 print '<td class="liste_titre"><input type="text" class="flat maxwidth100" name="$search_company_alias" value="' . dol_escape_htmltag($search_company_alias) . '"></td>';
2059 }
2060
2061 if (!empty($allprojectforuser)) {
2062 if (!empty($arrayfields['p.project_ref']['checked'])) {
2063 print '<td class="liste_titre"><input type="text" class="flat maxwidth100" name="$search_project_ref" value="' . dol_escape_htmltag($search_project_ref) . '"></td>';
2064 }
2065 if (!empty($arrayfields['p.project_label']['checked'])) {
2066 print '<td class="liste_titre"><input type="text" class="flat maxwidth100" name="$search_project_label" value="' . dol_escape_htmltag($search_project_label) . '"></td>';
2067 }
2068 }
2069 // Task
2070 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2071 if (!empty($arrayfields['t.element_ref']['checked'])) {
2072 print '<td class="liste_titre"><input type="text" class="flat maxwidth75" name="search_task_ref" value="'.dol_escape_htmltag($search_task_ref).'"></td>';
2073 }
2074 if (!empty($arrayfields['t.element_label']['checked'])) {
2075 print '<td class="liste_titre"><input type="text" class="flat maxwidth100" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
2076 }
2077 }
2078 // Author
2079 if (!empty($arrayfields['author']['checked'])) {
2080 print '<td class="liste_titre">'.$form->select_dolusers(($search_user > 0 ? $search_user : -1), 'search_user', 1, null, 0, '', '', '0', 0, 0, '', 0, '', 'maxwidth125').'</td>';
2081 }
2082 // Note
2083 if (!empty($arrayfields['t.note']['checked'])) {
2084 print '<td class="liste_titre"><input type="text" class="flat maxwidth75" name="search_note" value="' . dol_escape_htmltag($search_note) . '"></td>';
2085 }
2086 // Last modification
2087 if (!empty($arrayfields['t.tms']['checked'])) {
2088 print '<td class="liste_titre"></td>';
2089 }
2090 // Duration
2091 if (!empty($arrayfields['t.element_duration']['checked'])) {
2092 // Duration - Time spent
2093 print '<td class="liste_titre right">';
2094
2095 $durationtouse_start = '';
2096 if ($search_timespent_starthour || $search_timespent_startmin) {
2097 $durationtouse_start = ($search_timespent_starthour * 3600 + $search_timespent_startmin * 60);
2098 }
2099 print '<div class="nowraponall"><span class="opacitymedium">' . $langs->trans('fromhour') . '</span> ';
2100 print $form->select_duration('search_timespent_duration_start', $durationtouse_start, 0, 'text', 0, 1);
2101 print '</div>';
2102
2103 $durationtouse_end = '';
2104 if ($search_timespent_endhour || $search_timespent_endmin) {
2105 $durationtouse_end = ($search_timespent_endhour * 3600 + $search_timespent_endmin * 60);
2106 }
2107 print '<div class="nowraponall"><span class="opacitymedium">' . $langs->trans('tohour') . '</span> ';
2108 print $form->select_duration('search_timespent_duration_end', $durationtouse_end, 0, 'text', 0, 1);
2109 print '</div>';
2110
2111 print '</td>';
2112 }
2113 // Product
2114 if (!empty($arrayfields['t.fk_product']['checked'])) {
2115 print '<td class="liste_titre"></td>';
2116 }
2117 // Value in main currency
2118 if (!empty($arrayfields['value']['checked'])) {
2119 print '<td class="liste_titre"></td>';
2120 }
2121 // Value billed
2122 if (!empty($arrayfields['valuebilled']['checked'])) {
2123 print '<td class="liste_titre center">' . $form->selectyesno('search_valuebilled', $search_valuebilled, 1, false, 1) . '</td>';
2124 }
2125
2126 // Extra fields
2127 $extrafieldsobjectkey = 'projet_task';
2128 $extrafieldsobjectprefix = 'ef.';
2129 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
2130 // Fields from hook
2131 $parameters = array('arrayfields' => $arrayfields);
2132 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2133 print $hookmanager->resPrint;
2134 // Action column
2135 if (!$conf->main_checkbox_left_column) {
2136 print '<td class="liste_titre center">';
2137 $searchpicto = $form->showFilterButtons();
2138 print $searchpicto;
2139 print '</td>';
2140 }
2141 print '</tr>' . "\n";
2142
2143
2144 $totalarray = array();
2145 $totalarray['nbfield'] = 0;
2146
2147 // Fields title label
2148 // --------------------------------------------------------------------
2149 print '<tr class="liste_titre">';
2150 if ($conf->main_checkbox_left_column) {
2151 print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center maxwidthsearch ');
2152 $totalarray['nbfield']++;
2153 }
2154 if (!empty($arrayfields['t.element_date']['checked'])) {
2155 print_liste_field_titre($arrayfields['t.element_date']['label'], $_SERVER['PHP_SELF'], 't.element_date,t.element_datehour,t.rowid', '', $param, '', $sortfield, $sortorder);
2156 $totalarray['nbfield']++;
2157 }
2158 if (!empty($arrayfields['p.fk_soc']['checked'])) {
2159 print_liste_field_titre($arrayfields['p.fk_soc']['label'], $_SERVER['PHP_SELF'], 't.element_date,t.element_datehour,t.rowid', '', $param, '', $sortfield, $sortorder);
2160 $totalarray['nbfield']++;
2161 }
2162 if (!empty($arrayfields['s.name_alias']['checked'])) {
2163 // @phan-suppress-next-line PhanTypeInvalidDimOffset
2164 print_liste_field_titre($arrayfields['s.name_alias']['label'], $_SERVER['PHP_SELF'], 's.name_alias', '', $param, '', $sortfield, $sortorder);
2165 $totalarray['nbfield']++;
2166 }
2167 if (!empty($allprojectforuser)) {
2168 if (!empty($arrayfields['p.project_ref']['checked'])) {
2169 print_liste_field_titre($arrayfields['p.project_ref']['label'], $_SERVER['PHP_SELF'], 'p.ref', '', $param, '', $sortfield, $sortorder);
2170 $totalarray['nbfield']++;
2171 }
2172 if (!empty($arrayfields['p.project_label']['checked'])) {
2173 print_liste_field_titre($arrayfields['p.project_label']['label'], $_SERVER['PHP_SELF'], 'p.title', '', $param, '', $sortfield, $sortorder);
2174 $totalarray['nbfield']++;
2175 }
2176 }
2177 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2178 if (!empty($arrayfields['t.element_ref']['checked'])) {
2179 print_liste_field_titre($arrayfields['t.element_ref']['label'], $_SERVER['PHP_SELF'], 'pt.ref', '', $param, '', $sortfield, $sortorder);
2180 $totalarray['nbfield']++;
2181 }
2182 if (!empty($arrayfields['t.element_label']['checked'])) {
2183 print_liste_field_titre($arrayfields['t.element_label']['label'], $_SERVER['PHP_SELF'], 'pt.label', '', $param, '', $sortfield, $sortorder);
2184 $totalarray['nbfield']++;
2185 }
2186 }
2187 if (!empty($arrayfields['author']['checked'])) {
2188 print_liste_field_titre($arrayfields['author']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder);
2189 $totalarray['nbfield']++;
2190 }
2191 if (!empty($arrayfields['t.note']['checked'])) {
2192 print_liste_field_titre($arrayfields['t.note']['label'], $_SERVER['PHP_SELF'], 't.note', '', $param, '', $sortfield, $sortorder);
2193 $totalarray['nbfield']++;
2194 }
2195 if (!empty($arrayfields['t.tms']['checked'])) {
2196 print_liste_field_titre($arrayfields['t.tms']['label'], $_SERVER['PHP_SELF'], 't.tms', '', $param, '', $sortfield, $sortorder);
2197 $totalarray['nbfield']++;
2198 }
2199 if (!empty($arrayfields['t.element_duration']['checked'])) {
2200 print_liste_field_titre($arrayfields['t.element_duration']['label'], $_SERVER['PHP_SELF'], 't.element_duration', '', $param, '', $sortfield, $sortorder, 'right ');
2201 $totalarray['nbfield']++;
2202 }
2203 if (!empty($arrayfields['t.fk_product']['checked'])) {
2204 print_liste_field_titre($arrayfields['t.fk_product']['label'], $_SERVER['PHP_SELF'], 't.fk_product', '', $param, '', $sortfield, $sortorder);
2205 $totalarray['nbfield']++;
2206 }
2207
2208 if (!empty($arrayfields['value']['checked'])) {
2209 print_liste_field_titre($arrayfields['value']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
2210 $totalarray['nbfield']++;
2211 }
2212 if (!empty($arrayfields['valuebilled']['checked'])) {
2213 print_liste_field_titre($arrayfields['valuebilled']['label'], $_SERVER['PHP_SELF'], 'il.total_ht', '', $param, '', $sortfield, $sortorder, 'center ', $langs->trans("SelectLinesOfTimeSpentToInvoice"));
2214 $totalarray['nbfield']++;
2215 }
2216 // Extra fields
2217 $extrafieldsobjectkey = 'projet_task';
2218 $extrafieldsobjectprefix = 'ef.';
2219 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
2220 // Hook fields
2221 $parameters = array('arrayfields' => $arrayfields, 'param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
2222 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2223 print $hookmanager->resPrint;
2224 if (!$conf->main_checkbox_left_column) {
2225 print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center maxwidthsearch ');
2226 $totalarray['nbfield']++;
2227 }
2228 print "</tr>\n";
2229
2230 $tasktmp = new Task($db);
2231 $tmpinvoice = new Facture($db);
2232
2233 if ($page) {
2234 $param .= '&page='.((int) $page);
2235 }
2236 $param .= '&sortfield='.urlencode($sortfield).'&sortorder='.urlencode($sortorder);
2237
2238 $i = 0;
2239
2240 $savnbfield = $totalarray['nbfield'];
2241 $totalarray = array();
2242 $totalarray['nbfield'] = 0;
2243 //$imaxinloop = ($limit ? min($num, $limit) : $num);
2244 foreach ($tasks as $task_time) {
2245 if ($i >= $limit) {
2246 break;
2247 }
2248
2249 // Line is invoiced if it has an invoice_id
2250 $invoiced = $task_time->invoice_id ? true : false;
2251
2252 $date1 = $db->jdate($task_time->element_date);
2253 $date2 = $db->jdate($task_time->element_datehour);
2254
2255 // Show here line of result
2256 $j = 0;
2257 print '<tr data-rowid="'.$task_time->rowid.'" class="oddeven">';
2258
2259 // Action column
2260 if ($conf->main_checkbox_left_column) {
2261 print '<td class="center nowraponall">';
2262 if (($action == 'editline' || $action == 'splitline') && GETPOSTINT('lineid') == $task_time->rowid) {
2263 print '<input type="hidden" name="lineid" value="' . GETPOSTINT('lineid') . '">';
2264 if ($id) {
2265 print '<input type="hidden" name="id" value="' . $id . '">'; // If you enable this, the edit will go beack to task view
2266 }
2267 print '<input type="submit" class="button buttongen reposition smallpaddingimp margintoponlyshort marginbottomonlyshort button-save" name="save" value="'.$langs->trans("Save").'">';
2268 print '<br>';
2269 print '<input type="submit" class="button buttongen reposition smallpaddingimp margintoponlyshort marginbottomonlyshort button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
2270 } elseif ($user->hasRight('projet', 'time') || $user->hasRight('projet', 'all', 'creer')) { // Read project and enter time consumed on assigned tasks
2271 if (in_array($task_time->fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) {
2272 print '<a class="reposition editfielda" href="'.$_SERVER["PHP_SELF"].'?'.($withproject ? 'id='.$task_time->fk_element : '').'&action=editline&token='.newToken().'&lineid='.$task_time->rowid.$param.((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '').'">';
2273 print img_edit('default', 0, 'class="pictofixedwidth paddingleft"');
2274 print '</a>';
2275
2276 if (getDolGlobalString('PROJECT_ALLOW_SPLIT_TIMESPENT')) {
2277 print '<a class="reposition editfielda paddingleft" href="' . $_SERVER["PHP_SELF"] . '?action=splitline&token=' . newToken() . '&lineid=' . $task_time->rowid . $param . ((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '') . '">';
2278 print img_split('', 'class="pictofixedwidth paddingleft"');
2279 print '</a>';
2280 }
2281
2282 print '<a class="reposition paddingleft" href="'.$_SERVER["PHP_SELF"].'?'.($withproject ? 'id='.$task_time->fk_element : '').'&action=deleteline&token='.newToken().'&lineid='.$task_time->rowid.$param.((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '').'">';
2283 print img_delete('default', 'class="pictodelete paddingleft"');
2284 print '</a>';
2285
2286 if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
2287 $selected = 0;
2288 if (in_array($task_time->rowid, $arrayofselected)) {
2289 $selected = 1;
2290 }
2291 print '&nbsp;';
2292
2293 // Disable select if task not billable or already invoiced
2294 $disabled = (intval($task_time->billable) != 1 || $invoiced);
2295 $ctrl = '<input '.($disabled ? 'disabled' : '').' id="cb' . $task_time->rowid . '" class="flat checkforselect marginleftonly" type="checkbox" name="toselect[]" value="' . $task_time->rowid . '"' . ($selected ? ' checked="checked"' : '') . '>';
2296 if ($disabled) {
2297 // If disabled, a dbl-click very close outside the control
2298 // will re-enable it, so that user is not blocked if needed.
2299 print '<span id="cbsp'. $task_time->rowid . '">'.$ctrl.'</span>';
2300 print '<script>$("#cbsp' . $task_time->rowid . '").dblclick(()=>{ $("#cb' . $task_time->rowid . '").removeAttr("disabled") })</script>';
2301 } else {
2302 print $ctrl;
2303 }
2304 }
2305 }
2306 }
2307 print '</td>';
2308 if (!$i) {
2309 $totalarray['nbfield']++;
2310 }
2311 }
2312
2313 // Date
2314 if (!empty($arrayfields['t.element_date']['checked'])) {
2315 print '<td class="nowrap">';
2316 if ($action == 'editline' && GETPOSTINT('lineid') == $task_time->rowid) {
2317 if (empty($task_time->element_date_withhour)) {
2318 print $form->selectDate(($date2 ? $date2 : $date1), 'timeline', 4, 3, 2, "timespent_date", 1, 0);
2319 } else {
2320 print $form->selectDate(($date2 ? $date2 : $date1), 'timeline', 2, 1, 2, "timespent_date", 1, 0);
2321 }
2322 } else {
2323 print dol_print_date(($date2 ? $date2 : $date1), ($task_time->element_date_withhour ? 'dayhour' : 'day'));
2324 }
2325 print '</td>';
2326 if (!$i) {
2327 $totalarray['nbfield']++;
2328 }
2329 }
2330
2331 // Thirdparty
2332 if (!empty($arrayfields['p.fk_soc']['checked'])) {
2333 print '<td class="tdoverflowmax125">';
2334 if ($task_time->fk_soc > 0) {
2335 if (empty($conf->cache['thirdparty'][$task_time->fk_soc])) {
2336 $tmpsociete = new Societe($db);
2337 $tmpsociete->fetch($task_time->fk_soc);
2338 $conf->cache['thirdparty'][$task_time->fk_soc] = $tmpsociete;
2339 } else {
2340 $tmpsociete = $conf->cache['thirdparty'][$task_time->fk_soc];
2341 }
2342 print $tmpsociete->getNomUrl(1, '', 100, 0, 1, empty($arrayfields['s.name_alias']['checked']) ? 0 : 1);
2343 }
2344 print '</td>';
2345 if (!$i) {
2346 $totalarray['nbfield']++;
2347 }
2348 }
2349
2350 // Thirdparty alias
2351 if (!empty($arrayfields['s.name_alias']['checked'])) {
2352 $valtoshow = '';
2353 if ($task_time->fk_soc > 0) {
2354 if (empty($conf->cache['thirdparty'][$task_time->fk_soc])) {
2355 $tmpsociete = new Societe($db);
2356 $tmpsociete->fetch($task_time->fk_soc);
2357 $conf->cache['thirdparty'][$task_time->fk_soc] = $tmpsociete;
2358 } else {
2359 $tmpsociete = $conf->cache['thirdparty'][$task_time->fk_soc];
2360 }
2361 $valtoshow = $tmpsociete->name_alias;
2362 }
2363 print '<td class="nowrap tdoverflowmax150" title="'.dol_escape_htmltag($valtoshow).'">';
2364 print $valtoshow;
2365 print '</td>';
2366 if (!$i) {
2367 $totalarray['nbfield']++;
2368 }
2369 }
2370
2371 if (!empty($allprojectforuser)) {
2372 // Project ref
2373 if (!empty($arrayfields['p.project_ref']['checked'])) {
2374 if (empty($conf->cache['project'][$task_time->fk_projet])) {
2375 $tmpproject = new Project($db);
2376 $tmpproject->fetch($task_time->fk_projet);
2377 $conf->cache['project'][$task_time->fk_projet] = $tmpproject;
2378 } else {
2379 $tmpproject = $conf->cache['project'][$task_time->fk_projet];
2380 }
2381 print '<td class="nowraponall">';
2382 print $tmpproject->getNomUrl(1);
2383 print '</td>';
2384 if (!$i) {
2385 $totalarray['nbfield']++;
2386 }
2387 }
2388 // Project label
2389 if (!empty($arrayfields['p.project_label']['checked'])) {
2390 if (empty($conf->cache['project'][$task_time->fk_projet])) {
2391 $tmpproject = new Project($db);
2392 $tmpproject->fetch($task_time->fk_projet);
2393 $conf->cache['project'][$task_time->fk_projet] = $tmpproject;
2394 } else {
2395 $tmpproject = $conf->cache['project'][$task_time->fk_projet];
2396 }
2397 print '<td class="tdoverflowmax250" title="'.dolPrintHTMLForAttribute($tmpproject->title).'">';
2398 if (!empty($arrayfields['p.project_ref']['checked'])) {
2399 print dolPrintHTML($tmpproject->title);
2400 } else {
2401 print $tmpproject->getNomUrl(1, '', -1);
2402 }
2403 print '</td>';
2404 if (!$i) {
2405 $totalarray['nbfield']++;
2406 }
2407 }
2408 }
2409
2410 // Task ref
2411 if (!empty($arrayfields['t.element_ref']['checked'])) {
2412 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2413 print '<td class="nowrap">';
2414 if ($action == 'editline' && GETPOSTINT('lineid') == $task_time->rowid) {
2415 $formproject->selectTasks(-1, GETPOSTINT('taskid') ? GETPOSTINT('taskid') : $task_time->fk_element, 'taskid', 0, 0, '1', 1, 0, 0, 'maxwidth250', (string) $projectstatic->id, '');
2416 } else {
2417 $tasktmp->id = $task_time->fk_element;
2418 $tasktmp->ref = $task_time->ref;
2419 $tasktmp->label = $task_time->label;
2420 print $tasktmp->getNomUrl(1, 'withproject', 'time');
2421 }
2422 print '</td>';
2423 if (!$i) {
2424 $totalarray['nbfield']++;
2425 }
2426 }
2427 } elseif ($action !== 'createtime') {
2428 print '<input type="hidden" name="taskid" value="' . $id . '">';
2429 }
2430
2431 // Task label
2432 if (!empty($arrayfields['t.element_label']['checked'])) {
2433 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2434 print '<td class="tdoverflowmax250" title="'.dolPrintHTMLForAttribute($task_time->label).'">';
2435 if (!empty($arrayfields['t.element_ref']['checked'])) {
2436 print dolPrintHTML($task_time->label);
2437 } else {
2438 $tasktmp->id = $task_time->fk_element;
2439 $tasktmp->ref = $task_time->ref;
2440 $tasktmp->label = $task_time->label;
2441 print $tasktmp->getNomUrl(1, 'withproject', 'time', -1);
2442 }
2443 print '</td>';
2444 if (!$i) {
2445 $totalarray['nbfield']++;
2446 }
2447 }
2448 }
2449
2450 // User
2451 if (!empty($arrayfields['author']['checked'])) {
2452 print '<td class="tdoverflowmax125">';
2453 if ($action == 'editline' && GETPOSTINT('lineid') == $task_time->rowid) {
2454 // Here $object is task. TODO Add a cache
2455 if (empty($object->id)) {
2456 $object->fetch($task_time->fk_element);
2457 }
2458 $contactsoftask = $object->getListContactId('internal');
2459 if (!in_array($task_time->fk_user, $contactsoftask)) {
2460 $contactsoftask[] = $task_time->fk_user;
2461 }
2462 if (count($contactsoftask) > 0) {
2463 print img_object('', 'user', 'class="pictofixedwidth hideonsmartphone"');
2464 print $form->select_dolusers($task_time->fk_user, 'userid_line', 0, null, 0, '', $contactsoftask, '0', 0, 0, '', 0, '', 'minwidth100 maxwidth100'); // maxwidth must be lowed than minwidth of the td
2465 } else {
2466 print img_error($langs->trans('FirstAddRessourceToAllocateTime')) . $langs->trans('FirstAddRessourceToAllocateTime');
2467 }
2468 } else {
2469 $userstatic->id = $task_time->fk_user;
2470 $userstatic->lastname = $task_time->lastname;
2471 $userstatic->firstname = $task_time->firstname;
2472 $userstatic->photo = $task_time->photo;
2473 $userstatic->gender = $task_time->gender;
2474 $userstatic->status = $task_time->user_status;
2475
2476 print $userstatic->getNomUrl(-1);
2477 }
2478 print '</td>';
2479 if (!$i) {
2480 $totalarray['nbfield']++;
2481 }
2482 }
2483
2484 // Note
2485 if (!empty($arrayfields['t.note']['checked'])) {
2486 if ($action == 'editline' && GETPOSTINT('lineid') == $task_time->rowid) {
2487 print '<td class="small">';
2488 print '<textarea name="timespent_note_line" class="centpercentimp" rows="' . ROWS_2 . '">' . dol_escape_htmltag($task_time->note, 0, 1) . '</textarea>';
2489 print '</td>';
2490 } else {
2491 print '<td class="small tdoverflowmax150 classfortooltip" title="'.dol_string_onlythesehtmltags(dol_htmlentitiesbr($task_time->note)).'">';
2492 print dolGetFirstLineOfText($task_time->note);
2493 print '</td>';
2494 }
2495 if (!$i) {
2496 $totalarray['nbfield']++;
2497 }
2498 } elseif ($action == 'editline' && GETPOSTINT('lineid') == $task_time->rowid) {
2499 print '<input type="hidden" name="timespent_note_line" value="' . dol_escape_htmltag($task_time->note, 0, 1) . '">';
2500 }
2501
2502 // Last modification
2503 if (!empty($arrayfields['t.tms']['checked'])) {
2504 print '<td class="nowraponall">';
2505 print dol_print_date($task_time->tms, 'dayhour');
2506 print '</td>';
2507 if (!$i) {
2508 $totalarray['nbfield']++;
2509 }
2510 }
2511
2512 // Time spent - Duration
2513 if (!empty($arrayfields['t.element_duration']['checked'])) {
2514 print '<td class="right nowraponall">';
2515 if ($action == 'editline' && GETPOSTINT('lineid') == $task_time->rowid) {
2516 print '<input type="hidden" name="old_duration" value="'.$task_time->element_duration.'">';
2517 print $form->select_duration('new_duration', $task_time->element_duration, 0, 'text');
2518 } else {
2519 print convertSecondToTime($task_time->element_duration, 'allhourmin');
2520 }
2521 print '</td>';
2522 if (!$i) {
2523 $totalarray['nbfield']++;
2524 }
2525 if (!$i) {
2526 $totalarray['pos'][$totalarray['nbfield']] = 't.element_duration';
2527 }
2528 if (empty($totalarray['val']['t.element_duration'])) {
2529 $totalarray['val']['t.element_duration'] = $task_time->element_duration;
2530 } else {
2531 $totalarray['val']['t.element_duration'] += $task_time->element_duration;
2532 }
2533 if (!$i) {
2534 $totalarray['totaldurationfield'] = $totalarray['nbfield'];
2535 }
2536 if (empty($totalarray['totalduration'])) {
2537 $totalarray['totalduration'] = $task_time->element_duration;
2538 } else {
2539 $totalarray['totalduration'] += $task_time->element_duration;
2540 }
2541 }
2542
2543 // Product
2544 if (!empty($arrayfields['t.fk_product']['checked'])) {
2545 print '<td class="nowraponall">';
2546 if ($action == 'editline' && GETPOSTINT('lineid') == $task_time->rowid) {
2547 print img_picto('', 'service');
2548 print $form->select_produits($task_time->fk_product, 'fk_product', 1, 0, $projectstatic->thirdparty->price_level, 1, 2, '', 1, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500', ($user->hasRight('produit', 'lire') ? 0 : 1), '', null, 1);
2549 } elseif (!empty($task_time->fk_product)) {
2550 $product = new Product($db);
2551 $resultFetch = $product->fetch($task_time->fk_product);
2552 if ($resultFetch < 0) {
2553 setEventMessages($product->error, $product->errors, 'errors');
2554 } else {
2555 print $product->getNomUrl(1);
2556 }
2557 }
2558 print '</td>';
2559 if (!$i) {
2560 $totalarray['nbfield']++;
2561 }
2562 }
2563
2564 // Value spent
2565 if (!empty($arrayfields['value']['checked'])) {
2566 $langs->load("salaries");
2567 $value = price2num($task_time->thm * $task_time->element_duration / 3600, 'MT', 1);
2568
2569 print '<td class="nowraponall right">';
2570 print '<span class="amount" title="' . $langs->trans("THM") . ': ' . price($task_time->thm) . '">';
2571 print price($value, 1, $langs, 1, -1, -1, $conf->currency);
2572 print '</span>';
2573 print '</td>';
2574 if (!$i) {
2575 $totalarray['nbfield']++;
2576 }
2577 if (!$i) {
2578 $totalarray['pos'][$totalarray['nbfield']] = 'value';
2579 }
2580 if (empty($totalarray['val']['value'])) {
2581 $totalarray['val']['value'] = $value;
2582 } else {
2583 $totalarray['val']['value'] += $value;
2584 }
2585 if (!$i) {
2586 $totalarray['totalvaluefield'] = $totalarray['nbfield'];
2587 }
2588 if (empty($totalarray['totalvalue'])) {
2589 $totalarray['totalvalue'] = $value;
2590 } else {
2591 $totalarray['totalvalue'] += $value;
2592 }
2593 }
2594
2595 // Value billed
2596 if (!empty($arrayfields['valuebilled']['checked'])) {
2597 print '<td class="center">'; // invoice_id and invoice_line_id
2598 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
2599 if ($projectstatic->usage_bill_time) {
2600 if ($task_time->invoice_id) {
2601 $result = $tmpinvoice->fetch($task_time->invoice_id);
2602 if ($result > 0) {
2603 if ($user->hasRight('facture', 'lire')) {
2604 if ($action == 'editline' && GETPOSTINT('lineid') == $task_time->rowid) {
2605 print $formproject->selectInvoiceAndLine($task_time->invoice_id, $task_time->invoice_line_id, 'invoiceid', 'invoicelineid', 'maxwidth500', array('p.rowid' => $projectstatic->id));
2606 } else {
2607 print $tmpinvoice->getNomUrl(1);
2608 if (!empty($task_time->invoice_line_id)) {
2609 $invoiceLine = new FactureLigne($db);
2610 $invoiceLine->fetch($task_time->invoice_line_id);
2611 if (!empty($invoiceLine->id)) {
2612 print '<br><span class="small opacitymedium">'.$langs->trans('Qty').':'.$invoiceLine->qty;
2613 print ' '.$langs->trans('TotalHT').':'.price($invoiceLine->total_ht);
2614 print '</span>';
2615 }
2616 }
2617 }
2618 } else {
2619 print $langs->trans("Yes");
2620 }
2621 }
2622 $invoiced = true;
2623 } else {
2624 if (intval($task_time->billable) == 1) {
2625 print $langs->trans("No");
2626 } else {
2627 print $langs->trans("Disabled");
2628 }
2629 }
2630 } else {
2631 print '<span class="opacitymedium">' . $langs->trans("NA") . '</span>';
2632 }
2633 }
2634 print '</td>';
2635 if (!$i) {
2636 $totalarray['nbfield']++;
2637 }
2638 }
2639
2640 // Extra fields
2641 $obj = $task_time;
2642 $extrafieldsobjectkey = 'projet_task';
2643 $extrafieldsobjectprefix = 'ef.';
2644 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
2645
2646 // Fields from hook
2647 $parameters = array('arrayfields' => $arrayfields, 'obj' => $task_time, 'i' => $i, 'totalarray' => &$totalarray);
2648 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2649 print $hookmanager->resPrint;
2650
2651 // Action column
2652 if (!$conf->main_checkbox_left_column) {
2653 print '<td class="center nowraponall">';
2654 if (($action == 'editline' || $action == 'splitline') && GETPOSTINT('lineid') == $task_time->rowid) {
2655 print '<input type="hidden" name="lineid" value="'.GETPOSTINT('lineid').'">';
2656 print '<input type="submit" class="button buttongen smallpaddingimp margintoponlyshort marginbottomonlyshort button-save" name="save" value="'.$langs->trans("Save").'">';
2657 print '<br>';
2658 print '<input type="submit" class="button buttongen smallpaddingimp margintoponlyshort marginbottomonlyshort button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
2659 } elseif ($user->hasRight('projet', 'time') || $user->hasRight('projet', 'all', 'creer')) { // Read project and enter time consumed on assigned tasks
2660 if (in_array($task_time->fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) {
2661 print '<a class="reposition editfielda" href="'.$_SERVER["PHP_SELF"].'?'.($withproject ? 'id='.$task_time->fk_element : '').'&action=editline&token='.newToken().'&lineid='.$task_time->rowid.$param.((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '').'">';
2662 print img_edit('default', 0, 'class="pictofixedwidth paddingleft"');
2663 print '</a>';
2664
2665 if (getDolGlobalString('PROJECT_ALLOW_SPLIT_TIMESPENT')) {
2666 print '<a class="reposition editfielda paddingleft" href="' . $_SERVER["PHP_SELF"] . '?action=splitline&token=' . newToken() . '&lineid=' . $task_time->rowid . $param . ((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '') . '">';
2667 print img_split('', 'class="pictofixedwidth paddingleft"');
2668 print '</a>';
2669 }
2670
2671 print '<a class="reposition paddingleft" href="'.$_SERVER["PHP_SELF"].'?'.($withproject ? 'id='.$task_time->fk_element : '').'&action=deleteline&token='.newToken().'&lineid='.$task_time->rowid.$param.((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '').'">';
2672 print img_delete('default', 'class="pictodelete paddingleft"');
2673 print '</a>';
2674
2675 if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
2676 $selected = 0;
2677 if (in_array($task_time->rowid, $arrayofselected)) {
2678 $selected = 1;
2679 }
2680 print '&nbsp;';
2681
2682 // Disable select if task not billable or already invoiced
2683 $disabled = (intval($task_time->billable) != 1 || $invoiced);
2684 $ctrl = '<input '.($disabled ? 'disabled' : '').' id="cb' . $task_time->rowid . '" class="flat checkforselect marginleftonly" type="checkbox" name="toselect[]" value="' . $task_time->rowid . '"' . ($selected ? ' checked="checked"' : '') . '>';
2685 if ($disabled) {
2686 // If disabled, a dbl-click very close outside the control
2687 // will re-enable it, so that user is not blocked if needed.
2688 print '<span id="cbsp'. $task_time->rowid . '">'.$ctrl.'</span>';
2689 print '<script>$("#cbsp' . $task_time->rowid . '").dblclick(()=>{ $("#cb' . $task_time->rowid . '").removeAttr("disabled") })</script>';
2690 } else {
2691 print $ctrl;
2692 }
2693 }
2694 }
2695 }
2696 print '</td>';
2697 if (!$i) {
2698 $totalarray['nbfield']++;
2699 }
2700 }
2701
2702 print "</tr>\n";
2703
2704
2705 // Add the lines for the split feature
2706
2707 if ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2708 print '<!-- first line -->';
2709 print '<tr class="oddeven">';
2710
2711 // Action column
2712 if ($conf->main_checkbox_left_column) {
2713 print '<td></td>';
2714 }
2715
2716 // Date
2717 if (!empty($arrayfields['t.element_date']['checked'])) {
2718 print '<td class="nowrap">';
2719 if ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2720 if (empty($task_time->element_date_withhour)) {
2721 print $form->selectDate(($date2 ? $date2 : $date1), 'timeline', 3, 3, 2, "timespent_date", 1, 0);
2722 } else {
2723 print $form->selectDate(($date2 ? $date2 : $date1), 'timeline', 1, 1, 2, "timespent_date", 1, 0);
2724 }
2725 } else {
2726 print dol_print_date(($date2 ? $date2 : $date1), ($task_time->element_date_withhour ? 'dayhour' : 'day'));
2727 }
2728 print '</td>';
2729 }
2730
2731 // Thirdparty
2732 if (!empty($arrayfields['p.fk_soc']['checked'])) {
2733 print '<td class="nowrap">';
2734 print '</td>';
2735 }
2736
2737 // Thirdparty alias
2738 if (!empty($arrayfields['s.name_alias']['checked'])) {
2739 print '<td class="nowrap">';
2740 print '</td>';
2741 }
2742
2743 // Project ref
2744 if (!empty($allprojectforuser)) {
2745 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2746 print '<td class="nowrap">';
2747 print '</td>';
2748 }
2749 }
2750
2751 // Task ref
2752 if (!empty($arrayfields['t.element_ref']['checked'])) {
2753 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2754 print '<td class="nowrap">';
2755 $tasktmp->id = $task_time->fk_element;
2756 $tasktmp->ref = $task_time->ref;
2757 $tasktmp->label = $task_time->label;
2758 print $tasktmp->getNomUrl(1, 'withproject', 'time');
2759 print '</td>';
2760 }
2761 }
2762
2763 // Task label
2764 if (!empty($arrayfields['t.element_label']['checked'])) {
2765 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2766 print '<td class="tdoverflowmax300" title="'.dol_escape_htmltag($task_time->label).'">';
2767 print dol_escape_htmltag($task_time->label);
2768 print '</td>';
2769 }
2770 }
2771
2772 // User
2773 if (!empty($arrayfields['author']['checked'])) {
2774 print '<td class="nowraponall">';
2775 if ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2776 if (empty($object->id)) {
2777 $idTask = (!empty($id)) ? $id : $task_time->fk_element;
2778 $object->fetch($idTask);
2779 }
2780 $contactsoftask = $object->getListContactId('internal');
2781 if (!in_array($task_time->fk_user, $contactsoftask)) {
2782 $contactsoftask[] = $task_time->fk_user;
2783 }
2784 if (count($contactsoftask) > 0) {
2785 print img_object('', 'user', 'class="hideonsmartphone"');
2786 print $form->select_dolusers($task_time->fk_user, 'userid_line', 0, null, 0, '', $contactsoftask);
2787 } else {
2788 print img_error($langs->trans('FirstAddRessourceToAllocateTime')) . $langs->trans('FirstAddRessourceToAllocateTime');
2789 }
2790 } else {
2791 $userstatic->id = $task_time->fk_user;
2792 $userstatic->lastname = $task_time->lastname;
2793 $userstatic->firstname = $task_time->firstname;
2794 $userstatic->photo = $task_time->photo;
2795 $userstatic->status = $task_time->user_status;
2796 print $userstatic->getNomUrl(-1);
2797 }
2798 print '</td>';
2799 }
2800
2801 // Note
2802 if (!empty($arrayfields['t.note']['checked'])) {
2803 print '<td class="tdoverflowmax300">';
2804 if ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2805 print '<textarea name="timespent_note_line" class="centpercentimp" rows="' . ROWS_2 . '">' . dol_escape_htmltag($task_time->note, 0, 1) . '</textarea>';
2806 } else {
2807 print dol_nl2br($task_time->note);
2808 }
2809 print '</td>';
2810 } elseif ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2811 print '<input type="hidden" name="timespent_note_line" rows="' . ROWS_2 . '" value="' . dol_escape_htmltag($task_time->note, 0, 1) . '">';
2812 }
2813
2814 // Last modification
2815 if (!empty($arrayfields['t.tms']['checked'])) {
2816 print '<td class="nowraponall">';
2817 print '</td>';
2818 }
2819
2820 // Time spent - duration
2821 if (!empty($arrayfields['t.element_duration']['checked'])) {
2822 print '<td class="right">';
2823 if ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2824 print '<input type="hidden" name="old_duration" value="'.$task_time->element_duration.'">';
2825 print $form->select_duration('new_duration', $task_time->element_duration, 0, 'text');
2826 } else {
2827 print convertSecondToTime($task_time->element_duration, 'allhourmin');
2828 }
2829 print '</td>';
2830 }
2831
2832 // Product
2833 if (!empty($arrayfields['t.fk_product']['checked'])) {
2834 print '<td class="nowraponall tdoverflowmax125">';
2835 print '</td>';
2836 }
2837
2838 // Value spent
2839 if (!empty($arrayfields['value']['checked'])) {
2840 print '<td class="right">';
2841 print '<span class="amount">';
2842 $value = price2num($task_time->thm * $task_time->element_duration / 3600, 'MT', 1);
2843 print price($value, 1, $langs, 1, -1, -1, $conf->currency);
2844 print '</span>';
2845 print '</td>';
2846 }
2847
2848 // Value billed
2849 if (!empty($arrayfields['valuebilled']['checked'])) {
2850 print '<td class="right">';
2851 $valuebilled = price2num($task_time->total_ht, '', 1);
2852 if (isset($task_time->total_ht)) {
2853 print price($valuebilled, 1, $langs, 1, -1, -1, $conf->currency);
2854 }
2855 print '</td>';
2856 }
2857
2858 // Extra fields
2859 $obj = $task_time;
2860 $extrafieldsobjectkey = 'projet_task';
2861 $extrafieldsobjectprefix = 'ef.';
2862 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
2863
2864 // Fields from hook
2865 $parameters = array('arrayfields' => $arrayfields, 'obj' => $task_time, 'mode' => 'split1');
2866 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2867 print $hookmanager->resPrint;
2868
2869 // Action column
2870 if (!$conf->main_checkbox_left_column) {
2871 print '<td class="center nowraponall">';
2872 print '</td>';
2873 }
2874
2875 print "</tr>\n";
2876
2877
2878 // Line for second dispatching
2879
2880 print '<!-- second line --><tr class="oddeven">';
2881
2882 // Action column
2883 if ($conf->main_checkbox_left_column) {
2884 print '<td class="center nowraponall">';
2885 print '</td>';
2886 }
2887
2888 // Date
2889 if (!empty($arrayfields['t.element_date']['checked'])) {
2890 print '<td class="nowraponall">';
2891 if ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2892 if (empty($task_time->element_date_withhour)) {
2893 print $form->selectDate(($date2 ? $date2 : $date1), 'timeline_2', 3, 3, 2, "timespent_date", 1, 0);
2894 } else {
2895 print $form->selectDate(($date2 ? $date2 : $date1), 'timeline_2', 1, 1, 2, "timespent_date", 1, 0);
2896 }
2897 } else {
2898 print dol_print_date(($date2 ? $date2 : $date1), ($task_time->element_date_withhour ? 'dayhour' : 'day'));
2899 }
2900 print '</td>';
2901 }
2902
2903 // Thirdparty
2904 if (!empty($arrayfields['p.fk_soc']['checked'])) {
2905 print '<td>';
2906 print '</td>';
2907 }
2908
2909 // Thirdparty alias
2910 if (!empty($arrayfields['s.name_alias']['checked'])) {
2911 print '<td>';
2912 print '</td>';
2913 }
2914
2915 // Project ref
2916 if (!empty($allprojectforuser)) {
2917 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2918 print '<td>';
2919 print '</td>';
2920 }
2921 }
2922
2923 // Task ref
2924 if (!empty($arrayfields['t.element_ref']['checked'])) {
2925 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2926 print '<td class="nowraponall">';
2927 $tasktmp->id = $task_time->fk_element;
2928 $tasktmp->ref = $task_time->ref;
2929 $tasktmp->label = $task_time->label;
2930 print $tasktmp->getNomUrl(1, 'withproject', 'time');
2931 print '</td>';
2932 }
2933 }
2934
2935 // Task label
2936 if (!empty($arrayfields['t.element_label']['checked'])) {
2937 if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task
2938 print '<td class="tdoverflowmax125" title="'.dol_escape_htmltag($task_time->label).'">';
2939 print dol_escape_htmltag($task_time->label);
2940 print '</td>';
2941 }
2942 }
2943
2944 // User
2945 if (!empty($arrayfields['author']['checked'])) {
2946 print '<td class="nowraponall tdoverflowmax100">';
2947 if ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2948 if (empty($object->id)) {
2949 $idTask = (!empty($id)) ? $id : $task_time->fk_element;
2950 $object->fetch($idTask);
2951 }
2952 $contactsoftask = $object->getListContactId('internal');
2953 if (!in_array($task_time->fk_user, $contactsoftask)) {
2954 $contactsoftask[] = $task_time->fk_user;
2955 }
2956 if (count($contactsoftask) > 0) {
2957 print img_object('', 'user', 'class="hideonsmartphone"');
2958 print $form->select_dolusers($task_time->fk_user, 'userid_line_2', 0, null, 0, '', $contactsoftask);
2959 } else {
2960 print img_error($langs->trans('FirstAddRessourceToAllocateTime')) . $langs->trans('FirstAddRessourceToAllocateTime');
2961 }
2962 } else {
2963 $userstatic->id = $task_time->fk_user;
2964 $userstatic->lastname = $task_time->lastname;
2965 $userstatic->firstname = $task_time->firstname;
2966 $userstatic->photo = $task_time->photo;
2967 $userstatic->status = $task_time->user_status;
2968 print $userstatic->getNomUrl(-1);
2969 }
2970 print '</td>';
2971 }
2972
2973 // Note
2974 if (!empty($arrayfields['t.note']['checked'])) {
2975 print '<td class="small tdoverflowmax300"">';
2976 if ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2977 print '<textarea name="timespent_note_line_2" class="centpercentimp" rows="' . ROWS_2 . '">' . dol_escape_htmltag($task_time->note, 0, 1) . '</textarea>';
2978 } else {
2979 print dol_nl2br($task_time->note);
2980 }
2981 print '</td>';
2982 } elseif ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2983 print '<input type="hidden" name="timespent_note_line_2" value="' . dol_escape_htmltag($task_time->note, 0, 1) . '">';
2984 }
2985
2986 // Last modification
2987 if (!empty($arrayfields['t.tms']['checked'])) {
2988 print '<td class="nowraponall">';
2989 print dol_print_date($task_time->tms, 'dayhour');
2990 print '</td>';
2991 }
2992
2993 // Time spent - duration
2994 if (!empty($arrayfields['t.element_duration']['checked'])) {
2995 print '<td class="right">';
2996 if ($action == 'splitline' && GETPOSTINT('lineid') == $task_time->rowid) {
2997 print '<input type="hidden" name="old_duration_2" value="0">';
2998 print $form->select_duration('new_duration_2', 0, 0, 'text');
2999 } else {
3000 print convertSecondToTime($task_time->element_duration, 'allhourmin');
3001 }
3002 print '</td>';
3003 }
3004
3005 // Product
3006 if (!empty($arrayfields['t.fk_product']['checked'])) {
3007 print '<td class="nowraponall tdoverflowmax125">';
3008 print '</td>';
3009 }
3010
3011 // Value spent - duration
3012 if (!empty($arrayfields['value']['checked'])) {
3013 print '<td class="right">';
3014 print '<span class="amount nowraponall">';
3015 $value = 0;
3016 print price($value, 1, $langs, 1, -1, -1, $conf->currency);
3017 // Note: On the transverse project view, we also have a warning if value is zero here
3018 print '</span>';
3019 print '</td>';
3020 }
3021
3022 // Value billed
3023 if (!empty($arrayfields['valuebilled']['checked'])) {
3024 print '<td class="right">';
3025 if (isset($task_time->total_ht)) {
3026 $valuebilled = price2num($task_time->total_ht, '', 1);
3027 print '<span class="amount nowraponall small">';
3028 print price($valuebilled, 1, $langs, 1, -1, -1, $conf->currency);
3029 print '</span>';
3030 }
3031 print '</td>';
3032 }
3033
3034 // Extra fields
3035 $obj = $task_time;
3036 $extrafieldsobjectkey = 'projet_task';
3037 $extrafieldsobjectprefix = 'ef.';
3038 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
3039
3040 // Fields from hook
3041 $parameters = array('arrayfields' => $arrayfields, 'obj' => $task_time, 'mode' => 'split2');
3042 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3043 print $hookmanager->resPrint;
3044
3045 // Action column
3046 if (!$conf->main_checkbox_left_column) {
3047 print '<td class="center nowraponall">';
3048 print '</td>';
3049 }
3050
3051 print "</tr>\n";
3052 }
3053
3054 $i++;
3055 }
3056
3057 // Show total line
3058 //include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php';
3059 if (isset($totalarray['totaldurationfield']) || isset($totalarray['totalvaluefield'])) {
3060 print '<tr class="liste_total">';
3061 $i = 0;
3062 while ($i < $totalarray['nbfield']) {
3063 $i++;
3064 if ($i == 1) {
3065 if ($num < $limit && empty($offset)) {
3066 print '<td class="left">' . $langs->trans("Total") . '</td>';
3067 } else {
3068 print '<td class="left">'.$form->textwithpicto($langs->trans("Total"), $langs->trans("Totalforthispage")).'</td>';
3069 }
3070 } elseif (isset($totalarray['totaldurationfield']) && $totalarray['totaldurationfield'] == $i) {
3071 print '<td class="right">' . convertSecondToTime($totalarray['totalduration'], 'allhourmin') . '</td>';
3072 } elseif (isset($totalarray['totalvaluefield']) && $totalarray['totalvaluefield'] == $i) {
3073 print '<td class="right">' . price($totalarray['totalvalue']) . '</td>';
3074 //} elseif ($totalarray['totalvaluebilledfield'] == $i) { print '<td class="center">'.price($totalarray['totalvaluebilled']).'</td>';
3075 } else {
3076 print '<td></td>';
3077 }
3078 }
3079 print '</tr>';
3080 }
3081
3082 if (!count($tasks)) {
3083 $totalnboffields = 1;
3084 foreach ($arrayfields as $value) {
3085 if (!empty($value['checked'])) {
3086 $totalnboffields++;
3087 }
3088 }
3089 print '<tr class="oddeven"><td colspan="' . $totalnboffields . '">';
3090 print '<span class="opacitymedium">' . $langs->trans("None") . '</span>';
3091 print '</td></tr>';
3092 }
3093
3094 $parameters = array('arrayfields' => $arrayfields, 'sql' => $sql);
3095 $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3096 print $hookmanager->resPrint;
3097
3098 print "</table>";
3099 print '</div>';
3100 print "</form>";
3101 }
3102}
3103
3104// End of page
3105llxFooter();
3106$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Class to manage standard extra fields.
Class to manage invoices.
Class to manage invoice lines.
Class to manage generation of HTML components Only common components must be here.
Class to manage generation of HTML components for intervention module.
Class to help generate other html components Only common components are here.
Class to manage building of HTML components.
Class to manage products or services.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage tasks.
Class for TimeSpent.
Class to manage Dolibarr users.
global $mysoc
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:391
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:253
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
$date_start
Variables from include:
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
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) If ...
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
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.
natural_search($fields, $value, $mode=0, $nofirstand=0, $sqltoadd='')
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
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...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
print_liste_field_titre($name, $file="", $field="", $begin="", $param="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
Definition html.lib.php:540
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.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
Definition html.lib.php:738
img_split($titlealt='default', $other='class="pictosplit"')
Show split logo.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Definition html.lib.php:181
task_prepare_head($object)
Prepare array with list of tabs.
project_prepare_head(Project $project, $moreparam='')
Prepare array with list of tabs.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $nodie=0, $mode='')
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.