dolibarr 25.0.0-alpha
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_task_');
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 $search_options_pattern = 'search_task_options_';
636 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
637
638 $arrayofmassactions = array();
639 if ($user->hasRight('projet', 'creer')) {
640 $arrayofmassactions['preclonetasks'] = img_picto('', 'clone', 'class="pictofixedwidth"').$langs->trans("Clone");
641 }
642 if ($permissiontodelete) {
643 $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
644 }
645 if (in_array($massaction, array('presend', 'predelete'))) {
646 $arrayofmassactions = array();
647 }
648 $massactionbutton = $form->selectMassAction('', $arrayofmassactions) ?? '';
649
650 // Project card
651
652 if (!empty($_SESSION['pageforbacktolist']) && !empty($_SESSION['pageforbacktolist']['project'])) {
653 $tmpurl = $_SESSION['pageforbacktolist']['project'];
654 $tmpurl = preg_replace('/__SOCID__/', (string) $object->socid, $tmpurl);
655 $linkback = '<a href="'.$tmpurl.(preg_match('/\?/', $tmpurl) ? '&' : '?'). 'restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
656 } else {
657 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
658 }
659
660 $morehtmlref = '<div class="refidno">';
661 // Title
662 $morehtmlref .= $object->title;
663 // Thirdparty
664 if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
665 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'project');
666 }
667 $morehtmlref .= '</div>';
668
669 // Define a complementary filter for search of next/prev ref.
670 if (!$user->hasRight('projet', 'all', 'lire')) {
671 $objectsListId = $object->getProjectsAuthorizedForUser($user, 0, 0);
672 $object->next_prev_filter = "rowid:IN:".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0');
673 }
674
675 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
676
677 print '<div class="fichecenter">';
678 print '<div class="fichehalfleft">';
679 print '<div class="underbanner clearboth"></div>';
680
681 print '<table class="border tableforfield centpercent">';
682
683 // Usage
684 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJECT_HIDE_TASKS') || isModEnabled('eventorganization')) {
685 print '<tr><td class="tdtop">';
686 print $langs->trans("Usage");
687 print '</td>';
688 print '<td>';
689 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
690 print '<input type="checkbox" disabled name="usage_opportunity"'.(GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_opportunity ? ' checked="checked"' : '')).'"> ';
691 $htmltext = $langs->trans("ProjectFollowOpportunity");
692 print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
693 print '<br>';
694 }
695 if (!getDolGlobalString('PROJECT_HIDE_TASKS')) {
696 print '<input type="checkbox" disabled name="usage_task"'.(GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_task ? ' checked="checked"' : '')).'"> ';
697 $htmltext = $langs->trans("ProjectFollowTasks");
698 print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
699 print '<br>';
700 }
701 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
702 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"' : '')).'"> ';
703 $htmltext = $langs->trans("ProjectBillTimeDescription");
704 print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
705 print '<br>';
706 }
707 if (isModEnabled('eventorganization')) {
708 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"' : '')).'"> ';
709 $htmltext = $langs->trans("EventOrganizationDescriptionLong");
710 print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
711 }
712 print '</td></tr>';
713 }
714
715 // Budget
716 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
717 if (!is_null($object->budget_amount) && strcmp($object->budget_amount, '')) {
718 print '<span class="amount">'.price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
719 }
720 print '</td></tr>';
721
722 // Date start - end project
723 print '<tr><td>'.$langs->trans("Dates").'</td><td>';
724 $start = dol_print_date($object->date_start, 'day');
725 print($start ? $start : '?');
726 $end = dol_print_date($object->date_end, 'day');
727 print ' - ';
728 print($end ? $end : '?');
729 if ($object->hasDelay()) {
730 print img_warning("Late");
731 }
732 print '</td></tr>';
733
734 // Visibility
735 print '<tr><td class="titlefield">'.$langs->trans("Visibility").'</td><td>';
736 if ($object->public) {
737 print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
738 print $langs->trans('SharedProject');
739 } else {
740 print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
741 print $langs->trans('PrivateProject');
742 }
743 print '</td></tr>';
744
745 // Other attributes
746 $cols = 2;
747 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
748
749 print '</table>';
750
751 print '</div>';
752 print '<div class="fichehalfright">';
753 print '<div class="underbanner clearboth"></div>';
754
755 print '<table class="border tableforfield centpercent">';
756
757 // Categories
758 if (isModEnabled('category')) {
759 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
760 print $form->showCategories($object->id, Categorie::TYPE_PROJECT, 1);
761 print "</td></tr>";
762 }
763
764 // Description
765 print '<tr><td class="titlefield'.($object->description ? ' noborderbottom' : '').'" colspan="2">'.$langs->trans("Description").'</td></tr>';
766 if ($object->description) {
767 print '<tr><td class="nottitleforfield" colspan="2">';
768 print '<div class="longmessagecut">';
769 print dolPrintHTML($object->description);
770 print '</div>';
771 print '</td></tr>';
772 }
773
774 print '</table>';
775
776 print '</div>';
777 print '</div>';
778
779 print '<div class="clearboth"></div>';
780
781
782 print dol_get_fiche_end();
783}
784
785
786if ($action == 'create' && $user->hasRight('projet', 'creer') && (empty($object->thirdparty->id) || $userWrite > 0)) {
787 if ($id > 0 || !empty($ref)) {
788 print '<br>';
789 }
790
791 print load_fiche_titre($langs->trans("NewTask"), '', 'projecttask');
792
793 $projectoktoentertime = 1;
794 if ($object->id > 0 && $object->status == Project::STATUS_CLOSED) {
795 $projectoktoentertime = 0;
796 print '<div class="warning">';
797 $langs->load("errors");
798 print $langs->trans("WarningProjectClosed");
799 print '</div>';
800 }
801
802 if ($object->id > 0 && $object->status == Project::STATUS_DRAFT) {
803 $projectoktoentertime = 0;
804 print '<div class="warning">';
805 $langs->load("errors");
806 print $langs->trans("WarningProjectDraft");
807 print '</div>';
808 }
809
810 print '<form action="'.$_SERVER['PHP_SELF'].'" method="POST">';
811 print '<input type="hidden" name="token" value="'.newToken().'">';
812 print '<input type="hidden" name="action" value="createtask">';
813 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
814 if (!empty($object->id)) {
815 print '<input type="hidden" name="id" value="'.$object->id.'">';
816 }
817
818 print dol_get_fiche_head();
819
820 print '<div class="div-table-responsive-no-min">';
821 print '<table class="border centpercent">';
822
823 $defaultref = '';
824 $classnamemodtask = getDolGlobalString('PROJECT_TASK_ADDON', 'mod_task_simple');
825 if (getDolGlobalString('PROJECT_TASK_ADDON') && is_readable(DOL_DOCUMENT_ROOT."/core/modules/project/task/" . getDolGlobalString('PROJECT_TASK_ADDON').".php")) {
826 require_once DOL_DOCUMENT_ROOT."/core/modules/project/task/" . getDolGlobalString('PROJECT_TASK_ADDON').'.php';
827 $modTask = new $classnamemodtask();
828 '@phan-var-force ModeleNumRefTask $modTask';
829 $tasktmp = new Task($db); // Numbering modules expect a Task object (and use its creation date), not the project
830 $tasktmp->fk_project = $object->id;
831 $defaultref = $modTask->getNextValue($object->thirdparty, $tasktmp);
832 }
833
834 if (is_numeric($defaultref) && $defaultref <= 0) {
835 $defaultref = '';
836 }
837
838 // Ref
839 print '<tr><td class="titlefieldcreate"><span class="fieldrequired">'.$langs->trans("Ref").'</span></td><td>';
840 if (empty($duplicate_code_error)) {
841 print(GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : $defaultref);
842 } else {
843 print $defaultref;
844 }
845 print '<input type="hidden" name="taskref" value="'.(GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : $defaultref).'">';
846 print '</td></tr>';
847
848 // Label
849 print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td>';
850 print '<input type="text" name="label" autofocus class="minwidth500" value="'.$label.'">';
851 print '</td></tr>';
852
853 // Project
854 print '<tr><td class="fieldrequired">'.$langs->trans("ChildOfProjectTask").'</td><td>';
855 print img_picto('', 'project', 'class="pictofixedwidth"');
856 if ($projectoktoentertime) {
857 $formother->selectProjectTasks(GETPOSTINT('task_parent'), empty($projectid) ? $object->id : $projectid, 'task_parent', 0, 0, 1, 1, 0, '0,1', 'maxwidth500 widthcentpercentminusxx');
858 } else {
859 $formother->selectProjectTasks(GETPOSTINT('task_parent'), empty($projectid) ? $object->id : $projectid, 'task_parent', 0, 0, 1, 1, 0, '', 'maxwidth500 widthcentpercentminusxx');
860 }
861 print '</td></tr>';
862
863 $contactsofproject = (empty($object->id) ? '' : $object->getListContactId('internal'));
864
865 // Assigned to
866 print '<tr><td>'.$langs->trans("AffectedTo").'</td><td>';
867 print img_picto('', 'user', 'class="pictofixedwidth"');
868 if (is_array($contactsofproject) && count($contactsofproject)) {
869 print $form->select_dolusers('-4', 'userid', 0, null, 0, '', $contactsofproject, '0', 0, 0, '(statut:=:1)', 4, '', 'maxwidth500 widthcentpercentminusx');
870 } else {
871 if ((isset($projectid) && $projectid > 0) || $object->id > 0) {
872 print '<span class="opacitymedium">'.$langs->trans("NoUserAssignedToTheProject").'</span>';
873 } else {
874 print $form->select_dolusers('-4', 'userid', 0, null, 0, '', '', '0', 0, 0, '(statut:=:1)', 4, '', 'maxwidth500 widthcentpercentminusx');
875 }
876 }
877 print '</td></tr>';
878
879 // Billable
880 print '<tr><td>'.$langs->trans("Billable").'</td><td>';
881 print $form->selectyesno('billable');
882 print '</td></tr>';
883
884 // Date start task
885 print '<tr><td>'.$langs->trans("DateStart").'</td><td>';
886 print img_picto('', 'action', 'class="pictofixedwidth"');
887 print $form->selectDate((!empty($date_start) ? $date_start : ''), 'date_start', 1, 1, 0, '', 1, 1);
888 print '</td></tr>';
889
890 // Date end task
891 print '<tr><td>'.$langs->trans("DateEnd").'</td><td>';
892 print img_picto('', 'action', 'class="pictofixedwidth"');
893 print $form->selectDate((!empty($date_end) ? $date_end : -1), 'date_end', -1, 1, 0, '', 1, 1);
894 print '</td></tr>';
895
896 // Planned workload
897 print '<tr><td>'.$langs->trans("PlannedWorkload").'</td><td>';
898 print img_picto('', 'clock', 'class="pictofixedwidth"');
899 print $form->select_duration('planned_workload', $planned_workload, 0, 'text');
900 print '</td></tr>';
901
902 // Progress
903 print '<tr><td>'.$langs->trans("ProgressDeclared").'</td><td colspan="3">';
904 print img_picto('', 'fa-percent', 'class="pictofixedwidth"');
905 print $formother->select_percent($progress, 'progress', 0, 5, 0, 100, 1);
906 print '</td></tr>';
907
908 // Description
909 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td>';
910 print '<td>';
911
912 // WYSIWYG editor
913 include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
914 $nbrows = 0;
915 if (getDolGlobalString('MAIN_INPUT_DESC_HEIGHT')) {
916 $nbrows = getDolGlobalString('MAIN_INPUT_DESC_HEIGHT');
917 }
918 $doleditor = new DolEditor('description', $object->description, '', 80, 'dolibarr_details', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), $nbrows, '90%');
919 print $doleditor->Create();
920
921 print '</td></tr>';
922
923 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
924 print img_picto('', 'currency', 'class="pictofixedwidth"');
925 print '<input size="8" type="text" name="budget_amount" value="'.dol_escape_htmltag(GETPOSTISSET('budget_amount') ? GETPOST('budget_amount') : '').'"></td>';
926 print '</tr>';
927
928 // Other options
929 $parameters = array('arrayfields' => &$arrayfields);
930 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $taskstatic, $action); // Note that $action and $object may have been modified by hook
931 print $hookmanager->resPrint;
932
933 if (empty($reshook) && !empty($extrafields->attributes[$taskstatic->table_element]['label'])) {
934 print $taskstatic->showOptionals($extrafields, 'edit'); // Do not use $object here that is object of project but use $taskstatic
935 }
936
937 print '</table>';
938 print '</div>';
939
940 print dol_get_fiche_end();
941
942 print $form->buttonsSaveCancel("Add");
943
944 print '</form>';
945} elseif ($id > 0 || !empty($ref)) {
946 $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, $conf->main_checkbox_left_column); // This also change content of $arrayfields
947
948 // Projet card in view mode
949
950 print '<br>';
951
952 // Link to create task
953 $linktocreatetaskParam = array();
954 $linktocreatetaskUserRight = false;
955 if ($user->hasRight('projet', 'all', 'creer') || $user->hasRight('projet', 'creer')) {
956 if ($object->public || $userWrite > 0) {
957 $linktocreatetaskUserRight = true;
958 } else {
959 $linktocreatetaskParam['attr']['title'] = $langs->trans("NotOwnerOfProject");
960 }
961 }
962
963 $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);
964
965 print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
966 print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
967 print '<input type="hidden" name="token" value="'.newToken().'">';
968 print '<input type="hidden" name="action" value="list">';
969 print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
970 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
971 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
972 print '<input type="hidden" name="page" value="'.$page.'">';
973 print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
974
975 $title = $langs->trans("ListOfTasks");
976 $linktotasks = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id, '', 1, array('morecss' => 'reposition btnTitleSelected'));
977 $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'));
978
979 //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1);
980 print load_fiche_titre($title, $linktotasks.' &nbsp; '.$linktocreatetask, 'projecttask', 0, '', '', $massactionbutton);
981
982 $objecttmp = new Task($db);
983 $trackid = 'task'.$taskstatic->id;
984 include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
985
986 // Get list of tasks in tasksarray and taskarrayfiltered
987 // 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).
988 $filteronthirdpartyid = $socid;
989 $tasksarray = $taskstatic->getTasksArray(null, null, $object->id, $filteronthirdpartyid, 0, '', '-1', $morewherefilter, 0, 0, $extrafields, 1, $search_array_options, 1, 1, $sortfield, $sortorder);
990
991 // We load also tasks limited to a particular user
992 $tmpuser = new User($db);
993 if ($search_user_id > 0) {
994 $tmpuser->fetch($search_user_id);
995 }
996
997 $tasksrole = ($tmpuser->id > 0 ? $taskstatic->getUserRolesForProjectsOrTasks(null, $tmpuser, (string) $object->id, 0) : '');
998 //var_dump($tasksarray);
999 //var_dump($tasksrole);
1000
1001 if (!empty($conf->use_javascript_ajax)) {
1002 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
1003 }
1004
1005 // Filter on assigned users
1006 $moreforfilter = '';
1007 $moreforfilter .= '<div class="divsearchfield">';
1008 $moreforfilter .= img_picto('', 'user', 'class="pictofixedwidth"');
1009 $moreforfilter .= $form->select_dolusers($tmpuser->id > 0 ? $tmpuser->id : '', 'search_user_id', $langs->trans("TasksAssignedTo"), null, 0, '', '');
1010 $moreforfilter .= '</div>';
1011 if ($moreforfilter) {
1012 print '<div class="liste_titre liste_titre_bydiv centpercent">';
1013 print $moreforfilter;
1014 print '</div>';
1015 }
1016
1017 // Show the massaction checkboxes only when this page is not opened from the Extended POS
1018 if (!empty($massactionbutton) && $contextpage != 'poslist') {
1019 $selectedfields .= $form->showCheckAddButtons('checkforselect', 1);
1020 }
1021
1022 print '<div class="div-table-responsive">';
1023 print '<table id="tablelines" class="tagtable nobottom liste'.($moreforfilter ? " listwithfilterbefore" : "").'">';
1024
1025 // Fields title search
1026 print '<tr class="liste_titre_filter">';
1027
1028 // Action column
1029 if ($conf->main_checkbox_left_column) {
1030 print '<td class="liste_titre maxwidthsearch">';
1031 $searchpicto = $form->showFilterButtons();
1032 print $searchpicto;
1033 print '</td>';
1034 }
1035
1036 if (!empty($arrayfields['t.ref']['checked'])) {
1037 print '<td class="liste_titre">';
1038 print '<input class="flat searchstring maxwidth50" type="text" name="search_taskref" value="'.dol_escape_htmltag($search_taskref).'">';
1039 print '</td>';
1040 }
1041
1042 if (!empty($arrayfields['t.label']['checked'])) {
1043 print '<td class="liste_titre">';
1044 print '<input class="flat searchstring maxwidth100" type="text" name="search_tasklabel" value="'.dol_escape_htmltag($search_tasklabel).'">';
1045 print '</td>';
1046 }
1047
1048 if (!empty($arrayfields['t.description']['checked'])) {
1049 print '<td class="liste_titre">';
1050 print '<input class="flat searchstring maxwidth100" type="text" name="search_taskdescription" value="'.dol_escape_htmltag($search_taskdescription).'">';
1051 print '</td>';
1052 }
1053
1054 if (!empty($arrayfields['t.dateo']['checked'])) {
1055 print '<td class="liste_titre center">';
1056 /*print '<span class="nowraponall"><input class="flat valignmiddle width20" type="text" maxlength="2" name="search_dtstartday" value="'.$search_dtstartday.'">';
1057 print '<input class="flat valignmiddle width20" type="text" maxlength="2" name="search_dtstartmonth" value="'.$search_dtstartmonth.'"></span>';
1058 print $formother->selectyear($search_dtstartyear ? $search_dtstartyear : -1, 'search_dtstartyear', 1, 20, 5);*/
1059 print '<div class="nowrapfordate">';
1060 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'));
1061 print '</div>';
1062 print '<div class="nowrapfordate">';
1063 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'));
1064 print '</div>';
1065 print '</td>';
1066 }
1067
1068 if (!empty($arrayfields['t.datee']['checked'])) {
1069 print '<td class="liste_titre center">';
1070 /*print '<span class="nowraponall"><input class="flat valignmiddle width20" type="text" maxlength="2" name="search_dtendday" value="'.$search_dtendday.'">';
1071 print '<input class="flat valignmiddle width20" type="text" maxlength="2" name="search_dtendmonth" value="'.$search_dtendmonth.'"></span>';
1072 print $formother->selectyear($search_dtendyear ? $search_dtendyear : -1, 'search_dtendyear', 1, 20, 5);*/
1073 print '<div class="nowrapfordate">';
1074 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'));
1075 print '</div>';
1076 print '<div class="nowrapfordate">';
1077 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'));
1078 print '</div>';
1079 print '</td>';
1080 }
1081
1082 if (!empty($arrayfields['t.planned_workload']['checked'])) {
1083 print '<td class="liste_titre right">';
1084 print '<input class="flat" type="text" size="4" name="search_planedworkload" value="'.$search_planedworkload.'">';
1085 print '</td>';
1086 }
1087
1088 if (!empty($arrayfields['t.duration_effective']['checked'])) {
1089 print '<td class="liste_titre right">';
1090 print '<input class="flat" type="text" size="4" name="search_timespend" value="'.$search_timespend.'">';
1091 print '</td>';
1092 }
1093
1094 if (!empty($arrayfields['t.progress_calculated']['checked'])) {
1095 print '<td class="liste_titre right">';
1096 print '<input class="flat" type="text" size="4" name="search_progresscalc" value="'.$search_progresscalc.'">';
1097 print '</td>';
1098 }
1099
1100 if (!empty($arrayfields['t.progress']['checked'])) {
1101 print '<td class="liste_titre right">';
1102 print '<input class="flat" type="text" size="4" name="search_progressdeclare" value="'.$search_progressdeclare.'">';
1103 print '</td>';
1104 }
1105
1106 // progress resume not searchable
1107 if (!empty($arrayfields['t.progress_summary']['checked'])) {
1108 print '<td class="liste_titre right"></td>';
1109 }
1110
1111 if (!empty($arrayfields['t.fk_statut']['checked'])) {
1112 print '<td class="liste_titre center">';
1113 $arrayofstatus = array();
1114 foreach ($taskstatic->labelStatusShort as $key => $val) {
1115 $arrayofstatus[$key] = $langs->trans($val);
1116 }
1117 print $form->selectarray('search_status', $arrayofstatus, $search_status, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth100');
1118 print '</td>';
1119 }
1120
1121 if ($object->usage_bill_time) {
1122 if (!empty($arrayfields['t.tobill']['checked'])) {
1123 print '<td class="liste_titre right">';
1124 print '</td>';
1125 }
1126
1127 if (!empty($arrayfields['t.billed']['checked'])) {
1128 print '<td class="liste_titre right">';
1129 print '</td>';
1130 }
1131 }
1132
1133 if (!empty($arrayfields['t.budget_amount']['checked'])) {
1134 print '<td class="liste_titre center">';
1135 print '<input type="text" class="flat" name="search_task_budget_amount" value="'.$search_task_budget_amount.'" size="4">';
1136 print '</td>';
1137 }
1138
1139 if (!empty($arrayfields['c.assigned']['checked'])) {
1140 print '<td class="liste_titre right">';
1141 print '</td>';
1142 }
1143
1144 if (!empty($arrayfields['t.billable']['checked'])) {
1145 print '<td class="liste_titre center">';
1146 print $form->selectyesno('search_task_billable', $search_task_billable, 0, false, 1);
1147 print '</td>';
1148 }
1149
1150 $search_options_pattern = 'search_task_options_';
1151 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
1152
1153 // Fields from hook
1154 $parameters = array('arrayfields' => $arrayfields);
1155 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1156 print $hookmanager->resPrint;
1157
1158 print '<td class="liste_titre maxwidthsearch">&nbsp;</td>';
1159
1160 // Action column
1161 if (!$conf->main_checkbox_left_column) {
1162 print '<td class="liste_titre maxwidthsearch">';
1163 $searchpicto = $form->showFilterButtons();
1164 print $searchpicto;
1165 print '</td>';
1166 }
1167
1168 print "</tr>\n";
1169
1170 print '<tr class="liste_titre nodrag nodrop">';
1171 // Action column
1172 if ($conf->main_checkbox_left_column) {
1173 print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
1174 }
1175 // print '<td>'.$langs->trans("Project").'</td>';
1176 if (!empty($arrayfields['t.ref']['checked'])) {
1177 // @phan-suppress-next-line PhanTypeInvalidDimOffset
1178 print_liste_field_titre($arrayfields['t.ref']['label'], $_SERVER["PHP_SELF"], 't.ref', '', $param, '', $sortfield, $sortorder, '');
1179 }
1180 if (!empty($arrayfields['t.label']['checked'])) {
1181 print_liste_field_titre($arrayfields['t.label']['label'], $_SERVER["PHP_SELF"], "t.label", '', $param, '', $sortfield, $sortorder, '');
1182 }
1183 if (!empty($arrayfields['t.description']['checked'])) {
1184 print_liste_field_titre($arrayfields['t.description']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, '');
1185 }
1186 if (!empty($arrayfields['t.dateo']['checked'])) {
1187 print_liste_field_titre($arrayfields['t.dateo']['label'], $_SERVER["PHP_SELF"], "t.dateo", '', $param, '', $sortfield, $sortorder, 'center ');
1188 }
1189 if (!empty($arrayfields['t.datee']['checked'])) {
1190 print_liste_field_titre($arrayfields['t.datee']['label'], $_SERVER["PHP_SELF"], "t.datee", '', $param, '', $sortfield, $sortorder, 'center ');
1191 }
1192 if (!empty($arrayfields['t.planned_workload']['checked'])) {
1193 print_liste_field_titre($arrayfields['t.planned_workload']['label'], $_SERVER["PHP_SELF"], "t.planned_workload", '', $param, '', $sortfield, $sortorder, 'right ', '', 1);
1194 }
1195 if (!empty($arrayfields['t.duration_effective']['checked'])) {
1196 print_liste_field_titre($arrayfields['t.duration_effective']['label'], $_SERVER["PHP_SELF"], "t.duration_effective", '', $param, '', $sortfield, $sortorder, 'right ', '', 1);
1197 }
1198 if (!empty($arrayfields['t.progress_calculated']['checked'])) {
1199 print_liste_field_titre($arrayfields['t.progress_calculated']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'right ', '', 1);
1200 }
1201 if (!empty($arrayfields['t.progress']['checked'])) {
1202 print_liste_field_titre($arrayfields['t.progress']['label'], $_SERVER["PHP_SELF"], "t.progress", '', $param, '', $sortfield, $sortorder, 'right ', '', 1);
1203 }
1204 if (!empty($arrayfields['t.progress_summary']['checked'])) {
1205 print_liste_field_titre($arrayfields['t.progress_summary']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center ', '', 1);
1206 }
1207 if (!empty($arrayfields['t.fk_statut']['checked'])) {
1208 print_liste_field_titre($arrayfields['t.fk_statut']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center ', '');
1209 }
1210 if ($object->usage_bill_time) {
1211 if (!empty($arrayfields['t.tobill']['checked'])) {
1212 print_liste_field_titre($arrayfields['t.tobill']['label'], $_SERVER["PHP_SELF"], "t.tobill", '', $param, '', $sortfield, $sortorder, 'right ');
1213 }
1214 if (!empty($arrayfields['t.billed']['checked'])) {
1215 print_liste_field_titre($arrayfields['t.billed']['label'], $_SERVER["PHP_SELF"], "t.billed", '', $param, '', $sortfield, $sortorder, 'right ');
1216 }
1217 }
1218
1219 if (!empty($arrayfields['t.budget_amount']['checked'])) {
1220 print_liste_field_titre($arrayfields['t.budget_amount']['label'], $_SERVER["PHP_SELF"], "t.budget_amount", "", $param, '', $sortfield, $sortorder, 'center ');
1221 }
1222
1223 if (!empty($arrayfields['c.assigned']['checked'])) {
1224 print_liste_field_titre($arrayfields['c.assigned']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center ', '');
1225 }
1226
1227 if (!empty($arrayfields['t.billable']['checked'])) {
1228 print_liste_field_titre($arrayfields['t.billable']['label'], $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center ', '');
1229 }
1230
1231 // Extra fields
1232 $disablesortlink = 1;
1233 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1234 // Hook fields
1235 $parameters = array('arrayfields' => $arrayfields, 'param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
1236 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
1237 print $hookmanager->resPrint;
1238 print '<td></td>';
1239 // Action column
1240 if (!$conf->main_checkbox_left_column) {
1241 print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
1242 }
1243 print "</tr>\n";
1244
1245 $nboftaskshown = 0;
1246 if (count($tasksarray) > 0) {
1247 // Show all lines in taskarray (recursive function to go down on tree)
1248 $j = 0;
1249 $level = 0;
1250 $nboftaskshown = projectLinesa($j, 0, $tasksarray, $level, '', 0, $tasksrole, (string) $object->id, 1, $object->id, '', ($object->usage_bill_time ? 1 : 0), $arrayfields, $arrayofselected);
1251 } else {
1252 $colspan = count($arrayfields);
1253 if ($object->usage_bill_time) {
1254 $colspan += 2;
1255 }
1256 print '<tr class="oddeven"><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoTasks").'</span></td></tr>';
1257 }
1258
1259 print "</table>";
1260 print '</div>';
1261
1262 print '</form>';
1263
1264
1265 // Test if database is clean. If not we clean it.
1266 //print 'mode='.$_REQUEST["mode"].' $nboftaskshown='.$nboftaskshown.' count($tasksarray)='.count($tasksarray).' count($tasksrole)='.count($tasksrole).'<br>';
1267 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)
1268 if ($search_user_id == $user->id) {
1269 if ($nboftaskshown < count($tasksrole)) {
1270 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1271 cleanCorruptedTree($db, 'projet_task', 'fk_task_parent');
1272 }
1273 } else {
1274 if ($nboftaskshown < count($tasksarray) && !GETPOSTINT('search_user_id')) {
1275 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1276 cleanCorruptedTree($db, 'projet_task', 'fk_task_parent');
1277 }
1278 }
1279 }
1280}
1281
1282// End of page
1283llxFooter();
1284$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:391
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
$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...
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...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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).
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
print_liste_field_titre($name, $file="", $field="", $begin="", $param="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
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.
Definition html.lib.php:540
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.
Definition html.lib.php:738
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
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, $nodie=0, $mode='')
Check permissions of a user to show a page and an object.