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