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