from odoo import models, fields, api from odoo.cli.scaffold import template RATING_VALUATION = { '1': 'unsatisfactory', '2': 'needs_improvements', '3': 'meet_expectation', '4': 'exceed_expectation', '5': 'outstanding', } class EmployeeAppraisalKRA(models.Model): _name = 'employee.appraisal.kra' _description = 'Key Result Area' _order = 'sequence,id' sequence = fields.Integer(string="Sequence", default=10) template_appraisal_id = fields.Many2one('employee.appraisal.template', string="Template", ondelete='cascade') name = fields.Text(string="KRA Name", required=True) description = fields.Text(string="KRA Description", required=True) kra_weightage = fields.Float(string="KRA Weightage", compute='_compute_kpi_weightage', store=True) max_star_rating = fields.Selection([ ('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ], string='Maximum Stars', default='5') max_points = fields.Float(string='Maximum Points', default=10) kpi_line_ids = fields.One2many('employee.appraisal.kpi', 'kra_id', string="KPI Questions", copy=True) kpi_count = fields.Integer(compute="_compute_kpi_count") kra_template_rating_bool = fields.Boolean(related='template_appraisal_id.template_rating_bool', readonly=True) kra_template_point_bool = fields.Boolean(related='template_appraisal_id.template_point_bool', readonly=True) def _compute_kpi_count(self): for rec in self: rec.kpi_count = len(rec.kpi_line_ids) @api.onchange('kpi_line_ids') def _onchange_kpi_line_ids(self): for rec in self: if ( rec.template_appraisal_id and rec.template_appraisal_id.template_point_bool ): count = len(rec.kpi_line_ids) if count: point_per_kpi = rec.max_points / count for kpi in rec.kpi_line_ids: kpi.kpi_points = point_per_kpi @api.onchange('template_appraisal_id') def onchange_template_appraisal_id(self): for rec in self: template = rec.template_appraisal_id if template.template_rating_bool: rec.max_star_rating = '5' if template.template_point_bool: rec.max_points = 10 @api.depends('kpi_line_ids.kpi_weightage') def _compute_kpi_weightage(self): for rec in self: rec.kra_weightage = sum(rec.kpi_line_ids.mapped('kpi_weightage')) def action_open_questions(self): return { 'type': 'ir.actions.act_window', 'name': 'KPI Questions', 'res_model': 'employee.appraisal.kpi', 'view_mode': 'list,form', 'domain': [('kra_id', '=', self.id)], 'context': { 'default_kra_id': self.id }, 'target': 'new', } class EmployeeAppraisalKPI(models.Model): _name = 'employee.appraisal.kpi' _description = 'Key Performance Indicator' _order = 'sequence,id' sequence = fields.Integer(string="Sequence", default=10) kra_id = fields.Many2one('employee.appraisal.kra', string="KRA", ondelete='cascade') name = fields.Text(string="KPI / Question", required=True) kpi_description = fields.Text('Description') kpi_weightage = fields.Float(string="KRI Weightage") kpi_ratings = fields.Integer(string="KRI Ratings", default=5) kpi_points = fields.Integer(string="KRI Points") def action_delete_record(self): kra_id = self.kra_id.id self.unlink() return { 'type': 'ir.actions.act_window', 'name': 'KPI Questions', 'res_model': 'employee.appraisal.kpi', 'view_mode': 'list,form', 'domain': [('kra_id', '=', kra_id)], 'context': { 'default_kra_id': kra_id }, 'target': 'new', } class EmployeeAppraisalKRALine(models.Model): _name = 'employee.appraisal.kra.line' config_id = fields.Many2one( 'employee.appraisal.template.config', ondelete='cascade' ) template_empl_rating_bool = fields.Boolean( related='config_id.template_empl_rating_bool', readonly=True ) template_empl_point_bool = fields.Boolean(related='config_id.template_empl_point_bool', readonly=True) kra_id = fields.Many2one('employee.appraisal.kra') name = fields.Text('KRA Name') sequence = fields.Integer(default=10) description_line_kra = fields.Text('Description') kra_line_weightage = fields.Float(string="KRA Point Weightage", compute="_compute_kra_line_weightage", store=True) kra_line_star_weightage = fields.Integer(string="KRA Star Weightage", compute="_compute_kra_line_star_weightage", store=True) kra_line_star_demo_weightage = fields.Selection([ ('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ], compute='_compute_kra_line_demo_star_weightage', store=True) kpi_line_ids = fields.One2many('employee.appraisal.kpi.line', 'kra_line_id', string="Questions") kpi_count_line = fields.Integer(compute="_compute_kpi_count_line") max_kra_points = fields.Float(string='Maximum KRA Points') max_kra_stars = fields.Integer(string='Maximum KRA Stars') employee_kra_points = fields.Float(compute='_compute_employee_kra_points', store=True) employee_kra_stars = fields.Float(compute='_compute_employee_kra_stars', store=True) manager_kra_points = fields.Float(compute='_compute_kra_scores', store=True) hr_kra_points = fields.Float(compute='_compute_kra_scores', store=True) manager_kra_stars = fields.Float(compute='_compute_kra_scores', store=True) hr_kra_stars = fields.Float(compute='_compute_kra_scores', store=True) kra_line_star_display = fields.Char(compute='_compute_kra_line_star_display', string='Rating') kra_line_rating = fields.Char(compute="_compute_kra_line_star_display",string="Rating") @api.depends('kpi_line_ids.rating_star','kpi_line_ids.manager_rating_star','kpi_line_ids.hr_rating_star') def _compute_kra_line_star_display(self): for rec in self: ratings = [] ratings += [ int(kpi.rating_star) for kpi in rec.kpi_line_ids if kpi.rating_star ] ratings += [ int(kpi.manager_rating_star) for kpi in rec.kpi_line_ids if kpi.manager_rating_star ] ratings += [ int(kpi.hr_rating_star) for kpi in rec.kpi_line_ids if kpi.hr_rating_star ] if ratings: avg = round(sum(ratings) / len(ratings)) rec.kra_line_star_display = "★" * avg + "☆" * (5 - avg) rec.kra_line_rating = f"({avg})" else: rec.kra_line_star_display = "☆☆☆☆☆" rec.kra_line_rating = "(0)" @api.depends('kpi_line_ids.employee_score','kpi_line_ids.manager_score','kpi_line_ids.hr_score') def _compute_kra_line_weightage(self): for rec in self: employee_total = sum( rec.kpi_line_ids.mapped('employee_score') ) manager_total = sum( rec.kpi_line_ids.mapped('manager_score') ) hr_total = sum( rec.kpi_line_ids.mapped('hr_score') ) rec.kra_line_weightage = ( employee_total + manager_total + hr_total ) / 3 @api.depends('kpi_line_ids.rating_star') def _compute_kra_line_star_weightage(self): for rec in self: ratings = [ int(kpi.rating_star) for kpi in rec.kpi_line_ids if kpi.rating_star ] rec.kra_line_star_weightage = ( sum(ratings) / len(ratings) if ratings else 0 ) @api.depends( 'kpi_line_ids.employee_score', 'kpi_line_ids.manager_score', 'kpi_line_ids.hr_score', 'kpi_line_ids.rating_star', 'kpi_line_ids.manager_rating_star', 'kpi_line_ids.hr_rating_star' ) def _compute_kra_scores(self): for rec in self: # -------------------------- # POINTS # -------------------------- rec.employee_kra_points = sum( rec.kpi_line_ids.mapped('employee_score') ) rec.manager_kra_points = sum( rec.kpi_line_ids.mapped('manager_score') ) rec.hr_kra_points = sum( rec.kpi_line_ids.mapped('hr_score') ) # -------------------------- # STARS # -------------------------- emp_stars = [ int(x.rating_star) for x in rec.kpi_line_ids if x.rating_star ] mgr_stars = [ int(x.manager_rating_star) for x in rec.kpi_line_ids if x.manager_rating_star ] hr_stars = [ int(x.hr_rating_star) for x in rec.kpi_line_ids if x.hr_rating_star ] rec.employee_kra_stars = ( round(sum(emp_stars) / len(emp_stars), 2) if emp_stars else 0 ) rec.manager_kra_stars = ( round(sum(mgr_stars) / len(mgr_stars), 2) if mgr_stars else 0 ) rec.hr_kra_stars = ( round(sum(hr_stars) / len(hr_stars), 2) if hr_stars else 0 ) @api.depends('kpi_line_ids.rating_star') def _compute_kra_line_demo_star_weightage(self): for rec in self: ratings = [ int(kpi.rating_star) for kpi in rec.kpi_line_ids if kpi.rating_star ] if ratings: avg = round(sum(ratings) / len(ratings)) rec.kra_line_star_demo_weightage = str(avg) else: rec.kra_line_star_demo_weightage = '0' def _compute_kpi_count_line(self): for rec in self: rec.kpi_count_line = len(rec.kpi_line_ids) def action_open_questions_line(self): self.ensure_one() return { 'type': 'ir.actions.act_window', 'name': 'KRA Evaluation', 'res_model': 'employee.appraisal.kra.line', 'res_id': self.id, 'view_mode': 'form', 'target': 'new', } class EmployeeAppraisalKPILine(models.Model): _name = 'employee.appraisal.kpi.line' _rec_name = 'question' sequence = fields.Integer(default=10) kra_line_id = fields.Many2one('employee.appraisal.kra.line', ondelete='cascade') kra_name = fields.Text() question = fields.Text(string="KPI") kpi_line_weightage = fields.Float(string="Given KPI Weightage") description = fields.Text() employee_score = fields.Float() manager_score = fields.Float() hr_score = fields.Float() template_empl_rating_bool = fields.Boolean(related='kra_line_id.config_id.template_empl_rating_bool', readonly=True) template_empl_point_bool = fields.Boolean(related='kra_line_id.config_id.template_empl_point_bool', readonly=True) manager_kpi_points = fields.Float(string="Maximum KPI Points") manager_kpi_stars = fields.Integer(string="Maximum KPI Stars") rating = fields.Selection([ ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ], string="Rating") rating_value = fields.Selection([ ('unsatisfactory', 'Unsatisfactory'), ('needs_improvements', 'Needs Improvements'), ('meet_expectation', 'Meets Expectation'), ('exceed_expectation', 'Exceeds Expectation'), ('outstanding', 'Outstanding'), ], string="Rating Value") rating_star = fields.Selection([ ('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ], string="Stars", copy=False) manager_rating_star = fields.Selection([ ('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ], string="Stars", copy=False) hr_rating_star = fields.Selection([ ('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ], string="Stars", copy=False) is_employee_reviewer = fields.Boolean(compute="_compute_user_roles", store=False) is_manager_reviewer = fields.Boolean(compute="_compute_user_roles", store=False) is_hr_reviewer = fields.Boolean(compute="_compute_user_roles", store=False) def _compute_user_roles(self): current_user = self.env.user for rec in self: rec.is_employee_reviewer = ( rec.kra_line_id.config_id.employee_appraisal_id.user_id.id == current_user.id) rec.is_manager_reviewer= ( rec.kra_line_id.config_id.managerapp_id.user_id.id == current_user.id) rec.is_hr_reviewer= ( rec.kra_line_id.config_id.hr_apprai_id.user_id.id == current_user.id ) # self_rating = fields.Selection([ # ('0', '0'), # ('1', '1'), # ('2', '2'), # ('3', '3'), # ('4', '4'), # ('5', '5'), # ], string='Self Rating', compute="_compute_self_rating") # # @api.depends('program_id.self_other_ev_line_ids.rating_star') # def _compute_self_rating(self): # for line in self: # other_line = line.program_id.self_other_ev_line_ids.filtered(lambda l: l.name == line.name) # line.self_rating = other_line.rating_star if other_line else False @api.onchange('rating') def _onchange_rating(self): for rec in self: if rec.rating: rec.rating_value = RATING_VALUATION.get(rec.rating) rec.rating_star = rec.rating else: rec.rating_value = 0 rec.rating_star = 0 @api.onchange('rating_star') def _onchange_rating_star(self): for rec in self: rec.rating_value = RATING_VALUATION.get( rec.rating_star, False ) class ResCompany(models.Model): _inherit = 'res.company' short_code = fields.Char(string="Short Code") company_registry_placeholder = fields.Char(string="Short Code")