diff --git a/addons_extensions/hrms_employee_appraisal/__manifest__.py b/addons_extensions/hrms_employee_appraisal/__manifest__.py index c8c29b0e7..6d39924d6 100644 --- a/addons_extensions/hrms_employee_appraisal/__manifest__.py +++ b/addons_extensions/hrms_employee_appraisal/__manifest__.py @@ -10,7 +10,7 @@ 'company': 'FTPROTECH', 'website': 'https://www.ftprotech.in', - 'depends': ['base', 'hr','hr_employee_extended'], + 'depends': ['base', 'hr','hr_employee_extended','mail'], 'data': [ # 'data/reminder_corn.xml', diff --git a/addons_extensions/hrms_employee_appraisal/models/apprasial_conf.py b/addons_extensions/hrms_employee_appraisal/models/apprasial_conf.py index e25b9cc32..7eba55824 100644 --- a/addons_extensions/hrms_employee_appraisal/models/apprasial_conf.py +++ b/addons_extensions/hrms_employee_appraisal/models/apprasial_conf.py @@ -90,6 +90,7 @@ class AppraisalTemplate(models.Model): 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") + hr_head_employee_id = fields.Many2one('hr.employee',string="Head HR") 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") @@ -124,6 +125,10 @@ class AppraisalTemplate(models.Model): def action_sent_employee(self): for rec in self: + if not rec.kra_ids.name: + raise ValidationError('Please create KRA') + if not rec.kra_ids.mapped('kpi_line_ids'): + raise ValidationError('Please create KPI') # appraisal_config_obj = self.env['employee.appraisal.template.config'] # for rec in self: # first_stage = rec.stage_config_ids.sorted( @@ -160,6 +165,8 @@ class AppraisalTemplate(models.Model): employee_emails = rec.employee_ids.mapped('work_email') manager_emails = rec.manager_ids.mapped('work_email') all_emails = employee_emails + manager_emails + partner_ids = ( + self.employee_ids.mapped('user_id.partner_id')) email_to = ",".join(filter(None, all_emails)) body_html = f"""
@@ -204,6 +211,7 @@ class AppraisalTemplate(models.Model): 'default_res_ids': [rec.id], 'default_composition_mode': 'comment', 'default_email_to': email_to, + 'default_partner_ids': [(6, 0, partner_ids.ids)], 'default_subject': f'Employee Appraisal - {rec.seq}', 'default_body': body_html, 'mark_appraisal_sent_appraisal': True, diff --git a/addons_extensions/hrms_employee_appraisal/models/employee_appraisal.py b/addons_extensions/hrms_employee_appraisal/models/employee_appraisal.py index 99dad649e..215ee5beb 100644 --- a/addons_extensions/hrms_employee_appraisal/models/employee_appraisal.py +++ b/addons_extensions/hrms_employee_appraisal/models/employee_appraisal.py @@ -20,6 +20,7 @@ class EmployeeAppraisal(models.Model): 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') + hr_head_apprai_id = fields.Many2one('hr.employee') managerapp_id = fields.Many2one('hr.employee', string='Manager') # managerapp_id = fields.Many2one('hr.employee', compute='_compute_managerapp_id', string='Manager') performance_evaluator = fields.Selection([('manager', 'Manager'), ('colleague', 'Colleague'), ('own', 'Own')]) @@ -376,20 +377,20 @@ class EmployeeAppraisal(models.Model): 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.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): @@ -532,86 +533,74 @@ class EmployeeAppraisal(models.Model): raise ValidationError( _('Please provide Finance Remarks.') ) - if not self.current_salary: raise ValidationError( _('Please enter Current Salary.') ) - if not self.appraisal_percentage: raise ValidationError( _('Please enter Appraisal Percentage.') ) - - email_to = ",".join( - filter(None, [ - self.employee_appraisal_id.work_email, - self.managerapp_id.work_email, - self.creator_email - ]) - ) - + # email_to = ",".join( + # filter(None, [ + # self.employee_appraisal_id.work_email, + # self.managerapp_id.work_email, + # self.creator_email + # ]) + # ) + finance_head_group = self.env.ref('hrms_employee_appraisal.group_appraisal_finance_head') + email_list = [] + partner_ids = [] + for user in finance_head_group.users: + if user.partner_id.email: + email_list.append(user.partner_id.email) + if user.partner_id: + partner_ids.append(user.partner_id.id) body_html = f"""
-

Hello,

-

Finance review has been completed for the appraisal of {self.employee_appraisal_id.name}.

-

The salary revision details are given below for further approval.

-
- - - - - - - - -
Employee {self.employee_appraisal_id.name or ''}
Department {self.department_appraisal_id.name or ''}
Current Salary {self.current_salary or 0}
Appraisal Percentage {self.appraisal_percentage or 0}%
Appraisal Amount {self.appraisal_amount or 0}
Revised Salary {self.new_salary or 0}
Finance Remarks {self.finance_remarks or ''}
-
-

Kindly review and proceed with the next level approval.

-

Regards,

@@ -624,7 +613,8 @@ class EmployeeAppraisal(models.Model): 'default_model': 'employee.appraisal.template.config', 'default_res_ids': [self.id], 'default_composition_mode': 'comment', - 'default_email_to': email_to, + 'default_email_to': ",".join(email_list), + 'default_partner_ids': [(6, 0, list(set(partner_ids)))], 'default_subject': f'Finance Approval - {self.employee_appraisal_id.name}', 'default_body': body_html, 'move_next_stage': True, @@ -647,13 +637,21 @@ class EmployeeAppraisal(models.Model): _('Please provide Finance Head Remarks.') ) - email_to = ",".join( - filter(None, [ - self.employee_appraisal_id.work_email, - self.managerapp_id.work_email, - self.creator_email - ]) - ) + # email_to = ",".join( + # filter(None, [ + # self.employee_appraisal_id.work_email, + # self.managerapp_id.work_email, + # self.creator_email + # ]) + # ) + management_group = self.env.ref('hrms_employee_appraisal.group_appraisal_management') + email_list = [] + partner_ids = [] + for user in management_group.users: + if user.partner_id.email: + email_list.append(user.partner_id.email) + if user.partner_id: + partner_ids.append(user.partner_id.id) body_html = f"""
@@ -728,7 +726,8 @@ class EmployeeAppraisal(models.Model): 'default_model': 'employee.appraisal.template.config', 'default_res_ids': [self.id], 'default_composition_mode': 'comment', - 'default_email_to': email_to, + 'default_email_to': ",".join(email_list), + 'default_partner_ids': [(6, 0, list(set(partner_ids)))], 'default_subject': f'Finance Head Approval - {self.employee_appraisal_id.name}', 'default_body': body_html, 'move_next_stage': True, @@ -809,6 +808,20 @@ class EmployeeAppraisal(models.Model): def action_sent_employee_appraisal(self): self.ensure_one() + missing = [] + + for kra in self.kra_line_ids: + for kpi in kra.kpi_line_ids: + + if self.template_empl_rating_bool and not kpi.manager_rating_star: + missing.append(_("Please give the Star rating for KPI '%s'.") % (kpi.question or '')) + + if self.template_empl_point_bool and kpi.manager_score <= 0: + missing.append(_("Please enter the score for KPI '%s'.") % (kpi.question or '')) + + if missing: + raise ValidationError("\n".join(missing)) + if not self.manager_remarks: raise ValidationError("Please give the Manager Remarks") @@ -823,6 +836,22 @@ class EmployeeAppraisal(models.Model): creator_email ]) ) + partner_ids = [] + # if self.managerapp_id.user_id.partner_id: + # partner_ids.append(self.managerapp_id.user_id.partner_id.id) + + # if self.employee_appraisal_id.user_id.partner_id: + # partner_ids.append(self.employee_appraisal_id.user_id.partner_id.id) + + if self.hr_apprai_id.user_id.partner_id: + partner_ids.append(self.hr_apprai_id.user_id.partner_id.id) + + # creator = self.env['res.users'].search( + # [('email', '=', self.creator_email)], + # limit=1 + # ) + # if creator.partner_id: + # partner_ids.append(creator.partner_id.id) body_html = f"""
@@ -881,6 +910,7 @@ class EmployeeAppraisal(models.Model): 'default_res_ids': [self.id], 'default_composition_mode': 'comment', 'default_email_to': emails, + 'default_partner_ids': [(6, 0, list(set(partner_ids)))], 'default_subject': 'Employee Appraisal Notification', 'default_body': body_html, 'mark_appraisal_sent': True, @@ -896,12 +926,29 @@ class EmployeeAppraisal(models.Model): def action_confirm_hr(self): self.ensure_one() + missing = [] + + for kra in self.kra_line_ids: + for kpi in kra.kpi_line_ids: + + if self.template_empl_rating_bool and not kpi.hr_rating_star: + missing.append(_("Please give the Star rating for KPI '%s'.") % (kpi.question or '')) + + if self.template_empl_point_bool and kpi.hr_score <= 0: + missing.append(_("Please enter the score for KPI '%s'.") % (kpi.question or '')) + + if missing: + raise ValidationError("\n".join(missing)) if not self.hr_remarks: raise ValidationError ('Please Provide the Remarks') email_to = self.managerapp_id.work_email or '' + partner_ids = [] + if self.hr_head_apprai_id.user_id.partner_id: + partner_ids.append(self.hr_head_apprai_id.user_id.partner_id.id) + body_html = f"""

Hello,

@@ -945,6 +992,7 @@ class EmployeeAppraisal(models.Model): 'default_res_ids': [self.id], 'default_composition_mode': 'comment', 'default_email_to': email_to, + 'default_partner_ids': [(6, 0, list(set(partner_ids)))], 'default_subject': f'HR Evaluation Completed - {self.employee_appraisal_id.name}', 'default_body': body_html, 'move_hr_next_stage': True, @@ -966,7 +1014,18 @@ class EmployeeAppraisal(models.Model): _('Please provide HR Head Remarks.') ) - email_to = self.created_by_id.work_email or '' + # email_to = self.created_by_id.work_email or '' + # partner_ids = [] + # if self.created_by_id.user_id.partner_id: + # partner_ids.append(self.created_by_id.user_id.partner_id.id) + finance_group = self.env.ref('hrms_employee_appraisal.group_appraisal_finance') + email_list = [] + partner_ids = [] + for user in finance_group.users: + if user.partner_id.email: + email_list.append(user.partner_id.email) + if user.partner_id: + partner_ids.append(user.partner_id.id) body_html = f"""
@@ -1007,7 +1066,8 @@ class EmployeeAppraisal(models.Model): 'default_model': 'employee.appraisal.template.config', 'default_res_ids': [self.id], 'default_composition_mode': 'comment', - 'default_email_to': email_to, + 'default_email_to': ",".join(email_list), + 'default_partner_ids': [(6, 0, list(set(partner_ids)))], 'default_subject': f'HR Head Approval - {self.employee_appraisal_id.name}', 'default_body': body_html, 'move_hr_head_next_stage': True, @@ -1023,12 +1083,35 @@ class EmployeeAppraisal(models.Model): def action_send_colleague_feedback(self): for rec in self: + # for kra in rec.kra_line_ids: + # for kpi in kra.kpi_line_ids: + # if rec.template_empl_rating_bool and not kpi.rating_star: + # raise ValidationError(_( + # "Please give the self rating for the KPI '%s' before sending the colleague feedback." + # ) % (kpi.question or '')) + # if rec.template_empl_point_bool and not kpi.employee_score <= 0: + # raise ValidationError(_("Please enter the self score for the KPI '%s' before sending the colleague feedback." + # ) % (kpi.question or '')) + missing = [] + + for kra in rec.kra_line_ids: + for kpi in kra.kpi_line_ids: + + if rec.template_empl_rating_bool and not kpi.rating_star: + missing.append(_("Please give the self rating for KPI '%s'.") % (kpi.question or '')) + + if rec.template_empl_point_bool and kpi.employee_score <= 0: + missing.append(_("Please enter the self score for KPI '%s'.") % (kpi.question or '')) + + if missing: + raise ValidationError("\n".join(missing)) + employees = self.env['hr.employee'].search([ ('department_id', '=', rec.department_appraisal_id.id), ('id', '!=', rec.employee_appraisal_id.id) ]) vals = [] - email_list = [] + for emp in employees: already_exists = self.env['colleague.feedback'].search([ ('employee_appraisal_feed_id', '=', rec.id), @@ -1039,9 +1122,13 @@ class EmployeeAppraisal(models.Model): 'colleague_feed_id': emp.id, })) rec.colleague_feed_ids = vals - if self.managerapp_id and self.managerapp_id.work_email: - email_list.append(self.managerapp_id.work_email) - email_to = ",".join(filter(None, email_list)) + email_list = [] + partner_ids = [] + if rec.managerapp_id: + if rec.managerapp_id.work_email: + email_list.append(rec.managerapp_id.work_email) + if rec.managerapp_id.user_id.partner_id: + partner_ids.append(rec.managerapp_id.user_id.partner_id.id) body_html = f"""
@@ -1067,7 +1154,8 @@ class EmployeeAppraisal(models.Model): 'default_model': 'employee.appraisal.template.config', 'default_res_ids': [self.id], 'default_composition_mode': 'comment', - 'default_email_to': email_to, + 'default_email_to': ",".join(email_list), + 'default_partner_ids': [(6, 0, partner_ids)], 'default_subject': f'Colleague Feedback Request - {self.employee_appraisal_id.name}', 'default_body': body_html, 'mark_colleague_feedback_sent': True, diff --git a/addons_extensions/hrms_employee_appraisal/models/hr_head_nofication.py b/addons_extensions/hrms_employee_appraisal/models/hr_head_nofication.py index 67c2c2712..2308235da 100644 --- a/addons_extensions/hrms_employee_appraisal/models/hr_head_nofication.py +++ b/addons_extensions/hrms_employee_appraisal/models/hr_head_nofication.py @@ -1,4 +1,5 @@ from odoo import api, fields, models +from odoo.exceptions import ValidationError class HrHeadNofication(models.Model): @@ -37,6 +38,13 @@ class HrHeadNofication(models.Model): hr_users_ids = fields.Many2many('res.users', string="HR Team", copy=False, domain=_get_hr_users_domain) + @api.constrains('start_date','end_date') + def check_dates(self): + for rec in self: + if rec.start_date and rec.end_date and rec.end_date <= rec.start_date: + raise ValidationError("End date must be before start date.") + + @api.model def create(self, vals): if vals.get('seq', 'New') == 'New': @@ -68,6 +76,9 @@ class HrHeadNofication(models.Model): hr_emails = self.hr_users_ids.mapped('email') email_to = ",".join(filter(None, hr_emails)) + partner_ids = [] + if self.hr_users_ids.partner_id: + partner_ids = self.hr_users_ids.partner_id.ids body_html = f"""
@@ -108,6 +119,7 @@ class HrHeadNofication(models.Model): 'default_res_ids': [self.id], 'default_composition_mode': 'comment', 'default_email_to': email_to, + 'default_partner_ids':[(6,0,list(set(partner_ids)))], 'default_subject': self.name, 'default_body': body_html, 'mark_hr_notification_sent': True, diff --git a/addons_extensions/hrms_employee_appraisal/models/hr_notice_appraisal.py b/addons_extensions/hrms_employee_appraisal/models/hr_notice_appraisal.py index 667ba5f68..49efe03d6 100644 --- a/addons_extensions/hrms_employee_appraisal/models/hr_notice_appraisal.py +++ b/addons_extensions/hrms_employee_appraisal/models/hr_notice_appraisal.py @@ -17,6 +17,7 @@ class HrNoticeAppraisal(models.Model): return self.env.user.employee_id hr_employee_id = fields.Many2one('hr.employee', string='Employee', default=_default_employee_get) + hr_head_employe_id = fields.Many2one('hr.employee', string='HR Head') notification_id = fields.Many2one('hr.head.notification','HR') subject = fields.Char(string="Subject", required=True, tracking=True) body = fields.Html(string="Notice Body", required=True) @@ -35,7 +36,7 @@ class HrNoticeAppraisal(models.Model): appraisal_notice_id = fields.Many2one('employee.appraisal.year',string="Appraisal Name",domain="[('appraisal_type_id', '=', appraisal_type_id)]") template_appraisal_id = fields.Many2one('employee.appraisal.template', string="Template") seq = fields.Char( string="Reference",readonly=True,copy=False,default="New") - employee_rating = fields.Boolean(string="Employee Rating") + employee_rating = fields.Boolean(string="Employee star Rating") employee_points = fields.Boolean(string="Employee Points") cancel_reason = fields.Text(string="Cancel Reason",tracking=True) cancelled_date = fields.Datetime(string="Cancelled On",tracking=True) @@ -137,6 +138,10 @@ class HrNoticeAppraisal(models.Model): employee_emails = self.employee_ids.mapped('work_email') manager_emails = self.manager_ids.mapped('work_email') all_emails = employee_emails + manager_emails + partner_ids = ( + self.employee_ids.mapped('user_id.partner_id') | + self.manager_ids.mapped('user_id.partner_id') + ) email_to = ",".join(filter(None, all_emails)) body_html = f"""
@@ -187,7 +192,9 @@ class HrNoticeAppraisal(models.Model): 'default_model': 'hr.notice.appraisal', 'default_res_ids': [self.id], 'default_composition_mode': 'comment', + 'default_partner_ids': [(6, 0, partner_ids.ids)], 'default_email_to': email_to, + 'default_email_from': self.env.user.email_formatted, 'default_subject': self.subject, 'default_body': body_html, 'mark_notice_sent': True, @@ -277,6 +284,7 @@ class MailComposeMessage(models.TransientModel): 'name': rec.subject, 'seq': rec.seq, 'employee_eva_id': manager_id, + 'hr_head_employee_id': rec.hr_head_employe_id.id, 'employee_department_id': department_id, 'employee_ids': [(6, 0, employees.ids)], 'manager_ids': [(6, 0, [manager_id])] if manager_id else [(5, 0, 0)], @@ -345,6 +353,7 @@ class MailComposeMessage(models.TransientModel): 'employee_ids': [(6, 0, rec.employee_ids.ids)], 'manager_ids': [(6, 0, rec.manager_ids.ids)], 'notice_id': rec.notice_id.id, + 'hr_head_apprai_id': rec.hr_head_employee_id.id, 'start_date': rec.start_date, 'end_date': rec.end_date, 'appraisal_period_id': rec.appraisal_period_id.id, @@ -385,6 +394,7 @@ class MailComposeMessage(models.TransientModel): 'notification_id': record.id, 'hr_employee_id': employee.id, 'subject': record.name, + 'hr_head_employe_id':record.hr_employee_id.id, 'appraisal_type_id': record.appraisal_type_id.id, 'appraisal_notice_id': diff --git a/addons_extensions/hrms_employee_appraisal/models/kpi_kra.py b/addons_extensions/hrms_employee_appraisal/models/kpi_kra.py index aaa370f3a..4ebc7478c 100644 --- a/addons_extensions/hrms_employee_appraisal/models/kpi_kra.py +++ b/addons_extensions/hrms_employee_appraisal/models/kpi_kra.py @@ -148,47 +148,36 @@ class EmployeeAppraisalKRALine(models.Model): 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' - ) + @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)) - stars = '★' * avg + '☆' * (5 - avg) - rec.kra_line_star_display = f"{stars} ({avg})" + rec.kra_line_star_display = "★" * avg + "☆" * (5 - avg) + rec.kra_line_rating = f"({avg})" else: - rec.kra_line_star_display = "☆☆☆☆☆ (0)" + 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' - ) + @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( diff --git a/addons_extensions/hrms_employee_appraisal/static/src/css/wizard.css b/addons_extensions/hrms_employee_appraisal/static/src/css/wizard.css index 74ad25a86..63746ca17 100644 --- a/addons_extensions/hrms_employee_appraisal/static/src/css/wizard.css +++ b/addons_extensions/hrms_employee_appraisal/static/src/css/wizard.css @@ -5,8 +5,16 @@ } .kra_star_display { - font-size: 22px !important; - font-weight: bold !important; color: #FFD700 !important; + font-size: 22px !important; + font-weight: 700 !important; + text-align: center; +} + +.kra_rating_display { + color: #2563EB !important; /* Blue */ + font-size: 18px !important; + font-weight: 700 !important; + text-align: center; } diff --git a/addons_extensions/hrms_employee_appraisal/views/employee_appraisal.xml b/addons_extensions/hrms_employee_appraisal/views/employee_appraisal.xml index 9d75ce7d2..95dfe32ff 100644 --- a/addons_extensions/hrms_employee_appraisal/views/employee_appraisal.xml +++ b/addons_extensions/hrms_employee_appraisal/views/employee_appraisal.xml @@ -70,12 +70,15 @@ groups="hrms_employee_appraisal.group_appraisal_hr" class="btn-primary" invisible="stage_name != 'HR'"/>