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