218 lines
9.3 KiB
Python
218 lines
9.3 KiB
Python
from odoo import api, fields, models,_
|
|
from odoo.exceptions import ValidationError
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
|
|
|
|
class AppraisalYear(models.Model):
|
|
_name = 'employee.appraisal.year'
|
|
_description = 'Employee Appraisal Year'
|
|
_order = "year_seq"
|
|
_rec_name = 'appraisal_name'
|
|
|
|
year = fields.Integer(string="Performance Period")
|
|
appraisal_name_id = fields.Char(string="Appraisal Type")
|
|
appraisal_name = fields.Char(string="Appraisal Name")
|
|
start_month = fields.Date('Starting Month')
|
|
end_month = fields.Date('End Month')
|
|
active = fields.Boolean(default=True)
|
|
year_seq = fields.Integer(string="Sequence")
|
|
appraisal_type_id = fields.Many2one(
|
|
'employee.appraisal.type',
|
|
string="Appraisal Type"
|
|
)
|
|
|
|
@api.constrains('appraisal_type_id', 'start_month', 'end_month')
|
|
def _check_appraisal_type(self):
|
|
for rec in self:
|
|
if not rec.start_month or not rec.end_month:
|
|
continue
|
|
|
|
if rec.start_month > rec.end_month:
|
|
raise ValidationError(
|
|
_("Start Month cannot be greater than End Month.")
|
|
)
|
|
|
|
expected_end = False
|
|
|
|
if rec.appraisal_type_id.name == 'Monthly':
|
|
expected_end = rec.start_month + relativedelta(months=1, days=-1)
|
|
|
|
elif rec.appraisal_type_id.name == 'Quarterly':
|
|
expected_end = rec.start_month + relativedelta(months=3, days=-1)
|
|
|
|
elif rec.appraisal_type_id.name == 'Half-yearly':
|
|
expected_end = rec.start_month + relativedelta(months=6, days=-1)
|
|
|
|
elif rec.appraisal_type_id.name == 'Annual':
|
|
expected_end = rec.start_month + relativedelta(months=12, days=-1)
|
|
|
|
if expected_end and rec.end_month != expected_end:
|
|
raise ValidationError(_(
|
|
"Invalid period for %s.\nExpected End Date: %s"
|
|
) % (
|
|
rec.appraisal_type_id.name,
|
|
expected_end.strftime('%d/%m/%Y')
|
|
))
|
|
|
|
duplicate = self.search([
|
|
('id', '!=', rec.id),
|
|
('appraisal_type_id', '=', rec.appraisal_type_id.id),
|
|
('start_month', '<=', rec.end_month),
|
|
('end_month', '>=', rec.start_month),
|
|
], limit=1)
|
|
|
|
if duplicate:
|
|
raise ValidationError(
|
|
_("This appraisal period overlaps with existing period: %s")
|
|
% duplicate.appraisal_name
|
|
)
|
|
|
|
|
|
|
|
|
|
class EmployeeAppraisalType(models.Model):
|
|
_name = 'employee.appraisal.type'
|
|
_description = 'Employee Appraisal Type'
|
|
|
|
name = fields.Char(required=True)
|
|
seq = fields.Integer(string="Sequence")
|
|
|
|
|
|
|
|
class AppraisalTemplate(models.Model):
|
|
_name = 'employee.appraisal.template'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
_description = 'Employee Appraisal Template'
|
|
_order = "seq desc"
|
|
_rec_name = 'seq'
|
|
|
|
name = fields.Char(string="Name")
|
|
employee_evaluator_name_id = fields.Many2one('employee.appraisal.evaluator', string="Employee Appraisal Evaluator")
|
|
employee_eva_id = fields.Many2one('hr.employee',string="Manager")
|
|
image_template = fields.Image(related='employee_eva_id.image_1920', string="Image")
|
|
hr_employee_id = fields.Many2one('hr.employee',string="Employee HR Employee")
|
|
employee_department_id = fields.Many2one('hr.department',string="Department")
|
|
company_id = fields.Many2one('res.company', string="Company",default=lambda self: self.env.company)
|
|
email_notify_user_ids = fields.Many2many("res.users", string='Notify Users if New Evaluation Submited and Confirmed')
|
|
hr_email_notify = fields.Boolean("Send Email if HR APPROVE or REJECT Evaluation")
|
|
template_rating_bool = fields.Boolean()
|
|
template_point_bool = fields.Boolean()
|
|
stage_config_ids = fields.Many2many('employee.stage.config',string='Stages')
|
|
employee_state = fields.Selection([
|
|
('new', 'New'),
|
|
('sent', 'sent'),
|
|
], string='Status', copy=False, tracking=1, default='new')
|
|
kra_ids = fields.One2many('employee.appraisal.kra','template_appraisal_id',string="Key Result Areas",copy=True,tracking=True)
|
|
kra_weightage = fields.Integer(compute="_compute_total_kra_weightage",string="Total KRA Weightage")
|
|
notice_id = fields.Many2one('hr.notice.appraisal',string="Notice")
|
|
start_date = fields.Date(string="Start Date")
|
|
end_date = fields.Date(string="End Date")
|
|
is_readonly = fields.Boolean(compute="_compute_is_readonly")
|
|
mail_sent_employee_ids = fields.Many2many('hr.employee',string="Mail Sent Employees")
|
|
seq = fields.Char(string="Sequence",readonly=True,copy=False)
|
|
employee_ids = fields.Many2many('hr.employee','appraisal_employee_rel','appraisal_id','employee_id',string="Employees")
|
|
manager_ids = fields.Many2many('hr.employee','appraisal_manager_rel','appraisal_id','manager_id',string="Managers")
|
|
appraisal_period_id = fields.Many2one('employee.appraisal.year')
|
|
appraisal_period_type_id = fields.Many2one('employee.appraisal.type')
|
|
|
|
@api.depends('kra_ids.kra_weightage')
|
|
def _compute_total_kra_weightage(self):
|
|
for rec in self:
|
|
rec.kra_weightage = sum(
|
|
rec.kra_ids.mapped('kra_weightage'))
|
|
|
|
def action_sent_employee(self):
|
|
for rec in self:
|
|
# appraisal_config_obj = self.env['employee.appraisal.template.config']
|
|
# for rec in self:
|
|
# first_stage = rec.stage_config_ids.sorted(
|
|
# key=lambda s: s.seq
|
|
# )[:1]
|
|
# for employee in rec.employee_ids:
|
|
# already_exists = appraisal_config_obj.search([
|
|
# ('template_id', '=', rec.id),
|
|
# ('employee_appraisal_id', '=', employee.id)
|
|
# ], limit=1)
|
|
# if already_exists:
|
|
# continue
|
|
# appraisal = appraisal_config_obj.create({
|
|
# 'template_id': rec.id,
|
|
# 'seq': rec.seq,
|
|
# 'employee_appraisal_id': employee.id,
|
|
# 'employee_ids': [(6, 0, rec.employee_ids.ids)],
|
|
# 'manager_ids': [(6, 0, rec.manager_ids.ids)],
|
|
# 'notice_id': rec.notice_id.id,
|
|
# 'start_date': rec.start_date,
|
|
# 'end_date': rec.end_date,
|
|
# 'appraisal_period_id': rec.appraisal_period_id.id,
|
|
# 'hr_apprai_id': rec.hr_employee_id.id,
|
|
# 'managerapp_id': rec.employee_eva_id.id,
|
|
# 'template_empl_rating_bool': rec.template_rating_bool,
|
|
# 'template_empl_point_bool': rec.template_point_bool,
|
|
# 'available_stage_ids': [
|
|
# (6, 0, rec.stage_config_ids.ids)
|
|
# ],
|
|
# 'stage_id': first_stage.id if first_stage else False,
|
|
# # 'state': 'self_evaluation',
|
|
# })
|
|
# appraisal._onchange_template_id()
|
|
employee_emails = rec.employee_ids.mapped('work_email')
|
|
manager_emails = rec.manager_ids.mapped('work_email')
|
|
all_emails = employee_emails + manager_emails
|
|
email_to = ",".join(filter(None, all_emails))
|
|
body_html = f"""
|
|
<div>
|
|
<p>Hello Team,</p>
|
|
<p>
|
|
Employee appraisal process has been initiated.
|
|
</p>
|
|
<br/>
|
|
<table border="1" cellpadding="5" cellspacing="0">
|
|
<tr>
|
|
<td><b>Reference</b></td>
|
|
<td>{rec.seq or ''}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>Appraisal Template</b></td>
|
|
<td>{rec.name or ''}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>Start Date</b></td>
|
|
<td>{rec.start_date or ''}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>End Date</b></td>
|
|
<td>{rec.end_date or ''}</td>
|
|
</tr>
|
|
</table>
|
|
<br/>
|
|
<p>
|
|
Please complete the appraisal within timeline.
|
|
</p>
|
|
<br/>
|
|
<p>
|
|
Regards,
|
|
</p>
|
|
<p>
|
|
Team Manager
|
|
</p>
|
|
</div>
|
|
"""
|
|
ctx = {
|
|
'default_model': 'employee.appraisal.template',
|
|
'default_res_ids': [rec.id],
|
|
'default_composition_mode': 'comment',
|
|
'default_email_to': email_to,
|
|
'default_subject': f'Employee Appraisal - {rec.seq}',
|
|
'default_body': body_html,
|
|
'mark_appraisal_sent_appraisal': True,
|
|
}
|
|
return {
|
|
'type': 'ir.actions.act_window',
|
|
'res_model': 'mail.compose.message',
|
|
'view_mode': 'form',
|
|
'target': 'new',
|
|
'context': ctx,
|
|
}
|