diff --git a/htdocs/admin/emailcollector_card.php b/htdocs/admin/emailcollector_card.php index a5e557ddfeb..2c1e0948e01 100644 --- a/htdocs/admin/emailcollector_card.php +++ b/htdocs/admin/emailcollector_card.php @@ -561,6 +561,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea 'recordevent'=>'RecordEvent'); if ($conf->projet->enabled) $arrayoftypes['project'] = 'CreateLeadAndThirdParty'; if ($conf->ticket->enabled) $arrayoftypes['ticket'] = 'CreateTicketAndThirdParty'; + if ($conf->recruitment->enabled) $arrayoftypes['candidature'] = 'CreateCandidature'; // support hook for add action $parameters = array('arrayoftypes' => $arrayoftypes); diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index 96c99ebba36..dc14e132e41 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -418,7 +418,11 @@ class FormMail extends Form } foreach ($this->param as $key=>$value) { - $out .= ''."\n"; + if (is_array($value)) { + $out .= "\n"; + } else { + $out .= ''."\n"; + } } $modelmail_array = array(); @@ -1243,12 +1247,8 @@ class FormMail extends Form $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendShipping"); } elseif ($type_template == 'fichinter_send') { $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendFichInter"); - } elseif ($type_template == 'thirdparty') { - $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentThirdparty"); - } elseif ($type_template == 'user') { - $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentUser"); } elseif (!empty($type_template)) { - $defaultmessage = $outputlangs->transnoentities("PredefinedMailContent".ucfirst($type_template)); + $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentGeneric"); } $ret->label = 'default'; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 1e4e973109b..3f6ed2b1d23 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -3009,7 +3009,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ } } else { $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', $picto); - if (empty($srconly) && in_array($pictowithouttext, array( + if (empty($srconly) && in_array($pictowithouttext, array( '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected', 'accountancy', 'address', 'bank_account', 'barcode', 'bank', 'bill', 'bookmark', 'bom', 'building', 'cash-register', 'category', 'check', 'clock', 'close_title', 'company', 'contact', 'contract', 'cubes', @@ -3025,7 +3025,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'object_margin', 'object_money-bill-alt', 'object_multicurrency', 'object_order', 'object_payment', 'object_lot', 'object_mrp', 'object_payment', 'object_product', 'object_propal', 'object_other', 'object_paragraph', 'object_poll', 'object_printer', 'object_project', 'object_projectpub', 'object_propal', 'object_resource', 'object_rss', 'object_projecttask', - 'object_recruitmentjobposition', + 'object_recruitmentjobposition', 'object_recruitmentcandidature', 'object_shipment', 'object_supplier_invoice', 'object_supplier_invoicea', 'object_supplier_invoiced', 'object_supplier_order', 'object_supplier_proposal', 'object_service', 'object_stock', 'object_technic', 'object_ticket', 'object_trip', 'object_user', 'object_group', 'object_member', 'object_phoning', 'object_phoning_mobile', 'object_phoning_fax', 'object_email', 'object_website', @@ -3070,7 +3070,8 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle', 'other'=>'square', 'playdisabled'=>'play', 'poll'=>'check-double', 'preview'=>'binoculars', 'project'=>'sitemap', 'projectpub'=>'sitemap', 'projecttask'=>'tasks', 'propal'=>'file-signature', - 'recruitmentjobposition'=>'door-open', 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature', + 'recruitmentjobposition'=>'door-open', 'recruitmentcandidature'=>'door-open', + 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature', 'payment'=>'money-check-alt', 'phoning'=>'phone', 'phoning_mobile'=>'mobile-alt', 'phoning_fax'=>'fax', 'printer'=>'print', 'product'=>'cube', 'service'=>'concierge-bell', 'resource'=>'laptop-house', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'supplier_invoice'=>'file-invoice-dollar', 'technic'=>'cogs', 'ticket'=>'ticket-alt', @@ -3132,7 +3133,8 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'holiday'=>'infobox-holiday', 'invoice'=>'infobox-commande', 'payment'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'project'=>'infobox-project', 'projecttask'=>'infobox-project', 'propal'=>'infobox-propal', - 'recruitmentjobposition'=>'infobox-adherent', 'resource'=>'infobox-action', + 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent', + 'resource'=>'infobox-action', 'supplier_invoice'=>'infobox-order_supplier', 'supplier_invoicea'=>'infobox-order_supplier', 'supplier_invoiced'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal', 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action', diff --git a/htdocs/core/modules/modEmailCollector.class.php b/htdocs/core/modules/modEmailCollector.class.php index 59320a959f9..44309e20d81 100644 --- a/htdocs/core/modules/modEmailCollector.class.php +++ b/htdocs/core/modules/modEmailCollector.class.php @@ -375,6 +375,34 @@ class modEmailCollector extends DolibarrModules } } else dol_print_error($this->db); + $tmpsql = "SELECT rowid FROM ".MAIN_DB_PREFIX."emailcollector_emailcollector WHERE ref = 'Collect_Candidatures' and entity = ".$conf->entity; + $tmpresql = $this->db->query($tmpsql); + if ($tmpresql) { + if ($this->db->num_rows($tmpresql) == 0) { + $descriptionC1 = "This collector will scan your mailbox to find emails send for a recruitment (Module Recruitment must be enabled). You can complete this collector if you want to automaticallycreate a candidature for a job request."; + $descriptionC1 .= "Note: With this initial example, the title of the candidature is generated including the email."; + + $sqlforexampleC1 = "INSERT INTO ".MAIN_DB_PREFIX."emailcollector_emailcollector (entity, ref, label, description, source_directory, date_creation, fk_user_creat, status)"; + $sqlforexampleC1 .= " VALUES (".$conf->entity.", 'Collect_Candidatures', 'Example to collect leads', '".$this->db->escape($descriptionC1)."', 'INBOX', '".$this->db->idate(dol_now())."', ".$user->id.", 0)"; + + $sqlforexampleFilterC1 = "INSERT INTO ".MAIN_DB_PREFIX."emailcollector_emailcollectorfilter (fk_emailcollector, type, date_creation, fk_user_creat, status)"; + $sqlforexampleFilterC1 .= " VALUES ((SELECT rowid FROM ".MAIN_DB_PREFIX."emailcollector_emailcollector WHERE ref = 'Collect_Candidatures' and entity = ".$conf->entity."), 'isnotanswer', '".$this->db->idate(dol_now())."', ".$user->id.", 1)"; + $sqlforexampleFilterC2 = "INSERT INTO ".MAIN_DB_PREFIX."emailcollector_emailcollectorfilter (fk_emailcollector, type, date_creation, fk_user_creat, status)"; + $sqlforexampleFilterC2 .= " VALUES ((SELECT rowid FROM ".MAIN_DB_PREFIX."emailcollector_emailcollector WHERE ref = 'Collect_Candidatures' and entity = ".$conf->entity."), 'withouttrackingid', '".$this->db->idate(dol_now())."', ".$user->id.", 1)"; + $sqlforexampleFilterC3 = "INSERT INTO ".MAIN_DB_PREFIX."emailcollector_emailcollectorfilter (fk_emailcollector, type, rulevalue, date_creation, fk_user_creat, status)"; + $sqlforexampleFilterC3 .= " VALUES ((SELECT rowid FROM ".MAIN_DB_PREFIX."emailcollector_emailcollector WHERE ref = 'Collect_Candidatures' and entity = ".$conf->entity."), 'to', 'jobs@example.com', '".$this->db->idate(dol_now())."', ".$user->id.", 1)"; + + $sqlforexampleC4 = "INSERT INTO ".MAIN_DB_PREFIX."emailcollector_emailcollectoraction (fk_emailcollector, type, actionparam, date_creation, fk_user_creat, status)"; + $sqlforexampleC4 .= " VALUES ((SELECT rowid FROM ".MAIN_DB_PREFIX."emailcollector_emailcollector WHERE ref = 'Collect_Candidatures' and entity = ".$conf->entity."), 'candidature', 'tmp_from=EXTRACT:HEADER:^From:(.*);fk_recruitmentjobposition=EXTRACT:HEADER:^To:[^\n]*\+([^\n]*);description=EXTRACT:BODY:(.*);title=SET:Candidature from __tmp_from__ received by email', '".$this->db->idate(dol_now())."', ".$user->id.", 1)"; + + $sql[] = $sqlforexampleC1; + $sql[] = $sqlforexampleFilterC1; + $sql[] = $sqlforexampleFilterC2; + $sql[] = $sqlforexampleFilterC3; + $sql[] = $sqlforexampleC4; + } + } else dol_print_error($this->db); + return $this->_init($sql, $options); } diff --git a/htdocs/core/modules/modRecruitment.class.php b/htdocs/core/modules/modRecruitment.class.php index 0cbe9da017b..d40d7a84a1c 100644 --- a/htdocs/core/modules/modRecruitment.class.php +++ b/htdocs/core/modules/modRecruitment.class.php @@ -243,17 +243,17 @@ class modRecruitment extends DolibarrModules // Add here entries to declare new permissions /* BEGIN MODULEBUILDER PERMISSIONS */ $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) - $this->rights[$r][1] = 'Read job positions to fill'; // Permission label + $this->rights[$r][1] = 'Read job positions to fill and candidatures'; // Permission label $this->rights[$r][4] = 'recruitmentjobposition'; // In php code, permission will be checked by test if ($user->rights->recruitment->level1->level2) $this->rights[$r][5] = 'read'; // In php code, permission will be checked by test if ($user->rights->recruitment->level1->level2) $r++; $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) - $this->rights[$r][1] = 'Create/Update job positions to fill'; // Permission label + $this->rights[$r][1] = 'Create/Update job positions to fill and candidatures'; // Permission label $this->rights[$r][4] = 'recruitmentjobposition'; // In php code, permission will be checked by test if ($user->rights->recruitment->level1->level2) $this->rights[$r][5] = 'write'; // In php code, permission will be checked by test if ($user->rights->recruitment->level1->level2) $r++; $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) - $this->rights[$r][1] = 'Delete Job positions to fill'; // Permission label + $this->rights[$r][1] = 'Delete Job positions to fill and candidatures'; // Permission label $this->rights[$r][4] = 'recruitmentjobposition'; // In php code, permission will be checked by test if ($user->rights->recruitment->level1->level2) $this->rights[$r][5] = 'delete'; // In php code, permission will be checked by test if ($user->rights->recruitment->level1->level2) $r++; @@ -283,19 +283,19 @@ class modRecruitment extends DolibarrModules $this->menu[$r++]=array( 'fk_menu'=>'fk_mainmenu=hrm,fk_leftmenu=recruitmentjobposition', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 'type'=>'left', // This is a Left menu entry - 'titre'=>'PositionsToBeFilled', + 'titre'=>'NewPositionToBeFilled', 'mainmenu'=>'hrm', - 'leftmenu'=>'recruitment_recruitmentjobposition', - 'url'=>'/recruitment/recruitmentjobposition_list.php', + 'leftmenu'=>'recruitment_recruitmentjobposition_new', + 'url'=>'/recruitment/recruitmentjobposition_card.php?action=create', 'langs'=>'recruitment', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'position'=>1000+$r, 'enabled'=>'$conf->recruitment->enabled', // Define condition to show or hide menu entry. Use '$conf->recruitment->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. - 'perms'=>'$user->rights->recruitment->recruitmentjobposition->read', // Use 'perms'=>'$user->rights->recruitment->level1->level2' if you want your menu with a permission rules + 'perms'=>'$user->rights->recruitment->recruitmentjobposition->write', // Use 'perms'=>'$user->rights->recruitment->level1->level2' if you want your menu with a permission rules 'target'=>'', 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both ); $this->menu[$r++]=array( - 'fk_menu'=>'fk_mainmenu=hrm,fk_leftmenu=recruitment_recruitmentjobposition', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'fk_menu'=>'fk_mainmenu=hrm,fk_leftmenu=recruitmentjobposition', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 'type'=>'left', // This is a Left menu entry 'titre'=>'ListOfPositionsToBeFilled', 'mainmenu'=>'hrm', @@ -309,12 +309,12 @@ class modRecruitment extends DolibarrModules 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both ); $this->menu[$r++]=array( - 'fk_menu'=>'fk_mainmenu=hrm,fk_leftmenu=recruitment_recruitmentjobposition', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'fk_menu'=>'fk_mainmenu=hrm,fk_leftmenu=recruitmentjobposition', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 'type'=>'left', // This is a Left menu entry - 'titre'=>'NewPositionToBeFilled', + 'titre'=>'NewCandidature', 'mainmenu'=>'hrm', - 'leftmenu'=>'recruitment_recruitmentjobposition_new', - 'url'=>'/recruitment/recruitmentjobposition_card.php?action=create', + 'leftmenu'=>'recruitment_recruitmentcandidature_new', + 'url'=>'/recruitment/recruitmentcandidature_card.php?action=create', 'langs'=>'recruitment', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'position'=>1000+$r, 'enabled'=>'$conf->recruitment->enabled', // Define condition to show or hide menu entry. Use '$conf->recruitment->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. @@ -322,7 +322,20 @@ class modRecruitment extends DolibarrModules 'target'=>'', 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both ); - + $this->menu[$r++]=array( + 'fk_menu'=>'fk_mainmenu=hrm,fk_leftmenu=recruitmentjobposition', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'type'=>'left', // This is a Left menu entry + 'titre'=>'ListOfCandidatures', + 'mainmenu'=>'hrm', + 'leftmenu'=>'recruitment_recruitmentcandidature_list', + 'url'=>'/recruitment/recruitmentcandidature_list.php', + 'langs'=>'recruitment', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'position'=>1000+$r, + 'enabled'=>'$conf->recruitment->enabled', // Define condition to show or hide menu entry. Use '$conf->recruitment->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. + 'perms'=>'$user->rights->recruitment->recruitmentjobposition->read', // Use 'perms'=>'$user->rights->recruitment->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both + ); /* END MODULEBUILDER LEFTMENU RECRUITMENTJOBPOSITION */ // Exports profiles provided by this module diff --git a/htdocs/core/tpl/card_presend.tpl.php b/htdocs/core/tpl/card_presend.tpl.php index ba759eded31..93dee2ebda9 100644 --- a/htdocs/core/tpl/card_presend.tpl.php +++ b/htdocs/core/tpl/card_presend.tpl.php @@ -279,10 +279,10 @@ if ($action == 'presend') } } - // Tableau des substitutions + // Array of substitutions $formmail->substit = $substitutionarray; - // Tableau des parametres complementaires + // Array of other parameters $formmail->param['action'] = 'send'; $formmail->param['models'] = $modelmail; $formmail->param['models_id'] = GETPOST('modelmailselected', 'int'); diff --git a/htdocs/emailcollector/class/emailcollector.class.php b/htdocs/emailcollector/class/emailcollector.class.php index 7e5e1af1024..d89456981ea 100644 --- a/htdocs/emailcollector/class/emailcollector.class.php +++ b/htdocs/emailcollector/class/emailcollector.class.php @@ -1627,7 +1627,7 @@ class EmailCollector extends CommonObject // Overwrite values with values extracted from source email $errorforthisaction = $this->overwritePropertiesOfObject($actioncomm, $operation['actionparam'], $messagetext, $subject, $header); -var_dump($actioncomm); + if ($errorforthisaction) { $errorforactions++; @@ -1839,37 +1839,6 @@ var_dump($actioncomm); } $tickettocreate->ref = $defaultref; } - // Create event specific on hook - // this code action is hook..... for support this call - elseif (substr($operation['type'], 0, 4) == 'hook') { - global $hookmanager; - - if (!is_object($hookmanager)) - $hookmanager->initHooks(array('emailcollectorcard')); - - $parameters = array( - 'connection'=> $connection, - 'imapemail'=>$imapemail, - 'overview'=>$overview, - - 'from' => $from, - 'fromtext' => $fromtext, - - 'actionparam'=> $operation['actionparam'], - - 'thirdpartyid' => $thirdpartyid, - 'objectid'=> $objectid, - 'objectemail'=> $objectemail, - - 'messagetext'=>$messagetext, - 'subject'=>$subject, - 'header'=>$header, - ); - $res = $hookmanager->executeHooks('doCollectOneCollector', $parameters, $this, $operation['type']); - - if ($res < 0) - $this->error = $hookmanager->resPrint; - } if ($errorforthisaction) { @@ -1891,6 +1860,143 @@ var_dump($actioncomm); } } } + // Create candidature + elseif ($operation['type'] == 'candidature') + { + $candidaturetocreate = new RecruitmentCandidature($this->db); + + $description = $descriptiontitle; + $description = dol_concatdesc($description, "-----"); + $description = dol_concatdesc($description, $descriptionmeta); + $description = dol_concatdesc($description, "-----"); + $description = dol_concatdesc($description, $messagetext); + + $descriptionfull = $description; + $descriptionfull = dol_concatdesc($descriptionfull, "----- Header"); + $descriptionfull = dol_concatdesc($descriptionfull, $header); + + $candidaturetocreate->subject = $subject; + $candidaturetocreate->message = $description; + $candidaturetocreate->type_code = 0; + $candidaturetocreate->category_code = null; + $candidaturetocreate->severity_code = null; + $candidaturetocreate->origin_email = $from; + $candidaturetocreate->fk_user_create = $user->id; + $candidaturetocreate->datec = $date; + $candidaturetocreate->fk_project = $projectstatic->id; + $candidaturetocreate->notify_tiers_at_create = 0; + $candidaturetocreate->note_private = $descriptionfull; + $candidaturetocreate->entity = $conf->entity; + $candidaturetocreate->email_msgid = $msgid; + //$candidaturetocreate->fk_contact = $contactstatic->id; + + // Overwrite values with values extracted from source email. + // This may overwrite any $projecttocreate->xxx properties. + $errorforthisaction = $this->overwritePropertiesOfObject($candidaturetocreate, $operation['actionparam'], $messagetext, $subject, $header); + + // Set candidature ref if not yet defined + /*if (empty($candidaturetocreate->ref)) + { + // Get next project Ref + $defaultref = ''; + $modele = empty($conf->global->CANDIDATURE_ADDON) ? 'mod_candidature_simple' : $conf->global->CANDIDATURE_ADDON; + + // Search template files + $file = ''; $classname = ''; $filefound = 0; $reldir = ''; + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) + { + $file = dol_buildpath($reldir."core/modules/ticket/".$modele.'.php', 0); + if (file_exists($file)) + { + $filefound = 1; + $classname = $modele; + break; + } + } + + if ($filefound) + { + $result = dol_include_once($reldir."core/modules/ticket/".$modele.'.php'); + $modCandidature = new $classname; + + if ($savesocid > 0) + { + if ($savesocid != $candidaturetocreate->socid) + { + $errorforactions++; + setEventMessages('You loaded a thirdparty (id='.$savesocid.') and you force another thirdparty id (id='.$candidaturetocreate->socid.') by setting socid in operation with a different value', null, 'errors'); + } + } else { + if ($candidaturetocreate->socid > 0) + { + $thirdpartystatic->fetch($candidaturetocreate->socid); + } + } + + $defaultref = $modCandidature->getNextValue(($thirdpartystatic->id > 0 ? $thirdpartystatic : null), $tickettocreate); + } + $candidaturetocreate->ref = $defaultref; + }*/ + + if ($errorforthisaction) + { + $errorforactions++; + } else { + /*if (is_numeric($candidaturetocreate->ref) && $candidaturetocreate->ref <= 0) + { + $errorforactions++; + $this->error = 'Failed to create cancidature: Can\'t get a valid value for the field ref with numbering template = '.$modele.', thirdparty id = '.$thirdpartystatic->id; + } else {*/ + // Create project + $result = $candidaturetocreate->create($user); + if ($result <= 0) + { + $errorforactions++; + $this->error = 'Failed to create ticket: '.$langs->trans($candidaturetocreate->error); + $this->errors = $candidaturetocreate->errors; + } + //} + } + } + // Create event specific on hook + // this code action is hook..... for support this call + elseif (substr($operation['type'], 0, 4) == 'hook') { + global $hookmanager; + + if (!is_object($hookmanager)) { + $hookmanager->initHooks(array('emailcollectorcard')); + } + + $parameters = array( + 'connection'=> $connection, + 'imapemail'=>$imapemail, + 'overview'=>$overview, + + 'from' => $from, + 'fromtext' => $fromtext, + + 'actionparam'=> $operation['actionparam'], + + 'thirdpartyid' => $thirdpartyid, + 'objectid'=> $objectid, + 'objectemail'=> $objectemail, + + 'messagetext'=>$messagetext, + 'subject'=>$subject, + 'header'=>$header, + ); + $res = $hookmanager->executeHooks('doCollectOneCollector', $parameters, $this, $operation['type']); + + if ($res < 0) { + $errorforthisaction++; + $this->error = $hookmanager->resPrint; + } + if ($errorforthisaction) + { + $errorforactions++; + } + } if (!$errorforactions) { diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 4066c8bf205..55c2d03f2c1 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -139,7 +139,7 @@ ALTER TABLE llx_recruitment_recruitmentjobposition_extrafields ADD INDEX idx_fk_ CREATE TABLE llx_recruitment_recruitmentcandidature( -- BEGIN MODULEBUILDER FIELDS rowid integer AUTO_INCREMENT PRIMARY KEY NOT NULL, - fk_recruitmentjobposition INTEGER NOT NULL, + fk_recruitmentjobposition INTEGER NULL, ref varchar(128) DEFAULT '(PROV)' NOT NULL, description text, note_public text, @@ -152,7 +152,9 @@ CREATE TABLE llx_recruitment_recruitmentcandidature( model_pdf varchar(255), status smallint NOT NULL, firstname varchar(128), - lastname varchar(128), + lastname varchar(128), + email varchar(255), + phone varchar(64), remuneration_requested integer, remuneration_proposed integer, fk_recruitment_origin INTEGER NULL diff --git a/htdocs/install/mysql/tables/llx_recruitment_recruitmentcandidature.sql b/htdocs/install/mysql/tables/llx_recruitment_recruitmentcandidature.sql index 43bdb14e7bd..a635a11b8fe 100644 --- a/htdocs/install/mysql/tables/llx_recruitment_recruitmentcandidature.sql +++ b/htdocs/install/mysql/tables/llx_recruitment_recruitmentcandidature.sql @@ -17,7 +17,7 @@ CREATE TABLE llx_recruitment_recruitmentcandidature( -- BEGIN MODULEBUILDER FIELDS rowid integer AUTO_INCREMENT PRIMARY KEY NOT NULL, - fk_recruitmentjobposition INTEGER NOT NULL, + fk_recruitmentjobposition INTEGER NULL, ref varchar(128) DEFAULT '(PROV)' NOT NULL, description text, note_public text, @@ -31,6 +31,8 @@ CREATE TABLE llx_recruitment_recruitmentcandidature( status smallint NOT NULL, firstname varchar(128), lastname varchar(128), + email varchar(255), + phone varchar(64), remuneration_requested integer, remuneration_proposed integer, fk_recruitment_origin INTEGER NULL diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index a2b89101d16..fbbdf81ff93 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1950,6 +1950,7 @@ LoadThirdPartyFromName=Load third party searching on %s (load only) LoadThirdPartyFromNameOrCreate=Load third party searching on %s (create if not found) WithDolTrackingID=Message from a conversation initiated by a first email sent from Dolibarr WithoutDolTrackingID=Message from a conversation initiated by a first email NOT sent from Dolibarr +CreateCandidature=Create candidature FormatZip=Zip MainMenuCode=Menu entry code (mainmenu) ECMAutoTree=Show automatic ECM tree diff --git a/htdocs/langs/en_US/other.lang b/htdocs/langs/en_US/other.lang index aabc4f0472a..54c0572d453 100644 --- a/htdocs/langs/en_US/other.lang +++ b/htdocs/langs/en_US/other.lang @@ -97,11 +97,8 @@ PredefinedMailContentSendSupplierOrder=__(Hello)__\n\nPlease find our order __RE PredefinedMailContentSendSupplierInvoice=__(Hello)__\n\nPlease find invoice __REF__ attached\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__ PredefinedMailContentSendShipping=__(Hello)__\n\nPlease find shipping __REF__ attached\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__ PredefinedMailContentSendFichInter=__(Hello)__\n\nPlease find intervention __REF__ attached\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__ -PredefinedMailContentThirdparty=__(Hello)__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__ -PredefinedMailContentContact=__(Hello)__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__ -PredefinedMailContentUser=__(Hello)__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__ PredefinedMailContentLink=You can click on the link below to make your payment if it is not already done.\n\n%s\n\n -PredefinedMailContentTicket_send=__(Hello)__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__ +PredefinedMailContentGeneric=__(Hello)__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__ DemoDesc=Dolibarr is a compact ERP/CRM supporting several business modules. A demo showcasing all modules makes no sense as this scenario never occurs (several hundred available). So, several demo profiles are available. ChooseYourDemoProfil=Choose the demo profile that best suits your needs... ChooseYourDemoProfilMore=...or build your own profile
(manual module selection) diff --git a/htdocs/langs/en_US/recruitment.lang b/htdocs/langs/en_US/recruitment.lang index b4a7abbe825..aa4f12c1263 100644 --- a/htdocs/langs/en_US/recruitment.lang +++ b/htdocs/langs/en_US/recruitment.lang @@ -29,8 +29,8 @@ RecruitmentSetup = Recruitment setup Settings = Settings RecruitmentSetupPage = Enter here the setup of main options for the recruitment module RecruitmentArea=Recruitement area -PublicInterfaceRecruitmentDesc=Public interface is public URLs to show and answer to open jobs. There is one different link for each open job. -EnablePublicRecruitmentPages=Enable public recruitment pages +PublicInterfaceRecruitmentDesc=Public pages of jobs are public URLs to show and answer to open jobs. There is one different link for each open job, found on each job record. +EnablePublicRecruitmentPages=Enable public pages of open jobs # # About page @@ -54,4 +54,11 @@ JobOfferToBeFilled=Job offer to be filled ThisIsInformationOnJobPosition=Information of the job position to be filled ContactForRecruitment=Contact for recruitment EmailRecruiter=Email recruiter -ToUseAGenericEmail=To use a generic email. If not defined, the email of the responsible of recruitment will be used \ No newline at end of file +ToUseAGenericEmail=To use a generic email. If not defined, the email of the responsible of recruitment will be used +NewCandidature=New candidature +ListOfCandidatures=List of candidatures +RequestedRemuneration=Requested remuneration +ProposedRemuneration=Proposed remuneration +ContractProposed=Contract proposed +ContractSigned=Contract signed +RecruitmentCandidature=Candidature \ No newline at end of file diff --git a/htdocs/recruitment/class/recruitmentcandidature.class.php b/htdocs/recruitment/class/recruitmentcandidature.class.php index 4a18ddf85fb..9968e62d063 100644 --- a/htdocs/recruitment/class/recruitmentcandidature.class.php +++ b/htdocs/recruitment/class/recruitmentcandidature.class.php @@ -56,11 +56,14 @@ class RecruitmentCandidature extends CommonObject /** * @var string String with name of icon for recruitmentcandidature. Must be the part after the 'object_' into object_recruitmentcandidature.png */ - public $picto = 'recruitmentcandidature@recruitment'; + public $picto = 'recruitmentcandidature'; const STATUS_DRAFT = 0; const STATUS_VALIDATED = 1; + const STATUS_CONTRACT_PROPOSED = 3; + const STATUS_CONTRACT_SIGNED = 5; + const STATUS_REFUSED = 8; const STATUS_CANCELED = 9; @@ -96,22 +99,24 @@ class RecruitmentCandidature extends CommonObject public $fields=array( 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'comment'=>"Id"), 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>10, 'notnull'=>1, 'visible'=>4, 'noteditable'=>'1', 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'showoncombobox'=>'1', 'comment'=>"Reference of object"), - 'fk_recruitmentjobposition' => array('type'=>'integer:RecruitmentJobPosition:recruitment/class/recruitment_recruitmentjobposition.class.php', 'label'=>'Job', 'enabled'=>'1', 'position'=>15, 'notnull'=>1, 'visible'=>1, 'index'=>1), - 'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>'1', 'position'=>60, 'notnull'=>0, 'visible'=>3,), + 'fk_recruitmentjobposition' => array('type'=>'integer:RecruitmentJobPosition:recruitment/class/recruitmentjobposition.class.php', 'label'=>'Job', 'enabled'=>'1', 'position'=>15, 'notnull'=>0, 'visible'=>1, 'index'=>1), + 'description' => array('type'=>'html', '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,), + 'lastname' => array('type'=>'varchar(128)', 'label'=>'Lastname', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1,), + 'firstname' => array('type'=>'varchar(128)', 'label'=>'Firstname', 'enabled'=>'1', 'position'=>21, 'notnull'=>0, 'visible'=>1,), + 'email' => array('type'=>'varchar(255)', 'label'=>'EMail', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1,), + 'phone' => array('type'=>'varchar(64)', 'label'=>'Phone', 'enabled'=>'1', 'position'=>31, 'notnull'=>0, 'visible'=>1,), + //'fk_recruitment_origin' => array('type'=>'integer:CRecruitmentOrigin:recruitment/class/crecruitmentorigin.class.php', 'label'=>'Origin', 'enabled'=>'1', 'position'=>45, 'visible'=>1, 'index'=>1), + 'remuneration_requested' => array('type'=>'integer', 'label'=>'RequestedRemuneration', 'enabled'=>'1', 'position'=>80, 'notnull'=>0, 'visible'=>-1,), + 'remuneration_proposed' => array('type'=>'integer', 'label'=>'ProposedRemuneration', 'enabled'=>'1', 'position'=>81, 'notnull'=>0, 'visible'=>-1,), 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>'1', 'position'=>1000, 'notnull'=>-1, 'visible'=>-2,), 'model_pdf' => array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>'1', 'position'=>1010, 'notnull'=>-1, 'visible'=>0,), - 'status' => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>'1', 'position'=>1000, 'notnull'=>1, 'visible'=>1, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Draft', '1'=>'Validated', '9'=>'Canceled'),), - 'firstname' => array('type'=>'varchar(128)', 'label'=>'Firstname', 'enabled'=>'1', 'position'=>20, 'notnull'=>0, 'visible'=>1,), - 'lastname' => array('type'=>'varchar(128)', 'label'=>'Lastname', 'enabled'=>'1', 'position'=>21, 'notnull'=>0, 'visible'=>1,), - 'remuneration_requested' => array('type'=>'integer', 'label'=>'RequestedRemuneration', 'enabled'=>'1', 'position'=>40, 'notnull'=>0, 'visible'=>1,), - 'remuneration_proposed' => array('type'=>'integer', 'label'=>'ProposedRemuneration', 'enabled'=>'1', 'position'=>40, 'notnull'=>0, 'visible'=>1,), - 'fk_recruitment_origin' => array('type'=>'integer:CRecruitmentOrigin:recruitment/class/recruitment_crecruitmentorigin.class.php', 'label'=>'Origin', 'enabled'=>'1', 'position'=>45, 'visible'=>1, 'index'=>1), + 'status' => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>'1', 'position'=>1000, 'notnull'=>1, 'visible'=>1, 'index'=>1, 'default'=>0, 'arrayofkeyval'=>array('0'=>'Draft', '1'=>'Validated', '3'=>'ContractProposed', '5'=>'ContractSigned', '8'=>'Refused', '9'=>'Canceled')), ); public $rowid; public $ref; @@ -126,8 +131,10 @@ class RecruitmentCandidature extends CommonObject public $import_key; public $model_pdf; public $status; - public $firstname; public $lastname; + public $firstname; + public $email; + public $phone; public $remuneration_requested; public $remuneration_proposed; public $fk_recruitment_origin; @@ -793,10 +800,16 @@ class RecruitmentCandidature extends CommonObject global $langs; //$langs->load("recruitment@recruitment"); $this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft'); - $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Enabled'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Validated').' ('.$langs->trans("InterviewToDo").')'; + $this->labelStatus[self::STATUS_CONTRACT_PROPOSED] = $langs->trans('ContractProposed'); + $this->labelStatus[self::STATUS_CONTRACT_SIGNED] = $langs->trans('ContractSigned'); + $this->labelStatus[self::STATUS_REFUSED] = $langs->trans('Refused'); + $this->labelStatus[self::STATUS_REFUSED] = $langs->trans('Refused'); $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_VALIDATED] = $langs->trans('Validated'); + $this->labelStatusShort[self::STATUS_CONTRACT_PROPOSED] = $langs->trans('ContractProposed'); + $this->labelStatusShort[self::STATUS_CONTRACT_SIGNED] = $langs->trans('ContractSigned'); $this->labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Disabled'); } @@ -967,7 +980,7 @@ class RecruitmentCandidature extends CommonObject global $conf, $langs; $result = 0; - $includedocgeneration = 1; + $includedocgeneration = 0; $langs->load("recruitment@recruitment"); diff --git a/htdocs/recruitment/lib/recruitment_recruitmentcandidature.lib.php b/htdocs/recruitment/lib/recruitment_recruitmentcandidature.lib.php new file mode 100644 index 00000000000..44eb0bafe7c --- /dev/null +++ b/htdocs/recruitment/lib/recruitment_recruitmentcandidature.lib.php @@ -0,0 +1,85 @@ +. + */ + +/** + * \file lib/recruitment_recruitmentcandidature.lib.php + * \ingroup recruitment + * \brief Library files with common functions for RecruitmentCandidature + */ + +/** + * Prepare array of tabs for RecruitmentCandidature + * + * @param RecruitmentJobPosition $object RecruitmentCandidature + * @return array Array of tabs + */ +function recruitmentCandidaturePrepareHead($object) +{ + global $db, $langs, $conf; + + $langs->load("recruitment"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/recruitment/recruitmentcandidature_card.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("RecruitmentCandidature"); + $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('/recruitment/recruitmentcandidature_note.php', 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) $head[$h][1] .= ''.$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->recruitment->dir_output."/recruitmentcandidature/".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("/recruitment/recruitmentcandidature_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("/recruitment/recruitmentcandidature_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:@recruitment:/recruitment/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@recruitment:/recruitment/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'recruitmentcandidature'); + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'recruitmentcandidature', 'remove'); + + return $head; +} diff --git a/htdocs/recruitment/recruitmentcandidature_card.php b/htdocs/recruitment/recruitmentcandidature_card.php new file mode 100644 index 00000000000..c2d3866feaf --- /dev/null +++ b/htdocs/recruitment/recruitmentcandidature_card.php @@ -0,0 +1,612 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * 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 recruitmentcandidature_card.php + * \ingroup recruitment + * \brief Page to create/edit/view recruitmentcandidature + */ + +//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 + + +// 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('/recruitment/class/recruitmentcandidature.class.php'); +dol_include_once('/recruitment/lib/recruitment_recruitmentcandidature.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("recruitment", "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') : 'recruitmentcandidaturecard'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); +$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); +//$lineid = GETPOST('lineid', 'int'); + +// Initialize technical objects +$object = new RecruitmentCandidature($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->recruitment->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('recruitmentcandidaturecard', '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 = trim(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->recruitment->recruitmentjobposition->read; +$permissiontoadd = $user->rights->recruitment->recruitmentjobposition->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php +$permissiontodelete = $user->rights->recruitment->recruitmentjobposition->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT); +$permissionnote = $user->rights->recruitment->recruitmentjobposition->write; // Used by the include of actions_setnotes.inc.php +$permissiondellink = $user->rights->recruitment->recruitmentjobposition->write; // Used by the include of actions_dellink.inc.php +$upload_dir = $conf->recruitment->multidir_output[isset($object->entity) ? $object->entity : 1]; + +// Security check - Protection if external user +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +//$isdraft = (($object->statut == $object::STATUS_DRAFT) ? 1 : 0); +//$result = restrictedArea($user, 'recruitment', $object->id, '', '', 'fk_soc', 'rowid', $isdraft); + +//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('/recruitment/recruitmentcandidature_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('/recruitment/recruitmentcandidature_card.php', 1).'?id='.($id > 0 ? $id : '__ID__'); + } + } + $triggermodname = 'RECRUITMENT_RECRUITMENTCANDIDATURE_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, 'RECRUITMENTCANDIDATURE_MODIFY'); + } + if ($action == 'classin' && $permissiontoadd) + { + $object->setProject(GETPOST('projectid', 'int')); + } + + // Actions to send emails + $triggersendname = 'RECRUITMENTCANDIDATURE_SENTBYMAIL'; + $autocopy = 'MAIN_MAIL_AUTOCOPY_RECRUITMENTCANDIDATURE_TO'; + $trackid = 'recruitmentcandidature'.$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("RecruitmentCandidature"); +$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->transnoentitiesnoconv("RecruitmentCandidature")), '', 'object_'.$object->picto); + + print '
'; + print ''; + print ''; + if ($backtopage) print ''; + if ($backtopageforcancel) print ''; + + dol_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"; + + dol_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("RecruitmentCandidature"), '', 'object_'.$object->picto); + + print '
'; + print ''; + print ''; + print ''; + if ($backtopage) print ''; + if ($backtopageforcancel) print ''; + + dol_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 '
'; + + dol_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 = recruitmentcandidaturePrepareHead($object); + dol_fiche_head($head, 'card', $langs->trans("RecruitmentCandidature"), -1, $object->picto); + + $formconfirm = ''; + + // Confirmation to delete + if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteRecruitmentCandidature'), $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 = '
'; + /* + // 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); + + + 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 + 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 '
'; + + dol_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 + $object->formAddObjectLine(1, $mysoc, $soc); + + $parameters = array(); + $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + } + } + + 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)) + { + // Send + if (empty($user->socid)) { + print ''.$langs->trans('SendMail').''."\n"; + } + + // Back to draft + if ($object->status == $object::STATUS_VALIDATED) + { + if ($permissiontoadd) + { + print ''.$langs->trans("SetToDraft").''; + } + } + + // Modify + if ($permissiontoadd) + { + print ''.$langs->trans("Modify").''."\n"; + } else { + print ''.$langs->trans('Modify').''."\n"; + } + + // Validate + if ($object->status == $object::STATUS_DRAFT) + { + if ($permissiontoadd) + { + if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) + { + print ''.$langs->trans("Validate").''; + } else { + $langs->load("errors"); + print ''.$langs->trans("Validate").''; + } + } + } + + // Refuse - Decline + if ($object->status >= $object::STATUS_DRAFT && $object->status < $object::STATUS_CANCELED) + { + if ($permissiontoadd) + { + print ''.$langs->trans("Decline").''; + } + } + + // Clone + if ($permissiontoadd) + { + print ''.$langs->trans("ToClone").''."\n"; + } + + /* + if ($permissiontoadd) + { + if ($object->status == $object::STATUS_ENABLED) + { + print ''.$langs->trans("Disable").''."\n"; + } + else + { + print ''.$langs->trans("Enable").''."\n"; + } + } + if ($permissiontoadd) + { + if ($object->status == $object::STATUS_VALIDATED) + { + print ''.$langs->trans("Cancel").''."\n"; + } + else + { + print ''.$langs->trans("Re-Open").''."\n"; + } + } + */ + + // Delete (need delete permission, or if draft, just need create/modify permission) + if ($permissiontodelete || ($object->status == $object::STATUS_DRAFT && $permissiontoadd)) + { + print ''.$langs->trans('Delete').''."\n"; + } else { + print ''.$langs->trans('Delete').''."\n"; + } + } + print '
'."\n"; + } + + + // Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } + + if ($action != 'presend') + { + print '
'; + print ''; // ancre + + $includedocgeneration = 1; + + // Documents + if ($includedocgeneration) { + $objref = dol_sanitizeFileName($object->ref); + $relativepath = $objref . '/' . $objref . '.pdf'; + $filedir = $conf->recruitment->dir_output.'/'.$object->element.'/'.$objref; + $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id; + $genallowed = $user->rights->recruitment->recruitmentcandidature->read; // If you can read, you can build the PDF to read content + $delallowed = $user->rights->recruitment->recruitmentcandidature->write; // If you can create/edit, you can remove a file on card + print $formfile->showdocuments('recruitment:RecruitmentCandidature', $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('recruitmentcandidature')); + $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.'@recruitment', (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 = 'recruitmentcandidature'; + $defaulttopic = 'InformationMessage'; + $diroutput = $conf->recruitment->dir_output; + $trackid = 'recruitmentcandidature'.$object->id; + + include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php'; +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/recruitment/recruitmentcandidature_list.php b/htdocs/recruitment/recruitmentcandidature_list.php new file mode 100644 index 00000000000..62610ad96d8 --- /dev/null +++ b/htdocs/recruitment/recruitmentcandidature_list.php @@ -0,0 +1,601 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * 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 recruitmentcandidature_list.php + * \ingroup recruitment + * \brief List page for recruitmentcandidature + */ + +//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('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//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) +//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("XFRAMEOPTIONS_ALLOWALL")) define('XFRAMEOPTIONS_ALLOWALL', '1'); // Do not add the HTTP header 'X-Frame-Options: SAMEORIGIN' but 'X-Frame-Options: ALLOWALL' + +// 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 recruitment libraries +require_once __DIR__.'/class/recruitmentcandidature.class.php'; + +// for other modules +//dol_include_once('/othermodule/class/otherobject.class.php'); + +// Load translation files required by the page +$langs->loadLangs(array("recruitment@recruitment", "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') : 'recruitmentcandidaturelist'; // 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', 'alpha'); +$sortorder = GETPOST('sortorder', 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { $page = 0; } // If $page is not defined, or '' or -1 or if we click on clear filters +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +// Initialize technical objects +$object = new RecruitmentCandidature($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->recruitment->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('recruitmentcandidaturelist')); // 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) $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') ? trim(GETPOST('search_all', 'alphanohtml')) : trim(GETPOST('sall', 'alphanohtml')); +$search = array(); +foreach ($object->fields as $key => $val) +{ + if (GETPOST('search_'.$key, 'alpha') !== '') $search[$key] = GETPOST('search_'.$key, 'alpha'); +} + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array(); +foreach ($object->fields as $key => $val) +{ + if ($val['searchall']) $fieldstosearchall['t.'.$key] = $val['label']; +} + +// Definition of fields for list +$arrayfields = array(); +foreach ($object->fields as $key => $val) +{ + // If $val['visible']==0, then we never show the field + if (!empty($val['visible'])) { + $visible = 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'] + ); + } +} +// Extra fields +if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) +{ + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) + { + if (!empty($extrafields->attributes[$object->table_element]['list'][$key])) { + $arrayfields["ef.".$key] = array( + 'label'=>$extrafields->attributes[$object->table_element]['label'][$key], + 'checked'=>(($extrafields->attributes[$object->table_element]['list'][$key] < 0) ? 0 : 1), + 'position'=>$extrafields->attributes[$object->table_element]['pos'][$key], + 'enabled'=>(abs($extrafields->attributes[$object->table_element]['list'][$key]) != 3 && $extrafields->attributes[$object->table_element]['perms'][$key]) + ); + } + } +} +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + +$permissiontoread = $user->rights->recruitment->recruitmentjobposition->read; +$permissiontoadd = $user->rights->recruitment->recruitmentjobposition->write; +$permissiontodelete = $user->rights->recruitment->recruitmentjobposition->delete; + +// Security check +if (empty($conf->recruitment->enabled)) accessforbidden('Module not enabled'); +$socid = 0; +if ($user->socid > 0) // Protection if external user +{ + //$socid = $user->socid; + accessforbidden(); +} +//$result = restrictedArea($user, 'recruitment', $id, ''); +//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] = ''; + } + $toselect = ''; + $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 = 'RecruitmentCandidature'; + $objectlabel = 'RecruitmentCandidature'; + $uploaddir = $conf->recruitment->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + + +/* + * View + */ + +$form = new Form($db); + +$now = dol_now(); + +//$help_url="EN:Module_RecruitmentCandidature|FR:Module_RecruitmentCandidature_FR|ES:Módulo_RecruitmentCandidature"; +$help_url = ''; +$title = $langs->trans('ListOfCandidatures'); + + +// Build and execute select +// -------------------------------------------------------------------- +$sql = 'SELECT '; +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.' 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 (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)"; +if ($object->ismultientitymanaged == 1) $sql .= " WHERE t.entity IN (".getEntity($object->element).")"; +else $sql .= " WHERE 1 = 1"; +foreach ($search as $key => $val) +{ + 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) { + if ($search[$key] == '-1') $search[$key] = ''; + $mode_search = 2; + } + if ($search[$key] != '') $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search)); +} +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); // 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('/recruitment/recruitmentcandidature_card.php', 1).'?id='.$id); + exit; +} + + +// Output page +// -------------------------------------------------------------------- + +llxHeader('', $title, $help_url); + +// 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'; + +// List of mass actions available +$arrayofmassactions = array( + //'validate'=>$langs->trans("Validate"), + //'generate_doc'=>$langs->trans("ReGeneratePDF"), + //'builddoc'=>$langs->trans("PDFMerge"), + //'presend'=>$langs->trans("SendByMail"), +); +if ($permissiontodelete) $arrayofmassactions['predelete'] = ''.$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('/recruitment/recruitmentcandidature_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 = "SendRecruitmentCandidatureRef"; +$modelmail = "recruitmentcandidature"; +$objecttmp = new RecruitmentCandidature($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['css']) ? '' : $val['css']); + 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') $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['css']) ? '' : $val['css']); + 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') $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 (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(); +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['css']) ? '' : $val['css']); + 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')) && $key != 'status') $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); + 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; + $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 (is_array($val['arrayofkeyval'])) print $form->selectarray('search_'.$key, $val['arrayofkeyval'], $search[$key], $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth75'); + elseif (strpos($val['type'], 'integer:') === 0) { + print $object->showInputField($val, $key, $search[$key], '', '', 'search_', 'maxwidth150', 1); + } elseif (!preg_match('/^(date|timestamp)/', $val['type'])) 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_recruitment', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); +} + +// End of page +llxFooter(); +$db->close();