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