1 | <?php |
||
2 | |||
3 | /* Copyright (C) 2005 Matthieu Valleton <[email protected]> |
||
4 | * Copyright (C) 2005 Eric Seigne <[email protected]> |
||
5 | * Copyright (C) 2006-2015 Laurent Destailleur <[email protected]> |
||
6 | * Copyright (C) 2007 Patrick Raguin <[email protected]> |
||
7 | * Copyright (C) 2005-2012 Regis Houssin <[email protected]> |
||
8 | * Copyright (C) 2019-2024 Frédéric France <[email protected]> |
||
9 | * Copyright (C) 2024 Rafael San José <[email protected]> |
||
10 | * |
||
11 | * This program is free software; you can redistribute it and/or modify |
||
12 | * it under the terms of the GNU General Public License as published by |
||
13 | * the Free Software Foundation; either version 3 of the License, or |
||
14 | * (at your option) any later version. |
||
15 | * |
||
16 | * This program is distributed in the hope that it will be useful, |
||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
19 | * GNU General Public License for more details. |
||
20 | * |
||
21 | * You should have received a copy of the GNU General Public License |
||
22 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
||
23 | */ |
||
24 | |||
25 | use Dolibarr\Code\Core\Classes\Form; |
||
26 | use Dolibarr\Code\User\Classes\User; |
||
27 | use Dolibarr\Lib\ViewMain; |
||
28 | |||
29 | /** |
||
30 | * \file htdocs/user/hierarchy.php |
||
31 | * \ingroup user |
||
32 | * \brief Page of hierarchy view of user module |
||
33 | */ |
||
34 | |||
35 | // Load Dolibarr environment |
||
36 | require constant('DOL_DOCUMENT_ROOT') . '/main.inc.php'; |
||
37 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/treeview.lib.php'; |
||
38 | |||
39 | // Load translation files required by page |
||
40 | $langs->loadLangs(array('users', 'companies', 'hrm', 'salaries')); |
||
41 | |||
42 | // Security check (for external users) |
||
43 | $socid = 0; |
||
44 | if ($user->socid > 0) { |
||
45 | $socid = $user->socid; |
||
46 | } |
||
47 | |||
48 | $optioncss = GETPOST('optioncss', 'alpha'); |
||
49 | $contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'userlist'; // To manage different context of search |
||
50 | $mode = GETPOST("mode", 'alpha'); |
||
51 | if (empty($mode)) { |
||
52 | $mode = 'hierarchy'; |
||
53 | } |
||
54 | |||
55 | $sortfield = GETPOST('sortfield', 'aZ09comma'); |
||
56 | $sortorder = GETPOST('sortorder', 'aZ09comma'); |
||
57 | $page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page"); |
||
58 | |||
59 | |||
60 | $search_status = GETPOST('search_status', 'intcomma'); |
||
61 | if ($search_status == '') { |
||
62 | $search_status = '1'; |
||
63 | } |
||
64 | |||
65 | if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // Both test are required to be compatible with all browsers |
||
66 | $search_status = ""; |
||
67 | } |
||
68 | |||
69 | $search_employee = -1; |
||
70 | if ($contextpage == 'employeelist') { |
||
71 | $search_employee = 1; |
||
72 | } |
||
73 | |||
74 | $userstatic = new User($db); |
||
75 | |||
76 | // Define value to know what current user can do on users |
||
77 | $canadduser = (!empty($user->admin) || $user->hasRight("user", "user", "write")); |
||
78 | |||
79 | // Permission to list |
||
80 | if (isModEnabled('salaries') && $contextpage == 'employeelist' && $search_employee == 1) { |
||
81 | if (!$user->hasRight("salaries", "read")) { |
||
82 | accessforbidden(); |
||
83 | } |
||
84 | } else { |
||
85 | if (!$user->hasRight("user", "user", "read") && empty($user->admin)) { |
||
86 | accessforbidden(); |
||
87 | } |
||
88 | } |
||
89 | |||
90 | $childids = $user->getAllChildIds(1); |
||
91 | |||
92 | /* |
||
93 | * View |
||
94 | */ |
||
95 | |||
96 | $form = new Form($db); |
||
97 | |||
98 | $help_url = 'EN:Module_Users|FR:Module_Utilisateurs|ES:Módulo_Usuarios|DE:Modul_Benutzer'; |
||
99 | if ($contextpage == 'employeelist' && $search_employee == 1) { |
||
100 | $title = $langs->trans("Employees"); |
||
101 | } else { |
||
102 | $title = $langs->trans("Users"); |
||
103 | } |
||
104 | $arrayofjs = array( |
||
105 | '/includes/jquery/plugins/jquerytreeview/jquery.treeview.js', |
||
106 | '/includes/jquery/plugins/jquerytreeview/lib/jquery.cookie.js', |
||
107 | ); |
||
108 | $arrayofcss = array('/includes/jquery/plugins/jquerytreeview/jquery.treeview.css'); |
||
109 | |||
110 | ViewMain::llxHeader('', $title, $help_url, '', 0, 0, $arrayofjs, $arrayofcss, '', 'bodyforlist mod-user page-hierarchy'); |
||
111 | |||
112 | $filters = []; |
||
113 | if (($search_status != '' && $search_status >= 0)) { |
||
114 | $filters[] = "statut = " . ((int)$search_status); |
||
115 | } |
||
116 | if (($search_employee != '' && $search_employee >= 0)) { |
||
117 | $filters[] = "employee = " . ((int)$search_employee); |
||
118 | } |
||
119 | $sqlfilter = ''; |
||
120 | if (!empty($filters)) { |
||
121 | $sqlfilter = implode(' AND ', $filters); |
||
122 | } |
||
123 | // Load hierarchy of users |
||
124 | $user_arbo_all = $userstatic->get_full_tree(0, ''); |
||
125 | if ($sqlfilter) { |
||
126 | $user_arbo = $userstatic->get_full_tree(0, $sqlfilter); |
||
127 | } else { |
||
128 | $user_arbo = $user_arbo_all; |
||
129 | } |
||
130 | |||
131 | // Count total nb of records |
||
132 | $nbtotalofrecords = count($user_arbo); |
||
133 | |||
134 | |||
135 | if (!is_array($user_arbo) && $user_arbo < 0) { |
||
136 | setEventMessages($userstatic->error, $userstatic->errors, 'warnings'); |
||
137 | } else { |
||
138 | // Define fulltree array |
||
139 | $fulltree = $user_arbo; |
||
140 | //var_dump($fulltree); |
||
141 | // Define data (format for treeview) |
||
142 | $data = array(); |
||
143 | $data[0] = array('rowid' => 0, 'fk_menu' => -1, 'title' => "racine", 'mainmenu' => '', 'leftmenu' => '', 'fk_mainmenu' => '', 'fk_leftmenu' => ''); |
||
144 | |||
145 | foreach ($fulltree as $key => $val) { |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
146 | $userstatic->id = $val['id']; |
||
147 | $userstatic->ref = (string)$val['id']; |
||
148 | $userstatic->login = $val['login']; |
||
149 | $userstatic->firstname = $val['firstname']; |
||
150 | $userstatic->lastname = $val['lastname']; |
||
151 | $userstatic->status = $val['statut']; |
||
152 | $userstatic->email = $val['email']; |
||
153 | $userstatic->gender = $val['gender']; |
||
154 | $userstatic->socid = $val['fk_soc']; |
||
155 | $userstatic->admin = $val['admin']; |
||
156 | $userstatic->entity = $val['entity']; |
||
157 | $userstatic->photo = $val['photo']; |
||
158 | |||
159 | $entity = $val['entity']; |
||
160 | $entitystring = ''; |
||
161 | |||
162 | // TODO Set of entitystring should be done with a hook |
||
163 | if (isModEnabled('multicompany') && is_object($mc)) { |
||
164 | if (empty($entity)) { |
||
165 | $entitystring = $langs->trans("AllEntities"); |
||
166 | } else { |
||
167 | $mc->getInfo($entity); |
||
168 | $entitystring = $mc->label; |
||
169 | } |
||
170 | } |
||
171 | |||
172 | $li = $userstatic->getNomUrl(-1, '', 0, 1); |
||
173 | if (isModEnabled('multicompany') && $userstatic->admin && !$userstatic->entity) { |
||
174 | $li .= img_picto($langs->trans("SuperAdministratorDesc"), 'redstar', 'class="valignmiddle paddingright paddingleft"'); |
||
175 | } elseif ($userstatic->admin) { |
||
176 | $li .= img_picto($langs->trans("AdministratorDesc"), 'star', 'class="valignmiddle paddingright paddingleft"'); |
||
177 | } |
||
178 | $li .= ' <span class="opacitymedium">(' . $val['login'] . ($entitystring ? ' - ' . $entitystring : '') . ')</span>'; |
||
179 | |||
180 | $entry = '<table class="nobordernopadding centpercent"><tr class="trtree"><td class="' . ($val['statut'] ? 'usertdenabled' : 'usertddisabled') . '">' . $li . '</td><td align="right" class="' . ($val['statut'] ? 'usertdenabled' : 'usertddisabled') . '">' . $userstatic->getLibStatut(2) . '</td></tr></table>'; |
||
181 | |||
182 | $data[$val['rowid']] = array( |
||
183 | 'rowid' => $val['rowid'], |
||
184 | 'fk_menu' => $val['fk_user'], // TODO Replace fk_menu with fk_parent |
||
185 | 'statut' => $val['statut'], |
||
186 | 'entry' => $entry |
||
187 | ); |
||
188 | } |
||
189 | |||
190 | // Loop on $data to link user linked to a parent that was excluded by the filter |
||
191 | foreach ($data as $key => $tmpdata) { |
||
192 | $idparent = $tmpdata['fk_menu']; |
||
193 | // Loop to check if parent exists |
||
194 | if ($idparent > 0) { |
||
195 | $parentfound = array_key_exists($idparent, $data) ? 1 : 0; |
||
196 | |||
197 | $i = 0; |
||
198 | while (!$parentfound && $i < 50) { |
||
199 | // Parent was not found but we need it to show the child, so we reintroduce the parent |
||
200 | if (!empty($user_arbo_all[$idparent])) { |
||
201 | $val = $user_arbo_all[$idparent]; |
||
202 | $userstatic->id = $val['id']; |
||
203 | $userstatic->ref = (string)$val['id']; |
||
204 | $userstatic->login = $val['login']; |
||
205 | $userstatic->firstname = $val['firstname']; |
||
206 | $userstatic->lastname = $val['lastname']; |
||
207 | $userstatic->status = $val['statut']; |
||
208 | $userstatic->email = $val['email']; |
||
209 | $userstatic->gender = $val['gender']; |
||
210 | $userstatic->socid = $val['fk_soc']; |
||
211 | $userstatic->admin = $val['admin']; |
||
212 | $userstatic->entity = $val['entity']; |
||
213 | $userstatic->photo = $val['photo']; |
||
214 | |||
215 | $entity = $val['entity']; |
||
216 | $entitystring = ''; |
||
217 | |||
218 | // TODO Set of entitystring should be done with a hook |
||
219 | if (isModEnabled('multicompany') && is_object($mc)) { |
||
220 | if (empty($entity)) { |
||
221 | $entitystring = $langs->trans("AllEntities"); |
||
222 | } else { |
||
223 | $mc->getInfo($entity); |
||
224 | $entitystring = $mc->label; |
||
225 | } |
||
226 | } |
||
227 | |||
228 | $li = '<span class="opacitymedium">'; |
||
229 | $li .= $userstatic->getNomUrl(-1, '', 0, 1); |
||
230 | if (isModEnabled('multicompany') && $userstatic->admin && !$userstatic->entity) { |
||
231 | $li .= img_picto($langs->trans("SuperAdministrator"), 'redstar'); |
||
232 | } elseif ($userstatic->admin) { |
||
233 | $li .= img_picto($langs->trans("Administrator"), 'star'); |
||
234 | } |
||
235 | $li .= ' <span class="opacitymedium">(' . $val['login'] . ($entitystring ? ' - ' . $entitystring : '') . ')</span>'; |
||
236 | $li .= ' - <span class="opacitymedium">' . $langs->trans("ExcludedByFilter") . '</span>'; |
||
237 | $li .= '</span>'; |
||
238 | |||
239 | $entry = '<table class="nobordernopadding centpercent"><tr class="trtree"><td class="' . ($val['statut'] ? 'usertdenabled' : 'usertddisabled') . '">' . $li . '</td><td align="right" class="' . ($val['statut'] ? 'usertdenabled' : 'usertddisabled') . '">' . $userstatic->getLibStatut(2) . '</td></tr></table>'; |
||
240 | |||
241 | $data[$idparent] = array( |
||
242 | 'rowid' => $idparent, |
||
243 | 'fk_menu' => $user_arbo_all[$idparent]['fk_user'], |
||
244 | 'statut' => $user_arbo_all[$idparent]['statut'], |
||
245 | 'entry' => $entry |
||
246 | ); |
||
247 | $idparent = $user_arbo_all[$idparent]['fk_user']; |
||
248 | if ($idparent > 0) { |
||
249 | $parentfound = array_key_exists($idparent, $data) ? 1 : 0; |
||
250 | } else { |
||
251 | $parentfound = 1; |
||
252 | } |
||
253 | //var_dump($data[$idparent]); |
||
254 | } else { |
||
255 | // We should not be here. If a record has a parent id, parent id should be into $user_arbo_all |
||
256 | $data[$key]['fk_menu'] = -2; |
||
257 | if (empty($data[-2])) { |
||
258 | $li = '<span class="opacitymedium">' . $langs->trans("WarningParentIDDoesNotExistAnymore") . '</span>'; |
||
259 | $entry = '<table class="nobordernopadding centpercent"><tr class="trtree"><td class="usertddisabled">' . $li . '</td><td align="right" class="usertddisabled"></td></tr></table>'; |
||
260 | $data[-2] = array( |
||
261 | 'rowid' => '-2', |
||
262 | 'fk_menu' => null, |
||
263 | 'statut' => '1', |
||
264 | 'entry' => $entry |
||
265 | ); |
||
266 | } |
||
267 | $parentfound = 1; |
||
268 | } |
||
269 | |||
270 | $i++; |
||
271 | } |
||
272 | } |
||
273 | } |
||
274 | //var_dump($data);exit; |
||
275 | |||
276 | $param = "&search_status=" . urlencode($search_status); |
||
277 | $param = "&contextpage=" . urlencode($contextpage); |
||
278 | |||
279 | $newcardbutton = ''; |
||
280 | $newcardbutton .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars paddingleft imgforviewmode', constant('BASE_URL') . '/user/list.php?mode=common' . preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ((empty($mode) || $mode == 'common') ? 2 : 1), array('morecss' => 'reposition')); |
||
281 | $newcardbutton .= dolGetButtonTitle($langs->trans('HierarchicView'), '', 'fa fa-stream paddingleft imgforviewmode', constant('BASE_URL') . '/user/hierarchy.php?mode=hierarchy' . preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', (($mode == 'hierarchy') ? 2 : 1), array('morecss' => 'reposition')); |
||
282 | $newcardbutton .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', constant('BASE_URL') . '/user/list.php?mode=kanban' . preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ($mode == 'kanban' ? 2 : 1), array('morecss' => 'reposition')); |
||
283 | $newcardbutton .= dolGetButtonTitleSeparator(); |
||
284 | $newcardbutton .= dolGetButtonTitle($langs->trans('NewUser'), '', 'fa fa-plus-circle', constant('BASE_URL') . '/user/card.php?action=create' . ($mode == 'employee' ? '&employee=1' : '') . '&leftmenu=', '', $canadduser); |
||
285 | |||
286 | $massactionbutton = ''; |
||
287 | $num = 0; |
||
288 | $limit = 0; |
||
289 | |||
290 | print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'user', 0, $newcardbutton, '', $limit, 0, 0, 1); |
||
291 | |||
292 | print '<form method="POST" id="searchFormList" action="' . $_SERVER["PHP_SELF"] . '">' . "\n"; |
||
293 | if ($optioncss != '') { |
||
294 | print '<input type="hidden" name="optioncss" value="' . $optioncss . '">'; |
||
295 | } |
||
296 | print '<input type="hidden" name="token" value="' . newToken() . '">'; |
||
297 | print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">'; |
||
298 | print '<input type="hidden" name="sortfield" value="' . $sortfield . '">'; |
||
299 | print '<input type="hidden" name="sortorder" value="' . $sortorder . '">'; |
||
300 | print '<input type="hidden" name="page" value="' . $page . '">'; |
||
301 | print '<input type="hidden" name="contextpage" value="' . $contextpage . '">'; |
||
302 | print '<input type="hidden" name="mode" value="' . $mode . '">'; |
||
303 | |||
304 | print '<div class="div-table-responsive">'; // You can use div-table-responsive-no-min if you don't need reserved height for your table |
||
305 | print '<table class="liste nohover centpercent">'; |
||
306 | |||
307 | print '<tr class="liste_titre_filter">'; |
||
308 | // Action column |
||
309 | if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { |
||
310 | print '<td class="liste_titre maxwidthsearch">'; |
||
311 | $searchpicto = $form->showFilterAndCheckAddButtons(0); |
||
312 | print $searchpicto; |
||
313 | print '</td>'; |
||
314 | } |
||
315 | print '<td class="liste_titre"> </td>'; |
||
316 | print '<td class="liste_titre"> </td>'; |
||
317 | // Status |
||
318 | print '<td class="liste_titre right parentonrightofpage">'; |
||
319 | print $form->selectarray('search_status', array('-1' => '', '0' => $langs->trans('Disabled'), '1' => $langs->trans('Enabled')), $search_status, 0, 0, 0, '', 0, 0, 0, '', 'minwidth75imp onrightofpage width100'); |
||
320 | print '</td>'; |
||
321 | // Action column |
||
322 | if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { |
||
323 | print '<td class="liste_titre maxwidthsearch">'; |
||
324 | $searchpicto = $form->showFilterAndCheckAddButtons(0); |
||
325 | print $searchpicto; |
||
326 | print '</td>'; |
||
327 | } |
||
328 | print '</tr>'; |
||
329 | |||
330 | print '<tr class="liste_titre">'; |
||
331 | // Action column |
||
332 | if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { |
||
333 | print_liste_field_titre('', $_SERVER["PHP_SELF"], "", '', '', '', '', '', 'maxwidthsearch '); |
||
334 | } |
||
335 | print_liste_field_titre("HierarchicView"); |
||
336 | print_liste_field_titre('<div id="iddivjstreecontrol"><a href="#">' . img_picto('', 'folder', 'class="paddingright"') . '<span class="hideonsmartphone">' . $langs->trans("UndoExpandAll") . '</span></a> | <a href="#">' . img_picto('', 'folder-open', 'class="paddingright"') . '<span class="hideonsmartphone">' . $langs->trans("ExpandAll") . '</span></a></div>', $_SERVER['PHP_SELF'], "", '', "", 'align="center"'); |
||
337 | print_liste_field_titre("Status", $_SERVER['PHP_SELF'], "", '', "", '', '', '', 'right onrightofpage'); |
||
338 | // Action column |
||
339 | if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { |
||
340 | print_liste_field_titre('', $_SERVER["PHP_SELF"], "", '', '', '', '', '', 'maxwidthsearch '); |
||
341 | } |
||
342 | print '</tr>'; |
||
343 | |||
344 | |||
345 | $nbofentries = (count($data) - 1); |
||
346 | |||
347 | if ($nbofentries > 0) { |
||
348 | print '<tr>'; |
||
349 | // Action column |
||
350 | if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { |
||
351 | print '<td></td>'; |
||
352 | } |
||
353 | print '<td colspan="3">'; |
||
354 | tree_recur($data, $data[0], 0); |
||
355 | print '</td>'; |
||
356 | // Action column |
||
357 | if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { |
||
358 | print '<td></td>'; |
||
359 | } |
||
360 | print '</tr>'; |
||
361 | } else { |
||
362 | print '<tr class="oddeven">'; |
||
363 | print '<td colspan="3">'; |
||
364 | print '<table class="nobordernopadding"><tr class="nobordernopadding"><td>' . img_picto_common('', 'treemenu/branchbottom.gif') . '</td>'; |
||
365 | print '<td valign="middle">'; |
||
366 | print $langs->trans("NoCategoryYet"); |
||
367 | print '</td>'; |
||
368 | print '<td> </td>'; |
||
369 | print '</table>'; |
||
370 | print '</td>'; |
||
371 | print '<td></td>'; |
||
372 | print '</tr>'; |
||
373 | } |
||
374 | |||
375 | print "</table>"; |
||
376 | print '</div>'; |
||
377 | |||
378 | print "</form>\n"; |
||
379 | } |
||
380 | |||
381 | // |
||
382 | /*print '<script type="text/javascript"> |
||
383 | jQuery(document).ready(function() { |
||
384 | function init_myfunc() |
||
385 | { |
||
386 | jQuery(".usertddisabled").hide(); |
||
387 | } |
||
388 | init_myfunc(); |
||
389 | }); |
||
390 | </script>'; |
||
391 | */ |
||
392 | |||
393 | // End of page |
||
394 | ViewMain::llxFooter(); |
||
395 | $db->close(); |
||
396 |