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