Merge remote-tracking branch 'origin/feature/share_module' into feature/share_module
This commit is contained in:
commit
54541998c5
|
|
@ -0,0 +1,3 @@
|
|||
from . import cancel_wizard_hr
|
||||
from . import postpone_hr_appraisal
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
from odoo import models, fields
|
||||
|
||||
|
||||
class AppraisalCancelWizard(models.TransientModel):
|
||||
_name = 'appraisal.cancel.wizard'
|
||||
_description = 'Cancel Appraisal Wizard'
|
||||
|
||||
reason = fields.Text(
|
||||
string="Reason",
|
||||
required=True
|
||||
)
|
||||
|
||||
def action_confirm_cancel(self):
|
||||
|
||||
notice = self.env['hr.notice.appraisal'].browse(
|
||||
self.env.context.get('active_id')
|
||||
)
|
||||
notice.write({
|
||||
'state': 'cancelled',
|
||||
'cancel_reason': self.reason,
|
||||
'cancelled_date': fields.Datetime.now(),
|
||||
'cancelled_by_id': self.env.user.id,
|
||||
})
|
||||
|
||||
notice.message_post(
|
||||
body=f"""
|
||||
<b>Appraisal Cancelled</b><br/>
|
||||
Reason: {self.reason}
|
||||
"""
|
||||
)
|
||||
employee_emails = notice.employee_ids.mapped('work_email')
|
||||
manager_emails = notice.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>
|
||||
The appraisal has been cancelled.
|
||||
</p>
|
||||
<br/>
|
||||
<table border="1" cellpadding="5" cellspacing="0">
|
||||
<tr>
|
||||
<td><b>Reason</b></td>
|
||||
<td>{self.reason or ''}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<p>Regards,</p>
|
||||
<p>HR Team</p>
|
||||
</div>
|
||||
"""
|
||||
self.env['mail.mail'].create({
|
||||
'subject': 'Appraisal Cancelled',
|
||||
'body_html': body_html,
|
||||
'email_to': email_to,
|
||||
}).send()
|
||||
return {
|
||||
'type': 'ir.actions.act_window_close'
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record id="view_appraisal_cancel_wizard_form" model="ir.ui.view">
|
||||
<field name="name">appraisal.cancel.wizard.form</field>
|
||||
<field name="model">appraisal.cancel.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Cancel Appraisal">
|
||||
<group>
|
||||
<field name="reason"/>
|
||||
</group>
|
||||
|
||||
<footer>
|
||||
<button name="action_confirm_cancel"
|
||||
string="Confirm Cancel"
|
||||
type="object"
|
||||
class="btn-danger"/>
|
||||
<button string="Close"
|
||||
special="cancel"
|
||||
class="btn-secondary"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
from odoo import api, fields, models, tools
|
||||
|
||||
class AppraisalPostponeWizard(models.TransientModel):
|
||||
_name = 'appraisal.postpone.wizard'
|
||||
_description = 'Appraisal Postpone Wizard'
|
||||
|
||||
reason = fields.Text(string="Reason",required=True)
|
||||
new_start_date = fields.Datetime(string="New Start Date")
|
||||
new_end_date = fields.Datetime(string="New End Date")
|
||||
|
||||
def action_confirm_postpone(self):
|
||||
notice = self.env['hr.notice.appraisal'].browse(
|
||||
self.env.context.get('active_id')
|
||||
)
|
||||
notice.write({
|
||||
'state': 'postponed',
|
||||
'postpone_reason': self.reason,
|
||||
'postponed_date': fields.Datetime.now(),
|
||||
'postponed_by_id': self.env.user.id,
|
||||
'new_start_date': self.new_start_date,
|
||||
'new_end_date': self.new_end_date,
|
||||
})
|
||||
notice.message_post(
|
||||
body=f"""
|
||||
<b>Appraisal Postponed</b><br/>
|
||||
Reason: {self.reason}
|
||||
"""
|
||||
)
|
||||
employee_emails = notice.employee_ids.mapped('work_email')
|
||||
manager_emails = notice.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>
|
||||
The appraisal has been postponed.
|
||||
</p>
|
||||
<br/>
|
||||
<table border="1" cellpadding="5" cellspacing="0">
|
||||
<tr>
|
||||
<td><b>Reason</b></td>
|
||||
<td>{self.reason or ''}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>New Start Date</b></td>
|
||||
<td>{self.new_start_date or ''}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>New End Date</b></td>
|
||||
<td>{self.new_end_date or ''}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<p>Regards,</p>
|
||||
<p>HR Team</p>
|
||||
</div>
|
||||
"""
|
||||
self.env['mail.mail'].create({
|
||||
'subject': 'Appraisal Postponed',
|
||||
'body_html': body_html,
|
||||
'email_to': email_to,
|
||||
}).send()
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window_close'
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record id="view_appraisal_postpone_wizard_form" model="ir.ui.view">
|
||||
<field name="name">appraisal.postpone.wizard.form</field>
|
||||
<field name="model">appraisal.postpone.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Postpone Appraisal">
|
||||
<group>
|
||||
<field name="reason"/>
|
||||
<field name="new_start_date"/>
|
||||
<field name="new_end_date"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="action_confirm_postpone" string="Confirm Postpone"
|
||||
type="object" class="btn-warning"/>
|
||||
<button string="Close" special="cancel"
|
||||
class="btn-secondary"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
from . import models
|
||||
from . import Wizard
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
'name': 'PERFORMANCE MANAGEMENT',
|
||||
'version': '18.0.1.0.0',
|
||||
'category': 'PERFORMANCE MANAGEMENT',
|
||||
'summary': 'Manages the Employee Appraisal process of the employees',
|
||||
'description': """
|
||||
This module helps to create and approve/reject employee appraisal
|
||||
""",
|
||||
'author': 'Seshi Kanth D',
|
||||
'company': 'FTPROTECH',
|
||||
'website': 'https://www.ftprotech.in',
|
||||
|
||||
'depends': ['base', 'hr','hr_employee_extended'],
|
||||
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/employee_appraisal.xml',
|
||||
'views/employee_evalutor.xml',
|
||||
'views/employee_template_appraisal.xml',
|
||||
'views/hr_notice_appraisal.xml',
|
||||
'views/stage_config.xml',
|
||||
'Wizard/cancel_wizard_hr.xml',
|
||||
'Wizard/postpone_hr_appraisal.xml',
|
||||
],
|
||||
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'hrms_employee_appraisal/static/src/css/wizard.css'
|
||||
],
|
||||
},
|
||||
|
||||
'license': 'LGPL-3',
|
||||
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': True,
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
from . import employee_appraisal
|
||||
from . import apprasial_conf
|
||||
from . import kpi_kra
|
||||
from . import hr_notice_appraisal
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
from odoo import api, fields, models
|
||||
|
||||
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.Datetime('Starting Month')
|
||||
end_month = fields.Datetime('End Month')
|
||||
active = fields.Boolean(default=True)
|
||||
year_seq = fields.Integer(string="Sequence")
|
||||
appraisal_type_id = fields.Many2one(
|
||||
'employee.appraisal.type',
|
||||
string="Appraisal Type"
|
||||
)
|
||||
|
||||
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="Employee Appraisal Evaluator")
|
||||
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):
|
||||
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,
|
||||
}
|
||||
|
|
@ -0,0 +1,644 @@
|
|||
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'))
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
from random import randint
|
||||
|
||||
|
||||
class HrNoticeAppraisal(models.Model):
|
||||
_name = 'hr.notice.appraisal'
|
||||
_description = 'Performance Cycle Notification'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_rec_name = 'subject'
|
||||
_order = 'id desc'
|
||||
|
||||
@api.returns('self')
|
||||
def _default_employee_get(self):
|
||||
return self.env.user.employee_id
|
||||
|
||||
hr_employee_id = fields.Many2one('hr.employee', string='Employee', default=_default_employee_get)
|
||||
subject = fields.Char(string="Subject", required=True, tracking=True)
|
||||
body = fields.Html(string="Notice Body", required=True)
|
||||
start_date = fields.Datetime(string="Start Date", required=True)
|
||||
end_date = fields.Datetime(string="End Date", required=True)
|
||||
employee_ids = fields.Many2many('hr.employee', 'notice_employee_rel', 'notice_id', 'employee_id',string="Employees")
|
||||
manager_ids = fields.Many2many('hr.employee', 'notice_manager_rel', 'notice_id', 'manager_id', string="Managers")
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('sent', 'Sent'),
|
||||
('postponed', 'Postponed'),
|
||||
('cancelled', 'Cancelled'),
|
||||
], default='draft', tracking=True)
|
||||
# appraisal_notice_id = fields.Many2one('employee.appraisal.year', string="Appraisal Period", required=True)
|
||||
appraisal_type_id = fields.Many2one('employee.appraisal.type',string="Appraisal Type")
|
||||
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_points = fields.Boolean(string="Employee Points")
|
||||
cancel_reason = fields.Text(string="Cancel Reason",tracking=True)
|
||||
cancelled_date = fields.Datetime(string="Cancelled On",tracking=True)
|
||||
cancelled_by_id = fields.Many2one('res.users',string="Cancelled By",tracking=True)
|
||||
postpone_reason = fields.Text(string="Postpone Reason",tracking=True)
|
||||
postponed_date = fields.Datetime(string="Postponed On",tracking=True)
|
||||
postponed_by_id = fields.Many2one('res.users',string="Postponed By",tracking=True)
|
||||
new_start_date = fields.Datetime(string="New Start Date")
|
||||
new_end_date = fields.Datetime(string="New End Date")
|
||||
stage_config = fields.Many2many('employee.stage.config',string='Stages')
|
||||
hr_department_ids = fields.Many2many('hr.department', string="Departments")
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('seq', 'New') == 'New':
|
||||
company = self.env.company
|
||||
company_code = company.short_code or 'CMP'
|
||||
today = fields.Datetime.now()
|
||||
month = str(today.month).zfill(2)
|
||||
year = str(today.year)[-2:]
|
||||
prefix = f"{company_code}/{month}/{year}"
|
||||
last_record = self.search([
|
||||
('seq', '=like', f'{prefix}%')
|
||||
], order='id desc', limit=1)
|
||||
number = 1
|
||||
if last_record and last_record.seq:
|
||||
try:
|
||||
number = int(
|
||||
last_record.seq.split('/')[-1]
|
||||
) + 1
|
||||
except Exception:
|
||||
number = 1
|
||||
vals['seq'] = (
|
||||
f"{prefix}/{str(number).zfill(3)}"
|
||||
)
|
||||
return super().create(vals)
|
||||
|
||||
@api.constrains('start_date', 'end_date')
|
||||
def _check_dates(self):
|
||||
for rec in self:
|
||||
if rec.end_date < rec.start_date:
|
||||
raise ValidationError(_("End Date must be greater than Start Date."))
|
||||
|
||||
@api.onchange('employee_ids')
|
||||
def _onchange_employee_ids(self):
|
||||
managers = self.employee_ids.mapped('parent_id')
|
||||
departments = self.employee_ids.mapped('department_id')
|
||||
self.manager_ids = [(6, 0, managers.ids)]
|
||||
self.hr_department_ids = [(6,0, departments.ids)]
|
||||
|
||||
def action_send_notice(self):
|
||||
self.ensure_one()
|
||||
employee_emails = self.employee_ids.mapped('work_email')
|
||||
manager_emails = self.manager_ids.mapped('work_email')
|
||||
all_emails = employee_emails + manager_emails
|
||||
email_to = ",".join(filter(None, all_emails))
|
||||
template_obj = self.env['employee.appraisal.template']
|
||||
grouped_employees = {}
|
||||
for employee in self.employee_ids:
|
||||
manager = employee.parent_id
|
||||
department = employee.department_id
|
||||
key = (
|
||||
manager.id if manager else False,
|
||||
department.id if department else False
|
||||
)
|
||||
if key not in grouped_employees:
|
||||
grouped_employees[key] = self.env['hr.employee']
|
||||
grouped_employees[key] |= employee
|
||||
for (manager_id, department_id), employees in grouped_employees.items():
|
||||
already_exists = template_obj.search([
|
||||
('notice_id', '=', self.id),
|
||||
# ('employee_eva_id', '=', manager_id),
|
||||
('employee_department_id', '=', department_id),
|
||||
], limit=1)
|
||||
if already_exists:
|
||||
continue
|
||||
template_obj.create({
|
||||
'name': self.subject,
|
||||
'seq': self.seq,
|
||||
'employee_eva_id': manager_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)],
|
||||
'notice_id': self.id,
|
||||
'start_date': self.start_date,
|
||||
'end_date': self.end_date,
|
||||
'appraisal_period_id': self.appraisal_notice_id.id,
|
||||
'appraisal_period_type_id': self.appraisal_type_id.id,
|
||||
'template_rating_bool': self.employee_rating,
|
||||
'template_point_bool': self.employee_points,
|
||||
'hr_employee_id': self.hr_employee_id.id,
|
||||
'stage_config_ids': [(6, 0, self.stage_config.ids)],
|
||||
})
|
||||
# print('1234',template_obj.create({}))
|
||||
|
||||
body_html = f"""
|
||||
<div>
|
||||
<p>Hello,</p>
|
||||
<p>{self.body or ''}</p>
|
||||
<br/>
|
||||
<table border="1" cellpadding="5" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<b>Appraisal Period</b>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{self.appraisal_notice_id.appraisal_name or ''}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Start Date</b>
|
||||
</td>
|
||||
<td>
|
||||
{self.start_date or ''}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>End Date</b>
|
||||
</td>
|
||||
<td>
|
||||
{self.end_date or ''}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<p>
|
||||
Please complete the appraisal within the given timeline.
|
||||
</p>
|
||||
<br/>
|
||||
<p>
|
||||
Regards,
|
||||
</p>
|
||||
<p>
|
||||
HR Team
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
ctx = {
|
||||
'default_model': 'hr.notice.appraisal',
|
||||
'default_res_ids': [self.id],
|
||||
'default_composition_mode': 'comment',
|
||||
'default_email_to': email_to,
|
||||
'default_subject': self.subject,
|
||||
'default_body': body_html,
|
||||
'mark_notice_sent': True,
|
||||
}
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'mail.compose.message',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
def action_open_postpone_wizard(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Postpone Appraisal',
|
||||
'res_model': 'appraisal.postpone.wizard',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'active_id': self.id
|
||||
}
|
||||
}
|
||||
|
||||
def action_open_cancel_wizard(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Cancel Appraisal',
|
||||
'res_model': 'appraisal.cancel.wizard',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'active_id': self.id
|
||||
}
|
||||
}
|
||||
|
||||
class StageConfig(models.Model):
|
||||
_name = 'employee.stage.config'
|
||||
_description = 'employee.stage.config'
|
||||
_order = 'seq'
|
||||
|
||||
def _get_default_color_stage(self):
|
||||
return randint(1, 11)
|
||||
|
||||
name = fields.Char(required=True)
|
||||
seq = fields.Integer(required=True)
|
||||
active = fields.Boolean(default=True)
|
||||
color = fields.Integer('Color', default=_get_default_color_stage)
|
||||
|
||||
|
||||
class MailComposeMessage(models.TransientModel):
|
||||
_inherit = 'mail.compose.message'
|
||||
|
||||
def action_send_mail(self):
|
||||
|
||||
res = super().action_send_mail()
|
||||
|
||||
model = self.env.context.get('default_model')
|
||||
res_ids = self.env.context.get('default_res_ids')
|
||||
if self.env.context.get('mark_notice_sent'):
|
||||
|
||||
if model == 'hr.notice.appraisal' and res_ids:
|
||||
records = self.env[model].browse(res_ids)
|
||||
|
||||
records.write({
|
||||
'state': 'sent'
|
||||
})
|
||||
if self.env.context.get('mark_appraisal_sent'):
|
||||
if model == 'employee.appraisal.template.config' and res_ids:
|
||||
records = self.env[model].browse(res_ids)
|
||||
for record in records:
|
||||
record._move_to_next_stage()
|
||||
|
||||
if self.env.context.get('mark_appraisal_sent_appraisal'):
|
||||
|
||||
if model == 'employee.appraisal.template' and res_ids:
|
||||
records = self.env[model].browse(res_ids)
|
||||
|
||||
records.write({
|
||||
'employee_state': 'sent'
|
||||
})
|
||||
|
||||
return res
|
||||
|
|
@ -0,0 +1,414 @@
|
|||
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')
|
||||
|
||||
@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})"
|
||||
else:
|
||||
rec.kra_line_star_display = "☆☆☆☆☆ (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)
|
||||
# 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")
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_employee_appraisal_template_config,employee.appraisal.template.config,model_employee_appraisal_template_config,base.group_user,1,1,1,1
|
||||
access_employee_appraisal_year,employee.appraisal.year,model_employee_appraisal_year,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
access_employee_appraisal_template,employee.appraisal.template,model_employee_appraisal_template,base.group_user,1,1,1,1
|
||||
|
||||
access_employee_appraisal_kra_user,employee.appraisal.kra.user,model_employee_appraisal_kra,base.group_user,1,1,1,1
|
||||
access_employee_appraisal_kpi_user,employee.appraisal.kpi.user,model_employee_appraisal_kpi,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
access_employee_appraisal_kra_line_user,employee.appraisal.kra.line.user,model_employee_appraisal_kra_line,base.group_user,1,1,1,1
|
||||
access_employee_appraisal_kpi_line_user,employee.appraisal.kpi.line.user,model_employee_appraisal_kpi_line,base.group_user,1,1,1,1
|
||||
|
||||
access_colleague_feedback_user,colleague.feedback.user,model_colleague_feedback,base.group_user,1,1,1,1
|
||||
access_hr_notice_appraisal,hr.notice.appraisal,model_hr_notice_appraisal,base.group_user,1,1,1,1
|
||||
|
||||
access_employee.appraisal.type,employee.appraisal.type,model_employee_appraisal_type,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
|
||||
access_appraisal_postpone_wizard,appraisal_postpone_wizard,model_appraisal_postpone_wizard,base.group_user,1,1,1,1
|
||||
access_appraisal_cancel_wizard,appraisal.cancel.wizard,model_appraisal_cancel_wizard,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
access_employee_stage_config,employee.stage.config,model_employee_stage_config,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
.modal-dialog:has(.appraisal_kra_popup) {
|
||||
max-width: 75vw !important;
|
||||
width: 75vw !important;
|
||||
}
|
||||
|
||||
.kra_star_display {
|
||||
font-size: 22px !important;
|
||||
font-weight: bold !important;
|
||||
color: #FFD700 !important;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
|
|
@ -0,0 +1,247 @@
|
|||
<odoo>
|
||||
<data>
|
||||
|
||||
<!-- TREE VIEW -->
|
||||
<record id="view_employee_appraisal_template_tree" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.template.config.tree</field>
|
||||
<field name="model">employee.appraisal.template.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Employee Appraisal">
|
||||
<field name="seq" string="Performance Id"/>
|
||||
<field name="employee_appraisal_id"/>
|
||||
<!-- <field name="employee_evaluator_name_id"/>-->
|
||||
<!-- <field name="performance_evaluator"/>-->
|
||||
<field name="template_id" string="Template"/>
|
||||
<field name="appraisal_period_id" string="Performance Period"/>
|
||||
<!-- <field name="state" widget="badge"/>-->
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_employee_appraisal_form" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.template.config.form</field>
|
||||
<field name="model">employee.appraisal.template.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Employee Appraisal">
|
||||
<header>
|
||||
<!-- <field name="state" widget="statusbar"/>-->
|
||||
<field name="available_stage_ids" invisible="1"/>
|
||||
<!-- <field name="stage_id"-->
|
||||
<!-- widget="statusbar"/>-->
|
||||
<field name="stage_id"
|
||||
widget="statusbar"
|
||||
domain="[('id', 'in', available_stage_ids)]"/>
|
||||
<button name="action_sent_employee_appraisal" string="Send" type="object"
|
||||
confirm="Do you want to move to next stage?"
|
||||
class="btn-primary" invisible="stage_id.name != 'NEW'"/>
|
||||
<!-- class="btn-primary" invisible="state != 'new'"/>-->
|
||||
<button name="action_send_colleague_feedback"
|
||||
string="Send Colleague Feedback & Manager"
|
||||
type="object"
|
||||
class="btn-primary" invisible="stage_id.name != 'COLLEAGE&MANAGER'"/>
|
||||
<!-- invisible="state != 'self_evaluation'"/>-->
|
||||
<button name="action_confirm_manager" string="Manager" type="object"
|
||||
confirm="Do you want to move to next stage?"
|
||||
class="btn-primary" invisible="stage_id.name != 'HR'"/>
|
||||
<!-- invisible="state != 'colleague_manager'"/>-->
|
||||
<button name="action_confirm_hr" string="HR Confirm" type="object"
|
||||
confirm="Do you want to move to next stage?"
|
||||
class="btn-primary" invisible="stage_id.name != 'HR'"/>
|
||||
<!-- invisible="state != 'hr_evaluation'"/>-->
|
||||
<button name="action_finance_approve" string="Finance Appraisal"
|
||||
type="object" class="btn-primary" invisible="stage_id.name != 'FINANCE TEAM'"/>
|
||||
<!-- invisible="state != 'finance_team'"/>-->
|
||||
<!-- <button name="action_confirm" string="Confirm" type="object"-->
|
||||
<!-- confirm="Do you want to move to next stage?"-->
|
||||
<!-- class="btn-primary" invisible="state != 'self_evaluation'"/>-->
|
||||
<!-- <button name="action_move_manager_stage"-->
|
||||
<!-- type="object"-->
|
||||
<!-- string="Move To Manager Evaluation"-->
|
||||
<!-- class="btn-primary"-->
|
||||
<!-- invisible="state != 'colleague_feedback'"/>-->
|
||||
</header>
|
||||
<sheet>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="seq" string="Performance Id"/>
|
||||
<field name="employee_appraisal_id" string="Employee"/>
|
||||
<field name="job_appraisal_id" string="Current Job Title" readonly="1"/>
|
||||
<field name="department_appraisal_id" string="Department" readonly="1"/>
|
||||
<field name="template_id" string="Template"/>
|
||||
<!-- <field name="available_stage_ids" invisible="0" widget="many2many_tags"/>-->
|
||||
<field name="appraisal_period_id" string="Performance Period"/>
|
||||
<!-- <field name="manager_ids" widget="many2many_tags"/>-->
|
||||
<field name="managerapp_id"/>
|
||||
<field name="manager_remarks"/>
|
||||
<field name="hr_apprai_id" string="HR"/>
|
||||
<field name="hr_remarks"/>
|
||||
<field name="start_date" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="image_1920" widget="image" class="oe_avatar" nolabel="1"
|
||||
options="{'zoom': true}"/>
|
||||
<field name="total_employee_score" readonly="1"/>
|
||||
<field name="total_manager_score" readonly="1"/>
|
||||
<field name="total_hr_score" readonly="1"/>
|
||||
<field name="company_id" string="Company"/>
|
||||
<field name="end_date" readonly="1"/>
|
||||
<field name="template_empl_rating_bool"/>
|
||||
<field name="template_empl_point_bool"/>
|
||||
</group>
|
||||
<group string="Performance Standards">
|
||||
<div>
|
||||
1 = Unsatisfactory
|
||||
</div>
|
||||
<div>
|
||||
2 = Needs Improvements
|
||||
</div>
|
||||
<div>
|
||||
3 = Meets Expectations
|
||||
</div>
|
||||
<div>
|
||||
4 = Exceeds Expectations
|
||||
</div>
|
||||
<div>
|
||||
5 = Outstanding
|
||||
</div>
|
||||
<div></div>
|
||||
<div>
|
||||
<field name="Note_appraisal" widget="text" style="font-weight:bold;" nolabel="1"/>
|
||||
</div>
|
||||
</group>
|
||||
<group string="Overall Scores">
|
||||
<field name="overall_score" readonly="1"/>
|
||||
<field name="overall_rating" readonly="1"/>
|
||||
<field name="overall_rating_star" widget="priority" readonly="1"/>
|
||||
<field name="overall_rating_value" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="KRA & KPI Evaluation">
|
||||
<field name="kra_line_ids" nolabel="1">
|
||||
<!-- LIST VIEW -->
|
||||
<list>
|
||||
<field name="name" readonly="1"/>
|
||||
<field name="description_line_kra" readonly="1"/>
|
||||
<!-- <field name="kra_line_weightage" sum="Total Weightage" readonly="1"/>-->
|
||||
<!-- <field name="kra_line_star_weightage" sum="Total Weightage" readonly="1"/>-->
|
||||
<field name="kra_line_weightage"
|
||||
readonly="1" sum="Total weight"
|
||||
column_invisible="parent.template_empl_point_bool == False or parent.template_empl_rating_bool == True"/>
|
||||
<field name="kra_line_star_display" class="kra_star_display"
|
||||
readonly="1" sum="Total stars"
|
||||
column_invisible="parent.template_empl_rating_bool == False"/>
|
||||
<!-- <field name="kra_line_star_demo_weightage" widget="priority"-->
|
||||
<!-- sum="Total Weightage" readonly="1" column_invisible="1"/>-->
|
||||
<!-- <field name="kra_line_star_display" readonly="1" class="kra_star_display"/>-->
|
||||
<field name="kpi_count_line" readonly="1"/>
|
||||
</list>
|
||||
<form class="appraisal_kra_popup">
|
||||
<sheet>
|
||||
<group>
|
||||
<h2>
|
||||
<field name="name" readonly="1" nolabel="1"/>
|
||||
</h2>
|
||||
</group>
|
||||
<!-- KPI QUESTIONS -->
|
||||
<field name="kpi_line_ids" nolabel="1" string="KPI">
|
||||
<list editable="bottom" delete="0">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="question"/>
|
||||
<field name="description"/>
|
||||
<!-- <field name="kpi_line_weightage" sum="Total Weight Age"/>-->
|
||||
<field name="template_empl_rating_bool" column_invisible="1"/>
|
||||
<field name="template_empl_point_bool" column_invisible="1"/>
|
||||
<field name="employee_score" string="self Rating" sum="Total score"
|
||||
column_invisible="parent.template_empl_point_bool == False"/>
|
||||
<field name="rating_star" widget="priority" string="Self Rating"
|
||||
column_invisible="parent.template_empl_rating_bool == False or parent.template_empl_point_bool == True"/>
|
||||
<field name="manager_rating_star" widget="priority" string="Manager Rating"
|
||||
column_invisible="parent.template_empl_rating_bool == False or parent.template_empl_point_bool == True"/>
|
||||
<field name="hr_rating_star" widget="priority" string="HR Rating"
|
||||
column_invisible="parent.template_empl_rating_bool == False or parent.template_empl_point_bool == True"/>
|
||||
<field name="manager_score" sum="Total Points" column_invisible="parent.template_empl_point_bool == False"/>
|
||||
<field name="hr_score" sum="Total Points" column_invisible="parent.template_empl_point_bool == False"/>
|
||||
</list>
|
||||
</field>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Team Feed Back">
|
||||
<!-- <field name="colleague_feed_ids" readonly="state != 'colleague_feedback'">-->
|
||||
<field name="colleague_feed_ids">
|
||||
<list editable="bottom">
|
||||
<field name="colleague_feed_id"/>
|
||||
<field name="feedback"/>
|
||||
<!-- <field name="feedback" readonly="state == 'submitted'"/>-->
|
||||
<!-- <field name="state"/>-->
|
||||
<button name="action_submit_feedback" type="object" string="Submit"/>
|
||||
<!-- invisible="state == 'submitted'"/>-->
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Finance Review">
|
||||
|
||||
<group>
|
||||
|
||||
<group string="Salary Details">
|
||||
|
||||
<field name="current_salary"/>
|
||||
|
||||
<field name="appraisal_percentage"/>
|
||||
|
||||
<field name="appraisal_amount"/>
|
||||
|
||||
<field name="new_salary" readonly="1"/>
|
||||
|
||||
</group>
|
||||
|
||||
<group string="Finance Remarks">
|
||||
|
||||
<field name="finance_remarks"/>
|
||||
|
||||
<field name="finance_user_id"
|
||||
readonly="1"/>
|
||||
|
||||
<field name="finance_date"
|
||||
readonly="1"/>
|
||||
|
||||
</group>
|
||||
|
||||
</group>
|
||||
|
||||
<footer>
|
||||
|
||||
|
||||
</footer>
|
||||
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ACTION -->
|
||||
<record id="action_employee_appraisal_template" model="ir.actions.act_window">
|
||||
<field name="name">Employee Performance Review</field>
|
||||
<field name="res_model">employee.appraisal.template.config</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<!-- ROOT MENU -->
|
||||
<menuitem id="menu_employee_appraisal_root"
|
||||
name="Employee Appraisal"
|
||||
web_icon="hrms_employee_appraisal,static/description/icon.png"
|
||||
sequence="10"/>
|
||||
|
||||
<!-- CONFIGURATION -->
|
||||
<menuitem id="menu_employee_appraisal_configuration"
|
||||
name="Employee Performance Review"
|
||||
parent="menu_employee_appraisal_root"
|
||||
action="action_employee_appraisal_template"
|
||||
sequence="03"/>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<odoo>
|
||||
|
||||
<menuitem id="configuration_id_employee"
|
||||
name="Configuration"
|
||||
parent="menu_employee_appraisal_root"
|
||||
sequence="04"/>
|
||||
|
||||
<record id="view_employee_appraisal_yea_form" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.year.form</field>
|
||||
<field name="model">employee.appraisal.year</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Employee Appraisal Period">
|
||||
<sheet>
|
||||
<group>
|
||||
<!-- <field name="appraisal_name_id"/>-->
|
||||
<field name="year_seq"/>
|
||||
<field name="appraisal_type_id"/>
|
||||
<field name="appraisal_name"/>
|
||||
<!-- <field name="appraisal_period"/>-->
|
||||
<field name="start_month"/>
|
||||
<field name="end_month"/>
|
||||
</group>
|
||||
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_employee_appraisal_period_tree" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.year.tree</field>
|
||||
<field name="model">employee.appraisal.year</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Employee Appraisal Period"
|
||||
create="1"
|
||||
edit="1"
|
||||
delete="1">
|
||||
<field name="year_seq" widget="handle"/>
|
||||
<field name="appraisal_type_id"/>
|
||||
<field name="appraisal_name"/>
|
||||
<!-- <field name="appraisal_period" required="1"/>-->
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_employee_appraisal_year" model="ir.actions.act_window">
|
||||
<field name="name">Performance Evaluation Period</field>
|
||||
<field name="res_model">employee.appraisal.year</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<menuitem id="menu_employee_appraisal_year"
|
||||
name="Performance Evaluation Period"
|
||||
parent="configuration_id_employee"
|
||||
action="action_employee_appraisal_year"
|
||||
sequence="20"/>
|
||||
|
||||
<!-- employee.appraisal.type-->
|
||||
|
||||
<record id="view_employee_appraisal_type_form" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.type.form</field>
|
||||
<field name="model">employee.appraisal.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Employee Appraisal Period">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="seq"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_employee_appraisal_type_tree" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.type.tree</field>
|
||||
<field name="model">employee.appraisal.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="seq"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_employee_appraisal_type" model="ir.actions.act_window">
|
||||
<field name="name">Performance Evaluation Type</field>
|
||||
<field name="res_model">employee.appraisal.type</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<menuitem id="menu_employee_appraisal_type"
|
||||
name="Performance Evaluation Type"
|
||||
parent="configuration_id_employee"
|
||||
action="action_employee_appraisal_type"
|
||||
sequence="21"/>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record id="view_employee_appraisal_template_form_conf" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.template.form</field>
|
||||
<field name="model">employee.appraisal.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Employee Appraisal Template">
|
||||
<header>
|
||||
<button name="action_sent_employee"
|
||||
type="object"
|
||||
string="Send To Employee"
|
||||
class="oe_highlight"
|
||||
invisible="employee_state != 'new'"/>
|
||||
<field name="employee_state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group string="Details" col="2">
|
||||
<group>
|
||||
<field name="seq" string="Performance Id"/>
|
||||
<field name="name" string="Reference" placeholder="Administration Appraisal Template"/>
|
||||
<field name="manager_ids" widget="many2many_tags" string="Performance Evaluator"/>
|
||||
<field name="employee_eva_id"/>
|
||||
<field name="employee_department_id"/>
|
||||
<field name="appraisal_period_type_id" string="Performance Type"/>
|
||||
<field name="appraisal_period_id" string="Performance Period"/>
|
||||
<field name="hr_employee_id" string="HR"/>
|
||||
<field name="stage_config_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id" string="Company"/>
|
||||
<!-- <field name="email_notify_user_ids" widget="many2many_tags"-->
|
||||
<!-- string="Notify Users if New Evaluation Submited and Confirmed"/>-->
|
||||
<!-- <field name="hr_email_notify" string="Send Email if HR APPROVE or REJECT Evaluation?"/>-->
|
||||
<field name="start_date" readonly="1"/>
|
||||
<field name="end_date" readonly="1"/>
|
||||
<field name="template_rating_bool"/>
|
||||
<field name="template_point_bool"/>
|
||||
<field name="kra_weightage"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Key Result Areas">
|
||||
<field name="kra_ids">
|
||||
<list editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="description"/>
|
||||
<!-- <field name="kra_weightage" sum="Total Weightage"/>-->
|
||||
<field name="kra_template_rating_bool" column_invisible="1"/>
|
||||
<field name="kra_template_point_bool" column_invisible="1"/>
|
||||
<field name="max_star_rating" widget="priority" column_invisible="parent.template_rating_bool == False"/>
|
||||
<field name="max_points" column_invisible="parent.template_point_bool == False"/>
|
||||
<field name="kpi_count" readonly="1"/>
|
||||
<button name="action_open_questions"
|
||||
type="object"
|
||||
string="View KPI"
|
||||
class="oe_highlight"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Assigned Employees">
|
||||
<field name="employee_ids" widget="many2many_tags"/>
|
||||
<field name="mail_sent_employee_ids" widget="many2many_tags"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_employee_appraisal_template_list" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.template.list</field>
|
||||
<field name="model">employee.appraisal.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Employee Appraisal Templates">
|
||||
<field name="seq" string="Performance Id"/>
|
||||
<field name="name"/>
|
||||
<field name="employee_eva_id" string="Performance Evaluator"/>
|
||||
<field name="appraisal_period_type_id" string="Performance Type"/>
|
||||
<field name="appraisal_period_id" string="Performance Period"/>
|
||||
<field name="company_id"/>
|
||||
<field name="hr_email_notify"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_employee_appraisal_template_conf" model="ir.actions.act_window">
|
||||
<field name="name">Employee Appraisal Templates</field>
|
||||
<field name="res_model">employee.appraisal.template</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_employee_appraisal_template"
|
||||
name="Employee Appraisal Templates"
|
||||
parent="menu_employee_appraisal_root"
|
||||
action="action_employee_appraisal_template_conf"
|
||||
sequence="02"/>
|
||||
|
||||
<!-- KPI TREE VIEW -->
|
||||
|
||||
<record id="view_employee_appraisal_kpi_list" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.kpi.list</field>
|
||||
<field name="model">employee.appraisal.kpi</field>
|
||||
<field name="arch" type="xml">
|
||||
<list editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="kpi_description"/>
|
||||
<field name="kpi_weightage"/>
|
||||
<button name="action_delete_record"
|
||||
type="object"
|
||||
string="Delete"
|
||||
icon="fa-trash"
|
||||
confirm="Are you sure you want to delete this question?"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- KPI FORM VIEW -->
|
||||
|
||||
<record id="view_employee_appraisal_kpi_form" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.kpi.form</field>
|
||||
<field name="model">employee.appraisal.kpi</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Question">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
|
||||
<!-- SAVE -->
|
||||
<button string="Save"
|
||||
type="object"
|
||||
special="save"
|
||||
class="btn-primary"/>
|
||||
|
||||
<!-- DELETE -->
|
||||
<button name="action_delete_record"
|
||||
string="Delete"
|
||||
type="object"
|
||||
class="btn-danger"/>
|
||||
|
||||
<!-- CLOSE -->
|
||||
|
||||
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="short_code_res_company_view_form" model="ir.ui.view">
|
||||
<field name="model">res.company</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="color" position="after">
|
||||
<field name="short_code"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
<odoo>
|
||||
<record id="view_hr_notice_appraisal_form" model="ir.ui.view">
|
||||
<field name="name">hr.notice.appraisal.form</field>
|
||||
<field name="model">hr.notice.appraisal</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="HR Notice">
|
||||
<header>
|
||||
<button name="action_send_notice" string="Send Appraisal Initiation" type="object"
|
||||
class="btn btn-success" invisible="state != 'draft'"/>
|
||||
<button name="action_open_postpone_wizard" string="Postpone" type="object"
|
||||
class="btn-warning" invisible="state != 'sent'"/>
|
||||
<button name="action_open_cancel_wizard" string="Cancel" type="object"
|
||||
class="btn-danger" invisible="state not in ('postponed','sent')"/>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="seq"/>
|
||||
<field name="hr_employee_id" string="Created BY"/>
|
||||
<field name="appraisal_type_id"/>
|
||||
<field name="appraisal_notice_id"/>
|
||||
<field name="subject"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="employee_ids" widget="many2many_tags"/>
|
||||
<field name="manager_ids" widget="many2many_tags"/>
|
||||
<field name="hr_department_ids" widget="many2many_tags"/>
|
||||
<field name="stage_config" widget="many2many_tags"/>
|
||||
<field name="employee_rating"/>
|
||||
<field name="employee_points"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="body" widget="html"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Postponed Details">
|
||||
<group>
|
||||
<group>
|
||||
<field name="postponed_by_id" readonly="1"/>
|
||||
<field name="postponed_date" readonly="1"/>
|
||||
<field name="new_start_date" readonly="1"/>
|
||||
<field name="new_end_date" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="postpone_reason" readonly="1" widget="text"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Cancelled Details">
|
||||
<group>
|
||||
<group>
|
||||
<field name="cancelled_by_id" readonly="1"/>
|
||||
<field name="cancelled_date" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cancel_reason" readonly="1" widget="text"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_hr_notice_appraisal_list" model="ir.ui.view">
|
||||
<field name="name">hr.notice.appraisal.list</field>
|
||||
<field name="model">hr.notice.appraisal</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="seq"/>
|
||||
<field name="subject"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="state"
|
||||
widget="badge"
|
||||
decoration-success="state == 'sent'"
|
||||
decoration-warning="state == 'postponed'"
|
||||
decoration-danger="state == 'cancelled'"
|
||||
decoration-muted="state == 'draft'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_hr_notice_appraisal" model="ir.actions.act_window">
|
||||
<field name="name">Performance Cycle Notification</field>
|
||||
<field name="res_model">hr.notice.appraisal</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_hr_notice_appraisal"
|
||||
name="Performance Cycle Notification"
|
||||
parent="menu_employee_appraisal_root"
|
||||
action="action_hr_notice_appraisal"
|
||||
sequence="01"/>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record id="view_employee_stage_conf_form" model="ir.ui.view">
|
||||
<field name="name">employee.stage.config.form</field>
|
||||
<field name="model">employee.stage.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Employee Appraisal Period">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="seq" invisible="0"/>
|
||||
<field name="name"/>
|
||||
<field name="color" widget="color_picker"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_employee_appraisal_period_tree" model="ir.ui.view">
|
||||
<field name="name">employee.stage.config.tree</field>
|
||||
<field name="model">employee.stage.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Employee Appraisal Period">
|
||||
<field name="seq" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="color" widget="color_picker"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_employee_stage_confr" model="ir.actions.act_window">
|
||||
<field name="name">Employee Stage Configuration</field>
|
||||
<field name="res_model">employee.stage.config</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<menuitem id="menu_employee_stage_confr"
|
||||
name="Employee Stage Configuration"
|
||||
parent="configuration_id_employee"
|
||||
action="action_employee_stage_confr"
|
||||
sequence="20"/>
|
||||
</data>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue