dolibarr  16.0.5
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 class/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  */
35 
36 require_once '../main.inc.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
39 require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php';
40 require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php';
41 require_once DOL_DOCUMENT_ROOT . '/hrm/class/evaluation.class.php';
42 require_once DOL_DOCUMENT_ROOT . '/hrm/class/position.class.php';
43 require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm.lib.php';
44 
45 $permissiontoread = $user->rights->hrm->evaluation->read || $user->rights->hrm->compare_advance->read;
46 $permissiontoadd = 0;
47 if (empty($conf->hrm->enabled)) accessforbidden();
48 if (!$permissiontoread || ($action === 'create' && !$permissiontoadd)) accessforbidden();
49 
50 $langs->load('hrm');
51 
52 
53 
54 /*
55  * View
56  */
57 
58 $css = array();
59 $css[] = '/hrm/css/style.css';
60 llxHeader('', $langs->trans('SkillComparison'), '', '', 0, 0, '', $css);
61 
62 $head = array();
63 
64 $h = 0;
65 $head[$h][0] = $_SERVER["PHP_SELF"];
66 $head[$h][1] = $langs->trans("SkillComparison");
67 $head[$h][2] = 'compare';
68 
69 print dol_get_fiche_head($head, 'compare', '', 1);
70 
71 //$PDOdb = new TPDOdb;
72 $form = new Form($db);
73 ?>
74  <script type="text/javascript">
75 
76  $(document).ready(function () {
77 
78  $("li[fk_user]").click(function () {
79 
80  if ($(this).hasClass('disabled')) {
81  $(this).removeClass('disabled');
82  } else {
83  $(this).addClass('disabled');
84  }
85 
86 
87  $userl = $(this).closest('ul');
88  listname = $userl.attr('name');
89 
90  var TId = [];
91 
92  $userl.find('li').each(function (i, item) {
93 
94  if ($(item).hasClass('disabled')) {
95  TId.push($(item).attr('fk_user'));
96  }
97 
98  });
99 
100  $('#' + listname + '_excluded_id').val(TId.join(','));
101 
102  });
103 
104  });
105 
106 
107  </script>
108 
109 
110 <?php
111 $job = new Job($db);
112 $form = new Form($db);
113 
114 $fk_usergroup2 = 0;
115 $fk_job = (int) GETPOST('fk_job');
116 if ($fk_job <= 0) $fk_usergroup2 = GETPOST('fk_usergroup2');
117 
118 $fk_usergroup1 = GETPOST('fk_usergroup1');
119 
120 ?>
121 
122 
123  <div class="fichecenter">
124  <form action="<?php echo $_SERVER['PHP_SELF'] ?>">
125 
126  <div class="tabBar tabBarWithBottom">
127  <div class="fichehalfleft">
128  <table class="border tableforfield" width="100%">
129  <tr>
130  <td><?php echo $langs->trans('group1ToCompare').'</td><td>'.$form->select_dolgroups($fk_usergroup1, 'fk_usergroup1', 1); ?></td>
131  </tr>
132  <tr><td>&nbsp;</td></tr>
133  <tr>
134  <td><?php echo $langs->trans('group2ToCompare').'</td><td>'.$form->select_dolgroups($fk_usergroup2, 'fk_usergroup2', 1); ?></td>
135  </tr>
136  <tr>
137  <td><STRONG><?php print $langs->trans('or'); ?></STRONG></td>
138  </tr>
139  <tr>
140  <td><?php
141  echo $langs->trans('OrJobToCompare') . '</td><td>';
142  $j = new Job($db);
143  $jobs = $j->fetchAll();
144  $TJobs = array();
145 
146  foreach ($jobs as &$j) {
147  $TJobs[$j->id] = $j->label;
148  }
149 
150  print $form->selectarray('fk_job', $TJobs, $fk_job, 1);
151  ?></td>
152  </tr>
153  </table>
154  </div>
155 
156  <div style="background:#eee;border-radius:5px 0;margin:0px 0 10px;font-style:italic;padding:5px;" class="fichehalfright">
157  <!--<h4><?php echo $langs->trans('legend'); ?></h4>-->
158  <table class="border" width="100%">
159  <tr>
160  <td><span style="vertical-align:middle" class="toohappy diffnote little"></span>
161  <?php echo $langs->trans('CompetenceAcquiredByOneOrMore'); ?></td>
162  </tr>
163  <tr>
164  <td><span style="vertical-align:middle" class="veryhappy diffnote little"></span>
165  <?php echo $langs->trans('MaxlevelGreaterThan'); ?></td>
166  </tr>
167  <tr>
168  <td><span style="vertical-align:middle" class="happy diffnote little"></span>
169  <?php echo $langs->trans('MaxLevelEqualTo'); ?></td>
170  </tr>
171  <tr>
172  <td><span style="vertical-align:middle" class="sad diffnote little"></span>
173  <?php echo $langs->trans('MaxLevelLowerThan'); ?></td>
174  </tr>
175  <tr>
176  <td><span style="vertical-align:middle" class="toosad diffnote little"></span>
177  <?php echo $langs->trans('SkillNotAcquired'); ?></td>
178  </tr>
179  </table>
180 
181  </div>
182 
183  <div style="clear:both"></div>
184 
185  </div>
186 
187  <br><br>
188  <div class="center">
189  <input class="button" type="SUBMIT" name="bt1" VALUE="<?php print $langs->trans('Refresh'); ?>">
190  </div>
191  <br><br>
192 
193  <div id="compare" width="100%" style="position:relative;">
194 
195  <?php if ($fk_usergroup1 > 0 || $fk_usergroup2 > 0 || $fk_job > 0) { ?>
196  <table width="100%">
197  <tr>
198  <th></th>
199  <th><?php print $langs->trans('skill'); ?></th>
200  <th><?php print $langs->trans('rank'); ?></th>
201  <th><?php print $langs->trans('difference'); ?></th>
202  <th><?php print $langs->trans('rank'); ?></th>
203  <th></th>
204  </tr>
205 
206  <?php
207  echo '<tr><td id="list-user-left" style="width:30%" valign="top">';
208 
209  $TUser1 = $TUser2 = array();
210 
211  $userlist1 = displayUsersListWithPicto($TUser1, $fk_usergroup1, 'list1');
212 
213 
214  $skill = new Skill($db);
215  $TSkill1 = getSkillForUsers($TUser1);
216 
217  if ($fk_job > 0) {
218  $TSkill2 = getSkillForJob($fk_job);
219 
220  $job = new Job($db);
221  $job->fetch($fk_job);
222  $userlist2 = '<ul>
223  <li>
224  <h3>' . $job->label . '</h3>
225  <p>' . $job->description . '</p>
226  </li>
227  </ul>';
228  } else {
229  $userlist2 = displayUsersListWithPicto($TUser2, $fk_usergroup2, 'list2');
230  $TSkill2 = getSkillForUsers($TUser2);
231  }
232 
233  $TMergedSkills = mergeSkills($TSkill1, $TSkill2);
234 
235  echo $userlist1;
236 
237  echo '</td>';
238 
239  echo '<td id="" style="width:20%" valign="top">' . skillList($TMergedSkills) . '</td>';
240  echo '<td id="" style="width:5%" valign="top">' . rate($TMergedSkills, 'rate1') . '</td>';
241  echo '<td id="" style="width:10%" valign="top">' . diff($TMergedSkills) . '</td>';
242  echo '<td id="" style="width:5%" valign="top">' . rate($TMergedSkills, 'rate2') . '</td>';
243 
244  echo '<td id="list-user-right" style="width:30%" valign="top">';
245 
246  echo $userlist2;
247 
248  echo '</td></tr>';
249 
250  ?>
251 
252  </table>
253 
254  <?php } ?>
255 
256  </div>
257 
258  </form>
259 
260  </div>
261 
262 <?php
263 
264 print dol_get_fiche_end();
265 
266 llxFooter();
267 
268 
269 
277 function diff(&$TMergedSkills)
278 {
279 
280  $out = '<ul class="diff">';
281 
282  foreach ($TMergedSkills as $id => &$sk) {
283  $class = 'diffnote';
284 
285  if (empty($sk->rate2)) $class .= ' toohappy';
286  elseif (empty($sk->rate1)) $class .= ' toosad';
287  elseif ($sk->rate1 == $sk->rate2) $class .= ' happy';
288  elseif ($sk->rate2 < $sk->rate1) $class .= ' veryhappy';
289  elseif ($sk->rate2 > $sk->rate1) $class .= ' sad';
290 
291  $out .= '<li fk_skill="' . $id . '" class="' . $class . '" style="text-align:center;">
292  <span class="' . $class . '">&nbsp;</span>
293  </li>';
294  }
295 
296  $out .= '</ul>';
297 
298  return $out;
299 }
300 
307 function rate(&$TMergedSkills, $field)
308 {
309  global $langs, $fk_job;
310 
311  $out = '<ul class="competence">';
312 
313  foreach ($TMergedSkills as $id => &$sk) {
314  $class = "note";
315  $how_many = 0;
316  if (empty($sk->{$field})) {
317  $note = 'x';
318  $class .= ' none';
319  } else {
320  $note = $sk->{$field};
321  $how_many = ($field === 'rate1') ? $sk->how_many_max1 : $sk->how_many_max2;
322  }
323 
324  if ($field === 'rate2' && $fk_job > 0) $trad = $langs->trans('RequiredRank');
325  else $trad = $langs->trans('HighestRank');
326 
327  $out .= '<li fk_skill="' . $id . '" style="text-align:center;">
328  <p><span class="' . $class . ' classfortooltip" title="' . $trad . '">' . $note . '</span>' . ($how_many > 0 ? '<span class="bubble classfortooltip" title="' . $langs->trans('HowManyUserWithThisMaxNote') . '">' . $how_many . '</span>' : '') . '</p>
329  </li>';
330  }
331 
332  $out .= '</ul>';
333 
334  return $out;
335 }
336 
343 function skillList(&$TMergedSkills)
344 {
345 
346  $out = '<ul class="competence">';
347 
348  foreach ($TMergedSkills as $id => &$sk) {
349  $out .= '<li fk_skill="' . $id . '">
350  <h3>' . $sk->label . '</h3>
351  <p>' . $sk->description . '</p>
352  </li>';
353  }
354 
355  $out .= '</ul>';
356 
357  return $out;
358 }
359 
367 function mergeSkills($TSkill1, $TSkill2)
368 {
369 
370  $Tab = array();
371 
372  foreach ($TSkill1 as &$sk) {
373  if (empty($Tab[$sk->fk_skill])) $Tab[$sk->fk_skill] = new stdClass;
374 
375  $Tab[$sk->fk_skill]->rate1 = $sk->rankorder;
376  $Tab[$sk->fk_skill]->how_many_max1 = $sk->how_many_max;
377  $Tab[$sk->fk_skill]->label = $sk->label;
378  $Tab[$sk->fk_skill]->description = $sk->description;
379  }
380 
381  foreach ($TSkill2 as &$sk) {
382  if (empty($Tab[$sk->fk_skill])) $Tab[$sk->fk_skill] = new stdClass;
383  $Tab[$sk->fk_skill]->rate2 = $sk->rankorder;
384  $Tab[$sk->fk_skill]->label = $sk->label;
385  $Tab[$sk->fk_skill]->description = $sk->description;
386  $Tab[$sk->fk_skill]->how_many_max2 = $sk->how_many_max;
387  }
388 
389  return $Tab;
390 }
391 
399 function displayUsersListWithPicto(&$TUser, $fk_usergroup = 0, $namelist = 'list-user')
400 {
401  global $db, $langs, $conf, $form;
402 
403  $out = '';
404  if ($fk_usergroup > 0) {
405  $list = $namelist . '_excluded_id';
406 
407  $excludedIdsList = GETPOST($list);
408 
409 
410  $sql = "SELECT DISTINCT u.rowid FROM " . MAIN_DB_PREFIX . "user u
411  LEFT JOIN " . MAIN_DB_PREFIX . "usergroup_user as ugu ON (u.rowid = ugu.fk_user)
412  WHERE u.statut > 0
413  AND ugu.fk_usergroup=" . ((int) $fk_usergroup);
414 
415  $res = $db->query($sql);
416  $out .= '<ul name="' . $namelist . '">';
417 
418  $TExcludedId = explode(',', $excludedIdsList);
419 
420  $form = new Form($db);
421  $out .= '<input id="'.$list.'" type="HIDDEN" name="'.$list.'" value="'.$excludedIdsList.'"> ';
422 
423  while ($obj = $db->fetch_object($res)) {
424  $class = '';
425 
426  $user = new User($db);
427  $user->fetch($obj->rowid);
428 
429  $name = $user->getFullName($langs);
430  if (empty($name)) $name = $user->login;
431 
432  if (in_array($user->id, $TExcludedId)) {
433  $class .= ' disabled';
434  } else {
435  if (!in_array($user->id, $TUser)) $TUser[] = $user->id;
436  }
437 
438 
439  $desc = '';
440 
441  $job = Job::getLastJobForUser($user->id);
442  $desc .= $job;
443 
444  $static_eval = new Evaluation($db);
445  $evaluation = $static_eval->getLastEvaluationForUser($user->id);
446 
447  if (!empty($evaluation) && !empty($evaluation->date_eval)) {
448  $desc .= $langs->trans('DateLastEval') . ' : ' . dol_print_date($evaluation->date_eval);
449  } else {
450  $desc .= $langs->trans('NoEval');
451  }
452 
453  if (!empty($user->array_options['options_DDA'])) $desc .= '<br>' . $langs->trans('Anciennete') . ' : ' . dol_print_date(strtotime($user->array_options['options_DDA']));
454 
455  $out .= '<li fk_user="' . $user->id . '" class="' . $class . '">
456  ' . $form->showphoto('userphoto', $user, 0, 0, 0, 'photoref', 'small', 1, 0, 1) . '
457  <h3>' . $name . '</h3>
458  <p>' . $desc . '</p>
459  </li>';
460  }
461 
462  $out .= '</ul>';
463  }
464 
465  return $out;
466 }
467 
468 
476 function getSkillForUsers($TUser)
477 {
478  global $db;
479 
480  //I go back to the user with the highest score in a given group for all the skills assessed in that group
481  if (empty($TUser)) return array();
482 
483  $sql = 'SELECT sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill, ';
484  $sql.= ' MAX(sr.rankorder) as "rankorder"';
485  $sql.= ' FROM '.MAIN_DB_PREFIX.'hrm_skill sk';
486  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)';
487  $sql.= " WHERE sr.objecttype = '".SkillRank::SKILLRANK_TYPE_USER."'";
488  $sql.= ' AND sr.fk_object IN ('.$db->sanitize(implode(',', $TUser)).')';
489  $sql.= " GROUP BY sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill "; // group par competence
490 
491  $resql = $db->query($sql);
492  $Tab = array();
493 
494  if ($resql) {
495  //For each skill, we count the number of times that the max score has been reached within a given group
496  $num = 0;
497  while ($obj = $db->fetch_object($resql) ) {
498  $sql1 = "SELECT count(*) as how_many_max FROM ".MAIN_DB_PREFIX."hrm_skillrank sr";
499  $sql1.=" WHERE sr.rankorder = ".((int) $obj->rankorder);
500  $sql1.=" AND sr.objecttype = '".Skillrank::SKILLRANK_TYPE_USER."'";
501  $sql1.=" AND sr.fk_skill = ".((int) $obj->fk_skill);
502  $sql1.=" AND sr.fk_object IN (".$db->sanitize(implode(',', $TUser)).")";
503  $resql1 = $db->query($sql1);
504 
505  $objMax = $db->fetch_object($resql1);
506 
507  $Tab[$num] = new stdClass();
508  $Tab[$num]->fk_skill = $obj->fk_skill;
509  $Tab[$num]->label = $obj->label;
510  $Tab[$num]->description = $obj->description;
511  $Tab[$num]->skill_type = $obj->skill_type;
512  $Tab[$num]->fk_object = $obj->fk_object;
513  $Tab[$num]->objectType = SkillRank::SKILLRANK_TYPE_USER;
514  $Tab[$num]->rankorder = $obj->rankorder;
515  $Tab[$num]->how_many_max = $objMax->how_many_max;
516 
517  $num++;
518  }
519  } else {
520  dol_print_error($db);
521  }
522 
523  return $Tab;
524 }
525 
532 function getSkillForJob($fk_job)
533 {
534  global $db;
535 
536  if (empty($fk_job)) return array();
537 
538  $sql = 'SELECT sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill, ';
539  $sql.= ' MAX(sr.rankorder) as "rankorder"';
540  $sql.=' FROM '.MAIN_DB_PREFIX.'hrm_skill sk';
541  $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)';
542  $sql.=" WHERE sr.objecttype = '".SkillRank::SKILLRANK_TYPE_JOB."'";
543  $sql.=' AND sr.fk_object = '.((int) $fk_job);
544  $sql.=' GROUP BY sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill '; // group par competence*/
545 
546  $resql = $db->query($sql);
547  $Tab = array();
548 
549 
550  if ($resql) {
551  $num = 0;
552  while ($obj = $db->fetch_object($resql) ) {
553  $Tab[$num] = new stdClass();
554  $Tab[$num]->fk_skill = $obj->fk_skill;
555  $Tab[$num]->label = $obj->label;
556  $Tab[$num]->description = $obj->description;
557  $Tab[$num]->skill_type = $obj->skill_type;
558  //$Tab[$num]->date_start = '';// du poste
559  //$Tab[$num]->date_end = ''; // du poste
560  $Tab[$num]->fk_object = $obj->fk_object;
561  $Tab[$num]->objectType = SkillRank::SKILLRANK_TYPE_JOB;
562  $Tab[$num]->rankorder = $obj->rankorder;
563  $Tab[$num]->how_many_max = $obj->how_many_max;
564 
565  $num++;
566  }
567  } else {
568  dol_print_error($db);
569  }
570 
571 
572  return $Tab;
573 }
llxFooter
llxFooter()
Empty footer.
Definition: wrapper.php:73
Job\getLastJobForUser
getLastJobForUser($fk_user)
Get last job for user.
Definition: job.class.php:608
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:484
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4844
$form
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:142
name
$conf db name
Definition: repair.php:122
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2514
Skill
Class for Skill.
Definition: skill.class.php:36
dol_get_fiche_head
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tabs of a record.
Definition: functions.lib.php:1822
Evaluation
Class for Evaluation.
Definition: evaluation.class.php:37
dol_get_fiche_end
dol_get_fiche_end($notab=0)
Return tab footer of a card.
Definition: functions.lib.php:2018
User
Class to manage Dolibarr users.
Definition: user.class.php:44
Form
Class to manage generation of HTML components Only common components must be here.
Definition: html.form.class.php:52
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice') && $user->rights->supplier_invoice->lire)) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
accessforbidden
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program Calling this function terminate execution ...
Definition: security.lib.php:933
Job
Class for Job.
Definition: job.class.php:36
type
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:119
llxHeader
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOCSRFCHECK')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:59