dolibarr 24.0.0-beta
tasks.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2019 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
28require "../main.inc.php";
29require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
30require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
31require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
32require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
35require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
36if (isModEnabled('category')) {
37 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
38}
39
48// Load translation files required by the page
49$langsLoad = array('projects', 'users', 'companies');
50if (isModEnabled('eventorganization')) {
51 $langsLoad[] = 'eventorganization';
52}
53
54$langs->loadLangs($langsLoad);
55
56$action = GETPOST('action', 'aZ09');
57$massaction = GETPOST('massaction', 'alpha');
58//$show_files = GETPOSTINT('show_files');
59$confirm = GETPOST('confirm', 'alpha');
60$cancel = GETPOST('cancel');
61$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'projecttasklist';
62$backtopage = GETPOST('backtopage', 'alpha'); // if not set, a default page will be used
63//$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); // if not set, $backtopage will be used
64$optioncss = GETPOST('optioncss', 'aZ');
65$backtopage = GETPOST('backtopage', 'alpha');
66$toselect = GETPOST('toselect', 'array:int');
67
68$id = GETPOSTINT('id');
69$ref = GETPOST('ref', 'alpha');
70$taskref = GETPOST('taskref', 'alpha');
71
72// Load variable for pagination
73$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
74$sortfield = GETPOST('sortfield', 'aZ09comma');
75$sortorder = GETPOST('sortorder', 'aZ09comma');
76$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
77if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) {
78 $page = 0;
79} // If $page is not defined, or '' or -1 or if we click on clear filters
80$offset = $limit * $page;
81$pageprev = $page - 1;
82$pagenext = $page + 1;
83
84$search_user_id = GETPOSTINT('search_user_id');
85$search_taskref = GETPOST('search_taskref');
86$search_tasklabel = GETPOST('search_tasklabel');
87$search_taskdescription = GETPOST('search_taskdescription');
88$search_dtstartday = GETPOST('search_dtstartday');
89$search_dtstartmonth = GETPOST('search_dtstartmonth');
90$search_dtstartyear = GETPOST('search_dtstartyear');
91$search_dtendday = GETPOST('search_dtendday');
92$search_dtendmonth = GETPOST('search_dtendmonth');
93$search_dtendyear = GETPOST('search_dtendyear');
94$search_planedworkload = GETPOST('search_planedworkload');
95$search_timespend = GETPOST('search_timespend');
96$search_progresscalc = GETPOST('search_progresscalc');
97$search_progressdeclare = GETPOST('search_progressdeclare');
98$search_task_budget_amount = GETPOST('search_task_budget_amount');
99$search_task_billable = GETPOST('search_task_billable');
100$search_status = GETPOST('search_status');
101
102$search_date_start_startmonth = GETPOSTINT('search_date_start_startmonth');
103$search_date_start_startyear = GETPOSTINT('search_date_start_startyear');
104$search_date_start_startday = GETPOSTINT('search_date_start_startday');
105$search_date_start_start = dol_mktime(0, 0, 0, $search_date_start_startmonth, $search_date_start_startday, $search_date_start_startyear); // Use tzserver
106$search_date_start_endmonth = GETPOSTINT('search_date_start_endmonth');
107$search_date_start_endyear = GETPOSTINT('search_date_start_endyear');
108$search_date_start_endday = GETPOSTINT('search_date_start_endday');
109$search_date_start_end = dol_mktime(23, 59, 59, $search_date_start_endmonth, $search_date_start_endday, $search_date_start_endyear); // Use tzserver
110
111$search_date_end_startmonth = GETPOSTINT('search_date_end_startmonth');
112$search_date_end_startyear = GETPOSTINT('search_date_end_startyear');
113$search_date_end_startday = GETPOSTINT('search_date_end_startday');
114$search_date_end_start = dol_mktime(0, 0, 0, $search_date_end_startmonth, $search_date_end_startday, $search_date_end_startyear); // Use tzserver
115$search_date_end_endmonth = GETPOSTINT('search_date_end_endmonth');
116$search_date_end_endyear = GETPOSTINT('search_date_end_endyear');
117$search_date_end_endday = GETPOSTINT('search_date_end_endday');
118$search_date_end_end = dol_mktime(23, 59, 59, $search_date_end_endmonth, $search_date_end_endday, $search_date_end_endyear); // Use tzserver
119
120$object = new Project($db);
121$taskstatic = new Task($db);
122$extrafields = new ExtraFields($db);
123
124include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'
125if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_PROJECT') && method_exists($object, 'fetchComments') && empty($object->comments)) {
126 $object->fetchComments();
127}
128
129if ($id > 0 || !empty($ref)) {
130 // fetch optionals attributes and labels
131 $extrafields->fetch_name_optionals_label($object->table_element);
132 $object->fetch_optionals();
133}
134$extrafields->fetch_name_optionals_label($taskstatic->table_element);
135$search_array_options = $extrafields->getOptionalsFromPost($taskstatic->table_element, '', 'search_');
136
137// Default to no permission
138$permissiontoread = 0;
139$permissiontodelete = 0;
140
141// Default sort order (if not yet defined by previous GETPOST)
142/* if (!$sortfield) {
143 reset($object->fields); $sortfield="t.".key($object->fields);
144} // Set here default search field. By default 1st field in definition. Reset is required to avoid key() to return null.
145if (!$sortorder) {
146 $sortorder = "ASC";
147} */
148
149
150// Security check
151$socid = 0;
152
153// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
154$hookmanager->initHooks(array('projecttaskscard', 'globalcard'));
155
156//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.
157$result = restrictedArea($user, 'projet', $id, 'projet&project');
158
159$permissiontoadd = $user->hasRight('projet', 'creer');
160$permissiontoeditextra = $permissiontoadd;
161if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
162 $permissiontoeditextra = dol_eval((string) $extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
163}
164
165$diroutputmassaction = $conf->project->dir_output.'/tasks/temp/massgeneration/'.$user->id;
166
167$progress = GETPOSTINT('progress');
168$budget_amount = GETPOSTFLOAT('budget_amount');
169$billable = (GETPOST('billable', 'aZ') == 'yes' ? 1 : 0);
170$label = GETPOST('label', 'alpha');
171$description = GETPOST('description', 'restricthtml');
172$planned_workloadhour = (GETPOSTISSET('planned_workloadhour') ? GETPOSTINT('planned_workloadhour') : '');
173$planned_workloadmin = (GETPOSTISSET('planned_workloadmin') ? GETPOSTINT('planned_workloadmin') : '');
174if (GETPOSTISSET('planned_workloadhour') || GETPOSTISSET('planned_workloadmin')) {
175 $planned_workload = (int) $planned_workloadhour * 3600 + (int) $planned_workloadmin * 60;
176} else {
177 $planned_workload = '';
178}
179
180// Definition of fields for list
181$arrayfields = array(
182 't.ref' => array('label' => "RefTask", 'checked' => '1', 'position' => 1),
183 't.label' => array('label' => "LabelTask", 'checked' => '1', 'position' => 2),
184 't.description' => array('label' => "Description", 'checked' => '0', 'position' => 3),
185 't.dateo' => array('label' => "DateStart", 'checked' => '1', 'position' => 4),
186 't.datee' => array('label' => "Deadline", 'checked' => '1', 'position' => 5),
187 't.planned_workload' => array('label' => "PlannedWorkload", 'checked' => '1', 'position' => 6),
188 't.duration_effective' => array('label' => "TimeSpent", 'checked' => '1', 'position' => 7),
189 't.progress_calculated' => array('label' => "ProgressCalculated", 'checked' => '-1', 'position' => 8),
190 't.progress' => array('label' => "ProgressDeclared", 'checked' => '1', 'position' => 9),
191 't.progress_summary' => array('label' => "TaskProgressSummary", 'checked' => '1', 'position' => 10),
192 't.fk_statut' => array('label' => "Status", 'checked' => '1', 'position' => 11),
193 't.budget_amount' => array('label' => "Budget", 'checked' => '0', 'position' => 12),
194 'c.assigned' => array('label' => "TaskRessourceLinks", 'checked' => '1', 'position' => 13),
195
196);
197if ($object->usage_bill_time) {
198 $arrayfields['t.tobill'] = array('label' => $langs->trans("TimeToBill"), 'checked' => '0', 'position' => 11);
199 $arrayfields['t.billed'] = array('label' => $langs->trans("TimeBilled"), 'checked' => '0', 'position' => 12);
200 $arrayfields['t.billable'] = array('label' => $langs->trans("Billable"), 'checked' => '1', 'position' => 13);
201}
202
203// Extra fields
204$extrafieldsobjectkey = $taskstatic->table_element;
205$extrafieldsobjectprefix = 'efpt.';
206include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php';
207
208$arrayfields = dol_sort_array($arrayfields, 'position');
209
210$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
211
212
213/*
214 * Actions
215 */
216$error = 0;
217
218if ($cancel) {
219 if (!empty($backtopageforcancel)) {
220 header("Location: ".$backtopageforcancel);
221 exit;
222 } elseif (!empty($backtopage)) {
223 header("Location: ".$backtopage);
224 exit;
225 }
226 $action = 'list';
227 $massaction = '';
228}
229if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') {
230 $massaction = '';
231}
232
233$parameters = array('id' => $id);
234$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
235if ($reshook < 0) {
236 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
237}
238
239if (empty($reshook)) {
240 if ($action == 'update_extras' && ($id > 0 || !empty($ref)) && $permissiontoeditextra) {
241 $object->oldcopy = dol_clone($object, 2);
242 $attribute_name = GETPOST('attribute', 'aZ09');
243 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
244 if ($ret < 0) {
245 $error++;
246 }
247 if (!$error) {
248 $result = $object->updateExtraField($attribute_name, 'PROJECT_MODIFY');
249 if ($result < 0) {
250 setEventMessages($object->error, $object->errors, 'errors');
251 $error++;
252 }
253 }
254 if ($error) {
255 $action = 'edit_extras';
256 }
257 }
258
259 // Selection of new fields
260 include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
261
262 // Purge search criteria
263 if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
264 $search_user_id = "";
265 $search_taskref = '';
266 $search_tasklabel = '';
267 $search_dtstartday = '';
268 $search_dtstartmonth = '';
269 $search_dtstartyear = '';
270 $search_dtendday = '';
271 $search_dtendmonth = '';
272 $search_dtendyear = '';
273 $search_planedworkload = '';
274 $search_timespend = '';
275 $search_progresscalc = '';
276 $search_progressdeclare = '';
277 $search_task_budget_amount = '';
278 $search_task_billable = '';
279 $search_status = -1;
280 $toselect = array();
281 $search_array_options = array();
282 $search_date_start_startmonth = "";
283 $search_date_start_startyear = "";
284 $search_date_start_startday = "";
285 $search_date_start_start = "";
286 $search_date_start_endmonth = "";
287 $search_date_start_endyear = "";
288 $search_date_start_endday = "";
289 $search_date_start_end = "";
290 $search_date_end_startmonth = "";
291 $search_date_end_startyear = "";
292 $search_date_end_startday = "";
293 $search_date_end_start = "";
294 $search_date_end_endmonth = "";
295 $search_date_end_endyear = "";
296 $search_date_end_endday = "";
297 $search_date_end_end = "";
298 }
299
300 // Mass actions
301 $objectclass = 'Task';
302 $objectlabel = 'Tasks';
303 $permissiontoread = $user->hasRight('projet', 'lire');
304 $permissiontodelete = $user->hasRight('projet', 'supprimer');
305 $uploaddir = $conf->project->dir_output.'/tasks';
306 include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
307}
308
309$morewherefilterarray = array();
310
311if (!empty($search_taskref)) {
312 $morewherefilterarray[] = natural_search('t.ref', $search_taskref, 0, 1);
313}
314
315if (!empty($search_tasklabel)) {
316 $morewherefilterarray[] = natural_search('t.label', $search_tasklabel, 0, 1);
317}
318
319$moresql = dolSqlDateFilter('t.dateo', $search_dtstartday, $search_dtstartmonth, $search_dtstartyear, 1);
320if ($moresql) {
321 $morewherefilterarray[] = $moresql;
322}
323
324$moresql = dolSqlDateFilter('t.datee', $search_dtendday, $search_dtendmonth, $search_dtendyear, 1);
325if ($moresql) {
326 $morewherefilterarray[] = $moresql;
327}
328
329if ($search_date_start_start) {
330 $morewherefilterarray[] = " t.dateo >= '".$db->idate($search_date_start_start)."'";
331}
332if ($search_date_start_end) {
333 $morewherefilterarray[] = " t.dateo <= '".$db->idate($search_date_start_end)."'";
334}
335
336if ($search_date_end_start) {
337 $morewherefilterarray[] = " t.datee >= '".$db->idate($search_date_end_start)."'";
338}
339if ($search_date_end_end) {
340 $morewherefilterarray[] = " t.datee <= '".$db->idate($search_date_end_end)."'";
341}
342
343if (!empty($search_planedworkload)) {
344 $morewherefilterarray[] = natural_search('t.planned_workload', $search_planedworkload, 1, 1);
345}
346
347if (!empty($search_timespend)) {
348 $morewherefilterarray[] = natural_search('t.duration_effective', $search_timespend, 1, 1);
349}
350
351if (!empty($search_progressdeclare)) {
352 $morewherefilterarray[] = natural_search('t.progress', $search_progressdeclare, 1, 1);
353}
354if (!empty($search_progresscalc)) {
355 $morewherefilterarray[] = '(planned_workload IS NULL OR planned_workload = 0 OR '.natural_search('ROUND(100 * duration_effective / planned_workload, 2)', $search_progresscalc, 1, 1).')';
356 //natural_search('round(100 * $line->duration_effective / $line->planned_workload,2)', $filterprogresscalc, 1, 1).' {return 1;} else {return 0;}';
357}
358if ($search_status > -1 && $search_status != '') {
359 $morewherefilterarray[] = " t.fk_statut = ".((int) $search_status);
360}
361if ($search_task_budget_amount) {
362 $morewherefilterarray[] = natural_search('t.budget_amount', $search_task_budget_amount, 1, 1);
363}
364if ($search_task_billable && $search_task_billable != '-1') {
365 $morewherefilterarray[] = " t.billable = ".($search_task_billable == "yes" ? 1 : 0);
366}
367//var_dump($morewherefilterarray);
368
369$morewherefilter = '';
370if (count($morewherefilterarray) > 0) {
371 $morewherefilter = ' AND '.implode(' AND ', $morewherefilterarray);
372}
373
374if ($action == 'createtask' && $user->hasRight('projet', 'creer')) {
375 // If we use user timezone, we must change also view/list to use user timezone everywhere
376 $date_start = dol_mktime(GETPOSTINT('date_starthour'), GETPOSTINT('date_startmin'), 0, GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
377 $date_end = dol_mktime(GETPOSTINT('date_endhour'), GETPOSTINT('date_endmin'), 0, GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
378
379 if (!$cancel) {
380 if (empty($taskref)) {
381 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Ref")), null, 'errors');
382 $action = 'create';
383 $error++;
384 }
385 if (empty($label)) {
386 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
387 $action = 'create';
388 $error++;
389 } elseif (!GETPOST('task_parent')) {
390 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("ChildOfProjectTask")), null, 'errors');
391 $action = 'create';
392 $error++;
393 }
394
395 if (!$error) {
396 $tmparray = explode('_', GETPOST('task_parent'));
397 $projectid = empty($tmparray[0]) ? $id : (int) $tmparray[0];
398 $task_parent = empty($tmparray[1]) ? 0 : $tmparray[1];
399
400 $task = new Task($db);
401
402 $task->fk_project = $projectid;
403 $task->entity = $object->entity; // Task have the same entity of project
404 $task->ref = $taskref;
405 $task->label = $label;
406 $task->description = $description;
407 $task->planned_workload = $planned_workload;
408 $task->fk_task_parent = $task_parent;
409 $task->date_c = dol_now();
410 $task->date_start = $date_start;
411 $task->date_end = $date_end;
412 $task->progress = $progress;
413 $task->budget_amount = $budget_amount;
414 $task->billable = $billable;
415 $task->status = Task::STATUS_VALIDATED;
416
417 // Fill array 'array_options' with data from add form
418 $ret = $extrafields->setOptionalsFromPost(null, $task);
419
420 $taskid = $task->create($user);
421
422 if ($taskid > 0) {
423 $userid = GETPOSTINT("userid");
424 if ($userid == -4) {
425 if (empty($object->id)) {
426 $object->fetch($projectid);
427 }
428 $contactlist = array();
429 foreach (array('internal', 'external') as $source) {
430 $contactlist = array_merge($contactlist, $object->liste_contact(-1, $source));
431 }
432 foreach ($contactlist as $key => $contact) {
433 $result = $task->add_contact(((int) $contact["id"]), ($contact["code"] == "PROJECTLEADER" ? 'TASKEXECUTIVE' : "TASKCONTRIBUTOR"), $contact["source"]);
434 }
435 } else {
436 $result = $task->add_contact(GETPOSTINT("userid"), 'TASKEXECUTIVE', 'internal');
437 }
438 } else {
439 if ($db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
440 $langs->load("projects");
441 setEventMessages($langs->trans('NewTaskRefSuggested'), null, 'warnings');
442 $duplicate_code_error = true;
443 } else {
444 setEventMessages($task->error, $task->errors, 'errors');
445 }
446 $action = 'create';
447 $error++;
448 }
449 }
450
451 if (!$error) {
452 if (!empty($backtopage)) {
453 header("Location: ".$backtopage);
454 exit;
455 } elseif (empty($projectid)) {
456 header("Location: ".DOL_URL_ROOT.'/projet/tasks/list.php'.(empty($mode) ? '' : '?mode='.$mode));
457 exit;
458 }
459 $id = $projectid;
460 }
461 } else {
462 if (!empty($backtopage)) {
463 header("Location: ".$backtopage);
464 exit;
465 } elseif (empty($id)) {
466 // We go back on task list
467 header("Location: ".DOL_URL_ROOT.'/projet/tasks/list.php'.(empty($mode) ? '' : '?mode='.$mode));
468 exit;
469 }
470 }
471}
472
473/*
474 * View
475 */
476
477$now = dol_now();
478$form = new Form($db);
479$formother = new FormOther($db);
480$socstatic = new Societe($db);
481$projectstatic = new Project($db);
482$taskstatic = new Task($db);
483$userstatic = new User($db);
484
485$title = $langs->trans("Tasks").' - '.$object->ref.' '.$object->name;
486if (getDolGlobalString('MAIN_HTML_TITLE') && preg_match('/projectnameonly/', getDolGlobalString('MAIN_HTML_TITLE')) && $object->name) {
487 $title = $object->ref.' '.$object->name.' - '.$langs->trans("Tasks");
488}
489if ($action == 'create') {
490 $title = $langs->trans("NewTask");
491}
492$help_url = "EN:Module_Projects|FR:Module_Projets|ES:M&oacute;dulo_Proyectos";
493
494llxHeader("", $title, $help_url, '', 0, 0, '', '', '', 'mod-project page-card_tasks');
495
496$arrayofselected = is_array($toselect) ? $toselect : array();
497$param = '';
498$userWrite = 0;
499$massactionbutton = '';
500
501if ($id > 0 || !empty($ref)) {
502 $result = $object->fetch($id, $ref);
503 if ($result < 0) {
504 setEventMessages(null, $object->errors, 'errors');
505 }
506 $result = $object->fetch_thirdparty();
507 if ($result < 0) {
508 setEventMessages(null, $object->errors, 'errors');
509 }
510 $result = $object->fetch_optionals();
511 if ($result < 0) {
512 setEventMessages(null, $object->errors, 'errors');
513 }
514
515
516 // To verify role of users
517 //$userAccess = $object->restrictedProjectArea($user,'read');
518 $userWrite = $object->restrictedProjectArea($user, 'write');
519 //$userDelete = $object->restrictedProjectArea($user,'delete');
520 //print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete;
521
522
523 $tab = (GETPOSTISSET('tab') ? GETPOST('tab') : 'tasks');
524
525 $head = project_prepare_head($object);
526 print dol_get_fiche_head($head, $tab, $langs->trans("Project"), -1, ($object->public ? 'projectpub' : 'project'));
527
528 $param = '&id='.$object->id;
529 if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
530 $param .= '&contextpage='.urlencode($contextpage);
531 }
532 if ($search_user_id) {
533 $param .= '&search_user_id='.urlencode((string) ($search_user_id));
534 }
535 if ($search_taskref) {
536 $param .= '&search_taskref='.urlencode($search_taskref);
537 }
538 if ($search_tasklabel) {
539 $param .= '&search_tasklabel='.urlencode($search_tasklabel);
540 }
541 if ($search_taskdescription) {
542 $param .= '&search_taskdescription='.urlencode($search_taskdescription);
543 }
544 if ($search_dtstartday) {
545 $param .= '&search_dtstartday='.urlencode($search_dtstartday);
546 }
547 if ($search_dtstartmonth) {
548 $param .= '&search_dtstartmonth='.urlencode($search_dtstartmonth);
549 }
550 if ($search_dtstartyear) {
551 $param .= '&search_dtstartyear='.urlencode($search_dtstartyear);
552 }
553 if ($search_dtendday) {
554 $param .= '&search_dtendday='.urlencode($search_dtendday);
555 }
556 if ($search_dtendmonth) {
557 $param .= '&search_dtendmonth='.urlencode($search_dtendmonth);
558 }
559 if ($search_dtendyear) {
560 $param .= '&search_dtendyear='.urlencode($search_dtendyear);
561 }
562 if ($search_date_start_startmonth) {
563 $param .= '&search_date_start_startmonth='.urlencode((string) ($search_date_start_startmonth));
564 }
565 if ($search_date_start_startyear) {
566 $param .= '&search_date_start_startyear='.urlencode((string) ($search_date_start_startyear));
567 }
568 if ($search_date_start_startday) {
569 $param .= '&search_date_start_startday='.urlencode((string) ($search_date_start_startday));
570 }
571 if ($search_date_start_start) {
572 $param .= '&search_date_start_start='.urlencode((string) $search_date_start_start);
573 }
574 if ($search_date_start_endmonth) {
575 $param .= '&search_date_start_endmonth='.urlencode((string) ($search_date_start_endmonth));
576 }
577 if ($search_date_start_endyear) {
578 $param .= '&search_date_start_endyear='.urlencode((string) ($search_date_start_endyear));
579 }
580 if ($search_date_start_endday) {
581 $param .= '&search_date_start_endday='.urlencode((string) ($search_date_start_endday));
582 }
583 if ($search_date_start_end) {
584 $param .= '&search_date_start_end='.urlencode((string) $search_date_start_end);
585 }
586 if ($search_date_end_startmonth) {
587 $param .= '&search_date_end_startmonth='.urlencode((string) ($search_date_end_startmonth));
588 }
589 if ($search_date_end_startyear) {
590 $param .= '&search_date_end_startyear='.urlencode((string) ($search_date_end_startyear));
591 }
592 if ($search_date_end_startday) {
593 $param .= '&search_date_end_startday='.urlencode((string) ($search_date_end_startday));
594 }
595 if ($search_date_end_start) {
596 $param .= '&search_date_end_start='.urlencode((string) $search_date_end_start);
597 }
598 if ($search_date_end_endmonth) {
599 $param .= '&search_date_end_endmonth='.urlencode((string) ($search_date_end_endmonth));
600 }
601 if ($search_date_end_endyear) {
602 $param .= '&search_date_end_endyear='.urlencode((string) ($search_date_end_endyear));
603 }
604 if ($search_date_end_endday) {
605 $param .= '&search_date_end_endday='.urlencode((string) ($search_date_end_endday));
606 }
607 if ($search_date_end_end) {
608 $param .= '&search_date_end_end=' . urlencode((string) $search_date_end_end);
609 }
610 if ($search_planedworkload) {
611 $param .= '&search_planedworkload='.urlencode($search_planedworkload);
612 }
613 if ($search_timespend) {
614 $param .= '&search_timespend='.urlencode($search_timespend);
615 }
616 if ($search_progresscalc) {
617 $param .= '&search_progresscalc='.urlencode($search_progresscalc);
618 }
619 if ($search_progressdeclare) {
620 $param .= '&search_progressdeclare='.urlencode($search_progressdeclare);
621 }
622 if ($search_status) {
623 $param .= '&search_status='.urlencode((string) ($search_status));
624 }
625 if ($search_task_budget_amount) {
626 $param .= '&search_task_budget_amount='.urlencode($search_task_budget_amount);
627 }
628 if ($search_task_billable) {
629 $param .= '&search_task_billable='.urlencode($search_task_billable);
630 }
631 if ($optioncss != '') {
632 $param .= '&optioncss='.urlencode($optioncss);
633 }
634 // Add $param from extra fields
635 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
636
637 $arrayofmassactions = array();
638 if ($user->hasRight('projet', 'creer')) {
639 $arrayofmassactions['preclonetasks'] = img_picto('', 'clone', 'class="pictofixedwidth"').$langs->trans("Clone");
640 }
641 if ($permissiontodelete) {
642 $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
643 }
644 if (in_array($massaction, array('presend', 'predelete'))) {
645 $arrayofmassactions = array();
646 }
647 $massactionbutton = $form->selectMassAction('', $arrayofmassactions) ?? '';
648
649 // Project card
650
651 if (!empty($_SESSION['pageforbacktolist']) && !empty($_SESSION['pageforbacktolist']['project'])) {
652 $tmpurl = $_SESSION['pageforbacktolist']['project'];
653 $tmpurl = preg_replace('/__SOCID__/', (string) $object->socid, $tmpurl);
654 $linkback = '<a href="'.$tmpurl.(preg_match('/\?/', $tmpurl) ? '&' : '?'). 'restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
655 } else {
656 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
657 }
658
659 $morehtmlref = '<div class="refidno">';
660 // Title
661 $morehtmlref .= $object->title;
662 // Thirdparty
663 if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
664 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'project');
665 }
666 $morehtmlref .= '</div>';
667
668 // Define a complementary filter for search of next/prev ref.
669 if (!$user->hasRight('projet', 'all', 'lire')) {
670 $objectsListId = $object->getProjectsAuthorizedForUser($user, 0, 0);
671 $object->next_prev_filter = "rowid:IN:".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0');
672 }
673
674 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
675
676 print '<div class="fichecenter">';
677 print '<div class="fichehalfleft">';
678 print '<div class="underbanner clearboth"></div>';
679
680 print '<table class="border tableforfield centpercent">';
681
682 // Usage
683 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJECT_HIDE_TASKS') || isModEnabled('eventorganization')) {
684 print '<tr><td class="tdtop">';
685 print $langs->trans("Usage");
686 print '</td>';
687 print '<td>';
688 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
689 print '<input type="checkbox" disabled name="usage_opportunity"'.(GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_opportunity ? ' checked="checked"' : '')).'"> ';
690 $htmltext = $langs->trans("ProjectFollowOpportunity");
691 print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
692 print '<br>';
693 }
694 if (!getDolGlobalString('PROJECT_HIDE_TASKS')) {
695 print '<input type="checkbox" disabled name="usage_task"'.(GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_task ? ' checked="checked"' : '')).'"> ';
696 $htmltext = $langs->trans("ProjectFollowTasks");
697 print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
698 print '<br>';
699 }
700 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
701 print '<input type="checkbox" disabled name="usage_bill_time"'.(GETPOSTISSET('usage_bill_time') ? (GETPOST('usage_bill_time', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_bill_time ? ' checked="checked"' : '')).'"> ';
702 $htmltext = $langs->trans("ProjectBillTimeDescription");
703 print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
704 print '<br>';
705 }
706 if (isModEnabled('eventorganization')) {
707 print '<input type="checkbox" disabled name="usage_organize_event"'.(GETPOSTISSET('usage_organize_event') ? (GETPOST('usage_organize_event', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_organize_event ? ' checked="checked"' : '')).'"> ';
708 $htmltext = $langs->trans("EventOrganizationDescriptionLong");
709 print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
710 }
711 print '</td></tr>';
712 }
713
714 // Budget
715 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
716 if (!is_null($object->budget_amount) && strcmp($object->budget_amount, '')) {
717 print '<span class="amount">'.price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
718 }
719 print '</td></tr>';
720
721 // Date start - end project
722 print '<tr><td>'.$langs->trans("Dates").'</td><td>';
723 $start = dol_print_date($object->date_start, 'day');
724 print($start ? $start : '?');
725 $end = dol_print_date($object->date_end, 'day');
726 print ' - ';
727 print($end ? $end : '?');
728 if ($object->hasDelay()) {
729 print img_warning("Late");
730 }
731 print '</td></tr>';
732
733 // Visibility
734 print '<tr><td class="titlefield">'.$langs->trans("Visibility").'</td><td>';
735 if ($object->public) {
736 print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
737 print $langs->trans('SharedProject');
738 } else {
739 print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
740 print $langs->trans('PrivateProject');
741 }
742 print '</td></tr>';
743
744 // Other attributes
745 $cols = 2;
746 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
747
748 print '</table>';
749
750 print '</div>';
751 print '<div class="fichehalfright">';
752 print '<div class="underbanner clearboth"></div>';
753
754 print '<table class="border tableforfield centpercent">';
755
756 // Categories
757 if (isModEnabled('category')) {
758 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
759 print $form->showCategories($object->id, Categorie::TYPE_PROJECT, 1);
760 print "</td></tr>";
761 }
762
763 // Description
764 print '<tr><td class="titlefield'.($object->description ? ' noborderbottom' : '').'" colspan="2">'.$langs->trans("Description").'</td></tr>';
765 if ($object->description) {
766 print '<tr><td class="nottitleforfield" colspan="2">';
767 print '<div class="longmessagecut">';
768 print dolPrintHTML($object->description);
769 print '</div>';
770 print '</td></tr>';
771 }
772
773 print '</table>';
774
775 print '</div>';
776 print '</div>';
777
778 print '<div class="clearboth"></div>';
779
780
781 print dol_get_fiche_end();
782}
783
784
785if ($action == 'create' && $user->hasRight('projet', 'creer') && (empty($object->thirdparty->id) || $userWrite > 0)) {
786 if ($id > 0 || !empty($ref)) {
787 print '<br>';
788 }
789
790 print load_fiche_titre($langs->trans("NewTask"), '', 'projecttask');
791
792 $projectoktoentertime = 1;
793 if ($object->id > 0 && $object->status == Project::STATUS_CLOSED) {
794 $projectoktoentertime = 0;
795 print '<div class="warning">';
796 $langs->load("errors");
797 print $langs->trans("WarningProjectClosed");
798 print '</div>';
799 }
800
801 if ($object->id > 0 && $object->status == Project::STATUS_DRAFT) {
802 $projectoktoentertime = 0;
803 print '<div class="warning">';
804 $langs->load("errors");
805 print $langs->trans("WarningProjectDraft");
806 print '</div>';
807 }
808
809 print '<form action="'.$_SERVER['PHP_SELF'].'" method="POST">';
810 print '<input type="hidden" name="token" value="'.newToken().'">';
811 print '<input type="hidden" name="action" value="createtask">';
812 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
813 if (!empty($object->id)) {
814 print '<input type="hidden" name="id" value="'.$object->id.'">';
815 }
816
817 print dol_get_fiche_head();
818
819 print '<div class="div-table-responsive-no-min">';
820 print '<table class="border centpercent">';
821
822 $defaultref = '';
823 $classnamemodtask = getDolGlobalString('PROJECT_TASK_ADDON', 'mod_task_simple');
824 if (getDolGlobalString('PROJECT_TASK_ADDON') && is_readable(DOL_DOCUMENT_ROOT."/core/modules/project/task/" . getDolGlobalString('PROJECT_TASK_ADDON').".php")) {
825 require_once DOL_DOCUMENT_ROOT."/core/modules/project/task/" . getDolGlobalString('PROJECT_TASK_ADDON').'.php';
826 $modTask = new $classnamemodtask();
827 '@phan-var-force ModeleNumRefTask $modTask';
828 $defaultref = $modTask->getNextValue($object->thirdparty, $object);
829 }
830
831 if (is_numeric($defaultref) && $defaultref <= 0) {
832 $defaultref = '';
833 }
834
835 // Ref
836 print '<tr><td class="titlefieldcreate"><span class="fieldrequired">'.$langs->trans("Ref").'</span></td><td>';
837 if (empty($duplicate_code_error)) {
838 print(GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : $defaultref);
839 } else {
840 print $defaultref;
841 }
842 print '<input type="hidden" name="taskref" value="'.(GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : $defaultref).'">';
843 print '</td></tr>';
844
845 // Label
846 print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td>';
847 print '<input type="text" name="label" autofocus class="minwidth500" value="'.$label.'">';
848 print '</td></tr>';
849
850 // Project
851 print '<tr><td class="fieldrequired">'.$langs->trans("ChildOfProjectTask").'</td><td>';
852 print img_picto('', 'project', 'class="pictofixedwidth"');
853 if ($projectoktoentertime) {
854 $formother->selectProjectTasks(GETPOSTINT('task_parent'), empty($projectid) ? $object->id : $projectid, 'task_parent', 0, 0, 1, 1, 0, '0,1', 'maxwidth500 widthcentpercentminusxx');
855 } else {
856 $formother->selectProjectTasks(GETPOSTINT('task_parent'), empty($projectid) ? $object->id : $projectid, 'task_parent', 0, 0, 1, 1, 0, '', 'maxwidth500 widthcentpercentminusxx');
857 }
858 print '</td></tr>';
859
860 $contactsofproject = (empty($object->id) ? '' : $object->getListContactId('internal'));
861
862 // Assigned to
863 print '<tr><td>'.$langs->trans("AffectedTo").'</td><td>';
864 print img_picto('', 'user', 'class="pictofixedwidth"');
865 if (is_array($contactsofproject) && count($contactsofproject)) {
866 print $form->select_dolusers('-4', 'userid', 0, null, 0, '', $contactsofproject, '0', 0, 0, '(statut:=:1)', 4, '', 'maxwidth500 widthcentpercentminusx');
867 } else {
868 if ((isset($projectid) && $projectid > 0) || $object->id > 0) {
869 print '<span class="opacitymedium">'.$langs->trans("NoUserAssignedToTheProject").'</span>';
870 } else {
871 print $form->select_dolusers('-4', 'userid', 0, null, 0, '', '', '0', 0, 0, '(statut:=:1)', 4, '', 'maxwidth500 widthcentpercentminusx');
872 }
873 }
874 print '</td></tr>';
875
876 // Billable
877 print '<tr><td>'.$langs->trans("Billable").'</td><td>';
878 print $form->selectyesno('billable');
879 print '</td></tr>';
880
881 // Date start task
882 print '<tr><td>'.$langs->trans("DateStart").'</td><td>';
883 print img_picto('', 'action', 'class="pictofixedwidth"');
884 print $form->selectDate((!empty($date_start) ? $date_start : ''), 'date_start', 1, 1, 0, '', 1, 1);
885 print '</td></tr>';
886
887 // Date end task
888 print '<tr><td>'.$langs->trans("DateEnd").'</td><td>';
889 print img_picto('', 'action', 'class="pictofixedwidth"');
890 print $form->selectDate((!empty($date_end) ? $date_end : -1), 'date_end', -1, 1, 0, '', 1, 1);
891 print '</td></tr>';
892
893 // Planned workload
894 print '<tr><td>'.$langs->trans("PlannedWorkload").'</td><td>';
895 print img_picto('', 'clock', 'class="pictofixedwidth"');
896 print $form->select_duration('planned_workload', $planned_workload, 0, 'text');
897 print '</td></tr>';
898
899 // Progress
900 print '<tr><td>'.$langs->trans("ProgressDeclared").'</td><td colspan="3">';
901 print img_picto('', 'fa-percent', 'class="pictofixedwidth"');
902 print $formother->select_percent($progress, 'progress', 0, 5, 0, 100, 1);
903 print '</td></tr>';
904
905 // Description
906 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td>';
907 print '<td>';
908
909 // WYSIWYG editor
910 include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
911 $nbrows = 0;
912 if (getDolGlobalString('MAIN_INPUT_DESC_HEIGHT')) {
913 $nbrows = getDolGlobalString('MAIN_INPUT_DESC_HEIGHT');
914 }
915 $doleditor = new DolEditor('description', $object->description, '', 80, 'dolibarr_details', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), $nbrows, '90%');
916 print $doleditor->Create();
917
918 print '</td></tr>';
919
920 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
921 print img_picto('', 'currency', 'class="pictofixedwidth"');
922 print '<input size="8" type="text" name="budget_amount" value="'.dol_escape_htmltag(GETPOSTISSET('budget_amount') ? GETPOST('budget_amount') : '').'"></td>';
923 print '</tr>';
924
925 // Other options
926 $parameters = array('arrayfields' => &$arrayfields);
927 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $taskstatic, $action); // Note that $action and $object may have been modified by hook
928 print $hookmanager->resPrint;
929
930 if (empty($reshook) && !empty($extrafields->attributes[$taskstatic->table_element]['label'])) {
931 print $taskstatic->showOptionals($extrafields, 'edit'); // Do not use $object here that is object of project but use $taskstatic
932 }
933
934 print '</table>';
935 print '</div>';
936
937 print dol_get_fiche_end();
938
939 print $form->buttonsSaveCancel("Add");
940
941 print '</form>';
942} elseif ($id > 0 || !empty($ref)) {
943 $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, $conf->main_checkbox_left_column); // This also change content of $arrayfields
944
945 // Projet card in view mode
946
947 print '<br>';
948
949 // Link to create task
950 $linktocreatetaskParam = array();
951 $linktocreatetaskUserRight = false;
952 if ($user->hasRight('projet', 'all', 'creer') || $user->hasRight('projet', 'creer')) {
953 if ($object->public || $userWrite > 0) {
954 $linktocreatetaskUserRight = true;
955 } else {
956 $linktocreatetaskParam['attr']['title'] = $langs->trans("NotOwnerOfProject");
957 }
958 }
959
960 $linktocreatetask = dolGetButtonTitle($langs->trans('AddTask'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/projet/tasks.php?action=create'.$param.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$object->id), '', (int) $linktocreatetaskUserRight, $linktocreatetaskParam);
961
962 print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
963 print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
964 print '<input type="hidden" name="token" value="'.newToken().'">';
965 print '<input type="hidden" name="action" value="list">';
966 print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
967 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
968 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
969 print '<input type="hidden" name="page" value="'.$page.'">';
970 print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
971
972 $title = $langs->trans("ListOfTasks");
973 $linktotasks = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id, '', 1, array('morecss' => 'reposition btnTitleSelected'));
974 $linktotasks .= dolGetButtonTitle($langs->trans('ViewGantt'), '', 'fa fa-stream imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1', '', 1, array('morecss' => 'reposition marginleftonly'));
975
976 //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1);
977 print load_fiche_titre($title, $linktotasks.' &nbsp; '.$linktocreatetask, 'projecttask', 0, '', '', $massactionbutton);
978
979 $objecttmp = new Task($db);
980 $trackid = 'task'.$taskstatic->id;
981 include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
982
983 // Get list of tasks in tasksarray and taskarrayfiltered
984 // We need all tasks (even not limited to a user because a task to user can have a parent that is not affected to him).
985 $filteronthirdpartyid = $socid;
986 $tasksarray = $taskstatic->getTasksArray(null, null, $object->id, $filteronthirdpartyid, 0, '', '-1', $morewherefilter, 0, 0, $extrafields, 1, $search_array_options, 1, 1, $sortfield, $sortorder);
987
988 // We load also tasks limited to a particular user
989 $tmpuser = new User($db);
990 if ($search_user_id > 0) {
991 $tmpuser->fetch($search_user_id);
992 }
993
994 $tasksrole = ($tmpuser->id > 0 ? $taskstatic->getUserRolesForProjectsOrTasks(null, $tmpuser, (string) $object->id, 0) : '');
995 //var_dump($tasksarray);
996 //var_dump($tasksrole);
997
998 if (!empty($conf->use_javascript_ajax)) {
999 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
1000 }
1001
1002 // Filter on assigned users
1003 $moreforfilter = '';
1004 $moreforfilter .= '<div class="divsearchfield">';
1005 $moreforfilter .= img_picto('', 'user', 'class="pictofixedwidth"');
1006 $moreforfilter .= $form->select_dolusers($tmpuser->id > 0 ? $tmpuser->id : '', 'search_user_id', $langs->trans("TasksAssignedTo"), null, 0, '', '');
1007 $moreforfilter .= '</div>';
1008 if ($moreforfilter) {
1009 print '<div class="liste_titre liste_titre_bydiv centpercent">';
1010 print $moreforfilter;
1011 print '</div>';
1012 }
1013
1014 // Show the massaction checkboxes only when this page is not opened from the Extended POS
1015 if (!empty($massactionbutton) && $contextpage != 'poslist') {
1016 $selectedfields .= $form->showCheckAddButtons('checkforselect', 1);
1017 }
1018
1019 print '<div class="div-table-responsive">';
1020 print '<table id="tablelines" class="tagtable nobottom liste'.($moreforfilter ? " listwithfilterbefore" : "").'">';
1021
1022 // Fields title search
1023 print '<tr class="liste_titre_filter">';
1024
1025 // Action column
1026 if ($conf->main_checkbox_left_column) {
1027 print '<td class="liste_titre maxwidthsearch">';
1028 $searchpicto = $form->showFilterButtons();
1029 print $searchpicto;
1030 print '</td>';
1031 }
1032
1033 if (!empty($arrayfields['t.ref']['checked'])) {
1034 print '<td class="liste_titre">';
1035 print '<input class="flat searchstring maxwidth50" type="text" name="search_taskref" value="'.dol_escape_htmltag($search_taskref).'">';
1036 print '</td>';
1037 }
1038
1039 if (!empty($arrayfields['t.label']['checked'])) {
1040 print '<td class="liste_titre">';
1041 print '<input class="flat searchstring maxwidth100" type="text" name="search_tasklabel" value="'.dol_escape_htmltag($search_tasklabel).'">';
1042 print '</td>';
1043 }
1044
1045 if (!empty($arrayfields['t.description']['checked'])) {
1046 print '<td class="liste_titre">';
1047 print '<input class="flat searchstring maxwidth100" type="text" name="search_taskdescription" value="'.dol_escape_htmltag($search_taskdescription).'">';
1048 print '</td>';
1049 }
1050
1051 if (!empty($arrayfields['t.dateo']['checked'])) {
1052 print '<td class="liste_titre center">';
1053 /*print '<span class="nowraponall"><input class="flat valignmiddle width20" type="text" maxlength="2" name="search_dtstartday" value="'.$search_dtstartday.'">';
1054 print '<input class="flat valignmiddle width20" type="text" maxlength="2" name="search_dtstartmonth" value="'.$search_dtstartmonth.'"></span>';
1055 print $formother->selectyear($search_dtstartyear ? $search_dtstartyear : -1, 'search_dtstartyear', 1, 20, 5);*/
1056 print '<div class="nowrapfordate">';
1057 print $form->selectDate($search_date_start_start ? $search_date_start_start : -1, 'search_date_start_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
1058 print '</div>';
1059 print '<div class="nowrapfordate">';
1060 print $form->selectDate($search_date_start_end ? $search_date_start_end : -1, 'search_date_start_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
1061 print '</div>';
1062 print '</td>';
1063 }
1064
1065 if (!empty($arrayfields['t.datee']['checked'])) {
1066 print '<td class="liste_titre center">';
1067 /*print '<span class="nowraponall"><input class="flat valignmiddle width20" type="text" maxlength="2" name="search_dtendday" value="'.$search_dtendday.'">';
1068 print '<input class="flat valignmiddle width20" type="text" maxlength="2" name="search_dtendmonth" value="'.$search_dtendmonth.'"></span>';
1069 print $formother->selectyear($search_dtendyear ? $search_dtendyear : -1, 'search_dtendyear', 1, 20, 5);*/
1070 print '<div class="nowrapfordate">';
1071 print $form->selectDate($search_date_end_start ? $search_date_end_start : -1, 'search_date_end_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
1072 print '</div>';
1073 print '<div class="nowrapfordate">';
1074 print $form->selectDate($search_date_end_end ? $search_date_end_end : -1, 'search_date_end_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
1075 print '</div>';
1076 print '</td>';
1077 }
1078
1079 if (!empty($arrayfields['t.planned_workload']['checked'])) {
1080 print '<td class="liste_titre right">';
1081 print '<input class="flat" type="text" size="4" name="search_planedworkload" value="'.$search_planedworkload.'">';
1082 print '</td>';
1083 }
1084
1085 if (!empty($arrayfields['t.duration_effective']['checked'])) {
1086 print '<td class="liste_titre right">';
1087 print '<input class="flat" type="text" size="4" name="search_timespend" value="'.$search_timespend.'">';
1088 print '</td>';
1089 }
1090
1091 if (!empty($arrayfields['t.progress_calculated']['checked'])) {
1092 print '<td class="liste_titre right">';
1093 print '<input class="flat" type="text" size="4" name="search_progresscalc" value="'.$search_progresscalc.'">';
1094 print '</td>';
1095 }
1096
1097 if (!empty($arrayfields['t.progress']['checked'])) {
1098 print '<td class="liste_titre right">';
1099 print '<input class="flat" type="text" size="4" name="search_progressdeclare" value="'.$search_progressdeclare.'">';
1100 print '</td>';
1101 }
1102
1103 // progress resume not searchable
1104 if (!empty($arrayfields['t.progress_summary']['checked'])) {
1105 print '<td class="liste_titre right"></td>';
1106 }
1107
1108 if (!empty($arrayfields['t.fk_statut']['checked'])) {
1109 print '<td class="liste_titre center">';
1110 $arrayofstatus = array();
1111 foreach ($taskstatic->labelStatusShort as $key => $val) {
1112 $arrayofstatus[$key] = $langs->trans($val);
1113 }
1114 print $form->selectarray('search_status', $arrayofstatus, $search_status, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth100');
1115 print '</td>';
1116 }
1117
1118 if ($object->usage_bill_time) {
1119 if (!empty($arrayfields['t.tobill']['checked'])) {
1120 print '<td class="liste_titre right">';
1121 print '</td>';
1122 }
1123
1124 if (!empty($arrayfields['t.billed']['checked'])) {
1125 print '<td class="liste_titre right">';
1126 print '</td>';
1127 }
1128 }
1129
1130 if (!empty($arrayfields['t.budget_amount']['checked'])) {
1131 print '<td class="liste_titre center">';
1132 print '<input type="text" class="flat" name="search_task_budget_amount" value="'.$search_task_budget_amount.'" size="4">';
1133 print '</td>';
1134 }
1135
1136 if (!empty($arrayfields['c.assigned']['checked'])) {
1137 print '<td class="liste_titre right">';
1138 print '</td>';
1139 }
1140
1141 if (!empty($arrayfields['t.billable']['checked'])) {
1142 print '<td class="liste_titre center">';
1143 print $form->selectyesno('search_task_billable', $search_task_billable, 0, false, 1);
1144 print '</td>';
1145 }
1146
1147 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
1148
1149 // Fields from hook
1150 $parameters = array('arrayfields' => $arrayfields);
1151 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1152 print $hookmanager->resPrint;
1153
1154 print '<td class="liste_titre maxwidthsearch">&nbsp;</td>';
1155
1156 // Action column
1157 if (!$conf->main_checkbox_left_column) {
1158 print '<td class="liste_titre maxwidthsearch">';
1159 $searchpicto = $form->showFilterButtons();
1160 print $searchpicto;
1161 print '</td>';
1162 }
1163
1164 print "</tr>\n";
1165
1166 print '<tr class="liste_titre nodrag nodrop">';
1167 // Action column
1168 if ($conf->main_checkbox_left_column) {
1169 print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
1170 }
1171 // print '<td>'.$langs->trans("Project").'</td>';
1172 if (!empty($arrayfields['t.ref']['checked'])) {
1173 // @phan-suppress-next-line PhanTypeInvalidDimOffset
1174 print_liste_field_titre($arrayfields['t.ref']['label'], $_SERVER["PHP_SELF"], 't.ref', '', $param, '', $sortfield, $sortorder, '');
1175 }
1176 if (!empty($arrayfields['t.label']['checked'])) {
1177 print_liste_field_titre($arrayfields['t.label']['label'], $_SERVER["PHP_SELF"], "t.label", '', $param, '', $sortfield, $sortorder, '');
1178 }
1179 if (!empty($arrayfields['t.description']['checked'])) {
1180 print_liste_field_titre($arrayfields['t.description']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, '');
1181 }
1182 if (!empty($arrayfields['t.dateo']['checked'])) {
1183 print_liste_field_titre($arrayfields['t.dateo']['label'], $_SERVER["PHP_SELF"], "t.dateo", '', $param, '', $sortfield, $sortorder, 'center ');
1184 }
1185 if (!empty($arrayfields['t.datee']['checked'])) {
1186 print_liste_field_titre($arrayfields['t.datee']['label'], $_SERVER["PHP_SELF"], "t.datee", '', $param, '', $sortfield, $sortorder, 'center ');
1187 }
1188 if (!empty($arrayfields['t.planned_workload']['checked'])) {
1189 print_liste_field_titre($arrayfields['t.planned_workload']['label'], $_SERVER["PHP_SELF"], "t.planned_workload", '', $param, '', $sortfield, $sortorder, 'right ', '', 1);
1190 }
1191 if (!empty($arrayfields['t.duration_effective']['checked'])) {
1192 print_liste_field_titre($arrayfields['t.duration_effective']['label'], $_SERVER["PHP_SELF"], "t.duration_effective", '', $param, '', $sortfield, $sortorder, 'right ', '', 1);
1193 }
1194 if (!empty($arrayfields['t.progress_calculated']['checked'])) {
1195 print_liste_field_titre($arrayfields['t.progress_calculated']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'right ', '', 1);
1196 }
1197 if (!empty($arrayfields['t.progress']['checked'])) {
1198 print_liste_field_titre($arrayfields['t.progress']['label'], $_SERVER["PHP_SELF"], "t.progress", '', $param, '', $sortfield, $sortorder, 'right ', '', 1);
1199 }
1200 if (!empty($arrayfields['t.progress_summary']['checked'])) {
1201 print_liste_field_titre($arrayfields['t.progress_summary']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center ', '', 1);
1202 }
1203 if (!empty($arrayfields['t.fk_statut']['checked'])) {
1204 print_liste_field_titre($arrayfields['t.fk_statut']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center ', '');
1205 }
1206 if ($object->usage_bill_time) {
1207 if (!empty($arrayfields['t.tobill']['checked'])) {
1208 print_liste_field_titre($arrayfields['t.tobill']['label'], $_SERVER["PHP_SELF"], "t.tobill", '', $param, '', $sortfield, $sortorder, 'right ');
1209 }
1210 if (!empty($arrayfields['t.billed']['checked'])) {
1211 print_liste_field_titre($arrayfields['t.billed']['label'], $_SERVER["PHP_SELF"], "t.billed", '', $param, '', $sortfield, $sortorder, 'right ');
1212 }
1213 }
1214
1215 if (!empty($arrayfields['t.budget_amount']['checked'])) {
1216 print_liste_field_titre($arrayfields['t.budget_amount']['label'], $_SERVER["PHP_SELF"], "t.budget_amount", "", $param, '', $sortfield, $sortorder, 'center ');
1217 }
1218
1219 if (!empty($arrayfields['c.assigned']['checked'])) {
1220 print_liste_field_titre($arrayfields['c.assigned']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center ', '');
1221 }
1222
1223 if (!empty($arrayfields['t.billable']['checked'])) {
1224 print_liste_field_titre($arrayfields['t.billable']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center ', '');
1225 }
1226
1227 // Extra fields
1228 $disablesortlink = 1;
1229 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1230 // Hook fields
1231 $parameters = array('arrayfields' => $arrayfields, 'param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
1232 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
1233 print $hookmanager->resPrint;
1234 print '<td></td>';
1235 // Action column
1236 if (!$conf->main_checkbox_left_column) {
1237 print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
1238 }
1239 print "</tr>\n";
1240
1241 $nboftaskshown = 0;
1242 if (count($tasksarray) > 0) {
1243 // Show all lines in taskarray (recursive function to go down on tree)
1244 $j = 0;
1245 $level = 0;
1246 $nboftaskshown = projectLinesa($j, 0, $tasksarray, $level, '', 0, $tasksrole, (string) $object->id, 1, $object->id, '', ($object->usage_bill_time ? 1 : 0), $arrayfields, $arrayofselected);
1247 } else {
1248 $colspan = count($arrayfields);
1249 if ($object->usage_bill_time) {
1250 $colspan += 2;
1251 }
1252 print '<tr class="oddeven"><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoTasks").'</span></td></tr>';
1253 }
1254
1255 print "</table>";
1256 print '</div>';
1257
1258 print '</form>';
1259
1260
1261 // Test if database is clean. If not we clean it.
1262 //print 'mode='.$_REQUEST["mode"].' $nboftaskshown='.$nboftaskshown.' count($tasksarray)='.count($tasksarray).' count($tasksrole)='.count($tasksrole).'<br>';
1263 if ($user->hasRight('projet', 'all', 'lire')) { // We make test to clean only if user has permission to see all (test may report false positive otherwise)
1264 if ($search_user_id == $user->id) {
1265 if ($nboftaskshown < count($tasksrole)) {
1266 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1267 cleanCorruptedTree($db, 'projet_task', 'fk_task_parent');
1268 }
1269 } else {
1270 if ($nboftaskshown < count($tasksarray) && !GETPOSTINT('search_user_id')) {
1271 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1272 cleanCorruptedTree($db, 'projet_task', 'fk_task_parent');
1273 }
1274 }
1275 }
1276}
1277
1278// End of page
1279llxFooter();
1280$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Class to manage a WYSIWYG editor.
Class to manage standard extra fields.
Class to manage generation of HTML components Only common components must be here.
Class to help generate other html components Only common components are here.
Class to manage projects.
const STATUS_CLOSED
Closed status.
const STATUS_DRAFT
Draft status.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage tasks.
const STATUS_VALIDATED
Validated status (To do).
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:386
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
$date_start
Variables from include:
cleanCorruptedTree($db, $tabletocleantree, $fieldfkparent)
Clean corrupted database tree (orphelins linked to a not existing parent), record linked to themself,...
dol_now($mode='gmt')
Return date for now.
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...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
print_liste_field_titre($name, $file="", $field="", $begin="", $param="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
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.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dolPrintHTML($s, $allowiframe=0, $moreallowedtags=array())
Return a string (that can be on several lines) ready to be output on a HTML page.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
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.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
natural_search($fields, $value, $mode=0, $nofirstand=0, $sqltoadd='')
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
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.