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