mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-27 00:32:05 +02:00
19.0 vanilla
This commit is contained in:
parent
a1137a1456
commit
e1d89e11e3
2789 changed files with 1093187 additions and 605897 deletions
|
|
@ -1,71 +1,494 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import tagged, TransactionCase
|
||||
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 match ignores case
|
||||
# And that no match is found when there is none
|
||||
# Tests that duplicate email matching is case insesitive
|
||||
dup1, dup2, no_dup = self.env['hr.applicant'].create([
|
||||
{
|
||||
'name': 'Application 1',
|
||||
'partner_name': 'Application 1',
|
||||
'email_from': 'laurie.poiret@aol.ru',
|
||||
},
|
||||
{
|
||||
'name': 'Application 2',
|
||||
'partner_name': 'Application 2',
|
||||
'email_from': 'laurie.POIRET@aol.ru',
|
||||
},
|
||||
{
|
||||
'name': 'Application 3',
|
||||
'partner_name': 'Application 3',
|
||||
'email_from': 'laure.poiret@aol.ru',
|
||||
},
|
||||
])
|
||||
self.assertEqual(dup1.application_count, 1)
|
||||
self.assertEqual(dup2.application_count, 1)
|
||||
self.assertEqual(no_dup.application_count, 0)
|
||||
self.assertEqual(dup1.application_count, 2)
|
||||
self.assertEqual(dup2.application_count, 2)
|
||||
self.assertEqual(no_dup.application_count, 1)
|
||||
|
||||
def test_application_count(self):
|
||||
""" Test that we find same applicants based on simmilar mail,
|
||||
phone or mobile phone.
|
||||
"""
|
||||
A, B, C, D, E, F = self.env['hr.applicant'].create([
|
||||
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([
|
||||
{
|
||||
'name': 'Application A',
|
||||
'active': False, # Refused/archived application should still count
|
||||
'partner_name': 'Application A',
|
||||
'email_from': 'abc@odoo.com',
|
||||
'partner_phone': '123',
|
||||
'partner_mobile': '14-15-16',
|
||||
},
|
||||
{
|
||||
'name': 'Application B',
|
||||
'partner_name': 'Application B',
|
||||
'partner_phone': '456',
|
||||
'partner_mobile': '11-12-13',
|
||||
},
|
||||
{
|
||||
'name': 'Application C',
|
||||
'partner_name': 'Application C',
|
||||
'email_from': 'def@odoo.com',
|
||||
'partner_phone': '123',
|
||||
'partner_mobile': '14-15-16',
|
||||
},
|
||||
{
|
||||
'name': 'Application D',
|
||||
'email_from': 'def@odoo.com',
|
||||
'partner_name': 'Application D',
|
||||
'email_from': 'abc@odoo.com',
|
||||
'partner_phone': '456',
|
||||
'partner_mobile': '14-15-16',
|
||||
},
|
||||
{
|
||||
'name': 'Application E',
|
||||
'partner_name': 'Application E',
|
||||
'partner_phone': '',
|
||||
},
|
||||
{
|
||||
'name': 'Application F',
|
||||
'partner_phone': '11-12-13', # In case phone is configured in a wrong field
|
||||
}
|
||||
'partner_name': 'Application F',
|
||||
'email_from': 'ghi@odoo.com',
|
||||
'partner_phone': '789',
|
||||
},
|
||||
{
|
||||
'partner_name': 'Application G',
|
||||
},
|
||||
])
|
||||
self.assertEqual(A.application_count, 2) # C, D
|
||||
self.assertEqual(B.application_count, 2) # D, F
|
||||
self.assertEqual(C.application_count, 2) # A, D
|
||||
self.assertEqual(D.application_count, 3) # A, B, C
|
||||
self.assertEqual(E.application_count, 0)
|
||||
self.assertEqual(F.application_count, 1) # B
|
||||
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue