dolibarr 25.0.0-alpha
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-2026 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 $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty
211 if ($object->delete($user) > 0) {
212 header('Location: '.DOL_URL_ROOT.'/projet/tasks.php?restore_lastsearch_values=1&id='.$projectstatic->id.($withproject ? '&withproject=1' : ''));
213 exit;
214 } else {
215 setEventMessages($object->error, $object->errors, 'errors');
216 $action = '';
217 }
218}
219
220if ($action == 'confirm_close' && $confirm == "yes" && $user->hasRight('projet', 'creer')) {
221 $result = $projectstatic->fetch($object->fk_project);
222 $projectstatic->fetch_thirdparty();
223
224 // $object is task to close
225 if ($object->setStatusCommon($user, Task::STATUS_CLOSED) <= 0) {
226 setEventMessages($object->error, $object->errors, 'errors');
227 }
228 $action = '';
229}
230
231// Retrieve First Task ID of Project if withprojet is on to allow project prev next to work
232if (!empty($project_ref) && !empty($withproject)) {
233 if ($projectstatic->fetch(0, $project_ref) > 0) {
234 $tasksarray = $object->getTasksArray(null, null, $projectstatic->id, $socid, 0);
235 if (count($tasksarray) > 0) {
236 $id = $tasksarray[0]->id;
237 } else {
238 header("Location: ".DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.(empty($mode) ? '' : '&mode='.$mode));
239 }
240 }
241}
242
243// Build doc
244if ($action == 'builddoc' && $user->hasRight('projet', 'creer')) {
245 // Save last template used to generate document
246 if (GETPOST('model')) {
247 $object->setDocModel($user, GETPOST('model', 'alpha'));
248 }
249
250 $outputlangs = $langs;
251 if (GETPOST('lang_id', 'aZ09')) {
252 $outputlangs = new Translate("", $conf);
253 $outputlangs->setDefaultLang(GETPOST('lang_id', 'aZ09'));
254 }
255 $result = $object->generateDocument($object->model_pdf, $outputlangs);
256 if ($result <= 0) {
257 setEventMessages($object->error, $object->errors, 'errors');
258 $action = '';
259 }
260}
261
262// Delete file in doc form
263if ($action == 'remove_file' && $user->hasRight('projet', 'creer')) {
264 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
265
266 $langs->load("other");
267 $upload_dir = $conf->project->dir_output."/".dol_sanitizeFileName($projectstatic->ref)."/".dol_sanitizeFileName($object->ref);
268 $file = $upload_dir.'/'.dol_sanitizeFileName(GETPOST('file'));
269
270 $ret = dol_delete_file($file, 1);
271 if ($ret) {
272 setEventMessages($langs->trans("FileWasRemoved", GETPOST('file')), null, 'mesgs');
273 } else {
274 setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('file')), null, 'errors');
275 }
276}
277
278// Reopen task
279if ($action == 'reopen' && $user->hasRight('projet', 'creer')) {
280 $result = $object->setStatusCommon($user, Task::STATUS_DRAFT);
281 if ($result >= 0) {
282 setEventMessages($langs->trans("TaskBackToDraft"), null, 'mesgs');
283 } else {
284 $error++;
285 setEventMessages($object->error, $object->errors, 'errors');
286 }
287}
288
289// Validate status of task
290if ($action == 'valid' && $user->hasRight('projet', 'creer')) {
291 $result = $object->setStatusCommon($user, Task::STATUS_VALIDATED);
292 if ($result >= 0) {
293 setEventMessages($langs->trans("TaskValidated"), null, 'mesgs');
294 } else {
295 $error++;
296 setEventMessages($object->error, $object->errors, 'errors');
297 }
298}
299
300
301/*
302 * View
303 */
304
305$form = new Form($db);
306$formother = new FormOther($db);
307$formfile = new FormFile($db);
308$formproject = new FormProjets($db);
309
310$title = (string) $object->ref;
311if (!empty($withproject)) {
312 $title .= ' | ' . $langs->trans("Project") . (!empty($projectstatic->ref) ? ': '.$projectstatic->ref : '') ;
313}
314$help_url = '';
315
316llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-project project-tasks page-task');
317
318
319if ($id > 0 || !empty($ref)) {
320 $res = $object->fetch_optionals();
321 if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_TASK') && empty($object->comments)) {
322 $object->fetchComments();
323 }
324
325 if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_PROJECT') && method_exists($projectstatic, 'fetchComments') && empty($projectstatic->comments)) {
326 $projectstatic->fetchComments();
327 }
328 if (!empty($projectstatic->socid)) {
329 $projectstatic->fetch_thirdparty();
330 }
331
332 $object->project = clone $projectstatic;
333
334 //$userWrite = $projectstatic->restrictedProjectArea($user, 'write');
335
336 if (!empty($withproject)) {
337 // Tabs for project
338 $tab = 'tasks';
339 $head = project_prepare_head($projectstatic);
340 print dol_get_fiche_head($head, $tab, $langs->trans("Project"), -1, ($projectstatic->public ? 'projectpub' : 'project'), 0, '', '');
341
342 $param = ($mode == 'mine' ? '&mode=mine' : '');
343
344 // Project card
345
346 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
347
348 $morehtmlref = '<div class="refidno">';
349 // Title
350 $morehtmlref .= $projectstatic->title;
351 // Thirdparty
352 if (!empty($projectstatic->thirdparty->id) && $projectstatic->thirdparty->id > 0) {
353 $morehtmlref .= '<br>'.$projectstatic->thirdparty->getNomUrl(1, 'project');
354 }
355 $morehtmlref .= '</div>';
356
357 // Define a complementary filter for search of next/prev ref.
358 if (!$user->hasRight('projet', 'all', 'lire')) {
359 $objectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 0);
360 $projectstatic->next_prev_filter = "rowid:IN:".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0');
361 }
362
363 dol_banner_tab($projectstatic, 'project_ref', $linkback, 1, 'ref', 'ref', $morehtmlref, $param);
364
365 print '<div class="fichecenter">';
366 print '<div class="fichehalfleft">';
367 print '<div class="underbanner clearboth"></div>';
368
369 print '<table class="border tableforfield centpercent">';
370
371 // Usage
372 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJECT_HIDE_TASKS') || isModEnabled('eventorganization')) {
373 print '<tr><td class="tdtop">';
374 print $langs->trans("Usage");
375 print '</td>';
376 print '<td>';
377 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
378 print '<input type="checkbox" disabled name="usage_opportunity"'.(GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_opportunity ? ' checked="checked"' : '')).'"> ';
379 $htmltext = $langs->trans("ProjectFollowOpportunity");
380 print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
381 print '<br>';
382 }
383 if (!getDolGlobalString('PROJECT_HIDE_TASKS')) {
384 print '<input type="checkbox" disabled name="usage_task"'.(GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($projectstatic->usage_task ? ' checked="checked"' : '')).'"> ';
385 $htmltext = $langs->trans("ProjectFollowTasks");
386 print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
387 print '<br>';
388 }
389 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
390 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"' : '')).'"> ';
391 $htmltext = $langs->trans("ProjectBillTimeDescription");
392 print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
393 print '<br>';
394 }
395 if (isModEnabled('eventorganization')) {
396 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"' : '')).'"> ';
397 $htmltext = $langs->trans("EventOrganizationDescriptionLong");
398 print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
399 }
400 print '</td></tr>';
401 }
402
403 // Budget
404 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
405 if (isset($projectstatic->budget_amount) && strcmp($projectstatic->budget_amount, '')) {
406 print '<span class="amount">'.price($projectstatic->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
407 }
408 print '</td></tr>';
409
410 // Date start - end project
411 print '<tr><td>'.$langs->trans("Dates").'</td><td>';
412 $start = dol_print_date($projectstatic->date_start, 'day');
413 print($start ? $start : '?');
414 $end = dol_print_date($projectstatic->date_end, 'day');
415 print ' - ';
416 print($end ? $end : '?');
417 if ($projectstatic->hasDelay()) {
418 print img_warning("Late");
419 }
420 print '</td></tr>';
421
422 // Visibility
423 print '<tr><td class="titlefield">'.$langs->trans("Visibility").'</td><td>';
424 if ($projectstatic->public) {
425 print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
426 print $langs->trans('SharedProject');
427 } else {
428 print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
429 print $langs->trans('PrivateProject');
430 }
431 print '</td></tr>';
432
433 // Other attributes
434 $cols = 2;
435 $savobject = $object;
436 $object = $projectstatic;
437 include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
438 $object = $savobject;
439
440 print '</table>';
441
442 print '</div>';
443
444 print '<div class="fichehalfright">';
445 print '<div class="underbanner clearboth"></div>';
446
447 print '<table class="border tableforfield centpercent">';
448
449 // Categories
450 if (isModEnabled('category')) {
451 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
452 print $form->showCategories($projectstatic->id, 'project', 1);
453 print "</td></tr>";
454 }
455
456 // Description
457 print '<tr><td class="titlefield'.($projectstatic->description ? ' noborderbottom' : '').'" colspan="2">'.$langs->trans("Description").'</td></tr>';
458 if ($projectstatic->description) {
459 print '<tr><td class="nottitleforfield" colspan="2">';
460 print '<div class="longmessagecut">';
461 print dolPrintHTML($projectstatic->description);
462 print '</div>';
463 print '</td></tr>';
464 }
465
466 print '</table>';
467
468 print '</div>';
469 print '</div>';
470
471 print '<div class="clearboth"></div>';
472
473 print dol_get_fiche_end();
474
475 print '<br>';
476 }
477
478
479 // To verify role of users
480 //$userAccess = $projectstatic->restrictedProjectArea($user); // We allow task affected to user even if a not allowed project
481 //$arrayofuseridoftask=$object->getListContactId('internal');
482
483
484 $head = task_prepare_head($object);
485
486 if ($action == 'edit' && $user->hasRight('projet', 'creer')) {
487 print '<form method="POST" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
488 print '<input type="hidden" name="token" value="'.newToken().'">';
489 print '<input type="hidden" name="action" value="update">';
490 print '<input type="hidden" name="withproject" value="'.$withproject.'">';
491 print '<input type="hidden" name="id" value="'.$object->id.'">';
492
493 print dol_get_fiche_head($head, 'task_task', $langs->trans("Task"), 0, 'projecttask', 0, '', '');
494
495 $param = (GETPOST('withproject') ? '&withproject=1' : '');
496 $linkback = GETPOST('withproject') ? '<a href="'.DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.'">'.$langs->trans("BackToList").'</a>' : '';
497
498 if (!GETPOST('withproject') || empty($projectstatic->id)) {
499 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1);
500 $object->next_prev_filter = "fk_projet:IN:".$db->sanitize($projectsListId);
501 } else {
502 $object->next_prev_filter = "fk_projet:=:".((int) $projectstatic->id);
503 }
504
505 print '<table class="border centpercent">';
506
507 // Ref
508 print '<tr><td class="titlefield fieldrequired">'.$langs->trans("Ref").'</td>';
509 print '<td><input class="minwidth100" name="taskref" value="'.$object->ref.'"></td></tr>';
510
511 // Label
512 print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td>';
513 print '<td><input class="minwidth500" name="label" value="'.$object->label.'"></td></tr>';
514
515 // Project
516 if (empty($withproject)) {
517 print '<tr><td>'.$langs->trans("Project").'</td><td>';
518 print $projectstatic->getNomUrl(1);
519 print '</td></tr>';
520
521 // Third party
522 print '<td>'.$langs->trans("ThirdParty").'</td><td>';
523 if (!empty($projectstatic->thirdparty->id)) {
524 print $projectstatic->thirdparty->getNomUrl(1);
525 } else {
526 print '&nbsp;';
527 }
528 print '</td></tr>';
529 }
530
531 // Task parent
532 print '<tr><td>'.$langs->trans("ChildOfProjectTask").'</td><td>';
533 print img_picto('', 'projecttask');
534 $formother->selectProjectTasks($object->fk_task_parent, $projectstatic->id, 'task_parent', ($user->admin ? 0 : 1), 0, 0, 0, $object->id, '', 'minwidth100 widthcentpercentminusxx maxwidth500');
535 print '</td></tr>';
536
537 // Date start
538 print '<tr><td>'.$langs->trans("DateStart").'</td><td>';
539 print $form->selectDate($object->date_start, 'date_start', 1, 1, 0, '', 1, 0);
540 print '</td></tr>';
541
542 // Date end
543 print '<tr><td>'.$langs->trans("Deadline").'</td><td>';
544 print $form->selectDate($object->date_end ? $object->date_end : -1, 'date_end', 1, 1, 0, '', 1, 0);
545 print '</td></tr>';
546
547 // Planned workload
548 print '<tr><td>'.$langs->trans("PlannedWorkload").'</td><td>';
549 print $form->select_duration('planned_workload', $object->planned_workload, 0, 'text');
550 print '</td></tr>';
551
552 // Progress declared
553 print '<tr><td>'.$langs->trans("ProgressDeclared").'</td><td>';
554 print $formother->select_percent($object->progress, 'progress', 0, 5, 0, 100, 1);
555 print '</td></tr>';
556
557 // Billable
558 print '<tr><td>'.$langs->trans("Billable").'</td><td>';
559 print $form->selectyesno('billable', $object->billable);
560 print '</td></tr>';
561
562 // Description
563
564 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td>';
565 print '<td>';
566
567 // WYSIWYG editor
568 include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
569 $nbrows = getDolGlobalInt('MAIN_INPUT_DESC_HEIGHT', 0);
570 $doleditor = new DolEditor('description', $object->description, '', 80, 'dolibarr_details', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), $nbrows, '90%');
571 print $doleditor->Create();
572
573 print '</td></tr>';
574
575
576 print '<tr><td>'.$langs->trans("Budget").'</td>';
577 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>';
578 print '</tr>';
579
580 // Other options
581 $parameters = array();
582 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
583 print $hookmanager->resPrint;
584 if (empty($reshook)) {
585 print $object->showOptionals($extrafields, 'edit');
586 }
587
588 print '</table>';
589
590 print dol_get_fiche_end();
591
592 print $form->buttonsSaveCancel("Modify");
593
594 print '</form>';
595 } else {
596 /*
597 * Fiche tache en mode visu
598 */
599 $param = ($withproject ? '&withproject=1' : '');
600 $linkback = $withproject ? '<a href="'.DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.'&restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>' : '';
601
602 print dol_get_fiche_head($head, 'task_task', $langs->trans("Task"), -1, 'projecttask', 0, '', 'reposition', 0, '', 1);
603
604 if ($action == 'clone') {
605 $formquestion = array(
606 'text' => $langs->trans("ConfirmClone"),
607 //array('type' => 'checkbox', 'name' => 'clone_contacts', 'label' => $langs->trans("CloneContacts"), 'value' => true),
608 0 => array('type' => 'checkbox', 'name' => 'clone_change_dt', 'label' => $langs->trans("CloneChanges"), 'value' => true),
609 1 => array('type' => 'checkbox', 'name' => 'clone_affectation', 'label' => $langs->trans("CloneAffectation"), 'value' => true),
610 2 => array('type' => 'checkbox', 'name' => 'clone_prog', 'label' => $langs->trans("CloneProgression"), 'value' => true),
611 3 => array('type' => 'checkbox', 'name' => 'clone_time', 'label' => $langs->trans("CloneTimes"), 'value' => true),
612 4 => array('type' => 'checkbox', 'name' => 'clone_file', 'label' => $langs->trans("CloneFile"), 'value' => true),
613 );
614
615 print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("ToClone"), $langs->trans("ConfirmCloneTask"), "confirm_clone", $formquestion, '', 1, 0, 600);
616 }
617
618 if ($action == 'close') {
619 $formquestion = array(
620 'text' => $langs->trans("ConfirmClosed"),
621 );
622 print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("ToClose"), $langs->trans("ConfirmCloseTask"), "confirm_close", $formquestion, '', 1, 0, 600);
623 }
624
625
626 if ($action == 'merge') {
627 $formquestion = array(
628 array(
629 'name' => 'task_origin',
630 'label' => $langs->trans('MergeOriginTask'),
631 'type' => 'other',
632 'value' => $formproject->selectTasks(-1, 0, 'task_origin', 24, 0, $langs->trans('SelectTask'), 0, 0, 0, 'maxwidth500 minwidth200', '', '', null, 1)
633 )
634 );
635 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);
636 }
637
638 if ($action == 'delete') {
639 print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".GETPOSTINT("id").'&withproject='.$withproject, $langs->trans("DeleteATask"), $langs->trans("ConfirmDeleteATask"), "confirm_delete");
640 }
641
642 if (!GETPOST('withproject') || empty($projectstatic->id)) {
643 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1);
644 $object->next_prev_filter = "fk_projet:IN:".$db->sanitize($projectsListId);
645 } else {
646 $object->next_prev_filter = "fk_projet:=:".((int) $projectstatic->id);
647 }
648
649 $morehtmlref = '';
650
651 // Project
652 if (empty($withproject)) {
653 $morehtmlref .= '<div class="refidno">';
654 $morehtmlref .= $langs->trans("Project").': ';
655 $morehtmlref .= $projectstatic->getNomUrl(1);
656 $morehtmlref .= '<br>';
657
658 // Third party
659 $morehtmlref .= $langs->trans("ThirdParty").': ';
660 if (!empty($projectstatic->thirdparty) && is_object($projectstatic->thirdparty)) {
661 $morehtmlref .= $projectstatic->thirdparty->getNomUrl(1);
662 }
663 $morehtmlref .= '</div>';
664 }
665
666 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, $param);
667
668 print '<div class="fichecenter">';
669 print '<div class="fichehalfleft">';
670
671 print '<div class="underbanner clearboth"></div>';
672 print '<table class="border centpercent tableforfield">';
673
674 // Task parent
675 print '<tr><td class="titlefieldmiddle">'.$langs->trans("ChildOfTask").'</td><td>';
676 if ($object->fk_task_parent > 0) {
677 $tasktmp = new Task($db);
678 $tasktmp->fetch($object->fk_task_parent);
679 print $tasktmp->getNomUrl(1);
680 }
681 print '</td></tr>';
682
683 // Date start - Date end task
684 print '<tr><td>'.$langs->trans("DateStart").' - '.$langs->trans("Deadline").'</td><td colspan="3">';
685 $start = dol_print_date($object->date_start, 'dayhour');
686 print($start ? $start : '?');
687 $end = dol_print_date($object->date_end, 'dayhour');
688 print ' - ';
689 print($end ? $end : '?');
690 if ($object->hasDelay()) {
691 print img_warning("Late");
692 }
693 print '</td></tr>';
694
695 // Planned workload
696 print '<tr><td>'.$langs->trans("PlannedWorkload").'</td><td colspan="3">';
697 if ($object->planned_workload != '') {
698 print convertSecondToTime($object->planned_workload, 'allhourmin');
699 }
700 print '</td></tr>';
701
702 // Description
703 print '<td class="tdtop">'.$langs->trans("Description").'</td><td colspan="3">';
704 print dol_htmlentitiesbr($object->description);
705 print '</td></tr>';
706
707 print '</table>';
708 print '</div>';
709
710 print '<div class="fichehalfright">';
711
712 print '<div class="underbanner clearboth"></div>';
713 print '<table class="border centpercent tableforfield">';
714
715 // Progress declared
716 print '<tr><td class="titlefieldmiddle">'.$langs->trans("ProgressDeclared").'</td><td colspan="3">';
717 if ($object->progress != '' && $object->progress != '-1') {
718 print $object->progress.' %';
719 }
720 print '</td></tr>';
721
722 // Progress calculated
723 print '<tr><td>'.$langs->trans("ProgressCalculated").'</td><td colspan="3">';
724 if ($object->planned_workload != '') {
725 $tmparray = $object->getSummaryOfTimeSpent();
726 if ($tmparray['total_duration'] > 0 && !empty($object->planned_workload)) {
727 print round($tmparray['total_duration'] / $object->planned_workload * 100, 2).' %';
728 } else {
729 print '0 %';
730 }
731 } else {
732 print '<span class="opacitymedium">'.$langs->trans("WorkloadNotDefined").'</span>';
733 }
734 print '</td></tr>';
735
736 // Budget
737 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
738 if (!is_null($object->budget_amount) && strcmp((string) $object->budget_amount, '')) {
739 print '<span class="amount">'.price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
740 }
741 print '</td></tr>';
742
743 // Billable
744 print '<tr><td>'.$langs->trans("Billable").'</td><td>';
745 print '<span>'.($object->billable ? $langs->trans('Yes') : $langs->trans('No')).'</span>';
746 print '</td></tr>';
747
748
749 // Other attributes
750 $cols = 3;
751 $parameters = array('socid' => $socid);
752 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
753
754 print '</table>';
755
756 print '</div>';
757
758 print '</div>';
759 print '<div class="clearboth"></div>';
760
761 print dol_get_fiche_end();
762 }
763
764
765 if ($action != 'edit') {
766 /*
767 * Actions
768 */
769
770 print '<div class="tabsAction">';
771
772 $parameters = array();
773 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
774 // modified by hook
775 if (empty($reshook)) {
776 // Modify
777 if ($user->hasRight('projet', 'creer')) {
778 if ($object->status == $object::STATUS_VALIDATED || $object->status == $object::STATUS_ONGOING) {
779 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>';
780 } elseif ($object->status == $object::STATUS_DRAFT) {
781 print '<a class="butAction reposition" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=valid&token='.newToken().'&withproject='.((int) $withproject).'">'.$langs->trans('Validate').'</a>';
782 } elseif ($object->status == $object::STATUS_CLOSED) {
783 // A closed task had no way back, the reopen action above already accepts it
784 print '<a class="butAction reposition" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=reopen&token='.newToken().'&withproject='.((int) $withproject).'">'.$langs->trans('ReOpen').'</a>';
785 }
786 //if ($object->status != $object::STATUS_CLOSED) {
787 print '<a class="butAction reposition" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=edit&token='.newToken().'&withproject='.((int) $withproject).'">'.$langs->trans('Modify').'</a>';
788 //}
789
790 if ($object->status != $object::STATUS_CLOSED) {
791 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>';
792 }
793
794 print dolGetButtonAction($langs->trans('ToClone'), $langs->trans('ToClone'), 'clone', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=clone&token='.newToken().'&withproject='.((int) $withproject), '', true, array('attr' => array('class' => 'reposition')));
795
796 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>';
797 } else {
798 print '<a class="butActionRefused classfortooltip reposition" href="#" title="'.$langs->trans("NotAllowed").'">'.$langs->trans('Modify').'</a>';
799 }
800
801 // Delete
802 $permissiontodelete = $user->hasRight('projet', 'supprimer');
803 if ($permissiontodelete) {
804 if (!$object->hasChildren() && !$object->hasTimeSpent()) {
805 print dolGetButtonAction($langs->trans("Delete"), $langs->trans("Delete"), 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken().'&withproject='.((int) $withproject), 'delete', $permissiontodelete, array('attr' => array('class' => 'reposition')))."\n";
806 } else {
807 print dolGetButtonAction($langs->trans("TaskHasChild"), $langs->trans("Delete"), 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken().'&withproject='.((int) $withproject), 'delete', -1, array('attr' => array('class' => 'reposition')));
808 }
809 } else {
810 print dolGetButtonAction($langs->trans("Delete"), $langs->trans("Delete"), 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken().'&withproject='.((int) $withproject), 'delete', $permissiontodelete, array('attr' => array('class' => 'reposition')))."\n";
811 }
812
813 print '</div>';
814 }
815
816 print '<div class="fichecenter"><div class="fichehalfleft">';
817 print '<a name="builddoc"></a>'; // ancre
818
819 /*
820 * Generated documents
821 */
822 $subdir = dol_sanitizeFileName($projectstatic->ref)."/".dol_sanitizeFileName($object->ref);
823 $filedir = $conf->project->multidir_output[$object->entity ?? $conf->entity]."/".$subdir;
824 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
825 $genallowed = ($user->hasRight('projet', 'lire'));
826 $delallowed = ($user->hasRight('projet', 'creer'));
827
828 print $formfile->showdocuments('project_task', $subdir, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 0, 0, '', '', '', '', '', $object);
829
830 // Show links to link elements
831 $tmparray = $form->showLinkToObjectBlock($object, array(), array('project_task'), 1);
832 $linktoelem = $tmparray['linktoelem'];
833 $htmltoenteralink = $tmparray['htmltoenteralink'];
834 print $htmltoenteralink;
835
836 $compatibleImportElementsList = array();
837 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
838
839 print '</div><div class="fichehalfright">';
840
841 // List of actions on element
842 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
843 $formactions = new FormActions($db);
844 $formactions->showactions($object, 'project_task', 0, 1, '', 10, 'withproject='.$withproject);
845
846 print '</div></div>';
847 }
848}
849
850// End of page
851llxFooter();
852$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 to help generate other html components 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:253
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
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...
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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'.
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.
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.
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
dol_get_fiche_end($notab=0)
Return tab footer of a card.
Definition html.lib.php:738
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, $nodie=0, $mode='')
Check permissions of a user to show a page and an object.