From fde0f1ac251b353049d62de98ddd3824f8ff3f21 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Mon, 27 Sep 2021 11:20:38 +0200 Subject: [PATCH 01/79] NEW : HRM integration, source code --- htdocs/admin/hrm.php | 655 +++++++++ htdocs/core/lib/company.lib.php | 12 +- htdocs/core/lib/hrm.lib.php | 16 + htdocs/core/menus/standard/eldy.lib.php | 22 + .../modules/hrm/mod_evaluation_advanced.php | 148 +++ .../modules/hrm/mod_evaluation_standard.php | 161 +++ .../core/modules/hrm/modules_evaluation.php | 158 +++ htdocs/core/modules/modHRM.class.php | 244 +++- htdocs/hrm/class/evaluation.class.php | 1182 +++++++++++++++++ htdocs/hrm/class/evaluationdet.class.php | 1069 +++++++++++++++ htdocs/hrm/class/job.class.php | 1119 ++++++++++++++++ htdocs/hrm/class/position.class.php | 1091 +++++++++++++++ htdocs/hrm/class/skill.class.php | 1134 ++++++++++++++++ htdocs/hrm/class/skilldet.class.php | 1030 ++++++++++++++ htdocs/hrm/class/skillrank.class.php | 1086 +++++++++++++++ htdocs/hrm/compare.php | 635 +++++++++ htdocs/hrm/core/tpl/objectline_title.tpl.php | 77 ++ htdocs/hrm/core/tpl/objectline_view.tpl.php | 164 +++ htdocs/hrm/core/tpl/skilldet.fiche.tpl.php | 115 ++ htdocs/hrm/css/radio_js_number.css | 18 + htdocs/hrm/css/style.css | 130 ++ htdocs/hrm/evaluation_agenda.php | 282 ++++ htdocs/hrm/evaluation_card.php | 763 +++++++++++ htdocs/hrm/evaluation_contact.php | 220 +++ htdocs/hrm/evaluation_document.php | 224 ++++ htdocs/hrm/evaluation_list.php | 731 ++++++++++ htdocs/hrm/evaluation_note.php | 182 +++ htdocs/hrm/job_agenda.php | 275 ++++ htdocs/hrm/job_card.php | 532 ++++++++ htdocs/hrm/job_contact.php | 220 +++ htdocs/hrm/job_document.php | 219 +++ htdocs/hrm/job_list.php | 733 ++++++++++ htdocs/hrm/job_note.php | 175 +++ htdocs/hrm/lib/hrm.lib.php | 69 + htdocs/hrm/lib/hrm_evaluation.lib.php | 95 ++ htdocs/hrm/lib/hrm_job.lib.php | 106 ++ htdocs/hrm/lib/hrm_position.lib.php | 96 ++ htdocs/hrm/lib/hrm_skill.lib.php | 528 ++++++++ htdocs/hrm/lib/hrm_skilldet.lib.php | 95 ++ htdocs/hrm/lib/hrm_skillrank.lib.php | 149 +++ htdocs/hrm/modulebuilder.txt | 3 + htdocs/hrm/position.php | 950 +++++++++++++ htdocs/hrm/position_agenda.php | 282 ++++ htdocs/hrm/position_card.php | 444 +++++++ htdocs/hrm/position_contact.php | 220 +++ htdocs/hrm/position_document.php | 223 ++++ htdocs/hrm/position_list.php | 732 ++++++++++ htdocs/hrm/position_note.php | 183 +++ htdocs/hrm/skill_agenda.php | 275 ++++ htdocs/hrm/skill_card.php | 909 +++++++++++++ htdocs/hrm/skill_contact.php | 220 +++ htdocs/hrm/skill_document.php | 217 +++ htdocs/hrm/skill_list.php | 733 ++++++++++ htdocs/hrm/skill_note.php | 175 +++ htdocs/hrm/skill_tab.php | 374 ++++++ htdocs/langs/en_US/hrm.lang | 68 + htdocs/langs/fr_FR/hrm.lang | 81 +- 57 files changed, 21993 insertions(+), 56 deletions(-) create mode 100644 htdocs/admin/hrm.php create mode 100644 htdocs/core/modules/hrm/mod_evaluation_advanced.php create mode 100644 htdocs/core/modules/hrm/mod_evaluation_standard.php create mode 100644 htdocs/core/modules/hrm/modules_evaluation.php create mode 100644 htdocs/hrm/class/evaluation.class.php create mode 100644 htdocs/hrm/class/evaluationdet.class.php create mode 100644 htdocs/hrm/class/job.class.php create mode 100644 htdocs/hrm/class/position.class.php create mode 100644 htdocs/hrm/class/skill.class.php create mode 100644 htdocs/hrm/class/skilldet.class.php create mode 100644 htdocs/hrm/class/skillrank.class.php create mode 100644 htdocs/hrm/compare.php create mode 100644 htdocs/hrm/core/tpl/objectline_title.tpl.php create mode 100644 htdocs/hrm/core/tpl/objectline_view.tpl.php create mode 100644 htdocs/hrm/core/tpl/skilldet.fiche.tpl.php create mode 100644 htdocs/hrm/css/radio_js_number.css create mode 100644 htdocs/hrm/css/style.css create mode 100644 htdocs/hrm/evaluation_agenda.php create mode 100644 htdocs/hrm/evaluation_card.php create mode 100644 htdocs/hrm/evaluation_contact.php create mode 100644 htdocs/hrm/evaluation_document.php create mode 100644 htdocs/hrm/evaluation_list.php create mode 100644 htdocs/hrm/evaluation_note.php create mode 100644 htdocs/hrm/job_agenda.php create mode 100644 htdocs/hrm/job_card.php create mode 100644 htdocs/hrm/job_contact.php create mode 100644 htdocs/hrm/job_document.php create mode 100644 htdocs/hrm/job_list.php create mode 100644 htdocs/hrm/job_note.php create mode 100644 htdocs/hrm/lib/hrm.lib.php create mode 100644 htdocs/hrm/lib/hrm_evaluation.lib.php create mode 100644 htdocs/hrm/lib/hrm_job.lib.php create mode 100644 htdocs/hrm/lib/hrm_position.lib.php create mode 100644 htdocs/hrm/lib/hrm_skill.lib.php create mode 100644 htdocs/hrm/lib/hrm_skilldet.lib.php create mode 100644 htdocs/hrm/lib/hrm_skillrank.lib.php create mode 100644 htdocs/hrm/modulebuilder.txt create mode 100644 htdocs/hrm/position.php create mode 100644 htdocs/hrm/position_agenda.php create mode 100644 htdocs/hrm/position_card.php create mode 100644 htdocs/hrm/position_contact.php create mode 100644 htdocs/hrm/position_document.php create mode 100644 htdocs/hrm/position_list.php create mode 100644 htdocs/hrm/position_note.php create mode 100644 htdocs/hrm/skill_agenda.php create mode 100644 htdocs/hrm/skill_card.php create mode 100644 htdocs/hrm/skill_contact.php create mode 100644 htdocs/hrm/skill_document.php create mode 100644 htdocs/hrm/skill_list.php create mode 100644 htdocs/hrm/skill_note.php create mode 100644 htdocs/hrm/skill_tab.php diff --git a/htdocs/admin/hrm.php b/htdocs/admin/hrm.php new file mode 100644 index 00000000000..e520fae2aed --- /dev/null +++ b/htdocs/admin/hrm.php @@ -0,0 +1,655 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file hrm/admin/setup.php + * \ingroup hrm + * \brief HrmTest setup page. + */ + +// Load Dolibarr environment +require '../main.inc.php'; + +global $langs, $user; + +// Libraries +require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php"; +require_once DOL_DOCUMENT_ROOT.'/hrm/lib/hrm.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/class/skill.class.php'; +//require_once "../class/myclass.class.php"; + +// Translations +$langs->loadLangs(array("admin", "hrm")); + +// Access control +if (!$user->admin) { + accessforbidden(); +} + +// Parameters +$action = GETPOST('action', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +$value = GETPOST('value', 'alpha'); +$label = GETPOST('label', 'alpha'); +$scandir = GETPOST('scan_dir', 'alpha'); +$type = 'myobject'; + +$arrayofparameters = array( + 'HRM_MAXRANK'=>array('type'=>'integer','enabled'=>1), + 'HRM_DEFAULT_SKILL_DESCRIPTION'=>array('type'=>'textarea','enabled'=>1), +); + +$error = 0; +$setupnotempty = 0; + +$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + + +/* + * Actions + */ + +if ((float) DOL_VERSION >= 6) { + include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php'; +} + +if ($action == 'update') { + $max_rank = GETPOST('HRM_MAXRANK', 'int'); + + // We complete skill possible level notation if necessary + if (!empty($max_rank)) { + $static_skill = new Skill($db); + $TAllSkills = $static_skill->fetchAll(); + foreach ($TAllSkills as &$skill) { + if (empty($skill->lines)) $skill->fetchLines(); + if (count($skill->lines) < $conf->global->HRM_MAXRANK) { + $skill->createSkills(count($skill->lines) + 1); + } + } + } +} elseif ($action == 'updateMask') { + $maskconstorder = GETPOST('maskconstorder', 'alpha'); + $maskorder = GETPOST('maskorder', 'alpha'); + + if ($maskconstorder) { + $res = dolibarr_set_const($db, $maskconstorder, $maskorder, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } + } + + if (!$error) { + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } else { + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} elseif ($action == 'specimen') { + $modele = GETPOST('module', 'alpha'); + $tmpobjectkey = GETPOST('object'); + + $tmpobject = new $tmpobjectkey($db); + $tmpobject->initAsSpecimen(); + + // Search template files + $file = ''; $classname = ''; $filefound = 0; + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $file = dol_buildpath($reldir."core/modules/hrm/doc/pdf_".$modele."_".strtolower($tmpobjectkey).".modules.php", 0); + if (file_exists($file)) { + $filefound = 1; + $classname = "pdf_".$modele; + break; + } + } + + if ($filefound) { + require_once $file; + + $module = new $classname($db); + + if ($module->write_file($tmpobject, $langs) > 0) { + header("Location: ".DOL_URL_ROOT."/document.php?modulepart=".strtolower($tmpobjectkey)."&file=SPECIMEN.pdf"); + return; + } else { + setEventMessages($module->error, null, 'errors'); + dol_syslog($module->error, LOG_ERR); + } + } else { + setEventMessages($langs->trans("ErrorModuleNotFound"), null, 'errors'); + dol_syslog($langs->trans("ErrorModuleNotFound"), LOG_ERR); + } +} elseif ($action == 'setmod') { + // TODO Check if numbering module chosen can be activated by calling method canBeActivated + $tmpobjectkey = GETPOST('object'); + if (!empty($tmpobjectkey)) { + $constforval = 'HRMTEST_'.strtoupper($tmpobjectkey)."_ADDON"; + dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity); + } +} elseif ($action == 'set') { + // Activate a model + $ret = addDocumentModel($value, $type, $label, $scandir); +} elseif ($action == 'del') { + $ret = delDocumentModel($value, $type); + if ($ret > 0) { + $tmpobjectkey = GETPOST('object'); + if (!empty($tmpobjectkey)) { + $constforval = 'HRMTEST_'.strtoupper($tmpobjectkey).'_ADDON_PDF'; + if ($conf->global->$constforval == "$value") { + dolibarr_del_const($db, $constforval, $conf->entity); + } + } + } +} elseif ($action == 'setdoc') { + // Set or unset default model + $tmpobjectkey = GETPOST('object'); + if (!empty($tmpobjectkey)) { + $constforval = 'HRMTEST_'.strtoupper($tmpobjectkey).'_ADDON_PDF'; + if (dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity)) { + // The constant that was read before the new set + // We therefore requires a variable to have a coherent view + $conf->global->$constforval = $value; + } + + // We disable/enable the document template (into llx_document_model table) + $ret = delDocumentModel($value, $type); + if ($ret > 0) { + $ret = addDocumentModel($value, $type, $label, $scandir); + } + } +} elseif ($action == 'unsetdoc') { + $tmpobjectkey = GETPOST('object'); + if (!empty($tmpobjectkey)) { + $constforval = 'HRMTEST_'.strtoupper($tmpobjectkey).'_ADDON_PDF'; + dolibarr_del_const($db, $constforval, $conf->entity); + } +} + + +/* + * View + */ + +$form = new Form($db); + +$help_url = ''; +$page_name = "HrmSetup"; + +llxHeader('', $langs->trans($page_name), $help_url); + +// Subheader +$linkback = ''.$langs->trans("BackToModuleList").''; + +print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup'); + +// Configuration header +$head = hrmAdminPrepareHead(); +print dol_get_fiche_head($head, 'settings', $langs->trans($page_name), -1, "hrm"); + +$moduledir = 'hrm'; +$myTmpObjects = array(); +$myTmpObjects['evaluation'] = array('includerefgeneration'=>1, 'includedocgeneration'=>0); + +foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) { + if ($myTmpObjectKey == 'MyObject') { + continue; + } + if ($myTmpObjectArray['includerefgeneration']) { + /* + * Orders Numbering model + */ + $setupnotempty++; + + print load_fiche_titre($langs->trans("NumberingModules", $myTmpObjectKey), '', ''); + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''."\n"; + + clearstatcache(); + + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/".$moduledir); + + if (is_dir($dir)) { + $handle = opendir($dir); + if (is_resource($handle)) { + while (($file = readdir($handle)) !== false) { + if (strpos($file, 'mod_'.strtolower($myTmpObjectKey).'_') === 0 && substr($file, dol_strlen($file) - 3, 3) == 'php') { + $file = substr($file, 0, dol_strlen($file) - 4); + + require_once $dir.'/'.$file.'.php'; + + $module = new $file($db); + + // Show modules according to features level + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) { + continue; + } + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) { + continue; + } + + if ($module->isEnabled()) { + dol_include_once('/'.$moduledir.'/class/'.strtolower($myTmpObjectKey).'.class.php'); + + print ''; + + // Show example of numbering model + print ''."\n"; + + print ''; + + $mytmpinstance = new $myTmpObjectKey($db); + $mytmpinstance->initAsSpecimen(); + + // Info + $htmltooltip = ''; + $htmltooltip .= ''.$langs->trans("Version").': '.$module->getVersion().'
'; + + $nextval = $module->getNextValue($mytmpinstance); + if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval + $htmltooltip .= ''.$langs->trans("NextValue").': '; + if ($nextval) { + if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') { + $nextval = $langs->trans($nextval); + } + $htmltooltip .= $nextval.'
'; + } else { + $htmltooltip .= $langs->trans($module->error).'
'; + } + } + + print ''; + + print "\n"; + } + } + } + closedir($handle); + } + } + } + print "
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").'
'.$module->name."\n"; + print $module->info(); + print ''; + $tmp = $module->getExample(); + if (preg_match('/^Error/', $tmp)) { + $langs->load("errors"); + print '
'.$langs->trans($tmp).'
'; + } elseif ($tmp == 'NotConfigured') { + print $langs->trans($tmp); + } else { + print $tmp; + } + print '
'; + $constforvar = 'HRMTEST_'.strtoupper($myTmpObjectKey).'_ADDON'; + if ($conf->global->$constforvar == $file) { + print img_picto($langs->trans("Activated"), 'switch_on'); + } else { + print ''; + print img_picto($langs->trans("Disabled"), 'switch_off'); + print ''; + } + print ''; + print $form->textwithpicto('', $htmltooltip, 1, 0); + print '
\n"; + } + + if ($myTmpObjectArray['includedocgeneration']) { + /* + * Document templates generators + */ + $setupnotempty++; + $type = strtolower($myTmpObjectKey); + + print load_fiche_titre($langs->trans("DocumentModules", $myTmpObjectKey), '', ''); + + // Load array def with activated templates + $def = array(); + $sql = "SELECT nom"; + $sql .= " FROM ".MAIN_DB_PREFIX."document_model"; + $sql .= " WHERE type = '".$db->escape($type)."'"; + $sql .= " AND entity = ".$conf->entity; + $resql = $db->query($sql); + if ($resql) { + $i = 0; + $num_rows = $db->num_rows($resql); + while ($i < $num_rows) { + $array = $db->fetch_array($resql); + array_push($def, $array[0]); + $i++; + } + } else { + dol_print_error($db); + } + + print "\n"; + print "\n"; + print ''; + print ''; + print '\n"; + print '\n"; + print ''; + print ''; + print "\n"; + + clearstatcache(); + + foreach ($dirmodels as $reldir) { + foreach (array('', '/doc') as $valdir) { + $realpath = $reldir."core/modules/".$moduledir.$valdir; + $dir = dol_buildpath($realpath); + + if (is_dir($dir)) { + $handle = opendir($dir); + if (is_resource($handle)) { + while (($file = readdir($handle)) !== false) { + $filelist[] = $file; + } + closedir($handle); + arsort($filelist); + + foreach ($filelist as $file) { + if (preg_match('/\.modules\.php$/i', $file) && preg_match('/^(pdf_|doc_)/', $file)) { + if (file_exists($dir.'/'.$file)) { + $name = substr($file, 4, dol_strlen($file) - 16); + $classname = substr($file, 0, dol_strlen($file) - 12); + + require_once $dir.'/'.$file; + $module = new $classname($db); + + $modulequalified = 1; + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) { + $modulequalified = 0; + } + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) { + $modulequalified = 0; + } + + if ($modulequalified) { + print ''; + + // Active + if (in_array($name, $def)) { + print ''; + } else { + print '"; + } + + // Default + print ''; + + // Info + $htmltooltip = ''.$langs->trans("Name").': '.$module->name; + $htmltooltip .= '
'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown")); + if ($module->type == 'pdf') { + $htmltooltip .= '
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; + } + $htmltooltip .= '
'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file; + + $htmltooltip .= '

'.$langs->trans("FeaturesSupported").':'; + $htmltooltip .= '
'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1); + $htmltooltip .= '
'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1); + + print ''; + + // Preview + print ''; + + print "\n"; + } + } + } + } + } + } + } + } + + print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Status")."'.$langs->trans("Default")."'.$langs->trans("ShortInfo").''.$langs->trans("Preview").'
'; + print (empty($module->name) ? $name : $module->name); + print "\n"; + if (method_exists($module, 'info')) { + print $module->info($langs); + } else { + print $module->description; + } + print ''."\n"; + print ''; + print img_picto($langs->trans("Enabled"), 'switch_on'); + print ''; + print ''."\n"; + print 'scandir).'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"), 'switch_off').''; + print "'; + $constforvar = 'HRMTEST_'.strtoupper($myTmpObjectKey).'_ADDON'; + if ($conf->global->$constforvar == $name) { + //print img_picto($langs->trans("Default"), 'on'); + // Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset + print 'scandir.'&label='.urlencode($module->name).'&type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').''; + } else { + print 'scandir).'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').''; + } + print ''; + print $form->textwithpicto('', $htmltooltip, 1, 0); + print ''; + if ($module->type == 'pdf') { + print ''.img_object($langs->trans("Preview"), 'pdf').''; + } else { + print img_object($langs->trans("PreviewNotAvailable"), 'generic'); + } + print '
'; + } +} + +print load_fiche_titre($langs->trans('OtherOptions'), '', ''); + +if ($action == 'edit') { + print '
'; + print ''; + print ''; + + print ''; + print ''; + + foreach ($arrayofparameters as $constname => $val) { + if ($val['enabled']==1) { + $setupnotempty++; + print ''; + } + } + print '
'.$langs->trans("Parameter").''.$langs->trans("Value").'
'; + $tooltiphelp = (($langs->trans($constname . 'Tooltip') != $constname . 'Tooltip') ? $langs->trans($constname . 'Tooltip') : ''); + print ''.$form->textwithpicto($langs->trans($constname), $tooltiphelp, 1, 'info', '', 0, 3, 'tootips'.$constname).''; + print ''; + + if ($val['type'] == 'textarea') { + print '\n"; + } elseif ($val['type']== 'integer') { + print '' . "\n"; + } elseif ($val['type']== 'html') { + require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; + $doleditor = new DolEditor($constname, $conf->global->{$constname}, '', 160, 'dolibarr_notes', '', false, false, $conf->fckeditor->enabled, ROWS_5, '90%'); + $doleditor->Create(); + } elseif ($val['type'] == 'yesno') { + print $form->selectyesno($constname, $conf->global->{$constname}, 1); + } elseif (preg_match('/emailtemplate:/', $val['type'])) { + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + + $tmp = explode(':', $val['type']); + $nboftemplates = $formmail->fetchAllEMailTemplate($tmp[1], $user, null, 1); // We set lang=null to get in priority record with no lang + //$arraydefaultmessage = $formmail->getEMailTemplate($db, $tmp[1], $user, null, 0, 1, ''); + $arrayofmessagename = array(); + if (is_array($formmail->lines_model)) { + foreach ($formmail->lines_model as $modelmail) { + //var_dump($modelmail); + $moreonlabel = ''; + if (!empty($arrayofmessagename[$modelmail->label])) { + $moreonlabel = ' (' . $langs->trans("SeveralLangugeVariatFound") . ')'; + } + // The 'label' is the key that is unique if we exclude the language + $arrayofmessagename[$modelmail->id] = $langs->trans(preg_replace('/\(|\)/', '', $modelmail->label)) . $moreonlabel; + } + } + print $form->selectarray($constname, $arrayofmessagename, $conf->global->{$constname}, 'None', 0, 0, '', 0, 0, 0, '', '', 1); + } elseif (preg_match('/category:/', $val['type'])) { + require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; + $formother = new FormOther($db); + + $tmp = explode(':', $val['type']); + print img_picto('', 'category', 'class="pictofixedwidth"'); + print $formother->select_categories($tmp[1], $conf->global->{$constname}, $constname, 0, $langs->trans('CustomersProspectsCategoriesShort')); + } elseif (preg_match('/thirdparty_type/', $val['type'])) { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; + $formcompany = new FormCompany($db); + print $formcompany->selectProspectCustomerType($conf->global->{$constname}, $constname); + } elseif ($val['type'] == 'securekey') { + print ''; + if (!empty($conf->use_javascript_ajax)) { + print ' '.img_picto($langs->trans('Generate'), 'refresh', 'id="generate_token'.$constname.'" class="linkobject"'); + } + if (!empty($conf->use_javascript_ajax)) { + print "\n".''; + } + } elseif ($val['type'] == 'product') { + if (!empty($conf->product->enabled) || !empty($conf->service->enabled)) { + $selected = (empty($conf->global->$constname) ? '' : $conf->global->$constname); + $form->select_produits($selected, $constname, '', 0); + } + } else { + print ''; + } + print '
'; + + print '
'; + print ''; + print '
'; + + print '
'; + print '
'; +} else { + if (!empty($arrayofparameters)) { + print ''; + print ''; + + foreach ($arrayofparameters as $constname => $val) { + if ($val['enabled']==1) { + $setupnotempty++; + print ''; + } + } + + print '
'.$langs->trans("Parameter").''.$langs->trans("Value").'
'; + $tooltiphelp = (($langs->trans($constname . 'Tooltip') != $constname . 'Tooltip') ? $langs->trans($constname . 'Tooltip') : ''); + print $form->textwithpicto($langs->trans($constname), $tooltiphelp); + print ''; + + if ($val['type'] == 'textarea') { + print dol_nl2br($conf->global->{$constname}); + } elseif ($val['type']== 'html') { + print $conf->global->{$constname}; + } elseif ($val['type'] == 'yesno') { + print ajax_constantonoff($constname); + } elseif (preg_match('/emailtemplate:/', $val['type'])) { + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + + $tmp = explode(':', $val['type']); + + $template = $formmail->getEMailTemplate($db, $tmp[1], $user, $langs, $conf->global->{$constname}); + if ($template<0) { + setEventMessages(null, $formmail->errors, 'errors'); + } + print $langs->trans($template->label); + } elseif (preg_match('/category:/', $val['type'])) { + $c = new Categorie($db); + $result = $c->fetch($conf->global->{$constname}); + if ($result < 0) { + setEventMessages(null, $c->errors, 'errors'); + } + $ways = $c->print_all_ways(' >> ', 'none', 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text + $toprint = array(); + foreach ($ways as $way) { + $toprint[] = '
  • color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '
  • '; + } + print '
      ' . implode(' ', $toprint) . '
    '; + } elseif (preg_match('/thirdparty_type/', $val['type'])) { + if ($conf->global->{$constname}==2) { + print $langs->trans("Prospect"); + } elseif ($conf->global->{$constname}==3) { + print $langs->trans("ProspectCustomer"); + } elseif ($conf->global->{$constname}==1) { + print $langs->trans("Customer"); + } elseif ($conf->global->{$constname}==0) { + print $langs->trans("NorProspectNorCustomer"); + } + } elseif ($val['type'] == 'product') { + $product = new Product($db); + $resprod = $product->fetch($conf->global->{$constname}); + if ($resprod > 0) { + print $product->ref; + } elseif ($resprod < 0) { + setEventMessages(null, $object->errors, "errors"); + } + } else { + print $conf->global->{$constname}; + } + print '
    '; + + print '
    '; + print ''.$langs->trans("Modify").''; + print '
    '; + } else { + print '
    '.$langs->trans("NothingToSetup"); + } +} + + +if (empty($setupnotempty)) { + print '
    '.$langs->trans("NothingToSetup"); +} + +// Page end +print dol_get_fiche_end(); + +llxFooter(); +$db->close(); diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php index 1d8024cf40e..d0be91d8614 100644 --- a/htdocs/core/lib/company.lib.php +++ b/htdocs/core/lib/company.lib.php @@ -1446,8 +1446,12 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon = '', $noprin $sql .= ", o.ref"; } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') { $sql .= ", o.ref"; - } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && is_array($filterobj->fields['ref']) && $filterobj->table_element && $filterobj->element) { - $sql .= ", o.ref"; + } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && $filterobj->table_element && $filterobj->element) { + if (!empty($filterobj->fields['ref'])) { + $sql .= ", o.ref"; + } elseif (!empty($filterobj->fields['label'])) { + $sql .= ", o.label"; + } } $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a"; @@ -1482,7 +1486,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon = '', $noprin $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o"; } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') { $sql .= ", ".MAIN_DB_PREFIX."contrat as o"; - } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && is_array($filterobj->fields['ref']) && $filterobj->table_element && $filterobj->element) { + } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && (is_array($filterobj->fields['ref']) || is_array($filterobj->fields['label'])) && $filterobj->table_element && $filterobj->element) { $sql .= ", ".MAIN_DB_PREFIX.$filterobj->table_element." as o"; } @@ -1524,7 +1528,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon = '', $noprin if ($filterobj->id) { $sql .= " AND a.fk_element = ".((int) $filterobj->id); } - } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && is_array($filterobj->fields['ref']) && $filterobj->table_element && $filterobj->element) { + } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && (is_array($filterobj->fields['ref']) || is_array($filterobj->fields['label'])) && $filterobj->table_element && $filterobj->element) { // Generic case $sql .= " AND a.fk_element = o.rowid AND a.elementtype = '".$db->escape($filterobj->element).($module ? "@".$module : "")."'"; if ($filterobj->id) { diff --git a/htdocs/core/lib/hrm.lib.php b/htdocs/core/lib/hrm.lib.php index e24c503f449..e53cc9b3965 100644 --- a/htdocs/core/lib/hrm.lib.php +++ b/htdocs/core/lib/hrm.lib.php @@ -54,6 +54,22 @@ function establishment_prepare_head($object) complete_head_from_modules($conf, $langs, $object, $head, $h, 'establishment', 'remove'); + + + $head[$h][0] = dol_buildpath("/hrm/admin/setup.php", 1); + $head[$h][1] = $langs->trans("Settings"); + $head[$h][2] = 'settings'; + $h++; + + complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm'); + + $head[$h][0] = dol_buildpath("/hrm/admin/about.php", 1); + $head[$h][1] = $langs->trans("About"); + $head[$h][2] = 'about'; + $h++; + + complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm'); + return $head; } diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 0f4aedcd2f9..091e29ac3c6 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1850,6 +1850,28 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM $newmenu->add("/projet/activity/perweek.php?leftmenu=tasks".($search_project_user ? '&search_project_user='.$search_project_user : ''), $langs->trans("NewTimeSpent"), 0, $user->rights->projet->lire, '', $mainmenu, 'timespent', 0, '', '', '', img_picto('', 'timespent', 'class="pictofixedwidth"')); } } + + if (!empty($conf->hrm->enabled)) { + // Skills + $newmenu->add("/hrm/skill_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("Skill"), 0, $user->rights->hrm->all->read, '', $mainmenu, 'hrm', 0, '', '', '', img_picto('', 'shapes', 'class="pictofixedwidth"')); + $newmenu->add("/hrm/skill_card.php?mainmenu=hrm&leftmenu=hrm&action=create", $langs->trans("NewSkill"), 1, $user->rights->hrm->all->write); + $newmenu->add("/hrm/skill_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("List"), 1, $user->rights->hrm->all->read); + + // Job + $newmenu->add("/hrm/job_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("Job"), 0, $user->rights->hrm->all->read, '', $mainmenu, 'hrm', 0, '', '', '', img_picto('', 'technic', 'class="pictofixedwidth"')); + $newmenu->add("/hrm/job_card.php?mainmenu=hrm&leftmenu=hrm&action=create", $langs->transnoentities("NewObject", $langs->trans("Job")), 1, $user->rights->hrm->all->write); + $newmenu->add("/hrm/job_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("List"), 1, $user->rights->hrm->all->read); + + // Position + $newmenu->add("/hrm/position_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("Position"), 0, $user->rights->hrm->all->read, '', $mainmenu, 'hrm', 0, '', '', '', img_picto('', 'user-cog', 'class="pictofixedwidth"')); + $newmenu->add("/hrm/position_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("List"), 1, $user->rights->hrm->all->read); + + // Evaluation + $newmenu->add("/hrm/evaluation_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("Eval"), 0, $user->rights->hrm->evaluation->read, '', $mainmenu, 'hrm', 0, '', '', '', img_picto('', 'user', 'class="pictofixedwidth"')); + $newmenu->add("/hrm/evaluation_card.php?mainmenu=hrm&leftmenu=hrm&action=create", $langs->trans("NewEval"), 1, $user->rights->hrm->evaluation->write); + $newmenu->add("/hrm/evaluation_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("List"), 1, $user->rights->hrm->evaluation->read); + $newmenu->add("/hrm/compare.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("Compare"), 1, $user->rights->hrm->compare->read); + } } diff --git a/htdocs/core/modules/hrm/mod_evaluation_advanced.php b/htdocs/core/modules/hrm/mod_evaluation_advanced.php new file mode 100644 index 00000000000..0468c9ebb30 --- /dev/null +++ b/htdocs/core/modules/hrm/mod_evaluation_advanced.php @@ -0,0 +1,148 @@ + + * Copyright (C) 2004-2007 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2008 Raphael Bertrand (Resultic) + * Copyright (C) 2019 Frédéric France + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see https://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/hrm/mod_evaluation_advanced.php + * \ingroup hrm + * \brief File containing class for advanced numbering model of Evaluation + */ + +dol_include_once('/core/modules/hrm/modules_evaluation.php'); + + +/** + * Class to manage customer Bom numbering rules advanced + */ +class mod_evaluation_advanced extends ModeleNumRefEvaluation +{ + /** + * Dolibarr version of the loaded document + * @var string + */ + public $version = 'dolibarr'; // 'development', 'experimental', 'dolibarr' + + /** + * @var string Error message + */ + public $error = ''; + + /** + * @var string name + */ + public $name = 'advanced'; + + + /** + * Returns the description of the numbering model + * + * @return string Texte descripif + */ + public function info() + { + global $conf, $langs, $db; + + $langs->load("bills"); + + $form = new Form($db); + + $texte = $langs->trans('GenericNumRefModelDesc')."
    \n"; + $texte .= '
    '; + $texte .= ''; + $texte .= ''; + $texte .= ''; + $texte .= ''; + + $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Evaluation"), $langs->transnoentities("Evaluation")); + $tooltip .= $langs->trans("GenericMaskCodes2"); + $tooltip .= $langs->trans("GenericMaskCodes3"); + $tooltip .= $langs->trans("GenericMaskCodes4a", $langs->transnoentities("Evaluation"), $langs->transnoentities("Evaluation")); + $tooltip .= $langs->trans("GenericMaskCodes5"); + + // Parametrage du prefix + $texte .= ''; + $texte .= ''; + + $texte .= ''; + + $texte .= ''; + + $texte .= '
    '.$langs->trans("Mask").':'.$form->textwithpicto('', $tooltip, 1, 1).' 
    '; + $texte .= '
    '; + + return $texte; + } + + /** + * Return an example of numbering + * + * @return string Example + */ + public function getExample() + { + global $conf, $db, $langs, $mysoc; + + $object = new Evaluation($db); + $object->initAsSpecimen(); + + /*$old_code_client = $mysoc->code_client; + $old_code_type = $mysoc->typent_code; + $mysoc->code_client = 'CCCCCCCCCC'; + $mysoc->typent_code = 'TTTTTTTTTT';*/ + + $numExample = $this->getNextValue($object); + + /*$mysoc->code_client = $old_code_client; + $mysoc->typent_code = $old_code_type;*/ + + if (!$numExample) { + $numExample = $langs->trans('NotConfigured'); + } + return $numExample; + } + + /** + * Return next free value + * + * @param Object $object Object we need next value for + * @return string Value if KO, <0 if KO + */ + public function getNextValue($object) + { + global $db, $conf; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + + // We get cursor rule + $mask = $conf->global->HRM_EVALUATION_ADVANCED_MASK; + + if (!$mask) { + $this->error = 'NotConfigured'; + return 0; + } + + $date = $object->date; + + $numFinal = get_next_value($db, $mask, 'hrm_evaluation', 'ref', '', null, $date); + + return $numFinal; + } +} diff --git a/htdocs/core/modules/hrm/mod_evaluation_standard.php b/htdocs/core/modules/hrm/mod_evaluation_standard.php new file mode 100644 index 00000000000..4c5bb083870 --- /dev/null +++ b/htdocs/core/modules/hrm/mod_evaluation_standard.php @@ -0,0 +1,161 @@ + + * Copyright (C) 2005-2009 Regis Houssin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see https://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/hrm/mod_evaluation_standard.php + * \ingroup hrm + * \brief File of class to manage Evaluation numbering rules standard + */ +dol_include_once('/core/modules/hrm/modules_evaluation.php'); + + +/** + * Class to manage customer order numbering rules standard + */ +class mod_evaluation_standard extends ModeleNumRefEvaluation +{ + /** + * Dolibarr version of the loaded document + * @var string + */ + public $version = 'dolibarr'; // 'development', 'experimental', 'dolibarr' + + public $prefix = 'EVAL'; + + /** + * @var string Error code (or message) + */ + public $error = ''; + + /** + * @var string name + */ + public $name = 'standard'; + + + /** + * Return description of numbering module + * + * @return string Text with description + */ + public function info() + { + global $langs; + return $langs->trans("SimpleNumRefModelDesc", $this->prefix); + } + + + /** + * Return an example of numbering + * + * @return string Example + */ + public function getExample() + { + return $this->prefix."0501-0001"; + } + + + /** + * Checks if the numbers already in the database do not + * cause conflicts that would prevent this numbering working. + * + * @param Object $object Object we need next value for + * @return boolean false if conflict, true if ok + */ + public function canBeActivated($object) + { + global $conf, $langs, $db; + + $coyymm = ''; $max = ''; + + $posindice = strlen($this->prefix) + 6; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql .= " FROM ".MAIN_DB_PREFIX."hrm_evaluation"; + $sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'"; + if ($object->ismultientitymanaged == 1) { + $sql .= " AND entity = ".$conf->entity; + } elseif ($object->ismultientitymanaged == 2) { + // TODO + } + + $resql = $db->query($sql); + if ($resql) { + $row = $db->fetch_row($resql); + if ($row) { + $coyymm = substr($row[0], 0, 6); $max = $row[0]; + } + } + if ($coyymm && !preg_match('/'.$this->prefix.'[0-9][0-9][0-9][0-9]/i', $coyymm)) { + $langs->load("errors"); + $this->error = $langs->trans('ErrorNumRefModel', $max); + return false; + } + + return true; + } + + /** + * Return next free value + * + * @param Object $object Object we need next value for + * @return string Value if KO, <0 if KO + */ + public function getNextValue($object) + { + global $db, $conf; + + // first we get the max value + $posindice = strlen($this->prefix) + 6; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql .= " FROM ".MAIN_DB_PREFIX."hrm_evaluation"; + $sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'"; + if ($object->ismultientitymanaged == 1) { + $sql .= " AND entity = ".$conf->entity; + } elseif ($object->ismultientitymanaged == 2) { + // TODO + } + + $resql = $db->query($sql); + if ($resql) { + $obj = $db->fetch_object($resql); + if ($obj) { + $max = intval($obj->max); + } else { + $max = 0; + } + } else { + dol_syslog("mod_evaluation_standard::getNextValue", LOG_DEBUG); + return -1; + } + + //$date=time(); + $date = $object->date_creation; + $yymm = strftime("%y%m", $date); + + if ($max >= (pow(10, 4) - 1)) { + $num = $max + 1; // If counter > 9999, we do not format on 4 chars, we take number as it is + } else { + $num = sprintf("%04s", $max + 1); + } + + dol_syslog("mod_evaluation_standard::getNextValue return ".$this->prefix.$yymm."-".$num); + return $this->prefix.$yymm."-".$num; + } +} diff --git a/htdocs/core/modules/hrm/modules_evaluation.php b/htdocs/core/modules/hrm/modules_evaluation.php new file mode 100644 index 00000000000..36fc7e26d81 --- /dev/null +++ b/htdocs/core/modules/hrm/modules_evaluation.php @@ -0,0 +1,158 @@ + + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2004 Eric Seigne + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2006 Andre Cianfarani + * Copyright (C) 2012 Juanjo Menent + * Copyright (C) 2014 Marcos García + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see https://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/hrm/modules_evaluation.php + * \ingroup hrm + * \brief File that contains parent class for evaluations document models and parent class for evaluations numbering models + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/commondocgenerator.class.php'; +require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; // required for use by classes that inherit + + +/** + * Parent class for documents models + */ +abstract class ModelePDFEvaluation extends CommonDocGenerator +{ + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return list of active generation modules + * + * @param DoliDB $db Database handler + * @param integer $maxfilenamelength Max length of value to show + * @return array List of templates + */ + public static function liste_modeles($db, $maxfilenamelength = 0) + { + // phpcs:enable + global $conf; + + $type = 'evaluation'; + $list = array(); + + include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + $list = getListOfModels($db, $type, $maxfilenamelength); + + return $list; + } +} + + + +/** + * Parent class to manage numbering of Evaluation + */ +abstract class ModeleNumRefEvaluation +{ + /** + * @var string Error code (or message) + */ + public $error = ''; + + /** + * Return if a module can be used or not + * + * @return boolean true if module can be used + */ + public function isEnabled() + { + return true; + } + + /** + * Returns the default description of the numbering template + * + * @return string Texte descripif + */ + public function info() + { + global $langs; + $langs->load("hrm"); + return $langs->trans("NoDescription"); + } + + /** + * Returns an example of numbering + * + * @return string Example + */ + public function getExample() + { + global $langs; + $langs->load("hrm"); + return $langs->trans("NoExample"); + } + + /** + * Checks if the numbers already in the database do not + * cause conflicts that would prevent this numbering working. + * + * @param Object $object Object we need next value for + * @return boolean false if conflict, true if ok + */ + public function canBeActivated($object) + { + return true; + } + + /** + * Returns next assigned value + * + * @param Object $object Object we need next value for + * @return string Valeur + */ + public function getNextValue($object) + { + global $langs; + return $langs->trans("NotAvailable"); + } + + /** + * Returns version of numbering module + * + * @return string Valeur + */ + public function getVersion() + { + global $langs; + $langs->load("admin"); + + if ($this->version == 'development') { + return $langs->trans("VersionDevelopment"); + } + if ($this->version == 'experimental') { + return $langs->trans("VersionExperimental"); + } + if ($this->version == 'dolibarr') { + return DOL_VERSION; + } + if ($this->version) { + return $this->version; + } + return $langs->trans("NotAvailable"); + } +} diff --git a/htdocs/core/modules/modHRM.class.php b/htdocs/core/modules/modHRM.class.php index a50b06201a2..b7c4f3309f3 100644 --- a/htdocs/core/modules/modHRM.class.php +++ b/htdocs/core/modules/modHRM.class.php @@ -46,82 +46,219 @@ class modHRM extends DolibarrModules $this->module_position = '50'; // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) $this->name = preg_replace('/^mod/i', '', get_class($this)); - $this->description = "Management of employees carrier and feelings (department, employment contract)"; + // Module description, used if translation string 'ModulehrmDesc' not found (hrm is name of module). + $this->description = "hrm Description product "; + // Used only if file README.md and README-LL.md not found. + $this->descriptionlong = "hrm Description long"; - // Possible values for version are: 'development', 'experimental', 'dolibarr' or version - $this->version = 'experimental'; + // Author + $this->editor_name = 'Editor name'; + $this->editor_url = 'https://www.example.com'; + // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' + $this->version = '1.0'; + // Url to the file with your last numberversion of this module + //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; + + // Key used in llx_const table to save module status enabled/disabled (where HRMTEST is value of property name of module in uppercase) $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + // Name of image file used for this module. // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' + // To use a supported fa-xxx css style of font awesome, use this->picto='xxx' $this->picto = 'hrm'; - // define triggers - $this->module_parts = array(); + // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) + $this->module_parts = array( + // Set this to 1 if module has its own trigger directory (core/triggers) + 'triggers' => 0, + // Set this to 1 if module has its own login method file (core/login) + 'login' => 0, + // Set this to 1 if module has its own substitution function file (core/substitutions) + 'substitutions' => 0, + // Set this to 1 if module has its own menus handler directory (core/menus) + 'menus' => 0, + // Set this to 1 if module overwrite template dir (core/tpl) + 'tpl' => 1, + // Set this to 1 if module has its own barcode directory (core/modules/barcode) + 'barcode' => 0, + // Set this to 1 if module has its own models directory (core/modules/xxx) + 'models' => 1, + // Set this to 1 if module has its own printing directory (core/modules/printing) + 'printing' => 0, + // Set this to 1 if module has its own theme directory (theme) + 'theme' => 0, + // Set this to relative path of css file if module has its own css file + 'css' => array( + '/hrm/css/radio_js_number.css', + ), + // Set this to relative path of js file if module must load a js on all pages + 'js' => array( + // '/hrm/js/hrm.js.php', + ), - // Data directories to create when module is enabled - $this->dirs = array(); + // Set this to 1 if features of module are opened to external users + 'moduleforexternal' => 0, + ); - // Config pages - $this->config_page_url = array('admin_hrm.php@hrm'); + // Data directories to create when module is enabled. + // Example: this->dirs = array("/hrm/temp","/hrm/subdir"); + $this->dirs = array("/hrm/temp"); + + // Config pages. Put here list of php page, stored into hrm/admin directory, to use to setup module. + $this->config_page_url = array("hrm.php"); // Dependencies - $this->hidden = false; // A condition to hide module - $this->depends = array(); // List of module class names as string that must be enabled if this module is enabled - $this->requiredby = array(/*"modSalaries, modExpenseReport, modHoliday"*/); // List of module ids to disable if this one is disabled - $this->conflictwith = array(); // List of module class names as string this module is in conflict with - $this->phpmin = array(5, 6); // Minimum version of PHP required by module - $this->need_dolibarr_version = array(3, 9); // Minimum version of Dolibarr required by module + // A condition to hide module + $this->hidden = false; + // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...) + $this->depends = array(); + $this->requiredby = array(); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...) + $this->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...) + + // The language file dedicated to your module $this->langfiles = array("hrm"); + // Prerequisites + $this->phpmin = array(5, 6); // Minimum version of PHP required by module + $this->need_dolibarr_version = array(11, -3); // Minimum version of Dolibarr required by module + + // Messages at activation + $this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...) + $this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...) + //$this->automatic_activation = array('FR'=>'HrmTestWasAutomaticallyActivatedBecauseOfYourCountryChoice'); + //$this->always_enabled = true; // If true, can't be disabled + + // Constants + // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) + // Example: $this->const=array(1 => array('HRMTEST_MYNEWCONST1', 'chaine', 'myvalue', 'This is a constant to add', 1), + // 2 => array('HRMTEST_MYNEWCONST2', 'chaine', 'myvalue', 'This is another constant to add', 0, 'current', 1) + // ); + $this->const = array(); + + + if (!isset($conf->hrm) || !isset($conf->hrm->enabled)) { + $conf->hrm = new stdClass(); + $conf->hrm->enabled = 0; + } + + // Array to add new pages in new tabs + $this->tabs = array(); + $this->tabs[] = array('data'=>'user:+skill_tab:Skills:hrm:1:/hrm/skill_tab.php?id=__ID__&objecttype=user'); // To add a new tab identified by code tabname1 + //$this->tabs[] = array('data'=>'job:+tabname1:Poste:mylangfile@hrm:1:/hrm/poste_list.php?fk_job=__ID__'); // To add a new tab identified by code tabname1 + // Example: + // $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@hrm:$user->rights->hrm->read:/hrm/mynewtab1.php?id=__ID__'); // To add a new tab identified by code tabname1 + // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@hrm:$user->rights->othermodule->read:/hrm/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key. + // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname + // + // Where objecttype can be + // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) + // 'contact' to add a tab in contact view + // 'contract' to add a tab in contract view + // 'group' to add a tab in group view + // 'intervention' to add a tab in intervention view + // 'invoice' to add a tab in customer invoice view + // 'invoice_supplier' to add a tab in supplier invoice view + // 'member' to add a tab in fundation member view + // 'opensurveypoll' to add a tab in opensurvey poll view + // 'order' to add a tab in customer order view + // 'order_supplier' to add a tab in supplier order view + // 'payment' to add a tab in payment view + // 'payment_supplier' to add a tab in supplier payment view + // 'product' to add a tab in product view + // 'propal' to add a tab in propal view + // 'project' to add a tab in project view + // 'stock' to add a tab in stock view + // 'thirdparty' to add a tab in third party view + // 'user' to add a tab in user view + + // Dictionaries $this->dictionaries = array(); - // Constantes - $this->const = array(); + // Boxes/Widgets + // Add here list of php file(s) stored in hrm/core/boxes that contains a class to show a widget. + $this->boxes = array( + // 0 => array( + // 'file' => 'hrmwidget1.php@hrm', + // 'note' => 'Widget provided by HrmTest', + // 'enabledbydefaulton' => 'Home', + // ), + // ... + ); + + // Cronjobs (List of cron jobs entries to add when module is enabled) + // unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week + $this->cronjobs = array( + // 0 => array( + // 'label' => 'MyJob label', + // 'jobtype' => 'method', + // 'class' => '/hrm/class/poste.class.php', + // 'objectname' => 'Poste', + // 'method' => 'doScheduledJob', + // 'parameters' => '', + // 'comment' => 'Comment', + // 'frequency' => 2, + // 'unitfrequency' => 3600, + // 'status' => 0, + // 'test' => '$conf->hrm->enabled', + // 'priority' => 50, + // ), + ); + + // Permissions provided by this module + $this->rights = array(); $r = 0; + // Add here entries to declare new permissions + /* BEGIN MODULEBUILDER PERMISSIONS */ - // Boxes - $this->boxes = array(); - - // Permissions - $this->rights = array(); // Permission array used by this module - $r = 0; - - /* - $this->rights[$r][0] = 4001; - $this->rights[$r][1] = 'See employees'; - $this->rights[$r][3] = 0; - $this->rights[$r][4] = 'employee'; - $this->rights[$r][5] = 'read'; + // Skill / Job / Position + $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) + $this->rights[$r][1] = $langs->trans('ReadSkillJobPosition'); // Permission label + $this->rights[$r][4] = 'all'; + $this->rights[$r][5] = 'read'; // In php code, permission will be checked by test if ($user->rights->hrm->poste->read) + $r++; + $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) + $this->rights[$r][1] = $langs->trans('CreateUpdateSkillJobPosition'); // Permission label + $this->rights[$r][4] = 'all'; + $this->rights[$r][5] = 'write'; // In php code, permission will be checked by test if ($user->rights->hrm->poste->write) + $r++; + $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) + $this->rights[$r][1] = $langs->trans('DeleteSkillJobPosition'); // Permission label + $this->rights[$r][4] = 'all'; + $this->rights[$r][5] = 'delete'; // In php code, permission will be checked by test if ($user->rights->hrm->poste->delete) $r++; - $this->rights[$r][0] = 4002; - $this->rights[$r][1] = 'Create employees'; - $this->rights[$r][3] = 0; - $this->rights[$r][4] = 'employee'; - $this->rights[$r][5] = 'write'; + //Eval + $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) + $this->rights[$r][1] = $langs->trans('ReadEval'); // Permission label + $this->rights[$r][4] = 'evaluation'; + $this->rights[$r][5] = 'read'; // In php code, permission will be checked by test if ($user->rights->hrm->poste->read) + $r++; + $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) + $this->rights[$r][1] = $langs->trans('CreateUpdateEval'); // Permission label + $this->rights[$r][4] = 'evaluation'; + $this->rights[$r][5] = 'write'; // In php code, permission will be checked by test if ($user->rights->hrm->poste->write) + $r++; + $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) + $this->rights[$r][1] = $langs->trans('ValidateEval'); // Permission label + $this->rights[$r][4] = 'evaluation'; + $this->rights[$r][5] = 'validate'; // In php code, permission will be checked by test if ($user->rights->hrm->poste->write) + $r++; + $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) + $this->rights[$r][1] = $langs->trans('DeleteEval'); // Permission label + $this->rights[$r][4] = 'evaluation'; + $this->rights[$r][5] = 'delete'; // In php code, permission will be checked by test if ($user->rights->hrm->poste->delete) $r++; - $this->rights[$r][0] = 4003; - $this->rights[$r][1] = 'Delete employees'; - $this->rights[$r][3] = 0; - $this->rights[$r][4] = 'employee'; - $this->rights[$r][5] = 'delete'; + // Comparison + $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) + $this->rights[$r][1] = $langs->trans('SeeComparisonMenu'); // Permission label + $this->rights[$r][4] = 'compare'; + $this->rights[$r][5] = 'read'; // In php code, permission will be checked by test if ($user->rights->hrm->poste->delete) $r++; - $this->rights[$r][0] = 4004; - $this->rights[$r][1] = 'Export employees'; - $this->rights[$r][3] = 0; - $this->rights[$r][4] = 'employee'; - $this->rights[$r][5] = 'export'; - $r++; - */ - - // Menus - //------- - $this->menu = 1; // This module add menu entries. They are coded into menu manager. } /** @@ -138,6 +275,11 @@ class modHRM extends DolibarrModules // Permissions $this->remove($options); + /*$result = $this->_load_tables('/hrm/sql/'); + if ($result < 0) { + return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default') + }*/ + $sql = array(); return $this->_init($sql, $options); diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php new file mode 100644 index 00000000000..354b909d256 --- /dev/null +++ b/htdocs/hrm/class/evaluation.class.php @@ -0,0 +1,1182 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file class/evaluation.class.php + * \ingroup hrm + * \brief This file is a CRUD class file for Evaluation (Create/Read/Update/Delete) + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +dol_include_once('hrm/class/evaluationdet.class.php'); +//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; + +/** + * Class for Evaluation + */ +class Evaluation extends CommonObject +{ + /** + * @var string ID of module. + */ + public $module = 'hrm'; + + /** + * @var string ID to identify managed object. + */ + public $element = 'evaluation'; + + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. + */ + public $table_element = 'hrm_evaluation'; + + /** + * @var int Does this object support multicompany module ? + * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table + */ + public $ismultientitymanaged = 0; + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + + /** + * @var string String with name of icon for evaluation. Must be the part after the 'object_' into object_evaluation.png + */ + public $picto = 'label'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CANCELED = 9; + const STATUS_CLOSED = 2; + + + /** + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields=array( + 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"), + 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>4, 'noteditable'=>'1', 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'showoncombobox'=>'1', 'comment'=>"Reference of object"), + 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1, 'searchall'=>1, 'css'=>'minwidth300', 'cssview'=>'wordbreak', 'showoncombobox'=>'2',), + 'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>'1', 'position'=>60, 'notnull'=>0, 'visible'=>3,), + 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>61, 'notnull'=>0, 'visible'=>0,), + 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>'1', 'position'=>62, 'notnull'=>0, 'visible'=>0,), + 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>500, 'notnull'=>1, 'visible'=>-2,), + 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>'1', 'position'=>501, 'notnull'=>0, 'visible'=>-2,), + 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',), + 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>'1', 'position'=>511, 'notnull'=>-1, 'visible'=>-2,), + 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>'1', 'position'=>1000, 'notnull'=>-1, 'visible'=>-2,), + 'status' => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>'1', 'position'=>1000, 'notnull'=>1, 'default'=>0, 'visible'=>5, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Brouillon', '1'=>'Validé'),), + 'date_eval' => array('type'=>'date', 'label'=>'DateEval', 'enabled'=>'1', 'position'=>502, 'notnull'=>1, 'visible'=>1,), + 'fk_user' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'User', 'enabled'=>'1', 'position'=>504, 'notnull'=>1, 'visible'=>1,), + 'fk_job' => array('type'=>'integer:Job:/hrm/class/job.class.php', 'label'=>'Job', 'enabled'=>'1', 'position'=>505, 'notnull'=>1, 'visible'=>1,), + ); + public $rowid; + public $ref; + public $label; + public $description; + public $note_public; + public $note_private; + public $date_creation; + public $tms; + public $fk_user_creat; + public $fk_user_modif; + public $import_key; + public $status; + public $date_eval; + public $fk_user; + public $fk_job; + // END MODULEBUILDER PROPERTIES + + + // If this object has a subtable with lines + + /** + * @var string Name of subtable line + */ + public $table_element_line = 'hrm_evaluationdet'; + + /** + * @var string Field with ID of parent key if this object has a parent + */ + public $fk_element = 'fk_evaluation'; + + /** + * @var string Name of subtable class that manage subtable lines + */ + public $class_element_line = 'Evaluationdet'; + + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + // protected $childtables = array(); + + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + protected $childtablesoncascade = array('@Evaluationdet:hrm/class/evaluationdet.class.php:fk_evaluation'); + + /** + * @var Evaluationdet[] Array of subtable lines + */ + public $lines = array(); + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs; + + $this->db = $db; + + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { + $this->fields['rowid']['visible'] = 0; + } + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { + $this->fields['entity']['enabled'] = 0; + } + + $this->date_eval = dol_now(); + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $notrigger = false) + { + $resultcreate = $this->createCommon($user, $notrigger); + + if ($resultcreate > 0) { + dol_include_once('hrm/class/skillrank.class.php'); + $skillRank = new SkillRank($this->db); + $TRequiredRanks = $skillRank->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object='.$this->fk_job.' AND objecttype="job"')); + + if (is_array($TRequiredRanks) && !empty($TRequiredRanks)) { + $this->lines = array(); + foreach ($TRequiredRanks as $required) { + $line = new Evaluationdet($this->db); + $line->fk_evaluation = $resultcreate; + $line->fk_skill = $required->fk_skill; + $line->required_rank = $required->rank; + $line->fk_rank = 0; + + $res = $line->create($user, $notrigger); + if ($res > 0) $this->lines[] = $line; + } + } + } + + return $resultcreate; + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return mixed New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $result = $object->fetchCommon($fromid); + if ($result > 0 && !empty($object->table_element_line)) { + $object->fetchLines(); + } + + // get lines so they will be clone + //foreach($this->lines as $line) + // $line->fetch_optionals(); + + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + if (property_exists($object, 'ref')) { + $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; + } + if (property_exists($object, 'label')) { + $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; + } + if (property_exists($object, 'status')) { + $object->status = self::STATUS_DRAFT; + } + if (property_exists($object, 'date_creation')) { + $object->date_creation = dol_now(); + } + if (property_exists($object, 'date_modification')) { + $object->date_modification = null; + } + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->table_element); + foreach ($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->error = $object->error; + $this->errors = $object->errors; + } + + if (!$error) { + // copy internal contacts + if ($this->copy_linked_contact($object, 'internal') < 0) { + $error++; + } + } + + if (!$error) { + // copy external contacts if same company + if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + if ($this->copy_linked_contact($object, 'external') < 0) { + $error++; + } + } + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $ref = null) + { + $result = $this->fetchCommon($id, $ref); + if ($result > 0 && !empty($this->table_element_line)) { + $this->fetchLines(); + } + return $result; + } + + /** + * Load object lines in memory from the database + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetchLines() + { + $this->lines = array(); + + $objectlineclassname = get_class($this).'det'; + if (!class_exists($objectlineclassname)) { + $this->error = 'Error, class '.$objectlineclassname.' not found during call of fetchLinesCommon'; + return -1; + } + + $objectline = new $objectlineclassname($this->db); + + $sql = 'SELECT '.$objectline->getFieldList('l'); + $sql .= ' FROM '.MAIN_DB_PREFIX.$objectline->table_element.' as l'; + $sql .= ' WHERE l.fk_'.$this->element.' = '.$this->id; + if (isset($objectline->fields['position'])) { + $sql .= $this->db->order('position', 'ASC'); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num_rows = $this->db->num_rows($resql); + $i = 0; + while ($i < $num_rows) { + $obj = $this->db->fetch_object($resql); + if ($obj) { + $newline = new $objectlineclassname($this->db); + $newline->setVarsFromFetchObj($obj); + + $this->lines[] = $newline; + } + $i++; + } + + return 1; + } else { + $this->error = $this->db->lasterror(); + $this->errors[] = $this->error; + return -1; + } + } + + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = 'SELECT '; + $sql .= $this->getFieldList('t'); + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')'; + } else { + $sql .= ' WHERE 1 = 1'; + } + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid') { + $sqlwhere[] = $key.'='.$value; + } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) { + $sqlwhere[] = $key.' = \''.$this->db->idate($value).'\''; + } elseif ($key == 'customsql') { + $sqlwhere[] = $value; + } elseif (strpos($value, '%') === false) { + $sqlwhere[] = $key.' IN ('.$this->db->sanitize($this->db->escape($value)).')'; + } else { + $sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' '.$this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) + { + return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + /** + * Delete a line of object in database + * + * @param User $user User that delete + * @param int $idline Id of line to delete + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int >0 if OK, <0 if KO + */ + public function deleteLine(User $user, $idline, $notrigger = false) + { + if ($this->status < 0) { + $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; + return -2; + } + + return $this->deleteLineCommon($user, $idline, $notrigger); + } + + + /** + * Validate object + * + * @param User $user User making status change + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf, $langs; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING); + return 0; + } + + + + $now = dol_now(); + + $this->db->begin(); + + // Define new ref + if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life + $num = $this->getNextNumRef(); + } else { + $num = $this->ref; + } + $this->newref = $num; + + if (!empty($num)) { + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " SET ref = '".$this->db->escape($num)."',"; + $sql .= " status = ".self::STATUS_VALIDATED; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation = '".$this->db->idate($now)."'"; + } + if (!empty($this->fields['fk_user_valid'])) { + $sql .= ", fk_user_valid = ".((int) $user->id); + } + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog(get_class($this)."::validate()", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + dol_print_error($this->db); + $this->error = $this->db->lasterror(); + $error++; + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('EVALUATION_VALIDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + if (!$error) { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) { + // Now we rename also files into index + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'evaluation/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'evaluation/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; $this->error = $this->db->lasterror(); + } + + // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->hrm->dir_output.'/evaluation/'.$oldref; + $dirdest = $conf->hrm->dir_output.'/evaluation/'.$newref; + if (!$error && file_exists($dirsource)) { + dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->hrm->dir_output.'/evaluation/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); + foreach ($listoffiles as $fileentry) { + $dirsource = $fileentry['name']; + $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); + $dirsource = $fileentry['path'].'/'.$dirsource; + $dirdest = $fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + } + + // Set new ref and current status + if (!$error) { + $this->ref = $num; + $this->status = self::STATUS_VALIDATED; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Get the last evaluation by date for the user assigned + * + * @param int $fk_user ID of user we need to get last eval + * @return Evaluation|null + */ + public static function getLastEvaluationForUser($fk_user) + { + global $db; + + + $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."hrm_evaluation "; + $sql.= "WHERE fk_user=".$fk_user." "; + $sql.= "ORDER BY date_eval DESC "; + $sql.= "LIMIT 1 "; + + $res = $db->query($sql); + if (!$res) { dol_print_error($db);} + + $Tab = $db->fetch_object($res); + + if (empty($Tab)) return null; + else { + $evaluation = new Evaluation($db); + $evaluation->fetch($Tab->rowid); + + return $evaluation; + } + } + + + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->status <= self::STATUS_DRAFT) { + return 0; + } + + + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'EVALUATION_UNVALIDATE'); + } + + /** + * Set cancel status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function cancel($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_VALIDATED) { + return 0; + } + + + + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'EVALUATION_CANCEL'); + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_CANCELED) { + return 0; + } + + + + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'EVALUATION_REOPEN'); + } + + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $conf, $langs, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) { + $notooltip = 1; // Force disable tooltips + } + + $result = ''; + + $label = img_picto('', $this->picto).' '.$langs->trans("Evaluation").''; + if (isset($this->status)) { + $label .= ' '.$this->getLibStatut(5); + } + $label .= '
    '; + $label .= ''.$langs->trans('Ref').': '.$this->ref; + + $url = dol_buildpath('/hrm/evaluation_card.php', 1).'?id='.$this->id; + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values = 1; + } + if ($add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkclose = ''; + if (empty($notooltip)) { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { + $label = $langs->trans("ShowEvaluation"); + $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"'; + } else { + $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); + } + + if ($option == 'nolink') { + $linkstart = ''; + if ($option == 'nolink') { + $linkend = ''; + } else { + $linkend = ''; + } + + $result .= $linkstart; + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); + if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) { + $result .= '
    No photo
    '; + } else { + $result .= '
    No photo
    '; + } + + $result .= ''; + } else { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } + } + + if ($withpicto != 2) { + $result .= $this->ref; + } + + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action, $hookmanager; + $hookmanager->initHooks(array('evaluationdao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("hrm"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Validated'); + $this->labelStatus[self::STATUS_CLOSED] = $langs->trans('Closed'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Validated'); + $this->labelStatus[self::STATUS_CLOSED] = $langs->trans('Closed'); + } + + $statusType = 'status'.$status; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = 'SELECT rowid, date_creation as datec, tms as datem,'; + $sql .= ' fk_user_creat, fk_user_modif'; + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + $sql .= ' WHERE t.rowid = '.((int) $id); + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_valid) { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); + } + + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + + $this->initAsSpecimenCommon(); + } + + /** + * Create an array of lines + * + * @return array|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + $objectline = new Evaluationdet($this->db); + $result = $objectline->fetchAll('ASC', '', 0, 0, array('customsql'=>'fk_evaluation = '.$this->id)); + + if (is_numeric($result)) { + $this->error = $this->error; + $this->errors = $this->errors; + return $result; + } else { + $this->lines = $result; + return $this->lines; + } + } + + /** + * Returns the reference to the following non used object depending on the active numbering module. + * + * @return string Object free reference + */ + public function getNextNumRef() + { + global $langs, $conf; + $langs->load("hrm"); + + if (empty($conf->global->HRMTEST_EVALUATION_ADDON)) { + $conf->global->HRMTEST_EVALUATION_ADDON = 'mod_evaluation_standard'; + } + + if (!empty($conf->global->HRMTEST_EVALUATION_ADDON)) { + $mybool = false; + + $file = $conf->global->HRMTEST_EVALUATION_ADDON.".php"; + $classname = $conf->global->HRMTEST_EVALUATION_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/hrm/"); + + // Load file with numbering class (if found) + $mybool |= @include_once $dir.$file; + } + + if ($mybool === false) { + dol_print_error('', "Failed to include file ".$file); + return ''; + } + + if (class_exists($classname)) { + $obj = new $classname(); + $numref = $obj->getNextValue($this); + + if ($numref != '' && $numref != '-1') { + return $numref; + } else { + $this->error = $obj->error; + //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } else { + print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname; + return ""; + } + } else { + print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); + return ""; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force template to use ('' to not force) + * @param Translate $outputlangs objet lang a utiliser pour traduction + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @param null|array $moreparams Array to provide more information + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) + { + global $conf, $langs; + + $result = 0; + $includedocgeneration = 0; + + $langs->load("hrm"); + + if (!dol_strlen($modele)) { + $modele = 'standard_evaluation'; + + if (!empty($this->model_pdf)) { + $modele = $this->model_pdf; + } elseif (!empty($conf->global->EVALUATION_ADDON_PDF)) { + $modele = $conf->global->EVALUATION_ADDON_PDF; + } + } + + $modelpath = "core/modules/hrm/doc/"; + + if ($includedocgeneration && !empty($modele)) { + $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + } + + return $result; + } + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + public function doScheduledJob() + { + global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log'; + + $error = 0; + $this->output = ''; + $this->error = ''; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + return $error; + } + + /** + * @param string $action + * @param int $selected + */ +// public function printObjectLines($action, $selected = 0) +// { +// global $conf, $hookmanager, $langs, $user, $extrafields, $object; +// // TODO We should not use global var for this +// global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax; +// +// // Define usemargins +//// $usemargins = 0; +//// if (!empty($conf->margin->enabled) && !empty($this->element) && in_array($this->element, array('facture', 'facturerec', 'propal', 'commande'))) { +//// $usemargins = 1; +//// } +// +// $num = count($this->lines); +// +// // Line extrafield +// if (!is_object($extrafields)) { +// require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; +// $extrafields = new ExtraFields($this->db); +// } +// $extrafields->fetch_name_optionals_label($this->table_element_line); +// +// $parameters = array('num'=>$num, 'selected'=>$selected, 'table_element_line'=>$this->table_element_line); +// $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks +// if (empty($reshook)) { +// // Output template part (modules that overwrite templates must declare this into descriptor) +// // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook. +// include dol_buildpath('hrm/core/tpl/objectline_title.tpl.php'); +// } +// +// $i = 0; +// +// print "\n"; +// foreach ($this->lines as $line) { +// //Line extrafield +// $line->fetch_optionals(); +// +// //if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line))) +// if (is_object($hookmanager)) { // Old code is commented on preceding line. +// if (empty($line->fk_parent_line)) { +// $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'selected'=>$selected, 'table_element_line'=>$line->table_element); +// $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks +// } else { +// $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'selected'=>$selected, 'table_element_line'=>$line->table_element, 'fk_parent_line'=>$line->fk_parent_line); +// $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks +// } +// } +// if (empty($reshook)) { +// $this->printObjectLine($action, $line); +// } +// +// $i++; +// } +// print "\n"; +// } + +// public function printObjectLine($action, $line) +// { +// global $conf, $langs, $user, $object, $hookmanager; +// global $form; +// global $object_rights, $disableedit, $disablemove, $disableremove; // TODO We should not use global var for this ! +// +// $object_rights = $this->getRights(); +// +// $element = $this->element; +// +// $text = ''; +// $description = ''; +// +// include dol_buildpath('hrm/tpl/objectline_view.tpl.php'); +// } +} diff --git a/htdocs/hrm/class/evaluationdet.class.php b/htdocs/hrm/class/evaluationdet.class.php new file mode 100644 index 00000000000..0c591a3a374 --- /dev/null +++ b/htdocs/hrm/class/evaluationdet.class.php @@ -0,0 +1,1069 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file class/evaluationdet.class.php + * \ingroup hrm + * \brief This file is a CRUD class file for Evaluationdet (Create/Read/Update/Delete) + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +dol_include_once('hrm/class/skillrank.class.php'); +//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; + +/** + * Class for Evaluationdet + */ +class Evaluationdet extends CommonObject +{ + /** + * @var string ID of module. + */ + public $module = 'hrm'; + + /** + * @var string ID to identify managed object. + */ + public $element = 'evaluationdet'; + + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. + */ + public $table_element = 'hrm_evaluationdet'; + + /** + * @var int Does this object support multicompany module ? + * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table + */ + public $ismultientitymanaged = 0; + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + + /** + * @var string String with name of icon for evaluationdet. Must be the part after the 'object_' into object_evaluationdet.png + */ + public $picto = 'evaluationdet@hrm'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CANCELED = 9; + + + /** + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields=array( + 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"), + 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>500, 'notnull'=>1, 'visible'=>-2,), + 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>'1', 'position'=>501, 'notnull'=>0, 'visible'=>-2,), + 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',), + 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>'1', 'position'=>511, 'notnull'=>-1, 'visible'=>-2,), + 'fk_skill' => array('type'=>'integer:Skill:hrm/class/skill.class.php:1', 'label'=>'Skill', 'enabled'=>'1', 'position'=>3, 'notnull'=>1, 'visible'=>1, 'index'=>1,), + 'fk_evaluation' => array('type'=>'integer:Evaluation:hrm/class/evaluation.class.php:1', 'label'=>'Evaluation', 'enabled'=>'1', 'position'=>3, 'notnull'=>1, 'visible'=>1, 'index'=>1,), + 'rank' => array('type'=>'integer', 'label'=>'Rank', 'enabled'=>'1', 'position'=>4, 'notnull'=>1, 'visible'=>1,), + 'required_rank' => array('type'=>'integer', 'label'=>'requiredRank', 'enabled'=>'1', 'position'=>5, 'notnull'=>1, 'visible'=>1,), + 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>'1', 'position'=>1000, 'notnull'=>-1, 'visible'=>-2,), + ); + public $rowid; + public $date_creation; + public $tms; + public $fk_user_creat; + public $fk_user_modif; + public $fk_skill; + public $fk_evaluation; + public $fk_rank; + public $required_rank; + public $import_key; + // END MODULEBUILDER PROPERTIES + + + // If this object has a subtable with lines + + // /** + // * @var string Name of subtable line + // */ + // public $table_element_line = 'hrm_evaluationdetline'; + + // /** + // * @var string Field with ID of parent key if this object has a parent + // */ + // public $fk_element = 'fk_evaluationdet'; + + // /** + // * @var string Name of subtable class that manage subtable lines + // */ + // public $class_element_line = 'Evaluationdetline'; + + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + // protected $childtables = array(); + + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + // protected $childtablesoncascade = array('hrm_evaluationdetdet'); + + // /** + // * @var EvaluationdetLine[] Array of subtable lines + // */ + // public $lines = array(); + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs; + + $this->db = $db; + + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { + $this->fields['rowid']['visible'] = 0; + } + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { + $this->fields['entity']['enabled'] = 0; + } + + // Example to show how to set values of fields definition dynamically + /*if ($user->rights->hrm->evaluationdet->read) { + $this->fields['myfield']['visible'] = 1; + $this->fields['myfield']['noteditable'] = 0; + }*/ + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $notrigger = false) + { + $resultcreate = $this->createCommon($user, $notrigger); + + return $resultcreate; + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return mixed New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $result = $object->fetchCommon($fromid); + if ($result > 0 && !empty($object->table_element_line)) { + $object->fetchLines(); + } + + // get lines so they will be clone + //foreach($this->lines as $line) + // $line->fetch_optionals(); + + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + if (property_exists($object, 'ref')) { + $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; + } + if (property_exists($object, 'label')) { + $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; + } + if (property_exists($object, 'status')) { + $object->status = self::STATUS_DRAFT; + } + if (property_exists($object, 'date_creation')) { + $object->date_creation = dol_now(); + } + if (property_exists($object, 'date_modification')) { + $object->date_modification = null; + } + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->table_element); + foreach ($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->error = $object->error; + $this->errors = $object->errors; + } + + if (!$error) { + // copy internal contacts + if ($this->copy_linked_contact($object, 'internal') < 0) { + $error++; + } + } + + if (!$error) { + // copy external contacts if same company + if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + if ($this->copy_linked_contact($object, 'external') < 0) { + $error++; + } + } + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $ref = null) + { + $result = $this->fetchCommon($id, $ref); + if ($result > 0 && !empty($this->table_element_line)) { + $this->fetchLines(); + } + return $result; + } + + /** + * Load object lines in memory from the database + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetchLines() + { + $this->lines = array(); + + $result = $this->fetchLinesCommon(); + return $result; + } + + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = 'SELECT '; + $sql .= $this->getFieldList('t'); + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')'; + } else { + $sql .= ' WHERE 1 = 1'; + } + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid') { + $sqlwhere[] = $key.'='.$value; + } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) { + $sqlwhere[] = $key.' = \''.$this->db->idate($value).'\''; + } elseif ($key == 'customsql') { + $sqlwhere[] = $value; + } elseif (strpos($value, '%') === false) { + $sqlwhere[] = $key.' IN ('.$this->db->sanitize($this->db->escape($value)).')'; + } else { + $sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' '.$this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) + { + if ($this->fk_rank) { + $skillRank = new SkillRank($this->db); + $skillRank->fetch($this->fk_rank); + $skillRank->delete($user, $notrigger); + } + return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + /** + * Delete a line of object in database + * + * @param User $user User that delete + * @param int $idline Id of line to delete + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int >0 if OK, <0 if KO + */ + public function deleteLine(User $user, $idline, $notrigger = false) + { + if ($this->status < 0) { + $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; + return -2; + } + + return $this->deleteLineCommon($user, $idline, $notrigger); + } + + + /** + * Validate object + * + * @param User $user User making status change + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf, $langs; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING); + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->evaluationdet->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->evaluationdet->evaluationdet_advance->validate)))) + { + $this->error='NotEnoughPermissions'; + dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); + return -1; + }*/ + + $now = dol_now(); + + $this->db->begin(); + + // Define new ref + if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life + $num = $this->getNextNumRef(); + } else { + $num = $this->ref; + } + $this->newref = $num; + + if (!empty($num)) { + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " SET ref = '".$this->db->escape($num)."',"; + $sql .= " status = ".self::STATUS_VALIDATED; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation = '".$this->db->idate($now)."'"; + } + if (!empty($this->fields['fk_user_valid'])) { + $sql .= ", fk_user_valid = ".((int) $user->id); + } + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog(get_class($this)."::validate()", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + dol_print_error($this->db); + $this->error = $this->db->lasterror(); + $error++; + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('EVALUATIONDET_VALIDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + if (!$error) { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) { + // Now we rename also files into index + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'evaluationdet/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'evaluationdet/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; $this->error = $this->db->lasterror(); + } + + // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->hrm->dir_output.'/evaluationdet/'.$oldref; + $dirdest = $conf->hrm->dir_output.'/evaluationdet/'.$newref; + if (!$error && file_exists($dirsource)) { + dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->hrm->dir_output.'/evaluationdet/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); + foreach ($listoffiles as $fileentry) { + $dirsource = $fileentry['name']; + $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); + $dirsource = $fileentry['path'].'/'.$dirsource; + $dirdest = $fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + } + + // Set new ref and current status + if (!$error) { + $this->ref = $num; + $this->status = self::STATUS_VALIDATED; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->status <= self::STATUS_DRAFT) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'EVALUATIONDET_UNVALIDATE'); + } + + /** + * Set cancel status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function cancel($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_VALIDATED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'EVALUATIONDET_CANCEL'); + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_CANCELED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'EVALUATIONDET_REOPEN'); + } + + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $conf, $langs, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) { + $notooltip = 1; // Force disable tooltips + } + + $result = ''; + + $label = img_picto('', $this->picto).' '.$langs->trans("Evaluationdet").''; + if (isset($this->status)) { + $label .= ' '.$this->getLibStatut(5); + } + $label .= '
    '; + $label .= ''.$langs->trans('Ref').': '.$this->ref; + + $url = dol_buildpath('/hrm/evaluationdet_card.php', 1).'?id='.$this->id; + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values = 1; + } + if ($add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkclose = ''; + if (empty($notooltip)) { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { + $label = $langs->trans("ShowEvaluationdet"); + $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"'; + } else { + $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); + } + + if ($option == 'nolink') { + $linkstart = ''; + if ($option == 'nolink') { + $linkend = ''; + } else { + $linkend = ''; + } + + $result .= $linkstart; + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); + if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) { + $result .= '
    No photo
    '; + } else { + $result .= '
    No photo
    '; + } + + $result .= ''; + } else { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } + } + + if ($withpicto != 2) { + $result .= $this->ref; + } + + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action, $hookmanager; + $hookmanager->initHooks(array('evaluationdetdao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("hrm"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatus[self::STATUS_CANCELED] = $langs->trans('Disabled'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Disabled'); + } + + $statusType = 'status'.$status; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = 'SELECT rowid, date_creation as datec, tms as datem,'; + $sql .= ' fk_user_creat, fk_user_modif'; + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + $sql .= ' WHERE t.rowid = '.((int) $id); + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_valid) { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); + } + + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + + $this->initAsSpecimenCommon(); + } + + /** + * Create an array of lines + * + * @return array|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + $objectline = new EvaluationdetLine($this->db); + $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_evaluationdet = '.$this->id)); + + if (is_numeric($result)) { + $this->error = $this->error; + $this->errors = $this->errors; + return $result; + } else { + $this->lines = $result; + return $this->lines; + } + } + + /** + * Returns the reference to the following non used object depending on the active numbering module. + * + * @return string Object free reference + */ + public function getNextNumRef() + { + global $langs, $conf; + $langs->load("hrm"); + + if (empty($conf->global->hrm_EVALUATIONDET_ADDON)) { + $conf->global->hrm_EVALUATIONDET_ADDON = 'mod_evaluationdet_standard'; + } + + if (!empty($conf->global->hrm_EVALUATIONDET_ADDON)) { + $mybool = false; + + $file = $conf->global->hrm_EVALUATIONDET_ADDON.".php"; + $classname = $conf->global->hrm_EVALUATIONDET_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/hrm/"); + + // Load file with numbering class (if found) + $mybool |= @include_once $dir.$file; + } + + if ($mybool === false) { + dol_print_error('', "Failed to include file ".$file); + return ''; + } + + if (class_exists($classname)) { + $obj = new $classname(); + $numref = $obj->getNextValue($this); + + if ($numref != '' && $numref != '-1') { + return $numref; + } else { + $this->error = $obj->error; + //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } else { + print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname; + return ""; + } + } else { + print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); + return ""; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force template to use ('' to not force) + * @param Translate $outputlangs objet lang a utiliser pour traduction + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @param null|array $moreparams Array to provide more information + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) + { + global $conf, $langs; + + $result = 0; + $includedocgeneration = 0; + + $langs->load("hrm"); + + if (!dol_strlen($modele)) { + $modele = 'standard_evaluationdet'; + + if (!empty($this->model_pdf)) { + $modele = $this->model_pdf; + } elseif (!empty($conf->global->EVALUATIONDET_ADDON_PDF)) { + $modele = $conf->global->EVALUATIONDET_ADDON_PDF; + } + } + + $modelpath = "core/modules/hrm/doc/"; + + if ($includedocgeneration && !empty($modele)) { + $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + } + + return $result; + } + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + public function doScheduledJob() + { + global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log'; + + $error = 0; + $this->output = ''; + $this->error = ''; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + return $error; + } +} + + +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php'; + +/** + * Class EvaluationdetLine. You can also remove this and generate a CRUD class for lines objects. + */ +class EvaluationdetLine extends CommonObjectLine +{ + // To complete with content of an object EvaluationdetLine + // We should have a field rowid, fk_evaluationdet and position + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 0; + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + $this->db = $db; + } +} diff --git a/htdocs/hrm/class/job.class.php b/htdocs/hrm/class/job.class.php new file mode 100644 index 00000000000..248e367b998 --- /dev/null +++ b/htdocs/hrm/class/job.class.php @@ -0,0 +1,1119 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file class/job.class.php + * \ingroup hrm + * \brief This file is a CRUD class file for Job (Create/Read/Update/Delete) + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; + +/** + * Class for Job + */ +class Job extends CommonObject +{ + /** + * @var string ID of module. + */ + public $module = 'hrm'; + + /** + * @var string ID to identify managed object. + */ + public $element = 'job'; + + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. + */ + public $table_element = 'hrm_job'; + + /** + * @var int Does this object support multicompany module ? + * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table + */ + public $ismultientitymanaged = 0; + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + + /** + * @var string String with name of icon for job. Must be the part after the 'object_' into object_job.png + */ + public $picto = 'technic'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CANCELED = 9; + + + /** + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields=array( + 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"), + 'label' => array('type'=>'varchar(128)', 'label'=>'Label', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1, 'index'=>1, 'searchall'=>1, 'showoncombobox'=>'1', 'comment'=>"Label of object"), + 'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>'1', 'position'=>21, 'notnull'=>0, 'visible'=>1,), + 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>500, 'notnull'=>1, 'visible'=>2,), + 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>'1', 'position'=>501, 'notnull'=>0, 'visible'=>2,), + 'deplacement' => array('type'=>'select', 'required'=> 1,'label'=> 'deplacement', 'enabled'=> 1, 'position'=> 90, 'notnull'=> 1, 'visible'=> 1, 'arrayofkeyval'=> array(0 =>"No", 1=>"Yes"), 'default'=>0), + 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>70, 'notnull'=>0, 'visible'=>0,), + 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>'1', 'position'=>71, 'notnull'=>0, 'visible'=>0,), + 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',), + 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>'1', 'position'=>511, 'notnull'=>-1, 'visible'=>-2,), + ); + public $rowid; + public $ref; + public $description; + public $date_creation; + public $tms; + public $deplacement; + public $note_public; + public $note_private; + public $fk_user_creat; + public $fk_user_modif; + // END MODULEBUILDER PROPERTIES + + + // If this object has a subtable with lines + + // /** + // * @var string Name of subtable line + // */ + // public $table_element_line = 'hrm_jobline'; + + // /** + // * @var string Field with ID of parent key if this object has a parent + // */ + public $fk_element = 'fk_job'; + + // /** + // * @var string Name of subtable class that manage subtable lines + // */ + // public $class_element_line = 'Jobline'; + + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + protected $childtables = array('hrm_evaluation', 'hrm_position'); + + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + // protected $childtablesoncascade = array('hrm_jobdet'); + + // /** + // * @var JobLine[] Array of subtable lines + // */ + // public $lines = array(); + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs; + + $this->db = $db; + + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { + $this->fields['rowid']['visible'] = 0; + } + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { + $this->fields['entity']['enabled'] = 0; + } + + // Example to show how to set values of fields definition dynamically + /*if ($user->rights->hrm->job->read) { + $this->fields['myfield']['visible'] = 1; + $this->fields['myfield']['noteditable'] = 0; + }*/ + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $notrigger = false) + { + $resultcreate = $this->createCommon($user, $notrigger); + + //$resultvalidate = $this->validate($user, $notrigger); + + return $resultcreate; + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return mixed New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $result = $object->fetchCommon($fromid); + if ($result > 0 && !empty($object->table_element_line)) { + $object->fetchLines(); + } + + // get lines so they will be clone + //foreach($this->lines as $line) + // $line->fetch_optionals(); + + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + if (property_exists($object, 'ref')) { + $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; + } + if (property_exists($object, 'label')) { + $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; + } + if (property_exists($object, 'status')) { + $object->status = self::STATUS_DRAFT; + } + if (property_exists($object, 'date_creation')) { + $object->date_creation = dol_now(); + } + if (property_exists($object, 'date_modification')) { + $object->date_modification = null; + } + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->table_element); + foreach ($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->error = $object->error; + $this->errors = $object->errors; + } + + if (!$error) { + // copy internal contacts + if ($this->copy_linked_contact($object, 'internal') < 0) { + $error++; + } + } + + if (!$error) { + // copy external contacts if same company + if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + if ($this->copy_linked_contact($object, 'external') < 0) { + $error++; + } + } + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $ref = null) + { + $result = $this->fetchCommon($id, $ref); + if ($result > 0 && !empty($this->table_element_line)) { + $this->fetchLines(); + } + return $result; + } + + /** + * Load object lines in memory from the database + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetchLines() + { + $this->lines = array(); + + $result = $this->fetchLinesCommon(); + return $result; + } + + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = 'SELECT '; + $sql .= $this->getFieldList('t'); + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')'; + } else { + $sql .= ' WHERE 1 = 1'; + } + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid') { + $sqlwhere[] = $key.'='.$value; + } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) { + $sqlwhere[] = $key.' = \''.$this->db->idate($value).'\''; + } elseif ($key == 'customsql') { + $sqlwhere[] = $value; + } elseif (strpos($value, '%') === false) { + $sqlwhere[] = $key.' IN ('.$this->db->sanitize($this->db->escape($value)).')'; + } else { + $sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' '.$this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) + { + return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + /** + * Delete a line of object in database + * + * @param User $user User that delete + * @param int $idline Id of line to delete + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int >0 if OK, <0 if KO + */ + public function deleteLine(User $user, $idline, $notrigger = false) + { + if ($this->status < 0) { + $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; + return -2; + } + + return $this->deleteLineCommon($user, $idline, $notrigger); + } + + + /** + * Validate object + * + * @param User $user User making status change + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf, $langs; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING); + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->job->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->job->job_advance->validate)))) + { + $this->error='NotEnoughPermissions'; + dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); + return -1; + }*/ + + $now = dol_now(); + + $this->db->begin(); + + // Define new ref + if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life + $num = $this->getNextNumRef(); + } else { + $num = $this->ref; + } + $this->newref = $num; + + if (!empty($num)) { + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " SET ref = '".$this->db->escape($num)."',"; + $sql .= " status = ".self::STATUS_VALIDATED; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation = '".$this->db->idate($now)."'"; + } + if (!empty($this->fields['fk_user_valid'])) { + $sql .= ", fk_user_valid = ".((int) $user->id); + } + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog(get_class($this)."::validate()", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + dol_print_error($this->db); + $this->error = $this->db->lasterror(); + $error++; + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('JOB_VALIDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + if (!$error) { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) { + // Now we rename also files into index + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'job/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'job/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; $this->error = $this->db->lasterror(); + } + + // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->hrm->dir_output.'/job/'.$oldref; + $dirdest = $conf->hrm->dir_output.'/job/'.$newref; + if (!$error && file_exists($dirsource)) { + dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->hrm->dir_output.'/job/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); + foreach ($listoffiles as $fileentry) { + $dirsource = $fileentry['name']; + $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); + $dirsource = $fileentry['path'].'/'.$dirsource; + $dirdest = $fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + } + + // Set new ref and current status + if (!$error) { + $this->ref = $num; + $this->status = self::STATUS_VALIDATED; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Get last job for user + * + * @param $fk_user + * @return mixed|string|null + */ + public function getLastJobForUser($fk_user) + { + global $db; + + $j = new Job($db); + $Tab = $j->get_for_user($fk_user); + + if (empty($Tab)) return ''; + + $job = array_shift($Tab); + + return $job; + } + + /** + * Get jobs for user + * + * @param $userid + * @return array of jobs + */ + public function get_for_user($userid) + { + global $db; + + $TReturn = array(); + $position = new Position($db); + $TPosition = $position->get_for_user($userid); + foreach ($TPosition as $UPosition) { + $TReturn[$UPosition->Job->rowid] = $UPosition->Job->ref; + } + return $TReturn; + } + + /** + * + * @return array of key [rowid] => ref + */ + public function getCombo() + { + global $db; + + $res = $db->query("SELECT rowid, ref FROM ".MAIN_DB_PREFIX.'hrm_job WHERE 1 ORDER BY ref'); + $Tab=array(); + while ($obj = $db->fetch_object($res)) { + $Tab[$obj->rowid] = $obj->ref; + } + + return $Tab; + } + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->status <= self::STATUS_DRAFT) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'JOB_UNVALIDATE'); + } + + /** + * Set cancel status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function cancel($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_VALIDATED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'JOB_CANCEL'); + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_CANCELED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'JOB_REOPEN'); + } + + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $conf, $langs, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) { + $notooltip = 1; // Force disable tooltips + } + + $result = ''; + + $label = img_picto('', $this->picto).' '.$langs->trans("Job").''; + if (isset($this->status)) { + $label .= ' '.$this->getLibStatut(5); + } + $label .= '
    '; + $label .= ''.$langs->trans('Label').': '.$this->label; + + $url = dol_buildpath('/hrm/job_card.php', 1).'?id='.$this->id; + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values = 1; + } + if ($add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkclose = ''; + if (empty($notooltip)) { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { + $label = $langs->trans("ShowJob"); + $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"'; + } else { + $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); + } + + if ($option == 'nolink') { + $linkstart = ''; + if ($option == 'nolink') { + $linkend = ''; + } else { + $linkend = ''; + } + + $result .= $linkstart; + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->label); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class.'/'.$this->label.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); + if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) { + $result .= '
    No photo
    '; + } else { + $result .= '
    No photo
    '; + } + + $result .= ''; + } else { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } + } + + if ($withpicto != 2) { + $result .= $this->label; + } + + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action, $hookmanager; + $hookmanager->initHooks(array('jobdao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("hrm"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatus[self::STATUS_CANCELED] = $langs->trans('Disabled'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Disabled'); + } + + $statusType = 'status'.$status; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = 'SELECT rowid, date_creation as datec, tms as datem,'; + $sql .= ' fk_user_creat, fk_user_modif'; + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + $sql .= ' WHERE t.rowid = '.((int) $id); + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_valid) { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); + } + + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + + $this->initAsSpecimenCommon(); + } + + /** + * Create an array of lines + * + * @return array|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + $objectline = new JobLine($this->db); + $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_job = '.$this->id)); + + if (is_numeric($result)) { + $this->error = $this->error; + $this->errors = $this->errors; + return $result; + } else { + $this->lines = $result; + return $this->lines; + } + } + + /** + * Returns the reference to the following non used object depending on the active numbering module. + * + * @return string Object free reference + */ + public function getNextNumRef() + { + global $langs, $conf; + $langs->load("hrm"); + + if (empty($conf->global->hrm_JOB_ADDON)) { + $conf->global->hrm_JOB_ADDON = 'mod_job_standard'; + } + + if (!empty($conf->global->hrm_JOB_ADDON)) { + $mybool = false; + + $file = $conf->global->hrm_JOB_ADDON.".php"; + $classname = $conf->global->hrm_JOB_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/hrm/"); + + // Load file with numbering class (if found) + $mybool |= @include_once $dir.$file; + } + + if ($mybool === false) { + dol_print_error('', "Failed to include file ".$file); + return ''; + } + + if (class_exists($classname)) { + $obj = new $classname(); + $numref = $obj->getNextValue($this); + + if ($numref != '' && $numref != '-1') { + return $numref; + } else { + $this->error = $obj->error; + //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } else { + print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname; + return ""; + } + } else { + print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); + return ""; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force template to use ('' to not force) + * @param Translate $outputlangs objet lang a utiliser pour traduction + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @param null|array $moreparams Array to provide more information + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) + { + global $conf, $langs; + + $result = 0; + $includedocgeneration = 0; + + $langs->load("hrm"); + + if (!dol_strlen($modele)) { + $modele = 'standard_job'; + + if (!empty($this->model_pdf)) { + $modele = $this->model_pdf; + } elseif (!empty($conf->global->JOB_ADDON_PDF)) { + $modele = $conf->global->JOB_ADDON_PDF; + } + } + + $modelpath = "core/modules/hrm/doc/"; + + if ($includedocgeneration && !empty($modele)) { + $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + } + + return $result; + } + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + public function doScheduledJob() + { + global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log'; + + $error = 0; + $this->output = ''; + $this->error = ''; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + return $error; + } +} + + +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php'; + +/** + * Class JobLine. You can also remove this and generate a CRUD class for lines objects. + */ +class JobLine extends CommonObjectLine +{ + // To complete with content of an object JobLine + // We should have a field rowid, fk_job and position + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 0; + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + $this->db = $db; + } +} diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php new file mode 100644 index 00000000000..9b9241477c9 --- /dev/null +++ b/htdocs/hrm/class/position.class.php @@ -0,0 +1,1091 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file class/position.class.php + * \ingroup hrm + * \brief This file is a CRUD class file for Position (Create/Read/Update/Delete) + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; + +/** + * Class for Position + */ +class Position extends CommonObject +{ + /** + * @var string ID of module. + */ + public $module = 'hrm'; + + /** + * @var string ID to identify managed object. + */ + public $element = 'position'; + + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. + */ + public $table_element = 'hrm_position'; + + /** + * @var int Does this object support multicompany module ? + * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table + */ + public $ismultientitymanaged = 0; + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + + /** + * @var string String with name of icon for position. Must be the part after the 'object_' into object_position.png + */ + public $picto = 'user-cog'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CANCELED = 9; + + + /** + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields=array( + 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>2, 'index'=>1, 'css'=>'left', 'comment'=>"Id"), + //'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1, 'index'=>1, 'searchall'=>1, 'showoncombobox'=>'1', 'comment'=>"Reference of object"), + 'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>'1', 'position'=>60, 'notnull'=>0, 'visible'=>3,), + 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>500, 'notnull'=>1, 'visible'=>-2,), + 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>'1', 'position'=>501, 'notnull'=>0, 'visible'=>-2,), + 'fk_contrat' => array('type'=>'integer:Contrat:contrat/class/contrat.class.php', 'label'=>'fk_contrat', 'enabled'=>'1', 'position'=>50, 'notnull'=>0, 'visible'=>0,), + 'fk_user' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Employee', 'enabled'=>'1', 'position'=>55, 'notnull'=>1, 'visible'=>1,), + 'fk_job' => array('type'=>'integer:Job:/hrm/class/job.class.php', 'label'=>'Job', 'enabled'=>'1', 'position'=>56, 'notnull'=>1, 'visible'=>1,), + 'date_start' => array('type'=>'date', 'label'=>'DateStart', 'enabled'=>'1', 'position'=>51, 'notnull'=>1, 'visible'=>1,), + 'date_end' => array('type'=>'date', 'label'=>'DateEnd', 'enabled'=>'1', 'position'=>52, 'notnull'=>0, 'visible'=>1,), + 'commentaire_abandon' => array('type'=>'varchar(255)', 'label'=>'AbandonmentComment', 'enabled'=>'1', 'position'=>502, 'notnull'=>0, 'visible'=>1,), + 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>70, 'notnull'=>0, 'visible'=>0,), + 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>'1', 'position'=>71, 'notnull'=>0, 'visible'=>0,), + 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',), + 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>'1', 'position'=>511, 'notnull'=>-1, 'visible'=>-2,), + ); + public $rowid; + public $ref; + public $description; + public $date_creation; + public $tms; + public $fk_contrat; + public $fk_user; + public $fk_job; + public $date_start; + public $date_end; + public $commentaire_abandon; + public $note_public; + public $note_private; + public $fk_user_creat; + public $fk_user_modif; + + + // END MODULEBUILDER PROPERTIES + + + // If this object has a subtable with lines + + // /** + // * @var string Name of subtable line + // */ + // public $table_element_line = 'hrm_positionline'; + + // /** + // * @var string Field with ID of parent key if this object has a parent + // */ + // public $fk_element = 'fk_position'; + + // /** + // * @var string Name of subtable class that manage subtable lines + // */ + // public $class_element_line = 'Positionline'; + + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + // protected $childtables = array(); + + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + // protected $childtablesoncascade = array('hrm_positiondet'); + + // /** + // * @var PositionLine[] Array of subtable lines + // */ + // public $lines = array(); + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs; + + $this->db = $db; + + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { + //$this->fields['rowid']['visible'] = 0; + } + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { + $this->fields['entity']['enabled'] = 0; + } + + // Example to show how to set values of fields definition dynamically + /*if ($user->rights->hrm->position->read) { + $this->fields['myfield']['visible'] = 1; + $this->fields['myfield']['noteditable'] = 0; + }*/ + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $notrigger = false) + { + $resultcreate = $this->createCommon($user, $notrigger); + + //$resultvalidate = $this->validate($user, $notrigger); + + return $resultcreate; + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return mixed New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $result = $object->fetchCommon($fromid); + if ($result > 0 && !empty($object->table_element_line)) { + $object->fetchLines(); + } + + // get lines so they will be clone + //foreach($this->lines as $line) + // $line->fetch_optionals(); + + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + if (property_exists($object, 'ref')) { + $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_" . $object->ref : $this->fields['ref']['default']; + } + if (property_exists($object, 'label')) { + $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf") . " " . $object->label : $this->fields['label']['default']; + } + if (property_exists($object, 'status')) { + $object->status = self::STATUS_DRAFT; + } + if (property_exists($object, 'date_creation')) { + $object->date_creation = dol_now(); + } + if (property_exists($object, 'date_modification')) { + $object->date_modification = null; + } + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->table_element); + foreach ($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->error = $object->error; + $this->errors = $object->errors; + } + + if (!$error) { + // copy internal contacts + if ($this->copy_linked_contact($object, 'internal') < 0) { + $error++; + } + } + + if (!$error) { + // copy external contacts if same company + if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + if ($this->copy_linked_contact($object, 'external') < 0) { + $error++; + } + } + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $ref = null) + { + $result = $this->fetchCommon($id, $ref); + if ($result > 0 && !empty($this->table_element_line)) { + $this->fetchLines(); + } + return $result; + } + + /** + * Load object lines in memory from the database + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetchLines() + { + $this->lines = array(); + + $result = $this->fetchLinesCommon(); + return $result; + } + + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = 'SELECT '; + $sql .= $this->getFieldList('t'); + $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql .= ' WHERE t.entity IN (' . getEntity($this->table_element) . ')'; + } else { + $sql .= ' WHERE 1 = 1'; + } + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid') { + $sqlwhere[] = $key . '=' . $value; + } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) { + $sqlwhere[] = $key . ' = \'' . $this->db->idate($value) . '\''; + } elseif ($key == 'customsql') { + $sqlwhere[] = $value; + } elseif (strpos($value, '%') === false) { + $sqlwhere[] = $key . ' IN (' . $this->db->sanitize($this->db->escape($value)) . ')'; + } else { + $sqlwhere[] = $key . ' LIKE \'%' . $this->db->escape($value) . '%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' AND (' . implode(' ' . $filtermode . ' ', $sqlwhere) . ')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' ' . $this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) + { + return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + /** + * Delete a line of object in database + * + * @param User $user User that delete + * @param int $idline Id of line to delete + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int >0 if OK, <0 if KO + */ + public function deleteLine(User $user, $idline, $notrigger = false) + { + if ($this->status < 0) { + $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; + return -2; + } + + return $this->deleteLineCommon($user, $idline, $notrigger); + } + + + /** + * Validate object + * + * @param User $user User making status change + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf, $langs; + + require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this) . "::validate action abandonned: already validated", LOG_WARNING); + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->position->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->position->position_advance->validate)))) + { + $this->error='NotEnoughPermissions'; + dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); + return -1; + }*/ + + $now = dol_now(); + + $this->db->begin(); + + // Define new ref + if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life + $num = $this->getNextNumRef(); + } else { + $num = $this->ref; + } + $this->newref = $num; + + if (!empty($num)) { + // Validate + $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element; + $sql .= " SET ref = '" . $this->db->escape($num) . "',"; + $sql .= " status = " . self::STATUS_VALIDATED; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation = '" . $this->db->idate($now) . "'"; + } + if (!empty($this->fields['fk_user_valid'])) { + $sql .= ", fk_user_valid = " . ((int) $user->id); + } + $sql .= " WHERE rowid = " . ((int) $this->id); + + dol_syslog(get_class($this) . "::validate()", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + dol_print_error($this->db); + $this->error = $this->db->lasterror(); + $error++; + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('POSITION_VALIDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + if (!$error) { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) { + // Now we rename also files into index + $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filename = CONCAT('" . $this->db->escape($this->newref) . "', SUBSTR(filename, " . (strlen($this->ref) + 1) . ")), filepath = 'position/" . $this->db->escape($this->newref) . "'"; + $sql .= " WHERE filename LIKE '" . $this->db->escape($this->ref) . "%' AND filepath = 'position/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->error = $this->db->lasterror(); + } + + // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->hrm->dir_output . '/position/' . $oldref; + $dirdest = $conf->hrm->dir_output . '/position/' . $newref; + if (!$error && file_exists($dirsource)) { + dol_syslog(get_class($this) . "::validate() rename dir " . $dirsource . " into " . $dirdest); + + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->hrm->dir_output . '/position/' . $newref, 'files', 1, '^' . preg_quote($oldref, '/')); + foreach ($listoffiles as $fileentry) { + $dirsource = $fileentry['name']; + $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $newref, $dirsource); + $dirsource = $fileentry['path'] . '/' . $dirsource; + $dirdest = $fileentry['path'] . '/' . $dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + } + + // Set new ref and current status + if (!$error) { + $this->ref = $num; + $this->status = self::STATUS_VALIDATED; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->status <= self::STATUS_DRAFT) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'POSITION_UNVALIDATE'); + } + + /** + * Set cancel status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function cancel($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_VALIDATED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'POSITION_CANCEL'); + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_CANCELED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'POSITION_REOPEN'); + } + + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $conf, $langs, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) { + $notooltip = 1; // Force disable tooltips + } + + $result = ''; + + $label = img_picto('', $this->picto) . ' ' . $langs->trans("Position") . ''; + if (isset($this->status)) { + $label .= ' ' . $this->getLibStatut(5); + } + $label .= '
    '; + $label .= '' . $langs->trans('Ref') . ': ' . $this->ref; + + $url = dol_buildpath('/hrm/position_card.php', 1) . '?id=' . $this->id; + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values = 1; + } + if ($add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkclose = ''; + if (empty($notooltip)) { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { + $label = $langs->trans("ShowPosition"); + $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"'; + } + $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"'; + $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"'; + } else { + $linkclose = ($morecss ? ' class="' . $morecss . '"' : ''); + } + + if ($option == 'nolink') { + $linkstart = ''; + if ($option == 'nolink') { + $linkend = ''; + } else { + $linkend = ''; + } + + $result .= $linkstart; + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity] . "/$class/" . dol_sanitizeFileName($this->ref); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class . '/' . $this->ref . '/thumbs/' . substr($filename, 0, $pospoint) . '_mini' . substr($filename, $pospoint); + if (empty($conf->global->{strtoupper($module . '_' . $class) . '_FORMATLISTPHOTOSASUSERS'})) { + $result .= '
    No photo
    '; + } else { + $result .= '
    No photo
    '; + } + + $result .= ''; + } else { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } + } + + if ($withpicto != 2) { + $result .= $this->ref; + } + + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action, $hookmanager; + $hookmanager->initHooks(array('positiondao')); + $parameters = array('id' => $this->id, 'getnomurl' => $result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("hrm"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatus[self::STATUS_CANCELED] = $langs->trans('Disabled'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Disabled'); + } + + $statusType = 'status' . $status; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = 'SELECT rowid, date_creation as datec, tms as datem,'; + $sql .= ' fk_user_creat, fk_user_modif'; + $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; + $sql .= ' WHERE t.rowid = ' . ((int) $id); + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_valid) { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); + } + + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + + $this->initAsSpecimenCommon(); + } + + /** + * Create an array of lines + * + * @return array|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + $objectline = new PositionLine($this->db); + $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql' => 'fk_position = ' . $this->id)); + + if (is_numeric($result)) { + $this->error = $this->error; + $this->errors = $this->errors; + return $result; + } else { + $this->lines = $result; + return $this->lines; + } + } + + /** + * Returns the reference to the following non used object depending on the active numbering module. + * + * @return string Object free reference + */ + public function getNextNumRef() + { + global $langs, $conf; + $langs->load("hrm"); + + if (empty($conf->global->hrm_POSITION_ADDON)) { + $conf->global->hrm_POSITION_ADDON = 'mod_position_standard'; + } + + if (!empty($conf->global->hrm_POSITION_ADDON)) { + $mybool = false; + + $file = $conf->global->hrm_POSITION_ADDON . ".php"; + $classname = $conf->global->hrm_POSITION_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir . "core/modules/hrm/"); + + // Load file with numbering class (if found) + $mybool |= @include_once $dir . $file; + } + + if ($mybool === false) { + dol_print_error('', "Failed to include file " . $file); + return ''; + } + + if (class_exists($classname)) { + $obj = new $classname(); + $numref = $obj->getNextValue($this); + + if ($numref != '' && $numref != '-1') { + return $numref; + } else { + $this->error = $obj->error; + //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } else { + print $langs->trans("Error") . " " . $langs->trans("ClassNotFound") . ' ' . $classname; + return ""; + } + } else { + print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); + return ""; + } + } + + /** + * @param $userid + * @return array|int of positions of user with for each of them the job fetched into that array + */ + public function get_for_user($userid) + { + $TPosition = array(); + + $TPosition = $this->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_user=' . $userid)); + + return $TPosition; + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force template to use ('' to not force) + * @param Translate $outputlangs objet lang a utiliser pour traduction + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @param null|array $moreparams Array to provide more information + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) + { + global $conf, $langs; + + $result = 0; + $includedocgeneration = 0; + + $langs->load("hrm"); + + if (!dol_strlen($modele)) { + $modele = 'standard_position'; + + if (!empty($this->model_pdf)) { + $modele = $this->model_pdf; + } elseif (!empty($conf->global->POSITION_ADDON_PDF)) { + $modele = $conf->global->POSITION_ADDON_PDF; + } + } + + $modelpath = "core/modules/hrm/doc/"; + + if ($includedocgeneration && !empty($modele)) { + $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + } + + return $result; + } + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + public function doScheduledJob() + { + global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log'; + + $error = 0; + $this->output = ''; + $this->error = ''; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + return $error; + } +} + + +require_once DOL_DOCUMENT_ROOT . '/core/class/commonobjectline.class.php'; + +/** + * Class PositionLine. You can also remove this and generate a CRUD class for lines objects. + */ +class PositionLine extends CommonObjectLine +{ + // To complete with content of an object PositionLine + // We should have a field rowid, fk_position and position + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 0; + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + $this->db = $db; + } +} diff --git a/htdocs/hrm/class/skill.class.php b/htdocs/hrm/class/skill.class.php new file mode 100644 index 00000000000..0a1158593b2 --- /dev/null +++ b/htdocs/hrm/class/skill.class.php @@ -0,0 +1,1134 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file class/skill.class.php + * \ingroup hrm + * \brief This file is a CRUD class file for Skill (Create/Read/Update/Delete) + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; + +/** + * Class for Skill + */ +class Skill extends CommonObject +{ + /** + * @var string ID of module. + */ + public $module = 'hrm'; + + /** + * @var string ID to identify managed object. + */ + public $element = 'skill'; + + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. + */ + public $table_element = 'hrm_skill'; + + + /** + * @var string Name of subtable line + */ + public $table_element_line = 'skilldet'; + + /** + * @var int Does this object support multicompany module ? + * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table + */ + public $ismultientitymanaged = 0; + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + + /** + * @var string String with name of icon for skill. Must be the part after the 'object_' into object_skill.png + */ + public $picto = 'shapes'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CANCELED = 9; + const DEFAULT_MAX_RANK_PER_SKILL = 5; + + /** + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields=array( + 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"), + 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1, 'searchall'=>1, 'css'=>'minwidth300', 'cssview'=>'wordbreak', 'showoncombobox'=>'2',), + 'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>'1', 'position'=>60, 'notnull'=>0, 'visible'=>3,), + 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>500, 'notnull'=>1, 'visible'=>-2,), + 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>'1', 'position'=>501, 'notnull'=>0, 'visible'=>-2,), + 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',), + 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>'1', 'position'=>511, 'notnull'=>-1, 'visible'=>-2,), + 'required_level' => array('type'=>'integer', 'label'=>'requiredLevel', 'enabled'=>'1', 'position'=>50, 'notnull'=>1, 'visible'=>0,), + 'date_validite' => array('type'=>'integer', 'label'=>'date_validite', 'enabled'=>'1', 'position'=>52, 'notnull'=>1, 'visible'=>0,), + 'temps_theorique' => array('type'=>'double(24,8)', 'label'=>'temps_theorique', 'enabled'=>'1', 'position'=>54, 'notnull'=>1, 'visible'=>0,), + 'skill_type' => array('type'=>'integer', 'label'=>'SkillType', 'enabled'=>'1', 'position'=>55, 'notnull'=>1, 'visible'=>1, 'index'=>1, 'arrayofkeyval'=>array('0'=>'knowHow', '1'=>'HowToBe', '9'=>'knowledge'), 'default'=>0), + 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>70, 'notnull'=>0, 'visible'=>0,), + 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>'1', 'position'=>71, 'notnull'=>0, 'visible'=>0,), + ); + public $rowid; + public $label; + public $description; + public $date_creation; + public $tms; + public $fk_user_creat; + public $fk_user_modif; + public $required_level; + public $date_validite; + public $temps_theorique; + public $skill_type; + public $note_public; + public $note_private; + // END MODULEBUILDER PROPERTIES + + + // If this object has a subtable with lines + + // /** + // * @var string Name of subtable line + // */ + // public $table_element_line = 'hrm_skillline'; + + // /** + // * @var string Field with ID of parent key if this object has a parent + // */ + public $fk_element = 'fk_skill'; + + // /** + // * @var string Name of subtable class that manage subtable lines + // */ + // public $class_element_line = 'Skillline'; + + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + protected $childtables = array('hrm_skillrank', 'hrm_evaluationdet'); + + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + protected $childtablesoncascade = array('hrm_skilldet'); + + // /** + // * @var SkillLine[] Array of subtable lines + // */ + // public $lines = array(); + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs; + + $this->db = $db; + + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { + $this->fields['rowid']['visible'] = 0; + } + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { + $this->fields['entity']['enabled'] = 0; + } + + // Example to show how to set values of fields definition dynamically + /*if ($user->rights->hrm->skill->read) { + $this->fields['myfield']['visible'] = 1; + $this->fields['myfield']['noteditable'] = 0; + }*/ + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $notrigger = false) + { + global $langs,$conf; + + $resultcreate = $this->createCommon($user, $notrigger); + + + if ($resultcreate > 0) { + // skillDet create + $this->createSkills(); + } + + return $resultcreate; + } + + public function createSkills($i = 1) + { + + global $conf, $user, $langs; + + $MaxNumberSkill = isset($conf->global->HRM_MAXRANK) ? $conf->global->HRM_MAXRANK : self::DEFAULT_MAX_RANK_PER_SKILL; + $defaultSkillDesc = !empty($conf->global->HRM_DEFAULT_SKILL_DESCRIPTION) ? $conf->global->HRM_DEFAULT_SKILL_DESCRIPTION : 'no Description'; + require_once __DIR__ . '/skilldet.class.php'; + for ($i; $i <= $MaxNumberSkill ; $i++) { + $skilldet = new Skilldet($this->db); + $skilldet->description = $defaultSkillDesc . " " . $i ; + $skilldet->rank = $i; + $skilldet->fk_skill = $this->id; + + $result = $skilldet->create($user); + + if ($result > 0) { + setEventMessage($langs->trans('TraductionCreadted'), $i); + } + } + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return mixed New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $result = $object->fetchCommon($fromid); + if ($result > 0 && !empty($object->table_element_line)) { + $object->fetchLines(); + } + + // get lines so they will be clone + //foreach($this->lines as $line) + // $line->fetch_optionals(); + + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + if (property_exists($object, 'ref')) { + $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; + } + if (property_exists($object, 'label')) { + $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; + } + if (property_exists($object, 'status')) { + $object->status = self::STATUS_DRAFT; + } + if (property_exists($object, 'date_creation')) { + $object->date_creation = dol_now(); + } + if (property_exists($object, 'date_modification')) { + $object->date_modification = null; + } + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->table_element); + foreach ($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->error = $object->error; + $this->errors = $object->errors; + } + + if (!$error) { + // copy internal contacts + if ($this->copy_linked_contact($object, 'internal') < 0) { + $error++; + } + } + + if (!$error) { + // copy external contacts if same company + if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + if ($this->copy_linked_contact($object, 'external') < 0) { + $error++; + } + } + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $ref = null) + { + $result = $this->fetchCommon($id, $ref); + if ($result > 0 && !empty($this->table_element_line)) { + $this->fetchLines(); + } + return $result; + } + + /** + * Load object lines in memory from the database + * + * @return int | array <0 if KO, 0 if not found, array if OK + */ + public function fetchLines() + { + $this->lines = array(); + require_once __DIR__ . '/skilldet.class.php'; + $skilldet = new Skilldet($this->db); + $this->lines = $skilldet->fetchAll('ASC', '', '', '', array('fk_skill' => $this->id), ''); + + return (count($this->lines) > 0 ) ? $this->lines : 0; + } + + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = 'SELECT '; + $sql .= $this->getFieldList('t'); + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')'; + } else { + $sql .= ' WHERE 1 = 1'; + } + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid') { + $sqlwhere[] = $key.'='.$value; + } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) { + $sqlwhere[] = $key.' = \''.$this->db->idate($value).'\''; + } elseif ($key == 'customsql') { + $sqlwhere[] = $value; + } elseif (strpos($value, '%') === false) { + $sqlwhere[] = $key.' IN ('.$this->db->sanitize($this->db->escape($value)).')'; + } else { + $sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' '.$this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) + { + return $this->deleteCommon($user, $notrigger);; + } + + /** + * Delete a line of object in database + * + * @param User $user User that delete + * @param int $idline Id of line to delete + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int >0 if OK, <0 if KO + */ + public function deleteLine(User $user, $idline, $notrigger = false) + { + if ($this->status < 0) { + $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; + return -2; + } + + return $this->deleteLineCommon($user, $idline, $notrigger); + } + + + /** + * Validate object + * + * @param User $user User making status change + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf, $langs; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING); + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->skill->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->skill->skill_advance->validate)))) + { + $this->error='NotEnoughPermissions'; + dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); + return -1; + }*/ + + $now = dol_now(); + + $this->db->begin(); + + // Define new ref + if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life + $num = $this->getNextNumRef(); + } else { + $num = $this->ref; + } + $this->newref = $num; + + if (!empty($num)) { + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " SET ref = '".$this->db->escape($num)."',"; + $sql .= " status = ".self::STATUS_VALIDATED; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation = '".$this->db->idate($now)."'"; + } + if (!empty($this->fields['fk_user_valid'])) { + $sql .= ", fk_user_valid = ".((int) $user->id); + } + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog(get_class($this)."::validate()", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + dol_print_error($this->db); + $this->error = $this->db->lasterror(); + $error++; + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('SKILL_VALIDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + if (!$error) { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) { + // Now we rename also files into index + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'skill/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'skill/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; $this->error = $this->db->lasterror(); + } + + // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->hrm->dir_output.'/skill/'.$oldref; + $dirdest = $conf->hrm->dir_output.'/skill/'.$newref; + if (!$error && file_exists($dirsource)) { + dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->hrm->dir_output.'/skill/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); + foreach ($listoffiles as $fileentry) { + $dirsource = $fileentry['name']; + $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); + $dirsource = $fileentry['path'].'/'.$dirsource; + $dirdest = $fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + } + + // Set new ref and current status + if (!$error) { + $this->ref = $num; + $this->status = self::STATUS_VALIDATED; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->status <= self::STATUS_DRAFT) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'SKILL_UNVALIDATE'); + } + + /** + * Set cancel status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function cancel($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_VALIDATED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'SKILL_CANCEL'); + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_CANCELED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'SKILL_REOPEN'); + } + + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $conf, $langs, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) { + $notooltip = 1; // Force disable tooltips + } + + $result = ''; + + $label = img_picto('', $this->picto).' '.$langs->trans("Skill").''; + if (isset($this->status)) { + $label .= ' '.$this->getLibStatut(5); + } + $label .= '
    '; + $label .= ''.$langs->trans('Label').': '.$this->label; + + $url = dol_buildpath('/hrm/skill_card.php', 1).'?id='.$this->id; + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values = 1; + } + if ($add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkclose = ''; + if (empty($notooltip)) { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { + $label = $langs->trans("ShowSkill"); + $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"'; + } else { + $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); + } + + if ($option == 'nolink') { + $linkstart = ''; + if ($option == 'nolink') { + $linkend = ''; + } else { + $linkend = ''; + } + + $result .= $linkstart; + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); + if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) { + $result .= '
    No photo
    '; + } else { + $result .= '
    No photo
    '; + } + + $result .= ''; + } else { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } + } + + if ($withpicto != 2) { + $result .= $this->label; + } + + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action, $hookmanager; + $hookmanager->initHooks(array('jobdao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("hrm"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatus[self::STATUS_CANCELED] = $langs->trans('Disabled'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Disabled'); + } + + $statusType = 'status'.$status; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = 'SELECT rowid, date_creation as datec, tms as datem,'; + $sql .= ' fk_user_creat, fk_user_modif'; + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + $sql .= ' WHERE t.rowid = '.((int) $id); + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_valid) { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); + } + + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + + $this->initAsSpecimenCommon(); + } + + /** + * Create an array of lines + * + * @return array|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + $objectline = new SkillLine($this->db); + $result = $objectline->fetchAll('ASC', 'rank', 0, 0, array('customsql'=>'fk_skill = '.$this->id)); + + if (is_numeric($result)) { + $this->error = $this->error; + $this->errors = $this->errors; + return $result; + } else { + $this->lines = $result; + return $this->lines; + } + } + + /** + * Returns the reference to the following non used object depending on the active numbering module. + * + * @return string Object free reference + */ + public function getNextNumRef() + { + global $langs, $conf; + $langs->load("hrm"); + + if (empty($conf->global->hrm_SKILL_ADDON)) { + $conf->global->hrm_SKILL_ADDON = 'mod_skill_standard'; + } + + if (!empty($conf->global->hrm_SKILL_ADDON)) { + $mybool = false; + + $file = $conf->global->hrm_SKILL_ADDON.".php"; + $classname = $conf->global->hrm_SKILL_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/hrm/"); + + // Load file with numbering class (if found) + $mybool |= @include_once $dir.$file; + } + + if ($mybool === false) { + dol_print_error('', "Failed to include file ".$file); + return ''; + } + + if (class_exists($classname)) { + $obj = new $classname(); + $numref = $obj->getNextValue($this); + + if ($numref != '' && $numref != '-1') { + return $numref; + } else { + $this->error = $obj->error; + //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } else { + print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname; + return ""; + } + } else { + print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); + return ""; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force template to use ('' to not force) + * @param Translate $outputlangs objet lang a utiliser pour traduction + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @param null|array $moreparams Array to provide more information + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) + { + global $conf, $langs; + + $result = 0; + $includedocgeneration = 0; + + $langs->load("hrm"); + + if (!dol_strlen($modele)) { + $modele = 'standard_skill'; + + if (!empty($this->model_pdf)) { + $modele = $this->model_pdf; + } elseif (!empty($conf->global->SKILL_ADDON_PDF)) { + $modele = $conf->global->SKILL_ADDON_PDF; + } + } + + $modelpath = "core/modules/hrm/doc/"; + + if ($includedocgeneration && !empty($modele)) { + $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + } + + return $result; + } + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + public function doScheduledJob() + { + global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log'; + + $error = 0; + $this->output = ''; + $this->error = ''; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + return $error; + } + /** + * Permet de retourner un select html du dictionnaire llx_c_skill_type + * + * @global type $conf + * @param string $selected + * @param string $htmlname + * @param bool $emptyvalue + * @return string + */ + public function select_skill_type($selected = '', $htmlname = 'code_c_skill_type', $emptyvalue = true, $moreattr = '', $more_class = '') + { + global $conf; + + $out = ''; + + return $out; + } + + + public static function typeCodeToLabel($code) + { + global $langs; + $result = ''; + switch ($code) { + case 0 : $result = $langs->trans("knowHow"); break; //"Savoir Faire" + case 1 : $result = $langs->trans("HowToBe"); break; // "Savoir être" + case 9 : $result = $langs->trans("knowledge"); break; //"Savoir" + } + return $result; + } +} diff --git a/htdocs/hrm/class/skilldet.class.php b/htdocs/hrm/class/skilldet.class.php new file mode 100644 index 00000000000..ca6752b2508 --- /dev/null +++ b/htdocs/hrm/class/skilldet.class.php @@ -0,0 +1,1030 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file class/skilldet.class.php + * \ingroup hrm + * \brief This file is a CRUD class file for Skilldet (Create/Read/Update/Delete) + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; + +/** + * Class for Skilldet + */ +class Skilldet extends CommonObject +{ + /** + * @var string ID of module. + */ + public $module = 'hrm'; + + /** + * @var string ID to identify managed object. + */ + public $element = 'skilldet'; + + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. + */ + public $table_element = 'hrm_skilldet'; + + /** + * @var int Does this object support multicompany module ? + * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table + */ + public $ismultientitymanaged = 0; + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + + /** + * @var string String with name of icon for skilldet. Must be the part after the 'object_' into object_skilldet.png + */ + public $picto = 'skilldet@hrm'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CANCELED = 9; + + + /** + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields=array( + 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"), + 'rank' => array('type'=>'integer', 'label'=>'rank', 'enabled'=>'1', 'position'=>2, 'notnull'=>0, 'visible'=>2,), + 'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>'1', 'position'=>60, 'notnull'=>0, 'visible'=>1,), + 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',), + 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>'1', 'position'=>511, 'notnull'=>-1, 'visible'=>0,), + 'fk_skill' => array('type'=>'integer:Skill:/hrm/class/skill.class.php', 'label'=>'fk_skill', 'enabled'=>'1', 'position'=>513, 'notnull'=>1, 'visible'=>0,), + ); + public $rowid; + public $description; + public $fk_user_creat; + public $fk_user_modif; + public $fk_skill; + public $rank; + // END MODULEBUILDER PROPERTIES + + + // If this object has a subtable with lines + + // /** + // * @var string Name of subtable line + // */ + // public $table_element_line = 'hrm_skilldetline'; + + // /** + // * @var string Field with ID of parent key if this object has a parent + // */ + // public $fk_element = 'fk_skilldet'; + + // /** + // * @var string Name of subtable class that manage subtable lines + // */ + // public $class_element_line = 'Skilldetline'; + + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + // protected $childtables = array(); + + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + // protected $childtablesoncascade = array('hrm_skilldetdet'); + + // /** + // * @var SkilldetLine[] Array of subtable lines + // */ + // public $lines = array(); + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs; + + $this->db = $db; + + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { + $this->fields['rowid']['visible'] = 0; + } + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { + $this->fields['entity']['enabled'] = 0; + } + + // Example to show how to set values of fields definition dynamically + /*if ($user->rights->hrm->skilldet->read) { + $this->fields['myfield']['visible'] = 1; + $this->fields['myfield']['noteditable'] = 0; + }*/ + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $notrigger = false) + { + $resultcreate = $this->createCommon($user, $notrigger); + + //$resultvalidate = $this->validate($user, $notrigger); + + return $resultcreate; + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return mixed New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $result = $object->fetchCommon($fromid); + if ($result > 0 && !empty($object->table_element_line)) { + $object->fetchLines(); + } + + // get lines so they will be clone + //foreach($this->lines as $line) + // $line->fetch_optionals(); + + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + if (property_exists($object, 'ref')) { + $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; + } + if (property_exists($object, 'label')) { + $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; + } + if (property_exists($object, 'status')) { + $object->status = self::STATUS_DRAFT; + } + if (property_exists($object, 'date_creation')) { + $object->date_creation = dol_now(); + } + if (property_exists($object, 'date_modification')) { + $object->date_modification = null; + } + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->table_element); + foreach ($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->error = $object->error; + $this->errors = $object->errors; + } + + if (!$error) { + // copy internal contacts + if ($this->copy_linked_contact($object, 'internal') < 0) { + $error++; + } + } + + if (!$error) { + // copy external contacts if same company + if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + if ($this->copy_linked_contact($object, 'external') < 0) { + $error++; + } + } + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $ref = null) + { + $result = $this->fetchCommon($id, $ref); + if ($result > 0 && !empty($this->table_element_line)) { + $this->fetchLines(); + } + return $result; + } + + /** + * Load object lines in memory from the database + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetchLines() + { + $this->lines = array(); + + $result = $this->fetchLinesCommon(); + return $result; + } + + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = 'SELECT '; + $sql .= $this->getFieldList('t'); + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')'; + } else { + $sql .= ' WHERE 1 = 1'; + } + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid') { + $sqlwhere[] = $key.'='.$value; + } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) { + $sqlwhere[] = $key.' = \''.$this->db->idate($value).'\''; + } elseif ($key == 'customsql') { + $sqlwhere[] = $value; + } elseif (strpos($value, '%') === false) { + $sqlwhere[] = $key.' IN ('.$this->db->sanitize($this->db->escape($value)).')'; + } else { + $sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' '.$this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) + { + return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + /** + * Delete a line of object in database + * + * @param User $user User that delete + * @param int $idline Id of line to delete + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int >0 if OK, <0 if KO + */ + public function deleteLine(User $user, $idline, $notrigger = false) + { + if ($this->status < 0) { + $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; + return -2; + } + + return $this->deleteLineCommon($user, $idline, $notrigger); + } + + + /** + * Validate object + * + * @param User $user User making status change + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf, $langs; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING); + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->skilldet->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->skilldet->skilldet_advance->validate)))) + { + $this->error='NotEnoughPermissions'; + dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); + return -1; + }*/ + + $now = dol_now(); + + $this->db->begin(); + + // Define new ref + if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life + $num = $this->getNextNumRef(); + } else { + $num = $this->ref; + } + $this->newref = $num; + + if (!empty($num)) { + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " SET ref = '".$this->db->escape($num)."',"; + $sql .= " status = ".self::STATUS_VALIDATED; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation = '".$this->db->idate($now)."'"; + } + if (!empty($this->fields['fk_user_valid'])) { + $sql .= ", fk_user_valid = ".((int) $user->id); + } + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog(get_class($this)."::validate()", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + dol_print_error($this->db); + $this->error = $this->db->lasterror(); + $error++; + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('SKILLDET_VALIDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + if (!$error) { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) { + // Now we rename also files into index + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'skilldet/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'skilldet/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; $this->error = $this->db->lasterror(); + } + + // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->hrm->dir_output.'/skilldet/'.$oldref; + $dirdest = $conf->hrm->dir_output.'/skilldet/'.$newref; + if (!$error && file_exists($dirsource)) { + dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->hrm->dir_output.'/skilldet/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); + foreach ($listoffiles as $fileentry) { + $dirsource = $fileentry['name']; + $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); + $dirsource = $fileentry['path'].'/'.$dirsource; + $dirdest = $fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + } + + // Set new ref and current status + if (!$error) { + $this->ref = $num; + $this->status = self::STATUS_VALIDATED; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->status <= self::STATUS_DRAFT) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'SKILLDET_UNVALIDATE'); + } + + /** + * Set cancel status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function cancel($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_VALIDATED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'SKILLDET_CANCEL'); + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_CANCELED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'SKILLDET_REOPEN'); + } + + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $conf, $langs, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) { + $notooltip = 1; // Force disable tooltips + } + + $result = ''; + + $label = img_picto('', $this->picto).' '.$langs->trans("Skilldet").''; + if (isset($this->status)) { + $label .= ' '.$this->getLibStatut(5); + } + $label .= '
    '; + $label .= ''.$langs->trans('Ref').': '.$this->ref; + + $url = dol_buildpath('/hrm/skilldet_card.php', 1).'?id='.$this->id; + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values = 1; + } + if ($add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkclose = ''; + if (empty($notooltip)) { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { + $label = $langs->trans("ShowSkilldet"); + $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"'; + } else { + $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); + } + + if ($option == 'nolink') { + $linkstart = ''; + if ($option == 'nolink') { + $linkend = ''; + } else { + $linkend = ''; + } + + $result .= $linkstart; + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); + if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) { + $result .= '
    No photo
    '; + } else { + $result .= '
    No photo
    '; + } + + $result .= ''; + } else { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } + } + + if ($withpicto != 2) { + $result .= $this->ref; + } + + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action, $hookmanager; + $hookmanager->initHooks(array('skilldetdao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("hrm"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatus[self::STATUS_CANCELED] = $langs->trans('Disabled'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Disabled'); + } + + $statusType = 'status'.$status; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = 'SELECT rowid, date_creation as datec, tms as datem,'; + $sql .= ' fk_user_creat, fk_user_modif'; + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + $sql .= ' WHERE t.rowid = '.((int) $id); + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_valid) { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); + } + + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + + $this->initAsSpecimenCommon(); + } + + /** + * Create an array of lines + * + * @return array|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + $objectline = new SkilldetLine($this->db); + $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_skilldet = '.$this->id)); + + if (is_numeric($result)) { + $this->error = $this->error; + $this->errors = $this->errors; + return $result; + } else { + $this->lines = $result; + return $this->lines; + } + } + + /** + * Returns the reference to the following non used object depending on the active numbering module. + * + * @return string Object free reference + */ + public function getNextNumRef() + { + global $langs, $conf; + $langs->load("hrm"); + + if (empty($conf->global->hrm_SKILLDET_ADDON)) { + $conf->global->hrm_SKILLDET_ADDON = 'mod_skilldet_standard'; + } + + if (!empty($conf->global->hrm_SKILLDET_ADDON)) { + $mybool = false; + + $file = $conf->global->hrm_SKILLDET_ADDON.".php"; + $classname = $conf->global->hrm_SKILLDET_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/hrm/"); + + // Load file with numbering class (if found) + $mybool |= @include_once $dir.$file; + } + + if ($mybool === false) { + dol_print_error('', "Failed to include file ".$file); + return ''; + } + + if (class_exists($classname)) { + $obj = new $classname(); + $numref = $obj->getNextValue($this); + + if ($numref != '' && $numref != '-1') { + return $numref; + } else { + $this->error = $obj->error; + //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } else { + print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname; + return ""; + } + } else { + print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); + return ""; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force template to use ('' to not force) + * @param Translate $outputlangs objet lang a utiliser pour traduction + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @param null|array $moreparams Array to provide more information + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) + { + global $conf, $langs; + + $result = 0; + $includedocgeneration = 0; + + $langs->load("hrm"); + + if (!dol_strlen($modele)) { + $modele = 'standard_skilldet'; + + if (!empty($this->model_pdf)) { + $modele = $this->model_pdf; + } elseif (!empty($conf->global->SKILLDET_ADDON_PDF)) { + $modele = $conf->global->SKILLDET_ADDON_PDF; + } + } + + $modelpath = "core/modules/hrm/doc/"; + + if ($includedocgeneration && !empty($modele)) { + $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + } + + return $result; + } + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + public function doScheduledJob() + { + global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log'; + + $error = 0; + $this->output = ''; + $this->error = ''; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + return $error; + } +} diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php new file mode 100644 index 00000000000..5e1149f133e --- /dev/null +++ b/htdocs/hrm/class/skillrank.class.php @@ -0,0 +1,1086 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file class/skillrank.class.php + * \ingroup hrm + * \brief This file is a CRUD class file for SkillRank (Create/Read/Update/Delete) + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +dol_include_once('hrm/lib/hrm_skillrank.lib.php'); + +/** + * Class for SkillRank + */ +class SkillRank extends CommonObject +{ + /** + * @var string ID of module. + */ + public $module = 'hrm'; + + /** + * @var string ID to identify managed object. + */ + public $element = 'skillrank'; + + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. + */ + public $table_element = 'hrm_skillrank'; + + /** + * @var int Does this object support multicompany module ? + * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table + */ + public $ismultientitymanaged = 0; + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 0; + + /** + * @var string String with name of icon for skillrank. Must be the part after the 'object_' into object_skillrank.png + */ + public $picto = 'skillrank@hrm'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CANCELED = 9; + + const SKILLRANK_TYPE_JOB = "job"; + const SKILLRANK_TYPE_USER = "user"; + const SKILLRANK_TYPE_EVALDET = "evaluationdet"; + + /** + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields=array( + 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"), + 'fk_skill' => array('type'=>'integer:Skill:hrm/class/skill.class.php:1', 'label'=>'Skill', 'enabled'=>'1', 'position'=>3, 'notnull'=>1, 'visible'=>1, 'index'=>1,), + 'rank' => array('type'=>'integer', 'label'=>'Rank', 'enabled'=>'1', 'position'=>4, 'notnull'=>1, 'visible'=>1, 'default' => 0), + 'fk_object' => array('type'=>'integer', 'label'=>'object', 'enabled'=>'1', 'position'=>5, 'notnull'=>1, 'visible'=>0,), + 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>500, 'notnull'=>1, 'visible'=>-2,), + 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>'1', 'position'=>501, 'notnull'=>0, 'visible'=>-2,), + 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',), + 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>'1', 'position'=>511, 'notnull'=>-1, 'visible'=>-2,), + 'objecttype' => array('type'=>'varchar(128)', 'label'=>'objecttype', 'enabled'=>'1', 'position'=>6, 'notnull'=>1, 'visible'=>0,), + ); + public $rowid; + public $fk_skill; + public $rank; + public $fk_object; + public $date_creation; + public $tms; + public $fk_user_creat; + public $fk_user_modif; + public $objecttype; + // END MODULEBUILDER PROPERTIES + + + // If this object has a subtable with lines + + // /** + // * @var string Name of subtable line + // */ + // public $table_element_line = 'hrm_skillrankline'; + + // /** + // * @var string Field with ID of parent key if this object has a parent + // */ + // public $fk_element = 'fk_skillrank'; + + // /** + // * @var string Name of subtable class that manage subtable lines + // */ + // public $class_element_line = 'SkillRankline'; + + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + // protected $childtables = array(); + + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + // protected $childtablesoncascade = array('hrm_skillrankdet'); + + // /** + // * @var SkillRankLine[] Array of subtable lines + // */ + // public $lines = array(); + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs; + + $this->db = $db; + + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { + $this->fields['rowid']['visible'] = 0; + } + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { + $this->fields['entity']['enabled'] = 0; + } + + // Example to show how to set values of fields definition dynamically + /*if ($user->rights->hrm->skillrank->read) { + $this->fields['myfield']['visible'] = 1; + $this->fields['myfield']['noteditable'] = 0; + }*/ + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $notrigger = false) + { + global $langs; + + $sqlfilter = 'fk_object='.$this->fk_object.' AND objecttype="'.$this->objecttype.'" AND fk_skill = '.$this->fk_skill; + $alreadyLinked = $this->fetchAll('ASC', 'rowid', 0, 0, array('customsql' => $sqlfilter)); + if (!empty($alreadyLinked)) { + $this->error = $langs->trans('ErrSkillAlreadyAdded'); + return -1; + } + + $resultcreate = $this->createCommon($user, $notrigger); + + return $resultcreate; + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return mixed New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $result = $object->fetchCommon($fromid); + if ($result > 0 && !empty($object->table_element_line)) { + $object->fetchLines(); + } + + // get lines so they will be clone + //foreach($this->lines as $line) + // $line->fetch_optionals(); + + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + if (property_exists($object, 'ref')) { + $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; + } + if (property_exists($object, 'label')) { + $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; + } + if (property_exists($object, 'status')) { + $object->status = self::STATUS_DRAFT; + } + if (property_exists($object, 'date_creation')) { + $object->date_creation = dol_now(); + } + if (property_exists($object, 'date_modification')) { + $object->date_modification = null; + } + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->table_element); + foreach ($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->error = $object->error; + $this->errors = $object->errors; + } + + if (!$error) { + // copy internal contacts + if ($this->copy_linked_contact($object, 'internal') < 0) { + $error++; + } + } + + if (!$error) { + // copy external contacts if same company + if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + if ($this->copy_linked_contact($object, 'external') < 0) { + $error++; + } + } + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $ref = null) + { + $result = $this->fetchCommon($id, $ref); + if ($result > 0 && !empty($this->table_element_line)) { + $this->fetchLines(); + } + return $result; + } + + /** + * Load object lines in memory from the database + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetchLines() + { + $this->lines = array(); + + $result = $this->fetchLinesCommon(); + return $result; + } + + /** + * Clone skillrank Object linked to job with user id + * The skillrank table is a join table that is marked for multiple objects + * + * @param SkillRank $currentSkill + * @param $user + * @return int + */ + public function cloneFromCurrentSkill($currentSkill, $user, $fk_user) + { + + global $user; + + $this->fk_skill = $currentSkill->fk_skill; + $this->rank = $currentSkill->rank; + $this->fk_object = $fk_user; + $this->date_creation = dol_now(); + $this->fk_user_creat = $user->id; + $this->fk_user_modif = $user->id; + $this->objecttype = self::SKILLRANK_TYPE_USER; + $result = $this->create($user); + + return $result; + } + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = 'SELECT '; + $sql .= $this->getFieldList('t'); + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')'; + } else { + $sql .= ' WHERE 1 = 1'; + } + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid') { + $sqlwhere[] = $key.'='.$value; + } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) { + $sqlwhere[] = $key.' = \''.$this->db->idate($value).'\''; + } elseif ($key == 'customsql') { + $sqlwhere[] = $value; + } elseif (strpos($value, '%') === false) { + $sqlwhere[] = $key.' IN ('.$this->db->sanitize($this->db->escape($value)).')'; + } else { + $sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' '.$this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) + { + return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + /** + * Delete a line of object in database + * + * @param User $user User that delete + * @param int $idline Id of line to delete + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int >0 if OK, <0 if KO + */ + public function deleteLine(User $user, $idline, $notrigger = false) + { + if ($this->status < 0) { + $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; + return -2; + } + + return $this->deleteLineCommon($user, $idline, $notrigger); + } + + + /** + * Validate object + * + * @param User $user User making status change + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf, $langs; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING); + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->skillrank->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->skillrank->skillrank_advance->validate)))) + { + $this->error='NotEnoughPermissions'; + dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); + return -1; + }*/ + + $now = dol_now(); + + $this->db->begin(); + + // Define new ref + if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life + $num = $this->getNextNumRef(); + } else { + $num = $this->ref; + } + $this->newref = $num; + + if (!empty($num)) { + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " SET ref = '".$this->db->escape($num)."',"; + $sql .= " status = ".self::STATUS_VALIDATED; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation = '".$this->db->idate($now)."'"; + } + if (!empty($this->fields['fk_user_valid'])) { + $sql .= ", fk_user_valid = ".((int) $user->id); + } + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog(get_class($this)."::validate()", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + dol_print_error($this->db); + $this->error = $this->db->lasterror(); + $error++; + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('SKILLRANK_VALIDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + if (!$error) { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) { + // Now we rename also files into index + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'skillrank/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'skillrank/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; $this->error = $this->db->lasterror(); + } + + // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->hrm->dir_output.'/skillrank/'.$oldref; + $dirdest = $conf->hrm->dir_output.'/skillrank/'.$newref; + if (!$error && file_exists($dirsource)) { + dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->hrm->dir_output.'/skillrank/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); + foreach ($listoffiles as $fileentry) { + $dirsource = $fileentry['name']; + $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); + $dirsource = $fileentry['path'].'/'.$dirsource; + $dirdest = $fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + } + + // Set new ref and current status + if (!$error) { + $this->ref = $num; + $this->status = self::STATUS_VALIDATED; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->status <= self::STATUS_DRAFT) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'SKILLRANK_UNVALIDATE'); + } + + /** + * Set cancel status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function cancel($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_VALIDATED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'SKILLRANK_CANCEL'); + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_CANCELED) { + return 0; + } + + /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->write)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->hrm->hrm_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'SKILLRANK_REOPEN'); + } + + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $conf, $langs, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) { + $notooltip = 1; // Force disable tooltips + } + + $result = ''; + + $label = img_picto('', $this->picto).' '.$langs->trans("SkillRank").''; + if (isset($this->status)) { + $label .= ' '.$this->getLibStatut(5); + } + $label .= '
    '; + $label .= ''.$langs->trans('Ref').': '.$this->ref; + + $url = dol_buildpath('/hrm/skillrank_card.php', 1).'?id='.$this->id; + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values = 1; + } + if ($add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkclose = ''; + if (empty($notooltip)) { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { + $label = $langs->trans("ShowSkillRank"); + $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"'; + } else { + $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); + } + + if ($option == 'nolink') { + $linkstart = ''; + if ($option == 'nolink') { + $linkend = ''; + } else { + $linkend = ''; + } + + $result .= $linkstart; + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); + if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) { + $result .= '
    No photo
    '; + } else { + $result .= '
    No photo
    '; + } + + $result .= ''; + } else { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + } + } + + if ($withpicto != 2) { + $result .= $this->ref; + } + + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action, $hookmanager; + $hookmanager->initHooks(array('skillrankdao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("hrm"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatus[self::STATUS_CANCELED] = $langs->trans('Disabled'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Disabled'); + } + + $statusType = 'status'.$status; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = 'SELECT rowid, date_creation as datec, tms as datem,'; + $sql .= ' fk_user_creat, fk_user_modif'; + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + $sql .= ' WHERE t.rowid = '.((int) $id); + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_valid) { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); + } + + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + + $this->initAsSpecimenCommon(); + } + + /** + * Create an array of lines + * + * @return array|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + $objectline = new SkillRankLine($this->db); + $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_skillrank = '.$this->id)); + + if (is_numeric($result)) { + $this->error = $this->error; + $this->errors = $this->errors; + return $result; + } else { + $this->lines = $result; + return $this->lines; + } + } + + /** + * Returns the reference to the following non used object depending on the active numbering module. + * + * @return string Object free reference + */ + public function getNextNumRef() + { + global $langs, $conf; + $langs->load("hrm"); + + if (empty($conf->global->hrm_SKILLRANK_ADDON)) { + $conf->global->hrm_SKILLRANK_ADDON = 'mod_skillrank_standard'; + } + + if (!empty($conf->global->hrm_SKILLRANK_ADDON)) { + $mybool = false; + + $file = $conf->global->hrm_SKILLRANK_ADDON.".php"; + $classname = $conf->global->hrm_SKILLRANK_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/hrm/"); + + // Load file with numbering class (if found) + $mybool |= @include_once $dir.$file; + } + + if ($mybool === false) { + dol_print_error('', "Failed to include file ".$file); + return ''; + } + + if (class_exists($classname)) { + $obj = new $classname(); + $numref = $obj->getNextValue($this); + + if ($numref != '' && $numref != '-1') { + return $numref; + } else { + $this->error = $obj->error; + //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } else { + print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname; + return ""; + } + } else { + print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); + return ""; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force template to use ('' to not force) + * @param Translate $outputlangs objet lang a utiliser pour traduction + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @param null|array $moreparams Array to provide more information + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) + { + global $conf, $langs; + + $result = 0; + $includedocgeneration = 0; + + $langs->load("hrm"); + + if (!dol_strlen($modele)) { + $modele = 'standard_skillrank'; + + if (!empty($this->model_pdf)) { + $modele = $this->model_pdf; + } elseif (!empty($conf->global->SKILLRANK_ADDON_PDF)) { + $modele = $conf->global->SKILLRANK_ADDON_PDF; + } + } + + $modelpath = "core/modules/hrm/doc/"; + + if ($includedocgeneration && !empty($modele)) { + $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + } + + return $result; + } + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + public function doScheduledJob() + { + global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log'; + + $error = 0; + $this->output = ''; + $this->error = ''; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + return $error; + } + + /** + * @param array $val + * @param string $key + * @param string $value + * @param string $moreparam + * @param string $keysuffix + * @param string $keyprefix + * @param string $morecss + * @return string + */ + public function showOutputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '') + { + if ($key == "rank") { + return displayRankInfos($this); + } else return parent::showOutputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); + } +} diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php new file mode 100644 index 00000000000..83fc3a76ec6 --- /dev/null +++ b/htdocs/hrm/compare.php @@ -0,0 +1,635 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + + * \file class/compare.php + * \ingroup hrm + * \brief This file compares skills of user groups + * + * Displays a table in three parts. + * 1- the left part displays the list of users of the selected group 1. + * + * 2- the central part displays the skills. display of the maximum score for this group and the number of occurrences. + * + * 3- the right part displays the members of group 2 or the job to be compared + * + * + * + */ + +require_once '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + +ini_set('display_errors', 1); + +dol_include_once('/hrm/class/skill.class.php'); +dol_include_once('/hrm/class/job.class.php'); +dol_include_once('/hrm/class/evaluation.class.php'); +dol_include_once('/hrm/class/position.class.php'); +dol_include_once('/hrm/lib/hrm.lib.php'); + +$permissiontoread = $user->rights->hrm->compare->read; +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread || ($action === 'create' && !$permissiontoadd)) accessforbidden(); + +$langs->load('hrm'); + +$css = array(); +$css[] = '/hrm/css/style.css'; +llxHeader('', $langs->trans('SkillComparison'), '', '', 0, 0, '', $css); + +$head = array(); + +$h = 0; +$head[$h][0] = $_SERVER["PHP_SELF"]; +$head[$h][1] = $langs->trans("SkillComparison"); +$head[$h][2] = 'compare'; + +print dol_get_fiche_head($head, 'compare', '', 1); + +//$PDOdb = new TPDOdb; +$form = new Form($db); +?> + + + + + + +
    +
    + +
    +
    + + + + + + + + + + + + + + +
    trans('group1ToCompare').''.$form->select_dolgroups($fk_usergroup1, 'fk_usergroup1', 1); ?>
     
    trans('group2ToCompare').''.$form->select_dolgroups($fk_usergroup2, 'fk_usergroup2', 1); ?>
    trans('or'); ?>
    trans('OrJobToCompare') . '' . select_jobs($fk_job, 'fk_job', 1); ?>
    +
    + +
    + + + + + + + + + + + + + + + + + +
    + trans('CompetenceAcquiredByOneOrMore'); ?>
    + trans('MaxlevelGreaterThan'); ?>
    + trans('MaxLevelEqualTo'); ?>
    + trans('MaxLevelLowerThan'); ?>
    + trans('SkillNotAcquired'); ?>
    + +
    + +
    + +
    + +

    +
    + +
    +

    + +
    + + 0 || $fk_usergroup2 > 0 || $fk_job > 0) { ?> + + + + + + + + + + + '; + + echo ''; + echo ''; + echo ''; + echo ''; + + echo ''; + + ?> + +
    trans('skill'); ?>trans('rank'); ?>trans('difference'); ?>trans('rank'); ?>
    '; + + $TUser1 = $TUser2 = array(); + + $userlist1 = displayUsersListWithPicto($TUser1, $fk_usergroup1, 'list1'); + + + $skill = new Skill($db); + $TSkill1 = getSkillForUsers($TUser1); + + if ($fk_job > 0) { + $TSkill2 = getSkillForJob($fk_job); + + $job = new Job($db); + $job->fetch($fk_job); + $userlist2 = '
      +
    • +

      ' . $job->label . '

      +

      ' . $job->description . '

      +
    • +
    '; + } else { + $userlist2 = displayUsersListWithPicto($TUser2, $fk_usergroup2, 'list2'); + $TSkill2 = getSkillForUsers($TUser2); + } + + $TMergedSkills = mergeSkills($TSkill1, $TSkill2); + + echo $userlist1; + + echo '
    ' . skillList($TMergedSkills) . '' . rate($TMergedSkills, 'rate1') . '' . diff($TMergedSkills) . '' . rate($TMergedSkills, 'rate2') . ''; + + echo $userlist2; + + echo '
    + + + +
    + +
    + +
    + +'; + + foreach ($TMergedSkills as $id => &$sk) { + $class = 'diffnote'; + + if (empty($sk->rate2)) $class .= ' toohappy'; + elseif (empty($sk->rate1)) $class .= ' toosad'; + elseif ($sk->rate1 == $sk->rate2) $class .= ' happy'; + elseif ($sk->rate2 < $sk->rate1) $class .= ' veryhappy'; + elseif ($sk->rate2 > $sk->rate1) $class .= ' sad'; + + $out .= '
  • +   +
  • '; + } + + $out .= ''; + + return $out; +} + +/** + * Return a html list with rank informations + * @param $TMergedSkills + * @param $field + * @return string + */ +function rate(&$TMergedSkills, $field) +{ + global $langs, $fk_job; + + $out = '
      '; + + foreach ($TMergedSkills as $id => &$sk) { + $class = "note"; + $how_many = 0; + if (empty($sk->{$field})) { + $note = 'x'; + $class .= ' none'; + } else { + $note = $sk->{$field}; + $how_many = ($field === 'rate1') ? $sk->how_many_max1 : $sk->how_many_max2; + } + + if ($field === 'rate2' && $fk_job > 0) $trad = $langs->trans('RequiredRank'); + else $trad = $langs->trans('HighestRank'); + + $out .= '
    • +

      ' . $note . '' . ($how_many > 0 ? '' . $how_many . '' : '') . '

      +
    • '; + } + + $out .= '
    '; + + return $out; +} + +/** + * return a html ul list of skills + * + * @param $TMergedSkills + * @return string (ul list in html ) + */ +function skillList(&$TMergedSkills) +{ + + $out = '
      '; + + foreach ($TMergedSkills as $id => &$sk) { + $out .= '
    • +

      ' . $sk->label . '

      +

      ' . $sk->description . '

      +
    • '; + } + + $out .= '
    '; + + return $out; +} + +/** + * create an array of lines [ skillLabel,dscription, maxrank on group1 , minrank needed for this skill ] + * + * @param $TSkill1 + * @param $TSkill2 + * @return array + */ +function mergeSkills($TSkill1, $TSkill2) +{ + + $Tab = array(); + + foreach ($TSkill1 as &$sk) { + if (empty($Tab[$sk->fk_skill])) $Tab[$sk->fk_skill] = new stdClass; + + $Tab[$sk->fk_skill]->rate1 = $sk->rank; + $Tab[$sk->fk_skill]->how_many_max1 = $sk->how_many_max; + $Tab[$sk->fk_skill]->label = $sk->label; + $Tab[$sk->fk_skill]->description = $sk->description; + } + + foreach ($TSkill2 as &$sk) { + if (empty($Tab[$sk->fk_skill])) $Tab[$sk->fk_skill] = new stdClass; + $Tab[$sk->fk_skill]->rate2 = $sk->rank; + $Tab[$sk->fk_skill]->label = $sk->label; + $Tab[$sk->fk_skill]->description = $sk->description; + $Tab[$sk->fk_skill]->how_many_max2 = $sk->how_many_max; + } + + return $Tab; +} + +/** + * Display a list of User with picto + * @param $TUser + * @param int $fk_usergroup + * @param string $namelist + * @return string + */ +function displayUsersListWithPicto(&$TUser, $fk_usergroup = 0, $namelist = 'list-user') +{ + global $db, $langs, $conf, $form; + + $out = ''; + if ($fk_usergroup > 0) { + $list = $namelist . '_excluded_id'; + + $excludedIdsList = GETPOST($list); + + + $sql = "SELECT DISTINCT u.rowid FROM " . MAIN_DB_PREFIX . "user u + LEFT JOIN " . MAIN_DB_PREFIX . "usergroup_user ugu ON (u.rowid = ugu.fk_user) + WHERE 1 + AND u.statut > 0 + AND ugu.fk_usergroup=" . $fk_usergroup; + + $res = $db->query($sql); + + $out .= '
      '; + + $TExcludedId = explode(',', $excludedIdsList); + + $form = new Form($db); + $out .= ' '; + + while ($obj = $db->fetch_object($res)) { + $class = ''; + + $user = new User($db); + $user->fetch($obj->rowid); + + $name = $user->getFullName($langs); + if (empty($name)) $name = $user->login; + + if (in_array($user->id, $TExcludedId)) { + $class .= ' disabled'; + } else { + if (!in_array($user->id, $TUser)) $TUser[] = $user->id; + } + + + $desc = ''; + + $job = Job::getLastJobForUser($user->id); + $desc .= $job; + + $evaluation = Evaluation::getLastEvaluationForUser($user->id); + + if (!empty($evaluation) && !empty($evaluation->date_eval)) { + $desc .= $langs->trans('DateLastEval') . ' : ' . dol_print_date($evaluation->date_eval); + } else { + $desc .= $langs->trans('NoEval'); + } + + if (!empty($user->array_options['options_DDA'])) $desc .= '
      ' . $langs->trans('Anciennete') . ' : ' . dol_print_date(strtotime($user->array_options['options_DDA'])); + + $out .= '
    • + ' . $form->showphoto('userphoto', $user, 0, 0, 0, 'photoref', 'small', 1, 0, 1) . ' +

      ' . $name . '

      +

      ' . $desc . '

      +
    • '; + } + + $out .= '
    '; + } + + return $out; +} + + +/** + * + * Allow to get skill(s) of a user + * + * @param $TUser + * @return array|int + */ +function getSkillForUsers($TUser) +{ + global $db; + + //I go back to the user with the highest score in a given group for all the skills assessed in that group + if (empty($TUser)) return array(); + + $sql = 'SELECT sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill, '; + $sql.= " MAX(sr.rank) as rank"; + $sql.=' FROM '.MAIN_DB_PREFIX.'hrm_skill sk'; + $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)'; + $sql.=' WHERE sr.objecttype = "'.SkillRank::SKILLRANK_TYPE_USER.'"'; + $sql.=' AND sr.fk_object IN ('.implode(',', $TUser).')'; + $sql.=" GROUP BY sk.rowid "; // group par competence + + $resql = $db->query($sql); + $Tab = array(); + + if ($resql) { + //For each skill, we count the number of times that the max score has been reached within a given group + $num = 0; + while ($obj = $db->fetch_object($resql) ) { + $sql1 = "SELECT count(*) as how_many_max FROM ".MAIN_DB_PREFIX."hrm_skillrank sr"; + $sql1.=" WHERE sr.rank = ".(int) $obj->rank; + $sql1.=" AND sr.objecttype = '".Skillrank::SKILLRANK_TYPE_USER."'"; + $sql1.=" AND sr.fk_skill = ".$obj->fk_skill; + $sql1.=" AND sr.fk_object IN (".implode(',', $TUser).")"; + $resql1 = $db->query($sql1); + + $objMax = $db->fetch_object($resql1); + + $Tab[$num] = new stdClass(); + $Tab[$num]->fk_skill = $obj->fk_skill; + $Tab[$num]->label = $obj->label; + $Tab[$num]->description = $obj->description; + $Tab[$num]->skill_type = $obj->skill_type; + $Tab[$num]->fk_object = $obj->fk_object; + $Tab[$num]->objectType = SkillRank::SKILLRANK_TYPE_USER; + $Tab[$num]->rank = $obj->rank; + $Tab[$num]->how_many_max = $objMax->how_many_max; + + $num++; + } + } else { + dol_print_error($db); + } + + return $Tab; +} + +/** + * Allow to get skill(s) of a job + * + * @param $fk_job + * @return array|int + */ +function getSkillForJob($fk_job) +{ + global $db; + + if (empty($fk_job)) return array(); + + $sql = 'SELECT sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill, '; + $sql.= " MAX(sr.rank) as rank"; + $sql.=' FROM '.MAIN_DB_PREFIX.'hrm_skill sk'; + $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)'; + $sql.=' WHERE sr.objecttype = "'.SkillRank::SKILLRANK_TYPE_JOB.'"'; + $sql.=' AND sr.fk_object IN ('.$fk_job.')'; + $sql.=' GROUP BY sk.rowid '; // group par competence*/ + + $resql = $db->query($sql); + $Tab = array(); + + + if ($resql) { + $num = 0; + while ($obj = $db->fetch_object($resql) ) { + $Tab[$num] = new stdClass(); + $Tab[$num]->fk_skill = $obj->fk_skill; + $Tab[$num]->label = $obj->label; + $Tab[$num]->description = $obj->description; + $Tab[$num]->skill_type = $obj->skill_type; + //$Tab[$num]->date_start = '';// du poste + //$Tab[$num]->date_end = ''; // du poste + $Tab[$num]->fk_object = $obj->fk_object; + $Tab[$num]->objectType = SkillRank::SKILLRANK_TYPE_JOB; + $Tab[$num]->rank = $obj->rank; + $Tab[$num]->how_many_max = $obj->how_many_max; + + $num++; + } + } else { + dol_print_error($db); + } + + + return $Tab; +} + +/** + * duplicated with modified data from $form Class + * + * @param string $selected + * @param string $htmlname + * @param int $show_empty + * @param int $disabled + * @param string $enableonly + * @param string $force_entity + * @param false $multiple + * @param string $morecss + * @return string + */ +function select_jobs($selected = '', $htmlname = 'groupid', $show_empty = 0, $disabled = 0, $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '') +{ + // phpcs:enable + global $conf, $user, $langs,$db; + + if (!is_array($selected)) { + $selected = array($selected); + } + $out = ''; + + // On recherche les groupes + $sql = "SELECT j.rowid, j.label as name"; + $sql .= " FROM ".MAIN_DB_PREFIX."hrm_job as j "; + $sql .= " ORDER BY j.label ASC"; + + + $resql = $db->query($sql); + if ($resql) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + $out .= ajax_combobox($htmlname); + $out .= ''; + } else { + dol_print_error($db); + } + + return $out; +} diff --git a/htdocs/hrm/core/tpl/objectline_title.tpl.php b/htdocs/hrm/core/tpl/objectline_title.tpl.php new file mode 100644 index 00000000000..f5d72303e42 --- /dev/null +++ b/htdocs/hrm/core/tpl/objectline_title.tpl.php @@ -0,0 +1,77 @@ + + * Copyright (C) 2010-2011 Laurent Destailleur + * Copyright (C) 2012-2013 Christophe Battarel + * Copyright (C) 2012 Cédric Salvador + * Copyright (C) 2012-2014 Raphaël Doursenaud + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2017 Juanjo Menent + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Need to have following variables defined: + * $object (invoice, order, ...) + * $conf + * $langs + * $element (used to test $user->rights->$element->creer) + * $permtoedit (used to replace test $user->rights->$element->creer) + * $inputalsopricewithtax (0 by default, 1 to also show column with unit price including tax) + * $outputalsopricetotalwithtax + * $usemargins (0 to disable all margins columns, 1 to show according to margin setup) + * + * $type, $text, $description, $line + */ + +// Protection to avoid direct call of template +if (empty($object) || !is_object($object)) { + print "Error, template page can't be called as URL"; + exit; +} + +print "\n"; + +// Title line +print "\n"; + +print ''; + +// Adds a line numbering column +if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) { + print ' '; +} + +// Description +print ''.$langs->trans('Label').''; + +// Description +print ''.$langs->trans('Description').''; + +// Note +print ''.$langs->trans('Rank').''; + + +//print ''; // No width to allow autodim + +//print ''; + +//print ''; + +print "\n"; +print "\n"; + +print "\n"; diff --git a/htdocs/hrm/core/tpl/objectline_view.tpl.php b/htdocs/hrm/core/tpl/objectline_view.tpl.php new file mode 100644 index 00000000000..e8416c35711 --- /dev/null +++ b/htdocs/hrm/core/tpl/objectline_view.tpl.php @@ -0,0 +1,164 @@ + + * Copyright (C) 2010-2011 Laurent Destailleur + * Copyright (C) 2012-2013 Christophe Battarel + * Copyright (C) 2012 Cédric Salvador + * Copyright (C) 2012-2014 Raphaël Doursenaud + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2017 Juanjo Menent + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Need to have following variables defined: + * $object (invoice, order, ...) + * $conf + * $langs + * $dateSelector + * $forceall (0 by default, 1 for supplier invoices/orders) + * $element (used to test $user->rights->$element->creer) + * $permtoedit (used to replace test $user->rights->$element->creer) + * $senderissupplier (0 by default, 1 for supplier invoices/orders) + * $inputalsopricewithtax (0 by default, 1 to also show column with unit price including tax) + * $outputalsopricetotalwithtax + * $usemargins (0 to disable all margins columns, 1 to show according to margin setup) + * $object_rights->creer initialized from = $object->getRights() + * $disableedit, $disablemove, $disableremove + * + * $text, $description, $line + */ + +// Protection to avoid direct call of template +if (empty($object) || !is_object($object)) { + print "Error, template page can't be called as URL"; + exit; +} + +global $mysoc; +global $forceall, $senderissupplier, $inputalsopricewithtax, $outputalsopricetotalwithtax; + +// add html5 elements +$domData = ' data-element="'.$line->element.'"'; +$domData .= ' data-id="'.$line->id.'"'; +$domData .= ' data-qty="'.$line->qty.'"'; +$domData .= ' data-product_type="'.$line->product_type.'"'; + +$sign = 1; +if (!empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE_SCREEN) && in_array($object->element, array('facture', 'invoice_supplier')) && $object->type == $object::TYPE_CREDIT_NOTE) { + $sign = -1; +} + +$coldisplay = 0; +?> + + > +global->MAIN_VIEW_LINE_NUMBER)) { ?> + + +
    +fk_skill > 0) { + + $skill = new Skill($this->db); + $resSkill = $skill->fetch($line->fk_skill); + if ($resSkill > 0) print $skill->getNomUrl(1); + + } +?> + + + +fk_skill > 0 && $resSkill > 0) { + print $skill->description; +} + +print ''; + +?> + + +rank, $line->fk_skill, 'TNote', ($this->status == 0 && $permissiontoadd) ? 'edit' : 'view'); + +?> + + + +statut == 0 && !empty($object_rights->creer) && $action != 'selectlines') { + $situationinvoicelinewithparent = 0; + if ($line->fk_prev_id != null && in_array($object->element, array('facture', 'facturedet'))) { + if ($object->type == $object::TYPE_SITUATION) { // The constant TYPE_SITUATION exists only for object invoice + // Set constant to disallow editing during a situation cycle + $situationinvoicelinewithparent = 1; + } + } + + print ''; + $coldisplay++; + if (($line->info_bits & 2) == 2 || !empty($disableedit)) { + } else { ?> + id.'#line_'.$line->id; ?>"> + '; + } + print ''; + + /*print ''; + $coldisplay++; + if (!$situationinvoicelinewithparent && empty($disableremove)) { // For situation invoice, deletion is not possible if there is a parent company. + print 'id.'">'; + print img_delete(); + print ''; + } + print ''; + + if ($num > 1 && $conf->browser->layout != 'phone' && ($this->situation_counter == 1 || !$this->situation_cycle_ref) && empty($disablemove)) { + print ''; + $coldisplay++; + if ($i > 0) { ?> + id; ?>"> + + + + id; ?>"> + + + '; + } else { + print 'browser->layout != 'phone' && empty($disablemove)) ? ' class="linecolmove tdlineupdown center"' : ' class="linecolmove center"').'>'; + $coldisplay++; + }*/ +} else { + //print ''; + $coldisplay = $coldisplay + 3; +} + +if ($action == 'selectlines') { ?> + +\n"; + +print "\n"; diff --git a/htdocs/hrm/core/tpl/skilldet.fiche.tpl.php b/htdocs/hrm/core/tpl/skilldet.fiche.tpl.php new file mode 100644 index 00000000000..d7bfcf9e626 --- /dev/null +++ b/htdocs/hrm/core/tpl/skilldet.fiche.tpl.php @@ -0,0 +1,115 @@ +rights->module->create +// $cssclass must be defined by caller. For example $cssclass='fieldtitle' +$module = $object->element; +$note_public = 'note_public'; +$note_private = 'note_private'; + +$colwidth = (isset($colwidth) ? $colwidth : (empty($cssclass) ? '25' : '')); +// Set $permission from the $permissionnote var defined on calling page +$permission = (isset($permissionnote) ? $permissionnote : (isset($permission) ? $permission : (isset($user->rights->$module->create) ? $user->rights->$module->create : (isset($user->rights->$module->creer) ? $user->rights->$module->creer : 0)))); +$moreparam = (isset($moreparam) ? $moreparam : ''); +$value_public = $object->note_public; +$value_private = $object->note_private; +if (!empty($conf->global->MAIN_AUTO_TIMESTAMP_IN_PUBLIC_NOTES)) { +$stringtoadd = dol_print_date(dol_now(), 'dayhour').' '.$user->getFullName($langs).' --'; +if (GETPOST('action', 'aZ09') == 'edit'.$note_public) { +$value_public = dol_concatdesc($value_public, ($value_public ? "\n" : "")."-- ".$stringtoadd); +if (dol_textishtml($value_public)) { +$value_public .= "
    \n"; +} else { +$value_public .= "\n"; +} +} +} +if (!empty($conf->global->MAIN_AUTO_TIMESTAMP_IN_PRIVATE_NOTES)) { +$stringtoadd = dol_print_date(dol_now(), 'dayhour').' '.$user->getFullName($langs).' --'; +if (GETPOST('action', 'aZ09') == 'edit'.$note_private) { +$value_private = dol_concatdesc($value_private, ($value_private ? "\n" : "")."-- ".$stringtoadd); +if (dol_textishtml($value_private)) { +$value_private .= "
    \n"; +} else { +$value_private .= "\n"; +} +} +}*/ +/* +// Special cases +if ($module == 'propal') { +$permission = $user->rights->propale->creer; +} elseif ($module == 'supplier_proposal') { +$permission = $user->rights->supplier_proposal->creer; +} elseif ($module == 'fichinter') { +$permission = $user->rights->ficheinter->creer; +} elseif ($module == 'project') { +$permission = $user->rights->projet->creer; +} elseif ($module == 'project_task') { +$permission = $user->rights->projet->creer; +} elseif ($module == 'invoice_supplier') { +if (empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) { +$permission = $user->rights->fournisseur->facture->creer; +} else { +$permission = $user->rights->supplier_invoice->creer; +} +} elseif ($module == 'order_supplier') { +if (empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) { +$permission = $user->rights->fournisseur->commande->creer; +} else { +$permission = $user->rights->supplier_order->creer; +} +} elseif ($module == 'societe') { +$permission = $user->rights->societe->creer; +} elseif ($module == 'contact') { +$permission = $user->rights->societe->creer; +} elseif ($module == 'shipping') { +$permission = $user->rights->expedition->creer; +} elseif ($module == 'product') { +$permission = $user->rights->produit->creer; +} elseif ($module == 'ecmfiles') { +$permission = $user->rights->ecm->setup; +}*/ +//else dol_print_error('','Bad value '.$module.' for param module'); + +if (!empty($object->table_element_line)) { +// Show object lines +$result = $object->getLinesArray(); + + +} + + + +print ''."\n"; + +print '
    '."\n"; + print '
    '."\n"; + $editmode = (GETPOST('action', 'aZ09') == 'edit'.$note_public); + print '
    '."\n"; + print $form->editfieldkey("NotePublic", $note_public, $value_public, $object, $permission, $typeofdata, $moreparam, '', 0); + print '
    '."\n"; + print '
    '."\n"; + print $form->editfieldval("NotePublic", $note_public, $value_public, $object, $permission, $typeofdata, '', null, null, $moreparam, 1)."\n"; + print '
    '."\n"; + print '
    '."\n"; +if (empty($user->socid)) { +// Private notes (always hidden to external users) +print '
    '."\n"; + $editmode = (GETPOST('action', 'aZ09') == 'edit'.$note_private); + print '
    '."\n"; + print $form->editfieldkey("NotePrivate", $note_private, $value_private, $object, $permission, $typeofdata, $moreparam, '', 0); + print '
    '."\n"; +print '
    '."\n"; + print $form->editfieldval("NotePrivate", $note_private, $value_private, $object, $permission, $typeofdata, '', null, null, $moreparam, 1); + print '
    '."\n"; +print '
    '."\n"; +} +print '
    '."\n"; +?> + diff --git a/htdocs/hrm/css/radio_js_number.css b/htdocs/hrm/css/radio_js_number.css new file mode 100644 index 00000000000..320b0ddc1f2 --- /dev/null +++ b/htdocs/hrm/css/radio_js_number.css @@ -0,0 +1,18 @@ +.radio_js_bloc_number { + display:inline-block; + padding:5px 7px; + min-width:20px; + border-radius:3px; + border:1px solid #ccc; + background:#eee; + color:#555; + cursor:pointer; + margin:2px; + text-align:center; +} +.radio_js_bloc_number.selected { + transition:0.2s ease background; + background:#888; + color:#fff; + border-color:#555; +} \ No newline at end of file diff --git a/htdocs/hrm/css/style.css b/htdocs/hrm/css/style.css new file mode 100644 index 00000000000..0c8ba81d827 --- /dev/null +++ b/htdocs/hrm/css/style.css @@ -0,0 +1,130 @@ +#compare ul,#compare li,#compare h3 {margin: 0; padding: 0;} + +#compare div { + margin: 20px; +} + +#compare ul { + list-style-type: none; + width: 100%; +} + +#compare h3 { + font: bold 20px/1.5 Helvetica, Verdana, sans-serif; +} + +#compare li img { + float: left; + margin: 0 15px 0 0; + max-width:80px; +} + +#compare li p { + font: 200 12px/1.5 Georgia, Times New Roman, serif; +} + +#compare li { + padding: 10px; + overflow: auto; + border-bottom: 2px solid #98b880; +} +#compare ul.competence li,#compare ul.note li { + height:48px; + overflow: hidden; + border-bottom: 2px solid #6C286C; +} + +#compare li:hover { + background: #eee; + cursor: pointer; +} + +#compare li.disabled { + color:#999; + border-bottom: 2px solid #ff0000; +} + +#compare li.disabled img,#compare li.disabled p { + display:none; +} + +span.note { + font: bold Helvetica, Verdana, sans-serif; + background: #eee none repeat scroll 0 0; + border: 1px solid #ccc; + border-radius: 3px; + color: #555; + cursor: pointer; + display: inline-block; + margin: 2px; + min-width: 20px; + padding: 5px 7px; + text-align: center; + font-weight: bold; +} +span.note.none { + background: #BA7777 none repeat scroll 0 0; +} +#compare ul.diff li { + text-align: center; + border-bottom:0 none; + height:48px; + overflow: hidden; + border-bottom: 2px solid #77BABA; +} +span.diffnote { + display: inline-block; + background: #c3e6cb; + width:42px; + height: 42px; + overflow: hidden; + border:none; + box-sizing: border-box; +} +span.diffnote.little { + width:25px; + height: 25px; + border-width:3px; +} +span.toohappy { + background: #3097D1; + border:5px solid #3097D1; +} +span.veryhappy { + border:5px solid #3097D1; +} +span.toosad { + background: #ccc; + border:5px solid #ccc; +} +span.sad { + background:#bd4147; +} +/*span.diffnote { + display: inline-block; + background: url(img/smiley.png); + width:42px; + height: 42px; + overflow: hidden; +} +span.toohappy { + background-position: -105px 0px; +} +span.veryhappy { + background-position: -53px 0px; +} +span.toosad { + background-position: -105px -52px; +} +span.sad { + background-position: 0px -52px; +}*/ + +span.bubble { + background-color: #ccc; + border:1px; + display:inline-block; + width:20px; + height:20px; + border-radius:20px; +} \ No newline at end of file diff --git a/htdocs/hrm/evaluation_agenda.php b/htdocs/hrm/evaluation_agenda.php new file mode 100644 index 00000000000..8524f6df3d9 --- /dev/null +++ b/htdocs/hrm/evaluation_agenda.php @@ -0,0 +1,282 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file evaluation_agenda.php + * \ingroup hr + * \brief Tab of events on Evaluation + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/class/evaluation.class.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/lib/hrm_evaluation.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/class/job.class.php'; + + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +if (GETPOST('actioncode', 'array')) { + $actioncode = GETPOST('actioncode', 'array', 3); + if (!count($actioncode)) { + $actioncode = '0'; + } +} else { + $actioncode = GETPOST("actioncode", "alpha", 3) ? GETPOST("actioncode", "alpha", 3) : (GETPOST("actioncode") == '0' ? '0' : (empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT)); +} +$search_agenda_label = GETPOST('search_agenda_label'); + +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortfield) { + $sortfield = 'a.datep,a.id'; +} +if (!$sortorder) { + $sortorder = 'DESC,DESC'; +} + +// Initialize technical objects +$object = new Evaluation($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('evaluationagenda', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity]."/".$object->id; +} + +$permissiontoadd = $user->rights->hrm->evaluation->write; // Used by the include of actions_addupdatedelete.inc.php +$permissiontoread = $user->rights->hrm->evaluation->read; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array('id'=>$id); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Cancel + if (GETPOST('cancel', 'alpha') && !empty($backtopage)) { + header("Location: ".$backtopage); + exit; + } + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + $actioncode = ''; + $search_agenda_label = ''; + } +} + + + +/* + * View + */ + +$form = new Form($db); + +if ($object->id > 0) { + $title = $langs->trans("Agenda"); + //if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/thirdpartynameonly/',$conf->global->MAIN_HTML_TITLE) && $object->name) $title=$object->name." - ".$title; + $help_url = 'EN:Module_Agenda_En'; + llxHeader('', $title, $help_url); + + if (!empty($conf->notification->enabled)) { + $langs->load("mails"); + } + $head = evaluationPrepareHead($object); + + + print dol_get_fiche_head($head, 'agenda', $langs->trans("Agenda"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref .= $langs->trans('Label').' : '.$object->label; + $u_position = new User(($db)); + $u_position->fetch($object->fk_user); + $morehtmlref .= '
    '.$langs->trans('Employee').' : '.$u_position->getNomUrl(1); + $job = new Job($db); + $job->fetch($object->fk_job); + $morehtmlref .= '
    '.$langs->trans('Job').' : '.$job->getNomUrl(1); + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + print '
    '; + + $object->info($object->id); + dol_print_object_info($object, 1); + + print '
    '; + + print dol_get_fiche_end(); + + + + // Actions buttons + + $objthirdparty = $object; + $objcon = new stdClass(); + + $out = '&origin='.urlencode($object->element.'@'.$object->module).'&originid='.urlencode($object->id); + $urlbacktopage = $_SERVER['PHP_SELF'].'?id='.$object->id; + $out .= '&backtopage='.urlencode($urlbacktopage); + $permok = $user->rights->agenda->myactions->create; + if ((!empty($objthirdparty->id) || !empty($objcon->id)) && $permok) { + //$out.='trans("AddAnAction"),'filenew'); + //$out.=""; + } + + + print '
    '; + + if (!empty($conf->agenda->enabled)) { + if (!empty($user->rights->agenda->myactions->create) || !empty($user->rights->agenda->allactions->create)) { + print ''.$langs->trans("AddAction").''; + } else { + print ''.$langs->trans("AddAction").''; + } + } + + print '
    '; + + if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { + $param = '&id='.$object->id.'&socid='.$socid; + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); + } + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); + } + + + //print load_fiche_titre($langs->trans("ActionsOnEvaluation"), '', ''); + + // List of all actions + $filters = array(); + $filters['search_agenda_label'] = $search_agenda_label; + + // TODO Replace this with same code than into list.php + show_actions_done($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder, $object->module); + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php new file mode 100644 index 00000000000..48554770107 --- /dev/null +++ b/htdocs/hrm/evaluation_card.php @@ -0,0 +1,763 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file evaluation_card.php + * \ingroup hrm + * \brief Page to create/edit/view evaluation + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/class/evaluation.class.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/class/skill.class.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/class/skillrank.class.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/lib/hrm_evaluation.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/lib/hrm_skillrank.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'evaluationcard'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); +$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); +//$lineid = GETPOST('lineid', 'int'); + +// Initialize technical objects +$object = new Evaluation($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('evaluationcard', 'globalcard')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Initialize array of search criterias +$search_all = GETPOST("search_all", 'alpha'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_'.$key, 'alpha')) { + $search[$key] = GETPOST('search_'.$key, 'alpha'); + } +} + +if (empty($action) && empty($id) && empty($ref)) { + $action = 'view'; +} + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once. + + +$permissiontoread = $user->rights->hrm->evaluation->read; +$permissiontoadd = $user->rights->hrm->evaluation->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php +$permissiontovalidate = $user->rights->hrm->evaluation->validate; +$permissiontoClose = $user->rights->hrm->evaluation->write; +$permissiontodelete = $user->rights->hrm->evaluation->delete/* || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT)*/; +$permissiondellink = $user->rights->hrm->evaluation->write; // Used by the include of actions_dellink.inc.php +$upload_dir = $conf->hrm->multidir_output[isset($object->entity) ? $object->entity : 1].'/evaluation'; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread || ($action === 'create' && !$permissiontoadd)) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $error = 0; + + $backurlforlist = dol_buildpath('/hrm/evaluation_list.php', 1); + + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = dol_buildpath('/hrm/evaluation_card.php', 1).'?id='.($id > 0 ? $id : '__ID__'); + } + } + } + + $triggermodname = 'hrm_EVALUATION_MODIFY'; // Name of trigger action code to execute when we modify record + + // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen + include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php'; + + // Actions when linking object each other + include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; + + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + + // Action to move up and down lines of object + //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; + + // Action to build doc + include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; + + if ($action == 'set_thirdparty' && $permissiontoadd) { + $object->setValueFrom('fk_soc', GETPOST('fk_soc', 'int'), '', '', 'date', '', $user, $triggermodname); + } + if ($action == 'classin' && $permissiontoadd) { + $object->setProject(GETPOST('projectid', 'int')); + } + + // Actions to send emails + $triggersendname = 'hrm_EVALUATION_SENTBYMAIL'; + $autocopy = 'MAIN_MAIL_AUTOCOPY_EVALUATION_TO'; + $trackid = 'evaluation'.$object->id; + include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; + + if ($action == 'saveSkill') { + $TNote = GETPOST('TNote', 'array'); + if (!empty($TNote)) { + foreach ($object->lines as $line) { + $line->rank = $TNote[$line->fk_skill]; + $line->update($user); + } + } + } + + if ($action == 'close') { + // save evaldet lines to user; + $sk = new SkillRank($db); + $SkillrecordsForActiveUser = $sk->fetchAll('ASC', 'fk_skill', 0, 0, array("customsql"=>"fk_object = ".$object->fk_user ." AND objecttype ='".SkillRank::SKILLRANK_TYPE_USER."'"), 'AND'); + + $errors = 0; + // we go through the evaldets of the eval + foreach ($object->lines as $key => $line) { + // no reference .. we add the line to use it + if (count($SkillrecordsForActiveUser) == 0) { + if ($res > 0) { + $newSkill = new SkillRank($db); + $resCreate = $newSkill->cloneFromCurrentSkill($line, $user, $object->fk_user); + + if ($resCreate <= 0) { + $errors++; + setEventMessage($langs->trans('ErrorCreateUserSkill'), $line->fk_skill); + } + } else { + setEventMessage($langs->trans('NoSkilRankLoaded')); + } + } else { + //check if the skill is present to use it + $find = false; + $keyFind = 0; + foreach ($SkillrecordsForActiveUser as $k => $sr) { + if ($sr->fk_skill == $line->fk_skill) { + $keyFind = $k; + $find = true; + break; + } + } + //we update the skill user + if ($find) { + $updSkill = $SkillrecordsForActiveUser[$k]; + + $updSkill->rank = $line->rank; + $updSkill->update($user); + } else { // sinon on ajoute la skill + $newSkill = new SkillRank($db); + $resCreate = $newSkill->cloneFromCurrentSkill($line, $user, $object->fk_user); + } + } + } + $object->setStatut(Evaluation::STATUS_CLOSED); + } + + if ($action == 'reopen' ) { + // no update here we just change the evaluation status + $object->setStatut(Evaluation::STATUS_VALIDATED); + } +} + + + + +/* + * View + * + * Put here all code to build page + */ + +$form = new Form($db); +$formfile = new FormFile($db); +$formproject = new FormProjets($db); + +$title = $langs->trans("Evaluation"); +$help_url = ''; +llxHeader('', $title, $help_url); + +print ''; + +// Part to create +if ($action == 'create') { + print load_fiche_titre($langs->trans("NewEval"), '', 'object_' . $object->picto); + + print '
    '; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(array(), ''); + + // Set some default values + //if (! GETPOSTISSET('fieldname')) $_POST['fieldname'] = 'myvalue'; + + print ''."\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_add.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php'; + + print '
    '."\n"; + + print dol_get_fiche_end(); + + print '
    '; + print ''; + print '  '; + print ''; // Cancel for create does not post form if we don't know the backtopage + print '
    '; + + print '
    '; +} + +// Part to edit record +if (($id || $ref) && $action == 'edit') { + print load_fiche_titre($langs->trans("Evaluation"), '', 'object_'.$object->picto); + + print '
    '; + print ''; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(); + + print ''."\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_edit.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_edit.tpl.php'; + + print '
    '; + + print dol_get_fiche_end(); + + print '
    '; + print '   '; + print '
    '; + + print '
    '; +} + +// Part to show record +if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { + $res = $object->fetch_optionals(); + + $head = evaluationPrepareHead($object); + print dol_get_fiche_head($head, 'card', $langs->trans("Workstation"), -1, $object->picto); + + $formconfirm = ''; + + if ($action == 'validate' && $permissiontovalidate) { + // Confirm validate proposal + $error = 0; + + // We verify whether the object is provisionally numbering + $ref = substr($object->ref, 1, 4); + if ($ref == 'PROV') { + $numref = $object->getNextNumRef(); + if (empty($numref)) { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); + } + } else { + $numref = $object->ref; + } + + $text = $langs->trans('ConfirmValidateEvaluation', $numref); + if (!empty($conf->notification->enabled)) { + require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php'; + $notify = new Notify($db); + $text .= '
    '; + $text .= $notify->confirmMessage('HRM_EVALUATION_VALIDATE', $object->socid, $object); + } + + if (!$error) { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateEvaluation'), $text, 'confirm_validate', '', 0, 1); + } + } + + // Confirmation to delete + if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteEvaluation'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); + } + // Confirmation to delete line + if ($action == 'deleteline') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1); + } + // Clone confirmation + if ($action == 'clone') { + // Create an array for form + $formquestion = array(); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); + } + + // Confirmation of action xxxx + if ($action == 'xxx') { + $formquestion = array(); + + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('XXX'), $text, 'confirm_xxx', $formquestion, 0, 1, 220); + } + + // Call Hook formConfirm + $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + $formconfirm .= $hookmanager->resPrint; + } elseif ($reshook > 0) { + $formconfirm = $hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref .= $langs->trans('Label').' : '.$object->label; + $u_position = new User(($db)); + $u_position->fetch($object->fk_user); + $morehtmlref .= '
    '.$langs->trans('Employee').' : '.$u_position->getNomUrl(1); + $job = new Job($db); + $job->fetch($object->fk_job); + $morehtmlref .= '
    '.$langs->trans('Job').' : '.$job->getNomUrl(1); + $morehtmlref .= '
    '; + + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
    '; + print '
    '; + print '
    '; + print ''."\n"; + + $object->fields['label']['visible']=0; // Already in banner + $object->fields['fk_user']['visible']=0; // Already in banner + $object->fields['fk_job']['visible']=0; // Already in banner + include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php'; + + // Other attributes. Fields from hook formObjectOptions and Extrafields. + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; + + print '
    '; + print '
    '; + print '
    '; + + print '
    '; + + print dol_get_fiche_end(); + + + /* + * Lines + */ + + if (!empty($object->table_element_line)) { + if ($object->status == Evaluation::STATUS_DRAFT) { + $result = $object->getLinesArray(); + + print '
    + + + + + + '; + + if (!empty($conf->use_javascript_ajax) && $object->status == 0) { + include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php'; + } + + print '
    '; + /*if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + }*/ + + + if (!empty($object->lines)) { + print '
    '.$langs->trans('Skill').''.$langs->trans('Description').''.$langs->trans('Rank').'
    '; + $object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, ''); + print '
    '; + } + + + + if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) { + print ''; + + if ($object->status == $object::STATUS_DRAFT && $permissiontoadd) { + print '
    '; + print ''; + print '
    '; + } + } + + + print '
    '; + + print "
    \n"; + print "
    "; + } + } + + + // Buttons for actions + + if ($action != 'presend' && $action != 'editline') { + print '
    '."\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + if (empty($reshook)) { + // Send + if (empty($user->socid)) { + print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=presend&mode=init&token='.newToken().'#formmailbeforetitle'); + } + + // Back to draft + if ($object->status == $object::STATUS_VALIDATED) { + print dolGetButtonAction($langs->trans('SetToDraft'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_setdraft&confirm=yes&token='.newToken(), '', $permissiontoadd); + print dolGetButtonAction($langs->trans('Close'), '', 'close', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=close&token='.newToken(), '', $permissiontodelete || ($object->status == $object::STATUS_CLOSED && $permissiontoclose)); + } elseif ($object->status != $object::STATUS_CLOSED) { + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken(), '', $permissiontoadd); + } + + if ($object->status == $object::STATUS_CLOSED) { + print dolGetButtonAction($langs->trans('reopen'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken(), '', $permissiontoadd); + } + + + // Validate + if ($object->status == $object::STATUS_DRAFT) { + if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) { + print dolGetButtonAction($langs->trans('SaveRank').' '.$langs->trans('and').' '.$langs->trans('Valid'), '', 'default', '#', 'btn_valid', $permissiontovalidate); + } else { + $langs->load("errors"); + print dolGetButtonAction($langs->trans("ErrorAddAtLeastOneLineFirst"), $langs->trans("Validate"), 'default', '#', '', 0); + } + } + + + // Delete (need delete permission, or if draft, just need create/modify permission) + print dolGetButtonAction($langs->trans('Delete'), '', 'delete', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=delete&token='.newToken(), '', $permissiontodelete); + } + + + print '
    '."\n"; + } + + // list of comparison + if ($object->status != Evaluation::STATUS_DRAFT) { + // Recovery of skills related to this evaluation + + $sql = 'select'; + $sql .= ' e.ref,'; + $sql .= ' e.date_creation,'; + $sql .= ' e.fk_job,'; + $sql .= ' j.label as refjob,'; + $sql .= ' ed.fk_skill,'; + + $sql .= ' sk.label as skilllabel,'; + $sql .= ' sk.skill_type,'; + $sql .= ' sk.description,'; + $sql .= ' ed.rank,'; + $sql .= ' ed.required_rank,'; + $sql .= ' ed.rank as userRankForSkill,'; + $sql .= ' skdet_user.description as userRankForSkillDesc,'; + $sql .= ' skdet_required.description as required_rank_desc'; + + $sql .= ' FROM ' . MAIN_DB_PREFIX . 'hrm_evaluation as e'; + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'hrm_evaluationdet as ed ON e.rowid = ed.fk_evaluation'; + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'hrm_job as j ON e.fk_job = j.rowid'; + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'hrm_skill as sk ON ed.fk_skill = sk.rowid'; + $sql .= ' INNER JOIN ' . MAIN_DB_PREFIX . 'hrm_skilldet as skdet_user ON (skdet_user.fk_skill = sk.rowid AND skdet_user.rank = ed.rank)'; + //$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "hrm_skillrank as skr ON (j.rowid = skr.fk_object AND skr.fk_skill = ed.fk_skill AND skr.objecttype = 'job')"; + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'hrm_skilldet as skdet_required ON (skdet_required.fk_skill = sk.rowid AND skdet_required.rank = ed.required_rank)'; + $sql .= " WHERE e.rowid =" . $object->id; + + // echo $sql; + + $resql = $db->query($sql); + $Tab = array(); + + if ($resql) { + $num = 0; + while ($obj = $db->fetch_object($resql)) { + $Tab[$num] = new stdClass(); + $class = ''; + $Tab[$num]->skill_type = $obj->skill_type; + $Tab[$num]->skill_id = $obj->fk_skill; + $Tab[$num]->skilllabel = $obj->skilllabel; + $Tab[$num]->description = $obj->description; + $Tab[$num]->userRankForSkill = '' . $obj->userRankForSkill . ''; + $Tab[$num]->required_rank = '' . $obj->required_rank . ''; + + if ($obj->userRankForSkill > $obj->required_rank) { + $class .= 'veryhappy'; + } elseif ($obj->userRankForSkill == $obj->required_rank) { + $class .= 'happy'; + } elseif ($obj->userRankForSkill < $obj->required_rank) { + $class .= 'sad'; + } + + $Tab[$num]->result = ' '; + + $num++; + } + + print load_fiche_titre($langs->trans("SkillList"), '', 'title'); + print '
    '; + print ''; + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + $sk = new Skill($db); + foreach ($Tab as $t) { + $sk->fetch($t->skill_id); + print ''; + print ' '; + print ' '; + print ' '; + print ' '; + print ' '; + print ' '; + print ''; + } + + print '
    ' . $langs->trans("TypeSkill") . ' ' . $langs->trans("Label") . '' . $langs->trans("Description") . '' . $langs->trans("UserRank") . '' . $langs->trans("RequiredRank") . '' . $langs->trans("Result") . '
    ' . Skill::typeCodeToLabel($t->skill_type) . '' . $sk->getNomUrl(1) . '' . $t->description . '' . $t->userRankForSkill . '' . $t->required_rank . '' . $t->result . '
    '; + + ?> + + + +
    '; + print ''; // ancre + + $includedocgeneration = 0; + + // Documents + if ($includedocgeneration) { + $objref = dol_sanitizeFileName($object->ref); + $relativepath = $objref.'/'.$objref.'.pdf'; + $filedir = $conf->hrm->dir_output.'/'.$object->element.'/'.$objref; + $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; + $genallowed = $user->rights->hrm->evaluation->read; // If you can read, you can build the PDF to read content + $delallowed = $user->rights->hrm->evaluation->write; // If you can create/edit, you can remove a file on card + print $formfile->showdocuments('hrm:Evaluation', $object->element.'/'.$objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang); + } + + // Show links to link elements + $linktoelem = $form->showLinkToObjectBlock($object, null, array('evaluation')); + $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + + + print '
    '; + + $MAXEVENT = 10; + + $morehtmlright = ''; + $morehtmlright .= $langs->trans("SeeAll"); + $morehtmlright .= ''; + + // List of actions on element + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; + $formactions = new FormActions($db); + $somethingshown = $formactions->showactions($object, $object->element.'@'.$object->module, (is_object($object->thirdparty) ? $object->thirdparty->id : 0), 1, '', $MAXEVENT, '', $morehtmlright); + + print '
    '; + } + + //Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } + + // Presend form + $modelmail = 'evaluation'; + $defaulttopic = 'InformationMessage'; + $diroutput = $conf->hrm->dir_output; + $trackid = 'evaluation'.$object->id; + + include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php'; +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/evaluation_contact.php b/htdocs/hrm/evaluation_contact.php new file mode 100644 index 00000000000..db6d93f7ef7 --- /dev/null +++ b/htdocs/hrm/evaluation_contact.php @@ -0,0 +1,220 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file evaluation_contact.php + * \ingroup hrm + * \brief Tab for contacts linked to Evaluation + */ + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +dol_include_once('/hrm/class/evaluation.class.php'); +dol_include_once('/hrm/lib/hrm_evaluation.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies", "other", "mails")); + +$id = (GETPOST('id') ?GETPOST('id', 'int') : GETPOST('facid', 'int')); // For backward compatibility +$ref = GETPOST('ref', 'alpha'); +$lineid = GETPOST('lineid', 'int'); +$socid = GETPOST('socid', 'int'); +$action = GETPOST('action', 'aZ09'); + +// Initialize technical objects +$object = new Evaluation($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('evaluationcontact', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +$permission = $user->rights->hrm->evaluation->write; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//if (empty($conf->hrm->enabled)) accessforbidden(); +//if (!$permissiontoread) accessforbidden(); + + +/* + * Add a new contact + */ + +if ($action == 'addcontact' && $permission) { + $contactid = (GETPOST('userid') ? GETPOST('userid', 'int') : GETPOST('contactid', 'int')); + $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type')); + $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09')); + + if ($result >= 0) { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } else { + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $langs->load("errors"); + setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors'); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } +} elseif ($action == 'swapstatut' && $permission) { + // Toggle the status of a contact + $result = $object->swapContactStatus(GETPOST('ligne', 'int')); +} elseif ($action == 'deletecontact' && $permission) { + // Deletes a contact + $result = $object->delete_contact($lineid); + + if ($result >= 0) { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } else { + dol_print_error($db); + } +} + + +/* + * View + */ + +$title = $langs->trans('Evaluation')." - ".$langs->trans('ContactsAddresses'); +$help_url = ''; +//$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('', $title, $help_url); + +$form = new Form($db); +$formcompany = new FormCompany($db); +$contactstatic = new Contact($db); +$userstatic = new User($db); + + +/* *************************************************************************** */ +/* */ +/* View and edit mode */ +/* */ +/* *************************************************************************** */ + +if ($object->id) { + /* + * Show tabs + */ + $head = evaluationPrepareHead($object); + + print dol_get_fiche_head($head, 'contact', '', -1, $object->picto); + + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + /* + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
    '.$langs->trans('ThirdParty') . ' : ' . (is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
    '.$langs->trans('Project') . ' '; + if ($permissiontoadd) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
    '; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
    '; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ': '.$proj->getNomUrl(); + } else { + $morehtmlref .= ''; + } + } + }*/ + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0, '', '', 1); + + print dol_get_fiche_end(); + + print '
    '; + + // Contacts lines (modules that overwrite templates must declare this into descriptor) + $dirtpls = array_merge($conf->modules_parts['tpl'], array('/core/tpl')); + foreach ($dirtpls as $reldir) { + $res = @include dol_buildpath($reldir.'/contacts.tpl.php'); + if ($res) { + break; + } + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/evaluation_document.php b/htdocs/hrm/evaluation_document.php new file mode 100644 index 00000000000..06cbd7a621a --- /dev/null +++ b/htdocs/hrm/evaluation_document.php @@ -0,0 +1,224 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file evaluation_document.php + * \ingroup hrm + * \brief Tab for documents linked to Evaluation + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/evaluation.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_evaluation.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies", "other", "mails")); + + +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm'); +$id = (GETPOST('socid', 'int') ? GETPOST('socid', 'int') : GETPOST('id', 'int')); +$ref = GETPOST('ref', 'alpha'); + +// Get parameters +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortorder) { + $sortorder = "ASC"; +} +if (!$sortfield) { + $sortfield = "name"; +} +//if (! $sortfield) $sortfield="position_name"; + +// Initialize technical objects +$object = new Evaluation($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('evaluationdocument', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity ? $object->entity : $conf->entity]."/evaluation/".get_exdir(0, 0, 0, 1, $object); +} + +$permissiontoadd = $user->rights->hrm->evaluation->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles.inc.php +$permissiontoread = $user->rights->hrm->evaluation->read; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; + + +/* + * View + */ + +$form = new Form($db); + +$title = $langs->trans("Evaluation").' - '.$langs->trans("Files"); +$help_url = ''; +//$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('', $title, $help_url); + +if ($object->id) { + /* + * Show tabs + */ + $head = evaluationPrepareHead($object); + + print dol_get_fiche_head($head, 'document', $langs->trans("Documents"), -1, $object->picto); + + + // Build file list + $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1); + $totalsize = 0; + foreach ($filearray as $key => $file) { + $totalsize += $file['size']; + } + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref .= $langs->trans('Label').' : '.$object->label; + $u_position = new User(($db)); + $u_position->fetch($object->fk_user); + $morehtmlref .= '
    '.$langs->trans('Employee').' : '.$u_position->getNomUrl(1); + $job = new Job($db); + $job->fetch($object->fk_job); + $morehtmlref .= '
    '.$langs->trans('Job').' : '.$job->getNomUrl(1); + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + + print '
    '; + print ''; + + // Number of files + print ''; + + // Total size + print ''; + + print '
    '.$langs->trans("NbOfAttachedFiles").''.count($filearray).'
    '.$langs->trans("TotalSizeOfAttachedFiles").''.$totalsize.' '.$langs->trans("bytes").'
    '; + + print '
    '; + + print dol_get_fiche_end(); + + $modulepart = 'hrm'; + $permtoedit = $permissiontoadd; + $param = '&id='.$object->id; + + //$relativepathwithnofile='evaluation/' . dol_sanitizeFileName($object->id).'/'; + $relativepathwithnofile = 'evaluation/'.dol_sanitizeFileName($object->ref).'/'; + + include DOL_DOCUMENT_ROOT.'/core/tpl/document_actions_post_headers.tpl.php'; +} else { + accessforbidden('', 0, 1); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/evaluation_list.php b/htdocs/hrm/evaluation_list.php new file mode 100644 index 00000000000..6a74cb9bc6b --- /dev/null +++ b/htdocs/hrm/evaluation_list.php @@ -0,0 +1,731 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file evaluation_list.php + * \ingroup hrm + * \brief List page for evaluation + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; + +// load hrm libraries +require_once __DIR__.'/class/evaluation.class.php'; + +// for other modules +//dol_include_once('/othermodule/class/otherobject.class.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +$action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... +$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) +$show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? +$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation +$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button +$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'evaluationlist'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + +$id = GETPOST('id', 'int'); + +// Load variable for pagination +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST('sortfield', 'aZ09comma'); +$sortorder = GETPOST('sortorder', 'aZ09comma'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + // If $page is not defined, or '' or -1 or if we click on clear filters + $page = 0; +} +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +// Initialize technical objects +$object = new Evaluation($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('evaluationlist')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); +//$extrafields->fetch_name_optionals_label($object->table_element_line); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Default sort order (if not yet defined by previous GETPOST) +if (!$sortfield) { + reset($object->fields); // Reset is required to avoid key() to return null. + $sortfield = "t.".key($object->fields); // Set here default search field. By default 1st field in definition. +} +if (!$sortorder) { + $sortorder = "ASC"; +} + +// Initialize array of search criterias +$search_all = GETPOST('search_all', 'alphanohtml') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_'.$key, 'alpha') !== '') { + $search[$key] = GETPOST('search_'.$key, 'alpha'); + } + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int')); + $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int')); + } +} + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array(); +foreach ($object->fields as $key => $val) { + if (!empty($val['searchall'])) { + $fieldstosearchall['t.'.$key] = $val['label']; + } +} + +// Definition of array of fields for columns +$arrayfields = array(); +foreach ($object->fields as $key => $val) { + // If $val['visible']==0, then we never show the field + if (!empty($val['visible'])) { + $visible = (int) dol_eval($val['visible'], 1); + $arrayfields['t.'.$key] = array( + 'label'=>$val['label'], + 'checked'=>(($visible < 0) ? 0 : 1), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'position'=>$val['position'], + 'help'=> isset($val['help']) ? $val['help'] : '' + ); + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; + +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + +$permissiontoread = $user->rights->hrm->evaluation->read; +$permissiontoadd = $user->rights->hrm->evaluation->write; +$permissiontodelete = $user->rights->hrm->evaluation->delete; + +// Security check +if (empty($conf->hrm->enabled)) { + accessforbidden('Module not enabled'); +} + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) accessforbidden(); +//$socid = 0; if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//if (empty($conf->hrm->enabled)) accessforbidden(); +//if (!$permissiontoread) accessforbidden(); + + + +/* + * Actions + */ + +if (GETPOST('cancel', 'alpha')) { + $action = 'list'; + $massaction = ''; +} +if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { + $massaction = ''; +} + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + foreach ($object->fields as $key => $val) { + $search[$key] = ''; + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = ''; + $search[$key.'_dtend'] = ''; + } + } + $toselect = array(); + $search_array_options = array(); + } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha') + || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) { + $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation + } + + // Mass actions + $objectclass = 'Evaluation'; + $objectlabel = 'Evaluation'; + $uploaddir = $conf->hrm->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + + +/* + * View + */ + +$form = new Form($db); + +$now = dol_now(); + +//$help_url="EN:Module_Evaluation|FR:Module_Evaluation_FR|ES:Módulo_Evaluation"; +$help_url = ''; +$title = $langs->trans("List").' '.$langs->trans('Evaluations'); +$morejs = array(); +$morecss = array(); + + +// Build and execute select +// -------------------------------------------------------------------- +$sql = 'SELECT '; +$sql .= $object->getFieldList('t'); +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key.', ' : ''); + } +} +// Add fields from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= preg_replace('/^,/', '', $hookmanager->resPrint); +$sql = preg_replace('/,\s*$/', '', $sql); +$sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; +if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; +} +// Add table from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +if ($object->ismultientitymanaged == 1) { + $sql .= " WHERE t.entity IN (".getEntity($object->element).")"; +} else { + $sql .= " WHERE 1 = 1"; +} +foreach ($search as $key => $val) { + if (array_key_exists($key, $object->fields)) { + if ($key == 'status' && $search[$key] == -1) { + continue; + } + $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); + if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { + if ($search[$key] == '-1' || $search[$key] === '0') { + $search[$key] = ''; + } + $mode_search = 2; + } + if ($search[$key] != '') { + $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search)); + } + } else { + if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') { + $columnName=preg_replace('/(_dtstart|_dtend)$/', '', $key); + if (preg_match('/^(date|timestamp|datetime)/', $object->fields[$columnName]['type'])) { + if (preg_match('/_dtstart$/', $key)) { + $sql .= " AND t." . $columnName . " >= '" . $db->idate($search[$key]) . "'"; + } + if (preg_match('/_dtend$/', $key)) { + $sql .= " AND t." . $columnName . " <= '" . $db->idate($search[$key]) . "'"; + } + } + } + } +} +if ($search_all) { + $sql .= natural_search(array_keys($fieldstosearchall), $search_all); +} +//$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear); +// Add where from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; + +/* If a group by is required +$sql .= " GROUP BY "; +foreach($object->fields as $key => $val) { + $sql .= 't.'.$key.', '; +} +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : ''); + } +} +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +$sql = preg_replace('/,\s*$/', '', $sql); +*/ + +$sql .= $db->order($sortfield, $sortorder); + +// Count total nb of records +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + $resql = $db->query($sql); + $nbtotalofrecords = $db->num_rows($resql); + if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + $page = 0; + $offset = 0; + } +} +// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. +if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { + $num = $nbtotalofrecords; +} else { + if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); + } + + $resql = $db->query($sql); + if (!$resql) { + dol_print_error($db); + exit; + } + + $num = $db->num_rows($resql); +} + +// Direct jump if only one record found +if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { + $obj = $db->fetch_object($resql); + $id = $obj->rowid; + header("Location: ".dol_buildpath('/hrm/evaluation_card.php', 1).'?id='.$id); + exit; +} + + +// Output page +// -------------------------------------------------------------------- + +llxHeader('', $title, $help_url, '', 0, 0, $morejs, $morecss, '', ''); + +// Example : Adding jquery code +// print ''; + +$arrayofselected = is_array($toselect) ? $toselect : array(); + +$param = ''; +if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); +} +if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); +} +foreach ($search as $key => $val) { + if (is_array($search[$key]) && count($search[$key])) { + foreach ($search[$key] as $skey) { + $param .= '&search_'.$key.'[]='.urlencode($skey); + } + } else { + $param .= '&search_'.$key.'='.urlencode($search[$key]); + } +} +if ($optioncss != '') { + $param .= '&optioncss='.urlencode($optioncss); +} +// Add $param from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; +// Add $param from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook +$param .= $hookmanager->resPrint; + +// List of mass actions available +$arrayofmassactions = array( + //'validate'=>img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate"), + //'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"), + //'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"), + //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), +); +if ($permissiontodelete) { + $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); +} +if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete'))) { + $arrayofmassactions = array(); +} +$massactionbutton = $form->selectMassAction('', $arrayofmassactions); + +print '
    '."\n"; +if ($optioncss != '') { + print ''; +} +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +$newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/hrm/evaluation_card.php', 1).'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd); + +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'object_'.$object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1); + +// Add code for pre mass action (confirmation or email presend form) +$topicmail = "SendEvaluationRef"; +$modelmail = "evaluation"; +$objecttmp = new Evaluation($db); +$trackid = 'xxxx'.$object->id; +include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; + +if ($search_all) { + foreach ($fieldstosearchall as $key => $val) { + $fieldstosearchall[$key] = $langs->trans($val); + } + print '
    '.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'
    '; +} + +$moreforfilter = ''; +/*$moreforfilter.='
    '; +$moreforfilter.= $langs->trans('MyFilter') . ': '; +$moreforfilter.= '
    ';*/ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +if (empty($reshook)) { + $moreforfilter .= $hookmanager->resPrint; +} else { + $moreforfilter = $hookmanager->resPrint; +} + +if (!empty($moreforfilter)) { + print '
    '; + print $moreforfilter; + print '
    '; +} + +$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + +print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table +print ''."\n"; + + +// Fields title search +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + +// Fields from hook +$parameters = array('arrayfields'=>$arrayfields); +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print ''; +print ''."\n"; + + +// Fields title label +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($cssforfield ? 'class="'.$cssforfield.'"' : ''), $sortfield, $sortorder, ($cssforfield ? $cssforfield.' ' : ''))."\n"; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; +// Hook fields +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +print ''."\n"; + + +// Detect if we need a fetch on each output line +$needToFetchEachLine = 0; +if (isset($extrafields->attributes[$object->table_element]['computed']) && is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0) { + foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val) { + if (preg_match('/\$object/', $val)) { + $needToFetchEachLine++; // There is at least one compute field that use $object + } + } +} + + +// Loop on record +// -------------------------------------------------------------------- +$i = 0; +$totalarray = array(); +$totalarray['nbfield'] = 0; +while ($i < ($limit ? min($num, $limit) : $num)) { + $obj = $db->fetch_object($resql); + if (empty($obj)) { + break; // Should not happen + } + + // Store properties in $object + $object->setVarsFromFetchObj($obj); + + // Show here line of result + print ''; + foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } + + if (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif ($key == 'ref') { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } + + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && !in_array($key, array('rowid', 'status')) && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; + + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + if ($key == 'status') { + print $object->getLibStatut(5); + } elseif ($key == 'rowid') { + print $object->showOutputField($val, $key, $object->id, ''); + } else { + print $object->showOutputField($val, $key, $object->$key, ''); + } + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + if (!empty($val['isameasure'])) { + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 't.'.$key; + } + if (!isset($totalarray['val'])) { + $totalarray['val'] = array(); + } + if (!isset($totalarray['val']['t.'.$key])) { + $totalarray['val']['t.'.$key] = 0; + } + $totalarray['val']['t.'.$key] += $object->$key; + } + } + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields, 'object'=>$object, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + + print ''."\n"; + + $i++; +} + +// Show total line +include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + +// If no record found +if ($num == 0) { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; +} + + +$db->free($resql); + +$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql); +$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print '
    '; + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + print $form->selectarray('search_'.$key, $val['arrayofkeyval'], (isset($search[$key]) ? $search[$key] : ''), $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth100', 1); + } elseif ((strpos($val['type'], 'integer:') === 0) || (strpos($val['type'], 'sellist:') === 0)) { + print $object->showInputField($val, $key, (isset($search[$key]) ? $search[$key] : ''), '', '', 'search_', 'maxwidth125', 1); + } elseif (!preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print ''; + } elseif (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print '
    '; + print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
    '; + print '
    '; + print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
    '; + } + print '
    '; +$searchpicto = $form->showFilterButtons(); +print $searchpicto; +print '
    '; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print '
    '.$langs->trans("NoRecordFound").'
    '."\n"; +print '
    '."\n"; + +print '
    '."\n"; + +if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords)) { + $hidegeneratedfilelistifempty = 1; + if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) { + $hidegeneratedfilelistifempty = 0; + } + + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + $formfile = new FormFile($db); + + // Show list of available documents + $urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder; + $urlsource .= str_replace('&', '&', $param); + + $filedir = $diroutputmassaction; + $genallowed = $permissiontoread; + $delallowed = $permissiontoadd; + + print $formfile->showdocuments('massfilesarea_hrm', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/evaluation_note.php b/htdocs/hrm/evaluation_note.php new file mode 100644 index 00000000000..aae7b56acaf --- /dev/null +++ b/htdocs/hrm/evaluation_note.php @@ -0,0 +1,182 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file evaluation_note.php + * \ingroup hrm + * \brief Tab for notes on Evaluation + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT . '/hrm/class/evaluation.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_evaluation.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new Evaluation($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('evaluationnote', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity]."/".$object->id; +} + +$permissionnote = $user->rights->hrm->evaluation->write; // Used by the include of actions_setnotes.inc.php +$permissiontoread = $user->rights->hrm->evaluation->read; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//if (empty($conf->hrm->enabled)) accessforbidden(); +//if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { + include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once +} + + +/* + * View + */ + +$form = new Form($db); + +//$help_url='EN:Customers_Orders|FR:Commandes_Clients|ES:Pedidos de clientes'; +$help_url = ''; +llxHeader('', $langs->trans('Evaluation'), $help_url); + +if ($id > 0 || !empty($ref)) { + $object->fetch_thirdparty(); + + $head = evaluationPrepareHead($object); + + print dol_get_fiche_head($head, 'note', $langs->trans('Notes'), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref .= $langs->trans('Label').' : '.$object->label; + $u_position = new User(($db)); + $u_position->fetch($object->fk_user); + $morehtmlref .= '
    '.$langs->trans('Employee').' : '.$u_position->getNomUrl(1); + $job = new Job($db); + $job->fetch($object->fk_job); + $morehtmlref .= '
    '.$langs->trans('Job').' : '.$job->getNomUrl(1); + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
    '; + print '
    '; + + + $cssclass = "titlefield"; + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + + print '
    '; + + print dol_get_fiche_end(); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/job_agenda.php b/htdocs/hrm/job_agenda.php new file mode 100644 index 00000000000..b6fbd6aee82 --- /dev/null +++ b/htdocs/hrm/job_agenda.php @@ -0,0 +1,275 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file job_agenda.php + * \ingroup hrm + * \brief Tab of events on Job + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +dol_include_once('/hrm/class/job.class.php'); +dol_include_once('/hrm/lib/hrm_job.lib.php'); + + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +if (GETPOST('actioncode', 'array')) { + $actioncode = GETPOST('actioncode', 'array', 3); + if (!count($actioncode)) { + $actioncode = '0'; + } +} else { + $actioncode = GETPOST("actioncode", "alpha", 3) ? GETPOST("actioncode", "alpha", 3) : (GETPOST("actioncode") == '0' ? '0' : (empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT)); +} +$search_agenda_label = GETPOST('search_agenda_label'); + +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortfield) { + $sortfield = 'a.datep,a.id'; +} +if (!$sortorder) { + $sortorder = 'DESC,DESC'; +} + +// Initialize technical objects +$object = new Job($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('jobagenda', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity]."/".$object->id; +} + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array('id'=>$id); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Cancel + if (GETPOST('cancel', 'alpha') && !empty($backtopage)) { + header("Location: ".$backtopage); + exit; + } + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + $actioncode = ''; + $search_agenda_label = ''; + } +} + + + +/* + * View + */ + +$form = new Form($db); + +if ($object->id > 0) { + $title = $langs->trans("Agenda"); + //if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/thirdpartynameonly/',$conf->global->MAIN_HTML_TITLE) && $object->name) $title=$object->name." - ".$title; + $help_url = 'EN:Module_Agenda_En'; + llxHeader('', $title, $help_url); + + if (!empty($conf->notification->enabled)) { + $langs->load("mails"); + } + $head = jobPrepareHead($object); + + + print dol_get_fiche_head($head, 'agenda', $langs->trans("Agenda"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + print '
    '; + print '
    '; + + $object->info($object->id); + dol_print_object_info($object, 1); + + print '
    '; + + print dol_get_fiche_end(); + + + + // Actions buttons + + $objthirdparty = $object; + $objcon = new stdClass(); + + $out = '&origin='.urlencode($object->element.'@'.$object->module).'&originid='.urlencode($object->id); + $urlbacktopage = $_SERVER['PHP_SELF'].'?id='.$object->id; + $out .= '&backtopage='.urlencode($urlbacktopage); + $permok = $user->rights->agenda->myactions->create; + if ((!empty($objthirdparty->id) || !empty($objcon->id)) && $permok) { + //$out.='trans("AddAnAction"),'filenew'); + //$out.=""; + } + + + print '
    '; + + if (!empty($conf->agenda->enabled)) { + if (!empty($user->rights->agenda->myactions->create) || !empty($user->rights->agenda->allactions->create)) { + print ''.$langs->trans("AddAction").''; + } else { + print ''.$langs->trans("AddAction").''; + } + } + + print '
    '; + + if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { + $param = '&id='.$object->id.'&socid='.$socid; + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); + } + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); + } + + + //print load_fiche_titre($langs->trans("ActionsOnJob"), '', ''); + + // List of all actions + $filters = array(); + $filters['search_agenda_label'] = $search_agenda_label; + + // TODO Replace this with same code than into list.php + show_actions_done($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder, $object->module); + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/job_card.php b/htdocs/hrm/job_card.php new file mode 100644 index 00000000000..8cb8d0fceee --- /dev/null +++ b/htdocs/hrm/job_card.php @@ -0,0 +1,532 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file job_card.php + * \ingroup hrm + * \brief Page to create/edit/view job + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"] . "/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; +$tmp2 = realpath(__FILE__); +$i = strlen($tmp) - 1; +$j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; + $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1)) . "/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1)) . "/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; +dol_include_once('/hrm/class/job.class.php'); +dol_include_once('/hrm/lib/hrm_job.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'jobcard'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); +$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); +//$lineid = GETPOST('lineid', 'int'); + +// Initialize technical objects +$object = new Job($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output . '/temp/massgeneration/' . $user->id; +$hookmanager->initHooks(array('jobcard', 'globalcard')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Initialize array of search criterias +$search_all = GETPOST("search_all", 'alpha'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_' . $key, 'alpha')) { + $search[$key] = GETPOST('search_' . $key, 'alpha'); + } +} + +if (empty($action) && empty($id) && empty($ref)) { + $action = 'view'; +} + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once. + + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php +$permissiontodelete = $user->rights->hrm->all->delete; +$upload_dir = $conf->hrm->multidir_output[isset($object->entity) ? $object->entity : 1] . '/job'; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread || ($action === 'create' && !$permissiontoadd)) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $error = 0; + + $backurlforlist = dol_buildpath('/hrm/job_list.php', 1); + + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = dol_buildpath('/hrm/job_card.php', 1) . '?id=' . ($id > 0 ? $id : '__ID__'); + } + } + } + + $triggermodname = 'hrm_JOB_MODIFY'; // Name of trigger action code to execute when we modify record + + + // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen + include DOL_DOCUMENT_ROOT . '/core/actions_addupdatedelete.inc.php'; + + // Actions when linking object each other + include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; + + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT . '/core/actions_printing.inc.php'; + + // Action to move up and down lines of object + //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; + + // Action to build doc + include DOL_DOCUMENT_ROOT . '/core/actions_builddoc.inc.php'; + + if ($action == 'set_thirdparty' && $permissiontoadd) { + $object->setValueFrom('fk_soc', GETPOST('fk_soc', 'int'), '', '', 'date', '', $user, $triggermodname); + } + if ($action == 'classin' && $permissiontoadd) { + $object->setProject(GETPOST('projectid', 'int')); + } + + // Actions to send emails + $triggersendname = 'hrm_JOB_SENTBYMAIL'; + $autocopy = 'MAIN_MAIL_AUTOCOPY_JOB_TO'; + $trackid = 'job' . $object->id; + include DOL_DOCUMENT_ROOT . '/core/actions_sendmails.inc.php'; +} + + +/* + * View + * + * Put here all code to build page + */ + +$form = new Form($db); +$formfile = new FormFile($db); +$formproject = new FormProjets($db); + +$title = $langs->trans("Job"); +$help_url = ''; +llxHeader('', $title, $help_url); + +// Example : Adding jquery code +// print ''; + + +// Part to create +if ($action == 'create') { + print load_fiche_titre($langs->trans("NewObject", $langs->transnoentities('Job')), '', 'object_' . $object->picto); + + print '
    '; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(array(), ''); + + // Set some default values + //if (! GETPOSTISSET('fieldname')) $_POST['fieldname'] = 'myvalue'; + + print '' . "\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_add.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_add.tpl.php'; + + print '
    ' . "\n"; + + print dol_get_fiche_end(); + + print '
    '; + print ''; + print '  '; + print ''; // Cancel for create does not post form if we don't know the backtopage + print '
    '; + + print '
    '; + + //dol_set_focus('input[name="ref"]'); +} + +// Part to edit record +if (($id || $ref) && $action == 'edit') { + print load_fiche_titre($langs->trans("Job"), '', 'object_' . $object->picto); + + print '
    '; + print ''; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(); + + print '' . "\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_edit.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_edit.tpl.php'; + + print '
    '; + + print dol_get_fiche_end(); + + print '
    '; + print '   '; + print '
    '; + + print '
    '; +} + +// Part to show record +if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { + $res = $object->fetch_optionals(); + + $head = jobPrepareHead($object); + $picto = 'company.png'; + print dol_get_fiche_head($head, 'job_card', $langs->trans("Workstation"), -1, $object->picto); + + $formconfirm = ''; + + // Confirmation to delete + if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteJob'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); + } + // Confirmation to delete line + if ($action == 'deleteline') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1); + } + // Clone confirmation + if ($action == 'clone') { + // Create an array for form + $formquestion = array(); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); + } + + // Confirmation of action xxxx + if ($action == 'xxx') { + $formquestion = array(); + /* + $forcecombo=0; + if ($conf->browser->name == 'ie') $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy + $formquestion = array( + // 'text' => $langs->trans("ConfirmClone"), + // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), + // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1), + // array('type' => 'other', 'name' => 'idwarehouse', 'label' => $langs->trans("SelectWarehouseForStockDecrease"), 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse')?GETPOST('idwarehouse'):'ifone', 'idwarehouse', '', 1, 0, 0, '', 0, $forcecombo)) + ); + */ + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('XXX'), $text, 'confirm_xxx', $formquestion, 0, 1, 220); + } + + // Call Hook formConfirm + $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + $formconfirm .= $hookmanager->resPrint; + } elseif ($reshook > 0) { + $formconfirm = $hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + + // Common attributes + //$keyforbreak='fieldkeytoswitchonsecondcolumn'; // We change column just before this field + //unset($object->fields['fk_project']); // Hide field already shown in banner + //unset($object->fields['fk_soc']); // Hide field already shown in banner + $object->fields['label']['visible']=0; // Already in banner + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_view.tpl.php'; + + // Other attributes. Fields from hook formObjectOptions and Extrafields. + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
    '; + print '
    '; + print '
    '; + + print '
    '; + + print dol_get_fiche_end(); + + + /* + * Lines + */ + + if (!empty($object->table_element_line)) { + // Show object lines + $result = $object->getLinesArray(); + + print '
    + + + + + + '; + + if (!empty($conf->use_javascript_ajax) && $object->status == 0) { + include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php'; + } + + print '
    '; + if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) { + print ''; + } + + if (!empty($object->lines)) { + $object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1); + } + + // Form to add new line + if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') { + if ($action != 'editline') { + // Add products/services form + + $parameters = array(); + $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + if (empty($reshook)) + $object->formAddObjectLine(1, $mysoc, $soc); + } + } + + if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) { + print '
    '; + } + print '
    '; + + print "
    \n"; + } + + + // Buttons for actions + + if ($action != 'presend' && $action != 'editline') { + print '
    ' . "\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + if (empty($reshook)) { + // Back to draft + if ($object->status == $object::STATUS_VALIDATED) { + print dolGetButtonAction($langs->trans('SetToDraft'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=confirm_setdraft&confirm=yes&token=' . newToken(), '', $permissiontoadd); + } + + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken(), '', $permissiontoadd); + + // Delete (need delete permission, or if draft, just need create/modify permission) + print dolGetButtonAction($langs->trans('Delete'), '', 'delete', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=delete&token=' . newToken(), '', $permissiontodelete); + } + print '
    ' . "\n"; + } + + + // Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } + + if ($action != 'presend') { + print '
    '; + print ''; // ancre + + $includedocgeneration = 0; + + // Documents + if ($includedocgeneration) { + $objref = dol_sanitizeFileName($object->ref); + $relativepath = $objref . '/' . $objref . '.pdf'; + $filedir = $conf->hrm->dir_output . '/' . $object->element . '/' . $objref; + $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id; + $genallowed = $user->rights->hrm->job->read; // If you can read, you can build the PDF to read content + $delallowed = $user->rights->hrm->job->write; // If you can create/edit, you can remove a file on card + print $formfile->showdocuments('hrm:Job', $object->element . '/' . $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang); + } + + // Show links to link elements + $linktoelem = $form->showLinkToObjectBlock($object, null, array('job')); + $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + + + print '
    '; + + $MAXEVENT = 10; + + $morehtmlright = ''; + $morehtmlright .= $langs->trans("SeeAll"); + $morehtmlright .= ''; + + // List of actions on element + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; + $formactions = new FormActions($db); + $somethingshown = $formactions->showactions($object, $object->element . '@' . $object->module, (is_object($object->thirdparty) ? $object->thirdparty->id : 0), 1, '', $MAXEVENT, '', $morehtmlright); + + print '
    '; + } + + // Presend form + $modelmail = 'job'; + $defaulttopic = 'InformationMessage'; + $diroutput = $conf->hrm->dir_output; + $trackid = 'job' . $object->id; + + include DOL_DOCUMENT_ROOT . '/core/tpl/card_presend.tpl.php'; +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/job_contact.php b/htdocs/hrm/job_contact.php new file mode 100644 index 00000000000..471f5c63886 --- /dev/null +++ b/htdocs/hrm/job_contact.php @@ -0,0 +1,220 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file job_contact.php + * \ingroup hrm + * \brief Tab for contacts linked to Job + */ + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +dol_include_once('/hrm/class/job.class.php'); +dol_include_once('/hrm/lib/hrm_job.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies", "other", "mails")); + +$id = (GETPOST('id') ?GETPOST('id', 'int') : GETPOST('facid', 'int')); // For backward compatibility +$ref = GETPOST('ref', 'alpha'); +$lineid = GETPOST('lineid', 'int'); +$socid = GETPOST('socid', 'int'); +$action = GETPOST('action', 'aZ09'); + +// Initialize technical objects +$object = new Job($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('jobcontact', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +$permission = $user->rights->hrm->job->write; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//if (empty($conf->hrm->enabled)) accessforbidden(); +//if (!$permissiontoread) accessforbidden(); + + +/* + * Add a new contact + */ + +if ($action == 'addcontact' && $permission) { + $contactid = (GETPOST('userid') ? GETPOST('userid', 'int') : GETPOST('contactid', 'int')); + $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type')); + $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09')); + + if ($result >= 0) { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } else { + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $langs->load("errors"); + setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors'); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } +} elseif ($action == 'swapstatut' && $permission) { + // Toggle the status of a contact + $result = $object->swapContactStatus(GETPOST('ligne', 'int')); +} elseif ($action == 'deletecontact' && $permission) { + // Deletes a contact + $result = $object->delete_contact($lineid); + + if ($result >= 0) { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } else { + dol_print_error($db); + } +} + + +/* + * View + */ + +$title = $langs->trans('Job')." - ".$langs->trans('ContactsAddresses'); +$help_url = ''; +//$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('', $title, $help_url); + +$form = new Form($db); +$formcompany = new FormCompany($db); +$contactstatic = new Contact($db); +$userstatic = new User($db); + + +/* *************************************************************************** */ +/* */ +/* View and edit mode */ +/* */ +/* *************************************************************************** */ + +if ($object->id) { + /* + * Show tabs + */ + $head = jobPrepareHead($object); + + print dol_get_fiche_head($head, 'contact', '', -1, $object->picto); + + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + /* + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
    '.$langs->trans('ThirdParty') . ' : ' . (is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
    '.$langs->trans('Project') . ' '; + if ($permissiontoadd) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
    '; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
    '; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ': '.$proj->getNomUrl(); + } else { + $morehtmlref .= ''; + } + } + }*/ + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0, '', '', 1); + + print dol_get_fiche_end(); + + print '
    '; + + // Contacts lines (modules that overwrite templates must declare this into descriptor) + $dirtpls = array_merge($conf->modules_parts['tpl'], array('/core/tpl')); + foreach ($dirtpls as $reldir) { + $res = @include dol_buildpath($reldir.'/contacts.tpl.php'); + if ($res) { + break; + } + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/job_document.php b/htdocs/hrm/job_document.php new file mode 100644 index 00000000000..c8cd764b9de --- /dev/null +++ b/htdocs/hrm/job_document.php @@ -0,0 +1,219 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file job_document.php + * \ingroup hrm + * \brief Tab for documents linked to Job + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +dol_include_once('/hrm/class/job.class.php'); +dol_include_once('/hrm/lib/hrm_job.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies", "other", "mails")); + + +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm'); +$id = (GETPOST('socid', 'int') ? GETPOST('socid', 'int') : GETPOST('id', 'int')); +$ref = GETPOST('ref', 'alpha'); + +// Get parameters +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortorder) { + $sortorder = "ASC"; +} +if (!$sortfield) { + $sortfield = "name"; +} +//if (! $sortfield) $sortfield="position_name"; + +// Initialize technical objects +$object = new Job($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('jobdocument', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity ? $object->entity : $conf->entity]."/job/".get_exdir(0, 0, 0, 1, $object); +} + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; + + +/* + * View + */ + +$form = new Form($db); + +$title = $langs->trans("Job").' - '.$langs->trans("Files"); +$help_url = ''; +//$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('', $title, $help_url); + +if ($object->id) { + /* + * Show tabs + */ + $head = jobPrepareHead($object); + + print dol_get_fiche_head($head, 'document', $langs->trans("Document"), -1, $object->picto); + + + // Build file list + $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1); + $totalsize = 0; + foreach ($filearray as $key => $file) { + $totalsize += $file['size']; + } + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + print '
    '; + + print '
    '; + print ''; + + // Number of files + print ''; + + // Total size + print ''; + + print '
    '.$langs->trans("NbOfAttachedFiles").''.count($filearray).'
    '.$langs->trans("TotalSizeOfAttachedFiles").''.$totalsize.' '.$langs->trans("bytes").'
    '; + + print '
    '; + + print dol_get_fiche_end(); + + $modulepart = 'hrm'; + //$permissiontoadd = $user->rights->hrm->job->write; + //$permtoedit = $user->rights->hrm->job->write; + $permtoedit = $permissiontoadd; + $param = '&id='.$object->id; + + //$relativepathwithnofile='job/' . dol_sanitizeFileName($object->id).'/'; + $relativepathwithnofile = 'job/'.dol_sanitizeFileName($object->ref).'/'; + + include DOL_DOCUMENT_ROOT.'/core/tpl/document_actions_post_headers.tpl.php'; +} else { + accessforbidden('', 0, 1); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/job_list.php b/htdocs/hrm/job_list.php new file mode 100644 index 00000000000..1a2ca54f1a7 --- /dev/null +++ b/htdocs/hrm/job_list.php @@ -0,0 +1,733 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file job_list.php + * \ingroup hrm + * \brief List page for job + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; + +// load hrm libraries +require_once __DIR__.'/class/job.class.php'; + +// for other modules +//dol_include_once('/othermodule/class/otherobject.class.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +$action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... +$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) +$show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? +$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation +$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button +$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'joblist'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + +$id = GETPOST('id', 'int'); + +// Load variable for pagination +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST('sortfield', 'aZ09comma'); +$sortorder = GETPOST('sortorder', 'aZ09comma'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + // If $page is not defined, or '' or -1 or if we click on clear filters + $page = 0; +} +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +// Initialize technical objects +$object = new Job($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('joblist')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); +//$extrafields->fetch_name_optionals_label($object->table_element_line); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Default sort order (if not yet defined by previous GETPOST) +if (!$sortfield) { + reset($object->fields); // Reset is required to avoid key() to return null. + $sortfield = "t.".key($object->fields); // Set here default search field. By default 1st field in definition. +} +if (!$sortorder) { + $sortorder = "ASC"; +} + +// Initialize array of search criterias +$search_all = GETPOST('search_all', 'alphanohtml') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_'.$key, 'alpha') !== '') { + $search[$key] = GETPOST('search_'.$key, 'alpha'); + } + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int')); + $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int')); + } +} + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array(); +foreach ($object->fields as $key => $val) { + if (!empty($val['searchall'])) { + $fieldstosearchall['t.'.$key] = $val['label']; + } +} + +// Definition of array of fields for columns +$arrayfields = array(); +foreach ($object->fields as $key => $val) { + // If $val['visible']==0, then we never show the field + if (!empty($val['visible'])) { + $visible = (int) dol_eval($val['visible'], 1); + $arrayfields['t.'.$key] = array( + 'label'=>$val['label'], + 'checked'=>(($visible < 0) ? 0 : 1), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'position'=>$val['position'], + 'help'=> isset($val['help']) ? $val['help'] : '' + ); + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; + +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; +$permissiontodelete = $user->rights->hrm->all->delete; + +// Security check +if (empty($conf->hrm->enabled)) { + accessforbidden('Module not enabled'); +} + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) accessforbidden(); +//$socid = 0; if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + + +/* + * Actions + */ + +if (GETPOST('cancel', 'alpha')) { + $action = 'list'; + $massaction = ''; +} +if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { + $massaction = ''; +} + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + foreach ($object->fields as $key => $val) { + $search[$key] = ''; + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = ''; + $search[$key.'_dtend'] = ''; + } + } + $toselect = array(); + $search_array_options = array(); + } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha') + || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) { + $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation + } + + // Mass actions + $objectclass = 'Job'; + $objectlabel = 'Job'; + $uploaddir = $conf->hrm->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + + +/* + * View + */ + +$form = new Form($db); + +$now = dol_now(); + +//$help_url="EN:Module_Job|FR:Module_Job_FR|ES:Módulo_Job"; +$help_url = ''; +$title = $langs->trans("ListOf", $langs->transnoentities('Jobs')); +$morejs = array(); +$morecss = array(); + + +// Build and execute select +// -------------------------------------------------------------------- +$sql = 'SELECT '; +$sql .= $object->getFieldList('t'); +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key.', ' : ''); + } +} +// Add fields from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= preg_replace('/^,/', '', $hookmanager->resPrint); +$sql = preg_replace('/,\s*$/', '', $sql); +$sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; +if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; +} +// Add table from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +if ($object->ismultientitymanaged == 1) { + $sql .= " WHERE t.entity IN (".getEntity($object->element).")"; +} else { + $sql .= " WHERE 1 = 1"; +} +foreach ($search as $key => $val) { + if (array_key_exists($key, $object->fields)) { + if ($key == 'status' && $search[$key] == -1) { + continue; + } + $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); + if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { + if ($search[$key] == '-1' || $search[$key] === '0') { + $search[$key] = ''; + } + $mode_search = 2; + } + if ($search[$key] != '') { + $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search)); + } + } else { + if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') { + $columnName=preg_replace('/(_dtstart|_dtend)$/', '', $key); + if (preg_match('/^(date|timestamp|datetime)/', $object->fields[$columnName]['type'])) { + if (preg_match('/_dtstart$/', $key)) { + $sql .= " AND t." . $columnName . " >= '" . $db->idate($search[$key]) . "'"; + } + if (preg_match('/_dtend$/', $key)) { + $sql .= " AND t." . $columnName . " <= '" . $db->idate($search[$key]) . "'"; + } + } + } + } +} +if ($search_all) { + $sql .= natural_search(array_keys($fieldstosearchall), $search_all); +} +//$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear); +// Add where from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; + +/* If a group by is required +$sql .= " GROUP BY "; +foreach($object->fields as $key => $val) { + $sql .= 't.'.$key.', '; +} +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : ''); + } +} +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +$sql = preg_replace('/,\s*$/', '', $sql); +*/ + +$sql .= $db->order($sortfield, $sortorder); + +// Count total nb of records +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + $resql = $db->query($sql); + $nbtotalofrecords = $db->num_rows($resql); + if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + $page = 0; + $offset = 0; + } +} +// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. +if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { + $num = $nbtotalofrecords; +} else { + if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); + } + + $resql = $db->query($sql); + if (!$resql) { + dol_print_error($db); + exit; + } + + $num = $db->num_rows($resql); +} + +// Direct jump if only one record found +if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { + $obj = $db->fetch_object($resql); + $id = $obj->rowid; + header("Location: ".dol_buildpath('/hrm/job_card.php', 1).'?id='.$id); + exit; +} + + +// Output page +// -------------------------------------------------------------------- + +llxHeader('', $title, $help_url, '', 0, 0, $morejs, $morecss, '', ''); + +// Example : Adding jquery code +// print ''; + +$arrayofselected = is_array($toselect) ? $toselect : array(); + +$param = ''; +if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); +} +if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); +} +foreach ($search as $key => $val) { + if (is_array($search[$key]) && count($search[$key])) { + foreach ($search[$key] as $skey) { + $param .= '&search_'.$key.'[]='.urlencode($skey); + } + } else { + $param .= '&search_'.$key.'='.urlencode($search[$key]); + } +} +if ($optioncss != '') { + $param .= '&optioncss='.urlencode($optioncss); +} +// Add $param from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; +// Add $param from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook +$param .= $hookmanager->resPrint; + +// List of mass actions available +$arrayofmassactions = array( + //'validate'=>img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate"), + //'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"), + //'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"), + //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), +); +if ($permissiontodelete) { + $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); +} +if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete'))) { + $arrayofmassactions = array(); +} +$massactionbutton = $form->selectMassAction('', $arrayofmassactions); + +print '
    '."\n"; +if ($optioncss != '') { + print ''; +} +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +$newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/hrm/job_card.php', 1).'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd); + +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'object_'.$object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1); + +// Add code for pre mass action (confirmation or email presend form) +$topicmail = "SendJobRef"; +$modelmail = "job"; +$objecttmp = new Job($db); +$trackid = 'xxxx'.$object->id; +include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; + +if ($search_all) { + foreach ($fieldstosearchall as $key => $val) { + $fieldstosearchall[$key] = $langs->trans($val); + } + print '
    '.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'
    '; +} + +$moreforfilter = ''; +/*$moreforfilter.='
    '; +$moreforfilter.= $langs->trans('MyFilter') . ': '; +$moreforfilter.= '
    ';*/ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +if (empty($reshook)) { + $moreforfilter .= $hookmanager->resPrint; +} else { + $moreforfilter = $hookmanager->resPrint; +} + +if (!empty($moreforfilter)) { + print '
    '; + print $moreforfilter; + print '
    '; +} + +$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + +print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table +print ''."\n"; + + +// Fields title search +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + +// Fields from hook +$parameters = array('arrayfields'=>$arrayfields); +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print ''; +print ''."\n"; + + +// Fields title label +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($cssforfield ? 'class="'.$cssforfield.'"' : ''), $sortfield, $sortorder, ($cssforfield ? $cssforfield.' ' : ''))."\n"; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; +// Hook fields +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +print ''."\n"; + + +// Detect if we need a fetch on each output line +$needToFetchEachLine = 0; +if (isset($extrafields->attributes[$object->table_element]['computed']) && is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0) { + foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val) { + if (preg_match('/\$object/', $val)) { + $needToFetchEachLine++; // There is at least one compute field that use $object + } + } +} + + +// Loop on record +// -------------------------------------------------------------------- +$i = 0; +$totalarray = array(); +$totalarray['nbfield'] = 0; +while ($i < ($limit ? min($num, $limit) : $num)) { + $obj = $db->fetch_object($resql); + if (empty($obj)) { + break; // Should not happen + } + + // Store properties in $object + $object->setVarsFromFetchObj($obj); + + // Show here line of result + print ''; + foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } + + if (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif ($key == 'ref') { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } + + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && !in_array($key, array('rowid', 'status')) && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; + + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + if ($key == 'status') { + print $object->getLibStatut(5); + } elseif ($key == 'rowid') { + print $object->showOutputField($val, $key, $object->id, ''); + } elseif ($key == 'label') { + print $object->getNomUrl(1); + } else { + print $object->showOutputField($val, $key, $object->$key, ''); + } + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + if (!empty($val['isameasure'])) { + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 't.'.$key; + } + if (!isset($totalarray['val'])) { + $totalarray['val'] = array(); + } + if (!isset($totalarray['val']['t.'.$key])) { + $totalarray['val']['t.'.$key] = 0; + } + $totalarray['val']['t.'.$key] += $object->$key; + } + } + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields, 'object'=>$object, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + + print ''."\n"; + + $i++; +} + +// Show total line +include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + +// If no record found +if ($num == 0) { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; +} + + +$db->free($resql); + +$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql); +$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print '
    '; + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + print $form->selectarray('search_'.$key, $val['arrayofkeyval'], (isset($search[$key]) ? $search[$key] : ''), $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth100', 1); + } elseif ((strpos($val['type'], 'integer:') === 0) || (strpos($val['type'], 'sellist:') === 0)) { + print $object->showInputField($val, $key, (isset($search[$key]) ? $search[$key] : ''), '', '', 'search_', 'maxwidth125', 1); + } elseif (!preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print ''; + } elseif (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print '
    '; + print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
    '; + print '
    '; + print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
    '; + } + print '
    '; +$searchpicto = $form->showFilterButtons(); +print $searchpicto; +print '
    '; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print '
    '.$langs->trans("NoRecordFound").'
    '."\n"; +print '
    '."\n"; + +print '
    '."\n"; + +if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords)) { + $hidegeneratedfilelistifempty = 1; + if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) { + $hidegeneratedfilelistifempty = 0; + } + + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + $formfile = new FormFile($db); + + // Show list of available documents + $urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder; + $urlsource .= str_replace('&', '&', $param); + + $filedir = $diroutputmassaction; + $genallowed = $permissiontoread; + $delallowed = $permissiontoadd; + + print $formfile->showdocuments('massfilesarea_hrm', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/job_note.php b/htdocs/hrm/job_note.php new file mode 100644 index 00000000000..3f63e50b9a6 --- /dev/null +++ b/htdocs/hrm/job_note.php @@ -0,0 +1,175 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file job_note.php + * \ingroup hrm + * \brief Tab for notes on Job + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +dol_include_once('/hrm/class/job.class.php'); +dol_include_once('/hrm/lib/hrm_job.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new Job($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('jobnote', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity]."/".$object->id; +} + +$permissiontoread = $user->rights->hrm->all->read; +$permissionnote = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { + include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once +} + + +/* + * View + */ + +$form = new Form($db); + +//$help_url='EN:Customers_Orders|FR:Commandes_Clients|ES:Pedidos de clientes'; +$help_url = ''; +llxHeader('', $langs->trans('Job'), $help_url); + +if ($id > 0 || !empty($ref)) { + $object->fetch_thirdparty(); + + $head = jobPrepareHead($object); + + print dol_get_fiche_head($head, 'note', $langs->trans("Notes"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + + print '
    '; + print '
    '; + + + $cssclass = "titlefield"; + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + + print '
    '; + + print dol_get_fiche_end(); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/lib/hrm.lib.php b/htdocs/hrm/lib/hrm.lib.php new file mode 100644 index 00000000000..c886b32e7a4 --- /dev/null +++ b/htdocs/hrm/lib/hrm.lib.php @@ -0,0 +1,69 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file hrm/lib/hrm.lib.php + * \ingroup hr + * \brief Library files with common functions for Workstation + */ + +/** + * Prepare admin pages header + * + * @return array + */ +function hrmAdminPrepareHead() +{ + global $langs, $conf; + + $langs->load("hrm"); + + $h = 0; + $head = array(); + $head[$h][0] = DOL_URL_ROOT . "/admin/hrm.php"; + $head[$h][1] = $langs->trans("Settings"); + $head[$h][2] = 'settings'; + $h++; + + /* + $head[$h][0] = dol_buildpath("/workstation/admin/myobject_extrafields.php", 1); + $head[$h][1] = $langs->trans("ExtraFields"); + $head[$h][2] = 'myobject_extrafields'; + $h++; + */ + + /*$head[$h][0] = require_once "/admin/about.php"; + $head[$h][1] = $langs->trans("About"); + $head[$h][2] = 'about'; + $h++;*/ + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@workstation:/workstation/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@workstation:/workstation/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm'); + + return $head; +} diff --git a/htdocs/hrm/lib/hrm_evaluation.lib.php b/htdocs/hrm/lib/hrm_evaluation.lib.php new file mode 100644 index 00000000000..87e6b80adaa --- /dev/null +++ b/htdocs/hrm/lib/hrm_evaluation.lib.php @@ -0,0 +1,95 @@ + + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file lib/hrm_evaluation.lib.php + * \ingroup hrm + * \brief Library files with common functions for Evaluation + */ + +/** + * Prepare array of tabs for Evaluation + * + * @param Evaluation $object Evaluation + * @return array Array of tabs + */ +function evaluationPrepareHead($object) +{ + global $db, $langs, $conf; + + $langs->load("hrm"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/hrm/evaluation_card.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("EvaluationCard"); + $head[$h][2] = 'card'; + $h++; + + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) { + $nbNote = 0; + if (!empty($object->note_private)) { + $nbNote++; + } + if (!empty($object->note_public)) { + $nbNote++; + } + $head[$h][0] = dol_buildpath('/hrm/evaluation_note.php', 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) { + $head[$h][1] .= (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? ''.$nbNote.'' : ''); + } + $head[$h][2] = 'note'; + $h++; + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; + $upload_dir = $conf->hrm->dir_output."/evaluation/".dol_sanitizeFileName($object->ref); + $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); + $nbLinks = Link::count($db, $object->element, $object->id); + $head[$h][0] = dol_buildpath("/hrm/evaluation_document.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Documents'); + if (($nbFiles + $nbLinks) > 0) { + $head[$h][1] .= ''.($nbFiles + $nbLinks).''; + } + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = dol_buildpath("/hrm/evaluation_agenda.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'evaluation@hrm'); + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'evaluation@hrm', 'remove'); + + return $head; +} diff --git a/htdocs/hrm/lib/hrm_job.lib.php b/htdocs/hrm/lib/hrm_job.lib.php new file mode 100644 index 00000000000..f465d934b0f --- /dev/null +++ b/htdocs/hrm/lib/hrm_job.lib.php @@ -0,0 +1,106 @@ + + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file lib/hrm_job.lib.php + * \ingroup hrm + * \brief Library files with common functions for Job + */ + +/** + * Prepare array of tabs for Job + * + * @param Job $object Job + * @return array Array of tabs + */ +function jobPrepareHead($object) +{ + global $db, $langs, $conf; + + $langs->load("hrm"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/hrm/job_card.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("JobCard"); + $head[$h][2] = 'job_card'; + $h++; + + $head[$h][0] = dol_buildpath("/hrm/skill_tab.php", 1).'?id='.$object->id.'&objecttype=job'; + $head[$h][1] = $langs->trans("RequiredSkills"); + $head[$h][2] = 'skill_tab'; + $h++; + + $head[$h][0] = dol_buildpath("/hrm/position.php", 1).'?fk_job='.$object->id; + $head[$h][1] = $langs->trans("EmployeesInThisPosition"); + $head[$h][2] = 'position'; + $h++; + + + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) { + $nbNote = 0; + if (!empty($object->note_private)) { + $nbNote++; + } + if (!empty($object->note_public)) { + $nbNote++; + } + $head[$h][0] = dol_buildpath('/hrm/job_note.php', 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) { + $head[$h][1] .= (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? ''.$nbNote.'' : ''); + } + $head[$h][2] = 'note'; + $h++; + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; + $upload_dir = $conf->hrm->dir_output."/job/".dol_sanitizeFileName($object->label); + $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); + $nbLinks = Link::count($db, $object->element, $object->id); + $head[$h][0] = dol_buildpath("/hrm/job_document.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Documents'); + if (($nbFiles + $nbLinks) > 0) { + $head[$h][1] .= ''.($nbFiles + $nbLinks).''; + } + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = dol_buildpath("/hrm/job_agenda.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'job@hrm'); + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'job@hrm', 'remove'); + + return $head; +} diff --git a/htdocs/hrm/lib/hrm_position.lib.php b/htdocs/hrm/lib/hrm_position.lib.php new file mode 100644 index 00000000000..da9a7b3123a --- /dev/null +++ b/htdocs/hrm/lib/hrm_position.lib.php @@ -0,0 +1,96 @@ + + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file lib/hrm_position.lib.php + * \ingroup hrm + * \brief Library files with common functions for Position + */ + + +/** + * Prepare array of tabs for positions + * + * @param Position $object Position + * @return array Array of tabs + */ +function PositionCardPrepareHead($object) +{ + global $db, $langs, $conf; + + $langs->load("hrm"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/hrm/position_card.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("PositionCard"); + $head[$h][2] = 'position'; + $h++; + + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) { + $nbNote = 0; + if (!empty($object->note_private)) { + $nbNote++; + } + if (!empty($object->note_public)) { + $nbNote++; + } + $head[$h][0] = dol_buildpath('/hrm/position_note.php', 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) { + $head[$h][1] .= (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? ''.$nbNote.'' : ''); + } + $head[$h][2] = 'note'; + $h++; + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; + $upload_dir = $conf->hrm->dir_output."/position/".dol_sanitizeFileName($object->ref); + $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); + $nbLinks = Link::count($db, $object->element, $object->id); + $head[$h][0] = dol_buildpath("/hrm/position_document.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Documents'); + if (($nbFiles + $nbLinks) > 0) { + $head[$h][1] .= ''.($nbFiles + $nbLinks).''; + } + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = dol_buildpath("/hrm/position_agenda.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'position@hrm'); + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'position@hrm', 'remove'); + + return $head; +} diff --git a/htdocs/hrm/lib/hrm_skill.lib.php b/htdocs/hrm/lib/hrm_skill.lib.php new file mode 100644 index 00000000000..7ddaa166a04 --- /dev/null +++ b/htdocs/hrm/lib/hrm_skill.lib.php @@ -0,0 +1,528 @@ + + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file lib/hrm_skill.lib.php + * \ingroup hrm + * \brief Library files with common functions for Skill + */ + +/** + * Prepare array of tabs for Skill + * + * @param Skill $object Skill + * @return array Array of tabs + */ +function skillPrepareHead($object) +{ + global $db, $langs, $conf; + + $langs->load("hrm"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/hrm/skill_card.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("SkillCard"); + $head[$h][2] = 'card'; + $h++; + + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) { + $nbNote = 0; + if (!empty($object->note_private)) { + $nbNote++; + } + if (!empty($object->note_public)) { + $nbNote++; + } + $head[$h][0] = dol_buildpath('/hrm/skill_note.php', 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) { + $head[$h][1] .= (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? ''.$nbNote.'' : ''); + } + $head[$h][2] = 'note'; + $h++; + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; + $upload_dir = $conf->hrm->dir_output."/skill/".dol_sanitizeFileName($object->ref); + $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); + $nbLinks = Link::count($db, $object->element, $object->id); + $head[$h][0] = dol_buildpath("/hrm/skill_document.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Documents'); + if (($nbFiles + $nbLinks) > 0) { + $head[$h][1] .= ''.($nbFiles + $nbLinks).''; + } + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = dol_buildpath("/hrm/skill_agenda.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'skill@hrm'); + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'skill@hrm', 'remove'); + + return $head; +} + + +//Affichage des 5 trades pour cet object +function showTraductionNote($object) +{ +} + + +/** + * Show html area for list of traduction + * + * @param Conf $conf Object conf + * @param Translate $langs Object langs + * @param DoliDB $db Database handler + * @param Societe $object Third party object + * @param string $backtopage Url to go once contact is created + * @return int + */ +function show_traduction($conf, $langs, $db, $object, $backtopage = '') +{ + global $user, $conf, $extrafields, $hookmanager; + global $contextpage; + + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; + $formcompany = new FormCompany($db); + $form = new Form($db); + + $optioncss = GETPOST('optioncss', 'alpha'); + $sortfield = GETPOST("sortfield", 'alpha'); + $sortorder = GETPOST("sortorder", 'alpha'); + $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); + + $search_status = GETPOST("search_status", 'int'); + if ($search_status == '') { + $search_status = 1; // always display active customer first + } + + $search_name = GETPOST("search_name", 'alpha'); + $search_address = GETPOST("search_address", 'alpha'); + $search_poste = GETPOST("search_poste", 'alpha'); + $search_roles = GETPOST("search_roles", 'array'); + + $socialnetworks = getArrayOfSocialNetworks(); + + $searchAddressPhoneDBFields = array( + //Address + 't.address', + 't.zip', + 't.town', + + //Phone + 't.phone', + 't.phone_perso', + 't.phone_mobile', + + //Fax + 't.fax', + + //E-mail + 't.email', + ); + //Social media + // foreach ($socialnetworks as $key => $value) { + // if ($value['active']) { + // $searchAddressPhoneDBFields['t.'.$key] = "t.socialnetworks->'$.".$key."'"; + // } + // } + + if (!$sortorder) { + $sortorder = "ASC"; + } + if (!$sortfield) { + $sortfield = "t.lastname"; + } + + if (!empty($conf->clicktodial->enabled)) { + $user->fetch_clicktodial(); // lecture des infos de clicktodial du user + } + + + $SkillLinestatic = new SkillLine($db); + + $extrafields->fetch_name_optionals_label($SkillLinestatic->table_element); + + $SkillLinestatic->fields=array( + 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"), + 'fk_skill' => array('type'=>'integer:Skill:skill/class/skill.class.php', 'label'=>'foreign key skill', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',), + 'traduction_note' => array('type'=>'text', 'label'=>'traduction_note', 'enabled'=>'1', 'position'=>56, 'notnull'=>0, 'visible'=>1,), + 'rank' => array('type'=>'integer', 'label'=>'rank', 'enabled'=>'1', 'position'=>55, 'notnull'=>1, 'visible'=>1, 'index'=>1,), + ); + + // Definition of fields for list + $arrayfields = array( + 't.rowid'=>array('label'=>"TechnicalID", 'checked'=>(!empty($conf->global->MAIN_SHOW_TECHNICAL_ID) ? 1 : 0), 'enabled'=>(!empty($conf->global->MAIN_SHOW_TECHNICAL_ID) ? 1 : 0), 'position'=>1), + 't.name'=>array('label'=>"Name", 'checked'=>1, 'position'=>10), + 't.poste'=>array('label'=>"PostOrFunction", 'checked'=>1, 'position'=>20), + 't.address'=>array('label'=>(empty($conf->dol_optimize_smallscreen) ? $langs->trans("Address").' / '.$langs->trans("Phone").' / '.$langs->trans("Email") : $langs->trans("Address")), 'checked'=>1, 'position'=>30), + 'sc.role'=>array('label'=>"ContactByDefaultFor", 'checked'=>1, 'position'=>40), + 't.statut'=>array('label'=>"Status", 'checked'=>1, 'position'=>50, 'class'=>'center'), + ); + // Extra fields + if (!empty($extrafields->attributes[$contactstatic->table_element]['label']) && is_array($extrafields->attributes[$contactstatic->table_element]['label']) && count($extrafields->attributes[$contactstatic->table_element]['label'])) { + foreach ($extrafields->attributes[$contactstatic->table_element]['label'] as $key => $val) { + if (!empty($extrafields->attributes[$contactstatic->table_element]['list'][$key])) { + $arrayfields["ef.".$key] = array( + 'label'=>$extrafields->attributes[$contactstatic->table_element]['label'][$key], + 'checked'=>(($extrafields->attributes[$contactstatic->table_element]['list'][$key] < 0) ? 0 : 1), + 'position'=>1000 + $extrafields->attributes[$contactstatic->table_element]['pos'][$key], + 'enabled'=>(abs($extrafields->attributes[$contactstatic->table_element]['list'][$key]) != 3 && $extrafields->attributes[$contactstatic->table_element]['perms'][$key])); + } + } + } + + // Initialize array of search criterias + $search = array(); + foreach ($arrayfields as $key => $val) { + $queryName = 'search_'.substr($key, 2); + if (GETPOST($queryName, 'alpha')) { + $search[substr($key, 2)] = GETPOST($queryName, 'alpha'); + } + } + $search_array_options = $extrafields->getOptionalsFromPost($contactstatic->table_element, '', 'search_'); + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + $search_status = ''; + $search_name = ''; + $search_roles = array(); + $search_address = ''; + $search_poste = ''; + $search = array(); + $search_array_options = array(); + + foreach ($contactstatic->fields as $key => $val) { + $search[$key] = ''; + } + } + + $contactstatic->fields = dol_sort_array($contactstatic->fields, 'position'); + $arrayfields = dol_sort_array($arrayfields, 'position'); + + $newcardbutton = ''; + if ($user->rights->societe->contact->creer) { + $addTraduction = $langs->trans("AddTraduction"); + $newcardbutton .= dolGetButtonTitle($addTraduction, '', 'fa fa-plus-circle', DOL_URL_ROOT.'/skilldet/card.php?skillid='.$object->id.'&action=create&backtopage='.urlencode($backtopage)); + } + + print "\n"; + + $title = $langs->trans("TraductionRule"); + print load_fiche_titre($title, $newcardbutton, ''); + + print '
    '; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; + $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + //if ($massactionbutton) $selectedfields.=$form->showCheckAddButtons('checkforselect', 1); + + print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table + print "\n".''."\n"; + + $param = "socid=".urlencode($object->id); + if ($search_status != '') { + $param .= '&search_status='.urlencode($search_status); + } + if (count($search_roles) > 0) { + $param .= implode('&search_roles[]=', $search_roles); + } + if ($search_name != '') { + $param .= '&search_name='.urlencode($search_name); + } + if ($search_poste != '') { + $param .= '&search_poste='.urlencode($search_poste); + } + if ($search_address != '') { + $param .= '&search_address='.urlencode($search_address); + } + if ($optioncss != '') { + $param .= '&optioncss='.urlencode($optioncss); + } + + // Add $param from extra fields + $extrafieldsobjectkey = $contactstatic->table_element; + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; + + $sql = "SELECT t.rowid, t.lastname, t.firstname, t.fk_pays as country_id, t.civility, t.poste, t.phone as phone_pro, t.phone_mobile, t.phone_perso, t.fax, t.email, t.socialnetworks, t.statut, t.photo,"; + $sql .= " t.civility as civility_id, t.address, t.zip, t.town"; + $sql .= " FROM ".MAIN_DB_PREFIX."socpeople as t"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople_extrafields as ef on (t.rowid = ef.fk_object)"; + $sql .= " WHERE t.fk_soc = ".$object->id; + if ($search_status != '' && $search_status != '-1') { + $sql .= " AND t.statut = ".$db->escape($search_status); + } + if ($search_name) { + $sql .= natural_search(array('t.lastname', 't.firstname'), $search_name); + } + if ($search_poste) { + $sql .= natural_search('t.poste', $search_poste); + } + if ($search_address) { + $sql .= natural_search($searchAddressPhoneDBFields, $search_address); + } + if (count($search_roles) > 0) { + $sql .= " AND t.rowid IN (SELECT sc.fk_socpeople FROM ".MAIN_DB_PREFIX."societe_contacts as sc WHERE sc.fk_c_type_contact IN (".$db->sanitize(implode(',', $search_roles))."))"; + } + // Add where from extra fields + $extrafieldsobjectkey = $contactstatic->table_element; + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; + if ($sortfield == "t.name") { + $sql .= " ORDER BY t.lastname $sortorder, t.firstname $sortorder"; + } else { + $sql .= " ORDER BY $sortfield $sortorder"; + } + + dol_syslog('core/lib/company.lib.php :: show_contacts', LOG_DEBUG); + $result = $db->query($sql); + if (!$result) { + dol_print_error($db); + } + + $num = $db->num_rows($result); + + // Fields title search + // -------------------------------------------------------------------- + print ''; + foreach ($contactstatic->fields as $key => $val) { + $align = ''; + if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $align .= ($align ? ' ' : '').'center'; + } + if (in_array($val['type'], array('timestamp'))) { + $align .= ($align ? ' ' : '').'nowrap'; + } + if ($key == 'status' || $key == 'statut') { + $align .= ($align ? ' ' : '').'center'; + } + if (!empty($arrayfields['t.'.$key]['checked']) || !empty($arrayfields['sc.'.$key]['checked'])) { + print ''; + } + } + // Extra fields + $extrafieldsobjectkey = $contactstatic->table_element; + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields); + $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $contactstatic); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + print ''."\n"; + + + // Fields title label + // -------------------------------------------------------------------- + print ''; + foreach ($contactstatic->fields as $key => $val) { + $align = ''; + if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $align .= ($align ? ' ' : '').'center'; + } + if (in_array($val['type'], array('timestamp'))) { + $align .= ($align ? ' ' : '').'nowrap'; + } + if ($key == 'status' || $key == 'statut') { + $align .= ($align ? ' ' : '').'center'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print getTitleFieldOfList($val['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($align ? 'class="'.$align.'"' : ''), $sortfield, $sortorder, $align.' ')."\n"; + } + if ($key == 'role') { + $align .= ($align ? ' ' : '').'left'; + } + if (!empty($arrayfields['sc.'.$key]['checked'])) { + print getTitleFieldOfList($arrayfields['sc.'.$key]['label'], 0, $_SERVER['PHP_SELF'], '', '', $param, ($align ? 'class="'.$align.'"' : ''), $sortfield, $sortorder, $align.' ')."\n"; + } + } + // Extra fields + $extrafieldsobjectkey = $contactstatic->table_element; + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; + // Hook fields + $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); + $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ')."\n"; + print ''."\n"; + + $i = -1; + + if ($num || (GETPOST('button_search') || GETPOST('button_search.x') || GETPOST('button_search_x'))) { + $i = 0; + + while ($i < $num) { + $obj = $db->fetch_object($result); + + $contactstatic->id = $obj->rowid; + $contactstatic->ref = $obj->rowid; + $contactstatic->statut = $obj->statut; + $contactstatic->lastname = $obj->lastname; + $contactstatic->firstname = $obj->firstname; + $contactstatic->civility_id = $obj->civility_id; + $contactstatic->civility_code = $obj->civility_id; + $contactstatic->poste = $obj->poste; + $contactstatic->address = $obj->address; + $contactstatic->zip = $obj->zip; + $contactstatic->town = $obj->town; + $contactstatic->phone_pro = $obj->phone_pro; + $contactstatic->phone_mobile = $obj->phone_mobile; + $contactstatic->phone_perso = $obj->phone_perso; + $contactstatic->email = $obj->email; + $contactstatic->socialnetworks = $obj->socialnetworks; + $contactstatic->photo = $obj->photo; + + $country_code = getCountry($obj->country_id, 2); + $contactstatic->country_code = $country_code; + + $contactstatic->setGenderFromCivility(); + $contactstatic->fetch_optionals(); + + $resultRole = $contactstatic->fetchRoles(); + if ($resultRole < 0) { + setEventMessages(null, $contactstatic->errors, 'errors'); + } + + if (is_array($contactstatic->array_options)) { + foreach ($contactstatic->array_options as $key => $val) { + $obj->$key = $val; + } + } + + print ''; + + // ID + if (!empty($arrayfields['t.rowid']['checked'])) { + print ''; + } + + // Photo - Name + if (!empty($arrayfields['t.name']['checked'])) { + print ''; + } + + // Job position + if (!empty($arrayfields['t.poste']['checked'])) { + print ''; + } + + // Address - Phone - Email + if (!empty($arrayfields['t.address']['checked'])) { + print ''; + } + + // Role + if (!empty($arrayfields['sc.role']['checked'])) { + print ''; + } + + // Status + if (!empty($arrayfields['t.statut']['checked'])) { + print ''; + } + + // Extra fields + $extrafieldsobjectkey = $contactstatic->table_element; + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + + // Actions + print ''; + + print "\n"; + $i++; + } + } else { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; + } + print "\n
    '; + if (in_array($key, array('statut'))) { + print $form->selectarray('search_status', array('-1'=>'', '0'=>$contactstatic->LibStatut(0, 1), '1'=>$contactstatic->LibStatut(1, 1)), $search_status); + } elseif (in_array($key, array('role'))) { + print $formcompany->showRoles("search_roles", $contactstatic, 'edit', $search_roles); + } else { + print ''; + } + print ''; + print $form->showFilterButtons(); + print '
    '; + print $contactstatic->id; + print ''; + print $form->showphoto('contact', $contactstatic, 0, 0, 0, 'photorefnoborder valignmiddle marginrightonly', 'small', 1, 0, 1); + print $contactstatic->getNomUrl(0, '', 0, '&backtopage='.urlencode($backtopage)); + print ''; + if ($obj->poste) { + print $obj->poste; + } + print ''; + print $contactstatic->getBannerAddress('contact', $object); + print ''; + print $formcompany->showRoles("roles", $contactstatic, 'view'); + print ''.$contactstatic->getLibStatut(5).''; + + // Add to agenda + if (!empty($conf->agenda->enabled) && $user->rights->agenda->myactions->create) { + print ''; + print img_object($langs->trans("Event"), "action"); + print '   '; + } + + // Edit + if ($user->rights->societe->contact->creer) { + print ''; + print img_edit(); + print ''; + } + + print '
    '.$langs->trans("None").'
    \n"; + print '
    '; + + print '
    '."\n"; + + return $i; +} diff --git a/htdocs/hrm/lib/hrm_skilldet.lib.php b/htdocs/hrm/lib/hrm_skilldet.lib.php new file mode 100644 index 00000000000..df7e1af45fc --- /dev/null +++ b/htdocs/hrm/lib/hrm_skilldet.lib.php @@ -0,0 +1,95 @@ + + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file lib/hrm_skilldet.lib.php + * \ingroup hrm + * \brief Library files with common functions for Skilldet + */ + +/** + * Prepare array of tabs for Skilldet + * + * @param Skilldet $object Skilldet + * @return array Array of tabs + */ +function skilldetPrepareHead($object) +{ + global $db, $langs, $conf; + + $langs->load("hrm"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/hrm/skilldet_card.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Card"); + $head[$h][2] = 'card'; + $h++; + + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) { + $nbNote = 0; + if (!empty($object->note_private)) { + $nbNote++; + } + if (!empty($object->note_public)) { + $nbNote++; + } + $head[$h][0] = dol_buildpath('/hrm/skilldet_note.php', 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) { + $head[$h][1] .= (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? ''.$nbNote.'' : ''); + } + $head[$h][2] = 'note'; + $h++; + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; + $upload_dir = $conf->hrm->dir_output."/skilldet/".dol_sanitizeFileName($object->ref); + $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); + $nbLinks = Link::count($db, $object->element, $object->id); + $head[$h][0] = dol_buildpath("/hrm/skilldet_document.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Documents'); + if (($nbFiles + $nbLinks) > 0) { + $head[$h][1] .= ''.($nbFiles + $nbLinks).''; + } + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = dol_buildpath("/hrm/skilldet_agenda.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'skilldet@hrm'); + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'skilldet@hrm', 'remove'); + + return $head; +} diff --git a/htdocs/hrm/lib/hrm_skillrank.lib.php b/htdocs/hrm/lib/hrm_skillrank.lib.php new file mode 100644 index 00000000000..e7937001bc2 --- /dev/null +++ b/htdocs/hrm/lib/hrm_skillrank.lib.php @@ -0,0 +1,149 @@ + + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file lib/hrm_skillrank.lib.php + * \ingroup hrm + * \brief Library files with common functions for SkillRank + */ + +/** + * Prepare array of tabs for SkillRank + * + * @param SkillRank $object SkillRank + * @return array Array of tabs + */ +function skillrankPrepareHead($object) +{ + global $db, $langs, $conf; + + $langs->load("hrm"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/hrm/skillrank_card.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Card"); + $head[$h][2] = 'card'; + $h++; + + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) { + $nbNote = 0; + if (!empty($object->note_private)) { + $nbNote++; + } + if (!empty($object->note_public)) { + $nbNote++; + } + $head[$h][0] = dol_buildpath('/hrm/skillrank_note.php', 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) { + $head[$h][1] .= (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? ''.$nbNote.'' : ''); + } + $head[$h][2] = 'note'; + $h++; + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; + $upload_dir = $conf->hrm->dir_output."/skillrank/".dol_sanitizeFileName($object->ref); + $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); + $nbLinks = Link::count($db, $object->element, $object->id); + $head[$h][0] = dol_buildpath("/hrm/skillrank_document.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Documents'); + if (($nbFiles + $nbLinks) > 0) { + $head[$h][1] .= ''.($nbFiles + $nbLinks).''; + } + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = dol_buildpath("/hrm/skillrank_agenda.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@hrm:/hrm/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'skillrank@hrm'); + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'skillrank@hrm', 'remove'); + + return $head; +} + +function displayRankInfos($selected_rank, $fk_skill, $inputname = 'TNote', $mode = 'view') +{ + global $db, $conf, $langs; + + require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php'; + require_once DOL_DOCUMENT_ROOT . '/hrm/class/skilldet.class.php'; + + // On charge les différentes notes possibles pour la compétence $fk_skill + $skilldet = new Skilldet($db); + $Lines = $skilldet->fetchAll('ASC', 'rank', 0, 0, array('customsql'=>'fk_skill = '.$fk_skill)); + + if (empty($Lines)) return $langs->trans('SkillHasNoLines'); + + $ret = '0'; + + foreach ($Lines as $line) { + $MaxNumberSkill = isset($conf->global->HRM_MAXRANK) ? $conf->global->HRM_MAXRANK : Skill::DEFAULT_MAX_RANK_PER_SKILL; + if ($line->rank > $MaxNumberSkill) { + continue; + } + + $ret.= ''.$line->rank.''; + } + + if ($mode == 'edit') { + $ret.= ' + + '; + } + + return $ret; +} diff --git a/htdocs/hrm/modulebuilder.txt b/htdocs/hrm/modulebuilder.txt new file mode 100644 index 00000000000..670a1774929 --- /dev/null +++ b/htdocs/hrm/modulebuilder.txt @@ -0,0 +1,3 @@ +# DO NOT DELETE THIS FILE MANUALLY +# File to flag module built using official module template. +# When this file is present into a module directory, you can edit it with the module builder tool. \ No newline at end of file diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php new file mode 100644 index 00000000000..d0eb8159019 --- /dev/null +++ b/htdocs/hrm/position.php @@ -0,0 +1,950 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file position.php + * \ingroup hrm + * \brief Page to create/edit/view position + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"] . "/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; +$tmp2 = realpath(__FILE__); +$i = strlen($tmp) - 1; +$j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; + $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1)) . "/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1)) . "/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; +dol_include_once('/hrm/class/position.class.php'); +dol_include_once('/hrm/class/job.class.php'); +dol_include_once('/hrm/lib/hrm_position.lib.php'); +dol_include_once('/hrm/lib/hrm_job.lib.php'); + +$action = GETPOST('action', 'aZ09') ? GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... +$backtopage = GETPOST('backtopage', 'alpha'); +$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); +$fk_job = GETPOST('fk_job', 'int'); + +// Get parameters +$id = GETPOST('fk_job', 'int'); +$fk_job = GETPOST('fk_job', 'int'); +$fk_user = GETPOST('fk_user', 'int'); +//$start_date = date('Y-m-d', GETPOST('date_startyear', 'int').'-'.GETPOST('date_startmonth', 'int').'-'.GETPOST('date_startday', 'int')); +$start_date = dol_mktime(0, 0, 0, GETPOST('date_startmonth', 'int'), GETPOST('date_startday', 'int'), GETPOST('date_startyear', 'int')); + +$ref = GETPOST('ref', 'alpha'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'positioncard'; // To manage different context of search + +// Initialize technical objects +$object = new Job($db); + +$extrafields = new ExtraFields($db); + +$diroutputmassaction = $conf->hrm->dir_output . '/temp/massgeneration/' . $user->id; +$hookmanager->initHooks(array('positiontab', 'globalcard')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Initialize array of search criterias +$search_all = GETPOST("search_all", 'alpha'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_' . $key, 'alpha')) { + $search[$key] = GETPOST('search_' . $key, 'alpha'); + } +} + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once. + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php +$permissiontodelete = $user->rights->hrm->all->delete; +$upload_dir = $conf->hrm->multidir_output[isset($object->entity) ? $object->entity : 1] . '/position'; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread || ($action === 'create' && !$permissiontoadd)) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $error = 0; + + $backurlforlist = dol_buildpath('/hrm/position_list.php', 1); + //$backtopage = dol_buildpath('/hrm/position.php', 1) . '?fk_job=' . ($fk_job > 0 ? $fk_job : '__ID__'); + + if (empty($backtopage) || ($cancel && empty($fk_job))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($fk_job) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = dol_buildpath('/hrm/position.php', 1) . '?fk_job=' . ($fk_job > 0 ? $fk_job : '__ID__'); + } + } + } + + $triggermodname = 'hrm_POSITION_MODIFY'; // Name of trigger action code to execute when we modify record + + // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen + $job = $object; + $object = new Position($db); + include DOL_DOCUMENT_ROOT . '/core/actions_addupdatedelete.inc.php'; +} + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +$title = $langs->trans("Position"); +$help_url = ''; +llxHeader('', $title, $help_url); + +if ($job->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { + DisplayJob($job); + DisplayPositionList($conf, $langs, $db); +} + + +/** + * Show the top of the page including informations of a job + * + * @param DoliDB $db Database handler + * @param Job $object Job object + * @param $permissiontoadd $permissiontoadd Rights/permissions + * @return array + */ +function DisplayJob($object) +{ + global $conf, $langs, $db, $extrafields, $hookmanager, $action, $backtopage, $backtopageforcancel, $permissiontoadd; + + /* + * View + * + * Put here all code to build page + */ + + $form = new Form($db); + $formfile = new FormFile($db); + $formproject = new FormProjets($db); + + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + // Part to show record + + $res = $object->fetch_optionals(); + + $head = jobPrepareHead($object); + print dol_get_fiche_head($head, 'position', $langs->trans("Workstation"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'fk_job', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + + // Common attributes + //$keyforbreak='fieldkeytoswitchonsecondcolumn'; // We change column just before this field + //unset($object->fields['fk_project']); // Hide field already shown in banner + //unset($object->fields['fk_soc']); // Hide field already shown in banner + $object->fields['label']['visible']=0; // Already in banner + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_view.tpl.php'; + + // Other attributes. Fields from hook formObjectOptions and Extrafields. + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
    '; + print '
    '; + print '
    '; + + print '
    '; + + print dol_get_fiche_end(); +} + + +/** + * Show a list of positions for the current job + + * @param Conf $conf Object conf + * @param Translate $langs Object langs + * @param DoliDB $db Database handler + * @param Position $object Position object + * @return array|void + */ +function DisplayPositionList($conf, $langs, $db) +{ + global $user,$langs, $db, $conf, $extrafields, $hookmanager, $permissiontoadd, $permissiontodelete; + + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; + + // load hrm libraries + require_once __DIR__ . '/class/position.class.php'; + + // for other modules + //dol_include_once('/othermodule/class/otherobject.class.php'); + + $action = GETPOST('action', 'aZ09') ? GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... + $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) + $show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? + $confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation + $cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button + $toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list + $contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'positionlist'; // To manage different context of search + $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + $id = GETPOST('id', 'int'); + $fk_job = GETPOST('fk_job', 'int'); + + // Load variable for pagination + $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; + $sortfield = GETPOST('sortfield', 'aZ09comma'); + $sortorder = GETPOST('sortorder', 'aZ09comma'); + $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); + if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + // If $page is not defined, or '' or -1 or if we click on clear filters + $page = 0; + } + $offset = $limit * $page; + $pageprev = $page - 1; + $pagenext = $page + 1; + + // Initialize technical objects + $object = new Position($db); + + $extrafields = new ExtraFields($db); + $diroutputmassaction = $conf->hrm->dir_output . '/temp/massgeneration/' . $user->id; + $hookmanager->initHooks(array('positiontablist')); // Note that conf->hooks_modules contains array + + // Fetch optionals attributes and labels + $extrafields->fetch_name_optionals_label($object->table_element); + //$extrafields->fetch_name_optionals_label($object->table_element_line); + + $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + + // Default sort order (if not yet defined by previous GETPOST) + if (!$sortfield) { + reset($object->fields); // Reset is required to avoid key() to return null. + $sortfield = "t." . key($object->fields); // Set here default search field. By default 1st field in definition. + } + if (!$sortorder) { + $sortorder = "ASC"; + } + + // Initialize array of search criterias + $search_all = GETPOST('search_all', 'alphanohtml') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'); + $search = array(); + foreach ($object->fields as $key => $val) { + if (GETPOST('search_' . $key, 'alpha') !== '') { + $search[$key] = GETPOST('search_' . $key, 'alpha'); + } + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key . '_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_' . $key . '_dtstartmonth', 'int'), GETPOST('search_' . $key . '_dtstartday', 'int'), GETPOST('search_' . $key . '_dtstartyear', 'int')); + $search[$key . '_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_' . $key . '_dtendmonth', 'int'), GETPOST('search_' . $key . '_dtendday', 'int'), GETPOST('search_' . $key . '_dtendyear', 'int')); + } + } + + // List of fields to search into when doing a "search in all" + $fieldstosearchall = array(); + foreach ($object->fields as $key => $val) { + if (!empty($val['searchall'])) { + $fieldstosearchall['t.' . $key] = $val['label']; + } + } + + // Definition of array of fields for columns + $arrayfields = array(); + foreach ($object->fields as $key => $val) { + // If $val['visible']==0, then we never show the field + if (!empty($val['visible'])) { + $visible = (int) dol_eval($val['visible'], 1); + $arrayfields['t.' . $key] = array( + 'label' => $val['label'], + 'checked' => (($visible < 0) ? 0 : 1), + 'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1)), + 'position' => $val['position'], + 'help' => isset($val['help']) ? $val['help'] : '' + ); + } + } + // Extra fields + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_list_array_fields.tpl.php'; + + $object->fields = dol_sort_array($object->fields, 'position'); + $arrayfields = dol_sort_array($arrayfields, 'position'); + + // Security check + if (empty($conf->hrm->enabled)) { + accessforbidden('Module not enabled'); + } + + // Security check (enable the most restrictive one) + if ($user->socid > 0) accessforbidden(); + //if ($user->socid > 0) accessforbidden(); + //$socid = 0; if ($user->socid > 0) $socid = $user->socid; + //$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); + //restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); + //if (empty($conf->hrm->enabled)) accessforbidden(); + //if (!$permissiontoread) accessforbidden(); + + + /* + * Actions + */ + + if (GETPOST('cancel', 'alpha')) { + $action = 'list'; + $massaction = ''; + } + if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { + $massaction = ''; + } + + $parameters = array(); + $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + if (empty($reshook)) { + // Selection of new fields + include DOL_DOCUMENT_ROOT . '/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + foreach ($object->fields as $key => $val) { + $search[$key] = ''; + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key . '_dtstart'] = ''; + $search[$key . '_dtend'] = ''; + } + } + $toselect = array(); + $search_array_options = array(); + } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha') + || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) { + $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation + } + + // Mass actions + $objectclass = 'Position'; + $objectlabel = 'Position'; + $uploaddir = $conf->hrm->dir_output; + include DOL_DOCUMENT_ROOT . '/core/actions_massactions.inc.php'; + } + + + /* + * View + */ + + $form = new Form($db); + + $now = dol_now(); + + //$help_url="EN:Module_Position|FR:Module_Position_FR|ES:Módulo_Position"; + $help_url = ''; + $title = $langs->trans('ListOf', $langs->transnoentitiesnoconv("Positions")); + $morejs = array(); + $morecss = array(); + + + // Build and execute select + // -------------------------------------------------------------------- + $sql = 'SELECT '; + $sql .= $object->getFieldList('t'); + // Add fields from extrafields + if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef." . $key . ' as options_' . $key . ', ' : ''); + } + } + // Add fields from hooks + $parameters = array(); + $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook + $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); + $sql = preg_replace('/,\s*$/', '', $sql); + $sql .= " FROM " . MAIN_DB_PREFIX . $object->table_element . " as t"; + if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . $object->table_element . "_extrafields as ef on (t.rowid = ef.fk_object)"; + } + // Add table from hooks + $parameters = array(); + $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook + $sql .= $hookmanager->resPrint; + if ($object->ismultientitymanaged == 1) { + $sql .= " WHERE t.entity IN (" . getEntity($object->element) . ")"; + } else { + $sql .= " WHERE 1 = 1"; + } + $sql .= " AND t.fk_job = " . $fk_job . " "; + + foreach ($search as $key => $val) { + if (array_key_exists($key, $object->fields)) { + if ($key == 'status' && $search[$key] == -1) { + continue; + } + $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); + if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { + if ($search[$key] == '-1' || $search[$key] === '0') { + $search[$key] = ''; + } + $mode_search = 2; + } + if ($search[$key] != '') { + $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search)); + } + } else { + if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') { + $columnName = preg_replace('/(_dtstart|_dtend)$/', '', $key); + if (preg_match('/^(date|timestamp|datetime)/', $object->fields[$columnName]['type'])) { + if (preg_match('/_dtstart$/', $key)) { + $sql .= " AND t." . $columnName . " >= '" . $db->idate($search[$key]) . "'"; + } + if (preg_match('/_dtend$/', $key)) { + $sql .= " AND t." . $columnName . " <= '" . $db->idate($search[$key]) . "'"; + } + } + } + } + } + if ($search_all) { + $sql .= natural_search(array_keys($fieldstosearchall), $search_all); + } + //$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear); + // Add where from extra fields + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_list_search_sql.tpl.php'; + // Add where from hooks + $parameters = array(); + $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook + $sql .= $hookmanager->resPrint; + + /* If a group by is required + $sql .= " GROUP BY "; + foreach($object->fields as $key => $val) { + $sql .= 't.'.$key.', '; + } + // Add fields from extrafields + if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : ''); + } + } + // Add where from hooks + $parameters = array(); + $reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook + $sql .= $hookmanager->resPrint; + $sql = preg_replace('/,\s*$/', '', $sql); + */ + + $sql .= $db->order($sortfield, $sortorder); + + // Count total nb of records + $nbtotalofrecords = ''; + if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + $resql = $db->query($sql); + $nbtotalofrecords = $db->num_rows($resql); + if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + $page = 0; + $offset = 0; + } + } + // if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. + if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { + $num = $nbtotalofrecords; + } else { + if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); + } + + $resql = $db->query($sql); + if (!$resql) { + dol_print_error($db); + exit; + } + + $num = $db->num_rows($resql); + } + + // Direct jump if only one record found + if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { + $obj = $db->fetch_object($resql); + $id = $obj->rowid; + header("Location: " . dol_buildpath('/hrm/position.php', 1) . '?id=' . $id); + exit; + } + + $arrayofselected = is_array($toselect) ? $toselect : array(); + + $param = 'fk_job=' . $fk_job; + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage=' . urlencode($contextpage); + } + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit=' . urlencode($limit); + } + foreach ($search as $key => $val) { + if (is_array($search[$key]) && count($search[$key])) { + foreach ($search[$key] as $skey) { + $param .= '&search_' . $key . '[]=' . urlencode($skey); + } + } else { + $param .= '&search_' . $key . '=' . urlencode($search[$key]); + } + } + if ($optioncss != '') { + $param .= '&optioncss=' . urlencode($optioncss); + } + // Add $param from extra fields + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_list_search_param.tpl.php'; + // Add $param from hooks + $parameters = array(); + $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook + $param .= $hookmanager->resPrint; + + // List of mass actions available + $arrayofmassactions = array( + //'validate'=>img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate"), + //'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"), + //'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"), + //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), + ); + if ($permissiontodelete) { + $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"') . $langs->trans("Delete"); + } + if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete'))) { + $arrayofmassactions = array(); + } + $massactionbutton = $form->selectMassAction('', $arrayofmassactions); + + print '
    ' . "\n"; + if ($optioncss != '') { + print ''; + } + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + $newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/hrm/position.php', 1) . '?action=create&backtopage=' . urlencode($_SERVER['PHP_SELF'].'?fk_job=' . $fk_job).'&fk_job=' . $fk_job, '', $permissiontoadd); + + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'object_' . $object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1); + + // Add code for pre mass action (confirmation or email presend form) + $topicmail = "SendPositionRef"; + $modelmail = "position"; + $objecttmp = new Position($db); + $trackid = 'xxxx' . $object->id; + include DOL_DOCUMENT_ROOT . '/core/tpl/massactions_pre.tpl.php'; + + if ($search_all) { + foreach ($fieldstosearchall as $key => $val) { + $fieldstosearchall[$key] = $langs->trans($val); + } + print '
    ' . $langs->trans("FilterOnInto", $search_all) . join(', ', $fieldstosearchall) . '
    '; + } + + $moreforfilter = ''; + /*$moreforfilter.='
    '; + $moreforfilter.= $langs->trans('MyFilter') . ': '; + $moreforfilter.= '
    ';*/ + + $parameters = array(); + $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + $moreforfilter .= $hookmanager->resPrint; + } else { + $moreforfilter = $hookmanager->resPrint; + } + + if (!empty($moreforfilter)) { + print '
    '; + print $moreforfilter; + print '
    '; + } + + $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; + $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + + print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table + print '' . "\n"; + + + // Fields title search + // -------------------------------------------------------------------- + print ''; + foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '') . 'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '') . 'right'; + } + if (!empty($arrayfields['t.' . $key]['checked'])) { + print ''; + } + } + // Extra fields + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_list_search_input.tpl.php'; + + // Fields from hook + $parameters = array('arrayfields' => $arrayfields); + $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + print '' . "\n"; + + + // Fields title label + // -------------------------------------------------------------------- + print ''; + foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '') . 'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '') . 'right'; + } + if (!empty($arrayfields['t.' . $key]['checked'])) { + print getTitleFieldOfList($arrayfields['t.' . $key]['label'], 0, $_SERVER['PHP_SELF'], 't.' . $key, '', $param, ($cssforfield ? 'class="' . $cssforfield . '"' : ''), $sortfield, $sortorder, ($cssforfield ? $cssforfield . ' ' : '')) . "\n"; + } + } + // Extra fields + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_list_search_title.tpl.php'; + // Hook fields + $parameters = array('arrayfields' => $arrayfields, 'param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder); + $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ') . "\n"; + print '' . "\n"; + + // Detect if we need a fetch on each output line + $needToFetchEachLine = 0; + if (isset($extrafields->attributes[$object->table_element]['computed']) && is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0) { + foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val) { + if (preg_match('/\$object/', $val)) { + $needToFetchEachLine++; // There is at least one compute field that use $object + } + } + } + + + // Loop on record + // -------------------------------------------------------------------- + $i = 0; + $totalarray = array(); + $totalarray['nbfield'] = 0; + while ($i < ($limit ? min($num, $limit) : $num)) { + $obj = $db->fetch_object($resql); + if (empty($obj)) { + break; // Should not happen + } + + // Store properties in $object + $object->setVarsFromFetchObj($obj); + + // Show here line of result + print ''; + foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + } elseif ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + } + + if (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '') . 'nowrap'; + } elseif ($key == 'ref') { + $cssforfield .= ($cssforfield ? ' ' : '') . 'nowrap'; + } + + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && !in_array($key, array('rowid', 'status')) && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '') . 'right'; + } + //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; + + if (!empty($arrayfields['t.' . $key]['checked'])) { + print ''; + if ($key == 'status') { + print $object->getLibStatut(5); + } elseif ($key == 'rowid') { + print $object->getNomUrl(1); + } else { + print $object->showOutputField($val, $key, $object->$key, ''); + } + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + if (!empty($val['isameasure'])) { + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 't.' . $key; + } + if (!isset($totalarray['val'])) { + $totalarray['val'] = array(); + } + if (!isset($totalarray['val']['t.' . $key])) { + $totalarray['val']['t.' . $key] = 0; + } + $totalarray['val']['t.' . $key] += $object->$key; + } + } + } + // Extra fields + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters = array('arrayfields' => $arrayfields, 'object' => $object, 'obj' => $obj, 'i' => $i, 'totalarray' => &$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + + print '' . "\n"; + + $i++; + } + + // Show total line + include DOL_DOCUMENT_ROOT . '/core/tpl/list_print_total.tpl.php'; + + // If no record found + if ($num == 0) { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; + } + + + $db->free($resql); + + $parameters = array('arrayfields' => $arrayfields, 'sql' => $sql); + $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + + print '
    '; + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + print $form->selectarray('search_' . $key, $val['arrayofkeyval'], (isset($search[$key]) ? $search[$key] : ''), $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth100', 1); + } elseif ((strpos($val['type'], 'integer:') === 0) || (strpos($val['type'], 'sellist:') === 0)) { + print $object->showInputField($val, $key, (isset($search[$key]) ? $search[$key] : ''), '', '', 'search_', 'maxwidth125', 1); + } elseif (!preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print ''; + } elseif (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print '
    '; + print $form->selectDate($search[$key . '_dtstart'] ? $search[$key . '_dtstart'] : '', "search_" . $key . "_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
    '; + print '
    '; + print $form->selectDate($search[$key . '_dtend'] ? $search[$key . '_dtend'] : '', "search_" . $key . "_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
    '; + } + print '
    '; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
    '; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print '
    ' . $langs->trans("NoRecordFound") . '
    ' . "\n"; + print '
    ' . "\n"; + + print '
    ' . "\n"; + + if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords)) { + $hidegeneratedfilelistifempty = 1; + if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) { + $hidegeneratedfilelistifempty = 0; + } + + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; + $formfile = new FormFile($db); + + // Show list of available documents + $urlsource = $_SERVER['PHP_SELF'] . '?sortfield=' . $sortfield . '&sortorder=' . $sortorder; + $urlsource .= str_replace('&', '&', $param); + + $filedir = $diroutputmassaction; + $genallowed = $permissiontoread; + $delallowed = $permissiontoadd; + + print $formfile->showdocuments('massfilesarea_hrm', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); + } + return array($arrayfields, $object, $action, $obj, $totalarray); +} + +// Part to create +if ($action == 'create') { + $object = new Position($db); + print load_fiche_titre($langs->trans("NewObject", $langs->transnoentitiesnoconv("Position")), '', 'object_' . $object->picto); + + print '
    '; + print ''; + print ''; + if ($backtopage) { + print ''; + } + + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(array(), ''); + + // Set some default values + //if (! GETPOSTISSET('fieldname')) $_POST['fieldname'] = 'myvalue'; + + print '' . "\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_add.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_add.tpl.php'; + + print '
    ' . "\n"; + + print dol_get_fiche_end(); + + print '
    '; + + print ''; + print '  '; + print ''; // Cancel for create does not post form if we don't know the backtopage + print '
    '; + + print '
    '; + + //dol_set_focus('input[name="ref"]'); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/position_agenda.php b/htdocs/hrm/position_agenda.php new file mode 100644 index 00000000000..670ec51304b --- /dev/null +++ b/htdocs/hrm/position_agenda.php @@ -0,0 +1,282 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file position_agenda.php + * \ingroup hrm + * \brief Tab of events on Position + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/class/position.class.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/lib/hrm_position.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; + + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +if (GETPOST('actioncode', 'array')) { + $actioncode = GETPOST('actioncode', 'array', 3); + if (!count($actioncode)) { + $actioncode = '0'; + } +} else { + $actioncode = GETPOST("actioncode", "alpha", 3) ? GETPOST("actioncode", "alpha", 3) : (GETPOST("actioncode") == '0' ? '0' : (empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT)); +} +$search_agenda_label = GETPOST('search_agenda_label'); + +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortfield) { + $sortfield = 'a.datep,a.id'; +} +if (!$sortorder) { + $sortorder = 'DESC,DESC'; +} + +// Initialize technical objects +$object = new Position($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('positionagenda', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity]."/".$object->id; +} + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array('id'=>$id); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Cancel + if (GETPOST('cancel', 'alpha') && !empty($backtopage)) { + header("Location: ".$backtopage); + exit; + } + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + $actioncode = ''; + $search_agenda_label = ''; + } +} + + + +/* + * View + */ + +$form = new Form($db); + +if ($object->id > 0) { + $title = $langs->trans("Agenda"); + //if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/thirdpartynameonly/',$conf->global->MAIN_HTML_TITLE) && $object->name) $title=$object->name." - ".$title; + $help_url = 'EN:Module_Agenda_En'; + llxHeader('', $title, $help_url); + + if (!empty($conf->notification->enabled)) { + $langs->load("mails"); + } + $head = PositionCardPrepareHead($object); + + + print dol_get_fiche_head($head, 'agenda', $langs->trans("Agenda"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $u_position = new User(($db)); + $u_position->fetch($object->fk_user); + $morehtmlref .= $langs->trans('Employee').' : '.$u_position->getNomUrl(1); + $job = new Job($db); + $job->fetch($object->fk_job); + $morehtmlref .= '
    '.$langs->trans('Job').' : '.$job->getNomUrl(1); + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + print '
    '; + print '
    '; + + $object->info($object->id); + dol_print_object_info($object, 1); + + print '
    '; + + print dol_get_fiche_end(); + + + + // Actions buttons + + $objthirdparty = $object; + $objcon = new stdClass(); + + $out = '&origin='.urlencode($object->element.'@'.$object->module).'&originid='.urlencode($object->id); + $urlbacktopage = $_SERVER['PHP_SELF'].'?id='.$object->id; + $out .= '&backtopage='.urlencode($urlbacktopage); + $permok = $user->rights->agenda->myactions->create; + if ((!empty($objthirdparty->id) || !empty($objcon->id)) && $permok) { + //$out.='trans("AddAnAction"),'filenew'); + //$out.=""; + } + + + print '
    '; + + if (!empty($conf->agenda->enabled)) { + if (!empty($user->rights->agenda->myactions->create) || !empty($user->rights->agenda->allactions->create)) { + print ''.$langs->trans("AddAction").''; + } else { + print ''.$langs->trans("AddAction").''; + } + } + + print '
    '; + + if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { + $param = '&id='.$object->id.'&socid='.$socid; + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); + } + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); + } + + + //print load_fiche_titre($langs->trans("ActionsOnPosition"), '', ''); + + // List of all actions + $filters = array(); + $filters['search_agenda_label'] = $search_agenda_label; + $object->fields['label']=array(); // Usefull to get only get agenda events linked to position (this object doesn't need label of ref field, but show_actions_done() needs it to work correctly) + + // TODO Replace this with same code than into list.php + show_actions_done($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder, $object->module); + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/position_card.php b/htdocs/hrm/position_card.php new file mode 100644 index 00000000000..4538fbc98b2 --- /dev/null +++ b/htdocs/hrm/position_card.php @@ -0,0 +1,444 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file position_card.php + * \ingroup hrm + * \brief Page to create/edit/view position + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"] . "/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; +$tmp2 = realpath(__FILE__); +$i = strlen($tmp) - 1; +$j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; + $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1)) . "/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1)) . "/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/position.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_position.lib.php'; +//dol_include_once('/hrm/position.php'); + +$action = GETPOST('action', 'aZ09') ? GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... +$backtopage = GETPOST('backtopage', 'alpha'); +$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); +$id = GETPOST('id', 'int'); + +// Initialize technical objects +$form = new Form($db); +$object = new Position($db); +$res = $object->fetch($id); +if ($res < 0) { + dol_print_error($db, $object->error); +} + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php +$permissiontodelete = $user->rights->hrm->all->delete; +$permissiondellink = $user->rights->hrm->all->write; // Used by the include of actions_dellink.inc.php +$upload_dir = $conf->hrm->multidir_output[isset($object->entity) ? $object->entity : 1] . '/position'; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread || ($action === 'create' && !$permissiontoadd)) accessforbidden(); + +$langs->loadLangs(array("hrm", "other")); + + + +// Get parameters +$id = GETPOST('id', 'int'); +$fk_job = GETPOST('fk_job', 'int'); + +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'positioncard'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); +$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); +// $lineid = GETPOST('lineid', 'int'); + +// Initialize technical objects +//$object = new Position($db); +//$res = $object->fetch($id); +/*if ($res < 0) { + dol_print_error($db, &$object->error); +}*/ + +$extrafields = new ExtraFields($db); + +$diroutputmassaction = $conf->hrm->dir_output . '/temp/massgeneration/' . $user->id; +$hookmanager->initHooks(array('positioncard', 'globalcard')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Initialize array of search criterias +$search_all = GETPOST("search_all", 'alpha'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_' . $key, 'alpha')) { + $search[$key] = GETPOST('search_' . $key, 'alpha'); + } +} + +if (empty($action) && empty($id) && empty($ref)) { + $action = 'view'; +} + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once. + + +/* + * Actions + */ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $error = 0; + + $backurlforlist = dol_buildpath('/hrm/position_list.php', 1); + + if (empty($backtopage) || ($cancel && empty($fk_job))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = dol_buildpath('/hrm/position_card.php', 1) . '?id=' . ($id > 0 ? $id : '__ID__'); + } + } + } + + $triggermodname = 'hrm_POSITION_MODIFY'; // Name of trigger action code to execute when we modify record + + // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen + include DOL_DOCUMENT_ROOT . '/core/actions_addupdatedelete.inc.php'; + + // Actions when linking object each other + include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; + + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT . '/core/actions_printing.inc.php'; + + // Action to move up and down lines of object + //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; + + // Action to build doc + include DOL_DOCUMENT_ROOT . '/core/actions_builddoc.inc.php'; + + if ($action == 'set_thirdparty' && $permissiontoadd) { + $object->setValueFrom('fk_soc', GETPOST('fk_soc', 'int'), '', '', 'date', '', $user, $triggermodname); + } + if ($action == 'classin' && $permissiontoadd) { + $object->setProject(GETPOST('projectid', 'int')); + } + + // Actions to send emails + $triggersendname = 'hrm_POSITION_SENTBYMAIL'; + $autocopy = 'MAIN_MAIL_AUTOCOPY_POSITION_TO'; + $trackid = 'position' . $object->id; + include DOL_DOCUMENT_ROOT . '/core/actions_sendmails.inc.php'; +} + +DisplayPositionCard($object); + +/** + * Show the card of a position + * + * @param Position $object Position object + */ +function DisplayPositionCard(&$object) +{ + + global $user, $langs, $db, $conf, $extrafields, $hookmanager, $action, $permissiontoadd, $permissiontodelete; + + $id = $object->id; + + /* + * View + * + * Put here all code to build page + */ + + $form = new Form($db); + $formfile = new FormFile($db); + $formproject = new FormProjets($db); + + $title = $langs->trans("Position"); + $help_url = ''; + llxHeader('', $title, $help_url); + + + // Part to edit record + if (($id || $ref) && $action == 'edit') { + print load_fiche_titre($langs->trans("Position"), '', 'object_' . $object->picto); + + print '
    '; + print ''; + print ''; + print ''; + + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(); + + print '' . "\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_edit.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_edit.tpl.php'; + + print '
    '; + + print dol_get_fiche_end(); + + print '
    '; + print '   '; + print '
    '; + + print '
    '; + } + + + // Part to show record + if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { + $res = $object->fetch_optionals(); + + + $head = PositionCardPrepareHead($object); + print dol_get_fiche_head($head, 'position', $langs->trans("Workstation"), -1, $object->picto); + + $formconfirm = ''; + + // Confirmation to delete + if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeletePosition'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); + } + + // Call Hook formConfirm + $parameters = array('formConfirm' => $formconfirm/*, 'lineid' => $lineid*/); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + $formconfirm .= $hookmanager->resPrint; + } elseif ($reshook > 0) { + $formconfirm = $hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Object card + // ------------------------------------------------------------ + // $linkback = '' . $langs->trans("BackToList") . ''; + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $u_position = new User(($db)); + $u_position->fetch($object->fk_user); + $morehtmlref .= $langs->trans('Employee').' : '.$u_position->getNomUrl(1); + $job = new Job($db); + $job->fetch($object->fk_job); + $morehtmlref .= '
    '.$langs->trans('Job').' : '.$job->getNomUrl(1); + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + + // Common attributes + //$keyforbreak='fieldkeytoswitchonsecondcolumn'; // We change column just before this field + //unset($object->fields['fk_project']); // Hide field already shown in banner + //unset($object->fields['fk_soc']); // Hide field already shown in banner + $object->fields['fk_user']['visible']=0; // Already in banner + $object->fields['fk_job']['visible']=0; // Already in banner + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_view.tpl.php'; + + // Other attributes. Fields from hook formObjectOptions and Extrafields. + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
    '; + print '
    '; + print '
    '; + + print '
    '; + + print dol_get_fiche_end(); + + /* + * Action bar + */ + print '
    '; + + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + + + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken(), '', $permissiontoadd); + + // Delete (need delete permission, or if draft, just need create/modify permission) + print dolGetButtonAction($langs->trans('Delete'), '', 'delete', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=delete&token=' . newToken(), '', $permissiontodelete); + } +} + +//if ($action != 'presend') { +// $formfile = new FormFile($db); +// print '
    '; +// +// if (empty($conf->global->SOCIETE_DISABLE_BUILDDOC)) { +// print ''; // ancre +// +// /* +// * Generated documents +// */ +// $filedir = $conf->societe->multidir_output[$object->entity].'/'.$object->id; +// $urlsource = $_SERVER["PHP_SELF"]."?socid=".$object->id; +// $genallowed = $user->rights->societe->lire; +// $delallowed = $user->rights->societe->creer; +// +// print $formfile->showdocuments('company', $object->id, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 0, 0, 0, 28, 0, 'entity='.$object->entity, 0, '', $object->default_lang); +// } +// +// +// print '
    '; +// +// $MAXEVENT = 10; +// +// $morehtmlright = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-list-alt imgforviewmode', DOL_URL_ROOT.'/societe/agenda.php?socid='.$object->id); +// +// // List of actions on element +// include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; +// $formactions = new FormActions($db); +// $somethingshown = $formactions->showactions($object, '', $object->id, 1, '', $MAXEVENT, '', $morehtmlright); // Show all action for thirdparty +// +// print '
    '; +//} + + +print '' . "\n"; +print '
    ' . "\n"; + +print '' . "\n"; + + +if ($action !== 'edit' && $action !== 'create') { + print '
    '; + + // Show links to link elements + $linktoelem = $form->showLinkToObjectBlock($object, null, array('position')); + $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + + + print '
    '; + + $MAXEVENT = 10; + + $morehtmlright = ''; + $morehtmlright .= $langs->trans("SeeAll"); + $morehtmlright .= ''; + // List of actions on element + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; + $formactions = new FormActions($db); + $somethingshown = $formactions->showactions($object, $object->element . '@' . $object->module, (is_object($object->thirdparty) ? $object->thirdparty->id : 0), 1, '', $MAXEVENT, '', $morehtmlright); + + print '
    '; +} + + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/position_contact.php b/htdocs/hrm/position_contact.php new file mode 100644 index 00000000000..76ec4f0b349 --- /dev/null +++ b/htdocs/hrm/position_contact.php @@ -0,0 +1,220 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file position_contact.php + * \ingroup hrm + * \brief Tab for contacts linked to Position + */ + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +dol_include_once('/hrm/class/position.class.php'); +dol_include_once('/hrm/lib/hrm_position.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies", "other", "mails")); + +$id = (GETPOST('id') ?GETPOST('id', 'int') : GETPOST('facid', 'int')); // For backward compatibility +$ref = GETPOST('ref', 'alpha'); +$lineid = GETPOST('lineid', 'int'); +$socid = GETPOST('socid', 'int'); +$action = GETPOST('action', 'aZ09'); + +// Initialize technical objects +$object = new Position($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('positioncontact', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +$permission = $user->rights->hrm->position->write; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//if (empty($conf->hrm->enabled)) accessforbidden(); +//if (!$permissiontoread) accessforbidden(); + + +/* + * Add a new contact + */ + +if ($action == 'addcontact' && $permission) { + $contactid = (GETPOST('userid') ? GETPOST('userid', 'int') : GETPOST('contactid', 'int')); + $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type')); + $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09')); + + if ($result >= 0) { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } else { + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $langs->load("errors"); + setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors'); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } +} elseif ($action == 'swapstatut' && $permission) { + // Toggle the status of a contact + $result = $object->swapContactStatus(GETPOST('ligne', 'int')); +} elseif ($action == 'deletecontact' && $permission) { + // Deletes a contact + $result = $object->delete_contact($lineid); + + if ($result >= 0) { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } else { + dol_print_error($db); + } +} + + +/* + * View + */ + +$title = $langs->trans('Position')." - ".$langs->trans('ContactsAddresses'); +$help_url = ''; +//$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('', $title, $help_url); + +$form = new Form($db); +$formcompany = new FormCompany($db); +$contactstatic = new Contact($db); +$userstatic = new User($db); + + +/* *************************************************************************** */ +/* */ +/* View and edit mode */ +/* */ +/* *************************************************************************** */ + +if ($object->id) { + /* + * Show tabs + */ + $head = PositionCardPrepareHead($object); + + print dol_get_fiche_head($head, 'contact', '', -1, $object->picto); + + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + /* + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
    '.$langs->trans('ThirdParty') . ' : ' . (is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
    '.$langs->trans('Project') . ' '; + if ($permissiontoadd) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
    '; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
    '; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ': '.$proj->getNomUrl(); + } else { + $morehtmlref .= ''; + } + } + }*/ + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0, '', '', 1); + + print dol_get_fiche_end(); + + print '
    '; + + // Contacts lines (modules that overwrite templates must declare this into descriptor) + $dirtpls = array_merge($conf->modules_parts['tpl'], array('/core/tpl')); + foreach ($dirtpls as $reldir) { + $res = @include dol_buildpath($reldir.'/contacts.tpl.php'); + if ($res) { + break; + } + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/position_document.php b/htdocs/hrm/position_document.php new file mode 100644 index 00000000000..1ae41c193ab --- /dev/null +++ b/htdocs/hrm/position_document.php @@ -0,0 +1,223 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file position_document.php + * \ingroup hrm + * \brief Tab for documents linked to Position + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/position.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_position.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies", "other", "mails")); + + +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm'); +$id = (GETPOST('socid', 'int') ? GETPOST('socid', 'int') : GETPOST('id', 'int')); +$ref = GETPOST('ref', 'alpha'); + +// Get parameters +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortorder) { + $sortorder = "ASC"; +} +if (!$sortfield) { + $sortfield = "name"; +} +//if (! $sortfield) $sortfield="position_name"; + +// Initialize technical objects +$object = new Position($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('positiondocument', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity ? $object->entity : $conf->entity]."/position/".get_exdir(0, 0, 0, 1, $object); +} + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; + + +/* + * View + */ + +$form = new Form($db); + +$title = $langs->trans("Position").' - '.$langs->trans("Files"); +$help_url = ''; +//$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('', $title, $help_url); + +if ($object->id) { + /* + * Show tabs + */ + $head = PositionCardPrepareHead($object); + + print dol_get_fiche_head($head, 'document', $langs->trans("Document"), -1, $object->picto); + + + // Build file list + $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1); + $totalsize = 0; + foreach ($filearray as $key => $file) { + $totalsize += $file['size']; + } + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $u_position = new User(($db)); + $u_position->fetch($object->fk_user); + $morehtmlref .= $langs->trans('Employee').' : '.$u_position->getNomUrl(1); + $job = new Job($db); + $job->fetch($object->fk_job); + $morehtmlref .= '
    '.$langs->trans('Job').' : '.$job->getNomUrl(1); + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + print '
    '; + + print '
    '; + print ''; + + // Number of files + print ''; + + // Total size + print ''; + + print '
    '.$langs->trans("NbOfAttachedFiles").''.count($filearray).'
    '.$langs->trans("TotalSizeOfAttachedFiles").''.$totalsize.' '.$langs->trans("bytes").'
    '; + + print '
    '; + + print dol_get_fiche_end(); + + $modulepart = 'hrm'; + $permtoedit = $permissiontoadd; + $param = '&id='.$object->id; + + //$relativepathwithnofile='position/' . dol_sanitizeFileName($object->id).'/'; + $relativepathwithnofile = 'position/'.dol_sanitizeFileName($object->ref).'/'; + + include DOL_DOCUMENT_ROOT.'/core/tpl/document_actions_post_headers.tpl.php'; +} else { + accessforbidden('', 0, 1); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/position_list.php b/htdocs/hrm/position_list.php new file mode 100644 index 00000000000..fc40e58441c --- /dev/null +++ b/htdocs/hrm/position_list.php @@ -0,0 +1,732 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file position_list.php + * \ingroup hrm + * \brief List page for position + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; + +// load hrm libraries +require_once __DIR__.'/class/position.class.php'; + +// for other modules +//dol_include_once('/othermodule/class/otherobject.class.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +$action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... +$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) +$show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? +$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation +$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button +$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'positionlist'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + +$id = GETPOST('id', 'int'); + +// Load variable for pagination +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST('sortfield', 'aZ09comma'); +$sortorder = GETPOST('sortorder', 'aZ09comma'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + // If $page is not defined, or '' or -1 or if we click on clear filters + $page = 0; +} +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +// Initialize technical objects +$object = new Position($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('positionlist')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); +//$extrafields->fetch_name_optionals_label($object->table_element_line); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Default sort order (if not yet defined by previous GETPOST) +if (!$sortfield) { + reset($object->fields); // Reset is required to avoid key() to return null. + $sortfield = "t.".key($object->fields); // Set here default search field. By default 1st field in definition. +} +if (!$sortorder) { + $sortorder = "ASC"; +} + +// Initialize array of search criterias +$search_all = GETPOST('search_all', 'alphanohtml') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_'.$key, 'alpha') !== '') { + $search[$key] = GETPOST('search_'.$key, 'alpha'); + } + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int')); + $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int')); + } +} + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array(); +foreach ($object->fields as $key => $val) { + if (!empty($val['searchall'])) { + $fieldstosearchall['t.'.$key] = $val['label']; + } +} + +// Definition of array of fields for columns +$arrayfields = array(); +foreach ($object->fields as $key => $val) { + // If $val['visible']==0, then we never show the field + if (!empty($val['visible'])) { + $visible = (int) dol_eval($val['visible'], 1); + $arrayfields['t.'.$key] = array( + 'label'=>$val['label'], + 'checked'=>(($visible < 0) ? 0 : 1), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'position'=>$val['position'], + 'help'=> isset($val['help']) ? $val['help'] : '' + ); + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; + +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; +$permissiontodelete = $user->rights->hrm->all->delete; + +// Security check +if (empty($conf->hrm->enabled)) { + accessforbidden('Module not enabled'); +} + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) accessforbidden(); +//$socid = 0; if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + + +/* + * Actions + */ + +if (GETPOST('cancel', 'alpha')) { + $action = 'list'; + $massaction = ''; +} +if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { + $massaction = ''; +} + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + foreach ($object->fields as $key => $val) { + $search[$key] = ''; + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = ''; + $search[$key.'_dtend'] = ''; + } + } + $toselect = array(); + $search_array_options = array(); + } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha') + || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) { + $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation + } + + // Mass actions + $objectclass = 'Position'; + $objectlabel = 'Position'; + $uploaddir = $conf->hrm->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + + +/* + * View + */ + +$form = new Form($db); + +$now = dol_now(); + +//$help_url="EN:Module_Position|FR:Module_Position_FR|ES:Módulo_Position"; +$help_url = ''; +$title = $langs->trans("ListOf", $langs->trans('Positions')); +$morejs = array(); +$morecss = array(); + + +// Build and execute select +// -------------------------------------------------------------------- +$sql = 'SELECT '; +$sql .= $object->getFieldList('t'); +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key.', ' : ''); + } +} +// Add fields from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= preg_replace('/^,/', '', $hookmanager->resPrint); +$sql = preg_replace('/,\s*$/', '', $sql); +$sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; +if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; +} +// Add table from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +if ($object->ismultientitymanaged == 1) { + $sql .= " WHERE t.entity IN (".getEntity($object->element).")"; +} else { + $sql .= " WHERE 1 = 1"; +} +foreach ($search as $key => $val) { + if (array_key_exists($key, $object->fields)) { + if ($key == 'status' && $search[$key] == -1) { + continue; + } + $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); + if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { + if ($search[$key] == '-1' || $search[$key] === '0') { + $search[$key] = ''; + } + $mode_search = 2; + } + if ($search[$key] != '') { + $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search)); + } + } else { + if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') { + $columnName=preg_replace('/(_dtstart|_dtend)$/', '', $key); + if (preg_match('/^(date|timestamp|datetime)/', $object->fields[$columnName]['type'])) { + if (preg_match('/_dtstart$/', $key)) { + $sql .= " AND t." . $columnName . " >= '" . $db->idate($search[$key]) . "'"; + } + if (preg_match('/_dtend$/', $key)) { + $sql .= " AND t." . $columnName . " <= '" . $db->idate($search[$key]) . "'"; + } + } + } + } +} +if ($search_all) { + $sql .= natural_search(array_keys($fieldstosearchall), $search_all); +} +//$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear); +// Add where from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; + +/* If a group by is required +$sql .= " GROUP BY "; +foreach($object->fields as $key => $val) { + $sql .= 't.'.$key.', '; +} +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : ''); + } +} +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +$sql = preg_replace('/,\s*$/', '', $sql); +*/ + +$sql .= $db->order($sortfield, $sortorder); + +// Count total nb of records +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + $resql = $db->query($sql); + $nbtotalofrecords = $db->num_rows($resql); + if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + $page = 0; + $offset = 0; + } +} +// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. +if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { + $num = $nbtotalofrecords; +} else { + if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); + } + + $resql = $db->query($sql); + if (!$resql) { + dol_print_error($db); + exit; + } + + $num = $db->num_rows($resql); +} + +// Direct jump if only one record found +if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { + $obj = $db->fetch_object($resql); + $id = $obj->rowid; + header("Location: ".dol_buildpath('/hrm/position.php', 1).'?id='.$id); + exit; +} + + +// Output page +// -------------------------------------------------------------------- + +llxHeader('', $title, $help_url, '', 0, 0, $morejs, $morecss, '', ''); + +// Example : Adding jquery code +// print ''; + +$arrayofselected = is_array($toselect) ? $toselect : array(); + +$param = ''; +if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); +} +if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); +} + +foreach ($search as $key => $val) { + if (is_array($search[$key]) && count($search[$key])) { + foreach ($search[$key] as $skey) { + $param .= '&search_'.$key.'[]='.urlencode($skey); + } + } else { + $param .= '&search_'.$key.'='.urlencode($search[$key]); + } +} +if ($optioncss != '') { + $param .= '&optioncss='.urlencode($optioncss); +} +// Add $param from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; +// Add $param from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook +$param .= $hookmanager->resPrint; + +// List of mass actions available +$arrayofmassactions = array( + //'validate'=>img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate"), + //'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"), + //'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"), + //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), +); +if ($permissiontodelete) { + $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); +} +if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete'))) { + $arrayofmassactions = array(); +} +$massactionbutton = $form->selectMassAction('', $arrayofmassactions); + +print '
    '."\n"; +if ($optioncss != '') { + print ''; +} +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +$newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/hrm/position.php', 1).'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd); + +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'object_'.$object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1); + +// Add code for pre mass action (confirmation or email presend form) +$topicmail = "SendPositionRef"; +$modelmail = "position"; +$objecttmp = new Position($db); +$trackid = 'xxxx'.$object->id; +include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; + +if ($search_all) { + foreach ($fieldstosearchall as $key => $val) { + $fieldstosearchall[$key] = $langs->trans($val); + } + print '
    '.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'
    '; +} + +$moreforfilter = ''; +/*$moreforfilter.='
    '; +$moreforfilter.= $langs->trans('MyFilter') . ': '; +$moreforfilter.= '
    ';*/ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +if (empty($reshook)) { + $moreforfilter .= $hookmanager->resPrint; +} else { + $moreforfilter = $hookmanager->resPrint; +} + +if (!empty($moreforfilter)) { + print '
    '; + print $moreforfilter; + print '
    '; +} + +$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + +print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table +print ''."\n"; + + +// Fields title search +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + +// Fields from hook +$parameters = array('arrayfields'=>$arrayfields); +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print ''; +print ''."\n"; + + +// Fields title label +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($cssforfield ? 'class="'.$cssforfield.'"' : ''), $sortfield, $sortorder, ($cssforfield ? $cssforfield.' ' : ''))."\n"; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; +// Hook fields +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +print ''."\n"; + + +// Detect if we need a fetch on each output line +$needToFetchEachLine = 0; +if (isset($extrafields->attributes[$object->table_element]['computed']) && is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0) { + foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val) { + if (preg_match('/\$object/', $val)) { + $needToFetchEachLine++; // There is at least one compute field that use $object + } + } +} + + +// Loop on record +// -------------------------------------------------------------------- +$i = 0; +$totalarray = array(); +$totalarray['nbfield'] = 0; +while ($i < ($limit ? min($num, $limit) : $num)) { + $obj = $db->fetch_object($resql); + if (empty($obj)) { + break; // Should not happen + } + + // Store properties in $object + $object->setVarsFromFetchObj($obj); + + // Show here line of result + print ''; + foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } + + if (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif ($key == 'ref') { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } + + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && !in_array($key, array('rowid', 'status')) && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; + + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + if ($key == 'status') { + print $object->getLibStatut(5); + } elseif ($key == 'rowid') { + print $object->getNomUrl(1); + } else { + print $object->showOutputField($val, $key, $object->$key, ''); + } + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + if (!empty($val['isameasure'])) { + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 't.'.$key; + } + if (!isset($totalarray['val'])) { + $totalarray['val'] = array(); + } + if (!isset($totalarray['val']['t.'.$key])) { + $totalarray['val']['t.'.$key] = 0; + } + $totalarray['val']['t.'.$key] += $object->$key; + } + } + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields, 'object'=>$object, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + + print ''."\n"; + + $i++; +} + +// Show total line +include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + +// If no record found +if ($num == 0) { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; +} + + +$db->free($resql); + +$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql); +$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print '
    '; + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + print $form->selectarray('search_'.$key, $val['arrayofkeyval'], (isset($search[$key]) ? $search[$key] : ''), $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth100', 1); + } elseif ((strpos($val['type'], 'integer:') === 0) || (strpos($val['type'], 'sellist:') === 0)) { + print $object->showInputField($val, $key, (isset($search[$key]) ? $search[$key] : ''), '', '', 'search_', 'maxwidth125', 1); + } elseif (!preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print ''; + } elseif (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print '
    '; + print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
    '; + print '
    '; + print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
    '; + } + print '
    '; +$searchpicto = $form->showFilterButtons(); +print $searchpicto; +print '
    '; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print '
    '.$langs->trans("NoRecordFound").'
    '."\n"; +print '
    '."\n"; + +print '
    '."\n"; + +if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords)) { + $hidegeneratedfilelistifempty = 1; + if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) { + $hidegeneratedfilelistifempty = 0; + } + + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + $formfile = new FormFile($db); + + // Show list of available documents + $urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder; + $urlsource .= str_replace('&', '&', $param); + + $filedir = $diroutputmassaction; + $genallowed = $permissiontoread; + $delallowed = $permissiontoadd; + + print $formfile->showdocuments('massfilesarea_hrm', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/position_note.php b/htdocs/hrm/position_note.php new file mode 100644 index 00000000000..81548761326 --- /dev/null +++ b/htdocs/hrm/position_note.php @@ -0,0 +1,183 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file position_note.php + * \ingroup hrm + * \ingroup hrm + * \brief Tab for notes on Position + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT . '/hrm/class/position.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_position.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php';; + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new Position($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('positionnote', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity]."/".$object->id; +} + +$permissionnote = $user->rights->hrm->all->write; +$permissiontoread = $user->rights->hrm->all->read; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { + include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once +} + + +/* + * View + */ + +$form = new Form($db); + +//$help_url='EN:Customers_Orders|FR:Commandes_Clients|ES:Pedidos de clientes'; +$help_url = ''; +llxHeader('', $langs->trans('Position'), $help_url); + +if ($id > 0 || !empty($ref)) { + $object->fetch_thirdparty(); + + $head = PositionCardPrepareHead($object); + + print dol_get_fiche_head($head, 'note', $langs->trans("Notes"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $u_position = new User(($db)); + $u_position->fetch($object->fk_user); + $morehtmlref .= $langs->trans('Employee').' : '.$u_position->getNomUrl(1); + $job = new Job($db); + $job->fetch($object->fk_job); + $morehtmlref .= '
    '.$langs->trans('Job').' : '.$job->getNomUrl(1); + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + + print '
    '; + print '
    '; + + + $cssclass = "titlefield"; + + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + + print '
    '; + + print dol_get_fiche_end(); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/skill_agenda.php b/htdocs/hrm/skill_agenda.php new file mode 100644 index 00000000000..7fbcfe78369 --- /dev/null +++ b/htdocs/hrm/skill_agenda.php @@ -0,0 +1,275 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file skill_agenda.php + * \ingroup hrm + * \brief Tab of events on skill + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +dol_include_once('/hrm/class/skill.class.php'); +dol_include_once('/hrm/lib/hrm_skill.lib.php'); + + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +if (GETPOST('actioncode', 'array')) { + $actioncode = GETPOST('actioncode', 'array', 3); + if (!count($actioncode)) { + $actioncode = '0'; + } +} else { + $actioncode = GETPOST("actioncode", "alpha", 3) ? GETPOST("actioncode", "alpha", 3) : (GETPOST("actioncode") == '0' ? '0' : (empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT)); +} +$search_agenda_label = GETPOST('search_agenda_label'); + +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortfield) { + $sortfield = 'a.datep,a.id'; +} +if (!$sortorder) { + $sortorder = 'DESC,DESC'; +} + +// Initialize technical objects +$object = new Skill($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('skillagenda', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity]."/".$object->id; +} + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array('id'=>$id); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Cancel + if (GETPOST('cancel', 'alpha') && !empty($backtopage)) { + header("Location: ".$backtopage); + exit; + } + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + $actioncode = ''; + $search_agenda_label = ''; + } +} + + + +/* + * View + */ + +$form = new Form($db); + +if ($object->id > 0) { + $title = $langs->trans("Agenda"); + //if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/thirdpartynameonly/',$conf->global->MAIN_HTML_TITLE) && $object->name) $title=$object->name." - ".$title; + $help_url = 'EN:Module_Agenda_En'; + llxHeader('', $title, $help_url); + + if (!empty($conf->notification->enabled)) { + $langs->load("mails"); + } + $head = skillPrepareHead($object); + + + print dol_get_fiche_head($head, 'agenda', $langs->trans("Agenda"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + print '
    '; + print '
    '; + + $object->info($object->id); + dol_print_object_info($object, 1); + + print '
    '; + + print dol_get_fiche_end(); + + + + // Actions buttons + + $objthirdparty = $object; + $objcon = new stdClass(); + + $out = '&origin='.urlencode($object->element.'@'.$object->module).'&originid='.urlencode($object->id); + $urlbacktopage = $_SERVER['PHP_SELF'].'?id='.$object->id; + $out .= '&backtopage='.urlencode($urlbacktopage); + $permok = $user->rights->agenda->myactions->create; + if ((!empty($objthirdparty->id) || !empty($objcon->id)) && $permok) { + //$out.='trans("AddAnAction"),'filenew'); + //$out.=""; + } + + + print '
    '; + + if (!empty($conf->agenda->enabled)) { + if (!empty($user->rights->agenda->myactions->create) || !empty($user->rights->agenda->allactions->create)) { + print ''.$langs->trans("AddAction").''; + } else { + print ''.$langs->trans("AddAction").''; + } + } + + print '
    '; + + if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { + $param = '&id='.$object->id.'&socid='.$socid; + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); + } + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); + } + + + //print load_fiche_titre($langs->trans("ActionsOnskill"), '', ''); + + // List of all actions + $filters = array(); + $filters['search_agenda_label'] = $search_agenda_label; + + // TODO Replace this with same code than into list.php + show_actions_done($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder, $object->module); + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/skill_card.php b/htdocs/hrm/skill_card.php new file mode 100644 index 00000000000..d577605c6fb --- /dev/null +++ b/htdocs/hrm/skill_card.php @@ -0,0 +1,909 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file skill_card.php + * \ingroup hrm + * \brief Page to create/edit/view skill + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"] . "/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; +$tmp2 = realpath(__FILE__); +$i = strlen($tmp) - 1; +$j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; + $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1)) . "/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1)) . "/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; +dol_include_once('/hrm/class/skill.class.php'); +dol_include_once('/hrm/lib/hrm_skill.lib.php'); + + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'skillcard'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); +$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); +//$lineid = GETPOST('lineid', 'int'); + +// Initialize technical objects +$object = new Skill($db); +//$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('skillcard', 'globalcard')); // Note that conf->hooks_modules contains array + +// Initialize array of search criterias +$search_all = GETPOST("search_all", 'alpha'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_' . $key, 'alpha')) { + $search[$key] = GETPOST('search_' . $key, 'alpha'); + } +} + +if (empty($action) && empty($id) && empty($ref)) { + $action = 'view'; +} + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once. + + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php +$permissiontodelete = $user->rights->hrm->all->delete; +$upload_dir = $conf->hrm->multidir_output[isset($object->entity) ? $object->entity : 1] . '/skill'; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread || ($action === 'create' && !$permissiontoadd)) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $error = 0; + + $backurlforlist = dol_buildpath('/hrm/skill_list.php', 1); + + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = dol_buildpath('/hrm/skill_card.php', 1) . '?id=' . ($id > 0 ? $id : '__ID__'); + } + } + } + + $triggermodname = 'hrm_SKILL_MODIFY'; // Name of trigger action code to execute when we modify record + + + // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen + include DOL_DOCUMENT_ROOT . '/core/actions_addupdatedelete.inc.php'; + + // action update on Skilldet + + $skilldetArray = GETPOST("descriptionline", "array"); + + if (!$error) { + if (is_array($skilldetArray) && count($skilldetArray) > 0) { + foreach ($skilldetArray as $key => $SkValueToUpdate) { + $skilldetObj = new Skilldet($object->db); + $res = $skilldetObj->fetch($key); + if ($res > 0) { + $skilldetObj->description = $SkValueToUpdate; + $resupd = $skilldetObj->update($user); + if ($resupd <= 0) { + setEventMessage($langs->trans('errorUpdateSkilldet')); + } + } + } + } + } + + + // Actions when linking object each other + include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; + + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT . '/core/actions_printing.inc.php'; + + // Action to move up and down lines of object + //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; + + // Action to build doc + include DOL_DOCUMENT_ROOT . '/core/actions_builddoc.inc.php'; + + if ($action == 'set_thirdparty' && $permissiontoadd) { + $object->setValueFrom('fk_soc', GETPOST('fk_soc', 'int'), '', '', 'date', '', $user, $triggermodname); + } + if ($action == 'classin' && $permissiontoadd) { + $object->setProject(GETPOST('projectid', 'int')); + } + + // Actions to send emails + $triggersendname = 'hrm_SKILL_SENTBYMAIL'; + $autocopy = 'MAIN_MAIL_AUTOCOPY_SKILL_TO'; + $trackid = 'skill' . $object->id; + include DOL_DOCUMENT_ROOT . '/core/actions_sendmails.inc.php'; +} + + +/* + * View + * + * Put here all code to build page + */ + +$form = new Form($db); +$formfile = new FormFile($db); +$formproject = new FormProjets($db); + +$title = $langs->trans("skill"); +$help_url = ''; +llxHeader('', $title, $help_url); + + +// Part to create +if ($action == 'create') { + print load_fiche_titre($langs->trans("NewSkill"), '', 'object_' . $object->picto); + + print '
    '; + print ''; + print ''; + $backtopage .= "&objecttype=job"; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(array(), ''); + + // Set some default values + //if (! GETPOSTISSET('fieldname')) $_POST['fieldname'] = 'myvalue'; + + print '' . "\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_add.tpl.php'; + + + // SKILLDET ADD + //@todo je stop ici ... à continuer (affichage des 5 skilled input pour create action + //print $object->showInputField($val, $key, $value, '', '['']', '', 0); + + print '
    ' . "\n"; + + print dol_get_fiche_end(); + + print '
    '; + print ''; + print '  '; + + print ''; // Cancel for create does not post form if we don't know the backtopage + print '
    '; + + print '
    '; + + //dol_set_focus('input[name="ref"]'); +} + +// Part to edit record +// and skilldet edition +if (($id || $ref) && $action == 'edit') { + print load_fiche_titre($langs->trans("Skill"), '', 'object_' . $object->picto); + + print '
    '; + print ''; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(); + + print '' . "\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_edit.tpl.php'; + + print '
    '; + + + // SKILLDET + + print dol_get_fiche_head(array(), ''); + $SkilldetRecords = $object->fetchLines(); + if (is_array($SkilldetRecords) && count($SkilldetRecords) > 0) { + print ''; + foreach ($SkilldetRecords as $sk) { + $MaxNumberSkill = isset($conf->global->HRM_MAXRANK) ? $conf->global->HRM_MAXRANK : Skill::DEFAULT_MAX_RANK_PER_SKILL; + if ($sk->rank > $MaxNumberSkill) { + continue; + } + + print '
    ' . "\n"; + $sk->fields = dol_sort_array($sk->fields, 'position'); + foreach ($sk->fields as $key => $val) { + if (abs($val['visible']) != 1 && abs($val['visible']) != 3 && abs($val['visible']) != 4) { + continue; + } + + if (array_key_exists('enabled', $val) && isset($val['enabled']) && !verifCond($val['enabled'])) { + continue; // We don't want this field + } + + print ''; + // if (!empty($val['help'])) { + // print $form->textwithpicto($langs->trans($val['label']), $langs->trans($val['help'])); + // } else { + print $langs->trans($val['label']).' '.$langs->trans('Rank').' '.$sk->rank; + // } + print ''; + print ''; + print ''; + } + } + print '
    '; + // if (!empty($val['picto'])) { + // print img_picto('', $val['picto'], '', false, 0, 0, '', 'pictofixedwidth'); + // } + // if (in_array($val['type'], array('int', 'integer'))) { + // $value = GETPOSTISSET($key) ? GETPOST($key, 'int') : $sk->$key; + // } elseif ($val['type'] == 'double') { + // $value = GETPOSTISSET($key) ? price2num(GETPOST($key, 'alphanohtml')) : $sk->$key; + // } elseif (preg_match('/^(text|html)/', $val['type'])) { + // $tmparray = explode(':', $val['type']); + if (!empty($tmparray[1])) { + $check = $tmparray[1]; + } else { + $check = 'restricthtml'; + } + + $skilldetArray = GETPOST("descriptionline", "array"); + if (empty($skilldetArray)) { + $value = GETPOSTISSET($key) ? GETPOST($key, $check) : $sk->$key; + } else { + $value=$skilldetArray[$sk->id]; + } + // + // } elseif ($val['type'] == 'price') { + // $value = GETPOSTISSET($key) ? price2num(GETPOST($key)) : price2num($sk->$key); + // } else { + // $value = GETPOSTISSET($key) ? GETPOST($key, 'alpha') : $sk->$key; + // } + //var_dump($val.' '.$key.' '.$value); + if ($val['noteditable']) { + print $sk->showOutputField($val, $key, $value, '', '', '', 0); + } else { + /** @var Skilldet $sk */ + print $sk->showInputField($val, $key, $value, "", "line[" . $sk->id . "]", "", ""); + } + print '
    '; + } + + + print dol_get_fiche_end(); + + print '
    '; + print '   '; + print '
    '; + + print '
    '; +} + + +// Part to show record +if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { + $res = $object->fetch_optionals(); + + $head = skillPrepareHead($object); + print dol_get_fiche_head($head, 'card', $langs->trans("Workstation"), -1, $object->picto); + + $formconfirm = ''; + + // Confirmation to delete + if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteSkill'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); + } + // Confirmation to delete line + if ($action == 'deleteline') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1); + } + // Clone confirmation + if ($action == 'clone') { + // Create an array for form + $formquestion = array(); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); + } + + // Confirmation of action xxxx + if ($action == 'xxx') { + $formquestion = array(); + /* + $forcecombo=0; + if ($conf->browser->name == 'ie') $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy + $formquestion = array( + // 'text' => $langs->trans("ConfirmClone"), + // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), + // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1), + // array('type' => 'other', 'name' => 'idwarehouse', 'label' => $langs->trans("SelectWarehouseForStockDecrease"), 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse')?GETPOST('idwarehouse'):'ifone', 'idwarehouse', '', 1, 0, 0, '', 0, $forcecombo)) + ); + */ + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('XXX'), $text, 'confirm_xxx', $formquestion, 0, 1, 220); + } + + // Call Hook formConfirm + $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + $formconfirm .= $hookmanager->resPrint; + } elseif ($reshook > 0) { + $formconfirm = $hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + + $object->fields['label']['visible']=0; // Already in banner + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_view.tpl.php'; + + + print '
    '; + print '
    '; + print '
    '; + + print '
    '; + + print dol_get_fiche_end(); + + + //dol_include_once('/hrm/tpl/hrm_skillde.fiche.tpl.php'); + + // Buttons for actions + + if ($action != 'presend' && $action != 'editline') { + print '
    ' . "\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + if (empty($reshook)) { + // Back to draft + if ($object->status == $object::STATUS_VALIDATED) { + print dolGetButtonAction($langs->trans('SetToDraft'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=confirm_setdraft&confirm=yes&token=' . newToken(), '', $permissiontoadd); + } + + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken(), '', $permissiontoadd); + + // Delete (need delete permission, or if draft, just need create/modify permission) + print dolGetButtonAction($langs->trans('Delete'), '', 'delete', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=delete&token=' . newToken(), '', $permissiontodelete); + } + print '
    ' . "\n"; + } +} + +//*---------------------------------------------------------------------------- +//*---------------------------------------------------------------------------- + + +//*--------------------------------------------------------------------------- + +if ($action != "create" && $action != "edit") { + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; + + // load hrm libraries + require_once __DIR__ . '/class/skilldet.class.php'; + + // for other modules + //dol_include_once('/othermodule/class/otherobject.class.php'); + + $action = GETPOST('action', 'aZ09') ? GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... + $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) + $show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? + $confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation + $cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button + $toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list + $contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'skilldetlist'; // To manage different context of search + $backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page + $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + + $id = GETPOST('id', 'int'); + + // Load variable for pagination + $limit = 0; + $sortfield = GETPOST('sortfield', 'aZ09comma'); + $sortorder = GETPOST('sortorder', 'aZ09comma'); + $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); + if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + // If $page is not defined, or '' or -1 or if we click on clear filters + $page = 0; + } + $offset = $limit * $page; + $pageprev = $page - 1; + $pagenext = $page + 1; + + // Initialize technical objects + $objectline = new Skilldet($db); + // $diroutputmassaction = $conf->hrm->dir_output . '/temp/massgeneration/' . $user->id; + // $hookmanager->initHooks(array('skilldetlist')); // Note that conf->hooks_modules contains array + + // Default sort order (if not yet defined by previous GETPOST) + if (!$sortfield) { + reset($objectline->fields); // Reset is required to avoid key() to return null. + $sortfield = "t." . key($objectline->fields); // Set here default search field. By default 1st field in definition. + } + if (!$sortorder) { + $sortorder = "ASC"; + } + + // Initialize array of search criterias + $search_all = GETPOST('search_all', 'alphanohtml') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'); + $search = array(); + foreach ($objectline->fields as $key => $val) { + if (GETPOST('search_' . $key, 'alpha') !== '') { + $search[$key] = GETPOST('search_' . $key, 'alpha'); + } + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key . '_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_' . $key . '_dtstartmonth', 'int'), GETPOST('search_' . $key . '_dtstartday', 'int'), GETPOST('search_' . $key . '_dtstartyear', 'int')); + $search[$key . '_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_' . $key . '_dtendmonth', 'int'), GETPOST('search_' . $key . '_dtendday', 'int'), GETPOST('search_' . $key . '_dtendyear', 'int')); + } + } + + // List of fields to search into when doing a "search in all" + $fieldstosearchall = array(); + foreach ($objectline->fields as $key => $val) { + if (!empty($val['searchall'])) { + $fieldstosearchall['t.' . $key] = $val['label']; + } + } + + // Definition of array of fields for columns + $arrayfields = array(); + foreach ($objectline->fields as $key => $val) { + // If $val['visible']==0, then we never show the field + if (!empty($val['visible'])) { + $visible = (int) dol_eval($val['visible'], 1); + $arrayfields['t.' . $key] = array( + 'label' => $val['label'], + 'checked' => (($visible < 0) ? 0 : 1), + 'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1)), + 'position' => $val['position'], + 'help' => isset($val['help']) ? $val['help'] : '' + ); + } + } + + $objectline->fields = dol_sort_array($objectline->fields, 'position'); + $arrayfields = dol_sort_array($arrayfields, 'position'); + + + /* + * View + */ + + $form = new Form($db); + + $now = dol_now(); + + $help_url = ''; + $title = $langs->transnoentitiesnoconv("Skilldets"); + $morejs = array(); + $morecss = array(); + + + // Build and execute select + // -------------------------------------------------------------------- + $sql = 'SELECT '; + $sql .= $objectline->getFieldList('t'); + $sql .= " FROM " . MAIN_DB_PREFIX . $objectline->table_element . " as t"; + if ($objectline->ismultientitymanaged == 1) { + $sql .= " WHERE t.entity IN (" . getEntity($objectline->element) . ")"; + } else { + $sql .= " WHERE 1 = 1 "; + } + + if (!empty($id)) { + $sql .= " AND fk_skill = " . $id . " "; + } + + // if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. + if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { + $num = $nbtotalofrecords; + } else { + if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); + } + + $resql = $db->query($sql); + if (!$resql) { + dol_print_error($db); + exit; + } + + $num = $db->num_rows($resql); + } + + print '
    ' . "\n"; + if ($optioncss != '') { + print ''; + } + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + if (!empty($id)) { + print ''; + } + + $param_fk = "&fk_skill=" . $id . "&fk_user_creat=" . $user->rowid; + $backtopage = dol_buildpath('/hrm/skill_card.php', 1) . '?id=' . $id; + //$newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/hrm/skilldet_card.php', 1) . '?action=create&backtopage=' . urlencode($_SERVER['PHP_SELF']) . $param_fk . '&backtopage=' . $backtopage, '', $permissiontoadd); + + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'object_' . $object->picto, 0, "", '', '', 0, 0, 1); + + // Add code for pre mass action (confirmation or email presend form) + $topicmail = "SendSkilldetRef"; + $modelmail = "skilldet"; + $objecttmp = new Skilldet($db); + $trackid = 'xxxx' . $object->id; + //include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; + + if ($search_all) { + foreach ($fieldstosearchall as $key => $val) { + $fieldstosearchall[$key] = $langs->trans($val); + } + print '
    ' . $langs->trans("FilterOnInto", $search_all) . join(', ', $fieldstosearchall) . '
    '; + } + + $moreforfilter = ''; + /*$moreforfilter.='
    '; + $moreforfilter.= $langs->trans('MyFilter') . ': '; + $moreforfilter.= '
    ';*/ + + $parameters = array(); + $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $objectline); // Note that $action and $objectline may have been modified by hook + if (empty($reshook)) { + $moreforfilter .= $hookmanager->resPrint; + } else { + $moreforfilter = $hookmanager->resPrint; + } + + if (!empty($moreforfilter)) { + print '
    '; + print $moreforfilter; + print '
    '; + } + + $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; + // $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + // $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + + print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table + print '' . "\n"; + + + // Fields title label + // -------------------------------------------------------------------- + print ''; + foreach ($objectline->fields as $key => $val) { + // $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + // if ($key == 'status') { + // $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + // } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + // $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + // } elseif (in_array($val['type'], array('timestamp'))) { + // $cssforfield .= ($cssforfield ? ' ' : '') . 'nowrap'; + // } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + // $cssforfield .= ($cssforfield ? ' ' : '') . 'right'; + // } + if (!empty($arrayfields['t.' . $key]['checked'])) { + print getTitleFieldOfList($arrayfields['t.' . $key]['label'], 0, $_SERVER['PHP_SELF'], 't.' . $key, '', $param, ($cssforfield ? 'class="' . $cssforfield . '"' : ''), $sortfield, $sortorder, ($cssforfield ? $cssforfield . ' ' : '')) . "\n"; + } + } + print ''; + print ''; + print '' . "\n"; + + + // Display all ranks of skill + // -------------------------------------------------------------------- + + $i = 0; + $totalarray = array(); + $totalarray['nbfield'] = 0; + while ($i < ($limit ? min($num, $limit) : $num)) { + $obj = $db->fetch_object($resql); + if (empty($obj)) { + break; // Should not happen + } + + $MaxNumberSkill = isset($conf->global->HRM_MAXRANK) ? $conf->global->HRM_MAXRANK : Skill::DEFAULT_MAX_RANK_PER_SKILL; + if ($obj->rank > $MaxNumberSkill) { + continue; + } + + // Store properties in $objectline + $objectline->setVarsFromFetchObj($obj); + + // Show here line of result + print ''; + foreach ($objectline->fields as $key => $val) { + // $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + // if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + // $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + // } elseif ($key == 'status') { + // $cssforfield .= ($cssforfield ? ' ' : '') . 'center'; + // } + // + // if (in_array($val['type'], array('timestamp'))) { + // $cssforfield .= ($cssforfield ? ' ' : '') . 'nowrap'; + // } elseif ($key == 'ref') { + // $cssforfield .= ($cssforfield ? ' ' : '') . 'nowrap'; + // } + // + // if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && !in_array($key, array('rowid', 'status')) && empty($val['arrayofkeyval'])) { + // $cssforfield .= ($cssforfield ? ' ' : '') . 'right'; + // } + //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; + + if (!empty($arrayfields['t.' . $key]['checked'])) { + print ''; + if ($key == 'status') { + print $objectline->getLibStatut(5); + } elseif ($key == 'rowid') { + print $objectline->showOutputField($val, $key, $objectline->id, ''); + // ajout pencil + print ''; + } else { + print $objectline->showOutputField($val, $key, $objectline->$key, ''); + } + print ''; + + + if (!$i) { + $totalarray['nbfield']++; + } + if (!empty($val['isameasure'])) { + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 't.' . $key; + } + if (!isset($totalarray['val'])) { + $totalarray['val'] = array(); + } + if (!isset($totalarray['val']['t.' . $key])) { + $totalarray['val']['t.' . $key] = 0; + } + $totalarray['val']['t.' . $key] += $objectline->$key; + } + } + } + + + // LINE EDITION | SUPPRESSION + + print ''; + print ''; + + + // Fields from hook + $parameters = array('arrayfields' => $arrayfields, 'object' => $objectline, 'obj' => $obj, 'i' => $i, 'totalarray' => &$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $objectline); // Note that $action and $objectline may have been modified by hook + print $hookmanager->resPrint; + /*// Action column + print '';*/ + if (!$i) { + $totalarray['nbfield']++; + } + + print '' . "\n"; + + $i++; + } + + + // If no record found + + if ($num == 0) { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; + } + + + $db->free($resql); + + $parameters = array('arrayfields' => $arrayfields, 'sql' => $sql); + $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $objectline); // Note that $action and $objectline may have been modified by hook + print $hookmanager->resPrint; + + print '
    '; + + print ''; + // add pencil + //@todo change to proper call dol_ + //print 'id, 1) . '">'; + // add trash + //@todo change to proper call dol_ + //print 'id,1) .'">'; + //print ''; + + print '
    ' . $langs->trans("NoRecordFound") . '
    ' . "\n"; + print '
    ' . "\n"; + + print '
    ' . "\n"; + + // if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords)) { + // $hidegeneratedfilelistifempty = 1; + // if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) { + // $hidegeneratedfilelistifempty = 0; + // } + // + // require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; + // $formfile = new FormFile($db); + // + // // Show list of available documents + // $urlsource = $_SERVER['PHP_SELF'] . '?sortfield=' . $sortfield . '&sortorder=' . $sortorder; + // $urlsource .= str_replace('&', '&', $param); + // + // $filedir = $diroutputmassaction; + // $genallowed = $permissiontoread; + // $delallowed = $permissiontoadd; + // + // print $formfile->showdocuments('massfilesarea_hrm', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); + // } + + print '
    '; + + // Show links to link elements + $linktoelem = $form->showLinkToObjectBlock($object, null, array('skill')); + $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + + print '
    '; + + $MAXEVENT = 10; + + $morehtmlright = ''; + $morehtmlright .= $langs->trans("SeeAll"); + $morehtmlright .= ''; + // List of actions on element + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; + $formactions = new FormActions($db); + $somethingshown = $formactions->showactions($object, $object->element . '@' . $object->module, (is_object($object->thirdparty) ? $object->thirdparty->id : 0), 1, '', $MAXEVENT, '', $morehtmlright); + + print '
    '; +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/skill_contact.php b/htdocs/hrm/skill_contact.php new file mode 100644 index 00000000000..11ff55e8588 --- /dev/null +++ b/htdocs/hrm/skill_contact.php @@ -0,0 +1,220 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file skill_contact.php + * \ingroup hrm + * \brief Tab for contacts linked to Skill + */ + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +dol_include_once('/hrm/class/skill.class.php'); +dol_include_once('/hrm/lib/hrm_skill.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies", "other", "mails")); + +$id = (GETPOST('id') ?GETPOST('id', 'int') : GETPOST('facid', 'int')); // For backward compatibility +$ref = GETPOST('ref', 'alpha'); +$lineid = GETPOST('lineid', 'int'); +$socid = GETPOST('socid', 'int'); +$action = GETPOST('action', 'aZ09'); + +// Initialize technical objects +$object = new Skill($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('skillcontact', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +$permission = $user->rights->hrm->skill->write; + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//if (empty($conf->hrm->enabled)) accessforbidden(); +//if (!$permissiontoread) accessforbidden(); + + +/* + * Add a new contact + */ + +if ($action == 'addcontact' && $permission) { + $contactid = (GETPOST('userid') ? GETPOST('userid', 'int') : GETPOST('contactid', 'int')); + $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type')); + $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09')); + + if ($result >= 0) { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } else { + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $langs->load("errors"); + setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors'); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } +} elseif ($action == 'swapstatut' && $permission) { + // Toggle the status of a contact + $result = $object->swapContactStatus(GETPOST('ligne', 'int')); +} elseif ($action == 'deletecontact' && $permission) { + // Deletes a contact + $result = $object->delete_contact($lineid); + + if ($result >= 0) { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } else { + dol_print_error($db); + } +} + + +/* + * View + */ + +$title = $langs->trans('Skill')." - ".$langs->trans('ContactsAddresses'); +$help_url = ''; +//$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('', $title, $help_url); + +$form = new Form($db); +$formcompany = new FormCompany($db); +$contactstatic = new Contact($db); +$userstatic = new User($db); + + +/* *************************************************************************** */ +/* */ +/* View and edit mode */ +/* */ +/* *************************************************************************** */ + +if ($object->id) { + /* + * Show tabs + */ + $head = skillPrepareHead($object); + + print dol_get_fiche_head($head, 'contact', '', -1, $object->picto); + + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + /* + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
    '.$langs->trans('ThirdParty') . ' : ' . (is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
    '.$langs->trans('Project') . ' '; + if ($permissiontoadd) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
    '; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
    '; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ': '.$proj->getNomUrl(); + } else { + $morehtmlref .= ''; + } + } + }*/ + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0, '', '', 1); + + print dol_get_fiche_end(); + + print '
    '; + + // Contacts lines (modules that overwrite templates must declare this into descriptor) + $dirtpls = array_merge($conf->modules_parts['tpl'], array('/core/tpl')); + foreach ($dirtpls as $reldir) { + $res = @include dol_buildpath($reldir.'/contacts.tpl.php'); + if ($res) { + break; + } + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/skill_document.php b/htdocs/hrm/skill_document.php new file mode 100644 index 00000000000..4e15c2acb9f --- /dev/null +++ b/htdocs/hrm/skill_document.php @@ -0,0 +1,217 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file skill_document.php + * \ingroup hrm + * \brief Tab for documents linked to skill + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +dol_include_once('/hrm/class/skill.class.php'); +dol_include_once('/hrm/lib/hrm_skill.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies", "other", "mails")); + + +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm'); +$id = (GETPOST('socid', 'int') ? GETPOST('socid', 'int') : GETPOST('id', 'int')); +$ref = GETPOST('ref', 'alpha'); + +// Get parameters +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortorder) { + $sortorder = "ASC"; +} +if (!$sortfield) { + $sortfield = "name"; +} +//if (! $sortfield) $sortfield="position_name"; + +// Initialize technical objects +$object = new Skill($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('skilldocument', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity ? $object->entity : $conf->entity]."/skill/".get_exdir(0, 0, 0, 1, $object); +} + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; + + +/* + * View + */ + +$form = new Form($db); + +$title = $langs->trans("Skilldet").' - '.$langs->trans("Files"); +$help_url = ''; +//$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('', $title, $help_url); + +if ($object->id) { + /* + * Show tabs + */ + $head = skillPrepareHead($object); + + print dol_get_fiche_head($head, 'document', $langs->trans("Documents"), -1, $object->picto); + + + // Build file list + $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1); + $totalsize = 0; + foreach ($filearray as $key => $file) { + $totalsize += $file['size']; + } + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + print '
    '; + + print '
    '; + print ''; + + // Number of files + print ''; + + // Total size + print ''; + + print '
    '.$langs->trans("NbOfAttachedFiles").''.count($filearray).'
    '.$langs->trans("TotalSizeOfAttachedFiles").''.$totalsize.' '.$langs->trans("bytes").'
    '; + + print '
    '; + + print dol_get_fiche_end(); + + $modulepart = 'hrm'; + $permtoedit = $permissiontoadd; + $param = '&id='.$object->id; + + //$relativepathwithnofile='skill/' . dol_sanitizeFileName($object->id).'/'; + $relativepathwithnofile = 'skill/'.dol_sanitizeFileName($object->ref).'/'; + + include DOL_DOCUMENT_ROOT.'/core/tpl/document_actions_post_headers.tpl.php'; +} else { + accessforbidden('', 0, 1); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/skill_list.php b/htdocs/hrm/skill_list.php new file mode 100644 index 00000000000..009a5491342 --- /dev/null +++ b/htdocs/hrm/skill_list.php @@ -0,0 +1,733 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file skill_list.php + * \ingroup hrm + * \brief List page for skill + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; + +// load hrm libraries +require_once __DIR__.'/class/skill.class.php'; + +// for other modules +//dol_include_once('/othermodule/class/otherobject.class.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +$action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... +$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) +$show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? +$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation +$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button +$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'skilllist'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + +$id = GETPOST('id', 'int'); + +// Load variable for pagination +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST('sortfield', 'aZ09comma'); +$sortorder = GETPOST('sortorder', 'aZ09comma'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + // If $page is not defined, or '' or -1 or if we click on clear filters + $page = 0; +} +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +// Initialize technical objects +$object = new Skill($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('skilllist')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); +//$extrafields->fetch_name_optionals_label($object->table_element_line); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Default sort order (if not yet defined by previous GETPOST) +if (!$sortfield) { + reset($object->fields); // Reset is required to avoid key() to return null. + $sortfield = "t.".key($object->fields); // Set here default search field. By default 1st field in definition. +} +if (!$sortorder) { + $sortorder = "ASC"; +} + +// Initialize array of search criterias +$search_all = GETPOST('search_all', 'alphanohtml') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_'.$key, 'alpha') !== '') { + $search[$key] = GETPOST('search_'.$key, 'alpha'); + } + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int')); + $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int')); + } +} + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array(); +foreach ($object->fields as $key => $val) { + if (!empty($val['searchall'])) { + $fieldstosearchall['t.'.$key] = $val['label']; + } +} + +// Definition of array of fields for columns +$arrayfields = array(); +foreach ($object->fields as $key => $val) { + // If $val['visible']==0, then we never show the field + if (!empty($val['visible'])) { + $visible = (int) dol_eval($val['visible'], 1); + $arrayfields['t.'.$key] = array( + 'label'=>$val['label'], + 'checked'=>(($visible < 0) ? 0 : 1), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'position'=>$val['position'], + 'help'=> isset($val['help']) ? $val['help'] : '' + ); + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; + +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; +$permissiontodelete = $user->rights->hrm->all->delete; + +// Security check +if (empty($conf->hrm->enabled)) { + accessforbidden('Module not enabled'); +} + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) accessforbidden(); +//$socid = 0; if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + + +/* + * Actions + */ + +if (GETPOST('cancel', 'alpha')) { + $action = 'list'; + $massaction = ''; +} +if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { + $massaction = ''; +} + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + foreach ($object->fields as $key => $val) { + $search[$key] = ''; + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = ''; + $search[$key.'_dtend'] = ''; + } + } + $toselect = array(); + $search_array_options = array(); + } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha') + || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) { + $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation + } + + // Mass actions + $objectclass = 'Skill'; + $objectlabel = 'Skill'; + $uploaddir = $conf->hrm->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + + +/* + * View + */ + +$form = new Form($db); + +$now = dol_now(); + +//$help_url="EN:Module_Skill|FR:Module_Skill_FR|ES:Módulo_Skill"; +$help_url = ''; +$title = $langs->trans('ListOf', $langs->transnoentitiesnoconv("Skills")); +$morejs = array(); +$morecss = array(); + + +// Build and execute select +// -------------------------------------------------------------------- +$sql = 'SELECT '; +$sql .= $object->getFieldList('t'); +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key.', ' : ''); + } +} +// Add fields from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= preg_replace('/^,/', '', $hookmanager->resPrint); +$sql = preg_replace('/,\s*$/', '', $sql); +$sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; +if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; +} +// Add table from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +if ($object->ismultientitymanaged == 1) { + $sql .= " WHERE t.entity IN (".getEntity($object->element).")"; +} else { + $sql .= " WHERE 1 = 1"; +} +foreach ($search as $key => $val) { + if (array_key_exists($key, $object->fields)) { + if ($key == 'status' && $search[$key] == -1) { + continue; + } + $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); + if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { + if ($search[$key] == '-1' || $search[$key] === '0') { + $search[$key] = ''; + } + $mode_search = 2; + } + if ($search[$key] != '') { + $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search)); + } + } else { + if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') { + $columnName=preg_replace('/(_dtstart|_dtend)$/', '', $key); + if (preg_match('/^(date|timestamp|datetime)/', $object->fields[$columnName]['type'])) { + if (preg_match('/_dtstart$/', $key)) { + $sql .= " AND t." . $columnName . " >= '" . $db->idate($search[$key]) . "'"; + } + if (preg_match('/_dtend$/', $key)) { + $sql .= " AND t." . $columnName . " <= '" . $db->idate($search[$key]) . "'"; + } + } + } + } +} +if ($search_all) { + $sql .= natural_search(array_keys($fieldstosearchall), $search_all); +} +//$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear); +// Add where from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; + +/* If a group by is required +$sql .= " GROUP BY "; +foreach($object->fields as $key => $val) { + $sql .= 't.'.$key.', '; +} +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : ''); + } +} +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +$sql = preg_replace('/,\s*$/', '', $sql); +*/ + +$sql .= $db->order($sortfield, $sortorder); + +// Count total nb of records +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + $resql = $db->query($sql); + $nbtotalofrecords = $db->num_rows($resql); + if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + $page = 0; + $offset = 0; + } +} +// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. +if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { + $num = $nbtotalofrecords; +} else { + if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); + } + + $resql = $db->query($sql); + if (!$resql) { + dol_print_error($db); + exit; + } + + $num = $db->num_rows($resql); +} + +// Direct jump if only one record found +if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { + $obj = $db->fetch_object($resql); + $id = $obj->rowid; + header("Location: ".dol_buildpath('/hrm/skill_card.php', 1).'?id='.$id); + exit; +} + + +// Output page +// -------------------------------------------------------------------- + +llxHeader('', $title, $help_url, '', 0, 0, $morejs, $morecss, '', ''); + +// Example : Adding jquery code +// print ''; + +$arrayofselected = is_array($toselect) ? $toselect : array(); + +$param = ''; +if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); +} +if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); +} +foreach ($search as $key => $val) { + if (is_array($search[$key]) && count($search[$key])) { + foreach ($search[$key] as $skey) { + $param .= '&search_'.$key.'[]='.urlencode($skey); + } + } else { + $param .= '&search_'.$key.'='.urlencode($search[$key]); + } +} +if ($optioncss != '') { + $param .= '&optioncss='.urlencode($optioncss); +} +// Add $param from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; +// Add $param from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook +$param .= $hookmanager->resPrint; + +// List of mass actions available +$arrayofmassactions = array( + //'validate'=>img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate"), + //'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"), + //'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"), + //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), +); +if ($permissiontodelete) { + $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); +} +if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete'))) { + $arrayofmassactions = array(); +} +$massactionbutton = $form->selectMassAction('', $arrayofmassactions); + +print '
    '."\n"; +if ($optioncss != '') { + print ''; +} +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +$newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/hrm/skill_card.php', 1).'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd); + +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'object_'.$object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1); + +// Add code for pre mass action (confirmation or email presend form) +$topicmail = "SendSkillRef"; +$modelmail = "skill"; +$objecttmp = new Skill($db); +$trackid = 'xxxx'.$object->id; +include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; + +if ($search_all) { + foreach ($fieldstosearchall as $key => $val) { + $fieldstosearchall[$key] = $langs->trans($val); + } + print '
    '.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'
    '; +} + +$moreforfilter = ''; +/*$moreforfilter.='
    '; +$moreforfilter.= $langs->trans('MyFilter') . ': '; +$moreforfilter.= '
    ';*/ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +if (empty($reshook)) { + $moreforfilter .= $hookmanager->resPrint; +} else { + $moreforfilter = $hookmanager->resPrint; +} + +if (!empty($moreforfilter)) { + print '
    '; + print $moreforfilter; + print '
    '; +} + +$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + +print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table +print ''."\n"; + + +// Fields title search +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + +// Fields from hook +$parameters = array('arrayfields'=>$arrayfields); +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print ''; +print ''."\n"; + + +// Fields title label +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($cssforfield ? 'class="'.$cssforfield.'"' : ''), $sortfield, $sortorder, ($cssforfield ? $cssforfield.' ' : ''))."\n"; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; +// Hook fields +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +print ''."\n"; + + +// Detect if we need a fetch on each output line +$needToFetchEachLine = 0; +if (isset($extrafields->attributes[$object->table_element]['computed']) && is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0) { + foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val) { + if (preg_match('/\$object/', $val)) { + $needToFetchEachLine++; // There is at least one compute field that use $object + } + } +} + + +// Loop on record +// -------------------------------------------------------------------- +$i = 0; +$totalarray = array(); +$totalarray['nbfield'] = 0; +while ($i < ($limit ? min($num, $limit) : $num)) { + $obj = $db->fetch_object($resql); + if (empty($obj)) { + break; // Should not happen + } + + // Store properties in $object + $object->setVarsFromFetchObj($obj); + + // Show here line of result + print ''; + foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } + + if (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif ($key == 'ref') { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } + + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && !in_array($key, array('rowid', 'status')) && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; + + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + if ($key == 'status') { + print $object->getLibStatut(5); + } elseif ($key == 'rowid') { + print $object->showOutputField($val, $key, $object->id, ''); + }elseif ($key == 'label'){ + print $object->getNomUrl(1); + } else { + print $object->showOutputField($val, $key, $object->$key, ''); + } + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + if (!empty($val['isameasure'])) { + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 't.'.$key; + } + if (!isset($totalarray['val'])) { + $totalarray['val'] = array(); + } + if (!isset($totalarray['val']['t.'.$key])) { + $totalarray['val']['t.'.$key] = 0; + } + $totalarray['val']['t.'.$key] += $object->$key; + } + } + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields, 'object'=>$object, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + + print ''."\n"; + + $i++; +} + +// Show total line +include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + +// If no record found +if ($num == 0) { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; +} + + +$db->free($resql); + +$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql); +$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print '
    '; + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + print $form->selectarray('search_'.$key, $val['arrayofkeyval'], (isset($search[$key]) ? $search[$key] : ''), $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth100', 1); + } elseif ((strpos($val['type'], 'integer:') === 0) || (strpos($val['type'], 'sellist:') === 0)) { + print $object->showInputField($val, $key, (isset($search[$key]) ? $search[$key] : ''), '', '', 'search_', 'maxwidth125', 1); + } elseif (!preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print ''; + } elseif (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print '
    '; + print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
    '; + print '
    '; + print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
    '; + } + print '
    '; +$searchpicto = $form->showFilterButtons(); +print $searchpicto; +print '
    '; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print '
    '.$langs->trans("NoRecordFound").'
    '."\n"; +print '
    '."\n"; + +print '
    '."\n"; + +if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords)) { + $hidegeneratedfilelistifempty = 1; + if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) { + $hidegeneratedfilelistifempty = 0; + } + + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + $formfile = new FormFile($db); + + // Show list of available documents + $urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder; + $urlsource .= str_replace('&', '&', $param); + + $filedir = $diroutputmassaction; + $genallowed = $permissiontoread; + $delallowed = $permissiontoadd; + + print $formfile->showdocuments('massfilesarea_hrm', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/skill_note.php b/htdocs/hrm/skill_note.php new file mode 100644 index 00000000000..564561e7c75 --- /dev/null +++ b/htdocs/hrm/skill_note.php @@ -0,0 +1,175 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file skill_note.php + * \ingroup hrm + * \brief Tab for notes on skill + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +dol_include_once('/hrm/class/skill.class.php'); +dol_include_once('/hrm/lib/hrm_skill.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new Skill($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('skillnote', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->hrm->multidir_output[$object->entity]."/".$object->id; +} + +$permissionnote = $user->rights->hrm->all->write; +$permissiontoread = $user->rights->hrm->all->read; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { + include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once +} + + +/* + * View + */ + +$form = new Form($db); + +//$help_url='EN:Customers_Orders|FR:Commandes_Clients|ES:Pedidos de clientes'; +$help_url = ''; +llxHeader('', $langs->trans('Skill'), $help_url); + +if ($id > 0 || !empty($ref)) { + $object->fetch_thirdparty(); + + $head = skillPrepareHead($object); + + print dol_get_fiche_head($head, 'note', $langs->trans("Notes"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref); + + + print '
    '; + print '
    '; + + + $cssclass = "titlefield"; + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + + print '
    '; + + print dol_get_fiche_end(); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php new file mode 100644 index 00000000000..b522f5d4def --- /dev/null +++ b/htdocs/hrm/skill_tab.php @@ -0,0 +1,374 @@ + + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Greg Rastklan + * Copyright (C) 2021 Jean-Pascal BOUDET + * Copyright (C) 2021 Grégory BLEMAND + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file skill_tab.php + * \ingroup hrm + * \brief Page to add/delete/view skill to jobs/users + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies +//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET +//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { + $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"] . "/main.inc.php"; +} +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; +$tmp2 = realpath(__FILE__); +$i = strlen($tmp) - 1; +$j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { + $i--; + $j--; +} +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1)) . "/main.inc.php")) { + $res = @include substr($tmp, 0, ($i + 1)) . "/main.inc.php"; +} +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php")) { + $res = @include dirname(substr($tmp, 0, ($i + 1))) . "/main.inc.php"; +} +// Try main.inc.php using relative path +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; +require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php'; +dol_include_once('/hrm/class/skill.class.php'); +dol_include_once('/hrm/class/skillrank.class.php'); +dol_include_once('/hrm/lib/hrm_skill.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("hrm", "other")); + +$id = GETPOST('id', 'int'); +$fk_skill = GETPOST('fk_skill', 'int'); +$objecttype = GETPOST('objecttype', 'alpha'); +$TNote = GETPOST('TNote', 'array'); +$lineid = GETPOST('lineid', 'int'); +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'skillcard'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); +$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); + +$TAuthorizedObjects = array('job', 'user'); +$skill = new SkillRank($db); + +// Initialize technical objects +if (in_array($objecttype, $TAuthorizedObjects)) { + if ($objecttype == 'job') { + dol_include_once('/hrm/class/job.class.php'); + $object = new Job($db); + } else if ($objecttype == "user") { + $object = new User($db); + } +} else accessforbidden($langs->trans('ErrorBadObjectType')); + +$hookmanager->initHooks(array('skilltab', 'globalcard')); // Note that conf->hooks_modules contains array + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once. + +$permissiontoread = $user->rights->hrm->all->read; +$permissiontoadd = $user->rights->hrm->all->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +if (empty($conf->hrm->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $error = 0; + + $backurlforlist = dol_buildpath('/hrm/skill_list.php', 1); + + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = dol_buildpath('/hrm/skill_list.php', 1) . '?id=' . ($id > 0 ? $id : '__ID__'); + } + } + } + + if ($action == 'addSkill') { + $error = 0; + + if ($fk_skill <= 0) { + setEventMessage('ErrNoSkillSelected', 'errors'); + $error++; + } + + if (!$error) { + $skillAdded = new SkillRank($db); + $skillAdded->fk_skill = $fk_skill; + $skillAdded->fk_object = $id; + $skillAdded->objecttype = $objecttype; + $ret = $skillAdded->create($user); + if ($ret < 0) setEventMessage($skillAdded->error, 'errors'); + else unset($fk_skill); + } + } else if ($action == 'saveSkill') { + if (!empty($TNote)) { + foreach ($TNote as $skillId => $rank) { + $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . ' AND objecttype="' . $objecttype . '" AND fk_skill = ' . $skillId)); + if (is_array($TSkills) && !empty($TSkills)) { + foreach ($TSkills as $tmpObj) { + $tmpObj->rank = $rank; + $tmpObj->update($user); + } + } + } + } + + } else if ($action == 'confirm_deleteskill' && $confirm == 'yes') { + $skillToDelete = new SkillRank($db); + $ret = $skillToDelete->fetch($lineid); + if ($ret > 0) { + $skillToDelete->delete($user); + } + } +} + +/* + * View + * + * Put here all code to build page + */ + +$form = new Form($db); +$formfile = new FormFile($db); +$formproject = new FormProjets($db); + +$title = $langs->trans("RequiredSkills"); +$help_url = ''; +llxHeader('', $title, $help_url); + +// Part to show record +if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { + $res = $object->fetch_optionals(); + + // view configuration + if ($objecttype == 'job') { + dol_include_once('/hrm/lib/hrm_job.lib.php'); + $head = jobPrepareHead($object); + $listLink = dol_buildpath('/hrm/job_list.php', 1); + } else if ($objecttype == "user") { + require_once DOL_DOCUMENT_ROOT . "/core/lib/usergroups.lib.php"; + $object->getRights(); + $head = user_prepare_head($object); + $listLink = dol_buildpath('/user/list.php', 1); + } + + print dol_get_fiche_head($head, 'skill_tab', $langs->trans("Workstation"), -1, $object->picto); + + $formconfirm = ''; + + // Confirmation to delete + /*if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteSkill'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); + }*/ + // Confirmation to delete line + if ($action == 'ask_deleteskill') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&objecttype=' . $objecttype . '&lineid=' . $lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteskill', '', 0, 1); + } + // Clone confirmation + /*if ($action == 'clone') { + // Create an array for form + $formquestion = array(); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); + }*/ + + // Call Hook formConfirm + $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + $formconfirm .= $hookmanager->resPrint; + } elseif ($reshook > 0) { + $formconfirm = $hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref.= $object->label; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref, '&objecttype='.$objecttype); + + + // table of skillRank linked to current object + $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . ' AND objecttype="' . $objecttype . '"')); + +// $TAlreadyUsedSkill = array(); +// if (is_array($TSkills) && !empty($TSkills)) { +// foreach ($TSkills as $skillElement) { +// $TAlreadyUsedSkill[] = $skillElement->fk_skill; +// } +// } + + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + $object->fields['label']['visible']=0; // Already in banner + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_view.tpl.php'; + print '
    '; + print '
    '; + + print '

    '; + + if ($objecttype != 'user' && $permissiontoadd) + { + // form pour ajouter des compétences + print '
    '; + print ''; + print ''; + print ''; + print '
    '; + print ''; + print ''; + print ''; + foreach ($skill->fields as $key => $infos) { + if ($key == 'fk_skill') { + print ''; + } + } + print ''; + print ''; + print '
    ' . $langs->trans('AddSkill') . '
    ' . $skill->showInputField($infos, $key, $$key) . '
    '; + print '
    '; + print '
    '; + + } + print '
    '; + + print '
    '; + + if ($objecttype != 'user' && $permissiontoadd) + { + print '
    '; + print ''; + print ''; + print ''; + } + print '
    '; + print ''; + print ''; + foreach ($skill->fields as $key => $infos) { + if($infos['label'] === 'Rank') $infos['label'] = 'RequiredRank'; + if ($infos['visible'] > 0) print ''; + } + print ''; + print ''; + print ''; + if (!is_array($TSkills) || empty($TSkills)) { + print ''; + } else { + $sk = new Skill($db); + foreach ($TSkills as $skillElement) { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + } + + print '
    ' . $langs->trans($infos['label']) . '
    ' . $langs->trans("NoRecordFound") . '
    '; + $sk->fetch($skillElement->fk_skill); + print $sk->getNomUrl(1); + print ''; + print displayRankInfos($skillElement->rank, $skillElement->fk_skill, 'TNote', $objecttype == 'job' && $permissiontoadd ? 'edit' : 'view'); + print ''; + if ($objecttype != 'user' && $permissiontoadd) + { + print 'id . '">'; + print img_delete(); + print ''; + } + print '
    '; + if ($objecttype != 'user' && $permissiontoadd) print ''; + print '
    '; + if ($objecttype != 'user' && $permissiontoadd) print '
    '; + + + // liste des compétences liées + + print dol_get_fiche_end(); + + llxFooter(); + +} diff --git a/htdocs/langs/en_US/hrm.lang b/htdocs/langs/en_US/hrm.lang index da098e10bdb..b5a005a07ee 100644 --- a/htdocs/langs/en_US/hrm.lang +++ b/htdocs/langs/en_US/hrm.lang @@ -1,4 +1,6 @@ # Dolibarr language file - en_US - hrm + + # Admin HRM_EMAIL_EXTERNAL_SERVICE=Email to prevent HRM external service Establishments=Establishments @@ -17,3 +19,69 @@ Employees=Employees Employee=Employee NewEmployee=New employee ListOfEmployees=List of employees +HrmSetup = Hrm setup +HrmSetupPage = Hrm setup page +HRM_MAXRANK=Maximum rank for a skill +HRM_DEFAULT_SKILL_DESCRIPTION=Default description of ranks when skill is created +HrmAbout = About Hrm +traduction_note=Translate +deplacement=Shift +DateEval=Evaluation date +JobCard=Job card +Job=Job +Jobs=Jobs +NewSkill=New Skill +SkillType=Skill type +Skilldets=List of ranks for this skill +Skilldet=Skill level +rank=Rank +ErrNoSkillSelected=No skill selected +ErrSkillAlreadyAdded=This skill is already in the list +SkillHasNoLines=This skill has no lines +skill=Skill +Skills=Skills +SkillCard=Skill card +Eval=Evaluation +Evals=Evaluations +NewEval=New evaluation +ValidateEvaluation=Validate evaluation +ConfirmValidateEvaluation=Are you sure you want to validate this evaluation with reference %s? +EvaluationCard=Evaluation card +RequiredRank=Required rank for this job +Position=Position +Positions=Positions +PositionCard=Position card +EmployeesInThisPosition=Employees in this position +group1ToCompare=Usergroup to analyze +group2ToCompare=Second usergroup for comparison +OrJobToCompare=Compare to job skills requirements +difference=Difference +CompetenceAcquiredByOneOrMore=Competence acquired by one or more users but not requested by the second comparator +MaxlevelGreaterThan=Max level greater than the one requested +MaxLevelEqualTo=Max level equal to that demand +MaxLevelLowerThan= Max level lower than that demand +SkillNotAcquired=Skill not acquired by all users and requested by the second comparator +legend=Legend +TypeSkill=Skill type +AddSkill=Add skill to job +RequiredSkills=Required skills for this job +UserRank=User Rank +SkillList=Skill list +SaveRank=Save rank +knowHow=Know how +HowToBe=How to be +knowledge=Knowledge +AbandonmentComment=Abandonment comment +DateLastEval=Date last evaluation +NoEval=No evaluation done for this employee +HowManyUserWithThisMaxNote=Number of users with this rank +HighestRank=Highest rank +SkillComparison=Skill comparison +ReadSkillJobPosition=Read skills / jobs / positions +CreateUpdateSkillJobPosition=Create / update skills / jobs / positions +DeleteSkillJobPosition=Delete skills / jobs / positions +ReadEval=Read evaluations +CreateUpdateEval=Create / update evaluations +ValidateEval=Validate evaluations +DeleteEval=Delete evaluations +SeeComparisonMenu=Access skills comparison menu diff --git a/htdocs/langs/fr_FR/hrm.lang b/htdocs/langs/fr_FR/hrm.lang index 81fee383b56..9a2663d6714 100644 --- a/htdocs/langs/fr_FR/hrm.lang +++ b/htdocs/langs/fr_FR/hrm.lang @@ -1,4 +1,17 @@ -# Dolibarr language file - en_US - hrm +# Dolibarr language file - fr_FR - hrm + + +# +# Generic +# + +# Module label 'ModuleHrmName' +ModuleHrmName = GRH +# Module description 'ModuleHrmDesc' +ModuleHrmDesc = GRH description + + + # Admin HRM_EMAIL_EXTERNAL_SERVICE=Adresse email du service GRH externe à prévenir Establishments=Etablissements @@ -17,3 +30,69 @@ Employees=Salariés Employee=Salarié NewEmployee=Nouveau salarié ListOfEmployees=List des salariés +HrmSetup = Configuration GPEC +HrmSetupPage = Page de configuration du module GPEC +HRM_MAXRANK=Note maximale pour une compétence +HRM_DEFAULT_SKILL_DESCRIPTION=Description par défaut d'une note lors de la création d'une nouvelle compétence +HrmAbout = A propos du module GPEC +traduction_note=Translate +deplacement=Déplacement +DateEval=Date évaluation +JobCard=Fiche métier +Job=Métier +Jobs=Métiers +NewSkill=Nouvelle compétence +SkillType=Type de compétence +Skilldets=Liste des notes pour cette compétence +Skilldet=Skill level +rank=Note +ErrNoSkillSelected=Aucune compétence sélectionnée +ErrSkillAlreadyAdded=Cette compétence est déjà dans la liste +SkillHasNoLines=Cette compétence n'a pas de notes +skill=Compétence +Skills=Compétences +SkillCard=Fiche compétence +Eval=Evaluation +Evals=Evaluations +NewEval=Nouvelle evaluation +ValidateEvaluation=Valider évaluation +ConfirmValidateEvaluation=Etes vous sûr(e) de vouloir valider cette évaluation sous la référence %s? +EvaluationCard=Fiche évaluation +RequiredRank=Note requise pour ce métier +PositionCard=Fiche poste +EmployeesInThisPosition=Salariés occupant ce poste +Position=Poste +Positions=Postes +group1ToCompare=Groupe utilisateurs à analyser +group2ToCompare=Second groupe utilisateurs pour comparaison +OrJobToCompare=Comparer avec les compétences exigées pour un métier +difference=Différence +CompetenceAcquiredByOneOrMore=Compétence acquise par au moins un salarié mais non requise par le second élément de comparaison +MaxlevelGreaterThan=Niveau maximal supérieur au niveau requis +MaxLevelEqualTo=Niveau maximal égal au niveau requis +MaxLevelLowerThan= Niveau maximal inférieur au niveau requis +SkillNotAcquired=Compétence non acquise par tous les utilisateur et requise par le second élément de comparaison +legend=Légende +TypeSkill=Type de compétence +AddSkill=Ajouter une compétence à ce métier +RequiredSkills=Compétences requises pour ce métier +UserRank=Note utilisateur +SkillList=Liste des compétences +SaveRank=Enregistrer notes +knowHow=Savoir faire +HowToBe=Savoir être +knowledge=Savoir +AbandonmentComment=Commentaire abandon +DateLastEval=Date dernière évaluation +NoEval=Aucune évaluation effectuée pour ce salarié +HowManyUserWithThisMaxNote=Nombre d'utilisateurs ayant cette note +HighestRank=Note la plus haute +SkillComparison=Comparaison des compétences +ReadSkillJobPosition=Lire les compétences / métiers / postes +CreateUpdateSkillJobPosition=Créer / mettre à jour les compétences / métiers / postes +DeleteSkillJobPosition=Supprimer les compétences / métiers / postes +ReadEval=Lire les évaluations +CreateUpdateEval=Créer / mettre à jour les évaluations +ValidateEval=Valider les évaluations +DeleteEval=Supprimer les évaluations +SeeComparisonMenu=Accéder au menu de comparaison des compétences From 9713f6afd9cb8ff75c661f3ff2c726ccb9fcfa04 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Tue, 28 Sep 2021 08:40:15 +0200 Subject: [PATCH 02/79] FIX : stickler feedbacks part 1 --- htdocs/hrm/class/job.class.php | 10 ++--- htdocs/hrm/class/position.class.php | 4 +- htdocs/hrm/class/skill.class.php | 65 ++++++++++++++++------------ htdocs/hrm/class/skillrank.class.php | 6 +-- htdocs/hrm/evaluation_card.php | 4 +- htdocs/hrm/skill_card.php | 2 +- 6 files changed, 50 insertions(+), 41 deletions(-) diff --git a/htdocs/hrm/class/job.class.php b/htdocs/hrm/class/job.class.php index 248e367b998..263f685dc78 100644 --- a/htdocs/hrm/class/job.class.php +++ b/htdocs/hrm/class/job.class.php @@ -602,7 +602,7 @@ class Job extends CommonObject /** * Get last job for user * - * @param $fk_user + * @param int $fk_user id of user we need to get last job * @return mixed|string|null */ public function getLastJobForUser($fk_user) @@ -610,7 +610,7 @@ class Job extends CommonObject global $db; $j = new Job($db); - $Tab = $j->get_for_user($fk_user); + $Tab = $j->getForUser($fk_user); if (empty($Tab)) return ''; @@ -622,16 +622,16 @@ class Job extends CommonObject /** * Get jobs for user * - * @param $userid + * @param int $userid id of user we need to get job list * @return array of jobs */ - public function get_for_user($userid) + public function getForUser($userid) { global $db; $TReturn = array(); $position = new Position($db); - $TPosition = $position->get_for_user($userid); + $TPosition = $position->getForUser($userid); foreach ($TPosition as $UPosition) { $TReturn[$UPosition->Job->rowid] = $UPosition->Job->ref; } diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index 9b9241477c9..e15a15de12d 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -981,10 +981,10 @@ class Position extends CommonObject } /** - * @param $userid + * @param int $userid id of user we need to get position list * @return array|int of positions of user with for each of them the job fetched into that array */ - public function get_for_user($userid) + public function getForUser($userid) { $TPosition = array(); diff --git a/htdocs/hrm/class/skill.class.php b/htdocs/hrm/class/skill.class.php index 0a1158593b2..7cf2d60e88a 100644 --- a/htdocs/hrm/class/skill.class.php +++ b/htdocs/hrm/class/skill.class.php @@ -240,6 +240,10 @@ class Skill extends CommonObject return $resultcreate; } + /** + * @param int $i rank from which we want to create skilldets + * @return null + */ public function createSkills($i = 1) { @@ -1086,40 +1090,45 @@ class Skill extends CommonObject return $error; } + /** * Permet de retourner un select html du dictionnaire llx_c_skill_type * - * @global type $conf - * @param string $selected - * @param string $htmlname - * @param bool $emptyvalue + * @param string $selected preselected element + * @param string $htmlname html name of input + * @param bool $emptyvalue true if we need to put an empty value + * @param string $moreattr used to add more html attributes into input + * @param string $more_class used if we want to add new css class to input * @return string */ - public function select_skill_type($selected = '', $htmlname = 'code_c_skill_type', $emptyvalue = true, $moreattr = '', $more_class = '') - { - global $conf; - - $out = ''; - - return $out; - } - +// public function select_skill_type($selected = '', $htmlname = 'code_c_skill_type', $emptyvalue = true, $moreattr = '', $more_class = '') +// { +// global $conf; +// +// $out = ''; +// +// return $out; +// } + /** + * @param int $code number of code label + * @return int|string + */ public static function typeCodeToLabel($code) { global $langs; diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index 5e1149f133e..ffd83008589 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -362,10 +362,10 @@ class SkillRank extends CommonObject * The skillrank table is a join table that is marked for multiple objects * * @param SkillRank $currentSkill - * @param $user - * @return int + * @param int $fk_user id of user linked to skillrank + * @return int > 0 if ok, < 0 if ko */ - public function cloneFromCurrentSkill($currentSkill, $user, $fk_user) + public function cloneFromCurrentSkill($currentSkill, $fk_user) { global $user; diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 48554770107..4ae21fef372 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -223,7 +223,7 @@ if (empty($reshook)) { if (count($SkillrecordsForActiveUser) == 0) { if ($res > 0) { $newSkill = new SkillRank($db); - $resCreate = $newSkill->cloneFromCurrentSkill($line, $user, $object->fk_user); + $resCreate = $newSkill->cloneFromCurrentSkill($line, $object->fk_user); if ($resCreate <= 0) { $errors++; @@ -251,7 +251,7 @@ if (empty($reshook)) { $updSkill->update($user); } else { // sinon on ajoute la skill $newSkill = new SkillRank($db); - $resCreate = $newSkill->cloneFromCurrentSkill($line, $user, $object->fk_user); + $resCreate = $newSkill->cloneFromCurrentSkill($line, $object->fk_user); } } } diff --git a/htdocs/hrm/skill_card.php b/htdocs/hrm/skill_card.php index d577605c6fb..12602a46c0a 100644 --- a/htdocs/hrm/skill_card.php +++ b/htdocs/hrm/skill_card.php @@ -339,7 +339,7 @@ if (($id || $ref) && $action == 'edit') { // if (!empty($val['help'])) { // print $form->textwithpicto($langs->trans($val['label']), $langs->trans($val['help'])); // } else { - print $langs->trans($val['label']).' '.$langs->trans('Rank').' '.$sk->rank; + print $langs->trans($val['label']).' '.$langs->trans('rank').' '.$sk->rank; // } print ''; print ''; From 409c8c8d57e88ff94db66c730fbc01bf4e777e91 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Wed, 29 Sep 2021 07:49:42 +0200 Subject: [PATCH 03/79] FIX : stickler feedbacks part 2 --- htdocs/hrm/class/skillrank.class.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index ffd83008589..094eea1736e 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -1077,10 +1077,10 @@ class SkillRank extends CommonObject * @param string $morecss * @return string */ - public function showOutputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '') - { - if ($key == "rank") { - return displayRankInfos($this); - } else return parent::showOutputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); - } +// public function showOutputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '') +// { +// if ($key == "rank") { +// return displayRankInfos($this); +// } else return parent::showOutputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); +// } } From eccff256b130ba468c0b1959ad03ebb64da24fb1 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Wed, 29 Sep 2021 08:30:30 +0200 Subject: [PATCH 04/79] FIX : IHM --- htdocs/hrm/skill_tab.php | 28 +++++++++++++++++----------- htdocs/langs/en_US/hrm.lang | 1 + htdocs/langs/fr_FR/hrm.lang | 1 + 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php index b522f5d4def..28e6cbce764 100644 --- a/htdocs/hrm/skill_tab.php +++ b/htdocs/hrm/skill_tab.php @@ -324,32 +324,38 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; } print '
    '; - print ''; + print '
    '; print ''; - foreach ($skill->fields as $key => $infos) { - if($infos['label'] === 'Rank') $infos['label'] = 'RequiredRank'; - if ($infos['visible'] > 0) print ''; + print ''; + print ''; + print ''; + print ''; + if($objecttype === 'job') { + print ''; + print ''; } - print ''; - print ''; print ''; if (!is_array($TSkills) || empty($TSkills)) { print ''; } else { $sk = new Skill($db); foreach ($TSkills as $skillElement) { - print ''; - print ''; + print ''; - print ''; - print ''; - print ''; + print '\n"; -// foreach ($this->lines as $line) { -// //Line extrafield -// $line->fetch_optionals(); -// -// //if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line))) -// if (is_object($hookmanager)) { // Old code is commented on preceding line. -// if (empty($line->fk_parent_line)) { -// $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'selected'=>$selected, 'table_element_line'=>$line->table_element); -// $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks -// } else { -// $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'selected'=>$selected, 'table_element_line'=>$line->table_element, 'fk_parent_line'=>$line->fk_parent_line); -// $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks -// } -// } -// if (empty($reshook)) { -// $this->printObjectLine($action, $line); -// } -// -// $i++; -// } -// print "\n"; -// } + // public function printObjectLines($action, $selected = 0) + // { + // global $conf, $hookmanager, $langs, $user, $extrafields, $object; + // // TODO We should not use global var for this + // global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax; + // + // // Define usemargins + //// $usemargins = 0; + //// if (!empty($conf->margin->enabled) && !empty($this->element) && in_array($this->element, array('facture', 'facturerec', 'propal', 'commande'))) { + //// $usemargins = 1; + //// } + // + // $num = count($this->lines); + // + // // Line extrafield + // if (!is_object($extrafields)) { + // require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + // $extrafields = new ExtraFields($this->db); + // } + // $extrafields->fetch_name_optionals_label($this->table_element_line); + // + // $parameters = array('num'=>$num, 'selected'=>$selected, 'table_element_line'=>$this->table_element_line); + // $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + // if (empty($reshook)) { + // // Output template part (modules that overwrite templates must declare this into descriptor) + // // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook. + // include dol_buildpath('hrm/core/tpl/objectline_title.tpl.php'); + // } + // + // $i = 0; + // + // print "\n"; + // foreach ($this->lines as $line) { + // //Line extrafield + // $line->fetch_optionals(); + // + // //if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line))) + // if (is_object($hookmanager)) { // Old code is commented on preceding line. + // if (empty($line->fk_parent_line)) { + // $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'selected'=>$selected, 'table_element_line'=>$line->table_element); + // $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + // } else { + // $parameters = array('line'=>$line, 'num'=>$num, 'i'=>$i, 'selected'=>$selected, 'table_element_line'=>$line->table_element, 'fk_parent_line'=>$line->fk_parent_line); + // $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + // } + // } + // if (empty($reshook)) { + // $this->printObjectLine($action, $line); + // } + // + // $i++; + // } + // print "\n"; + // } -// public function printObjectLine($action, $line) -// { -// global $conf, $langs, $user, $object, $hookmanager; -// global $form; -// global $object_rights, $disableedit, $disablemove, $disableremove; // TODO We should not use global var for this ! -// -// $object_rights = $this->getRights(); -// -// $element = $this->element; -// -// $text = ''; -// $description = ''; -// -// include dol_buildpath('hrm/tpl/objectline_view.tpl.php'); -// } + // public function printObjectLine($action, $line) + // { + // global $conf, $langs, $user, $object, $hookmanager; + // global $form; + // global $object_rights, $disableedit, $disablemove, $disableremove; // TODO We should not use global var for this ! + // + // $object_rights = $this->getRights(); + // + // $element = $this->element; + // + // $text = ''; + // $description = ''; + // + // include dol_buildpath('hrm/tpl/objectline_view.tpl.php'); + // } } diff --git a/htdocs/hrm/class/skill.class.php b/htdocs/hrm/class/skill.class.php index 7cf2d60e88a..b2fe7719564 100644 --- a/htdocs/hrm/class/skill.class.php +++ b/htdocs/hrm/class/skill.class.php @@ -1101,29 +1101,29 @@ class Skill extends CommonObject * @param string $more_class used if we want to add new css class to input * @return string */ -// public function select_skill_type($selected = '', $htmlname = 'code_c_skill_type', $emptyvalue = true, $moreattr = '', $more_class = '') -// { -// global $conf; -// -// $out = ''; -// -// return $out; -// } + // public function select_skill_type($selected = '', $htmlname = 'code_c_skill_type', $emptyvalue = true, $moreattr = '', $more_class = '') + // { + // global $conf; + // + // $out = ''; + // + // return $out; + // } /** * @param int $code number of code label diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index 094eea1736e..2f0e2b5d0dd 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -1077,10 +1077,10 @@ class SkillRank extends CommonObject * @param string $morecss * @return string */ -// public function showOutputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '') -// { -// if ($key == "rank") { -// return displayRankInfos($this); -// } else return parent::showOutputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); -// } + // public function showOutputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '') + // { + // if ($key == "rank") { + // return displayRankInfos($this); + // } else return parent::showOutputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); + // } } diff --git a/htdocs/hrm/core/tpl/objectline_view.tpl.php b/htdocs/hrm/core/tpl/objectline_view.tpl.php index e8416c35711..04f4cc48bdd 100644 --- a/htdocs/hrm/core/tpl/objectline_view.tpl.php +++ b/htdocs/hrm/core/tpl/objectline_view.tpl.php @@ -71,13 +71,11 @@ $coldisplay = 0; diff --git a/htdocs/hrm/core/tpl/skilldet.fiche.tpl.php b/htdocs/hrm/core/tpl/skilldet.fiche.tpl.php index d7bfcf9e626..60bb56ff173 100644 --- a/htdocs/hrm/core/tpl/skilldet.fiche.tpl.php +++ b/htdocs/hrm/core/tpl/skilldet.fiche.tpl.php @@ -2,8 +2,8 @@ // Protection to avoid direct call of template if (empty($object) || !is_object($object)) { -print "Error, template page can't be called as URL"; -exit; + print "Error, template page can't be called as URL"; + exit; } /* // $permissionnote must be defined by caller. For example $permissionnote=$user->rights->module->create @@ -78,10 +78,8 @@ $permission = $user->rights->ecm->setup; //else dol_print_error('','Bad value '.$module.' for param module'); if (!empty($object->table_element_line)) { -// Show object lines -$result = $object->getLinesArray(); - - + // Show object lines + $result = $object->getLinesArray(); } @@ -99,16 +97,16 @@ print '
    '."\n print '
    '."\n"; print ''."\n"; if (empty($user->socid)) { -// Private notes (always hidden to external users) -print '
    '."\n"; + // Private notes (always hidden to external users) + print '
    '."\n"; $editmode = (GETPOST('action', 'aZ09') == 'edit'.$note_private); print '
    '."\n"; print $form->editfieldkey("NotePrivate", $note_private, $value_private, $object, $permission, $typeofdata, $moreparam, '', 0); print '
    '."\n"; -print '
    '."\n"; + print '
    '."\n"; print $form->editfieldval("NotePrivate", $note_private, $value_private, $object, $permission, $typeofdata, '', null, null, $moreparam, 1); print '
    '."\n"; -print '
    '."\n"; + print '
    '."\n"; } print '
    '."\n"; ?> From f12a30079594f90675b8f9bfc49674e52f24b7ab Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Wed, 29 Sep 2021 08:35:08 +0200 Subject: [PATCH 06/79] FIX : td --- htdocs/hrm/skill_tab.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php index 28e6cbce764..ae5ee4371a0 100644 --- a/htdocs/hrm/skill_tab.php +++ b/htdocs/hrm/skill_tab.php @@ -347,8 +347,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; - print $sk->description; print ''; From acbf09ba596f8aac68c2ed204c65252e7e0618fc Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 30 Sep 2021 08:44:38 +0200 Subject: [PATCH 07/79] FIX : stickler feedbacks part 3 --- htdocs/hrm/class/skillrank.class.php | 2 +- htdocs/hrm/compare.php | 114 ++++++--------------------- 2 files changed, 24 insertions(+), 92 deletions(-) diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index 2f0e2b5d0dd..e6f63bb7d68 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -361,7 +361,7 @@ class SkillRank extends CommonObject * Clone skillrank Object linked to job with user id * The skillrank table is a join table that is marked for multiple objects * - * @param SkillRank $currentSkill + * @param SkillRank $currentSkill line of evaluation (skill) we need to clone and add to user skills list * @param int $fk_user id of user linked to skillrank * @return int > 0 if ok, < 0 if ko */ diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php index 83fc3a76ec6..d89534fa2cc 100644 --- a/htdocs/hrm/compare.php +++ b/htdocs/hrm/compare.php @@ -133,7 +133,18 @@ $fk_usergroup1 = GETPOST('fk_usergroup1'); - +
    ' . $langs->trans($infos['label']) . ''.$langs->trans('SkillType').''.$langs->trans('Label').''.$langs->trans('Description').''.$langs->trans($objecttype === 'job' ? 'RequiredRank' : 'EmployeeRank').'
    ' . $langs->trans("NoRecordFound") . '
    '; $sk->fetch($skillElement->fk_skill); + print '
    '; + print Skill::typeCodeToLabel($sk->skill_type); + print ''; print $sk->getNomUrl(1); print ''; + print $sk->description; + print ''; + print ''; print displayRankInfos($skillElement->rank, $skillElement->fk_skill, 'TNote', $objecttype == 'job' && $permissiontoadd ? 'edit' : 'view'); print ''; if ($objecttype != 'user' && $permissiontoadd) { + print ''; print 'id . '">'; print img_delete(); print ''; diff --git a/htdocs/langs/en_US/hrm.lang b/htdocs/langs/en_US/hrm.lang index b5a005a07ee..45d1aadbbd3 100644 --- a/htdocs/langs/en_US/hrm.lang +++ b/htdocs/langs/en_US/hrm.lang @@ -48,6 +48,7 @@ ValidateEvaluation=Validate evaluation ConfirmValidateEvaluation=Are you sure you want to validate this evaluation with reference %s? EvaluationCard=Evaluation card RequiredRank=Required rank for this job +EmployeeRank=Employee rank for this skill Position=Position Positions=Positions PositionCard=Position card diff --git a/htdocs/langs/fr_FR/hrm.lang b/htdocs/langs/fr_FR/hrm.lang index 9a2663d6714..f0998719c47 100644 --- a/htdocs/langs/fr_FR/hrm.lang +++ b/htdocs/langs/fr_FR/hrm.lang @@ -59,6 +59,7 @@ ValidateEvaluation=Valider évaluation ConfirmValidateEvaluation=Etes vous sûr(e) de vouloir valider cette évaluation sous la référence %s? EvaluationCard=Fiche évaluation RequiredRank=Note requise pour ce métier +EmployeeRank=Note employé pour cette compétence PositionCard=Fiche poste EmployeesInThisPosition=Salariés occupant ce poste Position=Poste From e8a5a2cc627b8fbb726fea28b1a4d5536e4a0602 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Wed, 29 Sep 2021 06:34:00 +0000 Subject: [PATCH 05/79] Fixing style errors. --- htdocs/hrm/class/evaluation.class.php | 138 ++++++++++---------- htdocs/hrm/class/skill.class.php | 46 +++---- htdocs/hrm/class/skillrank.class.php | 12 +- htdocs/hrm/core/tpl/objectline_view.tpl.php | 12 +- htdocs/hrm/core/tpl/skilldet.fiche.tpl.php | 18 ++- 5 files changed, 111 insertions(+), 115 deletions(-) diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php index 354b909d256..237b4740641 100644 --- a/htdocs/hrm/class/evaluation.class.php +++ b/htdocs/hrm/class/evaluation.class.php @@ -1109,74 +1109,74 @@ class Evaluation extends CommonObject * @param string $action * @param int $selected */ -// public function printObjectLines($action, $selected = 0) -// { -// global $conf, $hookmanager, $langs, $user, $extrafields, $object; -// // TODO We should not use global var for this -// global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax; -// -// // Define usemargins -//// $usemargins = 0; -//// if (!empty($conf->margin->enabled) && !empty($this->element) && in_array($this->element, array('facture', 'facturerec', 'propal', 'commande'))) { -//// $usemargins = 1; -//// } -// -// $num = count($this->lines); -// -// // Line extrafield -// if (!is_object($extrafields)) { -// require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; -// $extrafields = new ExtraFields($this->db); -// } -// $extrafields->fetch_name_optionals_label($this->table_element_line); -// -// $parameters = array('num'=>$num, 'selected'=>$selected, 'table_element_line'=>$this->table_element_line); -// $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks -// if (empty($reshook)) { -// // Output template part (modules that overwrite templates must declare this into descriptor) -// // Note: This is deprecated. If you need to overwrite the tpl file, use instead the hook. -// include dol_buildpath('hrm/core/tpl/objectline_title.tpl.php'); -// } -// -// $i = 0; -// -// print "
    fk_skill > 0) { - - $skill = new Skill($this->db); - $resSkill = $skill->fetch($line->fk_skill); - if ($resSkill > 0) print $skill->getNomUrl(1); - - } +if ($line->fk_skill > 0) { + $skill = new Skill($this->db); + $resSkill = $skill->fetch($line->fk_skill); + if ($resSkill > 0) print $skill->getNomUrl(1); +} ?>
    '; print $sk->getNomUrl(1); print ''; + print $sk->description; print ''; print displayRankInfos($skillElement->rank, $skillElement->fk_skill, 'TNote', $objecttype == 'job' && $permissiontoadd ? 'edit' : 'view'); print 'trans('or'); ?>
    trans('OrJobToCompare') . '' . select_jobs($fk_job, 'fk_job', 1); ?>trans('OrJobToCompare') . ''; + $j = new Job($db); + $jobs = $j->fetchAll(); + $TJobs = array(); + + foreach ($jobs as &$j) { + $TJobs[$j->id] = $j->label; + } + + print $form->selectarray('fk_job', $TJobs, $fk_job, 1); + ?>
    @@ -253,7 +264,7 @@ llxFooter(); * * Return a html list element with diff between required rank and user rank * - * @param $TMergedSkills + * @param array $TMergedSkills skill list with all rate to add good picto * @return string */ function diff(&$TMergedSkills) @@ -282,8 +293,8 @@ function diff(&$TMergedSkills) /** * Return a html list with rank informations - * @param $TMergedSkills - * @param $field + * @param array $TMergedSkills skill list for display + * @param string $field which column of comparison we are working with * @return string */ function rate(&$TMergedSkills, $field) @@ -319,7 +330,7 @@ function rate(&$TMergedSkills, $field) /** * return a html ul list of skills * - * @param $TMergedSkills + * @param array $TMergedSkills skill list for display * @return string (ul list in html ) */ function skillList(&$TMergedSkills) @@ -342,8 +353,8 @@ function skillList(&$TMergedSkills) /** * create an array of lines [ skillLabel,dscription, maxrank on group1 , minrank needed for this skill ] * - * @param $TSkill1 - * @param $TSkill2 + * @param array $TSkill1 skill list of first column + * @param array $TSkill2 skill list of second column * @return array */ function mergeSkills($TSkill1, $TSkill2) @@ -373,9 +384,9 @@ function mergeSkills($TSkill1, $TSkill2) /** * Display a list of User with picto - * @param $TUser - * @param int $fk_usergroup - * @param string $namelist + * @param array $TUser list of users (employees) in selected usergroup of a column + * @param int $fk_usergroup selected usergroup id + * @param string $namelist html name * @return string */ function displayUsersListWithPicto(&$TUser, $fk_usergroup = 0, $namelist = 'list-user') @@ -453,7 +464,7 @@ function displayUsersListWithPicto(&$TUser, $fk_usergroup = 0, $namelist = 'list * * Allow to get skill(s) of a user * - * @param $TUser + * @param array $TUser array of employees we need to get skills * @return array|int */ function getSkillForUsers($TUser) @@ -509,7 +520,7 @@ function getSkillForUsers($TUser) /** * Allow to get skill(s) of a job * - * @param $fk_job + * @param int $fk_job job we need to get required skills * @return array|int */ function getSkillForJob($fk_job) @@ -554,82 +565,3 @@ function getSkillForJob($fk_job) return $Tab; } - -/** - * duplicated with modified data from $form Class - * - * @param string $selected - * @param string $htmlname - * @param int $show_empty - * @param int $disabled - * @param string $enableonly - * @param string $force_entity - * @param false $multiple - * @param string $morecss - * @return string - */ -function select_jobs($selected = '', $htmlname = 'groupid', $show_empty = 0, $disabled = 0, $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '') -{ - // phpcs:enable - global $conf, $user, $langs,$db; - - if (!is_array($selected)) { - $selected = array($selected); - } - $out = ''; - - // On recherche les groupes - $sql = "SELECT j.rowid, j.label as name"; - $sql .= " FROM ".MAIN_DB_PREFIX."hrm_job as j "; - $sql .= " ORDER BY j.label ASC"; - - - $resql = $db->query($sql); - if ($resql) { - include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; - $out .= ajax_combobox($htmlname); - $out .= ''; - } else { - dol_print_error($db); - } - - return $out; -} From e4b4035c05cf67bcbbffcf77e5ba5ff5456a704b Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Thu, 30 Sep 2021 06:47:15 +0000 Subject: [PATCH 08/79] Fixing style errors. --- htdocs/hrm/compare.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php index d89534fa2cc..44462791961 100644 --- a/htdocs/hrm/compare.php +++ b/htdocs/hrm/compare.php @@ -139,12 +139,12 @@ $fk_usergroup1 = GETPOST('fk_usergroup1'); $jobs = $j->fetchAll(); $TJobs = array(); - foreach ($jobs as &$j) { - $TJobs[$j->id] = $j->label; - } + foreach ($jobs as &$j) { + $TJobs[$j->id] = $j->label; + } print $form->selectarray('fk_job', $TJobs, $fk_job, 1); - ?> + ?>
    From 030829942c7035d6c4a4d8b868ccc3265e85f57d Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 30 Sep 2021 13:46:10 +0200 Subject: [PATCH 09/79] FIX : stickler feedbacks part 4 --- htdocs/hrm/lib/hrm_skill.lib.php | 6 ------ htdocs/hrm/lib/hrm_skillrank.lib.php | 10 ++++++++++ htdocs/hrm/position.php | 21 ++++++++------------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/htdocs/hrm/lib/hrm_skill.lib.php b/htdocs/hrm/lib/hrm_skill.lib.php index 7ddaa166a04..a2393229cb5 100644 --- a/htdocs/hrm/lib/hrm_skill.lib.php +++ b/htdocs/hrm/lib/hrm_skill.lib.php @@ -95,12 +95,6 @@ function skillPrepareHead($object) } -//Affichage des 5 trades pour cet object -function showTraductionNote($object) -{ -} - - /** * Show html area for list of traduction * diff --git a/htdocs/hrm/lib/hrm_skillrank.lib.php b/htdocs/hrm/lib/hrm_skillrank.lib.php index e7937001bc2..2aca41504ad 100644 --- a/htdocs/hrm/lib/hrm_skillrank.lib.php +++ b/htdocs/hrm/lib/hrm_skillrank.lib.php @@ -94,6 +94,16 @@ function skillrankPrepareHead($object) return $head; } +/** + * Used to print ranks of a skill into several case, view or edit pour js necessary to select a rank + * + * @param int $selected_rank rank we want to preselect + * @param int $fk_skill id of skill we display ranks + * @param string $inputname html name of input + * @param string $mode view or edit + * + * @return string string result + */ function displayRankInfos($selected_rank, $fk_skill, $inputname = 'TNote', $mode = 'view') { global $db, $conf, $langs; diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index d0eb8159019..17dbef5f25d 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -188,17 +188,16 @@ llxHeader('', $title, $help_url); if ($job->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { DisplayJob($job); - DisplayPositionList($conf, $langs, $db); + DisplayPositionList(); } /** * Show the top of the page including informations of a job * - * @param DoliDB $db Database handler * @param Job $object Job object - * @param $permissiontoadd $permissiontoadd Rights/permissions - * @return array + * + * @return void */ function DisplayJob($object) { @@ -266,16 +265,12 @@ function DisplayJob($object) /** * Show a list of positions for the current job - - * @param Conf $conf Object conf - * @param Translate $langs Object langs - * @param DoliDB $db Database handler - * @param Position $object Position object - * @return array|void + * + * @return void */ -function DisplayPositionList($conf, $langs, $db) +function DisplayPositionList() { - global $user,$langs, $db, $conf, $extrafields, $hookmanager, $permissiontoadd, $permissiontodelete; + global $user, $langs, $db, $conf, $extrafields, $hookmanager, $permissiontoadd, $permissiontodelete; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; @@ -897,7 +892,7 @@ function DisplayPositionList($conf, $langs, $db) print $formfile->showdocuments('massfilesarea_hrm', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); } - return array($arrayfields, $object, $action, $obj, $totalarray); + } // Part to create From 033e7565586072df2626a65a358dccc79168d91f Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Thu, 30 Sep 2021 11:48:42 +0000 Subject: [PATCH 10/79] Fixing style errors. --- htdocs/hrm/position.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index 17dbef5f25d..54e6993ef02 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -892,7 +892,6 @@ function DisplayPositionList() print $formfile->showdocuments('massfilesarea_hrm', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); } - } // Part to create From 53c63fdfe884713f59f272ae30e4bced31613234 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 30 Sep 2021 13:52:31 +0200 Subject: [PATCH 11/79] FIX : stickler feedbacks part 5 --- htdocs/hrm/position_card.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/hrm/position_card.php b/htdocs/hrm/position_card.php index 4538fbc98b2..8cb8ba9de8c 100644 --- a/htdocs/hrm/position_card.php +++ b/htdocs/hrm/position_card.php @@ -229,6 +229,8 @@ DisplayPositionCard($object); * Show the card of a position * * @param Position $object Position object + * + * @return void */ function DisplayPositionCard(&$object) { From d01460d6063ed8c7d288b60d82e93b3d8cc478a7 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 1 Oct 2021 08:06:45 +0200 Subject: [PATCH 12/79] FIX : hrm_position > hrm_job_user + seEventMessage on evaluation close --- htdocs/hrm/class/job.class.php | 2 +- htdocs/hrm/class/position.class.php | 6 +++--- htdocs/hrm/evaluation_card.php | 5 ++++- htdocs/langs/en_US/hrm.lang | 1 + htdocs/langs/fr_FR/hrm.lang | 1 + 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/htdocs/hrm/class/job.class.php b/htdocs/hrm/class/job.class.php index 263f685dc78..23b08e00012 100644 --- a/htdocs/hrm/class/job.class.php +++ b/htdocs/hrm/class/job.class.php @@ -147,7 +147,7 @@ class Job extends CommonObject // /** // * @var array List of child tables. To test if we can delete object. // */ - protected $childtables = array('hrm_evaluation', 'hrm_position'); + protected $childtables = array('hrm_evaluation', 'hrm_job_user'); // /** // * @var array List of child tables. To know object to delete on cascade. diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index e15a15de12d..673840c83d4 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -48,7 +48,7 @@ class Position extends CommonObject /** * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. */ - public $table_element = 'hrm_position'; + public $table_element = 'hrm_job_user'; /** * @var int Does this object support multicompany module ? @@ -144,7 +144,7 @@ class Position extends CommonObject // /** // * @var string Name of subtable line // */ - // public $table_element_line = 'hrm_positionline'; + // public $table_element_line = 'hrm_job_userline'; // /** // * @var string Field with ID of parent key if this object has a parent @@ -166,7 +166,7 @@ class Position extends CommonObject // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object // */ - // protected $childtablesoncascade = array('hrm_positiondet'); + // protected $childtablesoncascade = array('hrm_job_userdet'); // /** // * @var PositionLine[] Array of subtable lines diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 4ae21fef372..5234338212a 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -255,7 +255,10 @@ if (empty($reshook)) { } } } - $object->setStatut(Evaluation::STATUS_CLOSED); + if(empty($errors)) { + $object->setStatut(Evaluation::STATUS_CLOSED); + setEventMessage('EmployeeSkillsUpdated'); + } } if ($action == 'reopen' ) { diff --git a/htdocs/langs/en_US/hrm.lang b/htdocs/langs/en_US/hrm.lang index 45d1aadbbd3..cb6d860bb8c 100644 --- a/htdocs/langs/en_US/hrm.lang +++ b/htdocs/langs/en_US/hrm.lang @@ -41,6 +41,7 @@ SkillHasNoLines=This skill has no lines skill=Skill Skills=Skills SkillCard=Skill card +EmployeeSkillsUpdated=Employee skills have been updated (see "Skills" tab of employee card) Eval=Evaluation Evals=Evaluations NewEval=New evaluation diff --git a/htdocs/langs/fr_FR/hrm.lang b/htdocs/langs/fr_FR/hrm.lang index f0998719c47..c2a787cecb2 100644 --- a/htdocs/langs/fr_FR/hrm.lang +++ b/htdocs/langs/fr_FR/hrm.lang @@ -52,6 +52,7 @@ SkillHasNoLines=Cette compétence n'a pas de notes skill=Compétence Skills=Compétences SkillCard=Fiche compétence +EmployeeSkillsUpdated=Les compétences du salarié ont été mises à jour (voir l'onglet "compétences" de la fiche du salarié) Eval=Evaluation Evals=Evaluations NewEval=Nouvelle evaluation From 753644a024e2dbb8ea7977505632326356a9d952 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Fri, 1 Oct 2021 06:09:45 +0000 Subject: [PATCH 13/79] Fixing style errors. --- htdocs/hrm/evaluation_card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 5234338212a..3d52a2778db 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -255,7 +255,7 @@ if (empty($reshook)) { } } } - if(empty($errors)) { + if (empty($errors)) { $object->setStatut(Evaluation::STATUS_CLOSED); setEventMessage('EmployeeSkillsUpdated'); } From a6c854cb5961009f078ae2e13ba0f55c4d4ea883 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Sun, 3 Oct 2021 12:34:47 +0200 Subject: [PATCH 14/79] FIX : restore link to hrm establishment tab --- htdocs/admin/hrm.php | 2 +- htdocs/hrm/admin/admin_establishment.php | 6 +++--- htdocs/hrm/lib/hrm.lib.php | 10 +++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/htdocs/admin/hrm.php b/htdocs/admin/hrm.php index e520fae2aed..2bcd4977716 100644 --- a/htdocs/admin/hrm.php +++ b/htdocs/admin/hrm.php @@ -191,7 +191,7 @@ if ($action == 'update') { $form = new Form($db); $help_url = ''; -$page_name = "HrmSetup"; +$page_name = "HRMSetup"; llxHeader('', $langs->trans($page_name), $help_url); diff --git a/htdocs/hrm/admin/admin_establishment.php b/htdocs/hrm/admin/admin_establishment.php index f5baeee4027..dd17a2be4b0 100644 --- a/htdocs/hrm/admin/admin_establishment.php +++ b/htdocs/hrm/admin/admin_establishment.php @@ -21,7 +21,7 @@ * \brief HRM Establishment module setup page */ require '../../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/hrm.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/hrm/lib/hrm.lib.php'; require_once DOL_DOCUMENT_ROOT.'/hrm/class/establishment.class.php'; // Load translation files required by the page @@ -80,12 +80,12 @@ $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; // Subheader $linkback = ''.$langs->trans("BackToModuleList").''; -print load_fiche_titre($langs->trans("HRMSetup"), $linkback); +print load_fiche_titre($langs->trans("HRMSetup"), $linkback, 'title_setup'); $newcardbutton = dolGetButtonTitle($langs->trans('NewEstablishment'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/hrm/establishment/card.php?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd); // Configuration header -$head = hrm_admin_prepare_head(); +$head = hrmAdminPrepareHead(); print dol_get_fiche_head($head, 'establishments', $langs->trans("HRM"), -1, "user", 0, $newcardbutton); $sql = "SELECT e.rowid, e.rowid as ref, e.label, e.address, e.zip, e.town, e.status"; diff --git a/htdocs/hrm/lib/hrm.lib.php b/htdocs/hrm/lib/hrm.lib.php index c886b32e7a4..52b1f18d3fc 100644 --- a/htdocs/hrm/lib/hrm.lib.php +++ b/htdocs/hrm/lib/hrm.lib.php @@ -43,6 +43,11 @@ function hrmAdminPrepareHead() $head[$h][2] = 'settings'; $h++; + $head[$h][0] = DOL_URL_ROOT.'/hrm/admin/admin_establishment.php'; + $head[$h][1] = $langs->trans("Establishments"); + $head[$h][2] = 'establishments'; + $h++; + /* $head[$h][0] = dol_buildpath("/workstation/admin/myobject_extrafields.php", 1); $head[$h][1] = $langs->trans("ExtraFields"); @@ -63,7 +68,10 @@ function hrmAdminPrepareHead() //$this->tabs = array( // 'entity:-tabname:Title:@workstation:/workstation/mypage.php?id=__ID__' //); // to remove a tab - complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm'); + complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm_admin'); + + complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm_admin', 'remove'); return $head; } + From 76ec8e0f2515a76ad54b23e36eff34f895ca5aec Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Sun, 3 Oct 2021 10:37:31 +0000 Subject: [PATCH 15/79] Fixing style errors. --- htdocs/hrm/lib/hrm.lib.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/htdocs/hrm/lib/hrm.lib.php b/htdocs/hrm/lib/hrm.lib.php index 52b1f18d3fc..e875f61b9e4 100644 --- a/htdocs/hrm/lib/hrm.lib.php +++ b/htdocs/hrm/lib/hrm.lib.php @@ -43,10 +43,10 @@ function hrmAdminPrepareHead() $head[$h][2] = 'settings'; $h++; - $head[$h][0] = DOL_URL_ROOT.'/hrm/admin/admin_establishment.php'; - $head[$h][1] = $langs->trans("Establishments"); - $head[$h][2] = 'establishments'; - $h++; + $head[$h][0] = DOL_URL_ROOT.'/hrm/admin/admin_establishment.php'; + $head[$h][1] = $langs->trans("Establishments"); + $head[$h][2] = 'establishments'; + $h++; /* $head[$h][0] = dol_buildpath("/workstation/admin/myobject_extrafields.php", 1); @@ -70,8 +70,7 @@ function hrmAdminPrepareHead() //); // to remove a tab complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm_admin'); - complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm_admin', 'remove'); + complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm_admin', 'remove'); return $head; } - From 0dd3681e506fb899e15b75842192c8baf123cd70 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Mon, 4 Oct 2021 14:08:11 +0200 Subject: [PATCH 16/79] FIX : several debug --- htdocs/core/menus/standard/eldy.lib.php | 3 ++- htdocs/hrm/core/tpl/objectline_title.tpl.php | 2 +- htdocs/hrm/evaluation_card.php | 11 ++++++----- htdocs/hrm/position.php | 6 +++++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 091e29ac3c6..2dd0f055344 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1853,7 +1853,7 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM if (!empty($conf->hrm->enabled)) { // Skills - $newmenu->add("/hrm/skill_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("Skill"), 0, $user->rights->hrm->all->read, '', $mainmenu, 'hrm', 0, '', '', '', img_picto('', 'shapes', 'class="pictofixedwidth"')); + $newmenu->add("/hrm/skill_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("skill"), 0, $user->rights->hrm->all->read, '', $mainmenu, 'hrm', 0, '', '', '', img_picto('', 'shapes', 'class="pictofixedwidth"')); $newmenu->add("/hrm/skill_card.php?mainmenu=hrm&leftmenu=hrm&action=create", $langs->trans("NewSkill"), 1, $user->rights->hrm->all->write); $newmenu->add("/hrm/skill_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("List"), 1, $user->rights->hrm->all->read); @@ -1864,6 +1864,7 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM // Position $newmenu->add("/hrm/position_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("Position"), 0, $user->rights->hrm->all->read, '', $mainmenu, 'hrm', 0, '', '', '', img_picto('', 'user-cog', 'class="pictofixedwidth"')); + $newmenu->add("/hrm/position.php?mainmenu=hrm&leftmenu=hrm&action=create", $langs->transnoentities("NewObject", $langs->trans("Position")), 1, $user->rights->hrm->all->write); $newmenu->add("/hrm/position_list.php?mainmenu=hrm&leftmenu=hrm", $langs->trans("List"), 1, $user->rights->hrm->all->read); // Evaluation diff --git a/htdocs/hrm/core/tpl/objectline_title.tpl.php b/htdocs/hrm/core/tpl/objectline_title.tpl.php index f5d72303e42..2630a91ea6f 100644 --- a/htdocs/hrm/core/tpl/objectline_title.tpl.php +++ b/htdocs/hrm/core/tpl/objectline_title.tpl.php @@ -62,7 +62,7 @@ print ''.$langs->trans('Label').''; print ''.$langs->trans('Description').''; // Note -print ''.$langs->trans('Rank').''; +print ''.$langs->trans('rank').''; //print ''; // No width to allow autodim diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 3d52a2778db..156ee79518e 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -282,7 +282,9 @@ $formproject = new FormProjets($db); $title = $langs->trans("Evaluation"); $help_url = ''; -llxHeader('', $title, $help_url); +$css = array(); +$css[] = '/hrm/css/style.css'; +llxHeader('', $title, $help_url, '', 0, 0, '', $css); print ''; diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index 54e6993ef02..1ee06a9209c 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -166,7 +166,11 @@ if (empty($reshook)) { if (empty($fk_job) && (($action != 'add' && $action != 'create') || $cancel)) { $backtopage = $backurlforlist; } else { - $backtopage = dol_buildpath('/hrm/position.php', 1) . '?fk_job=' . ($fk_job > 0 ? $fk_job : '__ID__'); + if($fk_job > 0) { + $backtopage = dol_buildpath('/hrm/position.php', 1) . '?fk_job=' . ($fk_job > 0 ? $fk_job : '__ID__'); + } else { + $backtopage = dol_buildpath('/hrm/position_card.php', 1) . '?id=__ID__'; + } } } } From 35e7a473f4984c2c56f9ec0a91aef7f72ae90434 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 4 Oct 2021 12:10:54 +0000 Subject: [PATCH 17/79] Fixing style errors. --- htdocs/hrm/position.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index 1ee06a9209c..9a3b1e364ff 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -166,7 +166,7 @@ if (empty($reshook)) { if (empty($fk_job) && (($action != 'add' && $action != 'create') || $cancel)) { $backtopage = $backurlforlist; } else { - if($fk_job > 0) { + if ($fk_job > 0) { $backtopage = dol_buildpath('/hrm/position.php', 1) . '?fk_job=' . ($fk_job > 0 ? $fk_job : '__ID__'); } else { $backtopage = dol_buildpath('/hrm/position_card.php', 1) . '?id=__ID__'; From 5d179beaac8a1065a3a52eb9fc32586d3a85ac54 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Tue, 5 Oct 2021 11:14:08 +0200 Subject: [PATCH 18/79] FIX : several fixes + travis --- htdocs/hrm/class/evaluation.class.php | 13 +++--- htdocs/hrm/compare.php | 3 +- htdocs/hrm/evaluation_card.php | 8 ++-- htdocs/hrm/job_card.php | 2 +- htdocs/hrm/position.php | 2 +- htdocs/hrm/skill_card.php | 2 +- htdocs/hrm/skill_tab.php | 60 ++++++++++++++++----------- htdocs/langs/en_US/hrm.lang | 2 +- htdocs/langs/fr_FR/hrm.lang | 2 +- 9 files changed, 51 insertions(+), 43 deletions(-) diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php index 237b4740641..ae30c900338 100644 --- a/htdocs/hrm/class/evaluation.class.php +++ b/htdocs/hrm/class/evaluation.class.php @@ -659,24 +659,21 @@ class Evaluation extends CommonObject * @param int $fk_user ID of user we need to get last eval * @return Evaluation|null */ - public static function getLastEvaluationForUser($fk_user) + public function getLastEvaluationForUser($fk_user) { - global $db; - - $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."hrm_evaluation "; $sql.= "WHERE fk_user=".$fk_user." "; $sql.= "ORDER BY date_eval DESC "; $sql.= "LIMIT 1 "; - $res = $db->query($sql); - if (!$res) { dol_print_error($db);} + $res = $this->db->query($sql); + if (!$res) { dol_print_error($this->db);} - $Tab = $db->fetch_object($res); + $Tab = $this->db->fetch_object($res); if (empty($Tab)) return null; else { - $evaluation = new Evaluation($db); + $evaluation = new Evaluation($this->db); $evaluation->fetch($Tab->rowid); return $evaluation; diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php index 44462791961..f47eec79997 100644 --- a/htdocs/hrm/compare.php +++ b/htdocs/hrm/compare.php @@ -436,7 +436,8 @@ function displayUsersListWithPicto(&$TUser, $fk_usergroup = 0, $namelist = 'list $job = Job::getLastJobForUser($user->id); $desc .= $job; - $evaluation = Evaluation::getLastEvaluationForUser($user->id); + $static_eval = new Evaluation($db); + $evaluation = $static_eval->getLastEvaluationForUser($user->id); if (!empty($evaluation) && !empty($evaluation->date_eval)) { $desc .= $langs->trans('DateLastEval') . ' : ' . dol_print_date($evaluation->date_eval); diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 156ee79518e..172956fc379 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -88,7 +88,7 @@ require_once DOL_DOCUMENT_ROOT.'/hrm/lib/hrm_skillrank.lib.php'; require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; // Load translation files required by the page -$langs->loadLangs(array("hrm", "other")); +$langs->loadLangs(array("hrm", "other", 'products')); // Get parameters $id = GETPOST('id', 'int'); @@ -540,7 +540,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if ($object->status == $object::STATUS_DRAFT && $permissiontoadd) { print '
    '; - print ''; + print ''; print '
    '; } } @@ -579,14 +579,14 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } if ($object->status == $object::STATUS_CLOSED) { - print dolGetButtonAction($langs->trans('reopen'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken(), '', $permissiontoadd); + print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken(), '', $permissiontoadd); } // Validate if ($object->status == $object::STATUS_DRAFT) { if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) { - print dolGetButtonAction($langs->trans('SaveRank').' '.$langs->trans('and').' '.$langs->trans('Valid'), '', 'default', '#', 'btn_valid', $permissiontovalidate); + print dolGetButtonAction($langs->trans('Save').' '.$langs->trans('and').' '.$langs->trans('Valid'), '', 'default', '#', 'btn_valid', $permissiontovalidate); } else { $langs->load("errors"); print dolGetButtonAction($langs->trans("ErrorAddAtLeastOneLineFirst"), $langs->trans("Validate"), 'default', '#', '', 0); diff --git a/htdocs/hrm/job_card.php b/htdocs/hrm/job_card.php index 8cb8d0fceee..728c288d6cc 100644 --- a/htdocs/hrm/job_card.php +++ b/htdocs/hrm/job_card.php @@ -88,7 +88,7 @@ dol_include_once('/hrm/class/job.class.php'); dol_include_once('/hrm/lib/hrm_job.lib.php'); // Load translation files required by the page -$langs->loadLangs(array("hrm", "other")); +$langs->loadLangs(array("hrm", "other", 'products')); // Get parameters $id = GETPOST('id', 'int'); diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index 9a3b1e364ff..7fc5cc777b6 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -184,7 +184,7 @@ if (empty($reshook)) { } // Load translation files required by the page -$langs->loadLangs(array("hrm", "other")); +$langs->loadLangs(array("hrm", "other", 'products')); $title = $langs->trans("Position"); $help_url = ''; diff --git a/htdocs/hrm/skill_card.php b/htdocs/hrm/skill_card.php index 12602a46c0a..e3dbf63e160 100644 --- a/htdocs/hrm/skill_card.php +++ b/htdocs/hrm/skill_card.php @@ -89,7 +89,7 @@ dol_include_once('/hrm/lib/hrm_skill.lib.php'); // Load translation files required by the page -$langs->loadLangs(array("hrm", "other")); +$langs->loadLangs(array("hrm", "other", 'products')); // Get parameters $id = GETPOST('id', 'int'); diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php index ae5ee4371a0..4694d27679a 100644 --- a/htdocs/hrm/skill_tab.php +++ b/htdocs/hrm/skill_tab.php @@ -93,7 +93,7 @@ dol_include_once('/hrm/lib/hrm_skill.lib.php'); $langs->loadLangs(array("hrm", "other")); $id = GETPOST('id', 'int'); -$fk_skill = GETPOST('fk_skill', 'int'); +$TSkillsToAdd = GETPOST('fk_skill', 'array'); $objecttype = GETPOST('objecttype', 'alpha'); $TNote = GETPOST('TNote', 'array'); $lineid = GETPOST('lineid', 'int'); @@ -159,19 +159,21 @@ if (empty($reshook)) { if ($action == 'addSkill') { $error = 0; - if ($fk_skill <= 0) { + if (empty($TSkillsToAdd)) { setEventMessage('ErrNoSkillSelected', 'errors'); $error++; } if (!$error) { - $skillAdded = new SkillRank($db); - $skillAdded->fk_skill = $fk_skill; - $skillAdded->fk_object = $id; - $skillAdded->objecttype = $objecttype; - $ret = $skillAdded->create($user); - if ($ret < 0) setEventMessage($skillAdded->error, 'errors'); - else unset($fk_skill); + foreach ($TSkillsToAdd as $k=>$v) { + $skillAdded = new SkillRank($db); + $skillAdded->fk_skill = $v; + $skillAdded->fk_object = $id; + $skillAdded->objecttype = $objecttype; + $ret = $skillAdded->create($user); + if ($ret < 0) setEventMessage($skillAdded->error, 'errors'); + //else unset($TSkillsToAdd); + } } } else if ($action == 'saveSkill') { if (!empty($TNote)) { @@ -268,15 +270,27 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'rowid', $morehtmlref, '&objecttype='.$objecttype); - // table of skillRank linked to current object - $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . ' AND objecttype="' . $objecttype . '"')); + // Get all available skills + $static_skill = new Skill($db); + $TAllSkills = $static_skill->fetchAll(); -// $TAlreadyUsedSkill = array(); -// if (is_array($TSkills) && !empty($TSkills)) { -// foreach ($TSkills as $skillElement) { -// $TAlreadyUsedSkill[] = $skillElement->fk_skill; -// } -// } + // Array format for multiselectarray function + $TAllSkillsFormatted=array(); + if(!empty($TAllSkills)) { + foreach ($TAllSkills as $k=>$v) { + $TAllSkillsFormatted[$k] = $v->label; + } + } + + // table of skillRank linked to current object + $TSkillsJob = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . ' AND objecttype="' . $objecttype . '"')); + + $TAlreadyUsedSkill = array(); + if (is_array($TSkillsJob) && !empty($TSkillsJob)) { + foreach ($TSkillsJob as $skillElement) { + $TAlreadyUsedSkill[$skillElement->fk_skill] = $skillElement->fk_skill; + } + } print '
    '; print '
    '; @@ -298,13 +312,9 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; print '
    '; print ''; - print ''; + print ''; print ''; - foreach ($skill->fields as $key => $infos) { - if ($key == 'fk_skill') { - print ''; - } - } + print ''; print ''; print ''; print '
    ' . $langs->trans('AddSkill') . '
    ' . $langs->trans('AddSkill') . '
    ' . $skill->showInputField($infos, $key, $$key) . '' . $form->multiselectarray('fk_skill', array_diff_key($TAllSkillsFormatted, $TAlreadyUsedSkill), array(), 0, 0, '', 0, '100%') . '
    '; @@ -335,11 +345,11 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; } print ''; - if (!is_array($TSkills) || empty($TSkills)) { + if (!is_array($TSkillsJob) || empty($TSkillsJob)) { print '' . $langs->trans("NoRecordFound") . ''; } else { $sk = new Skill($db); - foreach ($TSkills as $skillElement) { + foreach ($TSkillsJob as $skillElement) { $sk->fetch($skillElement->fk_skill); print ''; print ''; diff --git a/htdocs/langs/en_US/hrm.lang b/htdocs/langs/en_US/hrm.lang index cb6d860bb8c..6a578aab50d 100644 --- a/htdocs/langs/en_US/hrm.lang +++ b/htdocs/langs/en_US/hrm.lang @@ -65,7 +65,7 @@ MaxLevelLowerThan= Max level lower than that demand SkillNotAcquired=Skill not acquired by all users and requested by the second comparator legend=Legend TypeSkill=Skill type -AddSkill=Add skill to job +AddSkill=Add skills to job RequiredSkills=Required skills for this job UserRank=User Rank SkillList=Skill list diff --git a/htdocs/langs/fr_FR/hrm.lang b/htdocs/langs/fr_FR/hrm.lang index c2a787cecb2..ceb86bab497 100644 --- a/htdocs/langs/fr_FR/hrm.lang +++ b/htdocs/langs/fr_FR/hrm.lang @@ -76,7 +76,7 @@ MaxLevelLowerThan= Niveau maximal inférieur au niveau requis SkillNotAcquired=Compétence non acquise par tous les utilisateur et requise par le second élément de comparaison legend=Légende TypeSkill=Type de compétence -AddSkill=Ajouter une compétence à ce métier +AddSkill=Ajouter des compétences à ce métier RequiredSkills=Compétences requises pour ce métier UserRank=Note utilisateur SkillList=Liste des compétences From 75c750292220a32661c1268a824e9d90563bc130 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Tue, 5 Oct 2021 11:35:00 +0200 Subject: [PATCH 19/79] FIX : useless dol_include_once + travis feedback --- htdocs/hrm/class/evaluation.class.php | 8 ++++---- htdocs/hrm/class/evaluationdet.class.php | 2 +- htdocs/hrm/class/skillrank.class.php | 2 +- htdocs/hrm/compare.php | 10 +++++----- htdocs/hrm/evaluation_contact.php | 4 ++-- htdocs/hrm/job_agenda.php | 4 ++-- htdocs/hrm/job_card.php | 4 ++-- htdocs/hrm/job_contact.php | 4 ++-- htdocs/hrm/job_document.php | 4 ++-- htdocs/hrm/job_note.php | 4 ++-- htdocs/hrm/position.php | 8 ++++---- htdocs/hrm/position_contact.php | 4 ++-- htdocs/hrm/skill_agenda.php | 4 ++-- htdocs/hrm/skill_card.php | 4 ++-- htdocs/hrm/skill_contact.php | 4 ++-- htdocs/hrm/skill_document.php | 4 ++-- htdocs/hrm/skill_note.php | 4 ++-- htdocs/hrm/skill_tab.php | 10 +++++----- 18 files changed, 44 insertions(+), 44 deletions(-) diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php index ae30c900338..b76d291cad1 100644 --- a/htdocs/hrm/class/evaluation.class.php +++ b/htdocs/hrm/class/evaluation.class.php @@ -26,8 +26,8 @@ */ // Put here all includes required by your class file -require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; -dol_include_once('hrm/class/evaluationdet.class.php'); +require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/evaluationdet.class.php'; //require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; @@ -226,7 +226,7 @@ class Evaluation extends CommonObject $resultcreate = $this->createCommon($user, $notrigger); if ($resultcreate > 0) { - dol_include_once('hrm/class/skillrank.class.php'); + require_once DOL_DOCUMENT_ROOT . '/hrm/class/skillrank.class.php'; $skillRank = new SkillRank($this->db); $TRequiredRanks = $skillRank->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object='.$this->fk_job.' AND objecttype="job"')); @@ -662,7 +662,7 @@ class Evaluation extends CommonObject public function getLastEvaluationForUser($fk_user) { $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."hrm_evaluation "; - $sql.= "WHERE fk_user=".$fk_user." "; + $sql.= "WHERE fk_user=".((int)$fk_user)." "; $sql.= "ORDER BY date_eval DESC "; $sql.= "LIMIT 1 "; diff --git a/htdocs/hrm/class/evaluationdet.class.php b/htdocs/hrm/class/evaluationdet.class.php index 0c591a3a374..aaea72b645e 100644 --- a/htdocs/hrm/class/evaluationdet.class.php +++ b/htdocs/hrm/class/evaluationdet.class.php @@ -27,7 +27,7 @@ // Put here all includes required by your class file require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; -dol_include_once('hrm/class/skillrank.class.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/skillrank.class.php'; //require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index e6f63bb7d68..b6242527178 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -27,7 +27,7 @@ // Put here all includes required by your class file require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; -dol_include_once('hrm/lib/hrm_skillrank.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_skillrank.lib.php'; /** * Class for SkillRank diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php index f47eec79997..af41e1bdca1 100644 --- a/htdocs/hrm/compare.php +++ b/htdocs/hrm/compare.php @@ -39,11 +39,11 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; ini_set('display_errors', 1); -dol_include_once('/hrm/class/skill.class.php'); -dol_include_once('/hrm/class/job.class.php'); -dol_include_once('/hrm/class/evaluation.class.php'); -dol_include_once('/hrm/class/position.class.php'); -dol_include_once('/hrm/lib/hrm.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/evaluation.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/position.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm.lib.php'; $permissiontoread = $user->rights->hrm->compare->read; if (empty($conf->hrm->enabled)) accessforbidden(); diff --git a/htdocs/hrm/evaluation_contact.php b/htdocs/hrm/evaluation_contact.php index db6d93f7ef7..540154b77ef 100644 --- a/htdocs/hrm/evaluation_contact.php +++ b/htdocs/hrm/evaluation_contact.php @@ -58,8 +58,8 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; -dol_include_once('/hrm/class/evaluation.class.php'); -dol_include_once('/hrm/lib/hrm_evaluation.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/evaluation.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_evaluation.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "companies", "other", "mails")); diff --git a/htdocs/hrm/job_agenda.php b/htdocs/hrm/job_agenda.php index b6fbd6aee82..77dd464a7f0 100644 --- a/htdocs/hrm/job_agenda.php +++ b/htdocs/hrm/job_agenda.php @@ -80,8 +80,8 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; -dol_include_once('/hrm/class/job.class.php'); -dol_include_once('/hrm/lib/hrm_job.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_job.lib.php'; // Load translation files required by the page diff --git a/htdocs/hrm/job_card.php b/htdocs/hrm/job_card.php index 728c288d6cc..19b40048f7b 100644 --- a/htdocs/hrm/job_card.php +++ b/htdocs/hrm/job_card.php @@ -84,8 +84,8 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; -dol_include_once('/hrm/class/job.class.php'); -dol_include_once('/hrm/lib/hrm_job.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_job.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "other", 'products')); diff --git a/htdocs/hrm/job_contact.php b/htdocs/hrm/job_contact.php index 471f5c63886..cbc961d3f9e 100644 --- a/htdocs/hrm/job_contact.php +++ b/htdocs/hrm/job_contact.php @@ -58,8 +58,8 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; -dol_include_once('/hrm/class/job.class.php'); -dol_include_once('/hrm/lib/hrm_job.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_job.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "companies", "other", "mails")); diff --git a/htdocs/hrm/job_document.php b/htdocs/hrm/job_document.php index c8cd764b9de..a32f02915e9 100644 --- a/htdocs/hrm/job_document.php +++ b/htdocs/hrm/job_document.php @@ -81,8 +81,8 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; -dol_include_once('/hrm/class/job.class.php'); -dol_include_once('/hrm/lib/hrm_job.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_job.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "companies", "other", "mails")); diff --git a/htdocs/hrm/job_note.php b/htdocs/hrm/job_note.php index 3f63e50b9a6..85a1cd1dc84 100644 --- a/htdocs/hrm/job_note.php +++ b/htdocs/hrm/job_note.php @@ -77,8 +77,8 @@ if (!$res) { die("Include of main fails"); } -dol_include_once('/hrm/class/job.class.php'); -dol_include_once('/hrm/lib/hrm_job.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_job.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "companies")); diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index 7fc5cc777b6..0fcc817c8c9 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -84,10 +84,10 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; -dol_include_once('/hrm/class/position.class.php'); -dol_include_once('/hrm/class/job.class.php'); -dol_include_once('/hrm/lib/hrm_position.lib.php'); -dol_include_once('/hrm/lib/hrm_job.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/position.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_position.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_job.lib.php'; $action = GETPOST('action', 'aZ09') ? GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... $backtopage = GETPOST('backtopage', 'alpha'); diff --git a/htdocs/hrm/position_contact.php b/htdocs/hrm/position_contact.php index 76ec4f0b349..56a4fc8ff8f 100644 --- a/htdocs/hrm/position_contact.php +++ b/htdocs/hrm/position_contact.php @@ -58,8 +58,8 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; -dol_include_once('/hrm/class/position.class.php'); -dol_include_once('/hrm/lib/hrm_position.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/position.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_position.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "companies", "other", "mails")); diff --git a/htdocs/hrm/skill_agenda.php b/htdocs/hrm/skill_agenda.php index 7fbcfe78369..0b854ccb028 100644 --- a/htdocs/hrm/skill_agenda.php +++ b/htdocs/hrm/skill_agenda.php @@ -80,8 +80,8 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; -dol_include_once('/hrm/class/skill.class.php'); -dol_include_once('/hrm/lib/hrm_skill.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_skill.lib.php'; // Load translation files required by the page diff --git a/htdocs/hrm/skill_card.php b/htdocs/hrm/skill_card.php index e3dbf63e160..7d45ab152a0 100644 --- a/htdocs/hrm/skill_card.php +++ b/htdocs/hrm/skill_card.php @@ -84,8 +84,8 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; -dol_include_once('/hrm/class/skill.class.php'); -dol_include_once('/hrm/lib/hrm_skill.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_skill.lib.php'; // Load translation files required by the page diff --git a/htdocs/hrm/skill_contact.php b/htdocs/hrm/skill_contact.php index 11ff55e8588..a535e00696b 100644 --- a/htdocs/hrm/skill_contact.php +++ b/htdocs/hrm/skill_contact.php @@ -58,8 +58,8 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; -dol_include_once('/hrm/class/skill.class.php'); -dol_include_once('/hrm/lib/hrm_skill.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_skill.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "companies", "other", "mails")); diff --git a/htdocs/hrm/skill_document.php b/htdocs/hrm/skill_document.php index 4e15c2acb9f..ca13044f712 100644 --- a/htdocs/hrm/skill_document.php +++ b/htdocs/hrm/skill_document.php @@ -81,8 +81,8 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; -dol_include_once('/hrm/class/skill.class.php'); -dol_include_once('/hrm/lib/hrm_skill.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_skill.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "companies", "other", "mails")); diff --git a/htdocs/hrm/skill_note.php b/htdocs/hrm/skill_note.php index 564561e7c75..000c5e1b41b 100644 --- a/htdocs/hrm/skill_note.php +++ b/htdocs/hrm/skill_note.php @@ -77,8 +77,8 @@ if (!$res) { die("Include of main fails"); } -dol_include_once('/hrm/class/skill.class.php'); -dol_include_once('/hrm/lib/hrm_skill.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_skill.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "companies")); diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php index 4694d27679a..4ecbc6439be 100644 --- a/htdocs/hrm/skill_tab.php +++ b/htdocs/hrm/skill_tab.php @@ -85,9 +85,9 @@ require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php'; -dol_include_once('/hrm/class/skill.class.php'); -dol_include_once('/hrm/class/skillrank.class.php'); -dol_include_once('/hrm/lib/hrm_skill.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/hrm/class/skill.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/class/skillrank.class.php'; +require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_skill.lib.php'; // Load translation files required by the page $langs->loadLangs(array("hrm", "other")); @@ -110,7 +110,7 @@ $skill = new SkillRank($db); // Initialize technical objects if (in_array($objecttype, $TAuthorizedObjects)) { if ($objecttype == 'job') { - dol_include_once('/hrm/class/job.class.php'); + require_once DOL_DOCUMENT_ROOT . '/hrm/class/job.class.php'; $object = new Job($db); } else if ($objecttype == "user") { $object = new User($db); @@ -217,7 +217,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // view configuration if ($objecttype == 'job') { - dol_include_once('/hrm/lib/hrm_job.lib.php'); + require_once DOL_DOCUMENT_ROOT . '/hrm/lib/hrm_job.lib.php'; $head = jobPrepareHead($object); $listLink = dol_buildpath('/hrm/job_list.php', 1); } else if ($objecttype == "user") { From 6c82b1d0e1bd57e65e4f2c4e426c566ba10df51d Mon Sep 17 00:00:00 2001 From: Indelog Date: Tue, 5 Oct 2021 11:18:42 +0200 Subject: [PATCH 20/79] Fix creataing invoice originating for custom module This fix the invoice create form when we provide `origin` element in url. The actual create form overide the value for origin field with `$objectsrc->element`. This make creation of invoice originating from a custom module module impossible because we need the module part to instantiate the class for the custom module object. This also modify Common Object::fetch Object Linked() to append the module part for `$sourcetype` and `$targettype` if it not set and object have module property and it not in core module. --- htdocs/compta/facture/card.php | 6 ++++-- htdocs/core/class/commonobject.class.php | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 6ea03d8bd23..1e2eb0bd8bb 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -3730,8 +3730,10 @@ if ($action == 'create') { print ''."\n"; print ''."\n"; print ''."\n"; - print ''; - print ''; + // The lines below override the parameters set by GET or POST for origin value and also be present in $origin and $originid variables (it make creation of invoice originating from an external module object impossible because for get an external module class we also need to know the name of the module in addition of the name of the element). + // This input fields already printed above at the
    begin. + //print ''; + //print ''; switch (get_class($objectsrc)) { case 'Propal': diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index ab258d736ff..c4564ddcd6d 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3708,10 +3708,23 @@ abstract class CommonObject } } + // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. + // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. + $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization'); + $sourceid = (!empty($sourceid) ? $sourceid : $this->id); $targetid = (!empty($targetid) ? $targetid : $this->id); - $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element); - $targettype = (!empty($targettype) ? $targettype : $this->element); + // For module whit + if (empty($sourcetype)) { + // If empty $sourcetype and no core module, add module part for searching element in llx_element_element (needed for external module). + if (!empty($this->module) && ! in_array($this->module, $coremodule)) $sourcetype = $this->module.'_'.$this->element; + else $sourcetype = $this->element; + } + if (empty($targettype)) { + // If empty $targettype and no core module, add module part for searching element in llx_element_element (needed for external module). + if (!empty($this->module) && ! in_array($this->module, $coremodule)) $targettype = $this->module.'_'.$this->element; + else $targettype = $this->element; + } /*if (empty($sourceid) && empty($targetid)) { From 75182f40a024ccefe7505eb6b5b8ef0abb534a94 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 5 Oct 2021 09:37:38 +0000 Subject: [PATCH 21/79] Fixing style errors. --- htdocs/hrm/class/evaluation.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php index b76d291cad1..35b46550b00 100644 --- a/htdocs/hrm/class/evaluation.class.php +++ b/htdocs/hrm/class/evaluation.class.php @@ -662,7 +662,7 @@ class Evaluation extends CommonObject public function getLastEvaluationForUser($fk_user) { $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."hrm_evaluation "; - $sql.= "WHERE fk_user=".((int)$fk_user)." "; + $sql.= "WHERE fk_user=".((int) $fk_user)." "; $sql.= "ORDER BY date_eval DESC "; $sql.= "LIMIT 1 "; From 39cc2ca5b6142252e5bf942f0ab40f2caaa74c96 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 5 Oct 2021 09:42:52 +0000 Subject: [PATCH 22/79] Fixing style errors. --- htdocs/compta/facture/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 1e2eb0bd8bb..0eb2a503e42 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -3731,7 +3731,7 @@ if ($action == 'create') { print ''."\n"; print ''."\n"; // The lines below override the parameters set by GET or POST for origin value and also be present in $origin and $originid variables (it make creation of invoice originating from an external module object impossible because for get an external module class we also need to know the name of the module in addition of the name of the element). - // This input fields already printed above at the begin. + // This input fields already printed above at the begin. //print ''; //print ''; From bea17e8d78fe22736a100aceedd23e46d190a7c8 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Tue, 5 Oct 2021 12:42:42 +0200 Subject: [PATCH 23/79] FIX : travis + User::hasRight() function modification to take care of hrm specific rights --- htdocs/hrm/class/evaluation.class.php | 52 +++--------------- htdocs/hrm/class/evaluationdet.class.php | 70 ++++++++---------------- htdocs/user/class/user.class.php | 5 +- 3 files changed, 36 insertions(+), 91 deletions(-) diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php index b76d291cad1..f0af0ed1251 100644 --- a/htdocs/hrm/class/evaluation.class.php +++ b/htdocs/hrm/class/evaluation.class.php @@ -71,7 +71,7 @@ class Evaluation extends CommonObject const STATUS_DRAFT = 0; const STATUS_VALIDATED = 1; const STATUS_CANCELED = 9; - const STATUS_CLOSED = 2; + const STATUS_CLOSED = 6; /** @@ -107,7 +107,7 @@ class Evaluation extends CommonObject public $fields=array( 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"), 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>4, 'noteditable'=>'1', 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'showoncombobox'=>'1', 'comment'=>"Reference of object"), - 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1, 'searchall'=>1, 'css'=>'minwidth300', 'cssview'=>'wordbreak', 'showoncombobox'=>'2',), + 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>'1', 'position'=>30, 'notnull'=>0, 'visible'=>1, 'searchall'=>1, 'css'=>'minwidth300', 'cssview'=>'wordbreak', 'showoncombobox'=>'2',), 'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>'1', 'position'=>60, 'notnull'=>0, 'visible'=>3,), 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>61, 'notnull'=>0, 'visible'=>0,), 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>'1', 'position'=>62, 'notnull'=>0, 'visible'=>0,), @@ -154,7 +154,7 @@ class Evaluation extends CommonObject /** * @var string Name of subtable class that manage subtable lines */ - public $class_element_line = 'Evaluationdet'; + public $class_element_line = 'Evaluationline'; // /** // * @var array List of child tables. To test if we can delete object. @@ -166,10 +166,10 @@ class Evaluation extends CommonObject // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object // */ - protected $childtablesoncascade = array('@Evaluationdet:hrm/class/evaluationdet.class.php:fk_evaluation'); + protected $childtablesoncascade = array('@Evaluationline:hrm/class/evaluationdet.class.php:fk_evaluation'); /** - * @var Evaluationdet[] Array of subtable lines + * @var Evaluationline[] Array of subtable lines */ public $lines = array(); @@ -233,7 +233,7 @@ class Evaluation extends CommonObject if (is_array($TRequiredRanks) && !empty($TRequiredRanks)) { $this->lines = array(); foreach ($TRequiredRanks as $required) { - $line = new Evaluationdet($this->db); + $line = new Evaluationline($this->db); $line->fk_evaluation = $resultcreate; $line->fk_skill = $required->fk_skill; $line->required_rank = $required->rank; @@ -372,42 +372,8 @@ class Evaluation extends CommonObject { $this->lines = array(); - $objectlineclassname = get_class($this).'det'; - if (!class_exists($objectlineclassname)) { - $this->error = 'Error, class '.$objectlineclassname.' not found during call of fetchLinesCommon'; - return -1; - } - - $objectline = new $objectlineclassname($this->db); - - $sql = 'SELECT '.$objectline->getFieldList('l'); - $sql .= ' FROM '.MAIN_DB_PREFIX.$objectline->table_element.' as l'; - $sql .= ' WHERE l.fk_'.$this->element.' = '.$this->id; - if (isset($objectline->fields['position'])) { - $sql .= $this->db->order('position', 'ASC'); - } - - $resql = $this->db->query($sql); - if ($resql) { - $num_rows = $this->db->num_rows($resql); - $i = 0; - while ($i < $num_rows) { - $obj = $this->db->fetch_object($resql); - if ($obj) { - $newline = new $objectlineclassname($this->db); - $newline->setVarsFromFetchObj($obj); - - $this->lines[] = $newline; - } - $i++; - } - - return 1; - } else { - $this->error = $this->db->lasterror(); - $this->errors[] = $this->error; - return -1; - } + $result = $this->fetchLinesCommon(); + return $result; } @@ -965,7 +931,7 @@ class Evaluation extends CommonObject { $this->lines = array(); - $objectline = new Evaluationdet($this->db); + $objectline = new Evaluationline($this->db); $result = $objectline->fetchAll('ASC', '', 0, 0, array('customsql'=>'fk_evaluation = '.$this->id)); if (is_numeric($result)) { diff --git a/htdocs/hrm/class/evaluationdet.class.php b/htdocs/hrm/class/evaluationdet.class.php index aaea72b645e..0608f14dbe9 100644 --- a/htdocs/hrm/class/evaluationdet.class.php +++ b/htdocs/hrm/class/evaluationdet.class.php @@ -32,9 +32,9 @@ require_once DOL_DOCUMENT_ROOT . '/hrm/class/skillrank.class.php'; //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; /** - * Class for Evaluationdet + * Class for Evaluationline */ -class Evaluationdet extends CommonObject +class Evaluationline extends CommonObject { /** * @var string ID of module. @@ -133,7 +133,7 @@ class Evaluationdet extends CommonObject // /** // * @var string Name of subtable line // */ - // public $table_element_line = 'hrm_evaluationdetline'; + // public $table_element_line = 'hrm_evaluationline'; // /** // * @var string Field with ID of parent key if this object has a parent @@ -143,7 +143,7 @@ class Evaluationdet extends CommonObject // /** // * @var string Name of subtable class that manage subtable lines // */ - // public $class_element_line = 'Evaluationdetline'; + // public $class_element_line = 'Evaluationline'; // /** // * @var array List of child tables. To test if we can delete object. @@ -158,7 +158,7 @@ class Evaluationdet extends CommonObject // protected $childtablesoncascade = array('hrm_evaluationdetdet'); // /** - // * @var EvaluationdetLine[] Array of subtable lines + // * @var EvaluationLine[] Array of subtable lines // */ // public $lines = array(); @@ -543,7 +543,7 @@ class Evaluationdet extends CommonObject if (!$error && !$notrigger) { // Call trigger - $result = $this->call_trigger('EVALUATIONDET_VALIDATE', $user); + $result = $this->call_trigger('EVALUATIONLINE_VALIDATE', $user); if ($result < 0) { $error++; } @@ -557,8 +557,8 @@ class Evaluationdet extends CommonObject // Rename directory if dir was a temporary ref if (preg_match('/^[\(]?PROV/i', $this->ref)) { // Now we rename also files into index - $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'evaluationdet/".$this->db->escape($this->newref)."'"; - $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'evaluationdet/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'evaluationline/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'evaluationline/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; $resql = $this->db->query($sql); if (!$resql) { $error++; $this->error = $this->db->lasterror(); @@ -567,15 +567,15 @@ class Evaluationdet extends CommonObject // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments $oldref = dol_sanitizeFileName($this->ref); $newref = dol_sanitizeFileName($num); - $dirsource = $conf->hrm->dir_output.'/evaluationdet/'.$oldref; - $dirdest = $conf->hrm->dir_output.'/evaluationdet/'.$newref; + $dirsource = $conf->hrm->dir_output.'/evaluationline/'.$oldref; + $dirdest = $conf->hrm->dir_output.'/evaluationline/'.$newref; if (!$error && file_exists($dirsource)) { dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); if (@rename($dirsource, $dirdest)) { dol_syslog("Rename ok"); // Rename docs starting with $oldref with $newref - $listoffiles = dol_dir_list($conf->hrm->dir_output.'/evaluationdet/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); + $listoffiles = dol_dir_list($conf->hrm->dir_output.'/evaluationline/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); foreach ($listoffiles as $fileentry) { $dirsource = $fileentry['name']; $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); @@ -625,7 +625,7 @@ class Evaluationdet extends CommonObject return -1; }*/ - return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'EVALUATIONDET_UNVALIDATE'); + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'EVALUATIONLINE_UNVALIDATE'); } /** @@ -649,7 +649,7 @@ class Evaluationdet extends CommonObject return -1; }*/ - return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'EVALUATIONDET_CANCEL'); + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'EVALUATIONLINE_CANCEL'); } /** @@ -673,7 +673,7 @@ class Evaluationdet extends CommonObject return -1; }*/ - return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'EVALUATIONDET_REOPEN'); + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'EVALUATIONLINE_REOPEN'); } /** @@ -779,7 +779,7 @@ class Evaluationdet extends CommonObject //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); global $action, $hookmanager; - $hookmanager->initHooks(array('evaluationdetdao')); + $hookmanager->initHooks(array('evaluationlinedao')); $parameters = array('id'=>$this->id, 'getnomurl'=>$result); $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks if ($reshook > 0) { @@ -903,7 +903,7 @@ class Evaluationdet extends CommonObject { $this->lines = array(); - $objectline = new EvaluationdetLine($this->db); + $objectline = new EvaluationLine($this->db); $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_evaluationdet = '.$this->id)); if (is_numeric($result)) { @@ -926,15 +926,15 @@ class Evaluationdet extends CommonObject global $langs, $conf; $langs->load("hrm"); - if (empty($conf->global->hrm_EVALUATIONDET_ADDON)) { - $conf->global->hrm_EVALUATIONDET_ADDON = 'mod_evaluationdet_standard'; + if (empty($conf->global->hrm_EVALUATIONLINE_ADDON)) { + $conf->global->hrm_EVALUATIONLINE_ADDON = 'mod_evaluationdet_standard'; } - if (!empty($conf->global->hrm_EVALUATIONDET_ADDON)) { + if (!empty($conf->global->hrm_EVALUATIONLINE_ADDON)) { $mybool = false; - $file = $conf->global->hrm_EVALUATIONDET_ADDON.".php"; - $classname = $conf->global->hrm_EVALUATIONDET_ADDON; + $file = $conf->global->hrm_EVALUATIONLINE_ADDON.".php"; + $classname = $conf->global->hrm_EVALUATIONLINE_ADDON; // Include file with class $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); @@ -996,8 +996,8 @@ class Evaluationdet extends CommonObject if (!empty($this->model_pdf)) { $modele = $this->model_pdf; - } elseif (!empty($conf->global->EVALUATIONDET_ADDON_PDF)) { - $modele = $conf->global->EVALUATIONDET_ADDON_PDF; + } elseif (!empty($conf->global->EVALUATIONLINE_ADDON_PDF)) { + $modele = $conf->global->EVALUATIONLINE_ADDON_PDF; } } @@ -1043,27 +1043,3 @@ class Evaluationdet extends CommonObject require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php'; - -/** - * Class EvaluationdetLine. You can also remove this and generate a CRUD class for lines objects. - */ -class EvaluationdetLine extends CommonObjectLine -{ - // To complete with content of an object EvaluationdetLine - // We should have a field rowid, fk_evaluationdet and position - - /** - * @var int Does object support extrafields ? 0=No, 1=Yes - */ - public $isextrafieldmanaged = 0; - - /** - * Constructor - * - * @param DoliDb $db Database handler - */ - public function __construct(DoliDB $db) - { - $this->db = $db; - } -} diff --git a/htdocs/user/class/user.class.php b/htdocs/user/class/user.class.php index 2dbc2a3f020..ace3960e38d 100644 --- a/htdocs/user/class/user.class.php +++ b/htdocs/user/class/user.class.php @@ -686,7 +686,10 @@ class User extends CommonObject 'fichinter' => 'ficheinter', 'invoice' => 'facture', 'invoice_supplier' => 'fournisseur', - 'knowledgerecord' => 'knowledgerecord@knowledgemanagement' + 'knowledgerecord' => 'knowledgerecord@knowledgemanagement', + 'skill@hrm' => 'all@hrm', // skill / job / position objects rights are for the moment grouped into right level "all" + 'job@hrm' => 'all@hrm', // skill / job / position objects rights are for the moment grouped into right level "all" + 'position@hrm' => 'all@hrm' // skill / job / position objects rights are for the moment grouped into right level "all" ); if (!empty($moduletomoduletouse[$module])) { $module = $moduletomoduletouse[$module]; From 5f0e09e1ef8838d8c7fa3d329f3fc3c5244e2d79 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Tue, 5 Oct 2021 15:04:15 +0200 Subject: [PATCH 24/79] FIX : postgres adaptation --- htdocs/hrm/class/evaluation.class.php | 2 +- htdocs/hrm/class/skillrank.class.php | 2 +- htdocs/hrm/compare.php | 26 ++++++++++++-------------- htdocs/hrm/evaluation_card.php | 10 +++++----- htdocs/hrm/skill_tab.php | 4 ++-- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php index 2fcce8e468e..7652b2bfd0f 100644 --- a/htdocs/hrm/class/evaluation.class.php +++ b/htdocs/hrm/class/evaluation.class.php @@ -228,7 +228,7 @@ class Evaluation extends CommonObject if ($resultcreate > 0) { require_once DOL_DOCUMENT_ROOT . '/hrm/class/skillrank.class.php'; $skillRank = new SkillRank($this->db); - $TRequiredRanks = $skillRank->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object='.$this->fk_job.' AND objecttype="job"')); + $TRequiredRanks = $skillRank->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object='.$this->fk_job." AND objecttype='job'")); if (is_array($TRequiredRanks) && !empty($TRequiredRanks)) { $this->lines = array(); diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index b6242527178..c2a09936199 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -217,7 +217,7 @@ class SkillRank extends CommonObject { global $langs; - $sqlfilter = 'fk_object='.$this->fk_object.' AND objecttype="'.$this->objecttype.'" AND fk_skill = '.$this->fk_skill; + $sqlfilter = 'fk_object='.$this->fk_object." AND objecttype='".$this->objecttype."' AND fk_skill = ".$this->fk_skill; $alreadyLinked = $this->fetchAll('ASC', 'rowid', 0, 0, array('customsql' => $sqlfilter)); if (!empty($alreadyLinked)) { $this->error = $langs->trans('ErrSkillAlreadyAdded'); diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php index af41e1bdca1..a42a0e158b5 100644 --- a/htdocs/hrm/compare.php +++ b/htdocs/hrm/compare.php @@ -401,13 +401,11 @@ function displayUsersListWithPicto(&$TUser, $fk_usergroup = 0, $namelist = 'list $sql = "SELECT DISTINCT u.rowid FROM " . MAIN_DB_PREFIX . "user u - LEFT JOIN " . MAIN_DB_PREFIX . "usergroup_user ugu ON (u.rowid = ugu.fk_user) - WHERE 1 - AND u.statut > 0 - AND ugu.fk_usergroup=" . $fk_usergroup; + LEFT JOIN " . MAIN_DB_PREFIX . "usergroup_user as ugu ON (u.rowid = ugu.fk_user) + WHERE u.statut > 0 + AND ugu.fk_usergroup=" . ((int)$fk_usergroup); $res = $db->query($sql); - $out .= '
      '; $TExcludedId = explode(',', $excludedIdsList); @@ -476,12 +474,12 @@ function getSkillForUsers($TUser) if (empty($TUser)) return array(); $sql = 'SELECT sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill, '; - $sql.= " MAX(sr.rank) as rank"; - $sql.=' FROM '.MAIN_DB_PREFIX.'hrm_skill sk'; - $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)'; - $sql.=' WHERE sr.objecttype = "'.SkillRank::SKILLRANK_TYPE_USER.'"'; - $sql.=' AND sr.fk_object IN ('.implode(',', $TUser).')'; - $sql.=" GROUP BY sk.rowid "; // group par competence + $sql.= ' MAX(sr.rank) as "rank"'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'hrm_skill sk'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)'; + $sql.= " WHERE sr.objecttype = '".SkillRank::SKILLRANK_TYPE_USER."'"; + $sql.= ' AND sr.fk_object IN ('.implode(',', $TUser).')'; + $sql.= " GROUP BY sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill "; // group par competence $resql = $db->query($sql); $Tab = array(); @@ -531,12 +529,12 @@ function getSkillForJob($fk_job) if (empty($fk_job)) return array(); $sql = 'SELECT sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill, '; - $sql.= " MAX(sr.rank) as rank"; + $sql.= ' MAX(sr.rank) as "rank"'; $sql.=' FROM '.MAIN_DB_PREFIX.'hrm_skill sk'; $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)'; - $sql.=' WHERE sr.objecttype = "'.SkillRank::SKILLRANK_TYPE_JOB.'"'; + $sql.=" WHERE sr.objecttype = '".SkillRank::SKILLRANK_TYPE_JOB."'"; $sql.=' AND sr.fk_object IN ('.$fk_job.')'; - $sql.=' GROUP BY sk.rowid '; // group par competence*/ + $sql.=' GROUP BY sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill '; // group par competence*/ $resql = $db->query($sql); $Tab = array(); diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 172956fc379..05e5af86b8f 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -610,17 +610,17 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $sql .= ' e.ref,'; $sql .= ' e.date_creation,'; $sql .= ' e.fk_job,'; - $sql .= ' j.label as refjob,'; + $sql .= ' j.label as "refjob",'; $sql .= ' ed.fk_skill,'; - $sql .= ' sk.label as skilllabel,'; + $sql .= ' sk.label as "skilllabel",'; $sql .= ' sk.skill_type,'; $sql .= ' sk.description,'; $sql .= ' ed.rank,'; $sql .= ' ed.required_rank,'; - $sql .= ' ed.rank as userRankForSkill,'; - $sql .= ' skdet_user.description as userRankForSkillDesc,'; - $sql .= ' skdet_required.description as required_rank_desc'; + $sql .= ' ed.rank as "userRankForSkill",'; + $sql .= ' skdet_user.description as "userRankForSkillDesc",'; + $sql .= ' skdet_required.description as "required_rank_desc"'; $sql .= ' FROM ' . MAIN_DB_PREFIX . 'hrm_evaluation as e'; $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'hrm_evaluationdet as ed ON e.rowid = ed.fk_evaluation'; diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php index 4ecbc6439be..5e4b33345b7 100644 --- a/htdocs/hrm/skill_tab.php +++ b/htdocs/hrm/skill_tab.php @@ -178,7 +178,7 @@ if (empty($reshook)) { } else if ($action == 'saveSkill') { if (!empty($TNote)) { foreach ($TNote as $skillId => $rank) { - $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . ' AND objecttype="' . $objecttype . '" AND fk_skill = ' . $skillId)); + $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . " AND objecttype='" . $objecttype . "' AND fk_skill = " . $skillId)); if (is_array($TSkills) && !empty($TSkills)) { foreach ($TSkills as $tmpObj) { $tmpObj->rank = $rank; @@ -283,7 +283,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } // table of skillRank linked to current object - $TSkillsJob = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . ' AND objecttype="' . $objecttype . '"')); + $TSkillsJob = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . " AND objecttype='" . $objecttype . "'")); $TAlreadyUsedSkill = array(); if (is_array($TSkillsJob) && !empty($TSkillsJob)) { From 6c630209573afaa6bb8c67bbde88bae9c5afac7e Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 5 Oct 2021 13:06:49 +0000 Subject: [PATCH 25/79] Fixing style errors. --- htdocs/hrm/compare.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php index a42a0e158b5..283a8a0fce2 100644 --- a/htdocs/hrm/compare.php +++ b/htdocs/hrm/compare.php @@ -403,7 +403,7 @@ function displayUsersListWithPicto(&$TUser, $fk_usergroup = 0, $namelist = 'list $sql = "SELECT DISTINCT u.rowid FROM " . MAIN_DB_PREFIX . "user u LEFT JOIN " . MAIN_DB_PREFIX . "usergroup_user as ugu ON (u.rowid = ugu.fk_user) WHERE u.statut > 0 - AND ugu.fk_usergroup=" . ((int)$fk_usergroup); + AND ugu.fk_usergroup=" . ((int) $fk_usergroup); $res = $db->query($sql); $out .= '
        '; From 370af17894198700d9e697db7fd2b4006dab911a Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Tue, 5 Oct 2021 15:21:37 +0200 Subject: [PATCH 26/79] FIX : ihm --- htdocs/hrm/evaluation_card.php | 9 ++++++--- htdocs/langs/en_US/hrm.lang | 5 ++++- htdocs/langs/fr_FR/hrm.lang | 5 ++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 05e5af86b8f..5d16647c243 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -649,14 +649,17 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $Tab[$num]->required_rank = '' . $obj->required_rank . ''; if ($obj->userRankForSkill > $obj->required_rank) { - $class .= 'veryhappy'; + $title=$langs->trans('MaxlevelGreaterThanShort'); + $class .= 'veryhappy diffnote'; } elseif ($obj->userRankForSkill == $obj->required_rank) { - $class .= 'happy'; + $title=$langs->trans('MaxLevelEqualToShort'); + $class .= 'happy diffnote'; } elseif ($obj->userRankForSkill < $obj->required_rank) { + $title=$langs->trans('MaxLevelLowerThanShort'); $class .= 'sad'; } - $Tab[$num]->result = ' '; + $Tab[$num]->result = ' '; $num++; } diff --git a/htdocs/langs/en_US/hrm.lang b/htdocs/langs/en_US/hrm.lang index 6a578aab50d..430124cecba 100644 --- a/htdocs/langs/en_US/hrm.lang +++ b/htdocs/langs/en_US/hrm.lang @@ -61,7 +61,10 @@ difference=Difference CompetenceAcquiredByOneOrMore=Competence acquired by one or more users but not requested by the second comparator MaxlevelGreaterThan=Max level greater than the one requested MaxLevelEqualTo=Max level equal to that demand -MaxLevelLowerThan= Max level lower than that demand +MaxLevelLowerThan=Max level lower than that demand +MaxlevelGreaterThanShort=Employee level greater than the one requested +MaxLevelEqualToShort=Employee level equals to that demand +MaxLevelLowerThanShort=Employee level lower than that demand SkillNotAcquired=Skill not acquired by all users and requested by the second comparator legend=Legend TypeSkill=Skill type diff --git a/htdocs/langs/fr_FR/hrm.lang b/htdocs/langs/fr_FR/hrm.lang index ceb86bab497..6da0d3f633e 100644 --- a/htdocs/langs/fr_FR/hrm.lang +++ b/htdocs/langs/fr_FR/hrm.lang @@ -72,7 +72,10 @@ difference=Différence CompetenceAcquiredByOneOrMore=Compétence acquise par au moins un salarié mais non requise par le second élément de comparaison MaxlevelGreaterThan=Niveau maximal supérieur au niveau requis MaxLevelEqualTo=Niveau maximal égal au niveau requis -MaxLevelLowerThan= Niveau maximal inférieur au niveau requis +MaxLevelLowerThan=Niveau maximal inférieur au niveau requis +MaxlevelGreaterThanShort=Niveau salarié supérieur au niveau requis +MaxLevelEqualToShort=Niveau salarié égal au niveau requis +MaxLevelLowerThanShort= Niveau salarié inférieur au niveau requis SkillNotAcquired=Compétence non acquise par tous les utilisateur et requise par le second élément de comparaison legend=Légende TypeSkill=Type de compétence From 1d4d4dfe1800814c227096ea4a8a1cf6ce661e6b Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Tue, 5 Oct 2021 15:43:57 +0200 Subject: [PATCH 27/79] FIX : ihm --- htdocs/core/modules/modHRM.class.php | 2 +- htdocs/hrm/core/tpl/objectline_title.tpl.php | 5 +- htdocs/hrm/core/tpl/objectline_view.tpl.php | 5 +- htdocs/hrm/evaluation_card.php | 96 ++++++++++---------- 4 files changed, 55 insertions(+), 53 deletions(-) diff --git a/htdocs/core/modules/modHRM.class.php b/htdocs/core/modules/modHRM.class.php index b7c4f3309f3..1bf43d9bfe7 100644 --- a/htdocs/core/modules/modHRM.class.php +++ b/htdocs/core/modules/modHRM.class.php @@ -80,7 +80,7 @@ class modHRM extends DolibarrModules // Set this to 1 if module has its own menus handler directory (core/menus) 'menus' => 0, // Set this to 1 if module overwrite template dir (core/tpl) - 'tpl' => 1, + 'tpl' => 0, // Set this to 1 if module has its own barcode directory (core/modules/barcode) 'barcode' => 0, // Set this to 1 if module has its own models directory (core/modules/xxx) diff --git a/htdocs/hrm/core/tpl/objectline_title.tpl.php b/htdocs/hrm/core/tpl/objectline_title.tpl.php index 2630a91ea6f..d33f0923335 100644 --- a/htdocs/hrm/core/tpl/objectline_title.tpl.php +++ b/htdocs/hrm/core/tpl/objectline_title.tpl.php @@ -55,7 +55,10 @@ if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) { print ' '; } -// Description +// Skill type +print ''.$langs->trans('SkillType').''; + +// Label skill print ''.$langs->trans('Label').''; // Description diff --git a/htdocs/hrm/core/tpl/objectline_view.tpl.php b/htdocs/hrm/core/tpl/objectline_view.tpl.php index 04f4cc48bdd..9be74a5f38f 100644 --- a/htdocs/hrm/core/tpl/objectline_view.tpl.php +++ b/htdocs/hrm/core/tpl/objectline_view.tpl.php @@ -74,7 +74,10 @@ $coldisplay = 0; if ($line->fk_skill > 0) { $skill = new Skill($this->db); $resSkill = $skill->fetch($line->fk_skill); - if ($resSkill > 0) print $skill->getNomUrl(1); + if ($resSkill > 0) { + print Skill::typeCodeToLabel($skill->skill_type).''; + print ''.$skill->getNomUrl(1); + } } ?> diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 5d16647c243..75c66ca3069 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -528,6 +528,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if (!empty($object->lines)) { + $conf->modules_parts['tpl']['hrm']='/hrm/core/tpl/'; // Pour utilisation du tpl hrm sur cet écran print ''; $object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, ''); print '
        '; @@ -553,55 +554,6 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } } - - // Buttons for actions - - if ($action != 'presend' && $action != 'editline') { - print '
        '."\n"; - $parameters = array(); - $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook - if ($reshook < 0) { - setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - } - - if (empty($reshook)) { - // Send - if (empty($user->socid)) { - print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=presend&mode=init&token='.newToken().'#formmailbeforetitle'); - } - - // Back to draft - if ($object->status == $object::STATUS_VALIDATED) { - print dolGetButtonAction($langs->trans('SetToDraft'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_setdraft&confirm=yes&token='.newToken(), '', $permissiontoadd); - print dolGetButtonAction($langs->trans('Close'), '', 'close', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=close&token='.newToken(), '', $permissiontodelete || ($object->status == $object::STATUS_CLOSED && $permissiontoclose)); - } elseif ($object->status != $object::STATUS_CLOSED) { - print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken(), '', $permissiontoadd); - } - - if ($object->status == $object::STATUS_CLOSED) { - print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken(), '', $permissiontoadd); - } - - - // Validate - if ($object->status == $object::STATUS_DRAFT) { - if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) { - print dolGetButtonAction($langs->trans('Save').' '.$langs->trans('and').' '.$langs->trans('Valid'), '', 'default', '#', 'btn_valid', $permissiontovalidate); - } else { - $langs->load("errors"); - print dolGetButtonAction($langs->trans("ErrorAddAtLeastOneLineFirst"), $langs->trans("Validate"), 'default', '#', '', 0); - } - } - - - // Delete (need delete permission, or if draft, just need create/modify permission) - print dolGetButtonAction($langs->trans('Delete'), '', 'delete', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=delete&token='.newToken(), '', $permissiontodelete); - } - - - print '
        '."\n"; - } - // list of comparison if ($object->status != Evaluation::STATUS_DRAFT) { // Recovery of skills related to this evaluation @@ -664,7 +616,6 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $num++; } - print load_fiche_titre($langs->trans("SkillList"), '', 'title'); print '
        '; print ''; @@ -706,7 +657,52 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } } + // Buttons for actions + if ($action != 'presend' && $action != 'editline') { + print '
        '."\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + if (empty($reshook)) { + // Send + if (empty($user->socid)) { + print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=presend&mode=init&token='.newToken().'#formmailbeforetitle'); + } + + // Back to draft + if ($object->status == $object::STATUS_VALIDATED) { + print dolGetButtonAction($langs->trans('SetToDraft'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_setdraft&confirm=yes&token='.newToken(), '', $permissiontoadd); + print dolGetButtonAction($langs->trans('Close'), '', 'close', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=close&token='.newToken(), '', $permissiontodelete || ($object->status == $object::STATUS_CLOSED && $permissiontoclose)); + } elseif ($object->status != $object::STATUS_CLOSED) { + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken(), '', $permissiontoadd); + } + + if ($object->status == $object::STATUS_CLOSED) { + print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken(), '', $permissiontoadd); + } + + + // Validate + if ($object->status == $object::STATUS_DRAFT) { + if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) { + print dolGetButtonAction($langs->trans('Save').' '.$langs->trans('and').' '.$langs->trans('Valid'), '', 'default', '#', 'btn_valid', $permissiontovalidate); + } else { + $langs->load("errors"); + print dolGetButtonAction($langs->trans("ErrorAddAtLeastOneLineFirst"), $langs->trans("Validate"), 'default', '#', '', 0); + } + } + + + // Delete (need delete permission, or if draft, just need create/modify permission) + print dolGetButtonAction($langs->trans('Delete'), '', 'delete', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=delete&token='.newToken(), '', $permissiontodelete); + } + + + print '
        '."\n"; + } // Select mail models is same action as presend if (GETPOST('modelselected')) { From 1a651f089dbdbf8432476c68b0e36bdc07dcf9c1 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Tue, 5 Oct 2021 16:38:20 +0200 Subject: [PATCH 28/79] FIX : travis feedback --- htdocs/hrm/class/evaluation.class.php | 2 +- htdocs/hrm/class/evaluationdet.class.php | 2 +- htdocs/hrm/class/job.class.php | 2 +- htdocs/hrm/class/position.class.php | 2 +- htdocs/hrm/class/skill.class.php | 2 +- htdocs/hrm/class/skilldet.class.php | 2 +- htdocs/hrm/class/skillrank.class.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php index 7652b2bfd0f..b13f031c136 100644 --- a/htdocs/hrm/class/evaluation.class.php +++ b/htdocs/hrm/class/evaluation.class.php @@ -422,7 +422,7 @@ class Evaluation extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/evaluationdet.class.php b/htdocs/hrm/class/evaluationdet.class.php index 0608f14dbe9..eb7ec1e253c 100644 --- a/htdocs/hrm/class/evaluationdet.class.php +++ b/htdocs/hrm/class/evaluationdet.class.php @@ -395,7 +395,7 @@ class Evaluationline extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/job.class.php b/htdocs/hrm/class/job.class.php index 23b08e00012..2360c3536ef 100644 --- a/htdocs/hrm/class/job.class.php +++ b/htdocs/hrm/class/job.class.php @@ -396,7 +396,7 @@ class Job extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index 673840c83d4..001a7151272 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -407,7 +407,7 @@ class Position extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND (' . implode(' ' . $filtermode . ' ', $sqlwhere) . ')'; + $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/skill.class.php b/htdocs/hrm/class/skill.class.php index b2fe7719564..5d37f367309 100644 --- a/htdocs/hrm/class/skill.class.php +++ b/htdocs/hrm/class/skill.class.php @@ -442,7 +442,7 @@ class Skill extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/skilldet.class.php b/htdocs/hrm/class/skilldet.class.php index ca6752b2508..03cd095ecc7 100644 --- a/htdocs/hrm/class/skilldet.class.php +++ b/htdocs/hrm/class/skilldet.class.php @@ -388,7 +388,7 @@ class Skilldet extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index c2a09936199..e9126707550 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -427,7 +427,7 @@ class SkillRank extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; } if (!empty($sortfield)) { From 298f337f36fc4ed53ef8d8144a04aa339e2560a8 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Tue, 5 Oct 2021 16:45:18 +0200 Subject: [PATCH 29/79] Revert "FIX : travis feedback" This reverts commit 1a651f089dbdbf8432476c68b0e36bdc07dcf9c1. --- htdocs/hrm/class/evaluation.class.php | 2 +- htdocs/hrm/class/evaluationdet.class.php | 2 +- htdocs/hrm/class/job.class.php | 2 +- htdocs/hrm/class/position.class.php | 2 +- htdocs/hrm/class/skill.class.php | 2 +- htdocs/hrm/class/skilldet.class.php | 2 +- htdocs/hrm/class/skillrank.class.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php index b13f031c136..7652b2bfd0f 100644 --- a/htdocs/hrm/class/evaluation.class.php +++ b/htdocs/hrm/class/evaluation.class.php @@ -422,7 +422,7 @@ class Evaluation extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/evaluationdet.class.php b/htdocs/hrm/class/evaluationdet.class.php index eb7ec1e253c..0608f14dbe9 100644 --- a/htdocs/hrm/class/evaluationdet.class.php +++ b/htdocs/hrm/class/evaluationdet.class.php @@ -395,7 +395,7 @@ class Evaluationline extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/job.class.php b/htdocs/hrm/class/job.class.php index 2360c3536ef..23b08e00012 100644 --- a/htdocs/hrm/class/job.class.php +++ b/htdocs/hrm/class/job.class.php @@ -396,7 +396,7 @@ class Job extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index 001a7151272..673840c83d4 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -407,7 +407,7 @@ class Position extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; + $sql .= ' AND (' . implode(' ' . $filtermode . ' ', $sqlwhere) . ')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/skill.class.php b/htdocs/hrm/class/skill.class.php index 5d37f367309..b2fe7719564 100644 --- a/htdocs/hrm/class/skill.class.php +++ b/htdocs/hrm/class/skill.class.php @@ -442,7 +442,7 @@ class Skill extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/skilldet.class.php b/htdocs/hrm/class/skilldet.class.php index 03cd095ecc7..ca6752b2508 100644 --- a/htdocs/hrm/class/skilldet.class.php +++ b/htdocs/hrm/class/skilldet.class.php @@ -388,7 +388,7 @@ class Skilldet extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index e9126707550..c2a09936199 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -427,7 +427,7 @@ class SkillRank extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.$this->db->escape(implode(' '.$filtermode.' ', $sqlwhere)).')'; + $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; } if (!empty($sortfield)) { From fb775e2c6eb5f0e92e59b70536fd758fb63d2074 Mon Sep 17 00:00:00 2001 From: Indelog Date: Wed, 6 Oct 2021 12:14:46 +0200 Subject: [PATCH 30/79] Fix Add module part in llx_element_element on CommonObject::add_object_linked() Add module part to target type if object has $module property and is'nt in core modules. --- htdocs/core/class/commonobject.class.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index c4564ddcd6d..9cb83668df9 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3623,6 +3623,12 @@ abstract class CommonObject $this->db->begin(); $error = 0; + // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. + // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. + $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization'); + // Add module part to target type if object has $module property and isn't in core modules. + $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "element_element ("; $sql .= "fk_source"; $sql .= ", sourcetype"; @@ -3632,7 +3638,7 @@ abstract class CommonObject $sql .= ((int) $origin_id); $sql .= ", '" . $this->db->escape($origin) . "'"; $sql .= ", " . ((int) $this->id); - $sql .= ", '" . $this->db->escape($this->element) . "'"; + $sql .= ", '" . $this->db->escape($targettype) . "'"; $sql .= ")"; dol_syslog(get_class($this) . "::add_object_linked", LOG_DEBUG); @@ -3714,7 +3720,6 @@ abstract class CommonObject $sourceid = (!empty($sourceid) ? $sourceid : $this->id); $targetid = (!empty($targetid) ? $targetid : $this->id); - // For module whit if (empty($sourcetype)) { // If empty $sourcetype and no core module, add module part for searching element in llx_element_element (needed for external module). if (!empty($this->module) && ! in_array($this->module, $coremodule)) $sourcetype = $this->module.'_'.$this->element; From 45e6ea45dc6b6b749e73d267e8bd703dc9437ec1 Mon Sep 17 00:00:00 2001 From: Indelog Date: Wed, 6 Oct 2021 12:19:10 +0200 Subject: [PATCH 31/79] Fix stickler --- htdocs/core/class/commonobject.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 9cb83668df9..d41fd96edf1 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3626,8 +3626,8 @@ abstract class CommonObject // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization'); - // Add module part to target type if object has $module property and isn't in core modules. - $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; + // Add module part to target type if object has $module property and isn't in core modules. + $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; $sql = "INSERT INTO " . MAIN_DB_PREFIX . "element_element ("; $sql .= "fk_source"; From ea13b043eeee13c67e3eaf7321548f7701a59d0e Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Wed, 6 Oct 2021 14:21:02 +0200 Subject: [PATCH 32/79] FIX : travis --- htdocs/hrm/class/evaluation.class.php | 2 +- htdocs/hrm/class/evaluationdet.class.php | 2 +- htdocs/hrm/class/job.class.php | 2 +- htdocs/hrm/class/position.class.php | 2 +- htdocs/hrm/class/skill.class.php | 2 +- htdocs/hrm/class/skilldet.class.php | 2 +- htdocs/hrm/class/skillrank.class.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/htdocs/hrm/class/evaluation.class.php b/htdocs/hrm/class/evaluation.class.php index 7652b2bfd0f..30e95e2d44e 100644 --- a/htdocs/hrm/class/evaluation.class.php +++ b/htdocs/hrm/class/evaluation.class.php @@ -422,7 +422,7 @@ class Evaluation extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")"; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/evaluationdet.class.php b/htdocs/hrm/class/evaluationdet.class.php index 0608f14dbe9..83a4c5a387b 100644 --- a/htdocs/hrm/class/evaluationdet.class.php +++ b/htdocs/hrm/class/evaluationdet.class.php @@ -395,7 +395,7 @@ class Evaluationline extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")"; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/job.class.php b/htdocs/hrm/class/job.class.php index 23b08e00012..c317fc9f08b 100644 --- a/htdocs/hrm/class/job.class.php +++ b/htdocs/hrm/class/job.class.php @@ -396,7 +396,7 @@ class Job extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")"; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index 673840c83d4..f349514b69a 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -407,7 +407,7 @@ class Position extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND (' . implode(' ' . $filtermode . ' ', $sqlwhere) . ')'; + $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")"; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/skill.class.php b/htdocs/hrm/class/skill.class.php index b2fe7719564..34013e3f435 100644 --- a/htdocs/hrm/class/skill.class.php +++ b/htdocs/hrm/class/skill.class.php @@ -442,7 +442,7 @@ class Skill extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")"; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/skilldet.class.php b/htdocs/hrm/class/skilldet.class.php index ca6752b2508..e4ac293c297 100644 --- a/htdocs/hrm/class/skilldet.class.php +++ b/htdocs/hrm/class/skilldet.class.php @@ -388,7 +388,7 @@ class Skilldet extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")"; } if (!empty($sortfield)) { diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index c2a09936199..016ee96dcab 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -427,7 +427,7 @@ class SkillRank extends CommonObject } } if (count($sqlwhere) > 0) { - $sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")"; } if (!empty($sortfield)) { From 23ffc1f4b5cb84987f81eaeaea6864b56f4b3cdd Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Wed, 6 Oct 2021 14:33:01 +0200 Subject: [PATCH 33/79] FIX : useless function --- htdocs/hrm/class/job.class.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/htdocs/hrm/class/job.class.php b/htdocs/hrm/class/job.class.php index c317fc9f08b..4ff5ccbe303 100644 --- a/htdocs/hrm/class/job.class.php +++ b/htdocs/hrm/class/job.class.php @@ -638,22 +638,6 @@ class Job extends CommonObject return $TReturn; } - /** - * - * @return array of key [rowid] => ref - */ - public function getCombo() - { - global $db; - - $res = $db->query("SELECT rowid, ref FROM ".MAIN_DB_PREFIX.'hrm_job WHERE 1 ORDER BY ref'); - $Tab=array(); - while ($obj = $db->fetch_object($res)) { - $Tab[$obj->rowid] = $obj->ref; - } - - return $Tab; - } /** * Set draft status * From 468b76e9d6b75b51d07548b733e9de59b081da4d Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Wed, 6 Oct 2021 15:15:22 +0200 Subject: [PATCH 34/79] FIX : useless function --- htdocs/hrm/class/skill.class.php | 34 -------------------------------- 1 file changed, 34 deletions(-) diff --git a/htdocs/hrm/class/skill.class.php b/htdocs/hrm/class/skill.class.php index 34013e3f435..ba7d0f43d3c 100644 --- a/htdocs/hrm/class/skill.class.php +++ b/htdocs/hrm/class/skill.class.php @@ -1091,40 +1091,6 @@ class Skill extends CommonObject return $error; } - /** - * Permet de retourner un select html du dictionnaire llx_c_skill_type - * - * @param string $selected preselected element - * @param string $htmlname html name of input - * @param bool $emptyvalue true if we need to put an empty value - * @param string $moreattr used to add more html attributes into input - * @param string $more_class used if we want to add new css class to input - * @return string - */ - // public function select_skill_type($selected = '', $htmlname = 'code_c_skill_type', $emptyvalue = true, $moreattr = '', $more_class = '') - // { - // global $conf; - // - // $out = ''; - // - // return $out; - // } - /** * @param int $code number of code label * @return int|string From 2f329bf053d156841df4595a2a96d77c2f0f5cfa Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Wed, 6 Oct 2021 15:31:32 +0200 Subject: [PATCH 35/79] FIX : cast int --- htdocs/hrm/class/skillrank.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index 016ee96dcab..500f61a8a36 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -217,7 +217,7 @@ class SkillRank extends CommonObject { global $langs; - $sqlfilter = 'fk_object='.$this->fk_object." AND objecttype='".$this->objecttype."' AND fk_skill = ".$this->fk_skill; + $sqlfilter = 'fk_object='.$this->fk_object." AND objecttype='".$this->objecttype."' AND fk_skill = ".((int)$this->fk_skill); $alreadyLinked = $this->fetchAll('ASC', 'rowid', 0, 0, array('customsql' => $sqlfilter)); if (!empty($alreadyLinked)) { $this->error = $langs->trans('ErrSkillAlreadyAdded'); @@ -585,7 +585,7 @@ class SkillRank extends CommonObject if (preg_match('/^[\(]?PROV/i', $this->ref)) { // Now we rename also files into index $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'skillrank/".$this->db->escape($this->newref)."'"; - $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'skillrank/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'skillrank/".$this->db->escape($this->ref)."' and entity = ".((int)$conf->entity); $resql = $this->db->query($sql); if (!$resql) { $error++; $this->error = $this->db->lasterror(); From fd7b8ae01a4ccfb427a721320279a99a25a6147f Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Wed, 6 Oct 2021 13:34:00 +0000 Subject: [PATCH 36/79] Fixing style errors. --- htdocs/hrm/class/skillrank.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index 500f61a8a36..ca8af709e37 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -217,7 +217,7 @@ class SkillRank extends CommonObject { global $langs; - $sqlfilter = 'fk_object='.$this->fk_object." AND objecttype='".$this->objecttype."' AND fk_skill = ".((int)$this->fk_skill); + $sqlfilter = 'fk_object='.$this->fk_object." AND objecttype='".$this->objecttype."' AND fk_skill = ".((int) $this->fk_skill); $alreadyLinked = $this->fetchAll('ASC', 'rowid', 0, 0, array('customsql' => $sqlfilter)); if (!empty($alreadyLinked)) { $this->error = $langs->trans('ErrSkillAlreadyAdded'); @@ -585,7 +585,7 @@ class SkillRank extends CommonObject if (preg_match('/^[\(]?PROV/i', $this->ref)) { // Now we rename also files into index $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'skillrank/".$this->db->escape($this->newref)."'"; - $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'skillrank/".$this->db->escape($this->ref)."' and entity = ".((int)$conf->entity); + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'skillrank/".$this->db->escape($this->ref)."' and entity = ".((int) $conf->entity); $resql = $this->db->query($sql); if (!$resql) { $error++; $this->error = $this->db->lasterror(); From ad2844d2f02d537d9f13e52e29a7b19bf2426f15 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Wed, 6 Oct 2021 15:55:59 +0200 Subject: [PATCH 37/79] FIX : cast int --- htdocs/hrm/class/skillrank.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index 500f61a8a36..bcb9b55476d 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -931,7 +931,7 @@ class SkillRank extends CommonObject $this->lines = array(); $objectline = new SkillRankLine($this->db); - $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_skillrank = '.$this->id)); + $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_skillrank = '.((int)$this->id))); if (is_numeric($result)) { $this->error = $this->error; From 528e4f87d18e153d9e4553d01ffe1cf66539ad37 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Wed, 6 Oct 2021 13:59:03 +0000 Subject: [PATCH 38/79] Fixing style errors. --- htdocs/hrm/class/skillrank.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index f6696870194..8f957841265 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -931,7 +931,7 @@ class SkillRank extends CommonObject $this->lines = array(); $objectline = new SkillRankLine($this->db); - $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_skillrank = '.((int)$this->id))); + $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_skillrank = '.((int) $this->id))); if (is_numeric($result)) { $this->error = $this->error; From f52e2be10e32b49372fdffbf962d0c2b7cbe1784 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 6 Oct 2021 16:23:11 +0200 Subject: [PATCH 39/79] NEW:Add filter from date to date into action/evt list --- htdocs/comm/action/list.php | 82 +++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/htdocs/comm/action/list.php b/htdocs/comm/action/list.php index 477146fbfd1..e07574bacf5 100644 --- a/htdocs/comm/action/list.php +++ b/htdocs/comm/action/list.php @@ -73,8 +73,10 @@ $search_title = GETPOST('search_title', 'alpha'); $search_note = GETPOST('search_note', 'alpha'); $dateselect = dol_mktime(0, 0, 0, GETPOST('dateselectmonth', 'int'), GETPOST('dateselectday', 'int'), GETPOST('dateselectyear', 'int'), 'tzuserrel'); -$datestart = dol_mktime(0, 0, 0, GETPOST('datestartmonth', 'int'), GETPOST('datestartday', 'int'), GETPOST('datestartyear', 'int'), 'tzuserrel'); -$dateend = dol_mktime(0, 0, 0, GETPOST('dateendmonth', 'int'), GETPOST('dateendday', 'int'), GETPOST('dateendyear', 'int'), 'tzuserrel'); +$datestart_dtstart = dol_mktime(0, 0, 0, GETPOST('datestart_dtstartmonth', 'int'), GETPOST('datestart_dtstartday', 'int'), GETPOST('datestart_dtstartyear', 'int'), 'tzuserrel'); +$datestart_dtend = dol_mktime(23, 59, 59, GETPOST('datestart_dtendmonth', 'int'), GETPOST('datestart_dtendday', 'int'), GETPOST('datestart_dtendyear', 'int'), 'tzuserrel'); +$dateend_dtstart = dol_mktime(0, 0, 0, GETPOST('dateend_dtstartmonth', 'int'), GETPOST('dateend_dtstartday', 'int'), GETPOST('dateend_dtstartyear', 'int'), 'tzuserrel'); +$dateend_dtend = dol_mktime(23, 59, 59, GETPOST('dateend_dtendmonth', 'int'), GETPOST('dateend_dtendday', 'int'), GETPOST('dateend_dtendyear', 'int'), 'tzuserrel'); if ($search_status == '' && !GETPOSTISSET('search_status')) { $search_status = (empty($conf->global->AGENDA_DEFAULT_FILTER_STATUS) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_STATUS); } @@ -205,8 +207,10 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x' $search_id = ''; $search_title = ''; $search_note = ''; - $datestart = ''; - $dateend = ''; + $datestart_dtstart = ''; + $datestart_dtend = ''; + $dateend_dtstart = ''; + $dateend_dtend = ''; $search_status = ''; $toselect = ''; $search_array_options = array(); @@ -323,23 +327,41 @@ if ($search_title != '') { if ($search_note != '') { $param .= '&search_note='.urlencode($search_note); } -if (GETPOST('datestartday', 'int')) { - $param .= '&datestartday='.GETPOST('datestartday', 'int'); +if (GETPOST('datestartday_dtstart', 'int')) { + $param .= '&datestartday_dtstart='.GETPOST('datestartday_dtstart', 'int'); } -if (GETPOST('datestartmonth', 'int')) { - $param .= '&datestartmonth='.GETPOST('datestartmonth', 'int'); +if (GETPOST('datestartmonth_dtstart', 'int')) { + $param .= '&datestartmonth_dtstart='.GETPOST('datestartmonth_dtstart', 'int'); } -if (GETPOST('datestartyear', 'int')) { - $param .= '&datestartyear='.GETPOST('datestartyear', 'int'); +if (GETPOST('datestartyear_dtstart', 'int')) { + $param .= '&datestartyear_dtstart='.GETPOST('datestartyear_dtstart', 'int'); } -if (GETPOST('dateendday', 'int')) { - $param .= '&dateendday='.GETPOST('dateendday', 'int'); +if (GETPOST('datestartday_dtend', 'int')) { + $param .= '&datestartday_dtend='.GETPOST('datestartday_dtend', 'int'); } -if (GETPOST('dateendmonth', 'int')) { - $param .= '&dateendmonth='.GETPOST('dateendmonth', 'int'); +if (GETPOST('datestartmonth_dtend', 'int')) { + $param .= '&datestartmonth_dtend='.GETPOST('datestartmonth_dtend', 'int'); } -if (GETPOST('dateendyear', 'int')) { - $param .= '&dateendyear='.GETPOST('dateendyear', 'int'); +if (GETPOST('datestartyear_dtend', 'int')) { + $param .= '&datestartyear_dtend='.GETPOST('datestartyear_dtend', 'int'); +} +if (GETPOST('dateendday_dtstart', 'int')) { + $param .= '&dateendday_dtstart='.GETPOST('dateendday_dtstart', 'int'); +} +if (GETPOST('dateendmonth_dtstart', 'int')) { + $param .= '&dateendmonth_dtstart='.GETPOST('dateendmonth_dtstart', 'int'); +} +if (GETPOST('dateendyear_dtstart', 'int')) { + $param .= '&dateendyear_dtstart='.GETPOST('dateendyear_dtstart', 'int'); +} +if (GETPOST('dateendday_dtend', 'int')) { + $param .= '&dateendday_dtend='.GETPOST('dateendday_dtend', 'int'); +} +if (GETPOST('dateendmonth_dtend', 'int')) { + $param .= '&dateendmonth_dtend='.GETPOST('dateendmonth_dtend', 'int'); +} +if (GETPOST('dateendyear_dtend', 'int')) { + $param .= '&dateendyear_dtend='.GETPOST('dateendyear_dtend', 'int'); } if ($optioncss != '') { $param .= '&optioncss='.urlencode($optioncss); @@ -502,11 +524,17 @@ if ($filtert > 0 || $usergroup > 0) { if ($dateselect > 0) { $sql .= " AND ((a.datep2 >= '".$db->idate($dateselect)."' AND a.datep <= '".$db->idate($dateselect + 3600 * 24 - 1)."') OR (a.datep2 IS NULL AND a.datep > '".$db->idate($dateselect - 3600)."' AND a.datep <= '".$db->idate($dateselect + 3600 * 24 - 1)."'))"; } -if ($datestart > 0) { - $sql .= " AND a.datep BETWEEN '".$db->idate($datestart)."' AND '".$db->idate($datestart + 3600 * 24 - 1)."'"; +if ($datestart_dtstart > 0) { + $sql .= " AND a.datep >= '".$db->idate($datestart_dtstart)."'"; } -if ($dateend > 0) { - $sql .= " AND a.datep2 BETWEEN '".$db->idate($dateend)."' AND '".$db->idate($dateend + 3600 * 24 - 1)."'"; +if ($datestart_dtend > 0) { + $sql .= " AND a.datep <= '".$db->idate($datestart_dtend)."'"; +} +if ($dateend_dtstart > 0) { + $sql .= " AND a.datep2 >= '".$db->idate($dateend_dtstart)."'"; +} +if ($dateend_dtend > 0) { + $sql .= " AND a.datep2 <= '".$db->idate($dateend_dtend)."'"; } // Add where from extra fields @@ -723,12 +751,22 @@ if (!empty($arrayfields['a.note']['checked'])) { } if (!empty($arrayfields['a.datep']['checked'])) { print ''; } if (!empty($arrayfields['a.datep2']['checked'])) { print ''; } if (!empty($arrayfields['s.nom']['checked'])) { From 18fb3a352b2105e13c594ca41cd75e75c216329a Mon Sep 17 00:00:00 2001 From: Indelog Date: Wed, 6 Oct 2021 17:18:45 +0200 Subject: [PATCH 40/79] Add hook to overide sourcetype and targettype for linked object This add hook `setLinkedObjectSourceTargetType` in `CommonObject::showLinkToObjectBlock()` and in `CommonObject::fetchObjectLinked()` to allow overiding sourcetype and targettype by custom modules. --- htdocs/core/class/commonobject.class.php | 54 +++++++++++------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index d41fd96edf1..1de8d8cd752 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3602,7 +3602,7 @@ abstract class CommonObject public function add_object_linked($origin = null, $origin_id = null, $f_user = null, $notrigger = 0) { // phpcs:enable - global $user; + global $user, $hookmanager, $action; $origin = (!empty($origin) ? $origin : $this->origin); $origin_id = (!empty($origin_id) ? $origin_id : $this->origin_id); $f_user = isset($f_user) ? $f_user : $user; @@ -3620,8 +3620,16 @@ abstract class CommonObject if ($origin == 'supplierorder') { $origin = 'order_supplier'; } - $this->db->begin(); - $error = 0; + + $targettype = $this->element; + + $parameters = array('sourcetype'=>$sourcetype, 'sourceid'=>$sourceid, 'targettype'=>$targettype, 'targetid'=>$targetid); + // Hook for explicitly set the targettype if it must be differtent than $this->element + $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype']; + if (!empty($hookmanager->resArray['sourcetype'])) $sourcetype = $hookmanager->resArray['sourcetype']; + } // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. @@ -3629,6 +3637,9 @@ abstract class CommonObject // Add module part to target type if object has $module property and isn't in core modules. $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; + $this->db->begin(); + $error = 0; + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "element_element ("; $sql .= "fk_source"; $sql .= ", sourcetype"; @@ -3691,7 +3702,7 @@ abstract class CommonObject */ public function fetchObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $clause = 'OR', $alsosametype = 1, $orderby = 'sourcetype', $loadalsoobjects = 1) { - global $conf; + global $conf, $hookmanager, $action; $this->linkedObjectsIds = array(); $this->linkedObjects = array(); @@ -3701,34 +3712,17 @@ abstract class CommonObject $withtargettype = false; $withsourcetype = false; - if (!empty($sourceid) && !empty($sourcetype) && empty($targetid)) { - $justsource = true; // the source (id and type) is a search criteria - if (!empty($targettype)) { - $withtargettype = true; - } - } - if (!empty($targetid) && !empty($targettype) && empty($sourceid)) { - $justtarget = true; // the target (id and type) is a search criteria - if (!empty($sourcetype)) { - $withsourcetype = true; - } - } - - // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. - // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. - $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization'); - $sourceid = (!empty($sourceid) ? $sourceid : $this->id); $targetid = (!empty($targetid) ? $targetid : $this->id); - if (empty($sourcetype)) { - // If empty $sourcetype and no core module, add module part for searching element in llx_element_element (needed for external module). - if (!empty($this->module) && ! in_array($this->module, $coremodule)) $sourcetype = $this->module.'_'.$this->element; - else $sourcetype = $this->element; - } - if (empty($targettype)) { - // If empty $targettype and no core module, add module part for searching element in llx_element_element (needed for external module). - if (!empty($this->module) && ! in_array($this->module, $coremodule)) $targettype = $this->module.'_'.$this->element; - else $targettype = $this->element; + $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element); + $targettype = (!empty($targettype) ? $targettype : $this->element); + + $parameters = array('sourcetype'=>$sourcetype, 'sourceid'=>$sourceid, 'targettype'=>$targettype, 'targetid'=>$targetid); + // Hook for explicitly set the targettype if it must be differtent than $this->element + $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + if (!empty($hookmanager->resArray['sourcetype'])) $sourcetype = $hookmanager->resArray['sourcetype']; + if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype']; } /*if (empty($sourceid) && empty($targetid)) From 2efea59614996ee0b2fc8561975ec5e4a20d90de Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Wed, 6 Oct 2021 17:47:27 +0200 Subject: [PATCH 41/79] FIX : db escape --- htdocs/hrm/class/skillrank.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index f6696870194..87a7b38e6a4 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -217,7 +217,7 @@ class SkillRank extends CommonObject { global $langs; - $sqlfilter = 'fk_object='.$this->fk_object." AND objecttype='".$this->objecttype."' AND fk_skill = ".((int) $this->fk_skill); + $sqlfilter = 'fk_object='.$this->fk_object." AND objecttype='".$this->db->escape($this->objecttype)."' AND fk_skill = ".((int) $this->fk_skill); $alreadyLinked = $this->fetchAll('ASC', 'rowid', 0, 0, array('customsql' => $sqlfilter)); if (!empty($alreadyLinked)) { $this->error = $langs->trans('ErrSkillAlreadyAdded'); From 24e3dd09920d05cc30e744c63eed4124693ac7f7 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 7 Oct 2021 06:05:36 +0200 Subject: [PATCH 42/79] Prepare sql --- htdocs/install/mysql/migration/14.0.0-15.0.0.sql | 4 ++++ htdocs/install/mysql/tables/llx_societe.sql | 6 +++--- htdocs/install/mysql/tables/llx_societe_perentity.sql | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql index 82a6bdec3dc..9a530147d9e 100644 --- a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql +++ b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql @@ -370,3 +370,7 @@ ALTER TABLE llx_hrm_skillrank ADD INDEX idx_hrm_skillrank_fk_skill (fk_skill); ALTER TABLE llx_hrm_skillrank ADD CONSTRAINT llx_hrm_skillrank_fk_user_creat FOREIGN KEY (fk_user_creat) REFERENCES llx_user(rowid); --END GRH/HRM MODULE + +-- Manage accountancy auxiliary account for thirdparties per entity +ALTER TABLE llx_societe_perentity ADD COLUMN accountancy_code_customer varchar(24) AFTER entity; -- equivalent to code_compta in llx_societe +ALTER TABLE llx_societe_perentity ADD COLUMN accountancy_code_supplier varchar(24) AFTER accountancy_code_supplier; -- equivalent to code_compta_supplier in llx_societe diff --git a/htdocs/install/mysql/tables/llx_societe.sql b/htdocs/install/mysql/tables/llx_societe.sql index 7112b6e93ea..011c82b65f7 100644 --- a/htdocs/install/mysql/tables/llx_societe.sql +++ b/htdocs/install/mysql/tables/llx_societe.sql @@ -37,9 +37,9 @@ create table llx_societe status tinyint DEFAULT 1, -- cessation d'activité ( 1 -- en activité, 0 -- cessation d'activité) code_client varchar(24), -- code client - code_fournisseur varchar(24), -- code founisseur - code_compta varchar(24), -- code compta client - code_compta_fournisseur varchar(24), -- code compta founisseur + code_fournisseur varchar(24), -- code fournisseur + code_compta varchar(24), -- customer accountancy auxiliary account + code_compta_fournisseur varchar(24), -- supplier accountancy auxiliary account address varchar(255), -- company address zip varchar(25), -- zipcode town varchar(50), -- town diff --git a/htdocs/install/mysql/tables/llx_societe_perentity.sql b/htdocs/install/mysql/tables/llx_societe_perentity.sql index 408169476d9..800d4a10679 100644 --- a/htdocs/install/mysql/tables/llx_societe_perentity.sql +++ b/htdocs/install/mysql/tables/llx_societe_perentity.sql @@ -21,8 +21,8 @@ create table llx_societe_perentity rowid integer AUTO_INCREMENT PRIMARY KEY, fk_soc integer, entity integer DEFAULT 1 NOT NULL, -- multi company id --- code_compta varchar(24), -- code compta client --- code_compta_fournisseur varchar(24), -- code compta founisseur + accountancy_code_customer varchar(24), -- customer accountancy auxiliary account + accountancy_code_supplier varchar(24), -- supplier accountancy auxiliary account accountancy_code_sell varchar(32), -- Selling accountancy code accountancy_code_buy varchar(32) -- Buying accountancy code )ENGINE=innodb; From adfae3011228067d1c1137b869e050d95a394490 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 7 Oct 2021 06:18:39 +0200 Subject: [PATCH 43/79] NEW Societe - Add perentity functionality on customer/supplier accountancy auxiliary account --- htdocs/accountancy/supplier/list.php | 4 +++- htdocs/core/boxes/box_factures_imp.php | 17 +++++++++++++-- htdocs/societe/class/societe.class.php | 29 ++++++++++++++++++++------ htdocs/societe/index.php | 12 +++++++++-- 4 files changed, 51 insertions(+), 11 deletions(-) diff --git a/htdocs/accountancy/supplier/list.php b/htdocs/accountancy/supplier/list.php index ffdd5b6de57..13553358cf9 100644 --- a/htdocs/accountancy/supplier/list.php +++ b/htdocs/accountancy/supplier/list.php @@ -243,10 +243,12 @@ if (!empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) { $sql .= " p.tosell as status, p.tobuy as status_buy,"; $sql .= " aa.rowid as aarowid, aa2.rowid as aarowid_intra, aa3.rowid as aarowid_export, aa4.rowid as aarowid_thirdparty,"; $sql .= " co.code as country_code, co.label as country_label,"; -$sql .= " s.rowid as socid, s.nom as name, s.tva_intra, s.email, s.town, s.zip, s.fk_pays, s.client, s.fournisseur, s.code_client, s.code_fournisseur, s.code_compta as code_compta_client, s.code_compta_fournisseur,"; +$sql .= " s.rowid as socid, s.nom as name, s.tva_intra, s.email, s.town, s.zip, s.fk_pays, s.client, s.fournisseur, s.code_client, s.code_fournisseur,"; if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= " spe.accountancy_code_customer as code_compta_client, spe.accountancy_code_supplier as code_compta_fournisseur,"; $sql .= " spe.accountancy_code_buy as company_code_buy"; } else { + $sql .= " s.code_compta as code_compta_client, s.code_compta_fournisseur,"; $sql .= " s.accountancy_code_buy as company_code_buy"; } $parameters = array(); diff --git a/htdocs/core/boxes/box_factures_imp.php b/htdocs/core/boxes/box_factures_imp.php index 3b6e857b058..434ebec2602 100644 --- a/htdocs/core/boxes/box_factures_imp.php +++ b/htdocs/core/boxes/box_factures_imp.php @@ -88,7 +88,12 @@ class box_factures_imp extends ModeleBoxes if ($user->rights->facture->lire) { $sql = "SELECT s.rowid as socid, s.nom as name, s.name_alias"; - $sql .= ", s.code_client, s.code_compta, s.client"; + $sql .= ", s.code_client, s.client"; + if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= ", spe.accountancy_code_customer as code_compta"; + } else { + $sql .= ", s.code_compta"; + } $sql .= ", s.logo, s.email, s.entity"; $sql .= ", s.tva_intra, s.siren as idprof1, s.siret as idprof2, s.ape as idprof3, s.idprof4, s.idprof5, s.idprof6"; $sql .= ", f.ref, f.date_lim_reglement as datelimite"; @@ -100,6 +105,9 @@ class box_factures_imp extends ModeleBoxes $sql .= ", f.paye, f.fk_statut as status, f.rowid as facid"; $sql .= ", sum(pf.amount) as am"; $sql .= " FROM ".MAIN_DB_PREFIX."societe as s"; + if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_perentity as spe ON spe.fk_soc = s.rowid AND spe.entity = " . ((int) $conf->entity); + } if (!$user->rights->societe->client->voir && !$user->socid) { $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; } @@ -115,7 +123,12 @@ class box_factures_imp extends ModeleBoxes if ($user->socid) { $sql .= " AND s.rowid = ".((int) $user->socid); } - $sql .= " GROUP BY s.rowid, s.nom, s.name_alias, s.code_client, s.code_compta, s.client, s.logo, s.email, s.entity, s.tva_intra, s.siren, s.siret, s.ape, s.idprof4, s.idprof5, s.idprof6,"; + $sql .= " GROUP BY s.rowid, s.nom, s.name_alias, s.code_client, s.client, s.logo, s.email, s.entity, s.tva_intra, s.siren, s.siret, s.ape, s.idprof4, s.idprof5, s.idprof6,"; + if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= " spe.accountancy_code_customer as code_compta"; + } else { + $sql .= " s.code_compta"; + } $sql .= " f.ref, f.date_lim_reglement,"; $sql .= " f.type, f.datef, f.total_ht, f.total_tva, f.total_ttc, f.paye, f.fk_statut, f.rowid"; //$sql.= " ORDER BY f.datef DESC, f.ref DESC "; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 8c5ef8ca5ca..d83dd1f3d34 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -1281,7 +1281,7 @@ class Societe extends CommonObject } $this->code_compta_client = trim(empty($this->code_compta) ? $this->code_compta_client : $this->code_compta); - $this->code_compta = $this->code_compta_client; // for backward compatbility + $this->code_compta = $this->code_compta_client; // for backward compatibility $this->code_compta_fournisseur = trim($this->code_compta_fournisseur); // Check parameters. More tests are done later in the ->verify() @@ -1451,6 +1451,14 @@ class Societe extends CommonObject if (empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { $sql .= ", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) . "'"; $sql .= ", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) . "'"; + + if ($customer) { + $sql .= ", code_compta = ".(!empty($this->code_compta_client) ? "'".$this->db->escape($this->code_compta_client)."'" : "null"); + } + + if ($supplier) { + $sql .= ", code_compta_fournisseur = ".(($this->code_compta_fournisseur != "") ? "'".$this->db->escape($this->code_compta_fournisseur)."'" : "null"); + } } $sql .= ",webservices_url = ".(!empty($this->webservices_url) ? "'".$this->db->escape($this->webservices_url)."'" : "null"); $sql .= ",webservices_key = ".(!empty($this->webservices_key) ? "'".$this->db->escape($this->webservices_key)."'" : "null"); @@ -1461,12 +1469,10 @@ class Societe extends CommonObject if ($customer) { $sql .= ", code_client = ".(!empty($this->code_client) ? "'".$this->db->escape($this->code_client)."'" : "null"); - $sql .= ", code_compta = ".(!empty($this->code_compta_client) ? "'".$this->db->escape($this->code_compta_client)."'" : "null"); } if ($supplier) { $sql .= ", code_fournisseur = ".(!empty($this->code_fournisseur) ? "'".$this->db->escape($this->code_fournisseur)."'" : "null"); - $sql .= ", code_compta_fournisseur = ".(($this->code_compta_fournisseur != "") ? "'".$this->db->escape($this->code_compta_fournisseur)."'" : "null"); } $sql .= ", fk_user_modif = ".($user->id > 0 ? $user->id : "null"); $sql .= ", fk_multicurrency = ".(int) $this->fk_multicurrency; @@ -1540,12 +1546,23 @@ class Societe extends CommonObject $sql = "INSERT INTO " . MAIN_DB_PREFIX . "societe_perentity ("; $sql .= " fk_soc"; $sql .= ", entity"; + $sql .= ", accountancy_code_customer"; + $sql .= ", accountancy_code_supplier"; $sql .= ", accountancy_code_buy"; $sql .= ", accountancy_code_sell"; $sql .= ") VALUES ("; $sql .= $this->id; $sql .= ", " . $conf->entity; $sql .= ", '" . $this->db->escape($this->accountancy_code_buy) . "'"; + + if ($customer) { + $sql .= ", accountancy_code_customer = ".(!empty($this->code_compta_client) ? "'".$this->db->escape($this->code_compta_client)."'" : "null"); + } + + if ($supplier) { + $sql .= ", accountancy_code_supplier = ".(($this->code_compta_fournisseur != "") ? "'".$this->db->escape($this->code_compta_fournisseur)."'" : "null"); + } + $sql .= ", '" . $this->db->escape($this->accountancy_code_sell) . "'"; $sql .= ")"; $result = $this->db->query($sql); @@ -1646,11 +1663,11 @@ class Societe extends CommonObject $sql .= ', s.fk_forme_juridique as forme_juridique_code'; $sql .= ', s.webservices_url, s.webservices_key, s.model_pdf'; if (empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { - $sql .= ', s.accountancy_code_buy, s.accountancy_code_sell'; + $sql .= ', s.code_compta, s.code_compta_fournisseur, s.accountancy_code_buy, s.accountancy_code_sell'; } else { - $sql .= ', spe.accountancy_code_buy, spe.accountancy_code_sell'; + $sql .= ', spe.accountancy_code_customer as code_compta, spe.accountancy_code_supplier as code_compta_fournisseur, spe.accountancy_code_buy, spe.accountancy_code_sell'; } - $sql .= ', s.code_client, s.code_fournisseur, s.code_compta, s.code_compta_fournisseur, s.parent, s.barcode'; + $sql .= ', s.code_client, s.code_fournisseur, s.parent, s.barcode'; $sql .= ', s.fk_departement as state_id, s.fk_pays as country_id, s.fk_stcomm, s.mode_reglement, s.cond_reglement, s.transport_mode'; $sql .= ', s.fk_account, s.tva_assuj'; $sql .= ', s.mode_reglement_supplier, s.cond_reglement_supplier, s.transport_mode_supplier'; diff --git a/htdocs/societe/index.php b/htdocs/societe/index.php index 3d645d41bf5..de3bae16627 100644 --- a/htdocs/societe/index.php +++ b/htdocs/societe/index.php @@ -263,12 +263,20 @@ $max = 15; $sql = "SELECT s.rowid, s.nom as name, s.email, s.client, s.fournisseur"; $sql .= ", s.code_client"; $sql .= ", s.code_fournisseur"; -$sql .= ", s.code_compta_fournisseur"; -$sql .= ", s.code_compta"; +if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= ", spe.accountancy_code_supplier as code_compta_fournisseur"; + $sql .= ", spe.accountancy_code_customer as code_compta"; +} else { + $sql .= ", s.code_compta_fournisseur"; + $sql .= ", s.code_compta"; +} $sql .= ", s.logo"; $sql .= ", s.entity"; $sql .= ", s.canvas, s.tms as date_modification, s.status as status"; $sql .= " FROM ".MAIN_DB_PREFIX."societe as s"; +if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_perentity as spe ON spe.fk_soc = s.rowid AND spe.entity = " . ((int) $conf->entity); +} if (!$user->rights->societe->client->voir && !$socid) { $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; } From cc21257e3ef5f52f31a448e1b3ddd65117da7686 Mon Sep 17 00:00:00 2001 From: lvessiller Date: Thu, 7 Oct 2021 09:51:55 +0200 Subject: [PATCH 44/79] NEW print without details --- htdocs/langs/en_US/cashdesk.lang | 3 + htdocs/langs/fr_FR/cashdesk.lang | 3 + htdocs/takepos/admin/receipt.php | 15 +++++ htdocs/takepos/invoice.php | 10 ++- htdocs/takepos/printbox.php | 102 +++++++++++++++++++++++++++++++ htdocs/takepos/receipt.php | 64 +++++++++++-------- 6 files changed, 171 insertions(+), 26 deletions(-) create mode 100644 htdocs/takepos/printbox.php diff --git a/htdocs/langs/en_US/cashdesk.lang b/htdocs/langs/en_US/cashdesk.lang index 52dc71d140c..22d5afed2fc 100644 --- a/htdocs/langs/en_US/cashdesk.lang +++ b/htdocs/langs/en_US/cashdesk.lang @@ -130,3 +130,6 @@ ShowPriceHT = Display the column with the price excluding tax (on screen) ShowPriceHTOnReceipt = Display the column with the price excluding tax (on the receipt) CustomerDisplay=Customer display SplitSale=Split sale +PrintWithoutDetailsButton=Add "Print without details" button +PrintWithoutDetailsLabelDefault=Line label by default on printing without details +PrintWithoutDetails=Print without details diff --git a/htdocs/langs/fr_FR/cashdesk.lang b/htdocs/langs/fr_FR/cashdesk.lang index 1a2381584ed..45679973a66 100644 --- a/htdocs/langs/fr_FR/cashdesk.lang +++ b/htdocs/langs/fr_FR/cashdesk.lang @@ -129,3 +129,6 @@ WeighingScale=échelle de poids ShowPriceHT = Afficher la colonne du prix HT (à l'écran) ShowPriceHTOnReceipt = Afficher la colonne avec le prix hors taxes (sur le ticket de caisse) CustomerDisplay=Customer display +PrintWithoutDetailsButton=Ajouter un bouton "Imprimer sans détail" +PrintWithoutDetailsLabelDefault=Libellé de la ligne par défaut sur l'impression sans détail +PrintWithoutDetails=Imprimer sans détail diff --git a/htdocs/takepos/admin/receipt.php b/htdocs/takepos/admin/receipt.php index 1fe95ff57d8..7da8436fab8 100644 --- a/htdocs/takepos/admin/receipt.php +++ b/htdocs/takepos/admin/receipt.php @@ -51,6 +51,7 @@ if (GETPOST('action', 'alpha') == 'set') { $res = dolibarr_set_const($db, "TAKEPOS_AUTO_PRINT_TICKETS", GETPOST('TAKEPOS_AUTO_PRINT_TICKETS', 'int'), 'int', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_PRINT_SERVER", GETPOST('TAKEPOS_PRINT_SERVER', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_PRINT_PAYMENT_METHOD", GETPOST('TAKEPOS_PRINT_PAYMENT_METHOD', 'alpha'), 'chaine', 0, '', $conf->entity); + $res = dolibarr_set_const($db, 'TAKEPOS_PRINT_WITHOUT_DETAILS_LABEL_DEFAULT', GETPOST('TAKEPOS_PRINT_WITHOUT_DETAILS_LABEL_DEFAULT', 'alphanohtml'), 'chaine', 0, '', $conf->entity); dol_syslog("admin/cashdesk: level ".GETPOST('level', 'alpha')); @@ -262,6 +263,20 @@ if ($conf->global->TAKEPOS_PRINT_METHOD == "takeposconnector" && filter_var($con print "\n"; } +// Print without details +print '\n"; +if (!empty($conf->global->TAKEPOS_PRINT_WITHOUT_DETAILS)) { + print '\n"; +} + print '
        '; - print $form->selectDate($datestart, 'datestart', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', '', 'tzuserrel'); + print '
        '; + print $form->selectDate($datestart_dtstart, 'datestart_dtstart', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'), 'tzuserrel'); + print '
        '; + print '
        '; + print $form->selectDate($datestart_dtend, 'datestart_dtend', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('To'), 'tzuserrel'); + print '
        '; print '
        '; - print $form->selectDate($dateend, 'dateend', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', '', 'tzuserrel'); + print '
        '; + print $form->selectDate($dateend_dtstart, 'dateend_dtstart', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'), 'tzuserrel'); + print '
        '; + print '
        '; + print $form->selectDate($dateend_dtend, 'dateend_dtend', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('To'), 'tzuserrel'); + print '
        '; print '
        '; +print $langs->trans('PrintWithoutDetailsButton'); +print ''; +print ajax_constantonoff('TAKEPOS_PRINT_WITHOUT_DETAILS', array(), $conf->entity, 0, 0, 1, 0); +print "
        '; + print $langs->trans('PrintWithoutDetailsLabelDefault'); + print ''; + print ''; + print "
        '; print '
    '; diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index 8b2e5ca78b7..8a6bdcfd2bd 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -158,7 +158,7 @@ if ($ret > 0) { $placeid = $invoice->id; } -$constforcompanyid = 'CASHDESK_ID_THIRDPARTY'. isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '' ; +$constforcompanyid = 'CASHDESK_ID_THIRDPARTY'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : ''); $soc = new Societe($db); if ($invoice->socid > 0) { @@ -877,6 +877,9 @@ if ($action == "valid" || $action == "history" || $action == 'creditnote') { $sectionwithinvoicelink .= ' '; } else { $sectionwithinvoicelink .= ' '; + if (getDolGlobalString('TAKEPOS_PRINT_WITHOUT_DETAILS')) { + $sectionwithinvoicelink .= ' '; + } if (getDolGlobalString('TAKEPOS_GIFT_RECEIPT')) { $sectionwithinvoicelink .= ' '; } @@ -1017,6 +1020,11 @@ function SendTicket(id) $.colorbox({href:"send.php?facid="+id, width:"70%", height:"30%", transition:"none", iframe:"true", title:'trans("SendTicket")); ?>'}); } +function PrintBox(id, action) { + console.log("Open box before printing"); + $.colorbox({href:"printbox.php?facid="+id+"&action="+action, width:"80%", height:"200px", transition:"none", iframe:"true", title:"trans("PrintWithoutDetails"); ?>"}); +} + function Print(id, gift){ console.log("Call Print() to generate the receipt."); $.colorbox({href:"receipt.php?facid="+id+"&gift="+gift, width:"40%", height:"90%", transition:"none", iframe:"true", title:'trans("PrintTicket")); ?>'}); diff --git a/htdocs/takepos/printbox.php b/htdocs/takepos/printbox.php new file mode 100644 index 00000000000..cc5f5b305d1 --- /dev/null +++ b/htdocs/takepos/printbox.php @@ -0,0 +1,102 @@ + + * Copyright (C) 2020 Laurent Destailleur + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/takepos/printbox.php + * \ingroup takepos + * \brief Popup to enter details before printing + */ + +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); // Not disabled cause need to load personalized language +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); // Not disabled cause need to load personalized language +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1'); +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1'); +if (!defined('NOCSRFCHECK')) { + define('NOCSRFCHECK', '1'); +} +if (!defined('NOTOKENRENEWAL')) { + define('NOTOKENRENEWAL', '1'); +} +if (!defined('NOREQUIREMENU')) { + define('NOREQUIREMENU', '1'); +} +if (!defined('NOREQUIREHTML')) { + define('NOREQUIREHTML', '1'); +} +if (!defined('NOREQUIREAJAX')) { + define('NOREQUIREAJAX', '1'); +} + +require '../main.inc.php'; // Load $user and permissions +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php'; + +global $langs, $db; + +$langs->loadLangs(array("bills", "cashdesk")); + +$facid = GETPOST('facid', 'int'); + +$action = GETPOST('action', 'aZ09'); + +if (empty($user->rights->takepos->run)) { + accessforbidden(); +} + + +/* + * View + */ + +$arrayofcss = array('/takepos/css/pos.css.php'); +$arrayofjs = array('/takepos/js/jquery.colorbox-min.js'); + +$head = ''; +top_htmlhead($head, '', 0, 0, $arrayofjs, $arrayofcss); +?> + + + +
    +
    +trans('Label') . '">'; + print ''; + } +?> + +
    + + + diff --git a/htdocs/takepos/receipt.php b/htdocs/takepos/receipt.php index 627a6c99565..df0b55bc64e 100644 --- a/htdocs/takepos/receipt.php +++ b/htdocs/takepos/receipt.php @@ -54,6 +54,7 @@ $place = (GETPOST('place', 'aZ09') ? GETPOST('place', 'aZ09') : 0); // $place is $facid = GETPOST('facid', 'int'); +$action = GETPOST('action', 'aZ09'); $gift = GETPOST('gift', 'int'); if (empty($user->rights->takepos->run)) { @@ -169,33 +170,46 @@ if ($conf->global->TAKEPOS_SHOW_CUSTOMER) { lines as $line) { - ?> - - - product_label)) { - echo $line->product_label; - } else { - echo $line->description; - } ?> - - qty; ?> - total_ttc / $line->qty, 'MT'), 1); - } ?> - global->TAKEPOS_SHOW_HT_RECEIPT)) { ?> - total_ht, 1); - } ?> + if ($action == 'without_details') { + $qty = GETPOST('qty', 'int') > 0 ? GETPOST('qty', 'int') : 1; + print ''; + print '' . GETPOST('label', 'alphanohtml') . ''; + print '' . $qty . ''; + print '' . price(price2num($object->total_ttc / $qty, 'MU'), 1) . ''; + if (!empty($conf->global->TAKEPOS_SHOW_HT_RECEIPT)) { + print '' . price($object->total_ht, 1) . ''; + } + print '' . price($object->total_ttc, 1) . ''; + print ''; + } else { + foreach ($object->lines as $line) { + ?> + + + product_label)) { + echo $line->product_label; + } else { + echo $line->description; + } ?> + + qty; ?> + total_ttc / $line->qty, 'MT'), 1); + } ?> + global->TAKEPOS_SHOW_HT_RECEIPT)) { ?> + total_ht, 1); + } ?> + + total_ttc, 1); + } ?> + - total_ttc, 1); - } ?> - - From da52ee55a4e9adaaa2e51806ceaecc168d3c57b2 Mon Sep 17 00:00:00 2001 From: lvessiller Date: Thu, 7 Oct 2021 10:13:30 +0200 Subject: [PATCH 45/79] FIX sickler-ci errors --- htdocs/takepos/printbox.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/takepos/printbox.php b/htdocs/takepos/printbox.php index cc5f5b305d1..5d612fd19f2 100644 --- a/htdocs/takepos/printbox.php +++ b/htdocs/takepos/printbox.php @@ -87,13 +87,13 @@ top_htmlhead($head, '', 0, 0, $arrayofjs, $arrayofcss);
    trans('Label') . '">'; - print ''; - } + print ''; + print ''; +} ?>
    From 92319464d8f418cc847eaa291145f2c66dac5d6f Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 7 Oct 2021 12:27:52 +0200 Subject: [PATCH 46/79] FIX : travis --- htdocs/hrm/class/skillrank.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index 02bab9f1b9d..ed41e253cbc 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -217,7 +217,7 @@ class SkillRank extends CommonObject { global $langs; - $sqlfilter = 'fk_object='.$this->fk_object." AND objecttype='".$this->db->escape($this->objecttype)."' AND fk_skill = ".((int) $this->fk_skill); + $sqlfilter = 'fk_object='.((int)$this->fk_object)." AND objecttype='".$this->db->escape($this->objecttype)."' AND fk_skill = ".((int) $this->fk_skill); $alreadyLinked = $this->fetchAll('ASC', 'rowid', 0, 0, array('customsql' => $sqlfilter)); if (!empty($alreadyLinked)) { $this->error = $langs->trans('ErrSkillAlreadyAdded'); From 5e02548abbe5e009ff63dd040e764355a65647b4 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Thu, 7 Oct 2021 10:30:32 +0000 Subject: [PATCH 47/79] Fixing style errors. --- htdocs/hrm/class/skillrank.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index ed41e253cbc..97fcd7edab4 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -217,7 +217,7 @@ class SkillRank extends CommonObject { global $langs; - $sqlfilter = 'fk_object='.((int)$this->fk_object)." AND objecttype='".$this->db->escape($this->objecttype)."' AND fk_skill = ".((int) $this->fk_skill); + $sqlfilter = 'fk_object='.((int) $this->fk_object)." AND objecttype='".$this->db->escape($this->objecttype)."' AND fk_skill = ".((int) $this->fk_skill); $alreadyLinked = $this->fetchAll('ASC', 'rowid', 0, 0, array('customsql' => $sqlfilter)); if (!empty($alreadyLinked)) { $this->error = $langs->trans('ErrSkillAlreadyAdded'); From 12488f4a29febeed4c20067c63c0c4880aa013d5 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 7 Oct 2021 13:19:21 +0200 Subject: [PATCH 48/79] FIX : travis --- htdocs/hrm/compare.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php index 283a8a0fce2..2f8dbc56188 100644 --- a/htdocs/hrm/compare.php +++ b/htdocs/hrm/compare.php @@ -489,9 +489,9 @@ function getSkillForUsers($TUser) $num = 0; while ($obj = $db->fetch_object($resql) ) { $sql1 = "SELECT count(*) as how_many_max FROM ".MAIN_DB_PREFIX."hrm_skillrank sr"; - $sql1.=" WHERE sr.rank = ".(int) $obj->rank; + $sql1.=" WHERE sr.rank = ".((int) $obj->rank); $sql1.=" AND sr.objecttype = '".Skillrank::SKILLRANK_TYPE_USER."'"; - $sql1.=" AND sr.fk_skill = ".$obj->fk_skill; + $sql1.=" AND sr.fk_skill = ".((int) $obj->fk_skill); $sql1.=" AND sr.fk_object IN (".implode(',', $TUser).")"; $resql1 = $db->query($sql1); @@ -533,7 +533,7 @@ function getSkillForJob($fk_job) $sql.=' FROM '.MAIN_DB_PREFIX.'hrm_skill sk'; $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)'; $sql.=" WHERE sr.objecttype = '".SkillRank::SKILLRANK_TYPE_JOB."'"; - $sql.=' AND sr.fk_object IN ('.$fk_job.')'; + $sql.=' AND sr.fk_object = '.((int) $fk_job); $sql.=' GROUP BY sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill '; // group par competence*/ $resql = $db->query($sql); From 0a73b2874219c9ee5592493b6de1e2571e49afeb Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 7 Oct 2021 14:18:03 +0200 Subject: [PATCH 49/79] FIX : travis --- htdocs/hrm/compare.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php index 2f8dbc56188..a13fa1245e9 100644 --- a/htdocs/hrm/compare.php +++ b/htdocs/hrm/compare.php @@ -478,7 +478,7 @@ function getSkillForUsers($TUser) $sql.= ' FROM '.MAIN_DB_PREFIX.'hrm_skill sk'; $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'hrm_skillrank sr ON (sk.rowid = sr.fk_skill)'; $sql.= " WHERE sr.objecttype = '".SkillRank::SKILLRANK_TYPE_USER."'"; - $sql.= ' AND sr.fk_object IN ('.implode(',', $TUser).')'; + $sql.= ' AND sr.fk_object IN ('.$db->sanitize(implode(',', $TUser)).')'; $sql.= " GROUP BY sk.rowid, sk.label, sk.description, sk.skill_type, sr.fk_object, sr.objecttype, sr.fk_skill "; // group par competence $resql = $db->query($sql); @@ -492,7 +492,7 @@ function getSkillForUsers($TUser) $sql1.=" WHERE sr.rank = ".((int) $obj->rank); $sql1.=" AND sr.objecttype = '".Skillrank::SKILLRANK_TYPE_USER."'"; $sql1.=" AND sr.fk_skill = ".((int) $obj->fk_skill); - $sql1.=" AND sr.fk_object IN (".implode(',', $TUser).")"; + $sql1.=" AND sr.fk_object IN (".$db->sanitize(implode(',', $TUser)).")"; $resql1 = $db->query($sql1); $objMax = $db->fetch_object($resql1); From da52b00aefea69c38a636237db3d4ea780793d52 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 7 Oct 2021 14:32:16 +0200 Subject: [PATCH 50/79] fix br --- htdocs/hrm/compare.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/compare.php b/htdocs/hrm/compare.php index a13fa1245e9..13b83af9737 100644 --- a/htdocs/hrm/compare.php +++ b/htdocs/hrm/compare.php @@ -443,7 +443,7 @@ function displayUsersListWithPicto(&$TUser, $fk_usergroup = 0, $namelist = 'list $desc .= $langs->trans('NoEval'); } - if (!empty($user->array_options['options_DDA'])) $desc .= '
    ' . $langs->trans('Anciennete') . ' : ' . dol_print_date(strtotime($user->array_options['options_DDA'])); + if (!empty($user->array_options['options_DDA'])) $desc .= '
    ' . $langs->trans('Anciennete') . ' : ' . dol_print_date(strtotime($user->array_options['options_DDA'])); $out .= '
  • ' . $form->showphoto('userphoto', $user, 0, 0, 0, 'photoref', 'small', 1, 0, 1) . ' From 4094d94bd6b9d87617e3d4717476af1ec602504b Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 7 Oct 2021 14:41:15 +0200 Subject: [PATCH 51/79] FIX : travis --- htdocs/hrm/evaluation_card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 75c66ca3069..72ed1761947 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -581,7 +581,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $sql .= ' INNER JOIN ' . MAIN_DB_PREFIX . 'hrm_skilldet as skdet_user ON (skdet_user.fk_skill = sk.rowid AND skdet_user.rank = ed.rank)'; //$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "hrm_skillrank as skr ON (j.rowid = skr.fk_object AND skr.fk_skill = ed.fk_skill AND skr.objecttype = 'job')"; $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'hrm_skilldet as skdet_required ON (skdet_required.fk_skill = sk.rowid AND skdet_required.rank = ed.required_rank)'; - $sql .= " WHERE e.rowid =" . $object->id; + $sql .= " WHERE e.rowid =" . ((int) $object->id); // echo $sql; From 6fdd1c49f3c9e073dc217cebb196607825d8016c Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 7 Oct 2021 17:29:20 +0200 Subject: [PATCH 52/79] FIX : travis --- htdocs/hrm/evaluation_list.php | 2 +- htdocs/hrm/job_list.php | 2 +- htdocs/hrm/position_list.php | 2 +- htdocs/hrm/skill_list.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/hrm/evaluation_list.php b/htdocs/hrm/evaluation_list.php index 6a74cb9bc6b..589dbb0dcfd 100644 --- a/htdocs/hrm/evaluation_list.php +++ b/htdocs/hrm/evaluation_list.php @@ -268,7 +268,7 @@ $sql .= $object->getFieldList('t'); // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key.', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$db->escape($key).' as options_'.$db->escape($key).', ' : ''); } } // Add fields from hooks diff --git a/htdocs/hrm/job_list.php b/htdocs/hrm/job_list.php index 1a2ca54f1a7..c1752c9dea7 100644 --- a/htdocs/hrm/job_list.php +++ b/htdocs/hrm/job_list.php @@ -268,7 +268,7 @@ $sql .= $object->getFieldList('t'); // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key.', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$db->escape($key).' as options_'.$db->escape($key).', ' : ''); } } // Add fields from hooks diff --git a/htdocs/hrm/position_list.php b/htdocs/hrm/position_list.php index fc40e58441c..54323a967e0 100644 --- a/htdocs/hrm/position_list.php +++ b/htdocs/hrm/position_list.php @@ -268,7 +268,7 @@ $sql .= $object->getFieldList('t'); // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key.', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$db->escape($key).' as options_'.$db->escape($key).', ' : ''); } } // Add fields from hooks diff --git a/htdocs/hrm/skill_list.php b/htdocs/hrm/skill_list.php index 009a5491342..a228e7c9c6e 100644 --- a/htdocs/hrm/skill_list.php +++ b/htdocs/hrm/skill_list.php @@ -268,7 +268,7 @@ $sql .= $object->getFieldList('t'); // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key.', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$db->escape($key).' as options_'.$db->escape($key).', ' : ''); } } // Add fields from hooks From 677002e8347aeb58e83e2d222aedc7bf5b39e4d5 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Thu, 7 Oct 2021 20:20:29 +0200 Subject: [PATCH 53/79] fix travis --- htdocs/expedition/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 1ba022efdb1..b9061b463ef 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -1162,7 +1162,7 @@ if ($action == 'create') { // unit of order $unit_order = ''; - if ($conf->global->PRODUCT_USE_UNITS) { + if (!empty($conf->global->PRODUCT_USE_UNITS)) { $unit_order = measuringUnitString($line->fk_unit); } From e68d9dc73c8309de6d15621d0338ec577d74b6ef Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 7 Oct 2021 22:02:56 +0200 Subject: [PATCH 54/79] NEW Societe - Add perentity functionality on customer/supplier accountancy auxiliary account --- htdocs/accountancy/customer/lines.php | 14 ++++++++++-- htdocs/accountancy/customer/list.php | 6 ++++- htdocs/accountancy/journal/bankjournal.php | 14 ++++++++++-- .../accountancy/journal/purchasesjournal.php | 12 +++++++++- htdocs/accountancy/journal/sellsjournal.php | 12 +++++++++- htdocs/accountancy/supplier/lines.php | 12 +++++++++- htdocs/core/boxes/box_contacts.php | 12 +++++++++- htdocs/fourn/index.php | 10 ++++++++- .../accountancy/export-thirdpartyaccount.php | 22 ++++++++++++++++--- 9 files changed, 101 insertions(+), 13 deletions(-) diff --git a/htdocs/accountancy/customer/lines.php b/htdocs/accountancy/customer/lines.php index 1e7c38b2607..b833ca887e9 100644 --- a/htdocs/accountancy/customer/lines.php +++ b/htdocs/accountancy/customer/lines.php @@ -191,7 +191,14 @@ print ''; -$sql = "(SELECT s.rowid, s.nom as name , s.address, s.zip , s.town, s.code_compta as compta , "; -$sql .= " s.fk_forme_juridique , s.fk_pays , s.phone , s.fax , f.datec , f.fk_soc , cp.label as country "; +$sql = "(SELECT s.rowid, s.nom as name , s.address, s.zip , s.town"; +if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= ", spe.accountancy_code_customer as compta"; +} else { + $sql .= ", s.code_compta"; +} +$sql .= ", s.fk_forme_juridique , s.fk_pays , s.phone , s.fax , f.datec , f.fk_soc , cp.label as country "; $sql .= " FROM ".MAIN_DB_PREFIX."societe as s"; +if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_perentity as spe ON spe.fk_soc = s.rowid AND spe.entity = " . ((int) $conf->entity); +} $sql .= ", ".MAIN_DB_PREFIX."facture as f"; $sql .= ", ".MAIN_DB_PREFIX."c_country as cp"; $sql .= " WHERE f.fk_soc = s.rowid"; @@ -146,9 +154,17 @@ if ($socid > 0) { } $sql .= " GROUP BY name"; $sql .= ")"; -$sql .= "UNION (SELECT s.rowid, s.nom as name , s.address, s.zip , s.town, s.code_compta_fournisseur as compta , "; +$sql .= "UNION (SELECT s.rowid, s.nom as name , s.address, s.zip , s.town, , "; +if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= ", spe.accountancy_code_supplier as compta"; +} else { + $sql .= ", s.code_compta_fournisseur as compta"; +} $sql .= " s.fk_forme_juridique , s.fk_pays , s.phone , s.fax , ff.datec , ff.fk_soc , cp.label as country "; $sql .= " FROM ".MAIN_DB_PREFIX."societe as s"; +if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_perentity as spe ON spe.fk_soc = s.rowid AND spe.entity = " . ((int) $conf->entity); +} $sql .= ", ".MAIN_DB_PREFIX."facture_fourn as ff"; $sql .= ", ".MAIN_DB_PREFIX."c_country as cp"; $sql .= " WHERE ff.fk_soc = s.rowid"; From c7fd9328cd0ab47cd138530f719dc0830da05380 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Fri, 8 Oct 2021 06:29:22 +0200 Subject: [PATCH 55/79] NEW Societe - Add perentity functionality on customer/supplier accountancy auxiliary account --- htdocs/accountancy/customer/lines.php | 8 +++---- htdocs/accountancy/supplier/list.php | 6 +++-- htdocs/core/boxes/box_factures_imp.php | 4 ++-- .../societe/mod_codecompta_digitaria.php | 23 +++++++++++++++---- .../install/mysql/migration/14.0.0-15.0.0.sql | 2 +- htdocs/societe/card.php | 3 +++ htdocs/societe/class/societe.class.php | 21 ++++++++--------- 7 files changed, 43 insertions(+), 24 deletions(-) diff --git a/htdocs/accountancy/customer/lines.php b/htdocs/accountancy/customer/lines.php index b833ca887e9..7f09e111a23 100644 --- a/htdocs/accountancy/customer/lines.php +++ b/htdocs/accountancy/customer/lines.php @@ -193,11 +193,11 @@ $sql = "SELECT f.rowid as facid, f.ref as ref, f.type, f.datef, f.ref_client,"; $sql .= " fd.rowid, fd.description, fd.product_type as line_type, fd.total_ht, fd.total_tva, fd.tva_tx, fd.vat_src_code, fd.total_ttc,"; $sql .= " s.rowid as socid, s.nom as name, s.code_client,"; if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { - $sql .= ", spe.accountancy_code_customer as code_compta_client"; - $sql .= ", spe.accountancy_code_supplier as code_compta_fournisseur"; + $sql .= " spe.accountancy_code_customer as code_compta_client,"; + $sql .= " spe.accountancy_code_supplier as code_compta_fournisseur,"; } else { - $sql .= ", s.code_compta as code_compta_client"; - $sql .= ", s.code_compta_fournisseur"; + $sql .= " s.code_compta as code_compta_client,"; + $sql .= " s.code_compta_fournisseur,"; } $sql .= " p.rowid as product_id, p.fk_product_type as product_type, p.ref as product_ref, p.label as product_label,"; if (!empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) { diff --git a/htdocs/accountancy/supplier/list.php b/htdocs/accountancy/supplier/list.php index 13553358cf9..b3cafa7e5fc 100644 --- a/htdocs/accountancy/supplier/list.php +++ b/htdocs/accountancy/supplier/list.php @@ -245,10 +245,12 @@ $sql .= " aa.rowid as aarowid, aa2.rowid as aarowid_intra, aa3.rowid as aarowid_ $sql .= " co.code as country_code, co.label as country_label,"; $sql .= " s.rowid as socid, s.nom as name, s.tva_intra, s.email, s.town, s.zip, s.fk_pays, s.client, s.fournisseur, s.code_client, s.code_fournisseur,"; if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { - $sql .= " spe.accountancy_code_customer as code_compta_client, spe.accountancy_code_supplier as code_compta_fournisseur,"; + $sql .= " spe.accountancy_code_customer as code_compta_client,"; + $sql .= " spe.accountancy_code_supplier as code_compta_fournisseur,"; $sql .= " spe.accountancy_code_buy as company_code_buy"; } else { - $sql .= " s.code_compta as code_compta_client, s.code_compta_fournisseur,"; + $sql .= " s.code_compta as code_compta_client,"; + $sql .= " s.code_compta_fournisseur,"; $sql .= " s.accountancy_code_buy as company_code_buy"; } $parameters = array(); diff --git a/htdocs/core/boxes/box_factures_imp.php b/htdocs/core/boxes/box_factures_imp.php index 434ebec2602..c78e5b7dec9 100644 --- a/htdocs/core/boxes/box_factures_imp.php +++ b/htdocs/core/boxes/box_factures_imp.php @@ -125,9 +125,9 @@ class box_factures_imp extends ModeleBoxes } $sql .= " GROUP BY s.rowid, s.nom, s.name_alias, s.code_client, s.client, s.logo, s.email, s.entity, s.tva_intra, s.siren, s.siret, s.ape, s.idprof4, s.idprof5, s.idprof6,"; if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { - $sql .= " spe.accountancy_code_customer as code_compta"; + $sql .= " spe.accountancy_code_customer as code_compta,"; } else { - $sql .= " s.code_compta"; + $sql .= " s.code_compta,"; } $sql .= " f.ref, f.date_lim_reglement,"; $sql .= " f.type, f.datef, f.total_ht, f.total_tva, f.total_ttc, f.paye, f.fk_statut, f.rowid"; diff --git a/htdocs/core/modules/societe/mod_codecompta_digitaria.php b/htdocs/core/modules/societe/mod_codecompta_digitaria.php index c4887f01383..91f4bff07c4 100644 --- a/htdocs/core/modules/societe/mod_codecompta_digitaria.php +++ b/htdocs/core/modules/societe/mod_codecompta_digitaria.php @@ -252,17 +252,32 @@ class mod_codecompta_digitaria extends ModeleAccountancyCode */ public function checkIfAccountancyCodeIsAlreadyUsed($db, $code, $type = '') { + global $conf; + if ($type == 'supplier') { - $typethirdparty = 'code_compta_fournisseur'; + if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $typethirdparty = 'accountancy_code_supplier'; + } else { + $typethirdparty = 'code_compta_fournisseur'; + } } elseif ($type == 'customer') { - $typethirdparty = 'code_compta'; + if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $typethirdparty = 'accountancy_code_customer'; + } else { + $typethirdparty = 'code_compta'; + } } else { $this->error = 'Bad value for parameter type'; return -1; } - $sql = "SELECT ".$typethirdparty." FROM ".MAIN_DB_PREFIX."societe"; - $sql .= " WHERE ".$typethirdparty." = '".$db->escape($code)."'"; + if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql = "SELECT " . $typethirdparty . " FROM " . MAIN_DB_PREFIX . "societe_perentity"; + $sql .= " WHERE " . $typethirdparty . " = '" . $db->escape($code) . "'"; + } else { + $sql = "SELECT " . $typethirdparty . " FROM " . MAIN_DB_PREFIX . "societe"; + $sql .= " WHERE " . $typethirdparty . " = '" . $db->escape($code) . "'"; + } $resql = $db->query($sql); if ($resql) { diff --git a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql index 9a530147d9e..56ac0290292 100644 --- a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql +++ b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql @@ -373,4 +373,4 @@ ALTER TABLE llx_hrm_skillrank ADD CONSTRAINT llx_hrm_skillrank_fk_user_creat FOR -- Manage accountancy auxiliary account for thirdparties per entity ALTER TABLE llx_societe_perentity ADD COLUMN accountancy_code_customer varchar(24) AFTER entity; -- equivalent to code_compta in llx_societe -ALTER TABLE llx_societe_perentity ADD COLUMN accountancy_code_supplier varchar(24) AFTER accountancy_code_supplier; -- equivalent to code_compta_supplier in llx_societe +ALTER TABLE llx_societe_perentity ADD COLUMN accountancy_code_supplier varchar(24) AFTER accountancy_code_customer; -- equivalent to code_compta_supplier in llx_societe diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index 334793985f0..6399add1af3 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -75,6 +75,9 @@ if (!empty($conf->incoterm->enabled)) { if (!empty($conf->notification->enabled)) { $langs->load("mails"); } +if (!empty($conf->accounting->enabled)) { + $langs->load("products"); +} $error = 0; $errors = array(); diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index d83dd1f3d34..a7db5c1b4bb 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -8,7 +8,7 @@ * Copyright (C) 2008 Patrick Raguin * Copyright (C) 2010-2018 Juanjo Menent * Copyright (C) 2013 Florian Henry - * Copyright (C) 2013 Alexandre Spangaro + * Copyright (C) 2013-2021 Alexandre Spangaro * Copyright (C) 2013 Peter Fontaine * Copyright (C) 2014-2015 Marcos García * Copyright (C) 2015 Raphaël Doursenaud @@ -838,6 +838,8 @@ class Societe extends CommonObject } $this->import_key = trim($this->import_key); + $this->accountancy_code_customer = trim($this->accountancy_code_customer); + $this->accountancy_code_supplier = trim($this->accountancy_code_supplier); $this->accountancy_code_buy = trim($this->accountancy_code_buy); $this->accountancy_code_sell= trim($this->accountancy_code_sell); @@ -922,11 +924,15 @@ class Societe extends CommonObject $sql = "INSERT INTO " . MAIN_DB_PREFIX . "societe_perentity ("; $sql .= " fk_soc"; $sql .= ", entity"; + $sql .= ", accountancy_code_customer"; + $sql .= ", accountancy_code_supplier"; $sql .= ", accountancy_code_buy"; $sql .= ", accountancy_code_sell"; $sql .= ") VALUES ("; $sql .= $this->id; $sql .= ", " . $conf->entity; + $sql .= ", '" . $this->db->escape($this->accountancy_code_customer) . "'"; + $sql .= ", '" . $this->db->escape($this->accountancy_code_supplier) . "'"; $sql .= ", '" . $this->db->escape($this->accountancy_code_buy) . "'"; $sql .= ", '" . $this->db->escape($this->accountancy_code_sell) . "'"; $sql .= ")"; @@ -1553,16 +1559,9 @@ class Societe extends CommonObject $sql .= ") VALUES ("; $sql .= $this->id; $sql .= ", " . $conf->entity; + $sql .= ", '" . $this->db->escape($this->code_compta_client)."'"; + $sql .= ", '" . $this->db->escape($this->code_compta_fournisseur)."'"; $sql .= ", '" . $this->db->escape($this->accountancy_code_buy) . "'"; - - if ($customer) { - $sql .= ", accountancy_code_customer = ".(!empty($this->code_compta_client) ? "'".$this->db->escape($this->code_compta_client)."'" : "null"); - } - - if ($supplier) { - $sql .= ", accountancy_code_supplier = ".(($this->code_compta_fournisseur != "") ? "'".$this->db->escape($this->code_compta_fournisseur)."'" : "null"); - } - $sql .= ", '" . $this->db->escape($this->accountancy_code_sell) . "'"; $sql .= ")"; $result = $this->db->query($sql); @@ -3353,7 +3352,7 @@ class Societe extends CommonObject } /** - * Define parent commany of current company + * Define parent company of current company * * @param int $id Id of thirdparty to set or '' to remove * @return int <0 if KO, >0 if OK From 00eafcb6e709c139ef9c2185595baa427ab6df27 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Fri, 8 Oct 2021 06:50:22 +0200 Subject: [PATCH 56/79] NEW Societe - Add perentity functionality on customer/supplier accountancy auxiliary account --- htdocs/societe/card.php | 40 +++++++++++++------------- htdocs/societe/class/societe.class.php | 27 +++++++++++++++-- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index 6399add1af3..11cc7b55a4d 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -6,7 +6,7 @@ * Copyright (C) 2005-2017 Regis Houssin * Copyright (C) 2008 Patrick Raguin * Copyright (C) 2010-2020 Juanjo Menent - * Copyright (C) 2011-2013 Alexandre Spangaro + * Copyright (C) 2011-2021 Alexandre Spangaro * Copyright (C) 2015 Jean-François Ferry * Copyright (C) 2015 Marcos García * Copyright (C) 2015 Raphaël Doursenaud @@ -446,19 +446,19 @@ if (empty($reshook)) { $object->name = dolGetFirstLastname(GETPOST('firstname', 'alphanohtml'), GETPOST('name', 'alphanohtml')); $object->civility_id = GETPOST('civility_id', 'alphanohtml'); // Note: civility id is a code, not an int // Add non official properties - $object->name_bis = GETPOST('name', 'alphanohtml'); - $object->firstname = GETPOST('firstname', 'alphanohtml'); + $object->name_bis = GETPOST('name', 'alphanohtml'); + $object->firstname = GETPOST('firstname', 'alphanohtml'); } else { - $object->name = GETPOST('name', 'alphanohtml'); + $object->name = GETPOST('name', 'alphanohtml'); } $object->entity = (GETPOSTISSET('entity') ? GETPOST('entity', 'int') : $conf->entity); - $object->name_alias = GETPOST('name_alias', 'alphanohtml'); + $object->name_alias = GETPOST('name_alias', 'alphanohtml'); $object->address = GETPOST('address', 'alphanohtml'); - $object->zip = GETPOST('zipcode', 'alphanohtml'); - $object->town = GETPOST('town', 'alphanohtml'); - $object->country_id = GETPOST('country_id', 'int'); - $object->state_id = GETPOST('state_id', 'int'); - //$object->skype = GETPOST('skype', 'alpha'); + $object->zip = GETPOST('zipcode', 'alphanohtml'); + $object->town = GETPOST('town', 'alphanohtml'); + $object->country_id = GETPOST('country_id', 'int'); + $object->state_id = GETPOST('state_id', 'int'); + //$object->skype = GETPOST('skype', 'alpha'); //$object->twitter = GETPOST('twitter', 'alpha'); //$object->facebook = GETPOST('facebook', 'alpha'); //$object->linkedin = GETPOST('linkedin', 'alpha'); @@ -470,9 +470,9 @@ if (empty($reshook)) { } } } - $object->phone = GETPOST('phone', 'alpha'); + $object->phone = GETPOST('phone', 'alpha'); $object->fax = GETPOST('fax', 'alpha'); - $object->email = trim(GETPOST('email', 'custom', 0, FILTER_SANITIZE_EMAIL)); + $object->email = trim(GETPOST('email', 'custom', 0, FILTER_SANITIZE_EMAIL)); $object->url = trim(GETPOST('url', 'custom', 0, FILTER_SANITIZE_URL)); $object->idprof1 = trim(GETPOST('idprof1', 'alphanohtml')); $object->idprof2 = trim(GETPOST('idprof2', 'alphanohtml')); @@ -482,7 +482,7 @@ if (empty($reshook)) { $object->idprof6 = trim(GETPOST('idprof6', 'alphanohtml')); $object->prefix_comm = GETPOST('prefix_comm', 'alphanohtml'); $object->code_client = GETPOSTISSET('customer_code') ?GETPOST('customer_code', 'alpha') : GETPOST('code_client', 'alpha'); - $object->code_fournisseur = GETPOSTISSET('supplier_code') ?GETPOST('supplier_code', 'alpha') : GETPOST('code_fournisseur', 'alpha'); + $object->code_fournisseur = GETPOSTISSET('supplier_code') ?GETPOST('supplier_code', 'alpha') : GETPOST('code_fournisseur', 'alpha'); $object->capital = GETPOST('capital', 'alphanohtml'); $object->barcode = GETPOST('barcode', 'alphanohtml'); @@ -497,24 +497,24 @@ if (empty($reshook)) { $object->localtax1_value = GETPOST('lt1', 'alpha'); $object->localtax2_value = GETPOST('lt2', 'alpha'); - $object->forme_juridique_code = GETPOST('forme_juridique_code', 'int'); + $object->forme_juridique_code = GETPOST('forme_juridique_code', 'int'); $object->effectif_id = GETPOST('effectif_id', 'int'); - $object->typent_id = GETPOST('typent_id', 'int'); + $object->typent_id = GETPOST('typent_id', 'int'); $object->typent_code = dol_getIdFromCode($db, $object->typent_id, 'c_typent', 'id', 'code'); // Force typent_code too so check in verify() will be done on new type - $object->client = GETPOST('client', 'int'); + $object->client = GETPOST('client', 'int'); $object->fournisseur = GETPOST('fournisseur', 'int'); - $object->commercial_id = GETPOST('commercial_id', 'int'); - $object->default_lang = GETPOST('default_lang'); + $object->commercial_id = GETPOST('commercial_id', 'int'); + $object->default_lang = GETPOST('default_lang'); // Webservices url/key $object->webservices_url = GETPOST('webservices_url', 'custom', 0, FILTER_SANITIZE_URL); $object->webservices_key = GETPOST('webservices_key', 'san_alpha'); if (GETPOSTISSET('accountancy_code_sell')) { - $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha'); + $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha'); if (empty($accountancy_code_sell) || $accountancy_code_sell == '-1') { $object->accountancy_code_sell = ''; @@ -523,7 +523,7 @@ if (empty($reshook)) { } } if (GETPOSTISSET('accountancy_code_buy')) { - $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha'); + $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha'); if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') { $object->accountancy_code_buy = ''; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index a7db5c1b4bb..a1c1dae1ffb 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -563,11 +563,23 @@ class Societe extends CommonObject public $code_compta_client; /** - * Accounting code for suppliers + * Accounting code for customer + * @var string + */ + public $accountancy_code_customer; + + /** + * Accounting code for supplier * @var string */ public $code_compta_fournisseur; + /** + * Accounting code for supplier + * @var string + */ + public $accountancy_code_supplier; + /** * @var string * @deprecated Note is split in public and private notes @@ -838,8 +850,8 @@ class Societe extends CommonObject } $this->import_key = trim($this->import_key); - $this->accountancy_code_customer = trim($this->accountancy_code_customer); - $this->accountancy_code_supplier = trim($this->accountancy_code_supplier); + $this->accountancy_code_customer = trim($this->code_compta); + $this->accountancy_code_supplier = trim($this->code_compta_fournisseur); $this->accountancy_code_buy = trim($this->accountancy_code_buy); $this->accountancy_code_sell= trim($this->accountancy_code_sell); @@ -2027,6 +2039,15 @@ class Societe extends CommonObject // Remove third party if (!$error) { + if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."societe_perentity"; + $sql .= " WHERE fk_soc = ".((int) $id); + if (!$this->db->query($sql)) { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } + $sql = "DELETE FROM ".MAIN_DB_PREFIX."societe"; $sql .= " WHERE rowid = ".((int) $id); if (!$this->db->query($sql)) { From 36aff803879fc3ab4b455277fcb20777825c3b3d Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 09:12:48 +0200 Subject: [PATCH 57/79] FIX : travis --- htdocs/hrm/evaluation_list.php | 2 +- htdocs/hrm/job_list.php | 2 +- htdocs/hrm/position_list.php | 2 +- htdocs/hrm/skill_list.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/hrm/evaluation_list.php b/htdocs/hrm/evaluation_list.php index 589dbb0dcfd..c99275bf784 100644 --- a/htdocs/hrm/evaluation_list.php +++ b/htdocs/hrm/evaluation_list.php @@ -268,7 +268,7 @@ $sql .= $object->getFieldList('t'); // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$db->escape($key).' as options_'.$db->escape($key).', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key.', ' : ''); } } // Add fields from hooks diff --git a/htdocs/hrm/job_list.php b/htdocs/hrm/job_list.php index c1752c9dea7..2fe052c3cb5 100644 --- a/htdocs/hrm/job_list.php +++ b/htdocs/hrm/job_list.php @@ -268,7 +268,7 @@ $sql .= $object->getFieldList('t'); // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$db->escape($key).' as options_'.$db->escape($key).', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key.', ' : ''); } } // Add fields from hooks diff --git a/htdocs/hrm/position_list.php b/htdocs/hrm/position_list.php index 54323a967e0..85fd5365598 100644 --- a/htdocs/hrm/position_list.php +++ b/htdocs/hrm/position_list.php @@ -268,7 +268,7 @@ $sql .= $object->getFieldList('t'); // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$db->escape($key).' as options_'.$db->escape($key).', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key.', ' : ''); } } // Add fields from hooks diff --git a/htdocs/hrm/skill_list.php b/htdocs/hrm/skill_list.php index a228e7c9c6e..bef3c07c770 100644 --- a/htdocs/hrm/skill_list.php +++ b/htdocs/hrm/skill_list.php @@ -268,7 +268,7 @@ $sql .= $object->getFieldList('t'); // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$db->escape($key).' as options_'.$db->escape($key).', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key.', ' : ''); } } // Add fields from hooks From eb5c7d1f6f11c63357882b6670cf5493a19238c9 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 09:22:35 +0200 Subject: [PATCH 58/79] FIX : travis --- htdocs/hrm/evaluation_list.php | 2 +- htdocs/hrm/job_list.php | 2 +- htdocs/hrm/position_list.php | 2 +- htdocs/hrm/skill_list.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/hrm/evaluation_list.php b/htdocs/hrm/evaluation_list.php index c99275bf784..9ec102c45ea 100644 --- a/htdocs/hrm/evaluation_list.php +++ b/htdocs/hrm/evaluation_list.php @@ -332,7 +332,7 @@ $sql .= $hookmanager->resPrint; /* If a group by is required $sql .= " GROUP BY "; foreach($object->fields as $key => $val) { - $sql .= 't.'.$key.', '; + $sql .= "t.".$key.", "; } // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { diff --git a/htdocs/hrm/job_list.php b/htdocs/hrm/job_list.php index 2fe052c3cb5..fdf2de51d45 100644 --- a/htdocs/hrm/job_list.php +++ b/htdocs/hrm/job_list.php @@ -332,7 +332,7 @@ $sql .= $hookmanager->resPrint; /* If a group by is required $sql .= " GROUP BY "; foreach($object->fields as $key => $val) { - $sql .= 't.'.$key.', '; + $sql .= "t.".$key.", "; } // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { diff --git a/htdocs/hrm/position_list.php b/htdocs/hrm/position_list.php index 85fd5365598..725948c4b3f 100644 --- a/htdocs/hrm/position_list.php +++ b/htdocs/hrm/position_list.php @@ -332,7 +332,7 @@ $sql .= $hookmanager->resPrint; /* If a group by is required $sql .= " GROUP BY "; foreach($object->fields as $key => $val) { - $sql .= 't.'.$key.', '; + $sql .= "t.".$key.", "; } // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { diff --git a/htdocs/hrm/skill_list.php b/htdocs/hrm/skill_list.php index bef3c07c770..19460326a67 100644 --- a/htdocs/hrm/skill_list.php +++ b/htdocs/hrm/skill_list.php @@ -332,7 +332,7 @@ $sql .= $hookmanager->resPrint; /* If a group by is required $sql .= " GROUP BY "; foreach($object->fields as $key => $val) { - $sql .= 't.'.$key.', '; + $sql .= "t.".$key.", "; } // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { From 47e1d4f86739fdb2fbae9b36333ef3554ade94be Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 09:39:04 +0200 Subject: [PATCH 59/79] FIX : useless function --- htdocs/hrm/lib/hrm_skill.lib.php | 427 ------------------------------- 1 file changed, 427 deletions(-) diff --git a/htdocs/hrm/lib/hrm_skill.lib.php b/htdocs/hrm/lib/hrm_skill.lib.php index a2393229cb5..c9c83fa6411 100644 --- a/htdocs/hrm/lib/hrm_skill.lib.php +++ b/htdocs/hrm/lib/hrm_skill.lib.php @@ -93,430 +93,3 @@ function skillPrepareHead($object) return $head; } - - -/** - * Show html area for list of traduction - * - * @param Conf $conf Object conf - * @param Translate $langs Object langs - * @param DoliDB $db Database handler - * @param Societe $object Third party object - * @param string $backtopage Url to go once contact is created - * @return int - */ -function show_traduction($conf, $langs, $db, $object, $backtopage = '') -{ - global $user, $conf, $extrafields, $hookmanager; - global $contextpage; - - require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; - $formcompany = new FormCompany($db); - $form = new Form($db); - - $optioncss = GETPOST('optioncss', 'alpha'); - $sortfield = GETPOST("sortfield", 'alpha'); - $sortorder = GETPOST("sortorder", 'alpha'); - $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); - - $search_status = GETPOST("search_status", 'int'); - if ($search_status == '') { - $search_status = 1; // always display active customer first - } - - $search_name = GETPOST("search_name", 'alpha'); - $search_address = GETPOST("search_address", 'alpha'); - $search_poste = GETPOST("search_poste", 'alpha'); - $search_roles = GETPOST("search_roles", 'array'); - - $socialnetworks = getArrayOfSocialNetworks(); - - $searchAddressPhoneDBFields = array( - //Address - 't.address', - 't.zip', - 't.town', - - //Phone - 't.phone', - 't.phone_perso', - 't.phone_mobile', - - //Fax - 't.fax', - - //E-mail - 't.email', - ); - //Social media - // foreach ($socialnetworks as $key => $value) { - // if ($value['active']) { - // $searchAddressPhoneDBFields['t.'.$key] = "t.socialnetworks->'$.".$key."'"; - // } - // } - - if (!$sortorder) { - $sortorder = "ASC"; - } - if (!$sortfield) { - $sortfield = "t.lastname"; - } - - if (!empty($conf->clicktodial->enabled)) { - $user->fetch_clicktodial(); // lecture des infos de clicktodial du user - } - - - $SkillLinestatic = new SkillLine($db); - - $extrafields->fetch_name_optionals_label($SkillLinestatic->table_element); - - $SkillLinestatic->fields=array( - 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"), - 'fk_skill' => array('type'=>'integer:Skill:skill/class/skill.class.php', 'label'=>'foreign key skill', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',), - 'traduction_note' => array('type'=>'text', 'label'=>'traduction_note', 'enabled'=>'1', 'position'=>56, 'notnull'=>0, 'visible'=>1,), - 'rank' => array('type'=>'integer', 'label'=>'rank', 'enabled'=>'1', 'position'=>55, 'notnull'=>1, 'visible'=>1, 'index'=>1,), - ); - - // Definition of fields for list - $arrayfields = array( - 't.rowid'=>array('label'=>"TechnicalID", 'checked'=>(!empty($conf->global->MAIN_SHOW_TECHNICAL_ID) ? 1 : 0), 'enabled'=>(!empty($conf->global->MAIN_SHOW_TECHNICAL_ID) ? 1 : 0), 'position'=>1), - 't.name'=>array('label'=>"Name", 'checked'=>1, 'position'=>10), - 't.poste'=>array('label'=>"PostOrFunction", 'checked'=>1, 'position'=>20), - 't.address'=>array('label'=>(empty($conf->dol_optimize_smallscreen) ? $langs->trans("Address").' / '.$langs->trans("Phone").' / '.$langs->trans("Email") : $langs->trans("Address")), 'checked'=>1, 'position'=>30), - 'sc.role'=>array('label'=>"ContactByDefaultFor", 'checked'=>1, 'position'=>40), - 't.statut'=>array('label'=>"Status", 'checked'=>1, 'position'=>50, 'class'=>'center'), - ); - // Extra fields - if (!empty($extrafields->attributes[$contactstatic->table_element]['label']) && is_array($extrafields->attributes[$contactstatic->table_element]['label']) && count($extrafields->attributes[$contactstatic->table_element]['label'])) { - foreach ($extrafields->attributes[$contactstatic->table_element]['label'] as $key => $val) { - if (!empty($extrafields->attributes[$contactstatic->table_element]['list'][$key])) { - $arrayfields["ef.".$key] = array( - 'label'=>$extrafields->attributes[$contactstatic->table_element]['label'][$key], - 'checked'=>(($extrafields->attributes[$contactstatic->table_element]['list'][$key] < 0) ? 0 : 1), - 'position'=>1000 + $extrafields->attributes[$contactstatic->table_element]['pos'][$key], - 'enabled'=>(abs($extrafields->attributes[$contactstatic->table_element]['list'][$key]) != 3 && $extrafields->attributes[$contactstatic->table_element]['perms'][$key])); - } - } - } - - // Initialize array of search criterias - $search = array(); - foreach ($arrayfields as $key => $val) { - $queryName = 'search_'.substr($key, 2); - if (GETPOST($queryName, 'alpha')) { - $search[substr($key, 2)] = GETPOST($queryName, 'alpha'); - } - } - $search_array_options = $extrafields->getOptionalsFromPost($contactstatic->table_element, '', 'search_'); - - // Purge search criteria - if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers - $search_status = ''; - $search_name = ''; - $search_roles = array(); - $search_address = ''; - $search_poste = ''; - $search = array(); - $search_array_options = array(); - - foreach ($contactstatic->fields as $key => $val) { - $search[$key] = ''; - } - } - - $contactstatic->fields = dol_sort_array($contactstatic->fields, 'position'); - $arrayfields = dol_sort_array($arrayfields, 'position'); - - $newcardbutton = ''; - if ($user->rights->societe->contact->creer) { - $addTraduction = $langs->trans("AddTraduction"); - $newcardbutton .= dolGetButtonTitle($addTraduction, '', 'fa fa-plus-circle', DOL_URL_ROOT.'/skilldet/card.php?skillid='.$object->id.'&action=create&backtopage='.urlencode($backtopage)); - } - - print "\n"; - - $title = $langs->trans("TraductionRule"); - print load_fiche_titre($title, $newcardbutton, ''); - - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - - $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; - $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields - //if ($massactionbutton) $selectedfields.=$form->showCheckAddButtons('checkforselect', 1); - - print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table - print "\n".''."\n"; - - $param = "socid=".urlencode($object->id); - if ($search_status != '') { - $param .= '&search_status='.urlencode($search_status); - } - if (count($search_roles) > 0) { - $param .= implode('&search_roles[]=', $search_roles); - } - if ($search_name != '') { - $param .= '&search_name='.urlencode($search_name); - } - if ($search_poste != '') { - $param .= '&search_poste='.urlencode($search_poste); - } - if ($search_address != '') { - $param .= '&search_address='.urlencode($search_address); - } - if ($optioncss != '') { - $param .= '&optioncss='.urlencode($optioncss); - } - - // Add $param from extra fields - $extrafieldsobjectkey = $contactstatic->table_element; - include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; - - $sql = "SELECT t.rowid, t.lastname, t.firstname, t.fk_pays as country_id, t.civility, t.poste, t.phone as phone_pro, t.phone_mobile, t.phone_perso, t.fax, t.email, t.socialnetworks, t.statut, t.photo,"; - $sql .= " t.civility as civility_id, t.address, t.zip, t.town"; - $sql .= " FROM ".MAIN_DB_PREFIX."socpeople as t"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople_extrafields as ef on (t.rowid = ef.fk_object)"; - $sql .= " WHERE t.fk_soc = ".$object->id; - if ($search_status != '' && $search_status != '-1') { - $sql .= " AND t.statut = ".$db->escape($search_status); - } - if ($search_name) { - $sql .= natural_search(array('t.lastname', 't.firstname'), $search_name); - } - if ($search_poste) { - $sql .= natural_search('t.poste', $search_poste); - } - if ($search_address) { - $sql .= natural_search($searchAddressPhoneDBFields, $search_address); - } - if (count($search_roles) > 0) { - $sql .= " AND t.rowid IN (SELECT sc.fk_socpeople FROM ".MAIN_DB_PREFIX."societe_contacts as sc WHERE sc.fk_c_type_contact IN (".$db->sanitize(implode(',', $search_roles))."))"; - } - // Add where from extra fields - $extrafieldsobjectkey = $contactstatic->table_element; - include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; - if ($sortfield == "t.name") { - $sql .= " ORDER BY t.lastname $sortorder, t.firstname $sortorder"; - } else { - $sql .= " ORDER BY $sortfield $sortorder"; - } - - dol_syslog('core/lib/company.lib.php :: show_contacts', LOG_DEBUG); - $result = $db->query($sql); - if (!$result) { - dol_print_error($db); - } - - $num = $db->num_rows($result); - - // Fields title search - // -------------------------------------------------------------------- - print ''; - foreach ($contactstatic->fields as $key => $val) { - $align = ''; - if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { - $align .= ($align ? ' ' : '').'center'; - } - if (in_array($val['type'], array('timestamp'))) { - $align .= ($align ? ' ' : '').'nowrap'; - } - if ($key == 'status' || $key == 'statut') { - $align .= ($align ? ' ' : '').'center'; - } - if (!empty($arrayfields['t.'.$key]['checked']) || !empty($arrayfields['sc.'.$key]['checked'])) { - print ''; - } - } - // Extra fields - $extrafieldsobjectkey = $contactstatic->table_element; - include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; - - // Fields from hook - $parameters = array('arrayfields'=>$arrayfields); - $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $contactstatic); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; - // Action column - print ''; - print ''."\n"; - - - // Fields title label - // -------------------------------------------------------------------- - print ''; - foreach ($contactstatic->fields as $key => $val) { - $align = ''; - if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { - $align .= ($align ? ' ' : '').'center'; - } - if (in_array($val['type'], array('timestamp'))) { - $align .= ($align ? ' ' : '').'nowrap'; - } - if ($key == 'status' || $key == 'statut') { - $align .= ($align ? ' ' : '').'center'; - } - if (!empty($arrayfields['t.'.$key]['checked'])) { - print getTitleFieldOfList($val['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($align ? 'class="'.$align.'"' : ''), $sortfield, $sortorder, $align.' ')."\n"; - } - if ($key == 'role') { - $align .= ($align ? ' ' : '').'left'; - } - if (!empty($arrayfields['sc.'.$key]['checked'])) { - print getTitleFieldOfList($arrayfields['sc.'.$key]['label'], 0, $_SERVER['PHP_SELF'], '', '', $param, ($align ? 'class="'.$align.'"' : ''), $sortfield, $sortorder, $align.' ')."\n"; - } - } - // Extra fields - $extrafieldsobjectkey = $contactstatic->table_element; - include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; - // Hook fields - $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); - $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; - print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ')."\n"; - print ''."\n"; - - $i = -1; - - if ($num || (GETPOST('button_search') || GETPOST('button_search.x') || GETPOST('button_search_x'))) { - $i = 0; - - while ($i < $num) { - $obj = $db->fetch_object($result); - - $contactstatic->id = $obj->rowid; - $contactstatic->ref = $obj->rowid; - $contactstatic->statut = $obj->statut; - $contactstatic->lastname = $obj->lastname; - $contactstatic->firstname = $obj->firstname; - $contactstatic->civility_id = $obj->civility_id; - $contactstatic->civility_code = $obj->civility_id; - $contactstatic->poste = $obj->poste; - $contactstatic->address = $obj->address; - $contactstatic->zip = $obj->zip; - $contactstatic->town = $obj->town; - $contactstatic->phone_pro = $obj->phone_pro; - $contactstatic->phone_mobile = $obj->phone_mobile; - $contactstatic->phone_perso = $obj->phone_perso; - $contactstatic->email = $obj->email; - $contactstatic->socialnetworks = $obj->socialnetworks; - $contactstatic->photo = $obj->photo; - - $country_code = getCountry($obj->country_id, 2); - $contactstatic->country_code = $country_code; - - $contactstatic->setGenderFromCivility(); - $contactstatic->fetch_optionals(); - - $resultRole = $contactstatic->fetchRoles(); - if ($resultRole < 0) { - setEventMessages(null, $contactstatic->errors, 'errors'); - } - - if (is_array($contactstatic->array_options)) { - foreach ($contactstatic->array_options as $key => $val) { - $obj->$key = $val; - } - } - - print ''; - - // ID - if (!empty($arrayfields['t.rowid']['checked'])) { - print ''; - } - - // Photo - Name - if (!empty($arrayfields['t.name']['checked'])) { - print ''; - } - - // Job position - if (!empty($arrayfields['t.poste']['checked'])) { - print ''; - } - - // Address - Phone - Email - if (!empty($arrayfields['t.address']['checked'])) { - print ''; - } - - // Role - if (!empty($arrayfields['sc.role']['checked'])) { - print ''; - } - - // Status - if (!empty($arrayfields['t.statut']['checked'])) { - print ''; - } - - // Extra fields - $extrafieldsobjectkey = $contactstatic->table_element; - include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; - - // Actions - print ''; - - print "\n"; - $i++; - } - } else { - $colspan = 1; - foreach ($arrayfields as $key => $val) { - if (!empty($val['checked'])) { - $colspan++; - } - } - print ''; - } - print "\n
    '; - if (in_array($key, array('statut'))) { - print $form->selectarray('search_status', array('-1'=>'', '0'=>$contactstatic->LibStatut(0, 1), '1'=>$contactstatic->LibStatut(1, 1)), $search_status); - } elseif (in_array($key, array('role'))) { - print $formcompany->showRoles("search_roles", $contactstatic, 'edit', $search_roles); - } else { - print ''; - } - print ''; - print $form->showFilterButtons(); - print '
    '; - print $contactstatic->id; - print ''; - print $form->showphoto('contact', $contactstatic, 0, 0, 0, 'photorefnoborder valignmiddle marginrightonly', 'small', 1, 0, 1); - print $contactstatic->getNomUrl(0, '', 0, '&backtopage='.urlencode($backtopage)); - print ''; - if ($obj->poste) { - print $obj->poste; - } - print ''; - print $contactstatic->getBannerAddress('contact', $object); - print ''; - print $formcompany->showRoles("roles", $contactstatic, 'view'); - print ''.$contactstatic->getLibStatut(5).''; - - // Add to agenda - if (!empty($conf->agenda->enabled) && $user->rights->agenda->myactions->create) { - print ''; - print img_object($langs->trans("Event"), "action"); - print '   '; - } - - // Edit - if ($user->rights->societe->contact->creer) { - print ''; - print img_edit(); - print ''; - } - - print '
    '.$langs->trans("None").'
    \n"; - print '
    '; - - print ''."\n"; - - return $i; -} From e00dcb4f736723cab3ba66ea060b167f5948a9d2 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 09:48:17 +0200 Subject: [PATCH 60/79] FIX : travis --- htdocs/hrm/position.php | 2 +- htdocs/hrm/skill_card.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index 0fcc817c8c9..f17676dc5d9 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -479,7 +479,7 @@ function DisplayPositionList() } else { $sql .= " WHERE 1 = 1"; } - $sql .= " AND t.fk_job = " . $fk_job . " "; + $sql .= " AND t.fk_job = " . ((int) $fk_job) . " "; foreach ($search as $key => $val) { if (array_key_exists($key, $object->fields)) { diff --git a/htdocs/hrm/skill_card.php b/htdocs/hrm/skill_card.php index 7d45ab152a0..c0d3d67ccab 100644 --- a/htdocs/hrm/skill_card.php +++ b/htdocs/hrm/skill_card.php @@ -627,7 +627,7 @@ if ($action != "create" && $action != "edit") { } if (!empty($id)) { - $sql .= " AND fk_skill = " . $id . " "; + $sql .= " AND fk_skill = " . ((int) $id) . " "; } // if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. From 0f6d29549b60b329ed0628212993ec43224b4b84 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 09:57:33 +0200 Subject: [PATCH 61/79] FIX : travis --- htdocs/hrm/position.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index f17676dc5d9..14ed85466c0 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -458,7 +458,7 @@ function DisplayPositionList() // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef." . $key . ' as options_' . $key . ', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef." . $key . " as options_" . $key . ', ' : ''); } } // Add fields from hooks From 03d7a8e946ff500108b6b6040858bbf9da4c6436 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 10:04:35 +0200 Subject: [PATCH 62/79] FIX : travis --- htdocs/hrm/position.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index 14ed85466c0..8eec7d0e660 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -524,7 +524,7 @@ function DisplayPositionList() /* If a group by is required $sql .= " GROUP BY "; foreach($object->fields as $key => $val) { - $sql .= 't.'.$key.', '; + $sql .= "t.".$key.", "; } // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { From 1329df69c615dff09490f7aa6b6a273eae350ce3 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 10:13:19 +0200 Subject: [PATCH 63/79] FIX : travis --- htdocs/hrm/skill_tab.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php index 5e4b33345b7..355374b6d7c 100644 --- a/htdocs/hrm/skill_tab.php +++ b/htdocs/hrm/skill_tab.php @@ -178,7 +178,7 @@ if (empty($reshook)) { } else if ($action == 'saveSkill') { if (!empty($TNote)) { foreach ($TNote as $skillId => $rank) { - $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . " AND objecttype='" . $objecttype . "' AND fk_skill = " . $skillId)); + $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . " AND objecttype='" . $objecttype . "' AND fk_skill = " . ((int) $skillId))); if (is_array($TSkills) && !empty($TSkills)) { foreach ($TSkills as $tmpObj) { $tmpObj->rank = $rank; From f4ffeacba8ffa429459a78ef05ba6da9b468715c Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 10:20:27 +0200 Subject: [PATCH 64/79] FIX : travis --- htdocs/hrm/skill_tab.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php index 355374b6d7c..d0b3af9ca1f 100644 --- a/htdocs/hrm/skill_tab.php +++ b/htdocs/hrm/skill_tab.php @@ -178,7 +178,7 @@ if (empty($reshook)) { } else if ($action == 'saveSkill') { if (!empty($TNote)) { foreach ($TNote as $skillId => $rank) { - $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . " AND objecttype='" . $objecttype . "' AND fk_skill = " . ((int) $skillId))); + $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . ((int) $id) . " AND objecttype='" . $objecttype . "' AND fk_skill = " . ((int) $skillId))); if (is_array($TSkills) && !empty($TSkills)) { foreach ($TSkills as $tmpObj) { $tmpObj->rank = $rank; @@ -283,7 +283,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } // table of skillRank linked to current object - $TSkillsJob = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . $id . " AND objecttype='" . $objecttype . "'")); + $TSkillsJob = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . ((int) $id) . " AND objecttype='" . $objecttype . "'")); $TAlreadyUsedSkill = array(); if (is_array($TSkillsJob) && !empty($TSkillsJob)) { From 82a299538b3242f989c7b473b67db64d6f87817a Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 10:56:51 +0200 Subject: [PATCH 65/79] FIX : travis --- htdocs/hrm/skill_tab.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php index d0b3af9ca1f..8cdf79f4bdf 100644 --- a/htdocs/hrm/skill_tab.php +++ b/htdocs/hrm/skill_tab.php @@ -178,7 +178,7 @@ if (empty($reshook)) { } else if ($action == 'saveSkill') { if (!empty($TNote)) { foreach ($TNote as $skillId => $rank) { - $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . ((int) $id) . " AND objecttype='" . $objecttype . "' AND fk_skill = " . ((int) $skillId))); + $TSkills = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . ((int) $id) . " AND objecttype='" . $db->escape($objecttype) . "' AND fk_skill = " . ((int) $skillId))); if (is_array($TSkills) && !empty($TSkills)) { foreach ($TSkills as $tmpObj) { $tmpObj->rank = $rank; @@ -283,7 +283,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } // table of skillRank linked to current object - $TSkillsJob = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . ((int) $id) . " AND objecttype='" . $objecttype . "'")); + $TSkillsJob = $skill->fetchAll('ASC', 't.rowid', 0, 0, array('customsql' => 'fk_object=' . ((int) $id) . " AND objecttype='" . $db->escape($objecttype) . "'")); $TAlreadyUsedSkill = array(); if (is_array($TSkillsJob) && !empty($TSkillsJob)) { From 6c548d064fabc44a97fd7e0743f5578246313480 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 11:47:35 +0200 Subject: [PATCH 66/79] FIX : IHM --- htdocs/hrm/evaluation_card.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/hrm/evaluation_card.php b/htdocs/hrm/evaluation_card.php index 72ed1761947..64b54b4c80b 100644 --- a/htdocs/hrm/evaluation_card.php +++ b/htdocs/hrm/evaluation_card.php @@ -623,8 +623,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print '' . $langs->trans("TypeSkill") . ' '; print '' . $langs->trans("Label") . ''; print '' . $langs->trans("Description") . ''; - print '' . $langs->trans("UserRank") . ''; - print '' . $langs->trans("RequiredRank") . ''; + print '' . $langs->trans("EmployeeRank") . ''; + print '' . $langs->trans("RequiredRank") . ''; print '' . $langs->trans("Result") . ''; print ''; @@ -635,8 +635,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ' ' . Skill::typeCodeToLabel($t->skill_type) . ''; print ' ' . $sk->getNomUrl(1) . ''; print ' ' . $t->description . ''; - print ' ' . $t->userRankForSkill . ''; - print ' ' . $t->required_rank . ''; + print ' ' . $t->userRankForSkill . ''; + print ' ' . $t->required_rank . ''; print ' ' . $t->result . ''; print ''; } From 3c5bf190a19bac5368ac3e8a65db54dd045125c7 Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Fri, 8 Oct 2021 11:56:35 +0200 Subject: [PATCH 67/79] FIX : langs --- htdocs/hrm/core/tpl/objectline_title.tpl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/core/tpl/objectline_title.tpl.php b/htdocs/hrm/core/tpl/objectline_title.tpl.php index d33f0923335..3801288543a 100644 --- a/htdocs/hrm/core/tpl/objectline_title.tpl.php +++ b/htdocs/hrm/core/tpl/objectline_title.tpl.php @@ -65,7 +65,7 @@ print ''.$langs->trans('Label').''; print ''.$langs->trans('Description').''; // Note -print ''.$langs->trans('rank').''; +print ''.$langs->trans('EmployeeRank').''; //print ''; // No width to allow autodim From 7ffa8a14abd87b8e56a0e661818c9ed9e91dcd8b Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 8 Oct 2021 13:10:44 +0200 Subject: [PATCH 68/79] fix: option COMPANY_SHOW_ADDRESS_SELECTLIST and SOCIETE_ADD_REF_IN_LIST work in ajaxcompanies --- htdocs/societe/ajax/ajaxcompanies.php | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/htdocs/societe/ajax/ajaxcompanies.php b/htdocs/societe/ajax/ajaxcompanies.php index 9295c363206..60448dbd875 100644 --- a/htdocs/societe/ajax/ajaxcompanies.php +++ b/htdocs/societe/ajax/ajaxcompanies.php @@ -88,7 +88,17 @@ if (GETPOST('newcompany') || GETPOST('socid', 'int') || GETPOST('id_fourn', 'int } $sql = "SELECT rowid, nom"; + if (!empty($conf->global->SOCIETE_ADD_REF_IN_LIST)) { + $sql .= "s.client, s.fournisseur, s.code_client, s.code_fournisseur"; + } + if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) { + $sql .= ", s.address, s.zip, s.town"; + $sql .= ", dictp.code as country_code"; + } $sql .= " FROM ".MAIN_DB_PREFIX."societe as s"; + if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid = s.fk_pays"; + } $sql .= " WHERE s.entity IN (".getEntity('societe').")"; if ($socid) { $sql .= " AND ("; @@ -114,7 +124,22 @@ if (GETPOST('newcompany') || GETPOST('socid', 'int') || GETPOST('id_fourn', 'int $resql = $db->query($sql); if ($resql) { while ($row = $db->fetch_array($resql)) { - $label = $row['nom']; + $label = ''; + if ($conf->global->SOCIETE_ADD_REF_IN_LIST) { + if (($row['client']) && (!empty($row['code_client']))) { + $label = $row['code_client'].' - '; + } + if (($row['fournisseur']) && (!empty($row['code_fournisseur']))) { + $label .= $row['code_fournisseur'].' - '; + } + $label .= ' '.$row['name']; + } + if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) { + $label .= ($row['address'] ? ' - '.$row['address'] : '').($row['zip'] ? ' - '.$row['zip'] : '').($row['town'] ? ' '.$row['town'] : ''); + if (!empty($row['country_code'])) { + $label .= ', '.$langs->trans('Country'.$row['country_code']); + } + } if ($socid) { $label = preg_replace('/('.preg_quote($socid, '/').')/i', '$1', $label, 1); } From 0d47797be7015d1254aff23df1a2d402759f5a1a Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 8 Oct 2021 13:14:08 +0200 Subject: [PATCH 69/79] fix sql --- htdocs/societe/ajax/ajaxcompanies.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/societe/ajax/ajaxcompanies.php b/htdocs/societe/ajax/ajaxcompanies.php index 60448dbd875..89aa4f524b6 100644 --- a/htdocs/societe/ajax/ajaxcompanies.php +++ b/htdocs/societe/ajax/ajaxcompanies.php @@ -87,9 +87,9 @@ if (GETPOST('newcompany') || GETPOST('socid', 'int') || GETPOST('id_fourn', 'int $socid = GETPOST('id_fourn', 'int'); } - $sql = "SELECT rowid, nom"; + $sql = "SELECT s.rowid, s.nom"; if (!empty($conf->global->SOCIETE_ADD_REF_IN_LIST)) { - $sql .= "s.client, s.fournisseur, s.code_client, s.code_fournisseur"; + $sql .= ", s.client, s.fournisseur, s.code_client, s.code_fournisseur"; } if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) { $sql .= ", s.address, s.zip, s.town"; From 5d393f201c80720d0e01e58ff3439c91115d4d05 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 8 Oct 2021 13:17:09 +0200 Subject: [PATCH 70/79] fix sql --- htdocs/core/class/html.formcompany.class.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/html.formcompany.class.php b/htdocs/core/class/html.formcompany.class.php index d1fc8f65edb..1c188792a09 100644 --- a/htdocs/core/class/html.formcompany.class.php +++ b/htdocs/core/class/html.formcompany.class.php @@ -700,8 +700,18 @@ class FormCompany extends Form return $socid; } else { // Search to list thirdparties - $sql = "SELECT s.rowid, s.nom as name FROM"; - $sql .= " ".MAIN_DB_PREFIX."societe as s"; + $sql = "SELECT s.rowid, s.nom as name "; + if (!empty($conf->global->SOCIETE_ADD_REF_IN_LIST)) { + $sql .= ", s.code_client, s.code_fournisseur"; + } + if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) { + $sql .= ", s.address, s.zip, s.town"; + $sql .= ", dictp.code as country_code"; + } + $sql .= " FROM ".MAIN_DB_PREFIX."societe as s"; + if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid = s.fk_pays"; + } $sql .= " WHERE s.entity IN (".getEntity('societe').")"; // For ajax search we limit here. For combo list, we limit later if (is_array($limitto) && count($limitto)) { From a9160f5af00823c29be23445565c687555cafc91 Mon Sep 17 00:00:00 2001 From: Lucas Marcouiller Date: Mon, 11 Oct 2021 11:42:40 +0200 Subject: [PATCH 71/79] Fix : error takepos on constforcompanyid --- htdocs/takepos/invoice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index d7be7d4e6eb..e4e5d61bf1d 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -158,7 +158,7 @@ if ($ret > 0) { $placeid = $invoice->id; } -$constforcompanyid = 'CASHDESK_ID_THIRDPARTY'. isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '' ; +$constforcompanyid = 'CASHDESK_ID_THIRDPARTY'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '') ; $soc = new Societe($db); if ($invoice->socid > 0) { From 94875cdc77fa541ffe4cabc9a497b7ec95249887 Mon Sep 17 00:00:00 2001 From: Indelog Date: Mon, 11 Oct 2021 13:37:37 +0200 Subject: [PATCH 72/79] Fix : Re-add bloc to set `$withtargettype` and `$withsourcetype` --- htdocs/core/class/commonobject.class.php | 25 +++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 1de8d8cd752..864e2cdf337 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3712,19 +3712,34 @@ abstract class CommonObject $withtargettype = false; $withsourcetype = false; - $sourceid = (!empty($sourceid) ? $sourceid : $this->id); - $targetid = (!empty($targetid) ? $targetid : $this->id); - $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element); - $targettype = (!empty($targettype) ? $targettype : $this->element); - $parameters = array('sourcetype'=>$sourcetype, 'sourceid'=>$sourceid, 'targettype'=>$targettype, 'targetid'=>$targetid); // Hook for explicitly set the targettype if it must be differtent than $this->element $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks if ($reshook > 0) { if (!empty($hookmanager->resArray['sourcetype'])) $sourcetype = $hookmanager->resArray['sourcetype']; + if (!empty($hookmanager->resArray['sourceid'])) $sourceid = $hookmanager->resArray['sourceid']; if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype']; + if (!empty($hookmanager->resArray['targetid'])) $targetid = $hookmanager->resArray['targetid']; } + if (!empty($sourceid) && !empty($sourcetype) && empty($targetid)) { + $justsource = true; // the source (id and type) is a search criteria + if (!empty($targettype)) { + $withtargettype = true; + } + } + if (!empty($targetid) && !empty($targettype) && empty($sourceid)) { + $justtarget = true; // the target (id and type) is a search criteria + if (!empty($sourcetype)) { + $withsourcetype = true; + } + } + + $sourceid = (!empty($sourceid) ? $sourceid : $this->id); + $targetid = (!empty($targetid) ? $targetid : $this->id); + $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element); + $targettype = (!empty($targettype) ? $targettype : $this->element); + /*if (empty($sourceid) && empty($targetid)) { dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR); From bbf5cb5db1cd591e8f7587cf44ed87d82619961d Mon Sep 17 00:00:00 2001 From: Lucas Marcouiller Date: Mon, 11 Oct 2021 15:02:53 +0200 Subject: [PATCH 73/79] FIX: creation of project backtopage --- htdocs/projet/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index 078082961a5..8aab287bbb6 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -224,7 +224,7 @@ if (empty($reshook)) { $db->commit(); if (!empty($backtopage)) { - $backtopage = preg_replace('/--IDFORBACKTOPAGE--/', $object->id, $backtopage); // New method to autoselect project after a New on another form object creation + $backtopage = preg_replace('/--IDFORBACKTOPAGE--|__ID__/', $object->id, $backtopage); // New method to autoselect project after a New on another form object creation $backtopage = $backtopage.'&projectid='.$object->id; // Old method header("Location: ".$backtopage); exit; From b29bd325fe3563537ace041e1f82b4921aa8e22c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 11 Oct 2021 15:25:25 +0200 Subject: [PATCH 74/79] Update card.php --- htdocs/compta/facture/card.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 0eb2a503e42..5b68f9f4a29 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -3730,8 +3730,7 @@ if ($action == 'create') { print ''."\n"; print ''."\n"; print ''."\n"; - // The lines below override the parameters set by GET or POST for origin value and also be present in $origin and $originid variables (it make creation of invoice originating from an external module object impossible because for get an external module class we also need to know the name of the module in addition of the name of the element). - // This input fields already printed above at the
    begin. + // The commented lines below are fields already added as hidden parameters before //print ''; //print ''; From 96bdd6168480bb0e1a71ca98c4953ea5905fd721 Mon Sep 17 00:00:00 2001 From: Christophe Battarel Date: Mon, 11 Oct 2021 17:36:31 +0200 Subject: [PATCH 75/79] NEW : add constant TICKETS_MESSAGE_FORCE_MAIL --- htdocs/core/class/html.formticket.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index a4b18470be4..5ce2dd0fca7 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -1232,7 +1232,7 @@ class FormTicket // External users can't send message email if ($user->rights->ticket->write && !$user->socid) { print ''; - $checkbox_selected = (GETPOST('send_email') == "1" ? ' checked' : ''); + $checkbox_selected = (GETPOST('send_email') == "1" ? ' checked' : ($conf->global->TICKETS_MESSAGE_FORCE_MAIL?'checked':'')); print ' '; print ''; print ''; From ed3b267d8fd91e9d4e1c45197fab9ef78628e200 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 12 Oct 2021 01:40:30 +0200 Subject: [PATCH 76/79] Fix css --- htdocs/accountancy/customer/list.php | 2 +- htdocs/accountancy/supplier/list.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/accountancy/customer/list.php b/htdocs/accountancy/customer/list.php index a730a8a9af6..c258ed81352 100644 --- a/htdocs/accountancy/customer/list.php +++ b/htdocs/accountancy/customer/list.php @@ -635,7 +635,7 @@ if ($result) { // Vat rate $code_vat_differ=''; - if ($product_static->tva_tx !== $facture_static_det->tva_tx) { + if ($product_static->tva_tx !== $facture_static_det->tva_tx && ! empty($facture_static_det->tva_tx)) { // Note: having a vat rate of 0 is often the normal case when sells is intra b2b or to export $code_vat_differ = 'font-weight:bold; text-decoration:blink; color:red'; } print ''; diff --git a/htdocs/accountancy/supplier/list.php b/htdocs/accountancy/supplier/list.php index ffdd5b6de57..cc8398bc759 100644 --- a/htdocs/accountancy/supplier/list.php +++ b/htdocs/accountancy/supplier/list.php @@ -678,7 +678,7 @@ if ($result) { print ''; // Vat rate - if ($objp->vat_tx_l != $objp->vat_tx_p) { + if ($objp->vat_tx_l != $objp->vat_tx_p && ! empty($objp->vat_tx_l)) { // Note: having a vat rate of 0 is often the normal case when sells is intra b2b or to export $code_vat_differ = 'font-weight:bold; text-decoration:blink; color:red'; } print ''; From bac0c3d7c850f22b7fdd33b958b07c00692f4a49 Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Tue, 12 Oct 2021 11:30:35 +0200 Subject: [PATCH 77/79] Fix fatal error on php 8.0 --- htdocs/eventorganization/class/conferenceorbooth.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/eventorganization/class/conferenceorbooth.class.php b/htdocs/eventorganization/class/conferenceorbooth.class.php index 6d0c77dc768..90462fdb762 100644 --- a/htdocs/eventorganization/class/conferenceorbooth.class.php +++ b/htdocs/eventorganization/class/conferenceorbooth.class.php @@ -238,9 +238,10 @@ class ConferenceOrBooth extends ActionComm * @param string $ref Ref * @param string $ref_ext Ref ext to get * @param string $email_msgid Email msgid + * @param int $loadresources 1=Load also resources * @return int <0 if KO, 0 if not found, >0 if OK */ - public function fetch($id, $ref = null, $ref_ext = '', $email_msgid = '') + public function fetch($id, $ref = null, $ref_ext = '', $email_msgid = '', $loadresources = 1) { global $dolibarr_main_url_root, $conf, $langs; From 791a7206ee258ea6053e56063ac8f3a691dd2657 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 12 Oct 2021 11:48:51 +0200 Subject: [PATCH 78/79] Fix var not defined --- htdocs/core/class/commonobject.class.php | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index cf64e298784..37083cdf5f8 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3637,22 +3637,19 @@ abstract class CommonObject $origin = 'order_supplier'; } - $targettype = $this->element; - - $parameters = array('sourcetype'=>$sourcetype, 'sourceid'=>$sourceid, 'targettype'=>$targettype, 'targetid'=>$targetid); - // Hook for explicitly set the targettype if it must be differtent than $this->element - $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks - if ($reshook > 0) { - if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype']; - if (!empty($hookmanager->resArray['sourcetype'])) $sourcetype = $hookmanager->resArray['sourcetype']; - } - // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization'); // Add module part to target type if object has $module property and isn't in core modules. $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; + $parameters = array('targettype'=>$targettype); + // Hook for explicitly set the targettype if it must be differtent than $this->element + $reshook = $hookmanager->executeHooks('setLinkedObjectSourceTargetType', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + if (!empty($hookmanager->resArray['targettype'])) $targettype = $hookmanager->resArray['targettype']; + } + $this->db->begin(); $error = 0; From eb73da5abc46401d940438553627a0db4346f771 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 12 Oct 2021 12:04:43 +0200 Subject: [PATCH 79/79] Fix set origin. --- htdocs/mrp/class/api_mos.class.php | 4 +++- htdocs/mrp/mo_production.php | 3 ++- htdocs/product/inventory/inventory.php | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/htdocs/mrp/class/api_mos.class.php b/htdocs/mrp/class/api_mos.class.php index 59b4cbfa16b..e6068eb3c81 100644 --- a/htdocs/mrp/class/api_mos.class.php +++ b/htdocs/mrp/class/api_mos.class.php @@ -382,7 +382,9 @@ class Mos extends DolibarrApi if (!$error && $value["fk_warehouse"] > 0) { // Record stock movement $id_product_batch = 0; - $stockmove->origin = $this->mo; + + $stockmove->setOrigin($this->mo->element, $this->mo->id); + if ($qtytoprocess >= 0) { $moline = new MoLine($this->db); $moline->fk_mo = $this->mo->id; diff --git a/htdocs/mrp/mo_production.php b/htdocs/mrp/mo_production.php index 510e7a433f4..533e81f80a2 100644 --- a/htdocs/mrp/mo_production.php +++ b/htdocs/mrp/mo_production.php @@ -211,7 +211,8 @@ if (empty($reshook)) { if (!$error && GETPOST('idwarehouse-'.$line->id.'-'.$i) > 0) { // Record stock movement $id_product_batch = 0; - $stockmove->origin = $object; + $stockmove->setOrigin($object->element, $object->id); + if ($qtytoprocess >= 0) { $idstockmove = $stockmove->livraison($user, $line->fk_product, GETPOST('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement); } else { diff --git a/htdocs/product/inventory/inventory.php b/htdocs/product/inventory/inventory.php index c0b607cde45..9a4d61209ba 100644 --- a/htdocs/product/inventory/inventory.php +++ b/htdocs/product/inventory/inventory.php @@ -109,7 +109,7 @@ if ($action == 'cancel_record' && $permissiontoadd) { if ($action == 'update' && !empty($user->rights->stock->mouvement->creer)) { $stockmovment = new MouvementStock($db); - $stockmovment->origin = $object; + $stockmovment->setOrigin($object->element, $object->id); $db->begin(); @@ -117,6 +117,7 @@ if ($action == 'update' && !empty($user->rights->stock->mouvement->creer)) { $sql .= ' id.fk_product, id.batch, id.qty_stock, id.qty_view, id.qty_regulated'; $sql .= ' FROM '.MAIN_DB_PREFIX.'inventorydet as id'; $sql .= ' WHERE id.fk_inventory = '.((int) $object->id); + $resql = $db->query($sql); if ($resql) { $num = $db->num_rows($resql);