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