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