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