dolibarr 25.0.0-alpha
index.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2010 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2019 Nicolas ZABOURI <info@inovea-conseil.com>
6 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
7 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
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
29// Load Dolibarr environment
30require '../main.inc.php';
38require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
39require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
40require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
41require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
42require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
43
44// Load translation files required by the page
45$langs->loadLangs(array('projects', 'companies'));
46
47// Initialize a technical object to manage hooks. Note that conf->hooks_modules contains array
48$hookmanager->initHooks(array('projectsindex'));
49
50$action = GETPOST('action', 'aZ09');
51$search_project_user = GETPOST('search_project_user');
52$mine = (GETPOST('mode', 'aZ09') == 'mine' || $search_project_user == $user->id) ? 1 : 0;
53if ($mine == 0 && $search_project_user === '') {
54 $search_project_user = getDolGlobalString('MAIN_SEARCH_PROJECT_USER_PROJECTSINDEX');
55}
56if ($search_project_user == $user->id) {
57 $mine = 1;
58}
59
60$sortfield = GETPOST('sortfield', 'aZ09comma');
61$sortorder = GETPOST('sortorder', 'aZ09comma');
62
63$max = getDolUserInt('MAIN_SIZE_SHORTLIST_LIMIT', getDolGlobalInt('MAIN_SIZE_SHORTLIST_LIMIT', 5));
64
65// Security check
66$socid = 0;
67//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.
68if (!$user->hasRight('projet', 'lire')) {
70}
71
72
73/*
74 * Actions
75 */
76
77$parameters = array();
78$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
79if ($reshook < 0) {
80 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
81}
82if (empty($reshook)) {
83 if ($action == 'refresh_search_project_user' && $user->hasRight('projet', 'lire')) {
84 $search_project_user = GETPOSTINT('search_project_user');
85 $tabparam = array("MAIN_SEARCH_PROJECT_USER_PROJECTSINDEX" => $search_project_user);
86
87 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
88 $result = dol_set_user_param($db, $conf, $user, $tabparam);
89 }
90}
91
92
93/*
94 * View
95 */
96
97$companystatic = new Societe($db);
98$projectstatic = new Project($db);
99$form = new Form($db);
100$formfile = new FormFile($db);
101
102$projectset = ($mine ? $mine : (!$user->hasRight('projet', 'all', 'lire') ? 0 : 2));
103$projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, $projectset, 1);
104//var_dump($projectsListId);
105
106
107$title = $langs->trans('ProjectsArea');
108
109$help_url = 'EN:Module_Projects|FR:Module_Projets|ES:M&oacute;dulo_Proyectos|DE:Modul_Projekte';
110
111llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-project page-dashboard');
112
113
114//if ($mine) $title=$langs->trans("MyProjectsArea");
115
116
117// Title for combo list see all projects
118$titleall = $langs->trans("AllAllowedProjects");
119if ($user->hasRight('projet', 'all', 'lire') && !$socid) {
120 $titleall = $langs->trans("AllProjects");
121} else {
122 $titleall = $langs->trans("AllAllowedProjects").'<br><br>';
123}
124
125$morehtml = '<form name="projectform" method="POST" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
126$morehtml .= '<input type="hidden" name="token" value="'.newToken().'">';
127$morehtml .= '<input type="hidden" name="action" value="refresh_search_project_user">';
128
129$morehtml .= '<select name="search_project_user" id="search_project_user">';
130$morehtml .= '<option name="all" value="0"'.($mine ? '' : ' selected').'>'.$titleall.'</option>';
131$morehtml .= '<option name="mine" value="'.$user->id.'"'.(($search_project_user == $user->id) ? ' selected' : '').'>'.$langs->trans("ProjectsImContactFor").'</option>';
132$morehtml .= '</select>';
133$morehtml .= ajax_combobox("search_project_user", array(), 0, 0, 'resolve', '-1', 'small');
134$morehtml .= '<input type="submit" class="button smallpaddingimp" name="refresh" value="'.$langs->trans("Refresh").'">';
135$morehtml .= '</form>';
136
137if ($mine) {
138 $htmltooltip = $langs->trans("MyProjectsDesc");
139} else {
140 if ($user->hasRight('projet', 'all', 'lire') && !$socid) {
141 $htmltooltip = $langs->trans("ProjectsDesc");
142 } else {
143 $htmltooltip = $langs->trans("ProjectsPublicDesc");
144 }
145}
146
147print_barre_liste($form->textwithpicto($title, $htmltooltip), 0, $_SERVER["PHP_SELF"], '', '', '', '', 0, -1, 'project', 0, $morehtml);
148
149
150// Get list of ponderated percent and colors for each status
151include DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/theme_vars.inc.php';
160// Available from theme_vars:
161'
162@phan-var-force string $badgeStatus0
163@phan-var-force string $badgeStatus1
164@phan-var-force string $badgeStatus2
165@phan-var-force string $badgeStatus3
166@phan-var-force string $badgeStatus4
167@phan-var-force string $badgeStatus5
168@phan-var-force string $badgeStatus6
169@phan-var-force string $badgeStatus7
170@phan-var-force string $badgeStatus8
171@phan-var-force string $badgeStatus9
172';
173$listofoppstatus = array();
174$listofopplabel = array();
175$listofoppcode = array();
176$colorseries = array();
177$sql = "SELECT cls.rowid, cls.code, cls.percent, cls.label";
178$sql .= " FROM ".MAIN_DB_PREFIX."c_lead_status as cls";
179$sql .= " WHERE active=1";
180$resql = $db->query($sql);
181if ($resql) {
182 $num = $db->num_rows($resql);
183 $i = 0;
184
185 while ($i < $num) {
186 $objp = $db->fetch_object($resql);
187 $listofoppstatus[$objp->rowid] = $objp->percent;
188 $listofopplabel[$objp->rowid] = $objp->label; // default label if translation from "OppStatus".code not found.
189 $listofoppcode[$objp->rowid] = $objp->code;
190 switch ($objp->code) {
191 case 'PROSP':
192 $colorseries[$objp->rowid] = "-".$badgeStatus0;
193 break;
194 case 'QUAL':
195 $colorseries[$objp->rowid] = "-".$badgeStatus1;
196 break;
197 case 'PROPO':
198 $colorseries[$objp->rowid] = $badgeStatus1;
199 break;
200 case 'NEGO':
201 $colorseries[$objp->rowid] = $badgeStatus4;
202 break;
203 case 'LOST':
204 $colorseries[$objp->rowid] = $badgeStatus9;
205 break;
206 case 'WON':
207 $colorseries[$objp->rowid] = $badgeStatus6;
208 break;
209 default:
210 $colorseries[$objp->rowid] = $badgeStatus2;
211 break;
212 }
213 $i++;
214 }
215} else {
217}
218
219
220print '<div class="fichecenter">';
221
222print '<div class="twocolumns">';
223
224print '<div class="firstcolumn fichehalfleft boxhalfleft" id="boxhalfleft">';
225
226
227// Statistics
228include DOL_DOCUMENT_ROOT.'/projet/graph_opportunities.inc.php';
229
230// List of draft projects
231print_projecttasks_array($db, $form, $socid, $projectsListId, 0, 0, $listofoppstatus, array('projectlabel', 'plannedworkload', 'declaredprogress', 'prospectionstatus', 'projectstatus'), $max);
232
233
234print '</div><div class="secondcolumn fichehalfright boxhalfright" id="boxhalfright">';
235
236
237// Latest modified projects
238$sql = "SELECT p.rowid, p.ref, p.title, p.dateo as date_start, p.datee as date_end, p.fk_statut as status, p.tms as datem";
239$sql .= ", s.rowid as socid, s.nom as name, s.name_alias";
240$sql .= ", s.code_client, s.code_compta, s.client";
241$sql .= ", s.code_fournisseur, s.code_compta_fournisseur, s.fournisseur";
242$sql .= ", s.logo, s.email, s.entity";
243$sql .= ", s.canvas, s.status as thirdpartystatus";
244$sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
245$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid";
246$sql .= " WHERE p.entity IN (".getEntity('project').")";
247if ($mine || !$user->hasRight('projet', 'all', 'lire')) {
248 $sql .= " AND p.rowid IN (".$db->sanitize($projectsListId).")"; // If we have this test true, it also means projectset is not 2
249}
250if ($socid) {
251 $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
252}
253$sql .= " ORDER BY p.tms DESC";
254$sql .= $db->plimit($max, 0);
255
256$resql = $db->query($sql);
257if ($resql) {
258 startSimpleTable($langs->trans("LatestModifiedProjects", $max), "projet/list.php", "sortfield=p.tms&sortorder=DESC", 3, -1, 'project');
259
260 $num = $db->num_rows($resql);
261
262 if ($num) {
263 $i = 0;
264 while ($i < $num) {
265 $obj = $db->fetch_object($resql);
266
267 print '<tr class="oddeven">';
268 print '<td class="nowrap">';
269
270 $projectstatic->id = $obj->rowid;
271 $projectstatic->ref = $obj->ref;
272 $projectstatic->title = $obj->title;
273 $projectstatic->thirdparty_name = $obj->name;
274 $projectstatic->status = $obj->status;
275 $projectstatic->date_start = $db->jdate($obj->date_start);
276 $projectstatic->date_end = $db->jdate($obj->date_end);
277
278 $companystatic->id = $obj->socid;
279 $companystatic->name = $obj->name;
280 $companystatic->name_alias = $obj->name_alias;
281 $companystatic->client = $obj->client;
282 $companystatic->fournisseur = $obj->fournisseur;
283
284 //$companystatic->code_client = $obj->code_client;
285 $companystatic->code_compta = $obj->code_compta;
286 $companystatic->code_compta_client = $obj->code_compta;
287 $companystatic->code_compta_fournisseur = $obj->code_compta_fournisseur;
288
289 $companystatic->logo = $obj->logo;
290 $companystatic->email = $obj->email;
291 $companystatic->entity = $obj->entity;
292 $companystatic->canvas = $obj->canvas;
293 $companystatic->status = $obj->thirdpartystatus;
294
295 print '<table class="nobordernopadding"><tr class="nocellnopadd">';
296 print '<td width="96" class="nobordernopadding nowraponall">';
297 print $projectstatic->getNomUrl(1);
298 print '</td>';
299
300 print '<td width="16" class="nobordernopadding nowrap">';
301 print '&nbsp;';
302 print '</td>';
303
304 print '<td width="16" class="right nobordernopadding hideonsmartphone">';
305 $filename = dol_sanitizeFileName($obj->ref);
306 $filedir = $conf->project->dir_output.'/'.dol_sanitizeFileName($obj->ref);
307 print $formfile->getDocumentsLink($projectstatic->element, $filename, $filedir);
308 print '</td></tr></table>';
309
310 print '</td>';
311
312 // Label
313 print '<td class="" title="'.dolPrintHTMLForAttribute($obj->title).'">';
314 print '<div class="twolinesmax-normallineheight minwidth100onall">';
315 print dolPrintHTML($projectstatic->title);
316 print '</div>';
317 print '</td>';
318
319 // Thirdparty
320 print '<td class="tdoverflowmax125" title="'.dolPrintHTMLForAttribute($companystatic->name).'">';
321 if ($companystatic->id > 0) {
322 print $companystatic->getNomUrl(1, 'company', 16);
323 }
324 print '</td>';
325
326 // Date
327 $datem = $db->jdate($obj->datem);
328 print '<td class="center" title="'.dolPrintHTMLForAttribute($langs->trans("DateModification").': '.dol_print_date($datem, 'dayhour', 'tzuserrel')).'">';
329 print dol_print_date($datem, 'day', 'tzuserrel');
330 print '</td>';
331
332 // Status
333 print '<td class="right">'.$projectstatic->LibStatut($obj->status, 3).'</td>';
334 print '</tr>';
335 $i++;
336 }
337 } else {
338 print '<tr><td colspan="4"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
339 }
340
341 finishSimpleTable(true);
342} else {
344}
345
346
347$companystatic = new Societe($db); // We need a clean new object for next loop because current one has some properties set.
348
349if (empty($sortfield)) {
350 $sortfield = 'nb';
351 $sortorder = 'desc';
352}
353
354// List of open projects per thirdparty
355$sql = "SELECT COUNT(p.rowid) as nb, SUM(p.opp_amount)";
356$sql .= ", s.rowid as socid, s.nom as name, s.name_alias";
357$sql .= ", s.code_client, s.code_compta, s.client";
358$sql .= ", s.code_fournisseur, s.code_compta_fournisseur, s.fournisseur";
359$sql .= ", s.logo, s.email, s.entity";
360$sql .= ", s.canvas, s.status";
361$sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
362$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid";
363$sql .= " WHERE p.entity IN (".getEntity('project').")";
364$sql .= " AND p.fk_statut = 1";
365if ($mine || !$user->hasRight('projet', 'all', 'lire')) {
366 $sql .= " AND p.rowid IN (".$db->sanitize($projectsListId).")"; // If we have this test true, it also means projectset is not 2
367}
368if ($socid > 0) {
369 $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
370}
371$sql .= " GROUP BY s.rowid, s.nom, s.name_alias, s.code_client, s.code_compta, s.client, s.code_fournisseur, s.code_compta_fournisseur, s.fournisseur, s.logo, s.email, s.entity, s.canvas, s.status";
372$sql .= $db->order($sortfield, $sortorder);
373//$sql .= $db->plimit($max + 1, 0);
374
375$resql = $db->query($sql);
376if ($resql) {
377 $num = $db->num_rows($resql);
378 $i = 0;
379 $othernb = 0;
380
381 if ($num) {
382 // Open project per thirdparty
383 print '<div class="div-table-responsive-no-min">';
384 print '<table class="noborder centpercent">';
385 print '<tr class="liste_titre">';
386 print_liste_field_titre("OpenedProjectsByThirdparties", $_SERVER["PHP_SELF"], "", "", "", '', $sortfield, $sortorder);
387 print_liste_field_titre("Number", $_SERVER["PHP_SELF"], "nb", "", "", '', $sortfield, $sortorder, 'right ');
388 print "</tr>\n";
389 }
390
391 while ($i < $num) {
392 $obj = $db->fetch_object($resql);
393
394 if ($i >= $max) {
395 $othernb += $obj->nb;
396 $i++;
397 continue;
398 }
399
400 print '<tr class="oddeven">';
401 print '<td class="nowraponall tdoverflowmax100">';
402 if ($obj->socid > 0) {
403 $companystatic->id = $obj->socid;
404 $companystatic->name = $obj->name;
405 $companystatic->name_alias = $obj->name_alias;
406 $companystatic->code_client = $obj->code_client;
407 $companystatic->code_compta = $obj->code_compta;
408 $companystatic->code_compta_client = $obj->code_compta;
409 $companystatic->client = $obj->client;
410 $companystatic->code_fournisseur = $obj->code_fournisseur;
411 $companystatic->code_compta_fournisseur = $obj->code_compta_fournisseur;
412 $companystatic->fournisseur = $obj->fournisseur;
413 $companystatic->logo = $obj->logo;
414 $companystatic->email = $obj->email;
415 $companystatic->entity = $obj->entity;
416 $companystatic->canvas = $obj->canvas;
417 $companystatic->status = $obj->status;
418
419 print $companystatic->getNomUrl(1);
420 } else {
421 print $langs->trans("OthersNotLinkedToThirdParty");
422 }
423 print '</td>';
424 print '<td class="right">';
425 if ($obj->socid) {
426 print '<a href="'.DOL_URL_ROOT.'/projet/list.php?socid='.$obj->socid.'&search_status=1">'.$obj->nb.'</a>';
427 } else {
428 print '<a href="'.DOL_URL_ROOT.'/projet/list.php?search_societe='.urlencode('^$').'&search_status=1">'.$obj->nb.'</a>';
429 }
430 print '</td>';
431 print "</tr>\n";
432
433 $i++;
434 }
435 if ($othernb) {
436 print '<tr class="oddeven">';
437 print '<td class="nowrap">';
438 print '<span class="opacitymedium">'.$langs->trans("More").'...</span>';
439 print '</td>';
440 print '<td class="nowrap right">';
441 print $othernb;
442 print '</td>';
443 print "</tr>\n";
444 }
445
446 if ($num) {
447 print "</table>";
448 print '</div>';
449 }
450
451 $db->free($resql);
452} else {
454}
455
456if ((!getDolGlobalInt('PROJECT_USE_OPPORTUNITIES') || getDolGlobalInt('PROJECT_SHOW_OPEN_PROJECTS_LIST_ON_PROJECT_AREA')) && !getDolGlobalInt('PROJECT_HIDE_OPEN_PROJECTS_LIST_ON_PROJECT_AREA')) {
457 // This list is surely very long and useless when we are using opportunities, so we hide it for this use case, but we allow to show it if
458 // we really want it and to allow interface backward compatibility.
459 print '<br>';
460
461 print_projecttasks_array($db, $form, $socid, $projectsListId, 0, 1, $listofoppstatus, array());
462}
463
464print '</div></div></div>';
465
466$parameters = array('user' => $user);
467$reshook = $hookmanager->executeHooks('dashboardProjects', $parameters, $projectstatic); // Note that $action and $object may have been modified by hook
468
469// End of page
470llxFooter();
471$db->close();
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:476
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 offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
dol_set_user_param($db, $conf, &$user, $tab, $entity=-1)
Save personal parameter.
finishSimpleTable($addLineBreak=false)
Add the correct HTML close tags for "startSimpleTable(...)" (use after the last table line)
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
print_liste_field_titre($name, $file="", $field="", $begin="", $param="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $selectlimitsuffix=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
dolPrintHTML($s, $allowiframe=0, $moreallowedtags=array())
Return a string (that can be on several lines) ready to be output on a HTML page.
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
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.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
startSimpleTable($header, $link="", $arguments="", $emptyColumns=0, $number=-1, $pictofulllist='')
Start a table with headers and a optional clickable number (don't forget to use "finishSimpleTable()"...
print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=0, $status=-1, $listofoppstatus=array(), $hiddenfields=array(), $max=0)
Return HTML table with list of projects and number of opened tasks.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.