645 lines
24 KiB
Python
645 lines
24 KiB
Python
from odoo import api, fields, models, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
RATING_VALUATION = {
|
|
'1': 'unsatisfactory',
|
|
'2': 'needs_improvements',
|
|
'3': 'meet_expectation',
|
|
'4': 'exceed_expectation',
|
|
'5': 'outstanding',
|
|
}
|
|
|
|
|
|
class EmployeeAppraisal(models.Model):
|
|
_name = 'employee.appraisal.template.config'
|
|
_description = 'Employee Appraisal'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
_order = "tracking_date desc"
|
|
_rec_name = 'template_id'
|
|
|
|
name = fields.Char(string="Reference", copy=False)
|
|
employee_evaluator_name_id = fields.Many2one('employee.appraisal.evaluator', string="Employee Appraisal Evaluator")
|
|
hr_apprai_id = fields.Many2one('hr.employee')
|
|
managerapp_id = fields.Many2one('hr.employee')
|
|
performance_evaluator = fields.Selection([('manager', 'Manager'), ('colleague', 'Colleague'), ('own', 'Own')])
|
|
template_id = fields.Many2one('employee.appraisal.template', string="Template")
|
|
stage_id = fields.Many2one('employee.stage.config',string='Stage')
|
|
available_stage_ids = fields.Many2many('employee.stage.config',compute='_compute_available_stages')
|
|
tracking_date = fields.Datetime(default=fields.Datetime.now, readonly=True, index=True)
|
|
company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.company)
|
|
state = fields.Selection([
|
|
('new', 'New'),
|
|
# ('draft', 'Draft'),
|
|
('self_evaluation', 'Self Evaluation'),
|
|
('colleague_manager', 'colleague Feedback & Manager Evaluation'),
|
|
# ('in_progress', 'Manager Evaluation'),
|
|
('hr_evaluation', 'HR Evaluation'),
|
|
('finance_team', 'Finance Evaluation'),
|
|
('management_team', 'Management Evaluation'),
|
|
('done', 'Completed'),
|
|
('reject', 'Rejected')
|
|
], string='Status', copy=False, tracking=1, default='new')
|
|
appraisal_period_id = fields.Many2one('employee.appraisal.year')
|
|
employee_appraisal_id = fields.Many2one('hr.employee')
|
|
image_1920 = fields.Image(related='employee_appraisal_id.image_1920')
|
|
employee_code = fields.Char(string='Employee Code', related='employee_appraisal_id.employee_id', store=True)
|
|
department_appraisal_id = fields.Many2one("hr.department", string="Department",related="employee_appraisal_id.department_id", store=True)
|
|
job_appraisal_id = fields.Many2one("hr.job", string="Job Position", related="employee_appraisal_id.job_id",store=True)
|
|
kra_line_ids = fields.One2many('employee.appraisal.kra.line', 'config_id', string='Kra')
|
|
manager_remarks = fields.Char(string="Manager Remarks")
|
|
hr_remarks = fields.Char(string="HR Remarks")
|
|
colleague_feed_ids = fields.One2many('colleague.feedback', 'employee_appraisal_feed_id', 'Colleague Feed Back')
|
|
created_by_id = fields.Many2one('hr.employee', string="Created By", default=lambda self: self.env.user.employee_id,readonly=True)
|
|
created_user_id = fields.Many2one('res.users', default=lambda self: self.env.user, readonly=True)
|
|
creator_email = fields.Char(related='created_by_id.work_email', string="Creator Email", readonly=True)
|
|
notice_id = fields.Many2one('hr.notice.appraisal', string="Notice")
|
|
start_date = fields.Date(string="Start Date")
|
|
end_date = fields.Date(string="End Date")
|
|
college_end_date = fields.Datetime(string="Colleges End Date")
|
|
college_end_date_time = fields.Datetime(string="Colleague 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_config_employee_rel', 'config_id', 'employee_id',string="Employees")
|
|
manager_ids = fields.Many2many('hr.employee', 'appraisal_config_manager_rel', 'config_id', 'manager_id',string="Managers")
|
|
total_employee_score = fields.Float(string="Employee Total Points", compute="_compute_total_scores", store=True)
|
|
total_manager_score = fields.Float(string="Manager Total Points", compute="_compute_total_scores", store=True)
|
|
total_hr_score = fields.Float(string="HR Total Points", compute="_compute_total_scores", store=True)
|
|
manager_email = fields.Char(compute="_compute_manager_email", string="Manager Email")
|
|
Note_appraisal = fields.Char(string="User Note", default="Please click KRA's Name, To open the KPI's",Readonly=True)
|
|
overall_score = fields.Float(compute="_compute_overall_scores", store=True)
|
|
overall_rating = fields.Selection([
|
|
('0', '0'),
|
|
('1', '1'),
|
|
('2', '2'),
|
|
('3', '3'),
|
|
('4', '4'),
|
|
('5', '5'),
|
|
], string="Overall Rating")
|
|
overall_rating_value = fields.Selection([
|
|
('unsatisfactory', 'Unsatisfactory'),
|
|
('needs_improvements', 'Needs Improvements'),
|
|
('meet_expectation', 'Meets Expectation'),
|
|
('exceed_expectation', 'Exceeds Expectation'),
|
|
('outstanding', 'Outstanding'),
|
|
], string="Overall Rating Value")
|
|
overall_rating_star = fields.Selection([
|
|
('0', '0'),
|
|
('1', '1'),
|
|
('2', '2'),
|
|
('3', '3'),
|
|
('4', '4'),
|
|
('5', '5'),
|
|
], string="Overall Stars")
|
|
employee_overall_score = fields.Float(compute='_compute_overall_scores',store=True)
|
|
manager_overall_score = fields.Float(compute='_compute_overall_scores',store=True)
|
|
hr_overall_score = fields.Float(compute='_compute_overall_scores',store=True)
|
|
employee_overall_star = fields.Selection([
|
|
('0', '0'),
|
|
('1', '1'),
|
|
('2', '2'),
|
|
('3', '3'),
|
|
('4', '4'),
|
|
('5', '5'),
|
|
], compute='_compute_overall_scores', store=True)
|
|
manager_overall_star = fields.Selection([
|
|
('0', '0'),
|
|
('1', '1'),
|
|
('2', '2'),
|
|
('3', '3'),
|
|
('4', '4'),
|
|
('5', '5'),
|
|
], compute='_compute_overall_scores', store=True)
|
|
hr_overall_star = fields.Selection([
|
|
('0', '0'),
|
|
('1', '1'),
|
|
('2', '2'),
|
|
('3', '3'),
|
|
('4', '4'),
|
|
('5', '5'),
|
|
], compute='_compute_overall_scores', store=True)
|
|
finance_user_id = fields.Many2one('res.users', string="Finance Approved By", readonly=True)
|
|
current_salary = fields.Float(string="Current Salary")
|
|
appraisal_percentage = fields.Float(string="Appraisal %")
|
|
appraisal_amount = fields.Float(string="Appraisal Amount")
|
|
new_salary = fields.Float(string="Revised Salary", compute="_compute_new_salary", store=True)
|
|
finance_remarks = fields.Text(string="Finance Remarks")
|
|
finance_date = fields.Datetime(string="Finance Approval Date", readonly=True)
|
|
template_empl_rating_bool = fields.Boolean('Star Rating')
|
|
template_empl_point_bool = fields.Boolean('Point Rating')
|
|
|
|
@api.depends('template_id')
|
|
def _compute_available_stages(self):
|
|
for rec in self:
|
|
rec.available_stage_ids = rec.template_id.stage_config_ids
|
|
|
|
@api.depends(
|
|
'kra_line_ids.kpi_line_ids.rating_star',
|
|
'kra_line_ids.kpi_line_ids.manager_rating_star',
|
|
'kra_line_ids.kpi_line_ids.hr_rating_star',
|
|
'kra_line_ids.kpi_line_ids.employee_score',
|
|
'kra_line_ids.kpi_line_ids.manager_score',
|
|
'kra_line_ids.kpi_line_ids.hr_score',
|
|
)
|
|
def _compute_overall_scores(self):
|
|
for rec in self:
|
|
|
|
employee_score = 0.0
|
|
manager_score = 0.0
|
|
hr_score = 0.0
|
|
|
|
# ==================================
|
|
# STAR RATING MODE
|
|
# ==================================
|
|
if rec.template_empl_rating_bool:
|
|
|
|
employee_ratings = [
|
|
int(kpi.rating_star)
|
|
for kra in rec.kra_line_ids
|
|
for kpi in kra.kpi_line_ids
|
|
if kpi.rating_star
|
|
]
|
|
|
|
manager_ratings = [
|
|
int(kpi.manager_rating_star)
|
|
for kra in rec.kra_line_ids
|
|
for kpi in kra.kpi_line_ids
|
|
if kpi.manager_rating_star
|
|
]
|
|
|
|
hr_ratings = [
|
|
int(kpi.hr_rating_star)
|
|
for kra in rec.kra_line_ids
|
|
for kpi in kra.kpi_line_ids
|
|
if kpi.hr_rating_star
|
|
]
|
|
|
|
employee_score = (
|
|
sum(employee_ratings) / len(employee_ratings)
|
|
if employee_ratings else 0
|
|
)
|
|
|
|
manager_score = (
|
|
sum(manager_ratings) / len(manager_ratings)
|
|
if manager_ratings else 0
|
|
)
|
|
|
|
hr_score = (
|
|
sum(hr_ratings) / len(hr_ratings)
|
|
if hr_ratings else 0
|
|
)
|
|
|
|
rec.employee_overall_score = round(employee_score, 2)
|
|
rec.manager_overall_score = round(manager_score, 2)
|
|
rec.hr_overall_score = round(hr_score, 2)
|
|
|
|
rec.employee_overall_star = str(round(employee_score)) if employee_score else '0'
|
|
rec.manager_overall_star = str(round(manager_score)) if manager_score else '0'
|
|
rec.hr_overall_star = str(round(hr_score)) if hr_score else '0'
|
|
|
|
# Final Overall
|
|
overall_avg = (
|
|
employee_score +
|
|
manager_score +
|
|
hr_score
|
|
) / 3 if (employee_score or manager_score or hr_score) else 0
|
|
|
|
rec.overall_score = round(overall_avg, 2)
|
|
|
|
overall_star = str(round(overall_avg)) if overall_avg else '0'
|
|
|
|
rec.overall_rating = overall_star
|
|
rec.overall_rating_star = overall_star
|
|
rec.overall_rating_value = RATING_VALUATION.get(
|
|
overall_star,
|
|
False
|
|
)
|
|
|
|
# ==================================
|
|
# POINT RATING MODE
|
|
# ==================================
|
|
elif rec.template_empl_point_bool:
|
|
|
|
employee_scores = [
|
|
kpi.employee_score
|
|
for kra in rec.kra_line_ids
|
|
for kpi in kra.kpi_line_ids
|
|
if kpi.employee_score is not False
|
|
]
|
|
|
|
manager_scores = [
|
|
kpi.manager_score
|
|
for kra in rec.kra_line_ids
|
|
for kpi in kra.kpi_line_ids
|
|
if kpi.manager_score is not False
|
|
]
|
|
|
|
hr_scores = [
|
|
kpi.hr_score
|
|
for kra in rec.kra_line_ids
|
|
for kpi in kra.kpi_line_ids
|
|
if kpi.hr_score is not False
|
|
]
|
|
|
|
employee_score = (
|
|
sum(employee_scores) / len(employee_scores)
|
|
if employee_scores else 0
|
|
)
|
|
|
|
manager_score = (
|
|
sum(manager_scores) / len(manager_scores)
|
|
if manager_scores else 0
|
|
)
|
|
|
|
hr_score = (
|
|
sum(hr_scores) / len(hr_scores)
|
|
if hr_scores else 0
|
|
)
|
|
|
|
rec.employee_overall_score = round(employee_score, 2)
|
|
rec.manager_overall_score = round(manager_score, 2)
|
|
rec.hr_overall_score = round(hr_score, 2)
|
|
|
|
rec.employee_overall_star = '0'
|
|
rec.manager_overall_star = '0'
|
|
rec.hr_overall_star = '0'
|
|
|
|
# Final Overall
|
|
overall_avg = (
|
|
employee_score +
|
|
manager_score +
|
|
hr_score
|
|
) / 3 if (employee_score or manager_score or hr_score) else 0
|
|
|
|
rec.overall_score = round(overall_avg, 2)
|
|
|
|
if overall_avg <= 1:
|
|
rating = '1'
|
|
elif overall_avg <= 2:
|
|
rating = '2'
|
|
elif overall_avg <= 3:
|
|
rating = '3'
|
|
elif overall_avg <= 4:
|
|
rating = '4'
|
|
else:
|
|
rating = '5'
|
|
|
|
rec.overall_rating = rating
|
|
rec.overall_rating_star = rating
|
|
rec.overall_rating_value = RATING_VALUATION.get(
|
|
rating,
|
|
False
|
|
)
|
|
|
|
# ==================================
|
|
# NO CONFIGURATION
|
|
# ==================================
|
|
else:
|
|
rec.employee_overall_score = 0
|
|
rec.manager_overall_score = 0
|
|
rec.hr_overall_score = 0
|
|
|
|
rec.employee_overall_star = '0'
|
|
rec.manager_overall_star = '0'
|
|
rec.hr_overall_star = '0'
|
|
|
|
rec.overall_score = 0
|
|
rec.overall_rating = '0'
|
|
rec.overall_rating_star = '0'
|
|
rec.overall_rating_value = False
|
|
|
|
@api.onchange('overall_rating_value')
|
|
def _onchange_overall_rating_value(self):
|
|
for rec in self:
|
|
if rec.overall_rating_value == 'outstanding':
|
|
rec.appraisal_percentage = 20
|
|
elif rec.overall_rating_value == 'exceed_expectation':
|
|
rec.appraisal_percentage = 15
|
|
elif rec.overall_rating_value == 'meet_expectation':
|
|
rec.appraisal_percentage = 10
|
|
elif rec.overall_rating_value == 'needs_improvements':
|
|
rec.appraisal_percentage = 5
|
|
else:
|
|
rec.appraisal_percentage = 0
|
|
|
|
@api.depends('manager_ids')
|
|
def _compute_manager_email(self):
|
|
for rec in self:
|
|
emails = rec.manager_ids.mapped('work_email')
|
|
rec.manager_email = ",".join(filter(None, emails))
|
|
|
|
@api.depends('end_date')
|
|
def _compute_is_readonly(self):
|
|
today = fields.Date.today()
|
|
for rec in self:
|
|
if rec.end_date and today > rec.end_date:
|
|
rec.is_readonly = True
|
|
else:
|
|
rec.is_readonly = False
|
|
|
|
@api.depends(
|
|
'kra_line_ids.kpi_line_ids.rating_star',
|
|
'kra_line_ids.kpi_line_ids.manager_rating_star',
|
|
'kra_line_ids.kpi_line_ids.hr_rating_star',
|
|
'kra_line_ids.kpi_line_ids.employee_score',
|
|
'kra_line_ids.kpi_line_ids.manager_score',
|
|
'kra_line_ids.kpi_line_ids.hr_score',
|
|
)
|
|
def _compute_total_scores(self):
|
|
for rec in self:
|
|
employee_total = 0.0
|
|
manager_total = 0.0
|
|
hr_total = 0.0
|
|
|
|
for kra in rec.kra_line_ids:
|
|
for kpi in kra.kpi_line_ids:
|
|
|
|
# Star Rating Mode
|
|
if rec.template_empl_rating_bool:
|
|
employee_total += float(kpi.rating_star or 0)
|
|
manager_total += float(kpi.manager_rating_star or 0)
|
|
hr_total += float(kpi.hr_rating_star or 0)
|
|
|
|
# Point Rating Mode
|
|
elif rec.template_empl_point_bool:
|
|
employee_total += float(kpi.employee_score or 0)
|
|
manager_total += float(kpi.manager_score or 0)
|
|
hr_total += float(kpi.hr_score or 0)
|
|
|
|
rec.total_employee_score = employee_total
|
|
rec.total_manager_score = manager_total
|
|
rec.total_hr_score = hr_total
|
|
|
|
@api.depends('current_salary', 'appraisal_amount')
|
|
def _compute_new_salary(self):
|
|
for rec in self:
|
|
rec.new_salary = (
|
|
rec.current_salary +
|
|
rec.appraisal_amount
|
|
)
|
|
|
|
@api.onchange('appraisal_percentage')
|
|
def _onchange_appraisal_percentage(self):
|
|
for rec in self:
|
|
if rec.current_salary:
|
|
rec.appraisal_amount = (
|
|
rec.current_salary *
|
|
rec.appraisal_percentage
|
|
) / 100
|
|
|
|
def _move_to_next_stage(self):
|
|
self.ensure_one()
|
|
next_stage = self.env['employee.stage.config'].search(
|
|
[('seq', '>', self.stage_id.seq)],
|
|
order='seq asc',
|
|
limit=1
|
|
)
|
|
if next_stage:
|
|
self.stage_id = next_stage.id
|
|
|
|
def action_finance_approve(self):
|
|
for rec in self:
|
|
rec.write({
|
|
'state': 'management_team',
|
|
'finance_user_id': self.env.user.id,
|
|
'finance_date': fields.Datetime.now()
|
|
})
|
|
|
|
rec.message_post(
|
|
body=_(
|
|
"Finance appraisal approved."
|
|
)
|
|
)
|
|
|
|
def _send_manager_notification_mail(self):
|
|
self.ensure_one()
|
|
email_to = self.manager_email
|
|
if not email_to:
|
|
return
|
|
body_html = f"""
|
|
<div>
|
|
<p>Hello Manager,</p>
|
|
<p>
|
|
Employee appraisal is ready for Manager Evaluation.
|
|
</p>
|
|
<br/>
|
|
<table border="1" cellpadding="5" cellspacing="0">
|
|
<tr>
|
|
<td><b>Employee</b></td>
|
|
<td>{self.employee_appraisal_id.name or ''}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>Department</b></td>
|
|
<td>{self.department_appraisal_id.name or ''}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>Performance Period</b></td>
|
|
<td>{self.appraisal_period_id.appraisal_type_id.id or ''}</td>
|
|
</tr>
|
|
</table>
|
|
<br/>
|
|
<p>
|
|
Please complete manager evaluation.
|
|
</p>
|
|
<br/>
|
|
<p>
|
|
Regards,<br/>
|
|
HR Team
|
|
</p>
|
|
</div>
|
|
"""
|
|
mail_values = {
|
|
'subject': 'Manager Evaluation Notification',
|
|
'body_html': body_html,
|
|
'email_to': email_to,
|
|
}
|
|
self.env['mail.mail'].create(mail_values).send()
|
|
|
|
def check_colleague_feedback_deadline(self):
|
|
now = fields.Datetime.now()
|
|
records = self.search([
|
|
('college_end_date_time', '!=', False),
|
|
('college_end_date_time', '<=', now),
|
|
('state', '=', 'colleague_feedback')
|
|
])
|
|
for rec in records:
|
|
rec.write({
|
|
'state': 'in_progress'
|
|
})
|
|
rec.message_post(
|
|
body=_(
|
|
"Colleague feedback deadline completed automatically. "
|
|
"Stage moved to Manager Evaluation."
|
|
)
|
|
)
|
|
rec._send_manager_notification_mail()
|
|
return True
|
|
|
|
def action_sent_employee_appraisal(self):
|
|
self.ensure_one()
|
|
employee_email = self.employee_appraisal_id.work_email or ''
|
|
creator_email = self.creator_email or ''
|
|
emails = ",".join(
|
|
filter(None, [employee_email, creator_email])
|
|
)
|
|
body_html = f"""
|
|
<div>
|
|
<p>Hello,Team</p>
|
|
<p>
|
|
Your appraisal evaluation has been initiated.
|
|
</p>
|
|
<br/>
|
|
<table border="1" cellpadding="5" cellspacing="0">
|
|
<tr>
|
|
<td>
|
|
<b>Employee</b>
|
|
</td>
|
|
|
|
<td>
|
|
{self.employee_appraisal_id.name or ''}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<b>Template</b>
|
|
</td>
|
|
|
|
<td>
|
|
{self.template_id.name or ''}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<b>Performance Period</b>
|
|
</td>
|
|
|
|
<td>
|
|
{self.appraisal_period_id.appraisal_type_id.id or ''}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<br/>
|
|
<p>
|
|
Please complete the self evaluation before deadline.
|
|
</p>
|
|
<br/>
|
|
<p>
|
|
Regards,
|
|
</p>
|
|
<p>
|
|
HR Team
|
|
</p>
|
|
</div>
|
|
"""
|
|
ctx = {
|
|
'default_model': 'employee.appraisal.template.config',
|
|
'default_res_ids': [self.id],
|
|
'default_composition_mode': 'comment',
|
|
'default_email_to': emails,
|
|
'default_subject': 'Employee Appraisal Notification',
|
|
'default_body': body_html,
|
|
'mark_appraisal_sent': True,
|
|
}
|
|
|
|
return {
|
|
'type': 'ir.actions.act_window',
|
|
'res_model': 'mail.compose.message',
|
|
'view_mode': 'form',
|
|
'target': 'new',
|
|
'context': ctx,
|
|
}
|
|
|
|
def action_confirm(self):
|
|
for rec in self:
|
|
rec.state = 'self_evaluation'
|
|
|
|
def action_confirm_manager(self):
|
|
for rec in self:
|
|
rec.state = 'hr_evaluation'
|
|
|
|
def action_confirm_hr(self):
|
|
for rec in self:
|
|
rec.state = 'finance_team'
|
|
|
|
def action_send_colleague_feedback(self):
|
|
for rec in self:
|
|
employees = self.env['hr.employee'].search([
|
|
('department_id', '=', rec.department_appraisal_id.id),
|
|
('id', '!=', rec.employee_appraisal_id.id)
|
|
])
|
|
vals = []
|
|
for emp in employees:
|
|
already_exists = self.env['colleague.feedback'].search([
|
|
('employee_appraisal_feed_id', '=', rec.id),
|
|
('colleague_feed_id', '=', emp.id)
|
|
], limit=1)
|
|
if not already_exists:
|
|
vals.append((0, 0, {
|
|
'colleague_feed_id': emp.id,
|
|
}))
|
|
rec.colleague_feed_ids = vals
|
|
rec.state = 'colleague_manager'
|
|
|
|
@api.onchange('template_id')
|
|
def _onchange_template_id(self):
|
|
self.kra_line_ids = [(5, 0, 0)]
|
|
if not self.template_id:
|
|
return
|
|
kra_vals = []
|
|
for kra in self.template_id.kra_ids:
|
|
kpi_vals = []
|
|
for kpi in kra.kpi_line_ids:
|
|
kpi_vals.append((0, 0, {
|
|
'question': kpi.name,
|
|
'description': kpi.kpi_description,
|
|
'kpi_line_weightage': kpi.kpi_weightage,
|
|
'manager_kpi_points': kpi.kpi_points,
|
|
'manager_kpi_stars': kpi.kpi_ratings,
|
|
}))
|
|
kra_vals.append((0, 0, {
|
|
'kra_id': kra.id,
|
|
'name': kra.name,
|
|
'description_line_kra': kra.description,
|
|
'kra_line_weightage': kra.kra_weightage,
|
|
'max_kra_points': kra.max_points,
|
|
'max_kra_stars': kra.max_star_rating,
|
|
'kpi_line_ids': kpi_vals,
|
|
}))
|
|
|
|
self.kra_line_ids = kra_vals
|
|
|
|
|
|
class ColleagueFeedBack(models.Model):
|
|
_name = 'colleague.feedback'
|
|
_description = 'Colleague Feedback'
|
|
|
|
colleague_feed_id = fields.Many2one('hr.employee', 'Employee', default=lambda self: self.env.user.employee_id.id)
|
|
feedback = fields.Char(string="Feedback")
|
|
employee_appraisal_feed_id = fields.Many2one('employee.appraisal.template.config')
|
|
state = fields.Selection([
|
|
('draft', 'Draft'),
|
|
('submitted', 'Submitted')
|
|
], default='draft')
|
|
|
|
submitted_date = fields.Datetime()
|
|
|
|
def action_submit_feedback(self):
|
|
|
|
for rec in self:
|
|
rec.write({
|
|
'state': 'submitted',
|
|
'submitted_date': fields.Datetime.now()
|
|
})
|
|
|
|
@api.constrains('colleague_feed_id', 'employee_appraisal_feed_id')
|
|
def _check_colleague_feed_id(self):
|
|
for rec in self:
|
|
duplicate = self.search([
|
|
('id', '!=', rec.id),
|
|
('colleague_feed_id', '=', rec.colleague_feed_id.id),
|
|
('employee_appraisal_feed_id', '=', rec.employee_appraisal_feed_id.id)
|
|
], limit=1)
|
|
|
|
if duplicate:
|
|
raise ValidationError(_('Colleague Feed Back already exists'))
|