457 lines
22 KiB
Python
457 lines
22 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from contextlib import contextmanager
|
|
from datetime import timedelta
|
|
from freezegun import freeze_time
|
|
from markupsafe import Markup
|
|
from unittest.mock import patch
|
|
|
|
from odoo.exceptions import UserError
|
|
from odoo.fields import Date
|
|
from odoo.tests.common import TransactionCase, tagged
|
|
from odoo.tools.zeep.exceptions import Fault
|
|
|
|
@tagged('-standard', 'external')
|
|
class TestMonsterIntegration(TransactionCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
|
|
cls.main_company = cls.env['res.company'].create({
|
|
'name': 'My company',
|
|
'hr_recruitment_monster_username': 'xrtpjobsx01',
|
|
'hr_recruitment_monster_password': 'rtp987654'
|
|
})
|
|
|
|
cls.env = cls.env(context=dict(cls.env.context, allowed_company_ids=cls.main_company.ids))
|
|
|
|
cls.partner = cls.env['res.partner'].create({
|
|
'name': 'Odoo',
|
|
'phone': '(603)-996-3829',
|
|
'street': "rue des Bourlottes, 9",
|
|
'street2': "",
|
|
'city': "Ramillies",
|
|
'zip': 1367,
|
|
'state_id': False,
|
|
'country_id': cls.env.ref('base.be').id,
|
|
})
|
|
|
|
cls.job1 = cls.env['hr.job'].create({
|
|
'name': 'Test job 1',
|
|
'address_id': cls.partner.id
|
|
})
|
|
|
|
cls.job2 = cls.env['hr.job'].create({
|
|
'name': 'Test job 2',
|
|
'address_id': cls.partner.id
|
|
})
|
|
|
|
cls.monster_platform = cls.env['hr.recruitment.platform'].search([
|
|
('name', '=', 'Monster.com')
|
|
])
|
|
|
|
cls.post_content = "As an employee of our company, you will collaborate with each department to create and deploy disruptive products. Come work at a growing company that offers great benefits with opportunities to moving forward and learn alongside accomplished leaders. We are seeking an experienced and outstanding member of staff. This position is both creative and rigorous by nature you need to think outside the box. We expect the candidate to be proactive and have a get it done spirit."
|
|
|
|
cls.today = Date().today()
|
|
|
|
def create_publish_job_post(self, job_id, campaign_start_date, campaign_end_date=None):
|
|
wiz_job_post = self.env['hr.recruitment.post.job.wizard'].create({
|
|
'job_id': job_id,
|
|
'job_apply_mail': '[email protected]',
|
|
'platform_ids': self.monster_platform.ids,
|
|
'post_html': self.post_content,
|
|
'campaign_start_date': campaign_start_date,
|
|
'campaign_end_date': campaign_end_date,
|
|
})
|
|
wiz_job_post.action_post_job()
|
|
return self.env['hr.job.post'].search(
|
|
[],
|
|
order='create_date desc',
|
|
limit=1
|
|
)
|
|
|
|
def test_wrong_campaign_dates(self):
|
|
yesterday = self.today - timedelta(days=1)
|
|
with self.assertRaises(UserError):
|
|
self.create_publish_job_post(self.job1.id, self.today, yesterday)
|
|
|
|
def test_no_monster_credentials(self):
|
|
self.main_company.hr_recruitment_monster_username = ''
|
|
self.main_company.hr_recruitment_monster_password = ''
|
|
|
|
job_post = self.create_publish_job_post(self.job1.id, self.today)
|
|
|
|
if not job_post:
|
|
self.fail("Should have created a job post.")
|
|
self.assertEqual(job_post.status, 'failure')
|
|
self.assertEqual(job_post.status_message, 'Monster.com credentials are not set. Please set them in the company settings or ask your administrator.')
|
|
|
|
self.main_company.hr_recruitment_monster_username = 'xrtpjobsx01'
|
|
self.main_company.hr_recruitment_monster_password = 'rtp987654'
|
|
|
|
def test_wrong_credentials(self):
|
|
self.main_company.hr_recruitment_monster_username = 'aaaaaaa'
|
|
self.main_company.hr_recruitment_monster_password = 'aaaaaaa'
|
|
|
|
job_post = self.create_publish_job_post(self.job1.id, self.today)
|
|
|
|
if not job_post:
|
|
self.fail("Should have created a job post.")
|
|
self.assertEqual(job_post.status, 'failure')
|
|
self.assertEqual(job_post.status_message, 'Authentication error: Monster.com credentials are invalid.')
|
|
|
|
self.main_company.hr_recruitment_monster_username = 'xrtpjobsx01'
|
|
self.main_company.hr_recruitment_monster_password = 'rtp987654'
|
|
|
|
def test_create_post(self):
|
|
job_post = self.create_publish_job_post(self.job1.id, self.today)
|
|
if not job_post:
|
|
self.fail("Should have created a job post.")
|
|
self.assertEqual(job_post.job_id.id, self.job1.id)
|
|
self.assertEqual(job_post.platform_id.id, self.monster_platform.id)
|
|
self.assertEqual(job_post.campaign_start_date, self.today)
|
|
self.assertEqual(job_post.post_html, Markup("<p>{content}</p>").format(content=self.post_content))
|
|
self.assertEqual(job_post.apply_vector, '[email protected]')
|
|
self.assertEqual(job_post.status, 'success')
|
|
|
|
def test_delete_post(self):
|
|
job_post = self.create_publish_job_post(self.job1.id, self.today)
|
|
self.assertEqual(job_post.status, 'success')
|
|
job_post._delete_post()
|
|
self.assertEqual(job_post.status, 'deleted')
|
|
|
|
@contextmanager
|
|
def patch_post_api_call(self):
|
|
def _post_api_call(data):
|
|
if data['jobAction'] == 'delete':
|
|
status = 'deleted'
|
|
else:
|
|
status = 'success'
|
|
return {
|
|
'status': status,
|
|
'status_message': '',
|
|
}
|
|
|
|
with patch('odoo.addons.hr_recruitment_integration_monster.models.hr_recruitment_platform.HrRecruitmentPlatform._post_api_call') as patched_function:
|
|
patched_function.side_effect = _post_api_call
|
|
yield patched_function
|
|
|
|
def test_postpone_create_post(self):
|
|
tomorrow = self.today + timedelta(days=1)
|
|
job_post = self.create_publish_job_post(self.job2.id, tomorrow)
|
|
if not job_post:
|
|
self.fail("Should have created a job post.")
|
|
self.assertEqual(job_post.job_id.id, self.job2.id)
|
|
self.assertEqual(job_post.platform_id.id, self.monster_platform.id)
|
|
self.assertEqual(job_post.campaign_start_date, tomorrow)
|
|
self.assertEqual(job_post.post_html, Markup("<p>{content}</p>").format(content=self.post_content))
|
|
self.assertEqual(job_post.apply_vector, '[email protected]')
|
|
self.assertEqual(job_post.status, 'pending')
|
|
|
|
with (
|
|
freeze_time(self.today + timedelta(days=2)),
|
|
# Patch API call as it complains with the freeze_time
|
|
self.patch_post_api_call(),
|
|
self.enter_registry_test_mode(),
|
|
):
|
|
self.env.ref('hr_recruitment_integration_base.job_board_campaign_manager_start').method_direct_trigger()
|
|
self.assertEqual(job_post.status, 'success')
|
|
|
|
def test_postpone_already_posted(self):
|
|
job_post = self.create_publish_job_post(self.job1.id, self.today)
|
|
with self.assertRaises(UserError):
|
|
job_post.campaign_start_date = self.today + timedelta(days=1)
|
|
job_post.action_update_job_post()
|
|
|
|
def test_stop_finished_campaign(self):
|
|
tomorrow = self.today + timedelta(days=1)
|
|
job_post = self.create_publish_job_post(self.job1.id, self.today, tomorrow)
|
|
self.assertEqual(job_post.status, 'success')
|
|
with (
|
|
freeze_time(self.today + timedelta(days=2)),
|
|
# Patch API call as it complains with the freeze_time
|
|
self.patch_post_api_call(),
|
|
self.enter_registry_test_mode(),
|
|
):
|
|
self.env.ref('hr_recruitment_integration_base.job_board_campaign_manager_stop').method_direct_trigger()
|
|
self.assertEqual(job_post.status, 'deleted')
|
|
|
|
|
|
@tagged('standard', '-external')
|
|
class TestMockupMonsterIntegration(TestMonsterIntegration):
|
|
|
|
@contextmanager
|
|
def patch_monster_requests(self):
|
|
""" Mock context for requests to the Monster.com API """
|
|
|
|
class MockedClient:
|
|
|
|
class Service:
|
|
def __init__(self, username, password):
|
|
self.username = username
|
|
self.password = password
|
|
|
|
def UpdateJobs(self, Job):
|
|
if self.username != "xrtpjobsx01" or self.password != "rtp987654":
|
|
raise Fault("Wrong credentials.")
|
|
if Job["jobAction"] == "addOrUpdate":
|
|
return {
|
|
"header":{
|
|
"header":"None"
|
|
},
|
|
"body":{
|
|
"ProcessingReceipt":{
|
|
"RequestDocElement":"{http://schemas.monster.com/Monster}Jobs",
|
|
"Status":{
|
|
"ReturnCode":{
|
|
"_value_1":"0",
|
|
"returnCodeType":"success"
|
|
},
|
|
"Descriptions":"None"
|
|
},
|
|
"Response":"None"
|
|
},
|
|
"JobsPreProcessResponse":"None",
|
|
"JobResponse":[
|
|
{
|
|
"JobReference":{
|
|
"JobTitle":"Test job 1",
|
|
"JobRankingScore":"None",
|
|
"jobRefCode":"110_20250114_1"
|
|
},
|
|
"RecruiterReference":{
|
|
"UserName":"None",
|
|
"PersonName":"None",
|
|
"EmailAddress":"None",
|
|
"userId":"204841377"
|
|
},
|
|
"FolderReference":{
|
|
"FolderName":"Test job 1",
|
|
"folderId":"338392218",
|
|
"folderRefCode":"None"
|
|
},
|
|
"SubmissionReference":"None",
|
|
"CompanyReference":{
|
|
"CompanyXCode":"xrtpjobsx",
|
|
"CompanyName":"None",
|
|
"companyId":"34889333"
|
|
},
|
|
"JobPostingResponse":[
|
|
{
|
|
"InventoryPreference":"None",
|
|
"RecruiterReference":"None",
|
|
"Location":{
|
|
"City":"None",
|
|
"State":"Walloon-Brabant",
|
|
"CountryCode":"BE",
|
|
"PostalCode":"None",
|
|
"Continent":"None",
|
|
"locationId":795,
|
|
"parentLocationId":"None"
|
|
},
|
|
"Locations":{
|
|
"Location":[
|
|
{
|
|
"City":"None",
|
|
"State":"Walloon-Brabant",
|
|
"CountryCode":"BE",
|
|
"PostalCode":"None",
|
|
"Continent":"None",
|
|
"locationId":795,
|
|
"parentLocationId":"None"
|
|
}
|
|
]
|
|
},
|
|
"TargetLocationGroups":"None",
|
|
"JobCategory":"None",
|
|
"JobCategories":"None",
|
|
"JobOccupations":"None",
|
|
"JobCity":"None",
|
|
"MoveJob":"None",
|
|
"BoardName":{
|
|
"_value_1":"None",
|
|
"monsterId":"178",
|
|
"boardGroupId":"None"
|
|
},
|
|
"JobPostingDates":{
|
|
"JobPostDate":"None",
|
|
"JobActiveDate":{
|
|
"_value_1":"Date().today()"
|
|
},
|
|
"JobExpireDate":{
|
|
"_value_1":"Date().today()"
|
|
},
|
|
"JobDeleteDate":"None",
|
|
"JobModifiedDate":"None"
|
|
},
|
|
"CareerAdNetworkDates":"None",
|
|
"PostingStats":"None",
|
|
"ApplyOnlineURL":"None",
|
|
"JobPostingSubBoards":"None",
|
|
"PhysicalAddress":[
|
|
|
|
],
|
|
"FilterParameters":"None",
|
|
"DisplayTemplate":"None",
|
|
"PositionOpenings":"None",
|
|
"PostingOccupationalClassification":"None",
|
|
"Industries":"None",
|
|
"Video":"None",
|
|
"JobTags":"None",
|
|
"JobPostingProperties":"None",
|
|
"JobViewURL":"None",
|
|
"jobPostingAction":"None",
|
|
"postingId":"284056346",
|
|
"jobPostingRefCode":"None",
|
|
"jobPostingState":"None",
|
|
"bold":"None",
|
|
"desiredDuration":"None"
|
|
}
|
|
],
|
|
"Status":{
|
|
"ReturnCode":{
|
|
"_value_1":"0",
|
|
"returnCodeType":"success"
|
|
},
|
|
"Descriptions":{
|
|
"Description":[
|
|
{
|
|
"_value_1":"[PhysicalAddress/City] [Ramillies] is not valid City.Job will be posted with invalid city value for Physical Address. \r\n[PhysicalAddress/State] [False] is not valid state for Country [BE]. \r\nIndustry was not provided. \r\n",
|
|
"descriptionType":"warning"
|
|
},
|
|
{
|
|
"_value_1":"Job added. \r\n Charges: Job-Board(178) PLGId(0): 1; \r\n",
|
|
"descriptionType":"info"
|
|
}
|
|
],
|
|
"Errors":"None",
|
|
"Warnings":"None",
|
|
"Infos":"None"
|
|
}
|
|
},
|
|
"JobCharges":{
|
|
"JobCharge":[
|
|
{
|
|
"ResourceLicenseId":"349964004",
|
|
"ChargeQuantity":"1",
|
|
"postingId":"284056346"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
],
|
|
"ProcessingSummary":"None",
|
|
"JobsPostProcessResponse":"None"
|
|
}}
|
|
elif Job["jobAction"] == "delete":
|
|
return {
|
|
"header":{
|
|
"header":"None"
|
|
},
|
|
"body":{
|
|
"ProcessingReceipt":{
|
|
"RequestDocElement":"{http://schemas.monster.com/Monster}Jobs",
|
|
"Status":{
|
|
"ReturnCode":{
|
|
"_value_1":"0",
|
|
"returnCodeType":"success"
|
|
},
|
|
"Descriptions":"None"
|
|
},
|
|
"Response":"None"
|
|
},
|
|
"JobsPreProcessResponse":"None",
|
|
"JobResponse":[
|
|
{
|
|
"JobReference":{
|
|
"JobTitle":"None",
|
|
"JobRankingScore":"None",
|
|
"jobRefCode":"110_20250114_1"
|
|
},
|
|
"RecruiterReference":{
|
|
"UserName":"None",
|
|
"PersonName":"None",
|
|
"EmailAddress":"None",
|
|
"userId":"204841377"
|
|
},
|
|
"FolderReference":{
|
|
"FolderName":"None",
|
|
"folderId":"0",
|
|
"folderRefCode":"None"
|
|
},
|
|
"SubmissionReference":"None",
|
|
"CompanyReference":{
|
|
"CompanyXCode":"xrtpjobsx",
|
|
"CompanyName":"None",
|
|
"companyId":"34889333"
|
|
},
|
|
"JobPostingResponse":[
|
|
|
|
],
|
|
"Status":{
|
|
"ReturnCode":{
|
|
"_value_1":"0",
|
|
"returnCodeType":"success"
|
|
},
|
|
"Descriptions":{
|
|
"Description":[
|
|
{
|
|
"_value_1":"JobPosting [|284056346|178|795||] expired. \r\nCharges: 0 \r\n",
|
|
"descriptionType":"info"
|
|
}
|
|
],
|
|
"Errors":"None",
|
|
"Warnings":"None",
|
|
"Infos":"None"
|
|
}
|
|
},
|
|
"JobCharges":"None"
|
|
}
|
|
],
|
|
"ProcessingSummary":"None",
|
|
"JobsPostProcessResponse":"None"
|
|
}}
|
|
return
|
|
|
|
def __init__(self, wsdl_uri, wsse):
|
|
self.service = self.Service(wsse.username, wsse.password)
|
|
self.wsdl_uri = wsdl_uri
|
|
self.wsse = wsse
|
|
|
|
with patch('odoo.addons.hr_recruitment_integration_monster.models.hr_recruitment_platform.Client') as mocked_client:
|
|
mocked_client.side_effect = MockedClient
|
|
yield mocked_client
|
|
|
|
def test_wrong_campaign_dates(self):
|
|
with self.patch_monster_requests():
|
|
super().test_wrong_campaign_dates()
|
|
|
|
def test_no_monster_credentials(self):
|
|
with self.patch_monster_requests():
|
|
super().test_no_monster_credentials()
|
|
|
|
def test_wrong_credentials(self):
|
|
with self.patch_monster_requests():
|
|
super().test_wrong_credentials()
|
|
|
|
def test_create_post(self):
|
|
with self.patch_monster_requests():
|
|
super().test_create_post()
|
|
|
|
def test_delete_post(self):
|
|
with self.patch_monster_requests():
|
|
super().test_delete_post()
|
|
|
|
def test_postpone_create_post(self):
|
|
with self.patch_monster_requests():
|
|
super().test_postpone_create_post()
|
|
|
|
def test_postpone_already_posted(self):
|
|
with self.patch_monster_requests():
|
|
super().test_postpone_already_posted()
|
|
|
|
def test_stop_finished_campaign(self):
|
|
with self.patch_monster_requests():
|
|
super().test_stop_finished_campaign()
|