Issues (2811)

public/htdocs/projet/ganttview.php (1 issue)

Labels
Severity
1
<?php
2
3
/* Copyright (C) 2005       Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2004-2017  Laurent Destailleur         <[email protected]>
5
 * Copyright (C) 2005-2012  Regis Houssin               <[email protected]>
6
 * Copyright (C) 2024		MDW							<[email protected]>
7
 * Copyright (C) 2024       Rafael San José             <[email protected]>
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
23
use Dolibarr\Code\Categories\Classes\Categorie;
24
use Dolibarr\Code\Contact\Classes\Contact;
25
use Dolibarr\Code\Core\Classes\Form;
26
use Dolibarr\Code\Core\Classes\FormOther;
27
use Dolibarr\Code\Projet\Classes\Project;
28
use Dolibarr\Code\Projet\Classes\Task;
29
use Dolibarr\Code\Societe\Classes\Societe;
30
use Dolibarr\Code\User\Classes\User;
31
use Dolibarr\Lib\ViewMain;
32
33
/**
34
 *  \file       htdocs/projet/ganttview.php
35
 *  \ingroup    projet
36
 *  \brief      Gantt diagram of a project
37
 */
38
39
require constant('DOL_DOCUMENT_ROOT') . '/main.inc.php';
40
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/project.lib.php';
41
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/date.lib.php';
42
43
$id = GETPOST('id', 'intcomma');
44
$ref = GETPOST('ref', 'alpha');
45
46
$mode = GETPOST('mode', 'alpha');
47
$mine = ($mode == 'mine' ? 1 : 0);
48
//if (! $user->rights->projet->all->lire) $mine=1;  // Special for projects
49
50
$object = new Project($db);
51
52
include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once
53
if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_PROJECT') && method_exists($object, 'fetchComments') && empty($object->comments)) {
54
    $object->fetchComments();
55
}
56
57
// Security check
58
$socid = 0;
59
//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.
60
$result = restrictedArea($user, 'projet', $id, 'projet&project');
61
62
// Load translation files required by the page
63
$langs->loadlangs(array('users', 'projects'));
64
65
66
/*
67
 * Actions
68
 */
69
70
// None
71
72
/*
73
 * View
74
 */
75
76
$form = new Form($db);
77
$formother = new FormOther($db);
78
$userstatic = new User($db);
79
$companystatic = new Societe($db);
80
$contactstatic = new Contact($db);
81
$task = new Task($db);
82
83
$arrayofcss = array('/includes/jsgantt/jsgantt.css');
84
85
if (!empty($conf->use_javascript_ajax)) {
86
    $arrayofjs = array(
87
        '/includes/jsgantt/jsgantt.js',
88
        '/projet/jsgantt_language.js.php?lang=' . $langs->defaultlang
89
    );
90
}
91
92
//$title=$langs->trans("Gantt").($object->ref?' - '.$object->ref.' '.$object->name:'');
93
$title = $langs->trans("Gantt");
94
if (getDolGlobalString('MAIN_HTML_TITLE') && preg_match('/projectnameonly/', getDolGlobalString('MAIN_HTML_TITLE')) && $object->name) {
95
    $title = ($object->ref ? $object->ref . ' ' . $object->name . ' - ' : '') . $langs->trans("Gantt");
96
}
97
$help_url = "EN:Module_Projects|FR:Module_Projets|ES:M&oacute;dulo_Proyectos";
98
99
ViewMain::llxHeader("", $title, $help_url, '', 0, 0, $arrayofjs, $arrayofcss);
100
101
if (($id > 0 && is_numeric($id)) || !empty($ref)) {
102
    // To verify role of users
103
    //$userAccess = $object->restrictedProjectArea($user,'read');
104
    $userWrite = $object->restrictedProjectArea($user, 'write');
105
    //$userDelete = $object->restrictedProjectArea($user,'delete');
106
    //print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete;
107
108
    $tab = 'tasks';
109
110
    $head = project_prepare_head($object);
111
    print dol_get_fiche_head($head, $tab, $langs->trans("Project"), -1, ($object->public ? 'projectpub' : 'project'));
112
113
    $param = ($mode == 'mine' ? '&mode=mine' : '');
114
115
116
    // Project card
117
118
    if (!empty($_SESSION['pageforbacktolist']) && !empty($_SESSION['pageforbacktolist']['project'])) {
119
        $tmpurl = $_SESSION['pageforbacktolist']['project'];
120
        $tmpurl = preg_replace('/__SOCID__/', (string)$object->socid, $tmpurl);
121
        $linkback = '<a href="' . $tmpurl . (preg_match('/\?/', $tmpurl) ? '&' : '?') . 'restore_lastsearch_values=1">' . $langs->trans("BackToList") . '</a>';
122
    } else {
123
        $linkback = '<a href="' . constant('BASE_URL') . '/projet/list.php?restore_lastsearch_values=1">' . $langs->trans("BackToList") . '</a>';
124
    }
125
126
    $morehtmlref = '<div class="refidno">';
127
    // Title
128
    $morehtmlref .= $object->title;
129
    // Thirdparty
130
    if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
131
        $morehtmlref .= '<br>' . $object->thirdparty->getNomUrl(1, 'project');
0 ignored issues
show
The method getNomUrl() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

131
        $morehtmlref .= '<br>' . $object->thirdparty->/** @scrutinizer ignore-call */ getNomUrl(1, 'project');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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