dolibarr 23.0.3
task.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2006-2017 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2010-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2018-2025 Frédéric France <frederic.france@free.fr>
6 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
7 * Copyright (C) 2024 Vincent de Grandpré <vincent@de-grandpre.quebec>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
29require "../../main.inc.php";
37require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
38require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
39require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
40require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
41require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
42require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
43require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
44require_once DOL_DOCUMENT_ROOT.'/core/modules/project/task/modules_task.php';
45require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
46
47// Load translation files required by the page
48$langs->loadlangs(array('projects', 'companies'));
49
50$action = GETPOST('action', 'aZ09');
51$confirm = GETPOST('confirm', 'alpha');
52//$cancel = GETPOST('cancel');
53//$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : str_replace('_', '', basename(dirname(__FILE__)).basename(__FILE__, '.php')); // To manage different context of search
54//$backtopage = GETPOST('backtopage', 'alpha'); // if not set, a default page will be used
55//$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); // if not set, $backtopage will be used
56
57$id = GETPOSTINT('id');
58$ref = GETPOST("ref", 'alpha', 1); // task ref
59$taskref = GETPOST("taskref", 'alpha'); // task ref
60$withproject = GETPOSTINT('withproject');
61$project_ref = GETPOST('project_ref', 'alpha');
62$planned_workload = ((GETPOST('planned_workloadhour') != '' || GETPOST('planned_workloadmin') != '') ? (GETPOSTINT('planned_workloadhour') > 0 ? GETPOSTINT('planned_workloadhour') * 3600 : 0) + (GETPOSTINT('planned_workloadmin') > 0 ? GETPOSTINT('planned_workloadmin') * 60 : 0) : '');
63$mode = GETPOST('mode', 'alpha');
64
65// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
66$hookmanager->initHooks(array('projecttaskcard', 'globalcard'));
67
68$object = new Task($db);
69$extrafields = new ExtraFields($db);
70$projectstatic = new Project($db);
71
72// fetch optionals attributes and labels
73$extrafields->fetch_name_optionals_label($object->table_element);
74
75$parameters = array('id' => $id);
76$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
77if ($reshook < 0) {
78 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
79}
80
81if ($id > 0 || $ref) {
82 $ret = $object->fetch($id, $ref);
83 if ($ret > 0) {
84 $projectstatic->fetch($object->fk_project);
85 }
86}
87
88// Security check
89$socid = 0;
90
91restrictedArea($user, 'projet', $object->fk_project, 'projet&project');
92
93
94
95/*
96 * Actions
97 */
98
99$error = 0;
100
101if ($action == 'update' && !GETPOST("cancel") && $user->hasRight('projet', 'creer')) {
102 if (empty($taskref)) {
103 $error++;
104 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Ref")), null, 'errors');
105 }
106 if (!GETPOST("label")) {
107 $error++;
108 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
109 }
110 if (!$error) {
111 $object->oldcopy = clone $object; // @phan-suppress-current-line PhanTypeMismatchProperty
112
113 $tmparray = explode('_', GETPOST('task_parent'));
114 $task_parent = $tmparray[1];
115 if (empty($task_parent)) {
116 $task_parent = 0; // If task_parent is ''
117 }
118
119 $object->ref = $taskref ? $taskref : GETPOST("ref", 'alpha', 2);
120 $object->label = GETPOST("label", "alphanohtml");
121 if (!getDolGlobalString('FCKEDITOR_ENABLE_SOCIETE')) {
122 $object->description = GETPOST('description', "alphanohtml");
123 } else {
124 $object->description = GETPOST('description', "restricthtml");
125 }
126 $object->fk_task_parent = $task_parent;
127 $object->planned_workload = $planned_workload;
128 $object->date_start = dol_mktime(GETPOSTINT('date_starthour'), GETPOSTINT('date_startmin'), 0, GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
129 $object->date_end = dol_mktime(GETPOSTINT('date_endhour'), GETPOSTINT('date_endmin'), 0, GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
130 $object->progress = price2num(GETPOST('progress', 'alphanohtml'));
131 $object->budget_amount = (GETPOST('budget_amount') != '' ? GETPOSTFLOAT('budget_amount'): null);
132 $object->billable = (GETPOST('billable', 'aZ') == 'yes' ? 1 : 0);
133 if (GETPOST('progress') == '100') {
134 $object->status = $object::STATUS_CLOSED;
135 } elseif (GETPOST('progress') != '0') {
136 $object->status = $object::STATUS_ONGOING;
137 }
138
139 // Fill array 'array_options' with data from add form
140 $ret = $extrafields->setOptionalsFromPost(null, $object, '@GETPOSTISSET');
141 if ($ret < 0) {
142 $error++;
143 }
144
145 if (!$error) {
146 $result = $object->update($user);
147 if ($result < 0) {
148 setEventMessages($object->error, $object->errors, 'errors');
149 $action = 'edit';
150 }
151 } else {
152 $action = 'edit';
153 }
154 } else {
155 $action = 'edit';
156 }
157}
158
159if ($action == 'confirm_merge' && $confirm == 'yes' && $user->hasRight('projet', 'creer')) {
160 $task_origin_id = GETPOSTINT('task_origin');
161 $task_origin = new Task($db); // The Task that we will delete
162
163 if ($task_origin_id <= 0) {
164 $langs->load('errors');
165 setEventMessages($langs->trans('ErrorTaskIdIsMandatory', $langs->transnoentitiesnoconv('MergeOriginTask')), null, 'errors');
166 } else {
167 if (!$error && $task_origin->fetch($task_origin_id) < 1) {
168 setEventMessages($langs->trans('ErrorRecordNotFound'), null, 'errors');
169 $error++;
170 }
171 if (!$error) {
172 $result = $object->mergeTask($task_origin_id);
173 if ($result < 0) {
174 $error++;
175 setEventMessages($object->error, $object->errors, 'errors');
176 } else {
177 setEventMessages($langs->trans('TaskMergeSuccess'), null, 'mesgs');
178 }
179 }
180 }
181}
182
183if ($action == 'confirm_clone' && $confirm == 'yes' && $user->hasRight('projet', 'creer')) {
184 //$clone_contacts = GETPOST('clone_contacts') ? 1 : 0;
185 $clone_prog = GETPOST('clone_prog') ? 1 : 0;
186 $clone_time = GETPOST('clone_time') ? 1 : 0;
187 $clone_affectation = GETPOST('clone_affectation') ? 1 : 0;
188 $clone_change_dt = GETPOST('clone_change_dt') ? 1 : 0;
189 $clone_notes = GETPOST('clone_notes') ? 1 : 0;
190 $clone_file = GETPOST('clone_file') ? 1 : 0;
191 $result = $object->createFromClone($user, $object->id, $object->fk_project, $object->fk_task_parent, $clone_change_dt, $clone_affectation, $clone_time, $clone_file, $clone_notes, $clone_prog);
192 if ($result <= 0) {
193 setEventMessages($object->error, $object->errors, 'errors');
194 } else {
195 // Load new object
196 $newobject = new Task($db);
197 $newobject->fetch($result);
198 $newobject->fetch_optionals();
199 $newobject->fetch_thirdparty(); // Load new object
200 $object = $newobject;
201 $action = '';
202 }
203}
204
205if ($action == 'confirm_delete' && $confirm == "yes" && $user->hasRight('projet', 'supprimer')) {
206 $result = $projectstatic->fetch($object->fk_project);
207 $projectstatic->fetch_thirdparty();
208
209 // $object is task to delete
210 if ($object->delete($user) > 0) {
211 header('Location: '.DOL_URL_ROOT.'/projet/tasks.php?restore_lastsearch_values=1&id='.$projectstatic->id.($withproject ? '&withproject=1' : ''));
212 exit;
213 } else {
214 setEventMessages($object->error, $object->errors, 'errors');
215 $action = '';
216 }
217}
218
219if ($action == 'confirm_close' && $confirm == "yes" && $user->hasRight('projet', 'creer')) {
220 $result = $projectstatic->fetch($object->fk_project);
221 $projectstatic->fetch_thirdparty();
222
223 // $object is task to close
224 if ($object->setStatusCommon($user, Task::STATUS_CLOSED) <= 0) {
225 setEventMessages($object->error, $object->errors, 'errors');
226 }
227 $action = '';
228}
229
230// Retrieve First Task ID of Project if withprojet is on to allow project prev next to work
231if (!empty($project_ref) && !empty($withproject)) {
232 if ($projectstatic->fetch(0, $project_ref) > 0) {
233 $tasksarray = $object->getTasksArray(null, null, $projectstatic->id, $socid, 0);
234 if (count($tasksarray) > 0) {
235 $id = $tasksarray[0]->id;
236 } else {
237 header("Location: ".DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.(empty($mode) ? '' : '&mode='.$mode));
238 }
239 }
240}
241
242// Build doc
243if ($action == 'builddoc' && $user->hasRight('projet', 'creer')) {
244 // Save last template used to generate document
245 if (GETPOST('model')) {
246 $object->setDocModel($user, GETPOST('model', 'alpha'));
247 }
248
249 $outputlangs = $langs;
250 if (GETPOST('lang_id', 'aZ09')) {
251 $outputlangs = new Translate("", $conf);
252 $outputlangs->setDefaultLang(GETPOST('lang_id', 'aZ09'));
253 }
254 $result = $object->generateDocument($object->model_pdf, $outputlangs);
255 if ($result <= 0) {
256 setEventMessages($object->error, $object->errors, 'errors');
257 $action = '';
258 }
259}
260
261// Delete file in doc form
262if ($action == 'remove_file' && $user->hasRight('projet', 'creer')) {
263 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
264
265 $langs->load("other");
266 $upload_dir = $conf->project->dir_output."/".dol_sanitizeFileName($projectstatic->ref)."/".dol_sanitizeFileName($object->ref);
267 $file = $upload_dir.'/'.dol_sanitizeFileName(GETPOST('file'));
268
269 $ret = dol_delete_file($file, 1);
270 if ($ret) {
271 setEventMessages($langs->trans("FileWasRemoved", GETPOST('file')), null, 'mesgs');
272 } else {
273 setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('file')), null, 'errors');
274 }
275}
276
277// Reopen task
278if ($action == 'reopen' && $user->hasRight('projet', 'creer')) {
279 $result = $object->setStatusCommon($user, Task::STATUS_DRAFT);
280 if ($result >= 0) {
281 setEventMessages($langs->trans("TaskBackToDraft"), null, 'mesgs');
282 } else {
283 $error++;
284 setEventMessages($object->error, $object->errors, 'errors');
285 }
286}
287
288// Validate status of task
289if ($action == 'valid' && $user->hasRight('projet', 'creer')) {
290 $result = $object->setStatusCommon($user, Task::STATUS_VALIDATED);
291 if ($result >= 0) {
292 setEventMessages($langs->trans("TaskValidated"), null, 'mesgs');
293 } else {
294 $error++;
295 setEventMessages($object->error, $object->errors, 'errors');
296 }
297}
298
299
300/*
301 * View
302 */
303
304$form = new Form($db);
305$formother = new FormOther($db);
306$formfile = new FormFile($db);
307$formproject = new FormProjets($db);
308
309$title = (string) $object->ref;
310if (!empty($withproject)) {
311 $title .= ' | ' . $langs->trans("Project") . (!empty($projectstatic->ref) ? ': '.$projectstatic->ref : '') ;
312}
313$help_url = '';
314
315llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-project project-tasks page-task');
316
317
318if ($id > 0 || !empty($ref)) {
319 $res = $object->fetch_optionals();
320 if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_TASK') && empty($object->comments)) {
321 $object->fetchComments();
322 }
323
324 if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_PROJECT') && method_exists($projectstatic, 'fetchComments') && empty($projectstatic->comments)) {
325 $projectstatic->fetchComments();
326 }
327 if (!empty($projectstatic->socid)) {
328 $projectstatic->fetch_thirdparty();
329 }
330
331 $object->project = clone $projectstatic;
332
333 //$userWrite = $projectstatic->restrictedProjectArea($user, 'write');
334
335 if (!empty($withproject)) {
336 // Tabs for project
337 $tab = 'tasks';
338 $head = project_prepare_head($projectstatic);
339 print dol_get_fiche_head($head, $tab, $langs->trans("Project"), -1, ($projectstatic->public ? 'projectpub' : 'project'), 0, '', '');
340
341 $param = ($mode == 'mine' ? '&mode=mine' : '');
342
343 // Project card
344
345 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
346
347 $morehtmlref = '<div class="refidno">';
348 // Title
349 $morehtmlref .= $projectstatic->title;
350 // Thirdparty
351 if (!empty($projectstatic->thirdparty->id) && $projectstatic->thirdparty->id > 0) {
352 $morehtmlref .= '<br>'.$projectstatic->thirdparty->getNomUrl(1, 'project');
353 }
354 $morehtmlref .= '</div>';
355
356 // Define a complementary filter for search of next/prev ref.
357 if (!$user->hasRight('projet', 'all', 'lire')) {
358 $objectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 0);
359 $projectstatic->next_prev_filter = "rowid:IN:".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0');
360 }
361
362 dol_banner_tab($projectstatic, 'project_ref', $linkback, 1, 'ref', 'ref', $morehtmlref, $param);
363
364 print '<div class="fichecenter">';
365 print '<div class="fichehalfleft">';
366 print '<div class="underbanner clearboth"></div>';
367
368 print '<table class="border tableforfield centpercent">';
369
370 // Usage
371 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJECT_HIDE_TASKS') || isModEnabled('eventorganization')) {
372 print '<tr><td class="tdtop">';
373 print $langs->trans("Usage");
374 print '</td>';
375 print '<td>';
376 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
377 print '<input type="checkbox" disabled name="usage_opportunity"'.(GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_opportunity ? ' checked="checked"' : '')).'"> ';
378 $htmltext = $langs->trans("ProjectFollowOpportunity");
379 print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
380 print '<br>';
381 }
382 if (!getDolGlobalString('PROJECT_HIDE_TASKS')) {
383 print '<input type="checkbox" disabled name="usage_task"'.(GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_task ? ' checked="checked"' : '')).'"> ';
384 $htmltext = $langs->trans("ProjectFollowTasks");
385 print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
386 print '<br>';
387 }
388 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
389 print '<input type="checkbox" disabled name="usage_bill_time"'.(GETPOSTISSET('usage_bill_time') ? (GETPOST('usage_bill_time', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_bill_time ? ' checked="checked"' : '')).'"> ';
390 $htmltext = $langs->trans("ProjectBillTimeDescription");
391 print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
392 print '<br>';
393 }
394 if (isModEnabled('eventorganization')) {
395 print '<input type="checkbox" disabled name="usage_organize_event"'.(GETPOSTISSET('usage_organize_event') ? (GETPOST('usage_organize_event', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_organize_event ? ' checked="checked"' : '')).'"> ';
396 $htmltext = $langs->trans("EventOrganizationDescriptionLong");
397 print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
398 }
399 print '</td></tr>';
400 }
401
402 // Budget
403 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
404 if (isset($projectstatic->budget_amount) && strcmp($projectstatic->budget_amount, '')) {
405 print '<span class="amount">'.price($projectstatic->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
406 }
407 print '</td></tr>';
408
409 // Date start - end project
410 print '<tr><td>'.$langs->trans("Dates").'</td><td>';
411 $start = dol_print_date($projectstatic->date_start, 'day');
412 print($start ? $start : '?');
413 $end = dol_print_date($projectstatic->date_end, 'day');
414 print ' - ';
415 print($end ? $end : '?');
416 if ($projectstatic->hasDelay()) {
417 print img_warning("Late");
418 }
419 print '</td></tr>';
420
421 // Visibility
422 print '<tr><td class="titlefield">'.$langs->trans("Visibility").'</td><td>';
423 if ($projectstatic->public) {
424 print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
425 print $langs->trans('SharedProject');
426 } else {
427 print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
428 print $langs->trans('PrivateProject');
429 }
430 print '</td></tr>';
431
432 // Other attributes
433 $cols = 2;
434 $savobject = $object;
435 $object = $projectstatic;
436 include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
437 $object = $savobject;
438
439 print '</table>';
440
441 print '</div>';
442
443 print '<div class="fichehalfright">';
444 print '<div class="underbanner clearboth"></div>';
445
446 print '<table class="border tableforfield centpercent">';
447
448 // Categories
449 if (isModEnabled('category')) {
450 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
451 print $form->showCategories($projectstatic->id, 'project', 1);
452 print "</td></tr>";
453 }
454
455 // Description
456 print '<tr><td class="titlefield'.($projectstatic->description ? ' noborderbottom' : '').'" colspan="2">'.$langs->trans("Description").'</td></tr>';
457 if ($projectstatic->description) {
458 print '<tr><td class="nottitleforfield" colspan="2">';
459 print '<div class="longmessagecut">';
460 print dolPrintHTML($projectstatic->description);
461 print '</div>';
462 print '</td></tr>';
463 }
464
465 print '</table>';
466
467 print '</div>';
468 print '</div>';
469
470 print '<div class="clearboth"></div>';
471
472 print dol_get_fiche_end();
473
474 print '<br>';
475 }
476
477
478 // To verify role of users
479 //$userAccess = $projectstatic->restrictedProjectArea($user); // We allow task affected to user even if a not allowed project
480 //$arrayofuseridoftask=$object->getListContactId('internal');
481
482
483 $head = task_prepare_head($object);
484
485 if ($action == 'edit' && $user->hasRight('projet', 'creer')) {
486 print '<form method="POST" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
487 print '<input type="hidden" name="token" value="'.newToken().'">';
488 print '<input type="hidden" name="action" value="update">';
489 print '<input type="hidden" name="withproject" value="'.$withproject.'">';
490 print '<input type="hidden" name="id" value="'.$object->id.'">';
491
492 print dol_get_fiche_head($head, 'task_task', $langs->trans("Task"), 0, 'projecttask', 0, '', '');
493
494 $param = (GETPOST('withproject') ? '&withproject=1' : '');
495 $linkback = GETPOST('withproject') ? '<a href="'.DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.'">'.$langs->trans("BackToList").'</a>' : '';
496
497 if (!GETPOST('withproject') || empty($projectstatic->id)) {
498 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1);
499 $object->next_prev_filter = "fk_projet:IN:".$db->sanitize($projectsListId);
500 } else {
501 $object->next_prev_filter = "fk_projet:=:".((int) $projectstatic->id);
502 }
503
504 print '<table class="border centpercent">';
505
506 // Ref
507 print '<tr><td class="titlefield fieldrequired">'.$langs->trans("Ref").'</td>';
508 print '<td><input class="minwidth100" name="taskref" value="'.$object->ref.'"></td></tr>';
509
510 // Label
511 print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td>';
512 print '<td><input class="minwidth500" name="label" value="'.$object->label.'"></td></tr>';
513
514 // Project
515 if (empty($withproject)) {
516 print '<tr><td>'.$langs->trans("Project").'</td><td>';
517 print $projectstatic->getNomUrl(1);
518 print '</td></tr>';
519
520 // Third party
521 print '<td>'.$langs->trans("ThirdParty").'</td><td>';
522 if ($projectstatic->thirdparty->id) {
523 print $projectstatic->thirdparty->getNomUrl(1);
524 } else {
525 print '&nbsp;';
526 }
527 print '</td></tr>';
528 }
529
530 // Task parent
531 print '<tr><td>'.$langs->trans("ChildOfProjectTask").'</td><td>';
532 print img_picto('', 'projecttask');
533 $formother->selectProjectTasks($object->fk_task_parent, $projectstatic->id, 'task_parent', ($user->admin ? 0 : 1), 0, 0, 0, $object->id, '', 'minwidth100 widthcentpercentminusxx maxwidth500');
534 print '</td></tr>';
535
536 // Date start
537 print '<tr><td>'.$langs->trans("DateStart").'</td><td>';
538 print $form->selectDate($object->date_start, 'date_start', 1, 1, 0, '', 1, 0);
539 print '</td></tr>';
540
541 // Date end
542 print '<tr><td>'.$langs->trans("Deadline").'</td><td>';
543 print $form->selectDate($object->date_end ? $object->date_end : -1, 'date_end', 1, 1, 0, '', 1, 0);
544 print '</td></tr>';
545
546 // Planned workload
547 print '<tr><td>'.$langs->trans("PlannedWorkload").'</td><td>';
548 print $form->select_duration('planned_workload', $object->planned_workload, 0, 'text');
549 print '</td></tr>';
550
551 // Progress declared
552 print '<tr><td>'.$langs->trans("ProgressDeclared").'</td><td>';
553 print $formother->select_percent($object->progress, 'progress', 0, 5, 0, 100, 1);
554 print '</td></tr>';
555
556 // Billable
557 print '<tr><td>'.$langs->trans("Billable").'</td><td>';
558 print $form->selectyesno('billable', $object->billable);
559 print '</td></tr>';
560
561 // Description
562
563 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td>';
564 print '<td>';
565
566 // WYSIWYG editor
567 include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
568 $nbrows = getDolGlobalInt('MAIN_INPUT_DESC_HEIGHT', 0);
569 $doleditor = new DolEditor('description', $object->description, '', 80, 'dolibarr_details', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), $nbrows, '90%');
570 print $doleditor->Create();
571
572 print '</td></tr>';
573
574
575 print '<tr><td>'.$langs->trans("Budget").'</td>';
576 print '<td><input class="width75" type="text" name="budget_amount" value="'.dol_escape_htmltag(GETPOSTISSET('budget_amount') ? GETPOST('budget_amount') : price2num($object->budget_amount)).'"></td>';
577 print '</tr>';
578
579 // Other options
580 $parameters = array();
581 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
582 print $hookmanager->resPrint;
583 if (empty($reshook)) {
584 print $object->showOptionals($extrafields, 'edit');
585 }
586
587 print '</table>';
588
589 print dol_get_fiche_end();
590
591 print $form->buttonsSaveCancel("Modify");
592
593 print '</form>';
594 } else {
595 /*
596 * Fiche tache en mode visu
597 */
598 $param = ($withproject ? '&withproject=1' : '');
599 $linkback = $withproject ? '<a href="'.DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.'&restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>' : '';
600
601 print dol_get_fiche_head($head, 'task_task', $langs->trans("Task"), -1, 'projecttask', 0, '', 'reposition');
602
603 if ($action == 'clone') {
604 $formquestion = array(
605 'text' => $langs->trans("ConfirmClone"),
606 //array('type' => 'checkbox', 'name' => 'clone_contacts', 'label' => $langs->trans("CloneContacts"), 'value' => true),
607 0 => array('type' => 'checkbox', 'name' => 'clone_change_dt', 'label' => $langs->trans("CloneChanges"), 'value' => true),
608 1 => array('type' => 'checkbox', 'name' => 'clone_affectation', 'label' => $langs->trans("CloneAffectation"), 'value' => true),
609 2 => array('type' => 'checkbox', 'name' => 'clone_prog', 'label' => $langs->trans("CloneProgression"), 'value' => true),
610 3 => array('type' => 'checkbox', 'name' => 'clone_time', 'label' => $langs->trans("CloneTimes"), 'value' => true),
611 4 => array('type' => 'checkbox', 'name' => 'clone_file', 'label' => $langs->trans("CloneFile"), 'value' => true),
612 );
613
614 print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("ToClone"), $langs->trans("ConfirmCloneTask"), "confirm_clone", $formquestion, '', 1, 300, 590);
615 }
616
617 if ($action == 'close') {
618 $formquestion = array(
619 'text' => $langs->trans("ConfirmClosed"),
620 );
621 print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("ToClose"), $langs->trans("ConfirmCloseTask"), "confirm_close", $formquestion, '', 1, 300, 590);
622 }
623
624
625 if ($action == 'merge') {
626 $formquestion = array(
627 array(
628 'name' => 'task_origin',
629 'label' => $langs->trans('MergeOriginTask'),
630 'type' => 'other',
631 'value' => $formproject->selectTasks(-1, 0, 'task_origin', 24, 0, $langs->trans('SelectTask'), 0, 0, 0, 'maxwidth500 minwidth200', '', '', null, 1)
632 )
633 );
634 print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id.(GETPOST('withproject') ? "&withproject=1" : ""), $langs->trans("MergeTasks"), $langs->trans("ConfirmMergeTasks"), "confirm_merge", $formquestion, 'yes', 1, 250);
635 }
636
637 if ($action == 'delete') {
638 print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".GETPOSTINT("id").'&withproject='.$withproject, $langs->trans("DeleteATask"), $langs->trans("ConfirmDeleteATask"), "confirm_delete");
639 }
640
641 if (!GETPOST('withproject') || empty($projectstatic->id)) {
642 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1);
643 $object->next_prev_filter = "fk_projet:IN:".$db->sanitize($projectsListId);
644 } else {
645 $object->next_prev_filter = "fk_projet:=:".((int) $projectstatic->id);
646 }
647
648 $morehtmlref = '';
649
650 // Project
651 if (empty($withproject)) {
652 $morehtmlref .= '<div class="refidno">';
653 $morehtmlref .= $langs->trans("Project").': ';
654 $morehtmlref .= $projectstatic->getNomUrl(1);
655 $morehtmlref .= '<br>';
656
657 // Third party
658 $morehtmlref .= $langs->trans("ThirdParty").': ';
659 if (!empty($projectstatic->thirdparty) && is_object($projectstatic->thirdparty)) {
660 $morehtmlref .= $projectstatic->thirdparty->getNomUrl(1);
661 }
662 $morehtmlref .= '</div>';
663 }
664
665 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, $param);
666
667 print '<div class="fichecenter">';
668 print '<div class="fichehalfleft">';
669
670 print '<div class="underbanner clearboth"></div>';
671 print '<table class="border centpercent tableforfield">';
672
673 // Task parent
674 print '<tr><td class="titlefieldmiddle">'.$langs->trans("ChildOfTask").'</td><td>';
675 if ($object->fk_task_parent > 0) {
676 $tasktmp = new Task($db);
677 $tasktmp->fetch($object->fk_task_parent);
678 print $tasktmp->getNomUrl(1);
679 }
680 print '</td></tr>';
681
682 // Date start - Date end task
683 print '<tr><td>'.$langs->trans("DateStart").' - '.$langs->trans("Deadline").'</td><td colspan="3">';
684 $start = dol_print_date($object->date_start, 'dayhour');
685 print($start ? $start : '?');
686 $end = dol_print_date($object->date_end, 'dayhour');
687 print ' - ';
688 print($end ? $end : '?');
689 if ($object->hasDelay()) {
690 print img_warning("Late");
691 }
692 print '</td></tr>';
693
694 // Planned workload
695 print '<tr><td>'.$langs->trans("PlannedWorkload").'</td><td colspan="3">';
696 if ($object->planned_workload != '') {
697 print convertSecondToTime($object->planned_workload, 'allhourmin');
698 }
699 print '</td></tr>';
700
701 // Description
702 print '<td class="tdtop">'.$langs->trans("Description").'</td><td colspan="3">';
703 print dol_htmlentitiesbr($object->description);
704 print '</td></tr>';
705
706 print '</table>';
707 print '</div>';
708
709 print '<div class="fichehalfright">';
710
711 print '<div class="underbanner clearboth"></div>';
712 print '<table class="border centpercent tableforfield">';
713
714 // Progress declared
715 print '<tr><td class="titlefieldmiddle">'.$langs->trans("ProgressDeclared").'</td><td colspan="3">';
716 if ($object->progress != '' && $object->progress != '-1') {
717 print $object->progress.' %';
718 }
719 print '</td></tr>';
720
721 // Progress calculated
722 print '<tr><td>'.$langs->trans("ProgressCalculated").'</td><td colspan="3">';
723 if ($object->planned_workload != '') {
724 $tmparray = $object->getSummaryOfTimeSpent();
725 if ($tmparray['total_duration'] > 0 && !empty($object->planned_workload)) {
726 print round($tmparray['total_duration'] / $object->planned_workload * 100, 2).' %';
727 } else {
728 print '0 %';
729 }
730 } else {
731 print '<span class="opacitymedium">'.$langs->trans("WorkloadNotDefined").'</span>';
732 }
733 print '</td></tr>';
734
735 // Budget
736 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
737 if (!is_null($object->budget_amount) && strcmp((string) $object->budget_amount, '')) {
738 print '<span class="amount">'.price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
739 }
740 print '</td></tr>';
741
742 // Billable
743 print '<tr><td>'.$langs->trans("Billable").'</td><td>';
744 print '<span>'.($object->billable ? $langs->trans('Yes') : $langs->trans('No')).'</span>';
745 print '</td></tr>';
746
747
748 // Other attributes
749 $cols = 3;
750 $parameters = array('socid' => $socid);
751 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
752
753 print '</table>';
754
755 print '</div>';
756
757 print '</div>';
758 print '<div class="clearboth"></div>';
759
760 print dol_get_fiche_end();
761 }
762
763
764 if ($action != 'edit') {
765 /*
766 * Actions
767 */
768
769 print '<div class="tabsAction">';
770
771 $parameters = array();
772 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
773 // modified by hook
774 if (empty($reshook)) {
775 // Modify
776 if ($user->hasRight('projet', 'creer')) {
777 if ($object->status == $object::STATUS_VALIDATED || $object->status == $object::STATUS_ONGOING) {
778 print '<a class="butAction classfortooltip reposition" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=reopen&token='.newToken().'&withproject='.((int) $withproject).'" title="'.$langs->trans("SetToDraft").'">'.$langs->trans('SetToDraft').'</a>';
779 } elseif ($object->status == $object::STATUS_DRAFT) {
780 print '<a class="butAction reposition" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=valid&token='.newToken().'&withproject='.((int) $withproject).'">'.$langs->trans('Validate').'</a>';
781 }
782 //if ($object->status != $object::STATUS_CLOSED) {
783 print '<a class="butAction reposition" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=edit&token='.newToken().'&withproject='.((int) $withproject).'">'.$langs->trans('Modify').'</a>';
784 //}
785
786 if ($object->status != $object::STATUS_CLOSED) {
787 print '<a class="butAction classfortooltip reposition" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=confirm_close&confirm=yes&token='.newToken().'&withproject='.((int) $withproject).'" title="'.$langs->trans("Close").'">'.$langs->trans('Close').'</a>';
788 }
789
790 print '<a class="butAction reposition" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=clone&token='.newToken().'&withproject='.((int) $withproject).'">'.$langs->trans('Clone').'</a>';
791
792 print '<a class="butActionDelete classfortooltip reposition" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=merge&token='.newToken().'&withproject='.((int) $withproject).'" title="'.$langs->trans("MergeTasks").'">'.$langs->trans('Merge').'</a>';
793 } else {
794 print '<a class="butActionRefused classfortooltip reposition" href="#" title="'.$langs->trans("NotAllowed").'">'.$langs->trans('Modify').'</a>';
795 }
796
797 // Delete
798 $permissiontodelete = $user->hasRight('projet', 'supprimer');
799 if ($permissiontodelete) {
800 if (!$object->hasChildren() && !$object->hasTimeSpent()) {
801 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken().'&withproject='.((int) $withproject), 'delete', $permissiontodelete);
802 } else {
803 print dolGetButtonAction($langs->trans("TaskHasChild"), $langs->trans("Delete"), 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken().'&withproject='.((int) $withproject), 'delete', -1);
804 }
805 } else {
806 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken().'&withproject='.((int) $withproject), 'delete', $permissiontodelete);
807 }
808
809 print '</div>';
810 }
811
812 print '<div class="fichecenter"><div class="fichehalfleft">';
813 print '<a name="builddoc"></a>'; // ancre
814
815 /*
816 * Generated documents
817 */
818 $subdir = dol_sanitizeFileName($projectstatic->ref)."/".dol_sanitizeFileName($object->ref);
819 $filedir = $conf->project->multidir_output[$object->entity ?? $conf->entity]."/".$subdir;
820 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
821 $genallowed = ($user->hasRight('projet', 'lire'));
822 $delallowed = ($user->hasRight('projet', 'creer'));
823
824 print $formfile->showdocuments('project_task', $subdir, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 0, 0, '', '', '', '', '', $object);
825
826 // Show links to link elements
827 $tmparray = $form->showLinkToObjectBlock($object, array(), array('project_task'), 1);
828 $linktoelem = $tmparray['linktoelem'];
829 $htmltoenteralink = $tmparray['htmltoenteralink'];
830 print $htmltoenteralink;
831
832 $compatibleImportElementsList = array();
833 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
834
835 print '</div><div class="fichehalfright">';
836
837 // List of actions on element
838 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
839 $formactions = new FormActions($db);
840 $formactions->showactions($object, 'project_task', 0, 1, '', 10, 'withproject='.$withproject);
841
842 print '</div></div>';
843 }
844}
845
846// End of page
847llxFooter();
848$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 building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class permettant la generation de composants html autre Only common components are here.
Class to manage building of HTML components.
Class to manage projects.
Class to manage tasks.
const STATUS_VALIDATED
Validated status (To do).
const STATUS_DRAFT
Draft status.
const STATUS_CLOSED
Finished status.
Class to manage translations.
convertSecondToTime($iSecond, $format='all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition date.lib.php:247
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
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.
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.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
dolPrintHTML($s, $allowiframe=0)
Return a string (that can be on several lines) ready to be output on a HTML page.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
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).
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
task_prepare_head($object)
Prepare array with list of tabs.
project_prepare_head(Project $project, $moreparam='')
Prepare array with list of tabs.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.