197 lines
9.7 KiB
Python
197 lines
9.7 KiB
Python
from odoo import models, fields, api, _
|
||
from odoo.exceptions import ValidationError
|
||
from datetime import date
|
||
from datetime import timedelta
|
||
import datetime
|
||
|
||
|
||
class Job(models.Model):
|
||
_inherit = 'hr.job'
|
||
|
||
secondary_skill_ids = fields.Many2many('hr.skill', "hr_job_secondary_hr_skill_rel",
|
||
'hr_job_id', 'hr_skill_id', "Secondary Skills")
|
||
locations = fields.Many2many('hr.location')
|
||
target_from = fields.Date(string="This is the date in which we starting the recruitment process", default=fields.Date.today)
|
||
target_to = fields.Date(string='This is the target end date')
|
||
hiring_history = fields.One2many('recruitment.status.history', 'job_id', string='History')
|
||
|
||
def buttion_view_applicants(self):
|
||
if self.skill_ids:
|
||
a = self.env['hr.candidate'].search([])
|
||
applicants = self.env['hr.candidate']
|
||
for i in a:
|
||
if all(skill in i.skill_ids for skill in self.skill_ids):
|
||
applicants += i
|
||
|
||
else:
|
||
applicants = self.env['hr.candidate'].search([])
|
||
action = self.env['ir.actions.act_window']._for_xml_id('hr_recruitment.action_hr_candidate')
|
||
action['domain'] = [('id', 'in', applicants.ids)]
|
||
action['context'] = dict(self._context)
|
||
return action
|
||
|
||
def hr_job_end_date_update(self):
|
||
# Find all jobs where the target_to is today's date
|
||
hr_jobs = self.sudo().search([('target_to', '=', fields.Date.today() - timedelta(days=1))])
|
||
# stage_ids = self.env['hr.recruitment.stage'].sudo().search([('hired_stage','=',True)])
|
||
for job in hr_jobs:
|
||
# Determine the hiring period
|
||
date_from = job.target_from
|
||
date_end = job.target_to
|
||
# Fetch hired applicants related to this job
|
||
hired_applicants = self.env['hr.applicant'].search([
|
||
('job_id', '=', job.id),
|
||
('stage_id.hired_stage', '=', True)
|
||
])
|
||
# Get today's date in the datetime format (with time set to midnight)
|
||
today_start = fields.Datetime.today()
|
||
|
||
# Get today's date at the end of the day (23:59:59) to include all records created today
|
||
today_end = fields.Datetime.today().now()
|
||
|
||
# Search for records where create_date is today
|
||
hiring_history_today = self.env['recruitment.status.history'].sudo().search([
|
||
('create_date', '>=', today_start),
|
||
('create_date', '<=', today_end),
|
||
('job_id','=',job.id)
|
||
])
|
||
# Create a hiring history record
|
||
if not hiring_history_today:
|
||
self.env['recruitment.status.history'].create({
|
||
'date_from': date_from,
|
||
'date_end': date_end,
|
||
'target': len(hired_applicants), # Number of hired applicants
|
||
'job_id': job.id,
|
||
'hired': [(6, 0, hired_applicants.ids)] # Many2many write operation
|
||
})
|
||
|
||
tomorrow_date = fields.Date.today() + timedelta(days=1)
|
||
jobs_ending_tomorrow = self.sudo().search([('target_to', '=', tomorrow_date)])
|
||
|
||
for job in jobs_ending_tomorrow:
|
||
# Fetch recruiters (assuming job has a field recruiter_id or similar)
|
||
recruiter = job.sudo().user_id # Replacne with the appropriate field name
|
||
if recruiter:
|
||
# Send mail
|
||
template = self.env.ref(
|
||
'hr_recruitment_extended.template_recruitment_deadline_alert') # Replace with your email template XML ID
|
||
if template:
|
||
template.sudo().send_mail(recruiter.id, force_send=True)
|
||
recruitment_history = self.env['recruitment.status.history'].sudo().search([('job_id','!=',False)])
|
||
|
||
for recruitment in recruitment_history:
|
||
# Determine the hiring period
|
||
if recruitment.date_from and recruitment.job_id:
|
||
# Use `date_end` or today's date if `date_end` is not provided
|
||
date_end = fields.Datetime.to_datetime(fields.Date.to_string(recruitment.date_end)) + datetime.timedelta(days=1,seconds=-1) or fields.Datetime.today().now()
|
||
current_hired_applicants = recruitment.hired
|
||
# Search for applicants matching the conditions
|
||
hired_applicants = self.env['hr.applicant'].search([
|
||
('date_closed', '>=', fields.Datetime.to_datetime(fields.Date.to_string(recruitment.date_from))),
|
||
('date_closed', '<=', date_end),
|
||
('job_id', '=', recruitment.job_id.id)
|
||
])
|
||
# Filter out the applicants that are already in the 'hired' field
|
||
new_hired_applicants = hired_applicants - current_hired_applicants
|
||
|
||
# Add the missing applicants to the 'hired' field
|
||
recruitment.hired = current_hired_applicants | new_hired_applicants
|
||
return True
|
||
|
||
class HrCandidate(models.Model):
|
||
_inherit = "hr.candidate"
|
||
|
||
first_name = fields.Char(string='First Name',required=True, help="This is the person's first name, given at birth or during a naming ceremony. It’s the name people use to address you.")
|
||
middle_name = fields.Char(string='Middle Name', help="This is an extra name that comes between the first name and last name. Not everyone has a middle name")
|
||
last_name = fields.Char(string='Last Name',required=True, help="This is the family name, shared with other family members. It’s usually the last name.")
|
||
alternate_phone = fields.Char(string='Alternate Phone')
|
||
|
||
@api.constrains('partner_name')
|
||
def partner_name_constrain(self):
|
||
for rec in self:
|
||
if any(char.isdigit() for char in rec.partner_name):
|
||
raise ValidationError(_("Enter Valid Name"))
|
||
|
||
|
||
class HRApplicant(models.Model):
|
||
_inherit = 'hr.applicant'
|
||
|
||
current_location = fields.Char('Current Location')
|
||
preferred_location = fields.Many2many('hr.location',string="Preferred Location's")
|
||
current_organization = fields.Char('Current Organization')
|
||
alternate_phone = fields.Char(related="candidate_id.alternate_phone", readonly=False)
|
||
|
||
|
||
exp_type = fields.Selection([('fresher','Fresher'),('experienced','Experienced')], default='fresher', required=True)
|
||
|
||
total_exp = fields.Integer(string="Total Experience")
|
||
relevant_exp = fields.Integer(string="Relevant Experience")
|
||
total_exp_type = fields.Selection([('month',"Month's"),('year',"Year's")])
|
||
relevant_exp_type = fields.Selection([('month',"Month's"),('year',"Year's")])
|
||
notice_period = fields.Integer(string="Notice Period")
|
||
notice_period_type = fields.Selection([('day',"Day's"),('month',"Month's"),('year',"Year's")], string='Type')
|
||
|
||
current_ctc = fields.Float(string="Current CTC", aggregator="avg", help="Applicant Current Salary", tracking=True, groups="hr_recruitment.group_hr_recruitment_user")
|
||
salary_expected = fields.Float("Expected CTC", aggregator="avg", help="Salary Expected by Applicant", tracking=True, groups="hr_recruitment.group_hr_recruitment_user")
|
||
salary_negotiable = fields.Boolean(string="Salary Negotiable")
|
||
np_negotiable = fields.Boolean(string="NP Negotiable")
|
||
holding_offer = fields.Char(string="Holding Offer")
|
||
applicant_comments = fields.Text(string='Applicant Comments')
|
||
recruiter_comments = fields.Text(string='Recruiter Comments')
|
||
|
||
class Location(models.Model):
|
||
_name = 'hr.location'
|
||
_rec_name = 'location_name'
|
||
# SQL Constraint to ensure the combination of location_name, zip_code, country_id, and state is unique
|
||
_sql_constraints = [
|
||
('unique_location_zip_state_country',
|
||
'UNIQUE(location_name, zip_code, country_id, state)',
|
||
'The selected Location, Zip Code, Country, and State combination already exists.')
|
||
]
|
||
|
||
|
||
location_name = fields.Char(string='Location', required=True)
|
||
zip_code = fields.Char(string = 'Zip Code')
|
||
country_id = fields.Many2one('res.country','Country',groups="hr.group_hr_user")
|
||
state = fields.Many2one("res.country.state", string="State",
|
||
domain="[('country_id', '=?', country_id)]",
|
||
groups="hr.group_hr_user")
|
||
|
||
@api.constrains('location_name')
|
||
def _check_location_name(self):
|
||
for record in self:
|
||
if record.location_name.isdigit():
|
||
raise ValidationError("Location name should not be a number. Please enter a valid location name.")
|
||
|
||
@api.constrains('zip_code')
|
||
def _check_zip_code(self):
|
||
for record in self:
|
||
if record.zip_code and not record.zip_code.isdigit(): # Check if zip_code exists and is not digit
|
||
raise ValidationError("Zip Code should contain only numeric characters. Please enter a valid zip code.")
|
||
|
||
|
||
class RecruitmentHistory(models.Model):
|
||
_name='recruitment.status.history'
|
||
|
||
date_from = fields.Date(string='Date From')
|
||
date_end = fields.Date(string='Date End')
|
||
target = fields.Integer(string='Target')
|
||
job_id = fields.Many2one('hr.job', string='Job Position') # Ensure this field exists
|
||
hired = fields.Many2many('hr.applicant')
|
||
|
||
@api.depends('date_from', 'date_end', 'job_id')
|
||
def _total_hired_users(self):
|
||
for rec in self:
|
||
if rec.date_from:
|
||
# Use `date_end` or today's date if `date_end` is not provided
|
||
date_end = rec.date_end or date.today()
|
||
|
||
# Search for applicants matching the conditions
|
||
hired_applicants = self.env['hr.applicant'].search([
|
||
('date_closed', '>=', rec.date_from),
|
||
('date_closed', '<=', date_end),
|
||
('job_id', '=', rec.job_id.id)
|
||
])
|
||
rec.hired = hired_applicants
|
||
else:
|
||
rec.hired = False |