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