diff --git a/addons/hr_recruitment/models/hr_applicant.py b/addons/hr_recruitment/models/hr_applicant.py index 4daf2848773..4ea632695be 100644 --- a/addons/hr_recruitment/models/hr_applicant.py +++ b/addons/hr_recruitment/models/hr_applicant.py @@ -280,7 +280,7 @@ class Applicant(models.Model): applicant.date_closed = False def _check_interviewer_access(self): - if self.user_has_groups('hr_recruitment.group_hr_recruitment_interviewer'): + if self.user_has_groups('hr_recruitment.group_hr_recruitment_interviewer') and not self.user_has_groups('hr_recruitment.group_hr_recruitment_user'): raise AccessError(_('You are not allowed to perform this action.')) @api.model_create_multi @@ -367,19 +367,20 @@ class Applicant(models.Model): def _notify_get_recipients(self, message, msg_vals, **kwargs): """ - Do not notify members of the Recruitment Interviewer group, as this + Do not notify members of the Recruitment Interviewer group that are not part of + Recruitment User group as well, as this might leak some data they shouldn't have access to. """ recipients = super()._notify_get_recipients(message, msg_vals, **kwargs) interviewer_group = self.env.ref('hr_recruitment.group_hr_recruitment_interviewer').id - return [recipient for recipient in recipients if interviewer_group not in recipient['groups']] + user_group = self.env.ref('hr_recruitment.group_hr_recruitment_user').id + return [recipient for recipient in recipients if not (interviewer_group in recipient['groups'] and user_group not in recipient['groups'])] def action_makeMeeting(self): """ This opens Meeting's calendar view to schedule meeting on current applicant @return: Dictionary value for created Meeting view """ self.ensure_one() - if not self.partner_id: if not self.partner_name: raise UserError(_('You must define a Contact Name for this applicant.')) @@ -392,11 +393,20 @@ class Applicant(models.Model): 'mobile': self.partner_mobile }) - partners = self.partner_id | self.user_id.partner_id | self.department_id.manager_id.user_id.partner_id + partners = self.partner_id | self.department_id.manager_id.user_id.partner_id + if self.user_has_groups('hr_recruitment.group_hr_recruitment_interviewer') and not self.user_has_groups('hr_recruitment.group_hr_recruitment_user'): + partners |= self.env.user.partner_id + else: + partners |= self.user_id.partner_id category = self.env.ref('hr_recruitment.categ_meet_interview') res = self.env['ir.actions.act_window']._for_xml_id('calendar.action_calendar_event') + # As we are redirected from the hr.applicant, calendar checks rules on "hr.applicant", + # in order to decide whether to allow creation of a meeting. + # As interviewer does not have create right on the hr.applicant, in order to allow them + # to create a meeting for an applicant, we pass 'create': True to the context. res['context'] = { + 'create': True, 'default_applicant_id': self.id, 'default_partner_ids': partners.ids, 'default_user_id': self.env.uid, diff --git a/addons/hr_recruitment/models/ir_ui_menu.py b/addons/hr_recruitment/models/ir_ui_menu.py index 8a376826a5c..571b850c68a 100644 --- a/addons/hr_recruitment/models/ir_ui_menu.py +++ b/addons/hr_recruitment/models/ir_ui_menu.py @@ -9,6 +9,8 @@ class IrUiMenu(models.Model): def _load_menus_blacklist(self): res = super()._load_menus_blacklist() - if self.env.user.has_group('hr_recruitment.group_hr_recruitment_interviewer'): + if self.env.user.has_group('hr_recruitment.group_hr_recruitment_interviewer') and not self.env.user.has_group('hr_recruitment.group_hr_recruitment_user'): res.append(self.env.ref('hr_recruitment.menu_hr_job_position').id) + elif self.env.user.has_group('hr_recruitment.group_hr_recruitment_user'): + res.append(self.env.ref('hr_recruitment.menu_hr_job_position_interviewer').id) return res diff --git a/addons/hr_recruitment/security/hr_recruitment_security.xml b/addons/hr_recruitment/security/hr_recruitment_security.xml index 17099c3c87c..2b337c5e3d5 100644 --- a/addons/hr_recruitment/security/hr_recruitment_security.xml +++ b/addons/hr_recruitment/security/hr_recruitment_security.xml @@ -2,7 +2,7 @@ - The user interacting with the application as interviewer don't need any specific access. They'll have access thanks to their interviewer assignation. + Interviewer right will give access to all job position/applications where the employee is defined. It will allow to refuse, plan meetings. Chatter content will not be available. 11 @@ -14,15 +14,15 @@ - Recruitment Interviewer - + Interviewer + Officer: Manage all applicants - + @@ -59,6 +59,20 @@ + + User: All Applicants + + [(1, '=', 1)] + + + + + User: All Applicants + + [(1, '=', 1)] + + + Interviewer: No Applicant Chatter @@ -74,4 +88,11 @@ + + + User: All Chatter + + [(1, '=', 1)] + + diff --git a/addons/hr_recruitment/tests/test_recruitment_interviewer.py b/addons/hr_recruitment/tests/test_recruitment_interviewer.py index 0e13a596e61..eeab5a9d3a3 100644 --- a/addons/hr_recruitment/tests/test_recruitment_interviewer.py +++ b/addons/hr_recruitment/tests/test_recruitment_interviewer.py @@ -67,11 +67,6 @@ class TestRecruitmentInterviewer(MailCommon): applicant.interviewer_ids = False self.assertFalse(interviewer_group.id in self.simple_user.groups_id.ids, "Simple User should be removed from interviewer") - # A Manager should not be added to the Interviewer group - self.assertFalse(interviewer_group.id in self.manager_user.groups_id.ids, "Manager User should not be interviewer") - applicant.interviewer_ids = self.manager_user.ids - self.assertFalse(interviewer_group.id in self.manager_user.groups_id.ids, "Manager User should not be added in Interviewer group") - def test_interviewer_access_rights(self): applicant = self.env['hr.applicant'].create({ 'name': 'toto', diff --git a/addons/hr_recruitment_skills/security/hr_recruitment_skills_security.xml b/addons/hr_recruitment_skills/security/hr_recruitment_skills_security.xml index 3d2eba831db..8352c26e65b 100644 --- a/addons/hr_recruitment_skills/security/hr_recruitment_skills_security.xml +++ b/addons/hr_recruitment_skills/security/hr_recruitment_skills_security.xml @@ -11,4 +11,12 @@ ] + + + Applicant Skill: Officer + + [(1, '=', 1)] + + + diff --git a/addons/hr_recruitment_skills/security/ir.model.access.csv b/addons/hr_recruitment_skills/security/ir.model.access.csv index ec8287d0e9a..f11e20132bf 100644 --- a/addons/hr_recruitment_skills/security/ir.model.access.csv +++ b/addons/hr_recruitment_skills/security/ir.model.access.csv @@ -1,3 +1,2 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -hr_recruitment_skills.access_hr_applicant_skill,access_hr_applicant_skill,hr_recruitment_skills.model_hr_applicant_skill,hr_recruitment.group_hr_recruitment_user,1,1,1,1 -hr_recruitment_skills.access_hr_applicant_skill_interviewer,access_hr_applicant_skill_interviewer,hr_recruitment_skills.model_hr_applicant_skill,hr_recruitment.group_hr_recruitment_interviewer,1,0,0,0 +hr_recruitment_skills.access_hr_applicant_skill_interviewer,access_hr_applicant_skill_interviewer,hr_recruitment_skills.model_hr_applicant_skill,hr_recruitment.group_hr_recruitment_interviewer,1,1,1,1 diff --git a/addons/hr_recruitment_skills/views/hr_applicant_views.xml b/addons/hr_recruitment_skills/views/hr_applicant_views.xml index aac87508aec..bd02884f5c3 100644 --- a/addons/hr_recruitment_skills/views/hr_applicant_views.xml +++ b/addons/hr_recruitment_skills/views/hr_applicant_views.xml @@ -12,7 +12,7 @@ + context="{'default_applicant_id': id}"> diff --git a/addons/hr_recruitment_survey/models/hr_applicant.py b/addons/hr_recruitment_survey/models/hr_applicant.py index 7b62eb205b4..acbdd795753 100644 --- a/addons/hr_recruitment_survey/models/hr_applicant.py +++ b/addons/hr_recruitment_survey/models/hr_applicant.py @@ -18,12 +18,18 @@ class Applicant(models.Model): .filtered(lambda i: i.survey_id == self.survey_id)\ .sorted(lambda i: i.create_date, reverse=True) if not sorted_interviews: - return self.survey_id.action_print_survey() + action = self.survey_id.action_print_survey() + action['target'] = 'new' + return action answered_interviews = sorted_interviews.filtered(lambda i: i.state == 'done') if answered_interviews: - return self.survey_id.action_print_survey(answer=answered_interviews[0]) - return self.survey_id.action_print_survey(answer=sorted_interviews[0]) + action = self.survey_id.action_print_survey(answer=answered_interviews[0]) + action['target'] = 'new' + return action + action = self.survey_id.action_print_survey(answer=sorted_interviews[0]) + action['target'] = 'new' + return action def action_send_survey(self): self.ensure_one() @@ -32,7 +38,7 @@ class Applicant(models.Model): if not self.partner_id: if not self.partner_name: raise UserError(_('Please provide an applicant name.')) - self.partner_id = self.env['res.partner'].create({ + self.partner_id = self.env['res.partner'].sudo().create({ 'is_company': False, 'type': 'private', 'name': self.partner_name, diff --git a/addons/hr_recruitment_survey/security/hr_recruitment_survey_security.xml b/addons/hr_recruitment_survey/security/hr_recruitment_survey_security.xml index 4df1366f2e5..66b739eadb7 100644 --- a/addons/hr_recruitment_survey/security/hr_recruitment_survey_security.xml +++ b/addons/hr_recruitment_survey/security/hr_recruitment_survey_security.xml @@ -1,8 +1,28 @@ - - + + + It will also allow to send surveys and see the resume. + + + Survey user input: officer: read all non private survey answers + [('applicant_id', '=', False)] + + + Survey user input: recruitment interview: read survey answers for which they are set as interviewer + + [ + ('applicant_id', '!=', False), + '|', + ('applicant_id.interviewer_ids', 'in', user.id), + ('applicant_id.job_id.interviewer_ids', 'in', user.id), + ] + + + + + diff --git a/addons/hr_recruitment_survey/views/hr_applicant_views.xml b/addons/hr_recruitment_survey/views/hr_applicant_views.xml index 54680b5d034..fab2019ac64 100644 --- a/addons/hr_recruitment_survey/views/hr_applicant_views.xml +++ b/addons/hr_recruitment_survey/views/hr_applicant_views.xml @@ -26,7 +26,7 @@ icon="fa-pencil-square-o" type="object" help="See interview report" - attrs="{'invisible':['|',('survey_id','=',False),('response_ids','=',False)]}"> + attrs="{'invisible':['|',('survey_id','=',False),('response_ids','=',[])]}">
Consult Interview diff --git a/addons/hr_recruitment_survey/wizard/survey_invite.py b/addons/hr_recruitment_survey/wizard/survey_invite.py index 6d01cc484d5..3c1a9bae9b8 100644 --- a/addons/hr_recruitment_survey/wizard/survey_invite.py +++ b/addons/hr_recruitment_survey/wizard/survey_invite.py @@ -31,8 +31,8 @@ class SurveyInvite(models.TransientModel): survey = self.survey_id.with_context(clean_context(self.env.context)) if not self.applicant_id.response_ids.filtered(lambda res: res.survey_id.id == self.survey_id.id): - self.applicant_id.write({ - 'response_ids': (self.applicant_id.response_ids | survey._create_answer(partner=self.applicant_id.partner_id, + self.applicant_id.sudo().write({ + 'response_ids': (self.applicant_id.response_ids | survey.sudo()._create_answer(partner=self.applicant_id.partner_id, **self._get_answers_values())).ids })