mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-26 05:32:03 +02:00
494 lines
20 KiB
Python
494 lines
20 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import base64
|
|
|
|
from odoo import Command
|
|
from odoo.fields import Domain
|
|
from odoo.tests import tagged, TransactionCase, Form
|
|
|
|
|
|
@tagged('recruitment')
|
|
class TestRecruitment(TransactionCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
|
|
cls.company = cls.env['res.company'].create({
|
|
'name': 'Company Test',
|
|
'country_id': cls.env.ref('base.us').id,
|
|
})
|
|
cls.env.user.company_id = cls.company
|
|
cls.env.user.company_ids = [Command.set(cls.company.ids)]
|
|
|
|
cls.TEXT = base64.b64encode(bytes("hr_recruitment", 'utf-8'))
|
|
cls.Attachment = cls.env['ir.attachment']
|
|
|
|
def test_infer_applicant_lang_from_context(self):
|
|
# Prerequisites
|
|
self.env['res.lang']._activate_lang('pl_PL')
|
|
self.env['res.lang']._activate_lang('en_US')
|
|
self.env['ir.default'].set('res.partner', 'lang', 'en_US')
|
|
|
|
# Creating an applicant will create a partner (email_from inverse)
|
|
applicant = self.env['hr.applicant'].sudo().with_context(lang='pl_PL').create({
|
|
'partner_name': 'Test Applicant',
|
|
'email_from': "test_aplicant@example.com"
|
|
})
|
|
self.assertEqual(applicant.partner_id.lang, 'pl_PL', 'Context langague not used for partner creation')
|
|
|
|
def test_duplicate_email(self):
|
|
# Tests that duplicate email matching is case insesitive
|
|
dup1, dup2, no_dup = self.env['hr.applicant'].create([
|
|
{
|
|
'partner_name': 'Application 1',
|
|
'email_from': 'laurie.poiret@aol.ru',
|
|
},
|
|
{
|
|
'partner_name': 'Application 2',
|
|
'email_from': 'laurie.POIRET@aol.ru',
|
|
},
|
|
{
|
|
'partner_name': 'Application 3',
|
|
'email_from': 'laure.poiret@aol.ru',
|
|
},
|
|
])
|
|
self.assertEqual(dup1.application_count, 2)
|
|
self.assertEqual(dup2.application_count, 2)
|
|
self.assertEqual(no_dup.application_count, 1)
|
|
|
|
def test_similar_applicants_count(self):
|
|
"""Test that we find same applicant based on simmilar mail or phone."""
|
|
A, B, C, D, E, F, _ = self.env['hr.applicant'].create([
|
|
{
|
|
'active': False, # Refused/archived application should still count
|
|
'partner_name': 'Application A',
|
|
'email_from': 'abc@odoo.com',
|
|
'partner_phone': '123',
|
|
},
|
|
{
|
|
'partner_name': 'Application B',
|
|
'partner_phone': '456',
|
|
},
|
|
{
|
|
'partner_name': 'Application C',
|
|
'email_from': 'def@odoo.com',
|
|
'partner_phone': '123',
|
|
},
|
|
{
|
|
'partner_name': 'Application D',
|
|
'email_from': 'abc@odoo.com',
|
|
'partner_phone': '456',
|
|
},
|
|
{
|
|
'partner_name': 'Application E',
|
|
'partner_phone': '',
|
|
},
|
|
{
|
|
'partner_name': 'Application F',
|
|
'email_from': 'ghi@odoo.com',
|
|
'partner_phone': '789',
|
|
},
|
|
{
|
|
'partner_name': 'Application G',
|
|
},
|
|
])
|
|
self.assertEqual(A.application_count, 3) # A, C, D
|
|
self.assertEqual(B.application_count, 2) # B, D
|
|
self.assertEqual(C.application_count, 2) # C, A
|
|
self.assertEqual(D.application_count, 3) # D, A, B
|
|
self.assertEqual(E.application_count, 0) # Should not match with E and G as there is no data to use for matching.
|
|
self.assertEqual(F.application_count, 1) # F
|
|
|
|
def test_talent_pool_count(self):
|
|
tp_A, tp_B = self.env["hr.talent.pool"].create([{"name": "Cool Pool"}, {"name": "Other Pool"}])
|
|
t_A, t_B = self.env["hr.applicant"].create(
|
|
[
|
|
{
|
|
"partner_name": "Talent A",
|
|
"email_from": "abc@example.com",
|
|
"partner_phone": "1234",
|
|
"linkedin_profile": "linkedin/talent",
|
|
"talent_pool_ids": [tp_A.id, tp_B.id],
|
|
},
|
|
{
|
|
"partner_name": "Talent B",
|
|
"email_from": "talent_b@example.com",
|
|
"partner_phone": "9999",
|
|
"talent_pool_ids": [tp_B.id],
|
|
},
|
|
]
|
|
)
|
|
# The only way to create a talent is through the wizards. Talents that are
|
|
# created through the wizard also assign their own ID as pool_applicant_id
|
|
t_A.pool_applicant_id = t_A.id
|
|
t_B.pool_applicant_id = t_B.id
|
|
|
|
A, B, C, D, E, F, G = self.env["hr.applicant"].create(
|
|
[
|
|
{"partner_name": "A", "pool_applicant_id": t_A.id},
|
|
{
|
|
"partner_name": "B",
|
|
"email_from": "def@example.com",
|
|
"partner_phone": "6789",
|
|
"linkedin_profile": "linkedin/b",
|
|
"pool_applicant_id": t_A.id,
|
|
},
|
|
{
|
|
"partner_name": "C",
|
|
"email_from": "def@example.com",
|
|
},
|
|
{
|
|
"partner_name": "D",
|
|
"partner_phone": "6789",
|
|
},
|
|
{
|
|
"partner_name": "E",
|
|
"linkedin_profile": "linkedin/b",
|
|
},
|
|
{
|
|
"partner_name": "F",
|
|
"email_from": "not_linked@example.com",
|
|
"partner_phone": "00000",
|
|
"linkedin_profile": "linkedin/not_linked",
|
|
},
|
|
{"partner_name": "G", "pool_applicant_id": t_B.id},
|
|
]
|
|
)
|
|
self.assertEqual(t_A.talent_pool_count, 2)
|
|
self.assertEqual(t_B.talent_pool_count, 1)
|
|
self.assertEqual(A.talent_pool_count, 2)
|
|
self.assertEqual(B.talent_pool_count, 2)
|
|
self.assertEqual(C.talent_pool_count, 2)
|
|
self.assertEqual(D.talent_pool_count, 2)
|
|
self.assertEqual(E.talent_pool_count, 2)
|
|
self.assertEqual(F.talent_pool_count, 0)
|
|
self.assertEqual(G.talent_pool_count, 1)
|
|
|
|
def test_compute_and_search_is_applicant_in_pool(self):
|
|
"""
|
|
Test that the _compute_is_applicant_in_pool and _search_is_applicant_in_pool
|
|
methods return correct information.
|
|
An application is considered to be in a pool if it is either directly linked
|
|
to a pool (through pool_applicant_id or talents_pool_ids) or shares a phone number,
|
|
email or linkedin with another directly linked application.
|
|
"""
|
|
talent_pool = self.env["hr.talent.pool"].create({"name": "Cool Pool"})
|
|
job = self.env["hr.job"].create(
|
|
{
|
|
"name": "Cool Job",
|
|
}
|
|
)
|
|
A, B, C, D, E, F, G, H = self.env["hr.applicant"].create(
|
|
[
|
|
{
|
|
"partner_name": "Talent A",
|
|
"email_from": "mainTalentEmail@example.com",
|
|
"talent_pool_ids": talent_pool.ids,
|
|
},
|
|
{
|
|
"partner_name": "Applicant 1 B",
|
|
"email_from": "otherTalentEmail@example.com",
|
|
"partner_phone": "1234",
|
|
"linkedin_profile": "linkedin.com/in/applicant",
|
|
"job_id": job.id,
|
|
},
|
|
{
|
|
"partner_name": "Applicant 1 C",
|
|
"email_from": "otherTalentEmail@example.com",
|
|
"job_id": job.id,
|
|
},
|
|
{
|
|
"partner_name": "Applicant 1 D",
|
|
"partner_phone": "1234",
|
|
"job_id": job.id,
|
|
},
|
|
{
|
|
"partner_name": "Applicant 1 E",
|
|
"linkedin_profile": "linkedin.com/in/applicant",
|
|
"job_id": job.id,
|
|
},
|
|
{
|
|
"partner_name": "A different applicant F",
|
|
"email_from": "differentEmail@example.com",
|
|
"partner_phone": "9876",
|
|
"linkedin_profile": "linkedin.com/in/NotAnApplicant",
|
|
"job_id": job.id,
|
|
},
|
|
{
|
|
"partner_name": "Talent With No information G",
|
|
"talent_pool_ids": talent_pool.ids,
|
|
},
|
|
{
|
|
"partner_name": "Applicant With No information H",
|
|
},
|
|
]
|
|
)
|
|
B.pool_applicant_id = A.id
|
|
H.pool_applicant_id = G.id
|
|
|
|
# Testing the compute
|
|
|
|
# A is directly linked to Cool Pool through talent_pool_ids
|
|
self.assertTrue(A.is_applicant_in_pool)
|
|
# B is directly linked to Cool Pool through pool_applicant_id
|
|
self.assertTrue(B.is_applicant_in_pool)
|
|
# C is indirectly linked through email to B who is directly linked
|
|
self.assertTrue(C.is_applicant_in_pool)
|
|
# D is indirectly linked through phone to B who is directly linked
|
|
self.assertTrue(D.is_applicant_in_pool)
|
|
# E is indirectly linked through linkedin to B who is directly linked
|
|
self.assertTrue(E.is_applicant_in_pool)
|
|
# F is not linked to a Pool
|
|
self.assertFalse(F.is_applicant_in_pool)
|
|
# G is directly linked to Cool Pool through talent_pool_ids
|
|
self.assertTrue(G.is_applicant_in_pool)
|
|
# H is directly linked to Cool Pool through pool_applicant_id
|
|
self.assertTrue(H.is_applicant_in_pool)
|
|
|
|
# Testing the search
|
|
# Note: For some reason testing the search does not work if the compute
|
|
# is not tested first which is why these two tests are in one test.
|
|
applicant = self.env["hr.applicant"]
|
|
in_pool_domain = applicant._search_is_applicant_in_pool("in", [True])
|
|
in_pool_applicants = applicant.search(Domain.AND([in_pool_domain, [("company_id", "=", self.env.company.id)]]))
|
|
out_of_pool_applicants = applicant.search(Domain.AND([~Domain(in_pool_domain), [("company_id", "=", self.env.company.id)]]))
|
|
self.assertCountEqual(in_pool_applicants, A | B | C | D | E | G | H)
|
|
self.assertCountEqual(out_of_pool_applicants, F)
|
|
|
|
def test_application_no_partner_duplicate(self):
|
|
""" Test that when applying, the existing partner
|
|
doesn't get duplicated.
|
|
"""
|
|
applicant_data = {
|
|
'partner_name': 'Test',
|
|
'email_from': 'test@thisisatest.com',
|
|
}
|
|
# First application, a partner should be created
|
|
self.env['hr.applicant'].create(applicant_data)
|
|
partner_count = self.env['res.partner'].search_count([('email', '=', 'test@thisisatest.com')])
|
|
self.assertEqual(partner_count, 1)
|
|
# Second application, no partner should be created
|
|
self.env['hr.applicant'].create(applicant_data)
|
|
partner_count = self.env['res.partner'].search_count([('email', '=', 'test@thisisatest.com')])
|
|
self.assertEqual(partner_count, 1)
|
|
|
|
def test_target_on_application_hiring(self):
|
|
"""
|
|
Test that the target is updated when hiring an applicant
|
|
"""
|
|
job = self.env['hr.job'].create({
|
|
'name': 'Test Job',
|
|
'no_of_recruitment': 1,
|
|
})
|
|
applicant = self.env['hr.applicant'].create({
|
|
'partner_name': 'Test Applicant',
|
|
'job_id': job.id,
|
|
})
|
|
stage_new = self.env['hr.recruitment.stage'].create({
|
|
'name': 'New',
|
|
'sequence': 0,
|
|
'hired_stage': False,
|
|
})
|
|
stage_hired = self.env['hr.recruitment.stage'].create({
|
|
'name': 'Hired',
|
|
'sequence': 1,
|
|
'hired_stage': True,
|
|
})
|
|
self.assertEqual(job.no_of_recruitment, 1)
|
|
applicant.stage_id = stage_hired
|
|
self.assertEqual(job.no_of_recruitment, 0)
|
|
|
|
applicant.stage_id = stage_new
|
|
self.assertEqual(job.no_of_recruitment, 1)
|
|
|
|
def test_open_refuse_applicant_wizard_without_partner_name(self):
|
|
"""Test opening the refuse wizard when the applicant has no partner_name."""
|
|
applicant = self.env['hr.applicant'].create({
|
|
'partner_phone': '123',
|
|
})
|
|
wizard = Form(self.env['applicant.get.refuse.reason'].with_context(
|
|
default_applicant_ids=[applicant.id], active_test=False))
|
|
|
|
wizard_applicant = wizard.applicant_ids[0]
|
|
self.assertFalse(wizard_applicant.partner_name)
|
|
|
|
def test_applicant_refuse_reason(self):
|
|
|
|
refuse_reason = self.env['hr.applicant.refuse.reason'].create([{'name': 'Fired'}])
|
|
|
|
app_1, app_2 = self.env['hr.applicant'].create([
|
|
{
|
|
'partner_name': 'Laurie Poiret',
|
|
'email_from': 'laurie.poiret@aol.ru',
|
|
},
|
|
{
|
|
'partner_name': 'Mitchell Admin',
|
|
'email_from': 'mitchell_admin@example.com',
|
|
},
|
|
])
|
|
|
|
applicant_get_refuse_reason = self.env['applicant.get.refuse.reason'].create([{
|
|
'refuse_reason_id': refuse_reason.id,
|
|
'applicant_ids': [app_1.id],
|
|
'duplicates': True
|
|
}])
|
|
applicant_get_refuse_reason.action_refuse_reason_apply()
|
|
self.assertFalse(self.env['hr.applicant'].search([('email_from', 'ilike', 'laurie.poiret@aol.ru')]))
|
|
self.assertEqual(
|
|
self.env['hr.applicant'].search([('email_from', 'ilike', 'mitchell_admin@example.com')]),
|
|
app_2
|
|
)
|
|
|
|
def test_applicant_refuse_mail_from_template(self):
|
|
mail_template = self.env['mail.template'].create({
|
|
'name': 'Test template',
|
|
'model_id': self.env['ir.model']._get('hr.applicant').id,
|
|
'email_from': 'test@test.test',
|
|
})
|
|
refuse_reason = self.env['hr.applicant.refuse.reason'].create({
|
|
'name': 'Not good',
|
|
})
|
|
applicant = self.env['hr.applicant'].create({
|
|
'partner_name': 'Laurie Poiret',
|
|
'email_from': 'laurie.poiret@aol.ru',
|
|
})
|
|
applicant_get_refuse_reason = self.env['applicant.get.refuse.reason'].create([{
|
|
'refuse_reason_id': refuse_reason.id,
|
|
'applicant_ids': applicant.ids,
|
|
'duplicates': True,
|
|
}])
|
|
mail_values = applicant_get_refuse_reason._prepare_mail_values(applicant)
|
|
self.assertEqual(mail_values['email_from'], self.env.user.email_formatted)
|
|
|
|
refuse_reason_template = self.env['hr.applicant.refuse.reason'].create({
|
|
'name': 'Fired',
|
|
'template_id': mail_template.id,
|
|
})
|
|
applicant_get_refuse_reason.refuse_reason_id = refuse_reason_template
|
|
mail_values = applicant_get_refuse_reason._prepare_mail_values(applicant)
|
|
self.assertEqual(mail_values['email_from'], 'test@test.test')
|
|
|
|
def test_copy_attachments_while_creating_employee(self):
|
|
"""
|
|
Test that attachments are copied when creating an employee from an applicant
|
|
"""
|
|
applicant_1 = self.env['hr.applicant'].create({
|
|
'partner_name': 'Applicant 1',
|
|
'email_from': 'test_applicant@example.com'
|
|
})
|
|
applicant_attachment = self.Attachment.create({
|
|
'datas': self.TEXT,
|
|
'name': 'textFile.txt',
|
|
'mimetype': 'text/plain',
|
|
'res_model': applicant_1._name,
|
|
'res_id': applicant_1.id
|
|
})
|
|
|
|
employee_applicant = applicant_1.create_employee_from_applicant()
|
|
self.assertTrue(employee_applicant['res_id'])
|
|
attachment_employee_applicant = self.Attachment.search([
|
|
('res_model', '=', employee_applicant['res_model']),
|
|
('res_id', '=', employee_applicant['res_id']),
|
|
])
|
|
self.assertEqual(applicant_attachment['datas'], attachment_employee_applicant['datas'])
|
|
|
|
def test_other_applications_count(self):
|
|
"""
|
|
Test that the application_count field does not change
|
|
when archiving or refusing a linked application.
|
|
"""
|
|
|
|
A1, A2, A3 = self.env["hr.applicant"].create(
|
|
[
|
|
{"partner_name": "test", "email_from": "test@example.com"},
|
|
{"partner_name": "test", "email_from": "test@example.com"},
|
|
{"partner_name": "test", "email_from": "test@example.com"},
|
|
]
|
|
)
|
|
|
|
self.assertEqual(A1.application_count, 3)
|
|
|
|
# Archive A2
|
|
A2.action_archive()
|
|
self.assertEqual(
|
|
A1.application_count,
|
|
3,
|
|
"Application_count should not change when archiving a linked application",
|
|
)
|
|
# Refuse A3
|
|
refuse_reason = self.env["hr.applicant.refuse.reason"].create([{"name": "Fired"}])
|
|
applicant_get_refuse_reason = self.env["applicant.get.refuse.reason"].create(
|
|
[
|
|
{
|
|
"refuse_reason_id": refuse_reason.id,
|
|
"applicant_ids": [A3.id],
|
|
}
|
|
]
|
|
)
|
|
applicant_get_refuse_reason.action_refuse_reason_apply()
|
|
self.assertEqual(
|
|
A1.application_count,
|
|
3,
|
|
"The other_applications_count should not change when refusing an application",
|
|
)
|
|
|
|
def test_open_other_applications_count(self):
|
|
"""
|
|
The smart button labeled 'Other Applications N' (where N represents the number of
|
|
other job applications linked to the same applicant) should, when clicked, open a list view
|
|
displaying all related applications.
|
|
|
|
This list should include both the N other applications and the current one,
|
|
resulting in a total of N + 1 records.
|
|
"""
|
|
|
|
A1, _, _ = self.env["hr.applicant"].create(
|
|
[
|
|
{"partner_name": "test", "email_from": "test@example.com"},
|
|
{"partner_name": "test", "email_from": "test@example.com"},
|
|
{"partner_name": "test", "email_from": "test@example.com"},
|
|
]
|
|
)
|
|
|
|
res = A1.action_open_applications()
|
|
self.assertEqual(len(res['domain'][0][2]), 3, "The list view should display 3 applications")
|
|
|
|
def test_applicant_modify_email_number(self):
|
|
applicant = self.env['hr.applicant'].create({
|
|
'partner_name': 'Mary Applicant',
|
|
'email_from': 'applicant@example.com',
|
|
'partner_phone': '123456789',
|
|
})
|
|
self.assertEqual(applicant.partner_id.email, 'applicant@example.com', "Email should have been set on the partner.")
|
|
self.assertEqual(applicant.partner_id.phone, '123456789', "Phone should have been set on the partner.")
|
|
|
|
applicant.email_from = 'applicant_diff@example.com'
|
|
self.assertEqual(applicant.partner_id.email, 'applicant_diff@example.com', "Email should have been updated on the partner.")
|
|
applicant.partner_phone = '987654321'
|
|
self.assertEqual(applicant.partner_id.phone, '987654321', "Phone should have been updated on the partner.")
|
|
|
|
def test_send_mail_when_refuse_applicant(self):
|
|
mail_template = self.env['mail.template'].create({
|
|
'name': 'Test template',
|
|
'model_id': self.env['ir.model']._get('hr.applicant').id,
|
|
'subject': 'Application refused: {{ object.partner_name }}',
|
|
})
|
|
|
|
refuse_reason = self.env['hr.applicant.refuse.reason'].create([{
|
|
'name': 'Not good',
|
|
'template_id': mail_template.id,
|
|
}])
|
|
|
|
app_1 = self.env['hr.applicant'].create({
|
|
'partner_name': 'Mario',
|
|
'email_from': 'super@mario.bros',
|
|
})
|
|
|
|
applicant_get_refuse_reason = self.env['applicant.get.refuse.reason'].create({
|
|
'refuse_reason_id': refuse_reason.id,
|
|
'send_mail': True,
|
|
'applicant_ids': [(6, 0, [app_1.id])],
|
|
})
|
|
applicant_get_refuse_reason._prepare_send_refusal_mails()
|
|
mail = self.env['mail.mail'].search([('subject', '=', 'Application refused: Mario')], limit=1)
|
|
self.assertEqual(mail.partner_ids, app_1.partner_id)
|