dolibarr 21.0.0-alpha
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 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
27require "../main.inc.php";
28require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
29require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
30require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
31require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
32require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
33require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
34require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
35require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
36
37$id = GETPOST('id', 'intcomma');
38$ref = GETPOST('ref', 'alpha');
39
40$mode = GETPOST('mode', 'alpha');
41$mine = ($mode == 'mine' ? 1 : 0);
42//if (! $user->rights->projet->all->lire) $mine=1; // Special for projects
43
44$object = new Project($db);
45
46include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'
47if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_PROJECT') && method_exists($object, 'fetchComments') && empty($object->comments)) {
48 $object->fetchComments();
49}
50
51// Security check
52$socid = 0;
53//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.
54$result = restrictedArea($user, 'projet', $id, 'projet&project');
55
56// Load translation files required by the page
57$langs->loadlangs(array('users', 'projects'));
58
59
60/*
61 * Actions
62 */
63
64// None
65
66
67/*
68 * View
69 */
70
71$form = new Form($db);
72$formother = new FormOther($db);
73$userstatic = new User($db);
74$companystatic = new Societe($db);
75$contactstatic = new Contact($db);
76$task = new Task($db);
77
78$arrayofcss = array('/includes/jsgantt/jsgantt.css');
79
80if (!empty($conf->use_javascript_ajax)) {
81 $arrayofjs = array(
82 '/includes/jsgantt/jsgantt.js',
83 '/projet/jsgantt_language.js.php?lang='.$langs->defaultlang
84 );
85}
86
87//$title=$langs->trans("Gantt").($object->ref?' - '.$object->ref.' '.$object->name:'');
88$title = $langs->trans("Gantt");
89if (getDolGlobalString('MAIN_HTML_TITLE') && preg_match('/projectnameonly/', getDolGlobalString('MAIN_HTML_TITLE')) && $object->name) {
90 $title = ($object->ref ? $object->ref.' '.$object->name.' - ' : '').$langs->trans("Gantt");
91}
92$help_url = "EN:Module_Projects|FR:Module_Projets|ES:M&oacute;dulo_Proyectos";
93
94llxHeader("", $title, $help_url, '', 0, 0, $arrayofjs, $arrayofcss, '', 'mod-project page-card_ganttview');
95
96if (($id > 0 && is_numeric($id)) || !empty($ref)) {
97 // To verify role of users
98 //$userAccess = $object->restrictedProjectArea($user,'read');
99 $userWrite = $object->restrictedProjectArea($user, 'write');
100 //$userDelete = $object->restrictedProjectArea($user,'delete');
101 //print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete;
102
103 $tab = 'tasks';
104
105 $head = project_prepare_head($object);
106 print dol_get_fiche_head($head, $tab, $langs->trans("Project"), -1, ($object->public ? 'projectpub' : 'project'));
107
108 $param = ($mode == 'mine' ? '&mode=mine' : '');
109
110
111
112 // Project card
113
114 if (!empty($_SESSION['pageforbacktolist']) && !empty($_SESSION['pageforbacktolist']['project'])) {
115 $tmpurl = $_SESSION['pageforbacktolist']['project'];
116 $tmpurl = preg_replace('/__SOCID__/', (string) $object->socid, $tmpurl);
117 $linkback = '<a href="'.$tmpurl.(preg_match('/\?/', $tmpurl) ? '&' : '?'). 'restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
118 } else {
119 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
120 }
121
122 $morehtmlref = '<div class="refidno">';
123 // Title
124 $morehtmlref .= $object->title;
125 // Thirdparty
126 if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
127 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'project');
128 }
129 $morehtmlref .= '</div>';
130
131 // Define a complementary filter for search of next/prev ref.
132 if (!$user->hasRight('projet', 'all', 'lire')) {
133 $objectsListId = $object->getProjectsAuthorizedForUser($user, 0, 0);
134 $object->next_prev_filter = "rowid IN (".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0').")";
135 }
136
137 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
138
139
140 print '<div class="fichecenter">';
141 print '<div class="fichehalfleft">';
142 print '<div class="underbanner clearboth"></div>';
143
144 print '<table class="border tableforfield centpercent">';
145
146 // Usage
147 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJECT_HIDE_TASKS') || isModEnabled('eventorganization')) {
148 print '<tr><td class="tdtop">';
149 print $langs->trans("Usage");
150 print '</td>';
151 print '<td>';
152 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
153 print '<input type="checkbox" disabled name="usage_opportunity"'.(GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_opportunity ? ' checked="checked"' : '')).'"> ';
154 $htmltext = $langs->trans("ProjectFollowOpportunity");
155 print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
156 print '<br>';
157 }
158 if (!getDolGlobalString('PROJECT_HIDE_TASKS')) {
159 print '<input type="checkbox" disabled name="usage_task"'.(GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_task ? ' checked="checked"' : '')).'"> ';
160 $htmltext = $langs->trans("ProjectFollowTasks");
161 print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
162 print '<br>';
163 }
164 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
165 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"' : '')).'"> ';
166 $htmltext = $langs->trans("ProjectBillTimeDescription");
167 print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
168 print '<br>';
169 }
170 if (isModEnabled('eventorganization')) {
171 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"' : '')).'"> ';
172 $htmltext = $langs->trans("EventOrganizationDescriptionLong");
173 print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
174 }
175 print '</td></tr>';
176 }
177
178 // Visibility
179 print '<tr><td class="titlefield">'.$langs->trans("Visibility").'</td><td>';
180 if ($object->public) {
181 print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
182 print $langs->trans('SharedProject');
183 } else {
184 print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
185 print $langs->trans('PrivateProject');
186 }
187 print '</td></tr>';
188
189 // Budget
190 print '<tr><td>'.$langs->trans("Budget").'</td><td>';
191 if (!is_null($object->budget_amount) && strcmp($object->budget_amount, '')) {
192 print price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
193 }
194 print '</td></tr>';
195
196 // Date start - end project
197 print '<tr><td>'.$langs->trans("Dates").'</td><td>';
198 $start = dol_print_date($object->date_start, 'day');
199 print($start ? $start : '?');
200 $end = dol_print_date($object->date_end, 'day');
201 print ' - ';
202 print($end ? $end : '?');
203 if ($object->hasDelay()) {
204 print img_warning("Late");
205 }
206 print '</td></tr>';
207
208 // Other attributes
209 $cols = 2;
210 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
211
212 print '</table>';
213
214 print '</div>';
215 print '<div class="fichehalfright">';
216 print '<div class="underbanner clearboth"></div>';
217
218 print '<table class="border tableforfield centpercent">';
219
220 // Description
221 print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>';
222 print nl2br($object->description);
223 print '</td></tr>';
224
225 // Categories
226 if (isModEnabled('category')) {
227 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
228 print $form->showCategories($object->id, Categorie::TYPE_PROJECT, 1);
229 print "</td></tr>";
230 }
231
232 print '</table>';
233
234 print '</div>';
235 print '</div>';
236
237 print '<div class="clearboth"></div>';
238
239 print dol_get_fiche_end();
240
241 print '<br>';
242}
243
244// Link to create task
245$linktocreatetaskParam = array();
246$linktocreatetaskUserRight = false;
247if ($user->hasRight('projet', 'all', 'creer') || $user->hasRight('projet', 'creer')) {
248 if ($object->public || $userWrite > 0) {
249 $linktocreatetaskUserRight = true;
250 } else {
251 $linktocreatetaskParam['attr']['title'] = $langs->trans("NotOwnerOfProject");
252 }
253}
254
255$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);
256
257$linktotasks = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id, '', 1, array('morecss' => 'reposition'));
258$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'));
259
260//print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1);
261print load_fiche_titre($title, $linktotasks.' &nbsp; '.$linktocreatetask, 'projecttask');
262
263
264// Get list of tasks in tasksarray and taskarrayfiltered
265// We need all tasks (even not limited to a user because a task to user
266// can have a parent that is not affected to him).
267$tasksarray = $task->getTasksArray(0, 0, ($object->id ? $object->id : $id), $socid, 0);
268// We load also tasks limited to a particular user
269//$tasksrole=($_REQUEST["mode"]=='mine' ? $task->getUserRolesForProjectsOrTasks(null, $user, $object->id, 0) : '');
270//var_dump($tasksarray);
271//var_dump($tasksrole);
272
273
274if (count($tasksarray) > 0) {
275 // Show Gant diagram from $taskarray using JSGantt
276
277 $dateformat = $langs->trans("FormatDateShortJQuery"); // Used by include ganttchart.inc.php later
278 $datehourformat = $langs->trans("FormatDateShortJQuery").' '.$langs->trans("FormatHourShortJQuery"); // Used by include ganttchart.inc.php later
279 $array_contacts = array();
280 $tasks = array();
281 $task_dependencies = array();
282 $taskcursor = 0;
283 foreach ($tasksarray as $key => $val) { // Task array are sorted by "project, position, date"
284 $task->fetch($val->id, '');
285
286 $idparent = ($val->fk_task_parent ? $val->fk_task_parent : '-'.$val->fk_project); // If start with -, id is a project id
287
288 $tasks[$taskcursor]['task_id'] = $val->id;
289 $tasks[$taskcursor]['task_alternate_id'] = ($taskcursor + 1); // An id that has same order than position (required by ganttchart)
290 $tasks[$taskcursor]['task_project_id'] = $val->fk_project;
291 $tasks[$taskcursor]['task_parent'] = $idparent;
292
293 $tasks[$taskcursor]['task_is_group'] = 0;
294 $tasks[$taskcursor]['task_css'] = 'gtaskblue';
295 $tasks[$taskcursor]['task_position'] = $val->rang;
296 $tasks[$taskcursor]['task_planned_workload'] = $val->planned_workload;
297
298 if ($val->fk_task_parent != 0 && $task->hasChildren() > 0) {
299 $tasks[$taskcursor]['task_is_group'] = 1;
300 $tasks[$taskcursor]['task_css'] = 'ggroupblack';
301 //$tasks[$taskcursor]['task_css'] = 'gtaskblue';
302 } elseif ($task->hasChildren() > 0) {
303 $tasks[$taskcursor]['task_is_group'] = 1;
304 //$tasks[$taskcursor]['task_is_group'] = 0;
305 $tasks[$taskcursor]['task_css'] = 'ggroupblack';
306 //$tasks[$taskcursor]['task_css'] = 'gtaskblue';
307 }
308 $tasks[$taskcursor]['task_milestone'] = '0';
309 $tasks[$taskcursor]['task_percent_complete'] = $val->progress;
310 //$tasks[$taskcursor]['task_name']=$task->getNomUrl(1);
311 //print dol_print_date($val->date_start).dol_print_date($val->date_end).'<br>'."\n";
312 $tasks[$taskcursor]['task_name'] = $val->ref.' - '.$val->label;
313 $tasks[$taskcursor]['task_start_date'] = $val->date_start;
314 $tasks[$taskcursor]['task_end_date'] = $val->date_end;
315 $tasks[$taskcursor]['task_color'] = 'b4d1ea';
316
317 $idofusers = $task->getListContactId('internal');
318 $idofcontacts = $task->getListContactId('external');
319 $s = '';
320 if (count($idofusers) > 0) {
321 $s .= $langs->trans("Internals").': ';
322 $i = 0;
323 foreach ($idofusers as $valid) {
324 $userstatic->fetch($valid);
325 if ($i) {
326 $s .= ', ';
327 }
328 $s .= $userstatic->login;
329 $i++;
330 }
331 }
332 //if (count($idofusers)>0 && (count($idofcontacts)>0)) $s.=' - ';
333 if (count($idofcontacts) > 0) {
334 if ($s) {
335 $s .= ' - ';
336 }
337 $s .= $langs->trans("Externals").': ';
338 $i = 0;
339 $contactidfound = array();
340 foreach ($idofcontacts as $valid) {
341 if (empty($contactidfound[$valid])) {
342 $res = $contactstatic->fetch($valid);
343 if ($res > 0) {
344 if ($i) {
345 $s .= ', ';
346 }
347 $s .= $contactstatic->getFullName($langs);
348 $contactidfound[$valid] = 1;
349 $i++;
350 }
351 }
352 }
353 }
354
355 /* For JSGanttImproved */
356 //if ($s) $tasks[$taskcursor]['task_resources']=implode(',',$idofusers);
357 $tasks[$taskcursor]['task_resources'] = $s;
358 if ($s) {
359 $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>';
360 }
361 //print "xxx".$val->id.$tasks[$taskcursor]['task_resources'];
362 $tasks[$taskcursor]['note'] = $task->note_public;
363 $taskcursor++;
364 }
365
366 // Search parent to set task_parent_alternate_id (required by ganttchart)
367 foreach ($tasks as $tmpkey => $tmptask) {
368 foreach ($tasks as $tmptask2) {
369 if ($tmptask2['task_id'] == $tmptask['task_parent']) {
370 $tasks[$tmpkey]['task_parent_alternate_id'] = $tmptask2['task_alternate_id'];
371 break;
372 }
373 }
374 if (empty($tasks[$tmpkey]['task_parent_alternate_id'])) {
375 $tasks[$tmpkey]['task_parent_alternate_id'] = $tasks[$tmpkey]['task_parent'];
376 }
377 }
378
379 print "\n";
380
381 if (!empty($conf->use_javascript_ajax)) {
382 //var_dump($_SESSION);
383
384 // How the date for data are formatted (format used bu jsgantt)
385 $dateformatinput = 'yyyy-mm-dd';
386 // How the date for data are formatted (format used by dol_print_date)
387 $dateformatinput2 = 'standard';
388 //var_dump($dateformatinput);
389 //var_dump($dateformatinput2);
390
391 $moreforfilter = '<div class="liste_titre liste_titre_bydiv centpercent">';
392
393 $moreforfilter .= '<div class="divsearchfield">';
394 //$moreforfilter .= $langs->trans("TasksAssignedTo").': ';
395 //$moreforfilter .= $form->select_dolusers($tmpuser->id > 0 ? $tmpuser->id : '', 'search_user_id', 1);
396 $moreforfilter .= '&nbsp;';
397 $moreforfilter .= '</div>';
398
399 $moreforfilter .= '</div>';
400
401 print $moreforfilter;
402
403 print '<div class="div-table-responsive">';
404
405 print '<div id="tabs" class="gantt" style="width: 80vw;">'."\n";
406 include_once DOL_DOCUMENT_ROOT.'/projet/ganttchart.inc.php';
407 print '</div>'."\n";
408
409 print '</div>';
410 } else {
411 $langs->load("admin");
412 print $langs->trans("AvailableOnlyIfJavascriptAndAjaxNotDisabled");
413 }
414} else {
415 print '<div class="opacitymedium">'.$langs->trans("NoTasks").'</div>';
416}
417
418// End of page
419llxFooter();
420$db->close();
$id
Definition account.php:39
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
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:70
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...
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.