dolibarr 21.0.0-beta
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 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
104if (($id > 0 && is_numeric($id)) || !empty($ref)) {
105 // To verify role of users
106 //$userAccess = $object->restrictedProjectArea($user,'read');
107 $userWrite = $object->restrictedProjectArea($user, 'write');
108 //$userDelete = $object->restrictedProjectArea($user,'delete');
109 //print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete;
110
111 $tab = 'tasks';
112
113 $head = project_prepare_head($object);
114 print dol_get_fiche_head($head, $tab, $langs->trans("Project"), -1, ($object->public ? 'projectpub' : 'project'));
115
116 $param = ($mode == 'mine' ? '&mode=mine' : '');
117
118
119
120 // Project card
121
122 if (!empty($_SESSION['pageforbacktolist']) && !empty($_SESSION['pageforbacktolist']['project'])) {
123 $tmpurl = $_SESSION['pageforbacktolist']['project'];
124 $tmpurl = preg_replace('/__SOCID__/', (string) $object->socid, $tmpurl);
125 $linkback = '<a href="'.$tmpurl.(preg_match('/\?/', $tmpurl) ? '&' : '?'). 'restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
126 } else {
127 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
128 }
129
130 $morehtmlref = '<div class="refidno">';
131 // Title
132 $morehtmlref .= $object->title;
133 // Thirdparty
134 if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
135 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'project');
136 }
137 $morehtmlref .= '</div>';
138
139 // Define a complementary filter for search of next/prev ref.
140 if (!$user->hasRight('projet', 'all', 'lire')) {
141 $objectsListId = $object->getProjectsAuthorizedForUser($user, 0, 0);
142 $object->next_prev_filter = "rowid:IN:(".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0').")";
143 }
144
145 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
146
147
148 print '<div class="fichecenter">';
149 print '<div class="fichehalfleft">';
150 print '<div class="underbanner clearboth"></div>';
151
152 print '<table class="border tableforfield centpercent">';
153
154 // Usage
155 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJECT_HIDE_TASKS') || isModEnabled('eventorganization')) {
156 print '<tr><td class="tdtop">';
157 print $langs->trans("Usage");
158 print '</td>';
159 print '<td>';
160 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
161 print '<input type="checkbox" disabled name="usage_opportunity"'.(GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_opportunity ? ' checked="checked"' : '')).'"> ';
162 $htmltext = $langs->trans("ProjectFollowOpportunity");
163 print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
164 print '<br>';
165 }
166 if (!getDolGlobalString('PROJECT_HIDE_TASKS')) {
167 print '<input type="checkbox" disabled name="usage_task"'.(GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_task ? ' checked="checked"' : '')).'"> ';
168 $htmltext = $langs->trans("ProjectFollowTasks");
169 print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
170 print '<br>';
171 }
172 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
173 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"' : '')).'"> ';
174 $htmltext = $langs->trans("ProjectBillTimeDescription");
175 print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
176 print '<br>';
177 }
178 if (isModEnabled('eventorganization')) {
179 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"' : '')).'"> ';
180 $htmltext = $langs->trans("EventOrganizationDescriptionLong");
181 print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
182 }
183 print '</td></tr>';
184 }
185
186 // Visibility
187 print '<tr><td class="titlefield">'.$langs->trans("Visibility").'</td><td>';
188 if ($object->public) {
189 print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
190 print $langs->trans('SharedProject');
191 } else {
192 print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
193 print $langs->trans('PrivateProject');
194 }
195 print '</td></tr>';
196
197 // Budget
198 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
199 if (!is_null($object->budget_amount) && strcmp($object->budget_amount, '')) {
200 print price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
201 }
202 print '</td></tr>';
203
204 // Date start - end project
205 print '<tr><td>'.$langs->trans("Dates").'</td><td>';
206 $start = dol_print_date($object->date_start, 'day');
207 print($start ? $start : '?');
208 $end = dol_print_date($object->date_end, 'day');
209 print ' - ';
210 print($end ? $end : '?');
211 if ($object->hasDelay()) {
212 print img_warning("Late");
213 }
214 print '</td></tr>';
215
216 // Other attributes
217 $cols = 2;
218 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
219
220 print '</table>';
221
222 print '</div>';
223 print '<div class="fichehalfright">';
224 print '<div class="underbanner clearboth"></div>';
225
226 print '<table class="border tableforfield centpercent">';
227
228 // Description
229 print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>';
230 print nl2br($object->description);
231 print '</td></tr>';
232
233 // Categories
234 if (isModEnabled('category')) {
235 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
236 print $form->showCategories($object->id, Categorie::TYPE_PROJECT, 1);
237 print "</td></tr>";
238 }
239
240 print '</table>';
241
242 print '</div>';
243 print '</div>';
244
245 print '<div class="clearboth"></div>';
246
247 print dol_get_fiche_end();
248
249 print '<br>';
250}
251
252// Link to create task
253$linktocreatetaskParam = array();
254$linktocreatetaskUserRight = false;
255if ($user->hasRight('projet', 'all', 'creer') || $user->hasRight('projet', 'creer')) {
256 if ($object->public || $userWrite > 0) {
257 $linktocreatetaskUserRight = true;
258 } else {
259 $linktocreatetaskParam['attr']['title'] = $langs->trans("NotOwnerOfProject");
260 }
261}
262
263$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);
264
265$linktotasks = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id, '', 1, array('morecss' => 'reposition'));
266$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'));
267
268//print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1);
269print load_fiche_titre($title, $linktotasks.' &nbsp; '.$linktocreatetask, 'projecttask');
270
271
272// Get list of tasks in tasksarray and taskarrayfiltered
273// We need all tasks (even not limited to a user because a task to user
274// can have a parent that is not affected to him).
275$tasksarray = $task->getTasksArray(0, 0, ($object->id ? $object->id : $id), $socid, 0);
276// We load also tasks limited to a particular user
277//$tasksrole=($_REQUEST["mode"]=='mine' ? $task->getUserRolesForProjectsOrTasks(null, $user, $object->id, 0) : '');
278//var_dump($tasksarray);
279//var_dump($tasksrole);
280
281
282if (count($tasksarray) > 0) {
283 // Show Gant diagram from $taskarray using JSGantt
284
285 $dateformat = $langs->trans("FormatDateShortJQuery"); // Used by include ganttchart.inc.php later
286 $datehourformat = $langs->trans("FormatDateShortJQuery").' '.$langs->trans("FormatHourShortJQuery"); // Used by include ganttchart.inc.php later
287 $array_contacts = array();
288 $tasks = array();
289 $task_dependencies = array();
290 $taskcursor = 0;
291 foreach ($tasksarray as $key => $val) { // Task array are sorted by "project, position, date"
292 $task->fetch($val->id, '');
293
294 $idparent = ($val->fk_task_parent ? $val->fk_task_parent : '-'.$val->fk_project); // If start with -, id is a project id
295
296 $tasks[$taskcursor]['task_id'] = $val->id;
297 $tasks[$taskcursor]['task_alternate_id'] = ($taskcursor + 1); // An id that has same order than position (required by ganttchart)
298 $tasks[$taskcursor]['task_project_id'] = $val->fk_project;
299 $tasks[$taskcursor]['task_parent'] = $idparent;
300
301 $tasks[$taskcursor]['task_is_group'] = 0;
302 $tasks[$taskcursor]['task_css'] = 'gtaskblue';
303 $tasks[$taskcursor]['task_position'] = $val->rang;
304 $tasks[$taskcursor]['task_planned_workload'] = $val->planned_workload;
305
306 if ($val->fk_task_parent != 0 && $task->hasChildren() > 0) {
307 $tasks[$taskcursor]['task_is_group'] = 1;
308 $tasks[$taskcursor]['task_css'] = 'ggroupblack';
309 //$tasks[$taskcursor]['task_css'] = 'gtaskblue';
310 } elseif ($task->hasChildren() > 0) {
311 $tasks[$taskcursor]['task_is_group'] = 1;
312 //$tasks[$taskcursor]['task_is_group'] = 0;
313 $tasks[$taskcursor]['task_css'] = 'ggroupblack';
314 //$tasks[$taskcursor]['task_css'] = 'gtaskblue';
315 }
316 $tasks[$taskcursor]['task_milestone'] = '0';
317 $tasks[$taskcursor]['task_percent_complete'] = $val->progress;
318 //$tasks[$taskcursor]['task_name']=$task->getNomUrl(1);
319 //print dol_print_date($val->date_start).dol_print_date($val->date_end).'<br>'."\n";
320 $tasks[$taskcursor]['task_name'] = $val->ref.' - '.$val->label;
321 $tasks[$taskcursor]['task_start_date'] = $val->date_start;
322 $tasks[$taskcursor]['task_end_date'] = $val->date_end;
323 $tasks[$taskcursor]['task_color'] = 'b4d1ea';
324
325 $idofusers = $task->getListContactId('internal');
326 $idofcontacts = $task->getListContactId('external');
327 $s = '';
328 if (count($idofusers) > 0) {
329 $s .= $langs->trans("Internals").': ';
330 $i = 0;
331 foreach ($idofusers as $valid) {
332 $userstatic->fetch($valid);
333 if ($i) {
334 $s .= ', ';
335 }
336 $s .= $userstatic->login;
337 $i++;
338 }
339 }
340 //if (count($idofusers)>0 && (count($idofcontacts)>0)) $s.=' - ';
341 if (count($idofcontacts) > 0) {
342 if ($s) {
343 $s .= ' - ';
344 }
345 $s .= $langs->trans("Externals").': ';
346 $i = 0;
347 $contactidfound = array();
348 foreach ($idofcontacts as $valid) {
349 if (empty($contactidfound[$valid])) {
350 $res = $contactstatic->fetch($valid);
351 if ($res > 0) {
352 if ($i) {
353 $s .= ', ';
354 }
355 $s .= $contactstatic->getFullName($langs);
356 $contactidfound[$valid] = 1;
357 $i++;
358 }
359 }
360 }
361 }
362
363 /* For JSGanttImproved */
364 //if ($s) $tasks[$taskcursor]['task_resources']=implode(',',$idofusers);
365 $tasks[$taskcursor]['task_resources'] = $s;
366 if ($s) {
367 $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>';
368 }
369 //print "xxx".$val->id.$tasks[$taskcursor]['task_resources'];
370 $tasks[$taskcursor]['note'] = $task->note_public;
371 $taskcursor++;
372 }
373
374 // Search parent to set task_parent_alternate_id (required by ganttchart)
375 foreach ($tasks as $tmpkey => $tmptask) {
376 foreach ($tasks as $tmptask2) {
377 if ($tmptask2['task_id'] == $tmptask['task_parent']) {
378 $tasks[$tmpkey]['task_parent_alternate_id'] = $tmptask2['task_alternate_id'];
379 break;
380 }
381 }
382 if (empty($tasks[$tmpkey]['task_parent_alternate_id'])) {
383 $tasks[$tmpkey]['task_parent_alternate_id'] = $tasks[$tmpkey]['task_parent'];
384 }
385 }
386
387 print "\n";
388
389 if (!empty($conf->use_javascript_ajax)) {
390 //var_dump($_SESSION);
391
392 // How the date for data are formatted (format used bu jsgantt)
393 $dateformatinput = 'yyyy-mm-dd';
394 // How the date for data are formatted (format used by dol_print_date)
395 $dateformatinput2 = 'standard';
396 //var_dump($dateformatinput);
397 //var_dump($dateformatinput2);
398
399 $moreforfilter = '<div class="liste_titre liste_titre_bydiv centpercent">';
400
401 $moreforfilter .= '<div class="divsearchfield">';
402 //$moreforfilter .= $langs->trans("TasksAssignedTo").': ';
403 //$moreforfilter .= $form->select_dolusers($tmpuser->id > 0 ? $tmpuser->id : '', 'search_user_id', 1);
404 $moreforfilter .= '&nbsp;';
405 $moreforfilter .= '</div>';
406
407 $moreforfilter .= '</div>';
408
409 print $moreforfilter;
410
411 print '<div class="div-table-responsive">';
412
413 print '<div id="tabs" class="gantt" style="width: 80vw;">'."\n";
414 include_once DOL_DOCUMENT_ROOT.'/projet/ganttchart.inc.php';
415 print '</div>'."\n";
416
417 print '</div>';
418 } else {
419 $langs->load("admin");
420 print $langs->trans("AvailableOnlyIfJavascriptAndAjaxNotDisabled");
421 }
422} else {
423 print '<div class="opacitymedium">'.$langs->trans("NoTasks").'</div>';
424}
425
426// End of page
427llxFooter();
428$db->close();
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
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:71
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.
llxFooter()
Footer empty.
Definition document.php:107
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
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.