# Part of Odoo. See LICENSE file for full copyright and licensing details. from markupsafe import Markup from odoo import fields, models, _ from odoo.exceptions import UserError class HrApplicant(models.Model): _inherit = 'hr.applicant' salary_offer_ids = fields.One2many('hr.contract.salary.offer', 'applicant_id') salary_offers_count = fields.Integer(compute='_compute_salary_offers_count', compute_sudo=True) proposed_contracts = fields.Many2many('hr.version', string="Proposed Contracts", domain="[('company_id', '=', company_id)]") proposed_contracts_count = fields.Integer(compute="_compute_proposed_contracts_count", string="Proposed Contracts Count", compute_sudo=True) def _compute_proposed_contracts_count(self): versions_data = self.env['hr.version']._read_group( domain=[ ('applicant_id', 'in', self.ids), ('active', '=', True), ], groupby=['applicant_id'], aggregates=['__count']) mapped_data = {applicant.id: count for applicant, count in versions_data} for applicant in self: applicant.proposed_contracts_count = mapped_data.get(applicant.id, 0) def _compute_salary_offers_count(self): offers_data = self.env['hr.contract.salary.offer']._read_group( domain=[('applicant_id', 'in', self.ids)], groupby=['applicant_id'], aggregates=['__count']) mapped_data = {applicant.id: count for applicant, count in offers_data} for applicant in self: applicant.salary_offers_count = mapped_data.get(applicant.id, 0) def _move_to_hired_stage(self): self.ensure_one() first_hired_stage = self.env['hr.recruitment.stage'].search([ '|', ('job_ids', '=', False), ('job_ids', '=', self.job_id.id), ('hired_stage', '=', True)]) if first_hired_stage: self.stage_id = first_hired_stage[0].id def action_show_proposed_contracts(self): self._check_interviewer_access() action_vals = { "type": "ir.actions.act_window", "res_model": "hr.version", "domain": [["applicant_id", "=", self.id], '|', ["active", "=", False], ["active", "=", True]], "name": _("Proposed Contracts"), "context": {'default_employee_id': self.employee_id.id, 'default_applicant_id': self.id}, } if self.proposed_contracts_count == 1: action_vals.update({ "views": [[False, "form"]], "res_id": self.env['hr.version'].search([("applicant_id", "=", self.id)]).id, }) else: action_vals.update({ "views": [[False, "list"], [False, "form"]], }) return action_vals def action_show_offers(self): self.ensure_one() action = self.env['ir.actions.act_window']._for_xml_id('hr_contract_salary.hr_contract_salary_offer_action') action['domain'] = [('applicant_id', '=', self.id)] action['context'] = {'default_applicant_id': self.id} if self.salary_offers_count == 1: action.update({ "views": [[False, "form"]], "res_id": self.salary_offer_ids.id, }) return action def archive_applicant(self): message = _("The offer has been marked as refused when the linked applicant was declined.") refuse_reason = self.env.ref("hr_contract_salary.refusal_reason_others", raise_if_not_found=False) self.salary_offer_ids.sudo().filtered(lambda o: o.state != "refused").action_refuse_offer(message=message, refusal_reason=refuse_reason) return super().archive_applicant() def action_generate_offer(self): if not self.partner_name: raise UserError(_('Offer link can not be sent without an applicant name.')) offer_validity_period = int(self.env['ir.config_parameter'].sudo().get_param( 'hr_contract_salary.access_token_validity', default=30)) offer_values = self._get_offer_values() offer_values['validity_days_count'] = offer_validity_period offer = self.env['hr.contract.salary.offer'].with_context( default_contract_template_id=self._get_contract_template().id).create(offer_values) self.message_post( body=_("An %(offer)s for the applicant %(applicant_name)s has been created by %(user)s.", offer=Markup("Offer") .format(offer_id=offer.id), applicant_name=self.partner_name, user=self.env.user.name ) ) return { 'type': 'ir.actions.act_window', 'view_mode': 'form', 'res_model': 'hr.contract.salary.offer', 'res_id': offer.id, 'views': [(False, 'form')], 'context': {'active_model': 'hr.applicant', 'default_applicant_id': self.id} } def _get_offer_values(self): self.ensure_one() contract_template = self._get_contract_template() return { 'company_id': contract_template.company_id.id or self.company_id.id or self.env.company.id, 'contract_template_id': contract_template.id, 'applicant_id': self.id, 'final_yearly_costs': contract_template.sudo().final_yearly_costs, 'job_title': self.job_id.name, 'employee_job_id': self.job_id.id, 'department_id': self.department_id.id, } def _get_contract_template(self): contract_template = self.job_id.contract_template_id if self.job_id else False if not contract_template: contract_template = self.env['hr.version'].search(domain=[ ('company_id', '=', self.company_id.id), ('employee_id', '=', False) ], limit=1) return contract_template def unlink_archived_versions(self): # TODO: depereceated method remove me in master archived_versions = self.env['hr.version'].search([ ('applicant_id', 'in', self.ids), ('active', '=', False) ]) if archived_versions: archived_versions.sign_request_ids.write({'state': 'canceled', 'active': False}) archived_versions.unlink()