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