dolibarr 22.0.5
ganttview.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024 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.'/societe/class/societe.class.php';
34require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
35require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
36require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
45$id = GETPOST('id', 'intcomma');
46$ref = GETPOST('ref', 'alpha');
47
48$mode = GETPOST('mode', 'alpha');
49$mine = ($mode == 'mine' ? 1 : 0);
50//if (! $user->rights->projet->all->lire) $mine=1; // Special for projects
51
52$object = new Project($db);
53
54include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'
55if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_PROJECT') && method_exists($object, 'fetchComments') && empty($object->comments)) {
56 $object->fetchComments();
57}
58
59// Security check
60$socid = 0;
61//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.
62$result = restrictedArea($user, 'projet', $id, 'projet&project');
63
64// Load translation files required by the page
65$langs->loadlangs(array('users', 'projects'));
66
67
68/*
69 * Actions
70 */
71
72// None
73
74
75/*
76 * View
77 */
78
79$form = new Form($db);
80$formother = new FormOther($db);
81$userstatic = new User($db);
82$companystatic = new Societe($db);
83$contactstatic = new Contact($db);
84$task = new Task($db);
85
86$arrayofcss = array('/includes/jsgantt/jsgantt.css');
87$arrayofjs = [];
88if (!empty($conf->use_javascript_ajax)) {
89 $arrayofjs = [
90 '/includes/jsgantt/jsgantt.js',
91 '/projet/jsgantt_language.js.php?lang='.$langs->defaultlang
92 ];
93}
94
95//$title=$langs->trans("Gantt").($object->ref?' - '.$object->ref.' '.$object->name:'');
96$title = $langs->trans("Gantt");
97if (getDolGlobalString('MAIN_HTML_TITLE') && preg_match('/projectnameonly/', getDolGlobalString('MAIN_HTML_TITLE')) && $object->name) {
98 $title = ($object->ref ? $object->ref.' '.$object->name.' - ' : '').$langs->trans("Gantt");
99}
100$help_url = "EN:Module_Projects|FR:Module_Projets|ES:M&oacute;dulo_Proyectos";
101
102llxHeader("", $title, $help_url, '', 0, 0, $arrayofjs, $arrayofcss, '', 'mod-project page-card_ganttview');
103
104$userWrite = 0;
105
106if (($id > 0 && is_numeric($id)) || !empty($ref)) {
107 // To verify role of users
108 //$userAccess = $object->restrictedProjectArea($user,'read');
109 $userWrite = $object->restrictedProjectArea($user, 'write');
110 //$userDelete = $object->restrictedProjectArea($user,'delete');
111 //print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete;
112
113 $tab = 'tasks';
114
115 $head = project_prepare_head($object);
116 print dol_get_fiche_head($head, $tab, $langs->trans("Project"), -1, ($object->public ? 'projectpub' : 'project'));
117
118 $param = ($mode == 'mine' ? '&mode=mine' : '');
119
120
121
122 // Project card
123
124 if (!empty($_SESSION['pageforbacktolist']) && !empty($_SESSION['pageforbacktolist']['project'])) {
125 $tmpurl = $_SESSION['pageforbacktolist']['project'];
126 $tmpurl = preg_replace('/__SOCID__/', (string) $object->socid, $tmpurl);
127 $linkback = '<a href="'.$tmpurl.(preg_match('/\?/', $tmpurl) ? '&' : '?'). 'restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
128 } else {
129 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
130 }
131
132 $morehtmlref = '<div class="refidno">';
133 // Title
134 $morehtmlref .= $object->title;
135 // Thirdparty
136 if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
137 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'project');
138 }
139 $morehtmlref .= '</div>';
140
141 // Define a complementary filter for search of next/prev ref.
142 if (!$user->hasRight('projet', 'all', 'lire')) {
143 $objectsListId = $object->getProjectsAuthorizedForUser($user, 0, 0);
144 $object->next_prev_filter = "rowid:IN:".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0');
145 }
146
147 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
148
149
150 print '<div class="fichecenter">';
151 print '<div class="fichehalfleft">';
152 print '<div class="underbanner clearboth"></div>';
153
154 print '<table class="border tableforfield centpercent">';
155
156 // Usage
157 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJECT_HIDE_TASKS') || isModEnabled('eventorganization')) {
158 print '<tr><td class="tdtop">';
159 print $langs->trans("Usage");
160 print '</td>';
161 print '<td>';
162 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
163 print '<input type="checkbox" disabled name="usage_opportunity"'.(GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_opportunity ? ' checked="checked"' : '')).'"> ';
164 $htmltext = $langs->trans("ProjectFollowOpportunity");
165 print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
166 print '<br>';
167 }
168 if (!getDolGlobalString('PROJECT_HIDE_TASKS')) {
169 print '<input type="checkbox" disabled name="usage_task"'.(GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_task ? ' checked="checked"' : '')).'"> ';
170 $htmltext = $langs->trans("ProjectFollowTasks");
171 print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
172 print '<br>';
173 }
174 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
175 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"' : '')).'"> ';
176 $htmltext = $langs->trans("ProjectBillTimeDescription");
177 print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
178 print '<br>';
179 }
180 if (isModEnabled('eventorganization')) {
181 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"' : '')).'"> ';
182 $htmltext = $langs->trans("EventOrganizationDescriptionLong");
183 print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
184 }
185 print '</td></tr>';
186 }
187
188 // Visibility
189 print '<tr><td class="titlefield">'.$langs->trans("Visibility").'</td><td>';
190 if ($object->public) {
191 print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
192 print $langs->trans('SharedProject');
193 } else {
194 print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
195 print $langs->trans('PrivateProject');
196 }
197 print '</td></tr>';
198
199 // Budget
200 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
201 if (!is_null($object->budget_amount) && strcmp($object->budget_amount, '')) {
202 print price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
203 }
204 print '</td></tr>';
205
206 // Date start - end project
207 print '<tr><td>'.$langs->trans("DateStart").' - '.$langs->trans("DateEnd").'</td><td>';
208 $start = dol_print_date($object->date_start, 'day');
209 print($start ? $start : '?');
210 $end = dol_print_date($object->date_end, 'day');
211 print ' - ';
212 print($end ? $end : '?');
213 if ($object->hasDelay()) {
214 print img_warning("Late");
215 }
216 print '</td></tr>';
217
218 // Other attributes
219 $cols = 2;
220 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
221
222 print '</table>';
223
224 print '</div>';
225 print '<div class="fichehalfright">';
226 print '<div class="underbanner clearboth"></div>';
227
228 print '<table class="border tableforfield centpercent">';
229
230 // Description
231 print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>';
232 print nl2br($object->description);
233 print '</td></tr>';
234
235 // Categories
236 if (isModEnabled('category')) {
237 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
238 print $form->showCategories($object->id, Categorie::TYPE_PROJECT, 1);
239 print "</td></tr>";
240 }
241
242 print '</table>';
243
244 print '</div>';
245 print '</div>';
246
247 print '<div class="clearboth"></div>';
248
249 print dol_get_fiche_end();
250
251 print '<br>';
252}
253
254// Link to create task
255$linktocreatetaskParam = array();
256$linktocreatetaskUserRight = false;
257if ($user->hasRight('projet', 'all', 'creer') || $user->hasRight('projet', 'creer')) {
258 if ($object->public || $userWrite > 0) {
259 $linktocreatetaskUserRight = true;
260 } else {
261 $linktocreatetaskParam['attr']['title'] = $langs->trans("NotOwnerOfProject");
262 }
263}
264
265$linktocreatetask = dolGetButtonTitle($langs->trans('AddTask'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id.'&action=create'.$param.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$object->id), '', (int) $linktocreatetaskUserRight, $linktocreatetaskParam);
266
267$linktotasks = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id, '', 1, array('morecss' => 'reposition'));
268$linktotasks .= dolGetButtonTitle($langs->trans('ViewGantt'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1', '', 1, array('morecss' => 'reposition marginleftonly btnTitleSelected'));
269
270//print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1);
271print load_fiche_titre($title, $linktotasks.' &nbsp; '.$linktocreatetask, 'projecttask');
272
273
274// Get list of tasks in tasksarray and taskarrayfiltered
275// We need all tasks (even not limited to a user because a task to user
276// can have a parent that is not affected to him).
277$tasksarray = $task->getTasksArray(null, null, ($object->id ? $object->id : $id), $socid, 0);
278// We load also tasks limited to a particular user
279//$tasksrole=($_REQUEST["mode"]=='mine' ? $task->getUserRolesForProjectsOrTasks(null, $user, $object->id, 0) : '');
280//var_dump($tasksarray);
281//var_dump($tasksrole);
282
283
284if (count($tasksarray) > 0) {
285 // Show Gant diagram from $taskarray using JSGantt
286
287 $dateformat = $langs->trans("FormatDateShortJQuery"); // Used by include ganttchart.inc.php later
288 $datehourformat = $langs->trans("FormatDateShortJQuery").' '.$langs->trans("FormatHourShortJQuery"); // Used by include ganttchart.inc.php later
289 $array_contacts = array();
290 $tasks = array();
291 $task_dependencies = array();
292 $taskcursor = 0;
293 foreach ($tasksarray as $key => $val) { // Task array are sorted by "project, position, date"
294 $task->fetch($val->id, '');
295
296 $idparent = ($val->fk_task_parent ? $val->fk_task_parent : '-'.$val->fk_project); // If start with -, id is a project id
297
298 $tasks[$taskcursor]['task_id'] = $val->id;
299 $tasks[$taskcursor]['task_alternate_id'] = ($taskcursor + 1); // An id that has same order than position (required by ganttchart)
300 $tasks[$taskcursor]['task_project_id'] = $val->fk_project;
301 $tasks[$taskcursor]['task_parent'] = $idparent;
302
303 $tasks[$taskcursor]['task_is_group'] = 0;
304 $tasks[$taskcursor]['task_css'] = 'gtaskblue';
305 $tasks[$taskcursor]['task_position'] = $val->rang;
306 $tasks[$taskcursor]['task_planned_workload'] = $val->planned_workload;
307
308 if ($val->fk_task_parent != 0 && $task->hasChildren() > 0) {
309 $tasks[$taskcursor]['task_is_group'] = 1;
310 $tasks[$taskcursor]['task_css'] = 'ggroupblack';
311 //$tasks[$taskcursor]['task_css'] = 'gtaskblue';
312 } elseif ($task->hasChildren() > 0) {
313 $tasks[$taskcursor]['task_is_group'] = 1;
314 //$tasks[$taskcursor]['task_is_group'] = 0;
315 $tasks[$taskcursor]['task_css'] = 'ggroupblack';
316 //$tasks[$taskcursor]['task_css'] = 'gtaskblue';
317 }
318 $tasks[$taskcursor]['task_milestone'] = 0;
319 $tasks[$taskcursor]['task_percent_complete'] = $val->progress;
320 //$tasks[$taskcursor]['task_name']=$task->getNomUrl(1);
321 //print dol_print_date($val->date_start).dol_print_date($val->date_end).'<br>'."\n";
322 $tasks[$taskcursor]['task_name'] = $val->ref.' - '.$val->label;
323 $tasks[$taskcursor]['task_start_date'] = $val->date_start;
324 $tasks[$taskcursor]['task_end_date'] = $val->date_end;
325 $tasks[$taskcursor]['task_color'] = 'b4d1ea';
326
327 $idofusers = $task->getListContactId('internal');
328 $idofcontacts = $task->getListContactId('external');
329 $s = '';
330 if (count($idofusers) > 0) {
331 $s .= $langs->trans("Internals").': ';
332 $i = 0;
333 foreach ($idofusers as $valid) {
334 $userstatic->fetch($valid);
335 if ($i) {
336 $s .= ', ';
337 }
338 $s .= $userstatic->login;
339 $i++;
340 }
341 }
342 //if (count($idofusers)>0 && (count($idofcontacts)>0)) $s.=' - ';
343 if (count($idofcontacts) > 0) {
344 if ($s) {
345 $s .= ' - ';
346 }
347 $s .= $langs->trans("Externals").': ';
348 $i = 0;
349 $contactidfound = array();
350 foreach ($idofcontacts as $valid) {
351 if (empty($contactidfound[$valid])) {
352 $res = $contactstatic->fetch($valid);
353 if ($res > 0) {
354 if ($i) {
355 $s .= ', ';
356 }
357 $s .= $contactstatic->getFullName($langs);
358 $contactidfound[$valid] = 1;
359 $i++;
360 }
361 }
362 }
363 }
364
365 /* For JSGanttImproved */
366 //if ($s) $tasks[$taskcursor]['task_resources']=implode(',',$idofusers);
367 $tasks[$taskcursor]['task_resources'] = $s;
368 if ($s) {
369 $tasks[$taskcursor]['task_resources'] = '<a href="'.DOL_URL_ROOT.'/projet/tasks/contact.php?id='.$val->id.'&withproject=1" title="'.dol_escape_htmltag($s).'">'.$langs->trans("Contacts").'</a>';
370 }
371 //print "xxx".$val->id.$tasks[$taskcursor]['task_resources'];
372 $tasks[$taskcursor]['note'] = $task->note_public;
373 $taskcursor++;
374 }
375
376 // Search parent to set task_parent_alternate_id (required by ganttchart)
377 foreach ($tasks as $tmpkey => $tmptask) {
378 foreach ($tasks as $tmptask2) {
379 if ($tmptask2['task_id'] == $tmptask['task_parent']) {
380 $tasks[$tmpkey]['task_parent_alternate_id'] = $tmptask2['task_alternate_id'];
381 break;
382 }
383 }
384 if (empty($tasks[$tmpkey]['task_parent_alternate_id'])) {
385 $tasks[$tmpkey]['task_parent_alternate_id'] = $tasks[$tmpkey]['task_parent'];
386 }
387 }
388
389 print "\n";
390
391 if (!empty($conf->use_javascript_ajax)) {
392 //var_dump($_SESSION);
393
394 // How the date for data are formatted (format used bu jsgantt)
395 $dateformatinput = 'yyyy-mm-dd';
396 // How the date for data are formatted (format used by dol_print_date)
397 $dateformatinput2 = 'standard';
398 //var_dump($dateformatinput);
399 //var_dump($dateformatinput2);
400
401 $moreforfilter = '<div class="liste_titre liste_titre_bydiv centpercent">';
402
403 $moreforfilter .= '<div class="divsearchfield">';
404 //$moreforfilter .= $langs->trans("TasksAssignedTo").': ';
405 //$moreforfilter .= $form->select_dolusers($tmpuser->id > 0 ? $tmpuser->id : '', 'search_user_id', 1);
406 $moreforfilter .= '&nbsp;';
407 $moreforfilter .= '</div>';
408
409 $moreforfilter .= '</div>';
410
411 print $moreforfilter;
412
413 print '<div class="div-table-responsive">';
414
415 print '<div id="tabs" class="gantt" style="width: 80vw;">'."\n";
416 include_once DOL_DOCUMENT_ROOT.'/projet/ganttchart.inc.php';
417 print '</div>'."\n";
418
419 print '</div>';
420 } else {
421 $langs->load("admin");
422 print $langs->trans("AvailableOnlyIfJavascriptAndAjaxNotDisabled");
423 }
424} else {
425 print '<div class="opacitymedium">'.$langs->trans("NoTasks").'</div>';
426}
427
428// End of page
429llxFooter();
430$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
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 contact/addresses.
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 projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage tasks.
Class to manage Dolibarr users.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
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.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
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.