[IMP] hr_recruitment: allow multiple interviewers on applicant

Allow multiple interviewers on hr.applicant instead of a Many2One.

odoo/upgrade#3904
task-2939388

closes odoo/odoo#100338

Signed-off-by: Kevin Baptiste <kba@odoo.com>
This commit is contained in:
Kevin Baptiste
2022-09-16 23:49:43 +02:00
parent 395b30e39d
commit b658171ea2
6 changed files with 27 additions and 27 deletions
+4 -4
View File
@@ -82,16 +82,16 @@ class Job(models.Model):
job.activities_overdue = job_activities[job.id].get('overdue', 0)
job.activities_today = job_activities[job.id].get('today', 0)
@api.depends('application_ids.interviewer_id')
@api.depends('application_ids.interviewer_ids')
def _compute_extended_interviewer_ids(self):
# Use SUPERUSER_ID as the search_read is protected in hr_referral
results_raw = self.env['hr.applicant'].with_user(SUPERUSER_ID).search_read([
('job_id', 'in', self.ids),
('interviewer_id', '!=', False)
], ['interviewer_id', 'job_id'])
('interviewer_ids', '!=', False)
], ['interviewer_ids', 'job_id'])
interviewers_by_job = defaultdict(set)
for result_raw in results_raw:
interviewers_by_job[result_raw['job_id'][0]].add(result_raw['interviewer_id'][0])
interviewers_by_job[result_raw['job_id'][0]] |= set(result_raw['interviewer_ids'])
for job in self:
job.extended_interviewer_ids = [(6, 0, list(interviewers_by_job[job.id]))]
@@ -190,8 +190,8 @@ class Applicant(models.Model):
campaign_id = fields.Many2one(ondelete='set null')
medium_id = fields.Many2one(ondelete='set null')
source_id = fields.Many2one(ondelete='set null')
interviewer_id = fields.Many2one(
'res.users', string='Interviewer', index=True, tracking=True,
interviewer_ids = fields.Many2many('res.users', 'hr_applicant_res_users_interviewers_rel',
string='Interviewers', index=True, tracking=True,
domain="[('share', '=', False), ('company_ids', 'in', company_id)]")
linkedin_profile = fields.Char('LinkedIn Profile')
application_status = fields.Selection([
@@ -391,7 +391,7 @@ class Applicant(models.Model):
if vals.get('email_from'):
vals['email_from'] = vals['email_from'].strip()
applicants = super().create(vals_list)
applicants.sudo().interviewer_id._create_recruitment_interviewers()
applicants.sudo().interviewer_ids._create_recruitment_interviewers()
# Record creation through calendar, creates the calendar event directly, it will also create the activity.
if 'default_activity_date_deadline' in self.env.context:
deadline = fields.Datetime.to_datetime(self.env.context.get('default_activity_date_deadline'))
@@ -415,7 +415,7 @@ class Applicant(models.Model):
vals['date_open'] = fields.Datetime.now()
if vals.get('email_from'):
vals['email_from'] = vals['email_from'].strip()
old_interviewers = self.interviewer_id
old_interviewers = self.interviewer_ids
# stage_id: track last stage before update
if 'stage_id' in vals:
vals['date_last_stage_update'] = fields.Datetime.now()
@@ -426,10 +426,10 @@ class Applicant(models.Model):
res = super(Applicant, self).write(vals)
else:
res = super(Applicant, self).write(vals)
if 'interviewer_id' in vals:
interviewers_to_clean = old_interviewers - self.interviewer_id
if 'interviewer_ids' in vals:
interviewers_to_clean = old_interviewers - self.interviewer_ids
interviewers_to_clean._remove_recruitment_interviewers()
self.sudo().interviewer_id._create_recruitment_interviewers()
self.sudo().interviewer_ids._create_recruitment_interviewers()
return res
def get_empty_list_help(self, help):
+2 -2
View File
@@ -26,8 +26,8 @@ class ResUsers(models.Model):
job_interviewers = self.env['hr.job']._read_group([('interviewer_ids', 'in', self.ids)], ['interviewer_ids'], ['interviewer_ids'])
user_ids = {j['interviewer_ids'][0] for j in job_interviewers}
application_interviewers = self.env['hr.applicant']._read_group([('interviewer_id', 'in', self.ids)], ['interviewer_id'], ['interviewer_id'])
user_ids |= {a['interviewer_id'][0] for a in application_interviewers}
application_interviewers = self.env['hr.applicant']._read_group([('interviewer_ids', 'in', self.ids)], ['interviewer_ids'], ['interviewer_ids'])
user_ids |= {a['interviewer_ids'][0] for a in application_interviewers}
# Remove users that are no longer interviewers on at least a job or an application
users_to_remove = set(self.ids) - (user_ids | set(recruitment_group.users.ids))
@@ -52,7 +52,7 @@
<field name="domain_force">[
'|',
('job_id.interviewer_ids', 'in', user.id),
('interviewer_id', '=', user.id),
('interviewer_ids', 'in', user.id),
]</field>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
@@ -46,30 +46,30 @@ class TestRecruitmentInterviewer(MailCommon):
'name': 'toto',
'partner_name': 'toto',
'job_id': self.job.id,
'interviewer_id': self.simple_user.id,
'interviewer_ids': self.simple_user.ids,
})
self.assertTrue(interviewer_group.id in self.simple_user.groups_id.ids, "Simple User should be added as interviewer")
applicant.interviewer_id = False
applicant.interviewer_ids = False
self.assertFalse(interviewer_group.id in self.simple_user.groups_id.ids, "Simple User should be removed from interviewer")
self.job.interviewer_ids = self.simple_user.ids
applicant.interviewer_id = self.simple_user.id
applicant.interviewer_ids = self.simple_user.ids
self.assertTrue(interviewer_group.id in self.simple_user.groups_id.ids, "Simple User should be added as interviewer")
applicant.interviewer_id = False
applicant.interviewer_ids = False
self.assertTrue(interviewer_group.id in self.simple_user.groups_id.ids, "Simple User should stay interviewer")
self.job.write({'interviewer_ids': [(5, 0, 0)]})
applicant.interviewer_id = self.simple_user.id
applicant.interviewer_ids = self.simple_user.ids
self.assertTrue(interviewer_group.id in self.simple_user.groups_id.ids, "Simple User should stay interviewer")
applicant.interviewer_id = False
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_id = self.manager_user.id
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):
@@ -85,7 +85,7 @@ class TestRecruitmentInterviewer(MailCommon):
'name': 'toto',
'partner_name': 'toto',
'job_id': self.job.id,
'interviewer_id': self.interviewer_user.id,
'interviewer_ids': self.interviewer_user.ids,
})
applicant.with_user(self.interviewer_user).read()
@@ -98,8 +98,8 @@ class TestRecruitmentInterviewer(MailCommon):
applicant.with_user(self.interviewer_user).read()
# An interviewer can change the interviewers
applicant.with_user(self.interviewer_user).interviewer_id = self.simple_user.id
self.assertEqual(self.simple_user, applicant.interviewer_id)
applicant.with_user(self.interviewer_user).interviewer_ids = self.simple_user.ids
self.assertEqual(self.simple_user, applicant.interviewer_ids)
with self.assertRaises(AccessError):
applicant.with_user(self.interviewer_user).create_employee_from_applicant()
@@ -111,7 +111,7 @@ class TestRecruitmentInterviewer(MailCommon):
'name': 'toto',
'partner_name': 'toto',
'job_id': self.job.id,
'interviewer_id': self.interviewer_user.id,
'interviewer_ids': self.interviewer_user.ids,
})
applicant.message_subscribe(partner_ids=[self.interviewer_user.partner_id.id])
@@ -40,7 +40,7 @@
<field name="partner_mobile" widget="phone" readonly="1" optional="show" class="text-end"/>
<field name="categ_ids" widget="many2many_tags" options="{'color_field': 'color'}" optional="show"/>
<field name="user_id" widget="many2one_avatar_user" optional="show"/>
<field name="interviewer_id" widget="many2one_avatar_user" optional="hide"/>
<field name="interviewer_ids" widget="many2many_avatar_user" optional="hide"/>
<field name="create_date" readonly="1" widget="date" optional="show"/>
<field name="partner_phone" widget="phone" readonly="1" optional="hide"/>
<field name="medium_id" optional="hide"/>
@@ -145,7 +145,7 @@
</group>
<group>
<field name="categ_ids" placeholder="Tags" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/>
<field name="interviewer_id" options="{'no_create': True, 'no_create_edit': True}" widget="many2one_avatar_user" />
<field name="interviewer_ids" options="{'no_create': True, 'no_create_edit': True}" widget="many2many_avatar_user" />
<field name="user_id" widget="many2one_avatar_user"/>
<field name="date_closed" attrs="{'invisible': [('date_closed', '=', False)]}" />
<field name="priority" widget="priority"/>