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