#fix: Employee Performance Management Module and few HRMS bugs
This commit is contained in:
parent
a8570dea30
commit
adc4733e15
|
|
@ -5,7 +5,7 @@
|
|||
<field name="name">bench.management.line.list</field>
|
||||
<field name="model">bench.management.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Bench Management">
|
||||
<list create="0" string="Bench Management">
|
||||
<field name="employee_id"/>
|
||||
<field name="job_id"/>
|
||||
<field name="status"/>
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
<field name="name">bench.management.line.form</field>
|
||||
<field name="model">bench.management.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Bench Management">
|
||||
<form create="0" string="Bench Management">
|
||||
<sheet>
|
||||
|
||||
<group>
|
||||
|
|
@ -73,9 +73,7 @@
|
|||
<field name="name">bench.management.line.kanban</field>
|
||||
<field name="model">bench.management.line</field>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<kanban class="o_kanban_mobile">
|
||||
|
||||
<kanban create="0" class="o_kanban_mobile">
|
||||
<field name="employee_id"/>
|
||||
<field name="job_id"/>
|
||||
<field name="status"/>
|
||||
|
|
@ -85,17 +83,12 @@
|
|||
<field name="future_project_count"/>
|
||||
<field name="completed_project_count"/>
|
||||
<field name="project_names_tooltip"/>
|
||||
|
||||
<templates>
|
||||
|
||||
<t t-name="kanban-box">
|
||||
|
||||
<div class="oe_kanban_card oe_kanban_global_click"
|
||||
style="border-radius:16px;border:1px solid #dbe4ee;background:linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);padding:16px;min-height:260px;box-shadow:0 8px 24px rgba(15, 23, 42, 0.06);">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
|
||||
<img t-att-src="'/web/image/hr.employee/' + record.employee_id.raw_value + '/avatar_128'"
|
||||
style="
|
||||
width:42px;
|
||||
|
|
@ -235,7 +228,6 @@
|
|||
</field>
|
||||
</record>
|
||||
<record id="action_bench_management" model="ir.actions.act_window">
|
||||
|
||||
<field name="name">Bench Management</field>
|
||||
<field name="res_model">bench.management.line</field>
|
||||
<field name="view_mode">kanban,list,form</field>
|
||||
|
|
@ -247,6 +239,7 @@
|
|||
<menuitem id="menu_bench_management"
|
||||
name="Employee Bench"
|
||||
parent="hr.menu_hr_root"
|
||||
groups="hr.group_hr_manager"
|
||||
action="action_bench_management"
|
||||
sequence="3"/>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,179 @@
|
|||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
from datetime import date
|
||||
|
||||
|
||||
class HRDisciplinaryAction(models.Model):
|
||||
_name = 'hr.employee.disciplinary'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_description = 'Employee Disciplinary Management'
|
||||
|
||||
active = fields.Boolean(default=True)
|
||||
name = fields.Char('Reference', copy=False, readonly=True, default=lambda x: _('New'))
|
||||
employee_id = fields.Many2one('hr.employee', string="Employee", required=True)
|
||||
company_id = fields.Many2one('res.company', string="Company", required=True, default=lambda self: self.env.company)
|
||||
employee_code = fields.Char(string='Employee Code', related='employee_id.employee_id',tracking=True,required=True)
|
||||
# unit_id = fields.Many2one('unit.master', string="Unit",tracking=True)
|
||||
department_id = fields.Many2one('hr.department', string="Department",tracking=True)
|
||||
designation_id = fields.Many2one('hr.job', string="Designation",tracking=True)
|
||||
doj = fields.Date(string="Date of Joining",tracking=True)
|
||||
referred_by_id = fields.Many2one('res.users', string="Referred By",tracking=True)
|
||||
loss_of_cost = fields.Float(string="Loss of Cost")
|
||||
# employee_section_id = fields.Many2one('section.master',string='Section')
|
||||
disciplinary_complaint_line_ids = fields.One2many('hr.disciplinary.complaint.line','disciplinary_id',string = 'Complaint Lines')
|
||||
disciplinary_action_line_ids = fields.One2many('hr.disciplinary.action.line','disciplinary_id',string = 'Action Lines')
|
||||
state = fields.Selection([
|
||||
('new', 'New'),
|
||||
('submitted', 'Submitted'),
|
||||
('pending', 'Pending'),
|
||||
('closed', 'Closed'),
|
||||
('cancel', 'Cancel')
|
||||
], default='new',tracking=True,string='State')
|
||||
complaint_name = fields.Text('Complaint', compute='_compute_complaint_name', store=True)
|
||||
name_1 = fields.Char('Name')
|
||||
disciplinary_id = fields.Many2one('hr.employee.disciplinary', string="Disciplinary")
|
||||
complaint_date = fields.Date('Complaint Date')
|
||||
language_id = fields.Many2one('res.lang', 'Language')
|
||||
complaint_type_id = fields.Many2one('disciplinary.complaint.type', string="Complaint Type")
|
||||
mistake_type_id = fields.Many2one('disciplinary.mistake.type', string="Mistake Type", required=True)
|
||||
complaint = fields.Char(string='Complaints')
|
||||
employee_id_2 = fields.Many2one('hr.employee', string='Employee')
|
||||
related_record_count = fields.Integer(string="Disciplinary Action Records Count", compute="_compute_related_record_count")
|
||||
# general_cat = fields.Many2one('general.category', string="General Category", tracking=True)
|
||||
# cat_id = fields.Many2one('hr.category','Category')
|
||||
occurrences = fields.Integer('Occurrences', store=True)
|
||||
severe = fields.Char('Severe')
|
||||
major = fields.Char('Major')
|
||||
less_major = fields.Char('Less Major')
|
||||
negligible = fields.Char('Negligible')
|
||||
normal = fields.Char('Normal')
|
||||
total_mistakes = fields.Char('Total Mistakes')
|
||||
memo = fields.Char('Memo')
|
||||
explanation = fields.Char('Explanation')
|
||||
show_cause = fields.Char('Show Cause')
|
||||
charge_sheet = fields.Char('Charge Sheet')
|
||||
warning = fields.Char('Warning')
|
||||
enquiry_notice = fields.Char('Enquiry Notice')
|
||||
recovery_order = fields.Char('Recovery_ Order')
|
||||
stoppage_of_increment = fields.Char('Stoppage Of Increment')
|
||||
demotion = fields.Char('Demotion')
|
||||
total_actions = fields.Char('Total Actions')
|
||||
normal_action = fields.Char('Normal Actions')
|
||||
suspension = fields.Char('Suspension')
|
||||
total_cost = fields.Float('Total Cost')
|
||||
|
||||
@api.depends('employee_id')
|
||||
def _compute_related_record_count(self):
|
||||
for record in self:
|
||||
record.related_record_count = self.env['hr.employee.disciplinary'].search_count([('employee_id', '=', record.employee_id.id)])
|
||||
|
||||
def action_open_related_records(self):
|
||||
return {
|
||||
'name': 'Disciplinary Action Records',
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'hr.employee.disciplinary',
|
||||
'view_mode': 'list',
|
||||
'domain': [('employee_id', '=', self.employee_id.id)],
|
||||
'context': {'default_employee_id': self.employee_id.id},
|
||||
}
|
||||
|
||||
@api.depends('disciplinary_complaint_line_ids.complaint')
|
||||
def _compute_complaint_name(self):
|
||||
for record in self:
|
||||
complaints = record.disciplinary_complaint_line_ids.mapped('complaint')
|
||||
record.complaint_name = "\n".join(filter(None, complaints))
|
||||
|
||||
def action_set_submitted(self):
|
||||
self.state = 'submitted'
|
||||
|
||||
def action_set_pending(self):
|
||||
self.state = 'pending'
|
||||
|
||||
def action_set_closed(self):
|
||||
self.state = 'closed'
|
||||
|
||||
def action_set_cancel(self):
|
||||
self.state = 'cancel'
|
||||
|
||||
def action_reset_to_new(self):
|
||||
self.state = 'new'
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if not vals.get('name') or vals['name'] == _('New'):
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('hr.employee.sequence') or _('New')
|
||||
return super().create(vals_list)
|
||||
|
||||
@api.onchange('employee_id')
|
||||
def _onchange_employee_id(self):
|
||||
for rec in self:
|
||||
if rec.employee_id:
|
||||
rec.employee_code = rec.employee_id.employee_id or ''
|
||||
rec.department_id = rec.employee_id.department_id.id
|
||||
rec.designation_id = rec.employee_id.job_id.id
|
||||
rec.doj = rec.employee_id.doj
|
||||
rec.company_id = rec.employee_id.company_id.id
|
||||
# rec.unit_id = rec.employee_id.unit_name_hr.id if rec.employee_id.unit_name_hr else False
|
||||
# rec.employee_section_id = rec.employee_id.section_name_hr.id if rec.employee_id.section_name_hr else False
|
||||
else:
|
||||
rec.employee_code = False
|
||||
rec.department_id = False
|
||||
rec.designation_id = False
|
||||
rec.doj = False
|
||||
|
||||
|
||||
class DisciplinaryComplaintLine(models.Model):
|
||||
_name = 'hr.disciplinary.complaint.line'
|
||||
_description = 'Disciplinary Complaint Line'
|
||||
|
||||
name = fields.Char('Name')
|
||||
disciplinary_id = fields.Many2one('hr.employee.disciplinary',string="Disciplinary")
|
||||
complaint_date = fields.Date('Complaint Date')
|
||||
language_id = fields.Many2one('res.lang','Language')
|
||||
complaint_type_id = fields.Many2one('disciplinary.complaint.type',string="Complaint Type")
|
||||
mistake_type_id = fields.Many2one('disciplinary.mistake.type',string="Mistake Type")
|
||||
complaint = fields.Char(string='Complaints')
|
||||
employee_id = fields.Many2one('hr.employee', string='Employee')
|
||||
|
||||
|
||||
|
||||
|
||||
class DisciplinaryActionLine(models.Model):
|
||||
_name = 'hr.disciplinary.action.line'
|
||||
_description = 'Disciplinary Action Line'
|
||||
|
||||
name = fields.Char('Name')
|
||||
disciplinary_id = fields.Many2one('hr.employee.disciplinary',string="Disciplinary")
|
||||
action_taken_date = fields.Date('Action On')
|
||||
action_type_id = fields.Many2one('disciplinary.action.type',string="Action Type")
|
||||
action = fields.Char(string='Description')
|
||||
action_name = fields.Char('ActionName')
|
||||
related_complaint_id = fields.Many2one('hr.disciplinary.complaint.line', string="Related Complaint",
|
||||
domain="[('disciplinary_id', '=', disciplinary_id)]")
|
||||
employee_id = fields.Many2one('hr.employee', string='Employee')
|
||||
|
||||
@api.constrains('action_taken_date')
|
||||
def _check_action_taken_date(self):
|
||||
for record in self:
|
||||
if record.action_taken_date and record.action_taken_date > date.today():
|
||||
raise ValidationError("The Action On date cannot be in the future.")
|
||||
|
||||
|
||||
class DisciplinaryActionType(models.Model):
|
||||
_name = 'disciplinary.action.type'
|
||||
_description = 'Action Type'
|
||||
|
||||
name = fields.Char('Name', required=True)
|
||||
|
||||
class DisciplinaryComplaintType(models.Model):
|
||||
_name = 'disciplinary.complaint.type'
|
||||
_description = 'Complaint Type'
|
||||
|
||||
name = fields.Char('Name', required=True)
|
||||
|
||||
class DisciplinaryMistakeType(models.Model):
|
||||
_name = 'disciplinary.mistake.type'
|
||||
_description = 'Mistake Type'
|
||||
|
||||
name = fields.Char('Name', required=True)
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="view_disciplinary_complaint_type_list" model="ir.ui.view">
|
||||
<field name="name">disciplinary.complaint.type</field>
|
||||
<field name="model">disciplinary.complaint.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_disciplinary_complaint_type_form" model="ir.ui.view">
|
||||
<field name="name">disciplinary.complaint.type.form</field>
|
||||
<field name="model">disciplinary.complaint.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_disciplinary_complaint_type" model="ir.actions.act_window">
|
||||
<field name="name">Employee Disciplinary Complaint Type</field>
|
||||
<field name="res_model">disciplinary.complaint.type</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_view_disciplinary_complaint"
|
||||
name="Disciplinary Complaints"
|
||||
action="action_disciplinary_complaint_type"
|
||||
parent="menu_employee_disciplinary_root"
|
||||
sequence="19"/>
|
||||
|
||||
|
||||
<record id="view_employee_disciplinary_complaint_line_list" model="ir.ui.view">
|
||||
<field name="name">hr.disciplinary.action.line</field>
|
||||
<field name="model">hr.disciplinary.action.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_employee_disciplinary_complaint_line_form" model="ir.ui.view">
|
||||
<field name="name">hr.disciplinary.action.line.form</field>
|
||||
<field name="model">hr.disciplinary.action.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" />
|
||||
<field name="disciplinary_id" />
|
||||
<field name="action_taken_date" />
|
||||
<field name="action_type_id" />
|
||||
<field name="action" />
|
||||
<field name="related_complaint_id" />
|
||||
<field name="employee_id" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_employee_disciplinary_complaint_line" model="ir.actions.act_window">
|
||||
<field name="name">Employee Disciplinary Action</field>
|
||||
<field name="res_model">hr.disciplinary.action.line</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_view_employee__disciplinary_complaint"
|
||||
name="Employee Disciplinary Complaints"
|
||||
action="action_employee_disciplinary_complaint_line"
|
||||
parent="menu_employee_disciplinary_root"
|
||||
sequence="20"/>
|
||||
|
||||
|
||||
|
||||
<record id="view_disciplinary_action_type_list" model="ir.ui.view">
|
||||
<field name="name">disciplinary.action.type</field>
|
||||
<field name="model">disciplinary.action.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_disciplinary_action_type_form" model="ir.ui.view">
|
||||
<field name="name">disciplinary.action.type.form</field>
|
||||
<field name="model">disciplinary.action.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_disciplinary_action_type" model="ir.actions.act_window">
|
||||
<field name="name">Employee Disciplinary Action Type</field>
|
||||
<field name="res_model">disciplinary.action.type</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_view_disciplinary_action_type"
|
||||
name="Disciplinary Action Type"
|
||||
action="action_disciplinary_action_type"
|
||||
parent="menu_employee_disciplinary_root"
|
||||
sequence="21"/>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
<odoo>
|
||||
<!-- Disciplinary Form View -->
|
||||
<record id="view_hr_employee_disciplinary_form" model="ir.ui.view">
|
||||
<field name="name">employee.disciplinary.form</field>
|
||||
<field name="model">hr.employee.disciplinary</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Employee Disciplinary">
|
||||
<header>
|
||||
|
||||
<button name="action_set_submitted"
|
||||
type="object"
|
||||
string="Submit"
|
||||
class="btn-primary"
|
||||
invisible="state != 'new'"/>
|
||||
|
||||
<button name="action_set_pending"
|
||||
type="object"
|
||||
string="Pending"
|
||||
class="btn-warning"
|
||||
invisible="state != 'submitted'"/>
|
||||
|
||||
<button name="action_set_closed"
|
||||
type="object"
|
||||
string="Closed"
|
||||
class="btn-success"
|
||||
invisible="state != 'pending'"/>
|
||||
|
||||
<button name="action_set_cancel" type="object" string="Cancel"
|
||||
class="btn-danger" invisible="state not in ['new', 'submitted', 'pending']"/>
|
||||
<button name="action_reset_to_new" type="object"
|
||||
string="Reset to New" class="btn-secondary" invisible="state != 'cancel'"/>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="action_open_related_records"
|
||||
type="object"
|
||||
icon="fa-gavel"
|
||||
class="oe_stat_button full-width-button"
|
||||
string="Disciplinary">
|
||||
<field name="related_record_count" widget="statinfo"/>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
<field name="name" readonly="1"/>
|
||||
</h3>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="employee_code"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="designation_id"/>
|
||||
<field name="doj"/>
|
||||
<!-- <field name="general_cat"/>-->
|
||||
<field name="referred_by_id"/>
|
||||
<!-- <field name="occurrences"/>-->
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id"/>
|
||||
<!-- <field name="unit_id"/>-->
|
||||
<field name="department_id"/>
|
||||
<!-- <field name="employee_section_id"/>-->
|
||||
<field name="loss_of_cost"/>
|
||||
<!-- <field name="cat_id"/>-->
|
||||
<field name="total_cost"/>
|
||||
|
||||
</group>
|
||||
</group>
|
||||
<group string="Complaints" colspan="2">
|
||||
<group colspan="1">
|
||||
<field name="complaint_date"/>
|
||||
<field name="language_id"/>
|
||||
<field name="complaint_type_id"/>
|
||||
|
||||
</group>
|
||||
<group colspan="1">
|
||||
<field name="mistake_type_id"/>
|
||||
<field name="complaint"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<!-- <page name="'complaints" string = "Complaints">-->
|
||||
<!-- <field name="disciplinary_complaint_line_ids">-->
|
||||
<!-- <list string="complaints" editable="bottom">-->
|
||||
<field name="name" column_invisible="1"/>
|
||||
<field name="complaint_date"/>
|
||||
<field name="language_id"/>
|
||||
<field name="complaint_type_id"/>
|
||||
<field name="mistake_type_id"/>
|
||||
<field name="complaint"/>
|
||||
<field name="disciplinary_id" column_invisible="1"/>
|
||||
<field name="employee_id" column_invisible="1"/>
|
||||
<!-- </list>-->
|
||||
<!-- </field>-->
|
||||
|
||||
<!-- </page>-->
|
||||
<page name="'actions" string="Actions">
|
||||
<field name="disciplinary_action_line_ids">
|
||||
<list string="Action Lines" editable="bottom">
|
||||
<field name="name" column_invisible="1"/>
|
||||
<field name="action_name"/>
|
||||
<!-- <field name="action_taken_date"/>-->
|
||||
<field name="action_taken_date"
|
||||
context="{'max_date': time.strftime('%Y-%m-%d')}"/>
|
||||
<field name="action_type_id"/>
|
||||
<field name="action"/>
|
||||
<field name="disciplinary_id" column_invisible="1"/>
|
||||
<field name="employee_id" column_invisible="1"/>
|
||||
|
||||
</list>
|
||||
</field>
|
||||
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<!-- list View for Employee Disciplinary -->
|
||||
<record id="view_hr_employee_disciplinary_list" model="ir.ui.view">
|
||||
<field name="name">hr.employee.disciplinary.list</field>
|
||||
<field name="model">hr.employee.disciplinary</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Employee Disciplinary">
|
||||
<field name="name"/>
|
||||
<field name="employee_id" string="Employee"/>
|
||||
<field name="designation_id" string="Designation"/>
|
||||
<field name="doj" string="Date of Joining"/>
|
||||
<field name="company_id" string="Company"/>
|
||||
<!-- <field name="unit_id" string="Unit"/>-->
|
||||
<field name="department_id" string="Department"/>
|
||||
<field name="state"
|
||||
widget="badge"
|
||||
decoration-primary="state == 'new'"
|
||||
decoration-warning="state == 'submitted'"
|
||||
decoration-info="state == 'pending'"
|
||||
decoration-success="state == 'closed'"
|
||||
decoration-danger="state == 'cancel'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_hr_employee_disciplinary_search" model="ir.ui.view">
|
||||
<field name="name">hr.employee.disciplinary.search</field>
|
||||
<field name="model">hr.employee.disciplinary</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Employee Disciplinary">
|
||||
<field name="employee_id" string="Employee"/>
|
||||
<field name="employee_code" string="Employee Code"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_hr_employee_disciplinary" model="ir.actions.act_window">
|
||||
<field name="name">Employee Disciplinary</field>
|
||||
<field name="res_model">hr.employee.disciplinary</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="search_view_id" ref="view_hr_employee_disciplinary_search"/>
|
||||
</record>
|
||||
|
||||
<!-- <menuitem id="menu_employee_disciplinary_root" name="Employee Disciplinary" sequence="15" parent="hr.menu_hr_root"/>-->
|
||||
<!-- <menuitem id="menu_employee_disciplinary" name="Employee Disciplinary"-->
|
||||
<!-- parent="menu_employee_disciplinary_root"-->
|
||||
<!-- action="action_hr_employee_disciplinary"-->
|
||||
<!-- sequence="10"/>-->
|
||||
|
||||
</odoo>
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
import calendar
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
import calendar
|
||||
|
||||
|
||||
class PayrollPeriod(models.Model):
|
||||
class PayrollPeriod(models.Model):
|
||||
_name = 'payroll.period'
|
||||
_description = 'Payroll Period'
|
||||
_rec_name = 'name'
|
||||
_order = 'id desc'
|
||||
_sql_constraints = [
|
||||
('unique_name', 'unique(name)', 'The name must be unique.')
|
||||
]
|
||||
|
|
@ -14,22 +15,22 @@ class PayrollPeriod(models.Model):
|
|||
from_date = fields.Date(string="From Date", required=True)
|
||||
to_date = fields.Date(string="To Date", required=True)
|
||||
name = fields.Char(string="Name", required=True)
|
||||
period_line_ids = fields.One2many('payroll.period.line', 'period_id', string="Monthly Periods")
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
periods = super().create(vals_list)
|
||||
active_investment_types = self.env['it.investment.type'].search([('active', '=', True)])
|
||||
if active_investment_types:
|
||||
active_investment_types.write({
|
||||
'period_ids': [(4, period.id) for period in periods],
|
||||
})
|
||||
return periods
|
||||
|
||||
@api.onchange('from_date', 'to_date')
|
||||
def onchange_from_to_date(self):
|
||||
for rec in self:
|
||||
if rec.from_date and rec.to_date:
|
||||
period_line_ids = fields.One2many('payroll.period.line', 'period_id', string="Monthly Periods")
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
periods = super().create(vals_list)
|
||||
active_investment_types = self.env['it.investment.type'].search([('active', '=', True)])
|
||||
if active_investment_types:
|
||||
active_investment_types.write({
|
||||
'period_ids': [(4, period.id) for period in periods],
|
||||
})
|
||||
return periods
|
||||
|
||||
@api.onchange('from_date', 'to_date')
|
||||
def onchange_from_to_date(self):
|
||||
for rec in self:
|
||||
if rec.from_date and rec.to_date:
|
||||
rec.name = f"{rec.from_date.year}-{rec.to_date.year}"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@
|
|||
<field name="payslip_count" readonly="1"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button string="Close"
|
||||
special="cancel"
|
||||
class="btn-secondary"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
'data': [
|
||||
'security/hr_resignation_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/resignation_groups.xml',
|
||||
'data/data.xml',
|
||||
'data/ir_sequence_data.xml',
|
||||
'data/ir_cron_data.xml',
|
||||
|
|
|
|||
|
|
@ -167,8 +167,33 @@ class HrResignation(models.Model):
|
|||
admin_checklist_submitted = fields.Boolean(tracking=True)
|
||||
hr_checklist_submitted = fields.Boolean(tracking=True)
|
||||
|
||||
manager_checklist_status = fields.Selection([('pending', 'Pending'),('completed', 'Completed')], compute='_compute_checklist_status')
|
||||
it_checklist_status = fields.Selection([('pending', 'Pending'),('completed', 'Completed')], compute='_compute_checklist_status')
|
||||
finance_checklist_status = fields.Selection([('pending', 'Pending'),('completed', 'Completed') ], compute='_compute_checklist_status')
|
||||
admin_checklist_status = fields.Selection([('pending', 'Pending'),('completed', 'Completed')], compute='_compute_checklist_status')
|
||||
hr_checklist_status = fields.Selection([('pending', 'Pending'),('completed', 'Completed')], compute='_compute_checklist_status')
|
||||
|
||||
relieving_documents = fields.Many2many('ir.attachment')
|
||||
applied_date = fields.Date(string="Applied Date",default=fields.Date.context_today,readonly=True,tracking=True)
|
||||
|
||||
@api.depends('manager_checklist_submitted','it_checklist_submitted','finance_checklist_submitted','admin_checklist_submitted', 'hr_checklist_submitted')
|
||||
def _compute_checklist_status(self):
|
||||
for rec in self:
|
||||
rec.manager_checklist_status = (
|
||||
'completed' if rec.manager_checklist_submitted else 'pending'
|
||||
)
|
||||
rec.it_checklist_status = (
|
||||
'completed' if rec.it_checklist_submitted else 'pending'
|
||||
)
|
||||
rec.finance_checklist_status = (
|
||||
'completed' if rec.finance_checklist_submitted else 'pending'
|
||||
)
|
||||
rec.admin_checklist_status = (
|
||||
'completed' if rec.admin_checklist_submitted else 'pending'
|
||||
)
|
||||
rec.hr_checklist_status = (
|
||||
'completed' if rec.hr_checklist_submitted else 'pending'
|
||||
)
|
||||
|
||||
@api.depends('employee_id')
|
||||
def _compute_user_rights(self):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<odoo>
|
||||
<record model="ir.module.category" id="module_resignation_management_group">
|
||||
<field name="name">Resignation Management</field>
|
||||
<field name="sequence">41</field>
|
||||
</record>
|
||||
<record id="group_resignation_user" model="res.groups">
|
||||
<field name="name">Resignation User</field>
|
||||
<field name="category_id" ref="module_resignation_management_group"/>
|
||||
</record>
|
||||
|
||||
<record id="group_resignation_manager" model="res.groups">
|
||||
<field name="name">Resignation Manager</field>
|
||||
<field name="category_id" ref="module_resignation_management_group"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -150,6 +150,7 @@
|
|||
<field name="employee_id"
|
||||
readonly="change_employee == False or state != 'draft'"/>
|
||||
<field name="department_id"/>
|
||||
<field name="applied_date"/>
|
||||
<field name="employee_contract" invisible="state == 'draft'"/>
|
||||
<field name="emp_responded" readonly="1" force_save="1" invisible="resignation_type != 'abosconded'"/>
|
||||
<field name="show_withdraw" invisible="not is_hr"/>
|
||||
|
|
@ -173,12 +174,30 @@
|
|||
<field name="reason"
|
||||
readonly="state != 'draft'"/>
|
||||
</group>
|
||||
<!-- <group string="Checklist Submission Status">-->
|
||||
<!-- <field name="manager_checklist_submitted" string="Manager" readonly="1" force_save="1"/>-->
|
||||
<!-- <field name="it_checklist_submitted" string="IT Manager" readonly="1" force_save="1"/>-->
|
||||
<!-- <field name="finance_checklist_submitted" string="Finance" readonly="1" force_save="1"/>-->
|
||||
<!-- <field name="admin_checklist_submitted" string="Admin" readonly="1" force_save="1"/>-->
|
||||
<!-- <field name="hr_checklist_submitted" string="HR" readonly="1" force_save="1" invisible="not is_hr or normal_resignation_status not in ['process_relieving_documents','final_clearance']"/>-->
|
||||
<!-- </group>-->
|
||||
<group string="Checklist Submission Status">
|
||||
<field name="manager_checklist_submitted" string="Manager" readonly="1" force_save="1"/>
|
||||
<field name="it_checklist_submitted" string="IT Manager" readonly="1" force_save="1"/>
|
||||
<field name="finance_checklist_submitted" string="Finance" readonly="1" force_save="1"/>
|
||||
<field name="admin_checklist_submitted" string="Admin" readonly="1" force_save="1"/>
|
||||
<field name="hr_checklist_submitted" string="HR" readonly="1" force_save="1" invisible="not is_hr or normal_resignation_status not in ['process_relieving_documents','final_clearance']"/>
|
||||
<field name="manager_checklist_status" string="Manager" widget="badge"
|
||||
decoration-success="manager_checklist_status == 'completed'"
|
||||
decoration-warning="manager_checklist_status == 'pending'"/>
|
||||
<field name="it_checklist_status" string="IT Manager" widget="badge"
|
||||
decoration-success="it_checklist_status == 'completed'"
|
||||
decoration-warning="it_checklist_status == 'pending'"/>
|
||||
<field name="finance_checklist_status" string="Finance" widget="badge"
|
||||
decoration-success="finance_checklist_status == 'completed'"
|
||||
decoration-warning="finance_checklist_status == 'pending'"/>
|
||||
<field name="admin_checklist_status" string="Admin" widget="badge"
|
||||
decoration-success="admin_checklist_status == 'completed'"
|
||||
decoration-warning="admin_checklist_status == 'pending'"/>
|
||||
<field name="hr_checklist_status" string="HR" widget="badge"
|
||||
decoration-success="hr_checklist_status == 'completed'"
|
||||
decoration-warning="hr_checklist_status == 'pending'"
|
||||
invisible="not is_hr or normal_resignation_status not in ['process_relieving_documents','final_clearance']"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
|
|
@ -186,7 +205,8 @@
|
|||
<group>
|
||||
<field name="emp_comments" readonly="not is_emp" string="Employee"/>
|
||||
<field name="manager_comments" readonly="not is_manager" string="Manager"/>
|
||||
<field name="finance_manager_comments" readonly="not is_finance_manager" string="Finance Manager"/>
|
||||
<field name="finance_manager_comments" readonly="not is_finance_manager"
|
||||
string="Finance Manager"/>
|
||||
<field name="it_manager_comments" readonly="not is_it_manager" string="IT Manager"/>
|
||||
<field name="admin_comments" readonly="not is_admin" string="Admin"/>
|
||||
<field name="hr_comments" readonly="not is_hr" string="HR"/>
|
||||
|
|
@ -387,7 +407,7 @@
|
|||
<!-- Menu item for Approved Resignation -->
|
||||
<menuitem id="hr_resignation_menu_approved_request"
|
||||
parent="hr_resignation_menu_root"
|
||||
name="Approved Resignation"
|
||||
name="Resignation Status"
|
||||
action="hr_resignation_approved_action"
|
||||
groups="hr.group_hr_user"
|
||||
sequence="4"/>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_hr_resignation_configurations" name="Configurations" parent="hr_resignation_menu_root" sequence="100"/>
|
||||
<menuitem id="menu_hr_resignation_configurations" name="Configurations" groups="hr_resignation.group_resignation_manager" parent="hr_resignation_menu_root" sequence="100"/>
|
||||
<menuitem id="menu_pre_resignation_root" name="Pre-Resignation" parent="menu_hr_resignation_configurations" sequence="100"/>
|
||||
|
||||
<menuitem id="menu_pre_resignation_requirements" name="Requirements Proceedings"
|
||||
|
|
|
|||
|
|
@ -109,9 +109,27 @@
|
|||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.hrms-icon-button.primary {
|
||||
/*.hrms-icon-button.primary {*/
|
||||
/* background: #16a34a;*/
|
||||
/* border-color: #22c55e;*/
|
||||
/*}*/
|
||||
|
||||
.hrms-icon-button.checkin {
|
||||
background: #16a34a;
|
||||
border-color: #22c55e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.hrms-icon-button.checkout {
|
||||
background: #dc2626;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.hrms-icon-button.checkout:hover {
|
||||
background: #b91c1c;
|
||||
}
|
||||
|
||||
.hrms-icon-button.checkin:hover {
|
||||
background: #15803d;
|
||||
}
|
||||
|
||||
.hrms-filter-box {
|
||||
|
|
|
|||
|
|
@ -292,12 +292,15 @@ class HrmsEmployeeDashboard extends Component {
|
|||
}
|
||||
|
||||
|
||||
// raiseHelpdeskTicket() {
|
||||
// window.open(
|
||||
// '/helpdesk/new',
|
||||
// 'helpdesk',
|
||||
// 'width=1200,height=800,resizable=yes,scrollbars=yes'
|
||||
// );
|
||||
// }
|
||||
raiseHelpdeskTicket() {
|
||||
window.open(
|
||||
'/helpdesk/new',
|
||||
'helpdesk',
|
||||
'width=1200,height=800,resizable=yes,scrollbars=yes'
|
||||
);
|
||||
window.open('/helpdesk/new', '_blank');
|
||||
}
|
||||
|
||||
async toggleAttendance() {
|
||||
|
|
@ -309,6 +312,9 @@ class HrmsEmployeeDashboard extends Component {
|
|||
}
|
||||
this.notification.add(response.message, { type: "success" });
|
||||
await this.loadData();
|
||||
setTimeout(() =>{
|
||||
window.location.reload();
|
||||
}, 500);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.notification.add("Unable to update attendance", { type: "danger" });
|
||||
|
|
|
|||
|
|
@ -27,10 +27,21 @@
|
|||
</div>
|
||||
<div class="hrms-employee-actions">
|
||||
<div class="hrms-action-buttons">
|
||||
<button class="hrms-icon-button primary" t-on-click="toggleAttendance" t-att-title="statusText">
|
||||
<i t-att-class="state.data.attendance_state === 'checked_in' ? 'fa fa-sign-out' : 'fa fa-sign-in'"/>
|
||||
<!-- <button class="hrms-icon-button primary" t-on-click="toggleAttendance" t-att-title="statusText">-->
|
||||
<!-- <i t-att-class="state.data.attendance_state === 'checked_in' ? 'fa fa-sign-out' : 'fa fa-sign-in'"/>-->
|
||||
<!-- <span t-esc="statusText"/>-->
|
||||
<!-- </button>-->
|
||||
<button
|
||||
t-att-class="'hrms-icon-button ' + (state.data.attendance_state === 'checked_in' ? 'checkout' : 'checkin')"
|
||||
t-on-click="toggleAttendance"
|
||||
t-att-title="statusText">
|
||||
|
||||
<i t-att-class="state.data.attendance_state === 'checked_in'
|
||||
? 'fa fa-sign-out'
|
||||
: 'fa fa-sign-in'"/>
|
||||
|
||||
<span t-esc="statusText"/>
|
||||
</button>
|
||||
</button>
|
||||
<button class="hrms-icon-button" t-on-click="downloadPayslip" title="Download Payslip">
|
||||
<i class="fa fa-download"/>
|
||||
<span>Payslip</span>
|
||||
|
|
|
|||
|
|
@ -13,12 +13,16 @@
|
|||
'depends': ['base', 'hr','hr_employee_extended'],
|
||||
|
||||
'data': [
|
||||
'data/reminder_corn.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/security_groups.xml',
|
||||
'security/performace_record_rules.xml',
|
||||
'views/employee_appraisal.xml',
|
||||
'views/employee_evalutor.xml',
|
||||
'views/employee_template_appraisal.xml',
|
||||
'views/hr_notice_appraisal.xml',
|
||||
'views/stage_config.xml',
|
||||
'views/employee_pip.xml',
|
||||
'Wizard/cancel_wizard_hr.xml',
|
||||
'Wizard/postpone_hr_appraisal.xml',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -2,3 +2,6 @@ from . import employee_appraisal
|
|||
from . import apprasial_conf
|
||||
from . import kpi_kra
|
||||
from . import hr_notice_appraisal
|
||||
from . import employee_pip
|
||||
from . import setting_config
|
||||
from . import hr_head_nofication
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
from odoo import api, fields, models
|
||||
from odoo import api, fields, models,_
|
||||
from odoo.exceptions import ValidationError
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
|
||||
|
||||
class AppraisalYear(models.Model):
|
||||
_name = 'employee.appraisal.year'
|
||||
|
|
@ -9,8 +13,8 @@ class AppraisalYear(models.Model):
|
|||
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')
|
||||
start_month = fields.Date('Starting Month')
|
||||
end_month = fields.Date('End Month')
|
||||
active = fields.Boolean(default=True)
|
||||
year_seq = fields.Integer(string="Sequence")
|
||||
appraisal_type_id = fields.Many2one(
|
||||
|
|
@ -18,6 +22,55 @@ class AppraisalYear(models.Model):
|
|||
string="Appraisal Type"
|
||||
)
|
||||
|
||||
@api.constrains('appraisal_type_id', 'start_month', 'end_month')
|
||||
def _check_appraisal_type(self):
|
||||
for rec in self:
|
||||
if not rec.start_month or not rec.end_month:
|
||||
continue
|
||||
|
||||
if rec.start_month > rec.end_month:
|
||||
raise ValidationError(
|
||||
_("Start Month cannot be greater than End Month.")
|
||||
)
|
||||
|
||||
expected_end = False
|
||||
|
||||
if rec.appraisal_type_id.name == 'Monthly':
|
||||
expected_end = rec.start_month + relativedelta(months=1, days=-1)
|
||||
|
||||
elif rec.appraisal_type_id.name == 'Quarterly':
|
||||
expected_end = rec.start_month + relativedelta(months=3, days=-1)
|
||||
|
||||
elif rec.appraisal_type_id.name == 'Half-yearly':
|
||||
expected_end = rec.start_month + relativedelta(months=6, days=-1)
|
||||
|
||||
elif rec.appraisal_type_id.name == 'Annual':
|
||||
expected_end = rec.start_month + relativedelta(months=12, days=-1)
|
||||
|
||||
if expected_end and rec.end_month != expected_end:
|
||||
raise ValidationError(_(
|
||||
"Invalid period for %s.\nExpected End Date: %s"
|
||||
) % (
|
||||
rec.appraisal_type_id.name,
|
||||
expected_end.strftime('%d/%m/%Y')
|
||||
))
|
||||
|
||||
duplicate = self.search([
|
||||
('id', '!=', rec.id),
|
||||
('appraisal_type_id', '=', rec.appraisal_type_id.id),
|
||||
('start_month', '<=', rec.end_month),
|
||||
('end_month', '>=', rec.start_month),
|
||||
], limit=1)
|
||||
|
||||
if duplicate:
|
||||
raise ValidationError(
|
||||
_("This appraisal period overlaps with existing period: %s")
|
||||
% duplicate.appraisal_name
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
class EmployeeAppraisalType(models.Model):
|
||||
_name = 'employee.appraisal.type'
|
||||
_description = 'Employee Appraisal Type'
|
||||
|
|
@ -36,7 +89,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="Employee Appraisal Evaluator")
|
||||
employee_eva_id = fields.Many2one('hr.employee',string="Manager")
|
||||
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)
|
||||
|
|
@ -69,39 +122,40 @@ class AppraisalTemplate(models.Model):
|
|||
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()
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -20,11 +20,13 @@ 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')
|
||||
managerapp_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')])
|
||||
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')
|
||||
stage_id = fields.Many2one('employee.stage.config', string='Stage')
|
||||
stage_name = fields.Char(related='stage_id.name', store=True)
|
||||
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([
|
||||
|
|
@ -43,13 +45,18 @@ class EmployeeAppraisal(models.Model):
|
|||
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)
|
||||
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")
|
||||
hr_head_remarks = fields.Text(string="HR Head Remarks")
|
||||
finance_head_remarks = fields.Text(string="Finance Head 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_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")
|
||||
|
|
@ -60,13 +67,16 @@ class EmployeeAppraisal(models.Model):
|
|||
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")
|
||||
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)
|
||||
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'),
|
||||
|
|
@ -91,9 +101,9 @@ class EmployeeAppraisal(models.Model):
|
|||
('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_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'),
|
||||
|
|
@ -119,14 +129,73 @@ class EmployeeAppraisal(models.Model):
|
|||
('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")
|
||||
currency_id = fields.Many2one('res.currency',string='Currency',default=lambda self: self.env.company.currency_id.id)
|
||||
current_salary = fields.Monetary(string="Current Salary",related="employee_appraisal_id.contract_id.wage",currency_field='currency_id',store=True,readonly=True,)
|
||||
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)
|
||||
salary_update = fields.Boolean(string="Salary Update",default=False,readonly=True)
|
||||
contract_count = fields.Integer(string="Contracts",compute="_compute_contract_count")
|
||||
template_empl_rating_bool = fields.Boolean('Star Rating')
|
||||
template_empl_point_bool = fields.Boolean('Point Rating')
|
||||
disciplinary_ids = fields.Many2many(
|
||||
'hr.employee.disciplinary',string='Disciplinary Actions',compute='_compute_disciplinary_ids')
|
||||
achievement_summary = fields.Html(string="Achievement Summary")
|
||||
employee_comments = fields.Text(string="Employee Comments")
|
||||
attachment_ids = fields.Many2many(
|
||||
'ir.attachment',
|
||||
'employee_appraisal_attachment_rel',
|
||||
'appraisal_id',
|
||||
'attachment_id',
|
||||
string='Supporting Documents'
|
||||
)
|
||||
stage_color_class = fields.Char(compute="_compute_stage_color_class")
|
||||
invite_pip = fields.Boolean('Invite Pip',default=False)
|
||||
is_manager_reviewer = fields.Boolean(compute="_compute_user_roles",store=False)
|
||||
is_hr_reviewer = fields.Boolean(compute="_compute_user_roles",store=False)
|
||||
is_current_employee = fields.Boolean(compute='_compute_is_current_employee')
|
||||
|
||||
@api.depends('employee_appraisal_id')
|
||||
def _compute_is_current_employee(self):
|
||||
current_employee = self.env.user.employee_id
|
||||
for rec in self:
|
||||
rec.is_current_employee = (
|
||||
rec.employee_appraisal_id == current_employee
|
||||
)
|
||||
|
||||
|
||||
def _compute_user_roles(self):
|
||||
current_user = self.env.user
|
||||
for rec in self:
|
||||
rec.is_manager_reviewer = (
|
||||
rec.managerapp_id.user_id.id == current_user.id
|
||||
)
|
||||
rec.is_hr_reviewer = (
|
||||
rec.hr_apprai_id.user_id.id == current_user.id
|
||||
)
|
||||
|
||||
@api.depends('stage_id')
|
||||
def _compute_stage_color_class(self):
|
||||
for rec in self:
|
||||
if rec.stage_id.colour_seq == 1:
|
||||
rec.stage_color_class = 'success'
|
||||
elif rec.stage_id.colour_seq == 2:
|
||||
rec.stage_color_class = 'info'
|
||||
elif rec.stage_id.colour_seq == 3:
|
||||
rec.stage_color_class = 'warning'
|
||||
elif rec.stage_id.colour_seq == 4:
|
||||
rec.stage_color_class = 'primary'
|
||||
else:
|
||||
rec.stage_color_class = 'danger'
|
||||
|
||||
@api.depends('employee_appraisal_id')
|
||||
def _compute_disciplinary_ids(self):
|
||||
for rec in self:
|
||||
rec.disciplinary_ids = self.env['hr.employee.disciplinary'].search([
|
||||
('employee_id', '=', rec.employee_appraisal_id.id)
|
||||
])
|
||||
|
||||
@api.depends('template_id')
|
||||
def _compute_available_stages(self):
|
||||
|
|
@ -322,11 +391,20 @@ class EmployeeAppraisal(models.Model):
|
|||
else:
|
||||
rec.appraisal_percentage = 0
|
||||
|
||||
@api.depends('manager_ids')
|
||||
def _compute_manager_email(self):
|
||||
# @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('managerapp_id')
|
||||
def _compute_managerapp_id(self):
|
||||
for rec in self:
|
||||
emails = rec.manager_ids.mapped('work_email')
|
||||
rec.manager_email = ",".join(filter(None, emails))
|
||||
rec.manager_email = rec.managerapp_id.work_email or ''
|
||||
|
||||
@api.onchange('employee_appraisal_id')
|
||||
def _onchange_employee_appraisal_id(self):
|
||||
self.managerapp_id = self.employee_appraisal_id.parent_id
|
||||
|
||||
@api.depends('end_date')
|
||||
def _compute_is_readonly(self):
|
||||
|
|
@ -373,44 +451,298 @@ class EmployeeAppraisal(models.Model):
|
|||
@api.depends('current_salary', 'appraisal_amount')
|
||||
def _compute_new_salary(self):
|
||||
for rec in self:
|
||||
rec.new_salary = (
|
||||
rec.current_salary +
|
||||
rec.appraisal_amount
|
||||
)
|
||||
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
|
||||
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)],
|
||||
[('id', 'in', self.available_stage_ids.ids),
|
||||
('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()
|
||||
})
|
||||
def action_create_pip(self):
|
||||
self.ensure_one()
|
||||
|
||||
rec.message_post(
|
||||
body=_(
|
||||
"Finance appraisal approved."
|
||||
)
|
||||
pip = self.env['employee.pip'].create({
|
||||
'employee_id': self.employee_appraisal_id.id,
|
||||
'manager_id': self.managerapp_id.id,
|
||||
'appraisal_id': self.id,
|
||||
'objective':
|
||||
'Improve performance and achieve expected goals.',
|
||||
'timeline': '90',
|
||||
})
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'employee.pip',
|
||||
'res_id': pip.id,
|
||||
'view_mode': 'form',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def _compute_contract_count(self):
|
||||
for rec in self:
|
||||
rec.contract_count = len(rec.employee_appraisal_id.contract_ids)
|
||||
|
||||
def action_view_current_contract(self):
|
||||
self.ensure_one()
|
||||
|
||||
contract = self.employee_appraisal_id.contract_id
|
||||
|
||||
if not contract:
|
||||
return False
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Contract',
|
||||
'res_model': 'hr.contract',
|
||||
'view_mode': 'form',
|
||||
'res_id': contract.id,
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def action_update_contract_salary(self):
|
||||
for rec in self:
|
||||
contract = rec.employee_appraisal_id.contract_id
|
||||
if not contract:
|
||||
raise ValidationError( "No active contract found for employee.")
|
||||
if rec.new_salary <= 0:
|
||||
raise ValidationError("Revised Salary must be greater than zero.")
|
||||
contract.write({
|
||||
'wage': rec.new_salary
|
||||
})
|
||||
rec.salary_update = True
|
||||
|
||||
def action_finance_approve(self):
|
||||
self.ensure_one()
|
||||
|
||||
if not self.finance_remarks:
|
||||
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
|
||||
])
|
||||
)
|
||||
|
||||
body_html = f"""
|
||||
<div>
|
||||
|
||||
<p>Hello,</p>
|
||||
|
||||
<p>
|
||||
Finance review has been completed for the appraisal of
|
||||
<b>{self.employee_appraisal_id.name}</b>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The salary revision details are given below for further approval.
|
||||
</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>Current Salary</b></td>
|
||||
<td>{self.current_salary or 0}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>Appraisal Percentage</b></td>
|
||||
<td>{self.appraisal_percentage or 0}%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>Appraisal Amount</b></td>
|
||||
<td>{self.appraisal_amount or 0}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>Revised Salary</b></td>
|
||||
<td>{self.new_salary or 0}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>Finance Remarks</b></td>
|
||||
<td>{self.finance_remarks or ''}</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>
|
||||
Kindly review and proceed with the next level approval.
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>Regards,</p>
|
||||
<p>Finance Team</p>
|
||||
|
||||
</div>
|
||||
"""
|
||||
|
||||
ctx = {
|
||||
'default_model': 'employee.appraisal.template.config',
|
||||
'default_res_ids': [self.id],
|
||||
'default_composition_mode': 'comment',
|
||||
'default_email_to': email_to,
|
||||
'default_subject': f'Finance Approval - {self.employee_appraisal_id.name}',
|
||||
'default_body': body_html,
|
||||
'move_next_stage': True,
|
||||
'mark_finance_approved': True,
|
||||
}
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'mail.compose.message',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
def action_finance_head(self):
|
||||
self.ensure_one()
|
||||
|
||||
if not self.finance_head_remarks:
|
||||
raise ValidationError(
|
||||
_('Please provide Finance Head Remarks.')
|
||||
)
|
||||
|
||||
email_to = ",".join(
|
||||
filter(None, [
|
||||
self.employee_appraisal_id.work_email,
|
||||
self.managerapp_id.work_email,
|
||||
self.creator_email
|
||||
])
|
||||
)
|
||||
|
||||
body_html = f"""
|
||||
<div>
|
||||
|
||||
<p>Hello,</p>
|
||||
|
||||
<p>
|
||||
Finance Head has completed the appraisal review for
|
||||
<b>{self.employee_appraisal_id.name}</b>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The compensation revision details have been reviewed and approved.
|
||||
</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>Current Salary</b></td>
|
||||
<td>{self.current_salary or 0}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>Appraisal %</b></td>
|
||||
<td>{self.appraisal_percentage or 0}%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>Increment Amount</b></td>
|
||||
<td>{self.appraisal_amount or 0}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>Revised Salary</b></td>
|
||||
<td>{self.new_salary or 0}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>Finance Head Remarks</b></td>
|
||||
<td>{self.finance_head_remarks or ''}</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>
|
||||
Kindly proceed with the next level approval.
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>Regards,</p>
|
||||
<p>Finance Head</p>
|
||||
|
||||
</div>
|
||||
"""
|
||||
|
||||
ctx = {
|
||||
'default_model': 'employee.appraisal.template.config',
|
||||
'default_res_ids': [self.id],
|
||||
'default_composition_mode': 'comment',
|
||||
'default_email_to': email_to,
|
||||
'default_subject': f'Finance Head Approval - {self.employee_appraisal_id.name}',
|
||||
'default_body': body_html,
|
||||
'move_next_stage': True,
|
||||
'mark_finance_head_approved': True,
|
||||
}
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'mail.compose.message',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
def _send_manager_notification_mail(self):
|
||||
self.ensure_one()
|
||||
email_to = self.manager_email
|
||||
|
|
@ -434,7 +766,7 @@ class EmployeeAppraisal(models.Model):
|
|||
</tr>
|
||||
<tr>
|
||||
<td><b>Performance Period</b></td>
|
||||
<td>{self.appraisal_period_id.appraisal_type_id.id or ''}</td>
|
||||
<td>{self.appraisal_period_id.appraisal_name or ''}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
|
|
@ -455,81 +787,94 @@ class EmployeeAppraisal(models.Model):
|
|||
}
|
||||
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 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()
|
||||
if not self.manager_remarks:
|
||||
raise ValidationError("Please give the Manager Remarks")
|
||||
|
||||
manager_email = self.managerapp_id.work_email or ''
|
||||
employee_email = self.employee_appraisal_id.work_email or ''
|
||||
creator_email = self.creator_email or ''
|
||||
|
||||
emails = ",".join(
|
||||
filter(None, [employee_email, creator_email])
|
||||
filter(None, [
|
||||
manager_email,
|
||||
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>
|
||||
<div>
|
||||
<p>Hello Team,</p>
|
||||
|
||||
<td>
|
||||
{self.employee_appraisal_id.name or ''}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Template</b>
|
||||
</td>
|
||||
<p>
|
||||
The employee has completed the self-assessment as part of the performance appraisal process.
|
||||
Your feedback and evaluation are now requested.
|
||||
</p>
|
||||
|
||||
<td>
|
||||
{self.template_id.name or ''}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Performance Period</b>
|
||||
</td>
|
||||
<br/>
|
||||
|
||||
<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>
|
||||
<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>Appraisal Template</b></td>
|
||||
<td>{self.template_id.name or ''}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Performance Period</b></td>
|
||||
<td>{self.appraisal_period_id.appraisal_name or ''}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>
|
||||
Kindly review the employee's self-assessment and provide your feedback,
|
||||
evaluation, and recommendations within the appraisal timeline.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Your valuable input will contribute to the employee's overall performance review.
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>
|
||||
Regards,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Manager Team
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
ctx = {
|
||||
'default_model': 'employee.appraisal.template.config',
|
||||
|
|
@ -549,17 +894,132 @@ class EmployeeAppraisal(models.Model):
|
|||
'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'
|
||||
self.ensure_one()
|
||||
|
||||
if not self.hr_remarks:
|
||||
raise ValidationError ('Please Provide the Remarks')
|
||||
|
||||
email_to = self.managerapp_id.work_email or ''
|
||||
|
||||
body_html = f"""
|
||||
<div>
|
||||
<p>Hello,</p>
|
||||
|
||||
<p>
|
||||
HR evaluation has been completed for the appraisal of
|
||||
<b>{self.employee_appraisal_id.name}</b>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Kindly review the appraisal and take the necessary action.
|
||||
</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>Template</b></td>
|
||||
<td>{self.template_id.name or ''}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<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': email_to,
|
||||
'default_subject': f'HR Evaluation Completed - {self.employee_appraisal_id.name}',
|
||||
'default_body': body_html,
|
||||
'move_hr_next_stage': True,
|
||||
}
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'mail.compose.message',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
def action_head_hr(self):
|
||||
self.ensure_one()
|
||||
|
||||
if not self.hr_head_remarks:
|
||||
raise ValidationError(
|
||||
_('Please provide HR Head Remarks.')
|
||||
)
|
||||
|
||||
email_to = self.created_by_id.work_email or ''
|
||||
|
||||
body_html = f"""
|
||||
<div>
|
||||
<p>Hello,</p>
|
||||
|
||||
<p>
|
||||
HR Head review has been completed for the appraisal of
|
||||
<b>{self.employee_appraisal_id.name}</b>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Kindly proceed with the next level approval.
|
||||
</p>
|
||||
|
||||
<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>HR Head Remarks</b></td>
|
||||
<td>{self.hr_head_remarks or ''}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>Regards,</p>
|
||||
<p>HR Head</p>
|
||||
</div>
|
||||
"""
|
||||
|
||||
ctx = {
|
||||
'default_model': 'employee.appraisal.template.config',
|
||||
'default_res_ids': [self.id],
|
||||
'default_composition_mode': 'comment',
|
||||
'default_email_to': email_to,
|
||||
'default_subject': f'HR Head Approval - {self.employee_appraisal_id.name}',
|
||||
'default_body': body_html,
|
||||
'move_hr_head_next_stage': True,
|
||||
}
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'mail.compose.message',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
def action_send_colleague_feedback(self):
|
||||
for rec in self:
|
||||
|
|
@ -568,6 +1028,7 @@ class EmployeeAppraisal(models.Model):
|
|||
('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),
|
||||
|
|
@ -578,7 +1039,123 @@ class EmployeeAppraisal(models.Model):
|
|||
'colleague_feed_id': emp.id,
|
||||
}))
|
||||
rec.colleague_feed_ids = vals
|
||||
rec.state = 'colleague_manager'
|
||||
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))
|
||||
|
||||
body_html = f"""
|
||||
<div>
|
||||
<p>Hello Team,</p>
|
||||
|
||||
<p>
|
||||
{self.employee_appraisal_id.name} has completed the self-assessment.
|
||||
Please provide your feedback as part of the appraisal process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Your feedback will help in evaluating the employee's overall performance.
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>Regards,</p>
|
||||
<p>{self.employee_appraisal_id.name}</p>
|
||||
</div>
|
||||
"""
|
||||
|
||||
ctx = {
|
||||
'default_model': 'employee.appraisal.template.config',
|
||||
'default_res_ids': [self.id],
|
||||
'default_composition_mode': 'comment',
|
||||
'default_email_to': email_to,
|
||||
'default_subject': f'Colleague Feedback Request - {self.employee_appraisal_id.name}',
|
||||
'default_body': body_html,
|
||||
'mark_colleague_feedback_sent': True,
|
||||
}
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'mail.compose.message',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
def action_initiate_pip(self):
|
||||
self.ensure_one()
|
||||
self.write({'invite_pip': True})
|
||||
|
||||
employee_email = self.employee_appraisal_id.work_email or ''
|
||||
|
||||
body_html = f"""
|
||||
<div>
|
||||
<p>Dear {self.employee_appraisal_id.name},</p>
|
||||
|
||||
<p>
|
||||
Based on the recent performance appraisal review, your overall performance
|
||||
rating indicates that improvement is required in certain areas.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Therefore, you are requested to attend a Performance Improvement Plan (PIP)
|
||||
discussion meeting with Management and HR.
|
||||
</p>
|
||||
|
||||
<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_name or ''}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Overall Rating</b></td>
|
||||
<td>{self.overall_rating or ''}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>
|
||||
During this meeting, we will discuss performance concerns,
|
||||
expectations, improvement objectives, and the Performance
|
||||
Improvement Plan (PIP) timeline.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Kindly acknowledge and attend the meeting as scheduled.
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
<p>Regards,</p>
|
||||
<p>Management Team</p>
|
||||
</div>
|
||||
"""
|
||||
|
||||
ctx = {
|
||||
'default_model': 'employee.appraisal.template.config',
|
||||
'default_res_ids': [self.id],
|
||||
'default_composition_mode': 'comment',
|
||||
'default_email_to': employee_email,
|
||||
'default_subject': 'Performance Improvement Plan (PIP) Meeting Notification',
|
||||
'default_body': body_html,
|
||||
'mark_invite_pip': True,
|
||||
}
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'mail.compose.message',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
@api.onchange('template_id')
|
||||
def _onchange_template_id(self):
|
||||
|
|
@ -624,7 +1201,6 @@ class ColleagueFeedBack(models.Model):
|
|||
submitted_date = fields.Datetime()
|
||||
|
||||
def action_submit_feedback(self):
|
||||
|
||||
for rec in self:
|
||||
rec.write({
|
||||
'state': 'submitted',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class EmployeePIP(models.Model):
|
||||
_name = 'employee.pip'
|
||||
_description = 'Performance Improvement Plan'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_rec_name = 'employee_id'
|
||||
|
||||
name = fields.Char(string="PIP Reference",default=lambda self: _('New'),readonly=True )
|
||||
employee_id = fields.Many2one( 'hr.employee',required=True)
|
||||
manager_id = fields.Many2one('hr.employee',string="Manager")
|
||||
appraisal_id = fields.Many2one('employee.appraisal.template.config',string="Appraisal")
|
||||
objective = fields.Text(string="Improvement Objective",required=True)
|
||||
timeline = fields.Selection([
|
||||
('30', '30 Days'),
|
||||
('60', '60 Days'),
|
||||
('90', '90 Days')
|
||||
], default='30', required=True)
|
||||
start_date = fields.Date(default=fields.Date.today)
|
||||
end_date = fields.Date()
|
||||
review_date = fields.Date()
|
||||
employee_acknowledged = fields.Boolean(string="Employee Acknowledged")
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('running', 'In Progress'),
|
||||
('review', 'Under Review'),
|
||||
('completed', 'Completed'),
|
||||
('failed', 'Failed')
|
||||
], default='draft', tracking=True)
|
||||
task_ids = fields.One2many('employee.pip.task','pip_id',string='Improvement Tasks')
|
||||
progress_percentage = fields.Float(compute='_compute_progress',store=True)
|
||||
remarks = fields.Text()
|
||||
|
||||
@api.depends('task_ids.state')
|
||||
def _compute_progress(self):
|
||||
for rec in self:
|
||||
|
||||
total = len(rec.task_ids)
|
||||
|
||||
completed = len(
|
||||
rec.task_ids.filtered(
|
||||
lambda l: l.state == 'done'
|
||||
)
|
||||
)
|
||||
|
||||
rec.progress_percentage = (
|
||||
(completed / total) * 100
|
||||
) if total else 0
|
||||
|
||||
@api.onchange('timeline', 'start_date')
|
||||
def _onchange_timeline(self):
|
||||
for rec in self:
|
||||
if rec.start_date and rec.timeline:
|
||||
rec.end_date = fields.Date.add(
|
||||
rec.start_date,
|
||||
days=int(rec.timeline)
|
||||
)
|
||||
|
||||
def action_start(self):
|
||||
self.state = 'running'
|
||||
|
||||
def action_review(self):
|
||||
self.state = 'review'
|
||||
|
||||
def action_complete(self):
|
||||
self.state = 'completed'
|
||||
|
||||
def action_fail(self):
|
||||
self.state = 'failed'
|
||||
|
||||
|
||||
|
||||
|
||||
class EmployeePIPTask(models.Model):
|
||||
_name = 'employee.pip.task'
|
||||
_description = 'PIP Task'
|
||||
|
||||
pip_id = fields.Many2one('employee.pip',ondelete='cascade')
|
||||
name = fields.Char(required=True)
|
||||
description = fields.Text()
|
||||
target_date = fields.Date()
|
||||
training_course = fields.Char(string="Suggested Training")
|
||||
state = fields.Selection([
|
||||
('pending', 'Pending'),
|
||||
('progress', 'In Progress'),
|
||||
('done', 'Completed')
|
||||
], default='pending')
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class HrHeadNofication(models.Model):
|
||||
_name = 'hr.head.notification'
|
||||
_description = 'HeadNofication'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
|
||||
@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)
|
||||
name = fields.Char("Subject")
|
||||
appraisal_type_id = fields.Many2one('employee.appraisal.type')
|
||||
appraisal_period_id = fields.Many2one('employee.appraisal.year',
|
||||
domain="[('appraisal_type_id', '=', appraisal_type_id)]")
|
||||
body = fields.Html(string="Notice Body", required=True)
|
||||
start_date = fields.Date()
|
||||
end_date = fields.Date()
|
||||
hr_ids = fields.Many2many('hr.employee', string="HR Team")
|
||||
# hr_employee_domain_ids = fields.Many2many('hr.employee',compute='_compute_hr_employee_domain')
|
||||
stage_config_ids = fields.Many2many('employee.stage.config', string="Stages")
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('sent', 'Sent')
|
||||
], default='draft')
|
||||
seq = fields.Char(string="Reference", readonly=True, copy=False, default="New")
|
||||
|
||||
@api.model
|
||||
def _get_hr_users_domain(self):
|
||||
group = self.env.ref('hrms_employee_appraisal.group_appraisal_hr')
|
||||
if group:
|
||||
return [('groups_id', 'in', [group.id])]
|
||||
return [('id', '=', False)]
|
||||
|
||||
hr_users_ids = fields.Many2many('res.users', string="HR Team", copy=False, domain=_get_hr_users_domain)
|
||||
|
||||
@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)
|
||||
|
||||
|
||||
def action_sent_hr(self):
|
||||
self.ensure_one()
|
||||
|
||||
hr_emails = self.hr_users_ids.mapped('email')
|
||||
email_to = ",".join(filter(None, hr_emails))
|
||||
|
||||
body_html = f"""
|
||||
<div>
|
||||
<p>Hello HR Team,</p>
|
||||
|
||||
<p>{self.body or ''}</p>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="0">
|
||||
<tr>
|
||||
<td><b>Appraisal Type</b></td>
|
||||
<td>{self.appraisal_type_id.name or ''}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Appraisal Period</b></td>
|
||||
<td>{self.appraisal_period_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 initiate the appraisal process.</p>
|
||||
|
||||
<p>Regards,</p>
|
||||
<p>HR Head</p>
|
||||
</div>
|
||||
"""
|
||||
|
||||
ctx = {
|
||||
'default_model': 'hr.head.notification',
|
||||
'default_res_ids': [self.id],
|
||||
'default_composition_mode': 'comment',
|
||||
'default_email_to': email_to,
|
||||
'default_subject': self.name,
|
||||
'default_body': body_html,
|
||||
'mark_hr_notification_sent': True,
|
||||
}
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'mail.compose.message',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ from odoo import models, fields, api, _
|
|||
from odoo.exceptions import ValidationError
|
||||
from random import randint
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class HrNoticeAppraisal(models.Model):
|
||||
_name = 'hr.notice.appraisal'
|
||||
|
|
@ -15,10 +17,11 @@ class HrNoticeAppraisal(models.Model):
|
|||
return self.env.user.employee_id
|
||||
|
||||
hr_employee_id = fields.Many2one('hr.employee', string='Employee', default=_default_employee_get)
|
||||
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)
|
||||
start_date = fields.Datetime(string="Start Date", required=True)
|
||||
end_date = fields.Datetime(string="End Date", required=True)
|
||||
start_date = fields.Date(string="Start Date")
|
||||
end_date = fields.Date(string="End Date")
|
||||
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([
|
||||
|
|
@ -45,36 +48,81 @@ class HrNoticeAppraisal(models.Model):
|
|||
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.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):
|
||||
@api.constrains('start_date', 'end_date','employee_ids','manager_ids','appraisal_notice_id','state')
|
||||
def _check_appraisal_validations(self):
|
||||
for rec in self:
|
||||
if rec.end_date < rec.start_date:
|
||||
raise ValidationError(_("End Date must be greater than Start Date."))
|
||||
if rec.start_date and rec.end_date:
|
||||
if rec.end_date <= rec.start_date:
|
||||
raise ValidationError(
|
||||
_("End Date must be greater than Start Date.")
|
||||
)
|
||||
if rec.state == 'cancelled':
|
||||
continue
|
||||
duplicate_period = self.search([
|
||||
('id', '!=', rec.id),
|
||||
('appraisal_notice_id', '=', rec.appraisal_notice_id.id),
|
||||
('hr_employee_id', '=', rec.hr_employee_id.id),
|
||||
('state', '!=', 'cancelled'),
|
||||
], limit=1)
|
||||
if duplicate_period:
|
||||
raise ValidationError(_(
|
||||
"An appraisal notification already exists for appraisal period '%s'."
|
||||
) % rec.appraisal_notice_id.display_name)
|
||||
|
||||
for employee in rec.employee_ids:
|
||||
duplicate_employee = self.search([
|
||||
('id', '!=', rec.id),
|
||||
('employee_ids', 'in', employee.id),
|
||||
('state', '!=', 'cancelled'),
|
||||
('start_date', '<=', rec.end_date),
|
||||
('end_date', '>=', rec.start_date),
|
||||
], limit=1)
|
||||
_logger.info(
|
||||
"Duplicate Period Records: %s",
|
||||
duplicate_period.ids
|
||||
)
|
||||
if duplicate_employee:
|
||||
raise ValidationError(_(
|
||||
"Employee '%s' is already assigned in another appraisal notification for the selected period."
|
||||
) % employee.name)
|
||||
|
||||
for manager in rec.manager_ids:
|
||||
duplicate_manager = self.search([
|
||||
('id', '!=', rec.id),
|
||||
('manager_ids', 'in', manager.id),
|
||||
('state', '!=', 'cancelled'),
|
||||
('start_date', '<=', rec.end_date),
|
||||
('end_date', '>=', rec.start_date),
|
||||
], limit=1)
|
||||
if duplicate_manager:
|
||||
raise ValidationError(_(
|
||||
"Manager '%s' is already assigned in another appraisal notification for the selected period."
|
||||
) % manager.name)
|
||||
|
||||
@api.onchange('employee_ids')
|
||||
def _onchange_employee_ids(self):
|
||||
|
|
@ -89,45 +137,6 @@ class HrNoticeAppraisal(models.Model):
|
|||
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>
|
||||
|
|
@ -226,6 +235,7 @@ class StageConfig(models.Model):
|
|||
|
||||
name = fields.Char(required=True)
|
||||
seq = fields.Integer(required=True)
|
||||
colour_seq = fields.Integer(required=True)
|
||||
active = fields.Boolean(default=True)
|
||||
color = fields.Integer('Color', default=_get_default_color_stage)
|
||||
|
||||
|
|
@ -240,26 +250,157 @@ class MailComposeMessage(models.TransientModel):
|
|||
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'):
|
||||
template_obj = self.env['employee.appraisal.template']
|
||||
for rec in records:
|
||||
grouped_employees = {}
|
||||
for employee in rec.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', '=', rec.id),
|
||||
('employee_department_id', '=', department_id),
|
||||
], limit=1)
|
||||
if already_exists:
|
||||
continue
|
||||
template_obj.create({
|
||||
'name': rec.subject,
|
||||
'seq': rec.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': rec.id,
|
||||
'start_date': rec.start_date,
|
||||
'end_date': rec.end_date,
|
||||
'appraisal_period_id': rec.appraisal_notice_id.id,
|
||||
'appraisal_period_type_id': rec.appraisal_type_id.id,
|
||||
'template_rating_bool': rec.employee_rating,
|
||||
'template_point_bool': rec.employee_points,
|
||||
'hr_employee_id': rec.hr_employee_id.id,
|
||||
'stage_config_ids': [(6, 0, rec.stage_config.ids)],
|
||||
})
|
||||
rec.write({
|
||||
'state': 'sent'
|
||||
})
|
||||
if (
|
||||
self.env.context.get('mark_appraisal_sent')
|
||||
or self.env.context.get('mark_colleague_feedback_sent')
|
||||
or self.env.context.get('move_hr_next_stage')
|
||||
or self.env.context.get('move_hr_head_next_stage')
|
||||
or self.env.context.get('mark_finance_approved')
|
||||
or self.env.context.get('mark_finance_head_approved')
|
||||
or self.env.context.get('mark_invite_pip')
|
||||
):
|
||||
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'):
|
||||
# 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_colleague_feedback_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'
|
||||
templates = self.env[model].browse(res_ids)
|
||||
appraisal_config_obj = self.env[
|
||||
'employee.appraisal.template.config'
|
||||
]
|
||||
for rec in templates:
|
||||
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,
|
||||
})
|
||||
|
||||
appraisal._onchange_template_id()
|
||||
|
||||
rec.write({
|
||||
'employee_state': 'sent'
|
||||
})
|
||||
|
||||
if self.env.context.get('mark_hr_notification_sent'):
|
||||
records = self.env[model].browse(res_ids)
|
||||
for record in records:
|
||||
for user in record.hr_users_ids:
|
||||
employee = self.env['hr.employee'].search([
|
||||
('user_id', '=', user.id)
|
||||
], limit=1)
|
||||
if not employee:
|
||||
continue
|
||||
already_exists = self.env[
|
||||
'hr.notice.appraisal'
|
||||
].search([
|
||||
('notification_id', '=', record.id),
|
||||
('hr_employee_id', '=', employee.id)
|
||||
], limit=1)
|
||||
if already_exists:
|
||||
continue
|
||||
self.env['hr.notice.appraisal'].create({
|
||||
'notification_id': record.id,
|
||||
'hr_employee_id': employee.id,
|
||||
'subject': record.name,
|
||||
'appraisal_type_id':
|
||||
record.appraisal_type_id.id,
|
||||
'appraisal_notice_id':
|
||||
record.appraisal_period_id.id,
|
||||
'start_date': record.start_date,
|
||||
'end_date': record.end_date,
|
||||
'seq': record.seq,
|
||||
'body': record.body,
|
||||
'stage_config': [
|
||||
(6, 0,
|
||||
record.stage_config_ids.ids)
|
||||
],
|
||||
})
|
||||
|
||||
record.write({
|
||||
'state': 'sent'
|
||||
})
|
||||
|
||||
return res
|
||||
|
||||
return res
|
||||
|
|
@ -373,6 +373,21 @@ class EmployeeAppraisalKPILine(models.Model):
|
|||
('4', '4'),
|
||||
('5', '5'),
|
||||
], string="Stars", copy=False)
|
||||
is_employee_reviewer = fields.Boolean(compute="_compute_user_roles", store=False)
|
||||
is_manager_reviewer = fields.Boolean(compute="_compute_user_roles", store=False)
|
||||
is_hr_reviewer = fields.Boolean(compute="_compute_user_roles", store=False)
|
||||
|
||||
def _compute_user_roles(self):
|
||||
current_user = self.env.user
|
||||
for rec in self:
|
||||
rec.is_employee_reviewer = (
|
||||
rec.kra_line_id.config_id.employee_appraisal_id.user_id.id == current_user.id)
|
||||
rec.is_manager_reviewer= (
|
||||
rec.kra_line_id.config_id.managerapp_id.user_id.id == current_user.id)
|
||||
rec.is_hr_reviewer= (
|
||||
rec.kra_line_id.config_id.hr_apprai_id.user_id.id == current_user.id
|
||||
)
|
||||
|
||||
# self_rating = fields.Selection([
|
||||
# ('0', '0'),
|
||||
# ('1', '1'),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
from odoo import api, fields, models
|
||||
from datetime import date
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
|
||||
appraisal_reminder_days = fields.Integer(
|
||||
string="Appraisal Reminder Before (Days)",
|
||||
config_parameter='hrms_employee_appraisal.appraisal_reminder_days',
|
||||
default=7
|
||||
)
|
||||
|
||||
appraisal_reminder_enabled = fields.Boolean(
|
||||
string="Enable Appraisal Reminders",
|
||||
config_parameter='hrms_employee_appraisal.appraisal_reminder_enabled',
|
||||
default=True
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class EmployeeAppraisal(models.Model):
|
||||
_inherit = 'employee.appraisal.template.config'
|
||||
|
||||
def cron_send_appraisal_reminder(self):
|
||||
|
||||
enabled = self.env['ir.config_parameter'].sudo().get_param(
|
||||
'hrms_employee_appraisal.appraisal_reminder_enabled'
|
||||
)
|
||||
|
||||
if not enabled:
|
||||
return
|
||||
|
||||
reminder_days = int(
|
||||
self.env['ir.config_parameter'].sudo().get_param(
|
||||
'hrms_employee_appraisal.appraisal_reminder_days',
|
||||
7
|
||||
)
|
||||
)
|
||||
|
||||
today = date.today()
|
||||
|
||||
records = self.search([
|
||||
('end_date', '!=', False)
|
||||
])
|
||||
|
||||
for rec in records:
|
||||
|
||||
days_left = (rec.end_date - today).days
|
||||
|
||||
if days_left == reminder_days:
|
||||
|
||||
if rec.employee_appraisal_id.work_email:
|
||||
|
||||
self.env['mail.mail'].sudo().create({
|
||||
'subject': 'Performance Appraisal Reminder',
|
||||
'email_to': rec.employee_appraisal_id.work_email,
|
||||
'body_html': f"""
|
||||
<p>Dear {rec.employee_appraisal_id.name},</p>
|
||||
|
||||
<p>
|
||||
Your appraisal period is ending in
|
||||
<b>{reminder_days}</b> days.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Please complete your self appraisal.
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
<p>Regards,<br/>HR Team</p>
|
||||
"""
|
||||
}).send()
|
||||
|
|
@ -23,7 +23,14 @@ access_appraisal_postpone_wizard,appraisal_postpone_wizard,model_appraisal_postp
|
|||
access_appraisal_cancel_wizard,appraisal.cancel.wizard,model_appraisal_cancel_wizard,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
access_hr_head_notification,hr.head.notification,model_hr_head_notification,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
|
||||
|
||||
|
||||
access_employee_pip,employee.pip,model_employee_pip,base.group_user,1,1,1,1
|
||||
access_employee_pip_task,employee.pip.task,model_employee_pip_task,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
|
@ -0,0 +1,111 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record id="hr_notice_hr_rule" model="ir.rule">
|
||||
<field name="name">HR Notice - HR Access</field>
|
||||
<field name="model_id" ref="model_hr_notice_appraisal"/>
|
||||
<field name="domain_force">
|
||||
[('hr_employee_id.user_id', '=', user.id)]
|
||||
</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_hr'))]"/>
|
||||
</record>
|
||||
<!-- Management Access - HR Notice -->
|
||||
<record id="hr_notice_management_rule" model="ir.rule">
|
||||
<field name="name">HR Notice - Management Access</field>
|
||||
<field name="model_id" ref="model_hr_notice_appraisal"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_management'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="appraisal_template_manager_rule" model="ir.rule">
|
||||
<field name="name">Appraisal Template Manager</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template"/>
|
||||
<field name="domain_force">
|
||||
[('employee_eva_id.user_id', '=', user.id)]
|
||||
</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="appraisal_template_hr_rule" model="ir.rule">
|
||||
<field name="name">Appraisal Template HR</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template"/>
|
||||
<field name="domain_force">
|
||||
[('hr_employee_id.user_id', '=', user.id)]
|
||||
</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_hr'))]"/>
|
||||
</record>
|
||||
<record id="appraisal_template_management_rule" model="ir.rule">
|
||||
<field name="name">Appraisal Template - Management Access</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_management'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="record_rule_employee" model="ir.rule">
|
||||
<field name="name">Employee Appraisal - employee access</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template_config"/>
|
||||
<field name="domain_force">
|
||||
[('employee_appraisal_id.user_id','=', user.id)]
|
||||
</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="record_rule_manager" model="ir.rule">
|
||||
<field name="name">Manager Access</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template_config"/>
|
||||
<field name="domain_force">
|
||||
[('managerapp_id.user_id','=',user.id)]
|
||||
</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_unlink" eval="True"/>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="employee_appraisal_hr_rule" model="ir.rule">
|
||||
<field name="name">Employee Appraisal - HR Access</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template_config"/>
|
||||
<field name="domain_force">
|
||||
[('hr_apprai_id.user_id', '=', user.id)]
|
||||
</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_hr'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="employee_appraisal_hr_head_rule" model="ir.rule">
|
||||
<field name="name">Employee Appraisal - HR Head Access</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template_config"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_hr_head'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="employee_appraisal_finance_rule" model="ir.rule">
|
||||
<field name="name">Employee Appraisal - Finance Access</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template_config"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_finance'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="employee_appraisal_finance_head_rule" model="ir.rule">
|
||||
<field name="name">Employee Appraisal - Finance Head Access</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template_config"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_finance_head'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="employee_appraisal_management_rule" model="ir.rule">
|
||||
<field name="name">Employee Appraisal - Management Access</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template_config"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_management'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="employee_appraisal_management_rule" model="ir.rule">
|
||||
<field name="name">Employee Appraisal - Management Access</field>
|
||||
<field name="model_id" ref="model_employee_appraisal_template_config"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('hrms_employee_appraisal.group_appraisal_management'))]"/>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record model="ir.module.category" id="module_performance_management_group">
|
||||
<field name="name">Performance Management</field>
|
||||
<field name="sequence">40</field>
|
||||
</record>
|
||||
|
||||
<record id="group_appraisal_employee" model="res.groups">
|
||||
<field name="name">Employee</field>
|
||||
<field name="category_id" ref="module_performance_management_group"/>
|
||||
</record>
|
||||
|
||||
<record id="group_appraisal_manager" model="res.groups">
|
||||
<field name="name">Appraisal Manager</field>
|
||||
<field name="category_id" ref="module_performance_management_group"/>
|
||||
</record>
|
||||
|
||||
<record id="group_appraisal_hr" model="res.groups">
|
||||
<field name="name">Appraisal HR</field>
|
||||
<field name="category_id" ref="module_performance_management_group"/>
|
||||
</record>
|
||||
|
||||
<record id="group_appraisal_hr_head" model="res.groups">
|
||||
<field name="name">Appraisal HR Head</field>
|
||||
<field name="category_id" ref="module_performance_management_group"/>
|
||||
</record>
|
||||
|
||||
<record id="group_appraisal_finance" model="res.groups">
|
||||
<field name="name">Appraisal Finance</field>
|
||||
<field name="category_id" ref="module_performance_management_group"/>
|
||||
</record>
|
||||
|
||||
<record id="group_appraisal_finance_head" model="res.groups">
|
||||
<field name="name">Appraisal Finance Head</field>
|
||||
<field name="category_id" ref="module_performance_management_group"/>
|
||||
</record>
|
||||
|
||||
<record id="group_appraisal_management" model="res.groups">
|
||||
<field name="name">Appraisal Management</field>
|
||||
<field name="category_id" ref="module_performance_management_group"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -13,10 +13,31 @@
|
|||
<!-- <field name="performance_evaluator"/>-->
|
||||
<field name="template_id" string="Template"/>
|
||||
<field name="appraisal_period_id" string="Performance Period"/>
|
||||
<!-- <field name="state" widget="badge"/>-->
|
||||
<field name="appraisal_period_id" string="Performance Period"/>
|
||||
<field name="stage_id" widget="badge"
|
||||
decoration-success="stage_color_class == 'success'"
|
||||
decoration-info="stage_color_class == 'info'"
|
||||
decoration-warning="stage_color_class == 'warning'"
|
||||
decoration-primary="stage_color_class == 'primary'"
|
||||
decoration-danger="stage_color_class == 'danger'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_employee_app_search" model="ir.ui.view">
|
||||
<field name="name">employee.app.search</field>
|
||||
<field name="model">employee.appraisal.template.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<searchpanel>
|
||||
<field name="company_id" icon="fa-building"/>
|
||||
<field name="department_appraisal_id" icon="fa-users"/>
|
||||
<field name="stage_id" icon="fa-tasks" select="multi" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</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>
|
||||
|
|
@ -32,23 +53,42 @@
|
|||
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'"/>-->
|
||||
groups="hrms_employee_appraisal.group_appraisal_manager"
|
||||
class="btn-primary" invisible="stage_name != 'COLLEAGUES&MANAGER'"/>
|
||||
<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'"/>-->
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
invisible="stage_name != 'NEW' or not is_current_employee"/>
|
||||
<!-- groups="group_appraisal_employee,group_appraisal_management"-->
|
||||
<!-- -->
|
||||
<!-- class="btn-primary" invisible="stage_name != 'COLLEAGE&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'"/>
|
||||
groups="hrms_employee_appraisal.group_appraisal_hr"
|
||||
class="btn-primary" invisible="stage_name != 'HR'"/>
|
||||
<button name="action_head_hr"
|
||||
string="HR Head Approval" type="object" class="btn-primary"
|
||||
invisible="stage_name != 'HR HEAD'"/>
|
||||
<!-- invisible="state != 'hr_evaluation'"/>-->
|
||||
<button name="action_finance_approve" string="Finance Appraisal"
|
||||
type="object" class="btn-primary" invisible="stage_id.name != 'FINANCE TEAM'"/>
|
||||
type="object" class="btn-primary" invisible="stage_name != 'FINANCE'"/>
|
||||
<button name="action_finance_head" string="Finance Head Approval" type="object"
|
||||
class="btn-primary" invisible="stage_name != 'FINANCE HEAD'"/>
|
||||
<button name="action_create_pip"
|
||||
string="Create PIP"
|
||||
type="object"
|
||||
class="btn-danger"
|
||||
invisible="invite_pip == False or overall_rating not in ('0','1','2')"/>
|
||||
<button name="action_initiate_pip"
|
||||
string="Initiate PIP"
|
||||
type="object"
|
||||
class="btn-danger"
|
||||
invisible="stage_name != 'MANAGEMENT'
|
||||
or overall_rating not in ('0', '1', '2')
|
||||
or invite_pip"/>
|
||||
<!-- invisible="state != 'finance_team'"/>-->
|
||||
<!-- <button name="action_confirm" string="Confirm" type="object"-->
|
||||
<!-- confirm="Do you want to move to next stage?"-->
|
||||
|
|
@ -60,21 +100,38 @@
|
|||
<!-- invisible="state != 'colleague_feedback'"/>-->
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
|
||||
<button name="action_view_current_contract"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-file-text-o">
|
||||
<field name="contract_count"
|
||||
string="Contracts"
|
||||
widget="statinfo"/>
|
||||
</button>
|
||||
</div>
|
||||
<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"/>
|
||||
<field name="employee_appraisal_id" string="Employee" readonly="1"
|
||||
options="{'no_open': True}"/>
|
||||
<field name="job_appraisal_id" string="Current Job Title" readonly="1"
|
||||
options="{'no_open': True}"/>
|
||||
<field name="department_appraisal_id" string="Department" readonly="1"
|
||||
options="{'no_open': True}"/>
|
||||
<!-- <field name="template_id" string="Template"/>-->
|
||||
<!-- <field name="available_stage_ids" invisible="0" widget="many2many_tags"/>-->
|
||||
<field name="appraisal_period_id" string="Performance Period" readonly="1"
|
||||
options="{'no_open': True}"/>
|
||||
<!-- <field name="manager_ids" widget="many2many_tags"/>-->
|
||||
<field name="managerapp_id" readonly="1" options="{'no_open': True}"/>
|
||||
<field name="is_manager_reviewer" invisible="1"/>
|
||||
<field name="manager_remarks" readonly="not is_manager_reviewer"/>
|
||||
<field name="hr_apprai_id" string="HR" readonly="1" options="{'no_open': True}"/>
|
||||
<field name="is_hr_reviewer" invisible="1"/>
|
||||
<field name="hr_remarks" readonly="not is_hr_reviewer"/>
|
||||
|
||||
</group>
|
||||
<group>
|
||||
<field name="image_1920" widget="image" class="oe_avatar" nolabel="1"
|
||||
|
|
@ -82,10 +139,13 @@
|
|||
<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="company_id" string="Company" readonly="1" options="{'no_open': True}"/>
|
||||
<field name="start_date" readonly="1"/>
|
||||
<field name="end_date" readonly="1"/>
|
||||
<field name="template_empl_rating_bool"/>
|
||||
<field name="template_empl_point_bool"/>
|
||||
<field name="template_empl_rating_bool" readonly="1" invisible="1"/>
|
||||
<field name="template_empl_point_bool" readonly="1" invisible="1"/>
|
||||
<field name="hr_head_remarks" placeholder="Enter HR Head Remarks..."
|
||||
invisible="stage_name != 'HR HEAD'"/>
|
||||
</group>
|
||||
<group string="Performance Standards">
|
||||
<div>
|
||||
|
|
@ -146,27 +206,64 @@
|
|||
<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="question" readonly="1"/>
|
||||
<field name="description" readonly="1"/>
|
||||
<!-- <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="is_employee_reviewer" column_invisible="1"/>
|
||||
<field name="employee_score" string="self Rating" sum="Total score"
|
||||
readonly="not is_employee_reviewer"
|
||||
column_invisible="parent.template_empl_point_bool == False"/>
|
||||
<field name="rating_star" widget="priority" string="Self Rating"
|
||||
readonly="not is_employee_reviewer"
|
||||
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"
|
||||
<field name="is_manager_reviewer" column_invisible="1"/>
|
||||
<field name="is_hr_reviewer" column_invisible="1"/>
|
||||
<field name="manager_rating_star" widget="priority"
|
||||
string="Manager Rating" readonly="not is_manager_reviewer"
|
||||
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"
|
||||
readonly="not is_hr_reviewer"
|
||||
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"/>
|
||||
<field name="manager_score" sum="Total Points"
|
||||
readonly="not is_manager_reviewer"
|
||||
column_invisible="parent.template_empl_point_bool == False"/>
|
||||
<field name="hr_score" sum="Total Points"
|
||||
readonly="not is_hr_reviewer"
|
||||
column_invisible="parent.template_empl_point_bool == False"/>
|
||||
</list>
|
||||
</field>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Disciplinary Actions">
|
||||
<field name="disciplinary_ids" readonly="1">
|
||||
<list create="0" delete="0" open_form_view="1">
|
||||
<field name="complaint_date"/>
|
||||
<field name="complaint_type_id"/>
|
||||
<field name="mistake_type_id"/>
|
||||
<field name="complaint"/>
|
||||
<field name="state"
|
||||
widget="badge"
|
||||
decoration-success="state == 'closed'"
|
||||
decoration-warning="state == 'submitted'"
|
||||
decoration-info="state == 'pending'"
|
||||
decoration-danger="state == 'cancel'"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Achievements & Documents">
|
||||
<group>
|
||||
<field name="achievement_summary" widget="html"
|
||||
placeholder="Describe your achievements during this appraisal period..."/>
|
||||
<field name="employee_comments" placeholder="Additional comments..."/>
|
||||
</group>
|
||||
<group string="Supporting Documents">
|
||||
<field name="attachment_ids" widget="many2many_binary"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Team Feed Back">
|
||||
<!-- <field name="colleague_feed_ids" readonly="state != 'colleague_feedback'">-->
|
||||
<field name="colleague_feed_ids">
|
||||
|
|
@ -174,47 +271,35 @@
|
|||
<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"/>
|
||||
|
||||
<button name="action_submit_feedback" type="object" string="Submit"
|
||||
invisible="state == 'submitted'"/>
|
||||
<field name="state"/>
|
||||
<!-- invisible="state == 'submitted'"/>-->
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Finance Review">
|
||||
|
||||
<group>
|
||||
|
||||
<button name="action_update_contract_salary"
|
||||
string="Update Contract Salary"
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
invisible="salary_update"/>
|
||||
<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="salary_update" readonly="1"/>
|
||||
<field name="finance_remarks"/>
|
||||
|
||||
<field name="finance_user_id"
|
||||
readonly="1"/>
|
||||
|
||||
<field name="finance_date"
|
||||
readonly="1"/>
|
||||
|
||||
<field name="finance_head_remarks"/>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
|
||||
<footer>
|
||||
|
||||
|
||||
</footer>
|
||||
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
|
|
@ -228,6 +313,7 @@
|
|||
<field name="name">Employee Performance Review</field>
|
||||
<field name="res_model">employee.appraisal.template.config</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="search_view_id" ref="view_employee_app_search"/>
|
||||
</record>
|
||||
|
||||
<!-- ROOT MENU -->
|
||||
|
|
@ -241,7 +327,7 @@
|
|||
name="Employee Performance Review"
|
||||
parent="menu_employee_appraisal_root"
|
||||
action="action_employee_appraisal_template"
|
||||
sequence="03"/>
|
||||
sequence="04"/>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,23 @@
|
|||
|
||||
<menuitem id="configuration_id_employee"
|
||||
name="Configuration"
|
||||
groups="group_appraisal_hr_head,group_appraisal_hr,group_appraisal_management"
|
||||
parent="menu_employee_appraisal_root"
|
||||
sequence="04"/>
|
||||
sequence="06"/>
|
||||
<record id="action_appraisal_settings" model="ir.actions.act_window">
|
||||
<field name="name">Settings</field>
|
||||
<field name="res_model">res.config.settings</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">inline</field>
|
||||
<field name="context">{'module':'hrms_employee_appraisal'}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_appraisal_settings"
|
||||
name="Settings"
|
||||
parent="configuration_id_employee"
|
||||
action="action_appraisal_settings"
|
||||
sequence="100"/>
|
||||
|
||||
|
||||
<record id="view_employee_appraisal_yea_form" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.year.form</field>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record id="view_employee_stage_conf_form" model="ir.ui.view">
|
||||
<field name="name">employee.pip.form</field>
|
||||
<field name="model">employee.pip</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Performance Improvement Plan">
|
||||
<header>
|
||||
<button name="action_start" string="Start" type="object" class="btn-primary" invisible="state != 'draft'"/>
|
||||
<button name="action_review" string="Review" type="object" class="btn-info" invisible="state != 'running'"/>
|
||||
<button name="action_complete" string="Complete" type="object" class="btn-success" invisible="state != 'review'"/>
|
||||
<button name="action_fail" string="Fail" type="object" class="btn-danger" invisible="state != 'review'"/>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="employee_id"/>
|
||||
<field name="manager_id"/>
|
||||
<field name="timeline"/>
|
||||
<field name="progress_percentage" widget="progressbar"/>
|
||||
<field name="objective"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="review_date"/>
|
||||
<field name="employee_acknowledged"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Improvement Tasks">
|
||||
<field name="task_ids">
|
||||
<list editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="description"/>
|
||||
<field name="target_date"/>
|
||||
<field name="training_course"/>
|
||||
<field name="state"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Manager Remarks">
|
||||
<field name="remarks"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_employee_pip_tree" model="ir.ui.view">
|
||||
<field name="name">employee.pip.tree</field>
|
||||
<field name="model">employee.pip</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Performance Improvement Plans">
|
||||
<field name="employee_id"/>
|
||||
<field name="manager_id"/>
|
||||
<field name="timeline"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="progress_percentage" widget="progressbar"/>
|
||||
<field name="review_date"/>
|
||||
<field name="employee_acknowledged"/>
|
||||
<field name="state"
|
||||
widget="badge"
|
||||
decoration-success="state == 'completed'"
|
||||
decoration-warning="state == 'review'"
|
||||
decoration-info="state == 'running'"
|
||||
decoration-danger="state == 'failed'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_employe_pip" model="ir.actions.act_window">
|
||||
<field name="name">Performance Improvement Plans</field>
|
||||
<field name="res_model">employee.pip</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<menuitem id="menu_employe_pip"
|
||||
name="Performance Improvement Plans"
|
||||
parent="menu_employee_appraisal_root"
|
||||
action="action_employe_pip"
|
||||
sequence="05"/>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
type="object"
|
||||
string="Send To Employee"
|
||||
class="oe_highlight"
|
||||
groups="hrms_employee_appraisal.group_appraisal_manager,hrms_employee_appraisal.group_appraisal_management"
|
||||
invisible="employee_state != 'new'"/>
|
||||
<field name="employee_state" widget="statusbar"/>
|
||||
</header>
|
||||
|
|
@ -18,7 +19,7 @@
|
|||
<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="manager_ids" widget="many2many_tags" string="Performance Evaluator" invisible="1"/>
|
||||
<field name="employee_eva_id"/>
|
||||
<field name="employee_department_id"/>
|
||||
<field name="appraisal_period_type_id" string="Performance Type"/>
|
||||
|
|
@ -48,8 +49,10 @@
|
|||
<!-- <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="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"
|
||||
|
|
@ -80,7 +83,10 @@
|
|||
<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"/>
|
||||
<field name="employee_state"
|
||||
widget="badge"
|
||||
decoration-muted="employee_state == 'new'"
|
||||
decoration-success="employee_state == 'sent'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
|
@ -96,9 +102,9 @@
|
|||
name="Employee Appraisal Templates"
|
||||
parent="menu_employee_appraisal_root"
|
||||
action="action_employee_appraisal_template_conf"
|
||||
sequence="02"/>
|
||||
groups="group_appraisal_management,group_appraisal_finance_head,group_appraisal_finance,group_appraisal_hr_head,group_appraisal_hr,group_appraisal_manager"
|
||||
sequence="03"/>
|
||||
|
||||
<!-- KPI TREE VIEW -->
|
||||
|
||||
<record id="view_employee_appraisal_kpi_list" model="ir.ui.view">
|
||||
<field name="name">employee.appraisal.kpi.list</field>
|
||||
|
|
@ -119,8 +125,6 @@
|
|||
</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>
|
||||
|
|
@ -132,22 +136,8 @@
|
|||
</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 -->
|
||||
|
||||
|
||||
<button string="Save" type="object" special="save" class="btn-primary"/>
|
||||
<button name="action_delete_record" string="Delete" type="object" class="btn-danger"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
<form string="HR Notice">
|
||||
<header>
|
||||
<button name="action_send_notice" string="Send Appraisal Initiation" type="object"
|
||||
class="btn btn-success" invisible="state != 'draft'"/>
|
||||
class="btn btn-success" groups="hrms_employee_appraisal.group_appraisal_hr,hrms_employee_appraisal.group_appraisal_management"
|
||||
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"
|
||||
|
|
@ -17,30 +18,36 @@
|
|||
<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"/>
|
||||
<field name="hr_employee_id" string="Created BY" readonly="1" options="{'no_open': True}"/>
|
||||
<field name="appraisal_type_id"
|
||||
options="{'no_edit': True, 'no_create': True, 'no_open': True}"
|
||||
readonly="state != 'draft'"/>
|
||||
<field name="appraisal_notice_id"
|
||||
options="{'no_edit': True, 'no_create': True, 'no_open': True}"
|
||||
readonly="state != 'draft'"/>
|
||||
<field name="subject" readonly="state != 'draft'"/>
|
||||
<field name="start_date" readonly="state != 'draft'" force_save="1"/>
|
||||
<field name="end_date" readonly="state != 'draft'" force_save="1"/>
|
||||
</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"/>
|
||||
<field name="employee_ids" widget="many2many_tags" required="1"
|
||||
readonly="state != 'draft'"/>
|
||||
<field name="manager_ids" widget="many2many_tags" readonly="state != 'draft'"/>
|
||||
<field name="hr_department_ids" widget="many2many_tags" readonly="state != 'draft'"/>
|
||||
<field name="stage_config" widget="many2many_tags" required="1"
|
||||
readonly="state != 'draft'"/>
|
||||
<field name="employee_rating" readonly="state != 'draft'"/>
|
||||
<field name="employee_points" readonly="state != 'draft'"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="body" widget="html"/>
|
||||
<field name="body" widget="html" readonly="state != 'draft'"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Postponed Details">
|
||||
<group>
|
||||
<group>
|
||||
<field name="postponed_by_id" readonly="1"/>
|
||||
<field name="postponed_by_id" readonly="1" options="{'no_open': True}"/>
|
||||
<field name="postponed_date" readonly="1"/>
|
||||
<field name="new_start_date" readonly="1"/>
|
||||
<field name="new_end_date" readonly="1"/>
|
||||
|
|
@ -53,7 +60,7 @@
|
|||
<page string="Cancelled Details">
|
||||
<group>
|
||||
<group>
|
||||
<field name="cancelled_by_id" readonly="1"/>
|
||||
<field name="cancelled_by_id" readonly="1" options="{'no_open': True}"/>
|
||||
<field name="cancelled_date" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
|
|
@ -74,6 +81,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="seq"/>
|
||||
<field name="hr_employee_id"/>
|
||||
<field name="subject"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
|
|
@ -97,6 +105,95 @@
|
|||
name="Performance Cycle Notification"
|
||||
parent="menu_employee_appraisal_root"
|
||||
action="action_hr_notice_appraisal"
|
||||
groups="group_appraisal_hr,group_appraisal_hr_head,group_appraisal_management"
|
||||
sequence="02"/>
|
||||
|
||||
<record id="view_hr_appraisal_notification_form" model="ir.ui.view">
|
||||
<field name="name">hr.head.notification.form</field>
|
||||
<field name="model">hr.head.notification</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Appraisal Notification">
|
||||
<header>
|
||||
<button name="action_sent_hr" string="Send To HR Team" type="object" class="btn-primary"
|
||||
invisible="state != 'draft'"/>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" placeholder="Performance Appraisal Notification"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group col="2">
|
||||
<group string="Appraisal Details">
|
||||
<field name="seq"/>
|
||||
<field name="hr_employee_id"/>
|
||||
<field name="appraisal_type_id" options="{'no_create': True,'no_open': True}"/>
|
||||
<field name="appraisal_period_id" options="{'no_create': True,'no_open': True}"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</group>
|
||||
<group string="Assignment">
|
||||
<!-- <field name="hr_employee_domain_ids" invisible="1"/>-->
|
||||
<!-- <field name="hr_ids"-->
|
||||
<!-- widget="many2many_tags"/>-->
|
||||
<!-- <field name="hr_user_domain_ids" invisible="1"/>-->
|
||||
<field name="hr_users_ids"
|
||||
widget="many2many_tags"/>
|
||||
<field name="stage_config_ids" widget="many2many_tags" required="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Notification Message">
|
||||
<field name="body" widget="html"/>
|
||||
</page>
|
||||
<page string="Audit">
|
||||
<group>
|
||||
<field name="create_uid" readonly="1"/>
|
||||
<field name="create_date" readonly="1"/>
|
||||
<field name="write_uid" readonly="1"/>
|
||||
<field name="write_date" readonly="1"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_hr_appraisal_notification_tree" model="ir.ui.view">
|
||||
<field name="name">hr.head.notification.tree</field>
|
||||
<field name="model">hr.head.notification</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="seq"/>
|
||||
<field name="hr_employee_id"/>
|
||||
<field name="name"/>
|
||||
<field name="appraisal_type_id"/>
|
||||
<field name="appraisal_period_id"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="state"
|
||||
widget="badge"
|
||||
decoration-success="state == 'sent'"
|
||||
decoration-muted="state == 'draft'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_hr_head_appraisal" model="ir.actions.act_window">
|
||||
<field name="name">Appraisal Notifications</field>
|
||||
<field name="res_model">hr.head.notification</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_hr_head_appraisal"
|
||||
name="Appraisal Notifications"
|
||||
parent="menu_employee_appraisal_root"
|
||||
action="action_hr_head_appraisal"
|
||||
groups="group_appraisal_hr_head,group_appraisal_management"
|
||||
sequence="01"/>
|
||||
|
||||
|
||||
</odoo>
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
<group>
|
||||
<field name="seq" invisible="0"/>
|
||||
<field name="name"/>
|
||||
<field name="colour_seq"/>
|
||||
<field name="color" widget="color_picker"/>
|
||||
</group>
|
||||
</sheet>
|
||||
|
|
@ -20,7 +21,7 @@
|
|||
<field name="model">employee.stage.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Employee Appraisal Period">
|
||||
<field name="seq" widget="handle"/>
|
||||
<field name="seq" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="color" widget="color_picker"/>
|
||||
</list>
|
||||
|
|
@ -36,5 +37,43 @@
|
|||
parent="configuration_id_employee"
|
||||
action="action_employee_stage_confr"
|
||||
sequence="20"/>
|
||||
|
||||
|
||||
<record id="res_config_settings_view_form_appraisal" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.appraisal.form</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form" position="inside">
|
||||
<app string="Employee Appraisal" name="employee_appraisal">
|
||||
<block title="Appraisal Settings">
|
||||
<setting string="Enable Appraisal Reminders"><field name="appraisal_reminder_enabled"/></setting>
|
||||
<setting string="Reminder Days"><field name="appraisal_reminder_days"/>
|
||||
<div class="text-muted">
|
||||
Reminder email will be sent before appraisal end date.
|
||||
</div>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_employee_appraisal_settings" model="ir.actions.act_window">
|
||||
<field name="name">Appraisal Settings</field>
|
||||
<field name="res_model">res.config.settings</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">inline</field>
|
||||
<field name="context">{'module': 'hrms_employee_appraisal'}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_employee_appraisal_settings"
|
||||
name="Settings"
|
||||
parent="configuration_id_employee"
|
||||
action="action_employee_appraisal_settings"
|
||||
sequence="10"/>
|
||||
<!-- groups="hrms_employee_appraisal.group_appraisal_hr_head,-->
|
||||
<!-- hrms_employee_appraisal.group_appraisal_hr,-->
|
||||
<!-- hrms_employee_appraisal.group_appraisal_management"-->
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
<field name="jd_file" filename="jd_file_name"
|
||||
widget="binary" force_save="1"/>
|
||||
<field name="jd_file_name" invisible="1" force_save="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="job_id" invisible="job_id == False" readonly="1" force_save="1" options="{'no_quick_create':True,'no_open':True}"/>
|
||||
<field name="number_of_positions" readonly="(state != 'draft' and not is_hr) or state == 'jd_created'"/>
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
<field name="assign_to" invisible="state not in ['final','jd_created']" options="{'no_quick_create': True, 'no_create_edit': True, 'no_open': True}"/>
|
||||
<field name="target_startdate" invisible="1" readonly="state in ['jd_created']"/>
|
||||
<field name="target_deadline" widget="daterange" string="Target Deadline" options="{'start_date_field': 'target_startdate'}" on_change="1" readonly="state in ['jd_created']"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="notes" placeholder="Remarks" readonly="state == 'jd_created'" invisible="not notes"/>
|
||||
</group>
|
||||
<notebook>
|
||||
|
|
@ -80,10 +80,18 @@
|
|||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_recruitment_requisition" model="ir.actions.act_window">
|
||||
<record id="action_recruitment_requisition" model="ir.actions.act_window">
|
||||
<field name="name">Recruitment Requisitions</field>
|
||||
<field name="res_model">recruitment.requisition</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No Recruitment Requisitions Found
|
||||
</p>
|
||||
<p>
|
||||
Click Create to raise a new recruitment requisition.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
|
|
|
|||
Loading…
Reference in New Issue