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