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