dolibarr 19.0.3
compare.php
1<?php
2/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2021 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
4 * Copyright (C) 2021 Greg Rastklan <greg.rastklan@atm-consulting.fr>
5 * Copyright (C) 2021 Jean-Pascal BOUDET <jean-pascal.boudet@atm-consulting.fr>
6 * Copyright (C) 2021 Grégory BLEMAND <gregory.blemand@atm-consulting.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 * \file htdocs/hrm/compare.php
22 * \ingroup hrm
23 * \brief This file compares skills of user groups
24 *
25 * Displays a table in three parts.
26 * 1- the left part displays the list of users of the selected group 1.
27 *
28 * 2- the central part displays the skills. display of the maximum score for this group and the number of occurrences.
29 *
30 * 3- the right part displays the members of group 2 or the job to be compared
31 */
32
33
34// Load Dolibarr environment
35require_once '../main.inc.php';
36require_once DOL_DOCUMENT_ROOT . '/core/lib/functions.lib.php';
37require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php';
38require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php';
39require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php';
40require_once DOL_DOCUMENT_ROOT . '/hrm/class/evaluation.class.php';
41require_once DOL_DOCUMENT_ROOT . '/hrm/class/position.class.php';
42require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm.lib.php';
43
44
45// Load translation files required by the page
46$langs->load('hrm');
47
48$job = new Job($db);
49
50// Permissions
51$permissiontoread = $user->rights->hrm->evaluation->read || $user->rights->hrm->compare_advance->read;
52$permissiontoadd = 0;
53
54if (empty($conf->hrm->enabled)) {
56}
57if (!$permissiontoread || ($action === 'create' && !$permissiontoadd)) {
59}
60
61
62/*
63 * View
64 */
65
66$css = array('/hrm/css/style.css');
67
68llxHeader('', $langs->trans('SkillComparison'), '', '', 0, 0, '', $css);
69
70$head = array();
71
72$h = 0;
73$head[$h][0] = $_SERVER["PHP_SELF"];
74$head[$h][1] = $langs->trans("SkillComparison");
75$head[$h][2] = 'compare';
76
77print dol_get_fiche_head($head, 'compare', '', 1);
78
79?>
80 <script type="text/javascript">
81
82 $(document).ready(function () {
83
84 $("li[fk_user]").click(function () {
85
86 if ($(this).hasClass('disabled')) {
87 $(this).removeClass('disabled');
88 } else {
89 $(this).addClass('disabled');
90 }
91
92
93 var $userl = $(this).closest('ul');
94 var listname = $userl.attr('name');
95
96 var TId = [];
97
98 $userl.find('li').each(function (i, item) {
99
100 if ($(item).hasClass('disabled')) {
101 TId.push($(item).attr('fk_user'));
102 }
103
104 });
105
106 $('#' + listname + '_excluded_id').val(TId.join(','));
107
108 });
109
110 });
111
112
113 </script>
114
115
116<?php
117
118$fk_usergroup2 = 0;
119$fk_job = (int) GETPOST('fk_job');
120if ($fk_job <= 0) {
121 $fk_usergroup2 = GETPOST('fk_usergroup2');
122}
123
124$fk_usergroup1 = GETPOST('fk_usergroup1');
125
126?>
127
128
129 <div class="fichecenter">
130 <form action="<?php echo $_SERVER['PHP_SELF'] ?>">
131
132 <div class="tabBar tabBarWithBottom">
133 <div class="fichehalfleft">
134 <table class="border tableforfield" width="100%">
135 <tr>
136 <td><?php
137 print $langs->trans('group1ToCompare').'</td><td>';
138 print img_picto('', 'group', 'class="pictofixedwidth"');
139 print $form->select_dolgroups($fk_usergroup1, 'fk_usergroup1', 1);
140 ?></td>
141 </tr>
142 <tr><td>&nbsp;</td></tr>
143 <tr>
144 <td><?php
145 print $langs->trans('group2ToCompare').'</td><td>';
146 print img_picto('', 'group', 'class="pictofixedwidth"');
147 print $form->select_dolgroups($fk_usergroup2, 'fk_usergroup2', 1);
148 ?></td>
149 </tr>
150 <tr>
151 <td><STRONG><?php print $langs->trans('or'); ?></STRONG></td>
152 </tr>
153 <tr>
154 <td><?php
155 echo $langs->trans('OrJobToCompare') . '</td><td>';
156 $j = new Job($db);
157 $jobs = $j->fetchAll();
158 $TJobs = array();
159
160 foreach ($jobs as &$j) {
161 $TJobs[$j->id] = $j->label;
162 }
163
164 print img_picto('', 'jobprofile', 'class="pictofixedwidth"').$form->selectarray('fk_job', $TJobs, $fk_job, 1);
165 ?></td>
166 </tr>
167 </table>
168 </div>
169
170 <div style="background:#eee;border-radius:5px 0;margin:0px 0 10px;font-style:italic;padding:5px;" class="fichehalfright">
171 <!--<h4><?php echo $langs->trans('legend'); ?></h4>-->
172 <table class="border" width="100%">
173 <tr>
174 <td><span style="vertical-align:middle" class="toohappy diffnote little"></span>
175 <?php echo $langs->trans('CompetenceAcquiredByOneOrMore'); ?></td>
176 </tr>
177 <tr>
178 <td><span style="vertical-align:middle" class="veryhappy diffnote little"></span>
179 <?php echo $langs->trans('MaxlevelGreaterThan'); ?></td>
180 </tr>
181 <tr>
182 <td><span style="vertical-align:middle" class="happy diffnote little"></span>
183 <?php echo $langs->trans('MaxLevelEqualTo'); ?></td>
184 </tr>
185 <tr>
186 <td><span style="vertical-align:middle" class="sad diffnote little"></span>
187 <?php echo $langs->trans('MaxLevelLowerThan'); ?></td>
188 </tr>
189 <tr>
190 <td><span style="vertical-align:middle" class="toosad diffnote little"></span>
191 <?php echo $langs->trans('SkillNotAcquired'); ?></td>
192 </tr>
193 </table>
194
195 </div>
196
197 <div class="clearboth"></div>
198
199 </div>
200
201 <br><br>
202 <div class="center">
203 <input class="button" type="SUBMIT" name="bt1" VALUE="<?php print $langs->trans('Refresh'); ?>">
204 </div>
205 <br><br>
206
207 <div id="compare" width="100%" style="position:relative;">
208
209 <?php if ($fk_usergroup1 > 0 || $fk_usergroup2 > 0 || $fk_job > 0) { ?>
210 <table width="100%">
211 <tr>
212 <th></th>
213 <th><?php print $langs->trans('skill'); ?></th>
214 <th><?php print $langs->trans('rank'); ?></th>
215 <th><?php print $langs->trans('difference'); ?></th>
216 <th><?php print $langs->trans('rank'); ?></th>
217 <th></th>
218 </tr>
219
220 <?php
221 echo '<tr><td id="list-user-left" style="width:30%" valign="top">';
222
223 $TUser1 = $TUser2 = array();
224
225 $userlist1 = displayUsersListWithPicto($TUser1, $fk_usergroup1, 'list1');
226
227
228 $skill = new Skill($db);
229 $TSkill1 = getSkillForUsers($TUser1);
230
231 if ($fk_job > 0) {
232 $TSkill2 = getSkillForJob($fk_job);
233
234 $job = new Job($db);
235 $job->fetch($fk_job);
236 $userlist2 = '<ul>
237 <li>
238 <h3>' . $job->label . '</h3>
239 <p>' . $job->description . '</p>
240 </li>
241 </ul>';
242 } else {
243 $userlist2 = displayUsersListWithPicto($TUser2, $fk_usergroup2, 'list2');
244 $TSkill2 = getSkillForUsers($TUser2);
245 }
246
247 $TMergedSkills = mergeSkills($TSkill1, $TSkill2);
248
249 echo $userlist1;
250
251 echo '</td>';
252
253 echo '<td id="" style="width:20%" valign="top">' . skillList($TMergedSkills) . '</td>';
254 echo '<td id="" style="width:5%" valign="top">' . rate($TMergedSkills, 'rate1') . '</td>';
255 echo '<td id="" style="width:10%" valign="top">' . diff($TMergedSkills) . '</td>';
256 echo '<td id="" style="width:5%" valign="top">' . rate($TMergedSkills, 'rate2') . '</td>';
257
258 echo '<td id="list-user-right" style="width:30%" valign="top">';
259
260 echo $userlist2;
261
262 echo '</td></tr>';
263
264 ?>
265
266 </table>
267
268 <?php } ?>
269
270 </div>
271
272 </form>
273
274 </div>
275
276<?php
277
278print dol_get_fiche_end();
279
280llxFooter();
281
282
283
291function diff(&$TMergedSkills)
292{
293 $out = '<ul class="diff">';
294
295 foreach ($TMergedSkills as $id => &$sk) {
296 $class = 'diffnote';
297
298 if (empty($sk->rate2)) {
299 $class .= ' toohappy';
300 } elseif (empty($sk->rate1)) {
301 $class .= ' toosad';
302 } elseif ($sk->rate1 == $sk->rate2) {
303 $class .= ' happy';
304 } elseif ($sk->rate2 < $sk->rate1) {
305 $class .= ' veryhappy';
306 } elseif ($sk->rate2 > $sk->rate1) {
307 $class .= ' sad';
308 }
309
310 $out .= '<li fk_skill="' . $id . '" class="' . $class . '" style="text-align:center;">
311 <span class="' . $class . '">&nbsp;</span>
312 </li>';
313 }
314
315 $out .= '</ul>';
316
317 return $out;
318}
319
326function rate(&$TMergedSkills, $field)
327{
328 global $langs, $fk_job;
329
330 $out = '<ul class="competence">';
331
332 foreach ($TMergedSkills as $id => &$sk) {
333 $class = "note";
334 $how_many = 0;
335 if (empty($sk->$field)) {
336 $note = 'x';
337 $class .= ' none';
338 } else {
339 $note = $sk->$field;
340 $how_many = ($field === 'rate1') ? $sk->how_many_max1 : $sk->how_many_max2;
341 }
342
343 if ($field === 'rate2' && $fk_job > 0) {
344 $trad = $langs->trans('RequiredRank');
345 } else {
346 $trad = $langs->trans('HighestRank');
347 }
348
349 $out .= '<li fk_skill="' . $id . '" style="text-align:center;">
350 <p><span class="' . $class . ' classfortooltip" title="' . $trad . '">' . $note . '</span>' . ($how_many > 0 ? '<span class="bubble classfortooltip" title="' . $langs->trans('HowManyUserWithThisMaxNote') . '">' . $how_many . '</span>' : '') . '</p>
351 </li>';
352 }
353
354 $out .= '</ul>';
355
356 return $out;
357}
358
365function skillList(&$TMergedSkills)
366{
367 $out = '<ul class="competence">';
368
369 foreach ($TMergedSkills as $id => &$sk) {
370 $out .= '<li fk_skill="' . $id . '">
371 <h3>' . $sk->label . '</h3>
372 <p>' . $sk->description . '</p>
373 </li>';
374 }
375
376 $out .= '</ul>';
377
378 return $out;
379}
380
388function mergeSkills($TSkill1, $TSkill2)
389{
390 $Tab = array();
391
392 foreach ($TSkill1 as &$sk) {
393 if (empty($Tab[$sk->fk_skill])) {
394 $Tab[$sk->fk_skill] = new stdClass();
395 }
396
397 $Tab[$sk->fk_skill]->rate1 = $sk->rankorder;
398 $Tab[$sk->fk_skill]->how_many_max1 = $sk->how_many_max;
399 $Tab[$sk->fk_skill]->label = $sk->label;
400 $Tab[$sk->fk_skill]->description = $sk->description;
401 }
402
403 foreach ($TSkill2 as &$sk) {
404 if (empty($Tab[$sk->fk_skill])) {
405 $Tab[$sk->fk_skill] = new stdClass();
406 }
407 $Tab[$sk->fk_skill]->rate2 = $sk->rankorder;
408 $Tab[$sk->fk_skill]->label = $sk->label;
409 $Tab[$sk->fk_skill]->description = $sk->description;
410 $Tab[$sk->fk_skill]->how_many_max2 = $sk->how_many_max;
411 }
412
413 return $Tab;
414}
415
424function displayUsersListWithPicto(&$TUser, $fk_usergroup = 0, $namelist = 'list-user')
425{
426 global $db, $langs, $conf, $form;
427
428 $out = '';
429 if ($fk_usergroup > 0) {
430 $list = $namelist . '_excluded_id';
431
432 $excludedIdsList = GETPOST($list);
433
434 $sql = "SELECT u.rowid FROM " . MAIN_DB_PREFIX . "user u
435 LEFT JOIN " . MAIN_DB_PREFIX . "usergroup_user as ugu ON (u.rowid = ugu.fk_user)
436 WHERE u.statut > 0 AND ugu.entity = ".((int) $conf->entity);
437 $sql .= " AND ugu.fk_usergroup=" . ((int) $fk_usergroup);
438
439 $res = $db->query($sql);
440 $out .= '<ul name="' . $namelist . '">';
441
442 $TExcludedId = explode(',', $excludedIdsList);
443
444 $out .= '<input id="'.$list.'" type="hidden" name="'.$list.'" value="'.$excludedIdsList.'"> ';
445
446 $job = new Job($db);
447
448 while ($obj = $db->fetch_object($res)) {
449 $class = '';
450
451 $user = new User($db);
452 $user->fetch($obj->rowid);
453
454 $name = $user->getFullName($langs);
455 if (empty($name)) {
456 $name = $user->login;
457 }
458
459 if (in_array($user->id, $TExcludedId)) {
460 $class .= ' disabled';
461 } else {
462 if (!in_array($user->id, $TUser)) {
463 $TUser[] = $user->id;
464 }
465 }
466
467 $desc = '';
468
469 $jobstring = $job->getLastJobForUser($user->id);
470 $desc .= $jobstring;
471
472 $static_eval = new Evaluation($db);
473 $evaluation = $static_eval->getLastEvaluationForUser($user->id);
474
475 if (!empty($evaluation) && !empty($evaluation->date_eval)) {
476 $desc .= $langs->trans('DateLastEval') . ' : ' . dol_print_date($evaluation->date_eval);
477 } else {
478 $desc .= $langs->trans('NoEval');
479 }
480
481 if (!empty($user->array_options['options_DDA'])) {
482 $desc .= '<br>' . $langs->trans('Anciennete') . ' : ' . dol_print_date(strtotime($user->array_options['options_DDA']));
483 }
484
485 $out .= '<li fk_user="' . $user->id . '" class="' . $class . '">
486 ' . $form->showphoto('userphoto', $user, 0, 0, 0, 'photoref', 'small', 1, 0, 1) . '
487 <h3>' . $name . '</h3>
488 <p>' . $desc . '</p>
489 </li>';
490 }
491
492 $out .= '</ul>';
493 }
494
495 return $out;
496}
497
498
506function getSkillForUsers($TUser)
507{
508 global $db;
509
510 //I go back to the user with the highest score in a given group for all the skills assessed in that group
511 if (empty($TUser)) {
512 return array();
513 }
514
515 $sql = 'SELECT sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill, ';
516 $sql.= ' MAX(sr.rankorder) as rankorder';
517 $sql.= ' FROM '.MAIN_DB_PREFIX.'hrm_skill sk';
518 $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)';
519 $sql.= " WHERE sr.objecttype = '".$db->escape(SkillRank::SKILLRANK_TYPE_USER)."'";
520 $sql.= ' AND sr.fk_object IN ('.$db->sanitize(implode(',', $TUser)).')';
521 $sql.= " GROUP BY sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill "; // group par competence
522
523 $resql = $db->query($sql);
524 $Tab = array();
525
526 if ($resql) {
527 //For each skill, we count the number of times that the max score has been reached within a given group
528 $num = 0;
529 while ($obj = $db->fetch_object($resql)) {
530 $sql1 = "SELECT COUNT(rowid) as how_many_max FROM ".MAIN_DB_PREFIX."hrm_skillrank as sr";
531 $sql1.=" WHERE sr.rankorder = ".((int) $obj->rankorder);
532 $sql1.=" AND sr.objecttype = '".$db->escape(SkillRank::SKILLRANK_TYPE_USER)."'";
533 $sql1.=" AND sr.fk_skill = ".((int) $obj->fk_skill);
534 $sql1.=" AND sr.fk_object IN (".$db->sanitize(implode(',', $TUser)).")";
535 $resql1 = $db->query($sql1);
536
537 $objMax = $db->fetch_object($resql1);
538
539 $Tab[$num] = new stdClass();
540 $Tab[$num]->fk_skill = $obj->fk_skill;
541 $Tab[$num]->label = $obj->label;
542 $Tab[$num]->description = $obj->description;
543 $Tab[$num]->skill_type = $obj->skill_type;
544 $Tab[$num]->fk_object = $obj->fk_object;
545 $Tab[$num]->objectType = SkillRank::SKILLRANK_TYPE_USER;
546 $Tab[$num]->rankorder = $obj->rankorder;
547 $Tab[$num]->how_many_max = $objMax->how_many_max;
548
549 $num++;
550 }
551 } else {
552 dol_print_error($db);
553 }
554
555 return $Tab;
556}
557
564function getSkillForJob($fk_job)
565{
566 global $db;
567
568 if (empty($fk_job)) {
569 return array();
570 }
571
572 $sql = 'SELECT sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill,';
573 $sql.= " MAX(sr.rankorder) as rankorder";
574 $sql.=' FROM '.MAIN_DB_PREFIX.'hrm_skill as sk';
575 $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank as sr ON (sk.rowid = sr.fk_skill)';
576 $sql.=" WHERE sr.objecttype = '".SkillRank::SKILLRANK_TYPE_JOB."'";
577 $sql.=' AND sr.fk_object = '.((int) $fk_job);
578 $sql.=' GROUP BY sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill'; // group par competence*/
579
580 $resql = $db->query($sql);
581 $Tab = array();
582
583 if ($resql) {
584 $num = 0;
585 while ($obj = $db->fetch_object($resql)) {
586 $Tab[$num] = new stdClass();
587 $Tab[$num]->fk_skill = $obj->fk_skill;
588 $Tab[$num]->label = $obj->label;
589 $Tab[$num]->description = $obj->description;
590 $Tab[$num]->skill_type = $obj->skill_type;
591 //$Tab[$num]->date_start = '';// du poste
592 //$Tab[$num]->date_end = ''; // du poste
593 $Tab[$num]->fk_object = $obj->fk_object;
594 $Tab[$num]->objectType = SkillRank::SKILLRANK_TYPE_JOB;
595 $Tab[$num]->rankorder = $obj->rankorder;
596 $Tab[$num]->how_many_max = $obj->how_many_max;
597
598 $num++;
599 }
600 } else {
601 dol_print_error($db);
602 }
603
604 return $Tab;
605}
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:55
llxFooter()
Empty footer.
Definition wrapper.php:69
Class for Evaluation.
Class for Job.
Definition job.class.php:37
Class for Skill.
Class to manage Dolibarr users.
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.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:121
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:124
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.