Merge remote-tracking branch 'origin/feature/share_module' into feature/share_module
This commit is contained in:
commit
80e90ca88a
|
|
@ -5,7 +5,7 @@
|
||||||
<field name="name">bench.management.line.list</field>
|
<field name="name">bench.management.line.list</field>
|
||||||
<field name="model">bench.management.line</field>
|
<field name="model">bench.management.line</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<list string="Bench Management">
|
<list create="0" string="Bench Management">
|
||||||
<field name="employee_id"/>
|
<field name="employee_id"/>
|
||||||
<field name="job_id"/>
|
<field name="job_id"/>
|
||||||
<field name="status"/>
|
<field name="status"/>
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
<field name="name">bench.management.line.form</field>
|
<field name="name">bench.management.line.form</field>
|
||||||
<field name="model">bench.management.line</field>
|
<field name="model">bench.management.line</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Bench Management">
|
<form create="0" string="Bench Management">
|
||||||
<sheet>
|
<sheet>
|
||||||
|
|
||||||
<group>
|
<group>
|
||||||
|
|
@ -73,9 +73,7 @@
|
||||||
<field name="name">bench.management.line.kanban</field>
|
<field name="name">bench.management.line.kanban</field>
|
||||||
<field name="model">bench.management.line</field>
|
<field name="model">bench.management.line</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
|
<kanban create="0" class="o_kanban_mobile">
|
||||||
<kanban class="o_kanban_mobile">
|
|
||||||
|
|
||||||
<field name="employee_id"/>
|
<field name="employee_id"/>
|
||||||
<field name="job_id"/>
|
<field name="job_id"/>
|
||||||
<field name="status"/>
|
<field name="status"/>
|
||||||
|
|
@ -85,17 +83,12 @@
|
||||||
<field name="future_project_count"/>
|
<field name="future_project_count"/>
|
||||||
<field name="completed_project_count"/>
|
<field name="completed_project_count"/>
|
||||||
<field name="project_names_tooltip"/>
|
<field name="project_names_tooltip"/>
|
||||||
|
|
||||||
<templates>
|
<templates>
|
||||||
|
|
||||||
<t t-name="kanban-box">
|
<t t-name="kanban-box">
|
||||||
|
|
||||||
<div class="oe_kanban_card oe_kanban_global_click"
|
<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);">
|
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 -->
|
<!-- Header -->
|
||||||
<div class="d-flex align-items-center mb-3">
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
|
||||||
<img t-att-src="'/web/image/hr.employee/' + record.employee_id.raw_value + '/avatar_128'"
|
<img t-att-src="'/web/image/hr.employee/' + record.employee_id.raw_value + '/avatar_128'"
|
||||||
style="
|
style="
|
||||||
width:42px;
|
width:42px;
|
||||||
|
|
@ -235,7 +228,6 @@
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="action_bench_management" model="ir.actions.act_window">
|
<record id="action_bench_management" model="ir.actions.act_window">
|
||||||
|
|
||||||
<field name="name">Bench Management</field>
|
<field name="name">Bench Management</field>
|
||||||
<field name="res_model">bench.management.line</field>
|
<field name="res_model">bench.management.line</field>
|
||||||
<field name="view_mode">kanban,list,form</field>
|
<field name="view_mode">kanban,list,form</field>
|
||||||
|
|
@ -247,6 +239,7 @@
|
||||||
<menuitem id="menu_bench_management"
|
<menuitem id="menu_bench_management"
|
||||||
name="Employee Bench"
|
name="Employee Bench"
|
||||||
parent="hr.menu_hr_root"
|
parent="hr.menu_hr_root"
|
||||||
|
groups="hr.group_hr_manager"
|
||||||
action="action_bench_management"
|
action="action_bench_management"
|
||||||
sequence="3"/>
|
sequence="3"/>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
{
|
||||||
|
'name': 'Disciplinary',
|
||||||
|
'version': '1.0.0',
|
||||||
|
'category': 'Apps',
|
||||||
|
'summary': 'Disciplinary',
|
||||||
|
'description': 'Employee Disciplinary',
|
||||||
|
'sequence': '10',
|
||||||
|
'author': '',
|
||||||
|
'company': 'FTPROTECH',
|
||||||
|
'website': 'https://www.ftprotech.in',
|
||||||
|
'depends': ['mail', 'hr', 'base', 'website_hr_recruitment', 'contacts', 'point_of_sale'],
|
||||||
|
'demo': [],
|
||||||
|
'data': [
|
||||||
|
'data/sequence.xml',
|
||||||
|
'security/ir.model.access.csv',
|
||||||
|
'views/disciplinary_view.xml',
|
||||||
|
'views/employee_displance.xml',
|
||||||
|
'views/mistake_type_views.xml',
|
||||||
|
'views/incident_sub_type.xml',
|
||||||
|
'views/disciplinary_complaint_type.xml',
|
||||||
|
],
|
||||||
|
'installable': True,
|
||||||
|
'application': False,
|
||||||
|
'auto_install': False,
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<record id="incident_report_sequence" model="ir.sequence">
|
||||||
|
<field name="name">Employee Disciplinary</field>
|
||||||
|
<field name="code">employee.disciplinary</field>
|
||||||
|
<field name="prefix">IR</field>
|
||||||
|
<field name="padding">5</field>
|
||||||
|
<field name="company_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="manage_incident_report_sequence" model="ir.sequence">
|
||||||
|
<field name="name">Manage Incident</field>
|
||||||
|
<field name="code">manage.incident</field>
|
||||||
|
<field name="prefix">MI</field>
|
||||||
|
<field name="padding">5</field>
|
||||||
|
<field name="company_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="seq_employee_disciplinary_sequence" model="ir.sequence">
|
||||||
|
<field name="name">Disciplinary Sequence</field>
|
||||||
|
<field name="code">hr.employee.sequence</field>
|
||||||
|
<field name="prefix">ED</field>
|
||||||
|
<field name="padding">5</field>
|
||||||
|
<field name="company_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
from . import disciplinary
|
||||||
|
from . import employee_displane
|
||||||
|
|
@ -0,0 +1,188 @@
|
||||||
|
from datetime import datetime, date
|
||||||
|
from odoo import fields, models, api
|
||||||
|
|
||||||
|
#
|
||||||
|
# class NameChangeHrEmployee(models.Model):
|
||||||
|
# _inherit = "hr.employee"
|
||||||
|
#
|
||||||
|
# employee_name_ids1 = fields.One2many('employee.disciplinary', 'disp_name')
|
||||||
|
# employee_self_service_line_ids = fields.One2many('manage.incident', 'emp_incident', domain=[('state', '=', 'closed')])
|
||||||
|
#
|
||||||
|
# def name_get(self):
|
||||||
|
# result = []
|
||||||
|
# for record in self:
|
||||||
|
# if self.env.context.get('new_custom_name', False):
|
||||||
|
# result.append((record.id, "{} - {}".format(record.name, record.identification_id)))
|
||||||
|
# else:
|
||||||
|
# return super(NameChangeHrEmployee, self).name_get()
|
||||||
|
# return result
|
||||||
|
|
||||||
|
|
||||||
|
class EmployeeDisciplinary(models.Model):
|
||||||
|
_name = 'employee.disciplinary'
|
||||||
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||||
|
_rec_name = 'incident_type'
|
||||||
|
|
||||||
|
incident_date = fields.Datetime(string='Incident Date & Time', tracking=True, default=datetime.now(), required=True)
|
||||||
|
incident_type = fields.Many2one('incident.employee', string='Incident Type', tracking=True, required=True)
|
||||||
|
incident_sub_type = fields.Many2many('incident.sub.employee', string='Incident Sub Type', tracking=True,
|
||||||
|
required=True)
|
||||||
|
incident_details = fields.Char(string='Incident Details', tracking=True, required=True)
|
||||||
|
seized_items = fields.Char(string='Seized Items', tracking=True)
|
||||||
|
incident_summary = fields.Text(string='Incident Summary', tracking=True, required=True)
|
||||||
|
attach = fields.Many2many('ir.attachment', string='Attachments', tracking=True)
|
||||||
|
emp_many_disp = fields.Many2many('hr.employee', 'new_custom_table', string='Employees Involved in the Incident',
|
||||||
|
tracking=True, required=True)
|
||||||
|
date_action = fields.Date(string='Date')
|
||||||
|
employee = fields.Many2one('manage.incident')
|
||||||
|
employee_code = fields.Many2one("hr.employee", string="Employee Name", required=True)
|
||||||
|
employee_name = fields.Char(related="employee_code.identification_id")
|
||||||
|
disp_name = fields.Many2one('hr.employee')
|
||||||
|
|
||||||
|
@api.onchange('incident_type')
|
||||||
|
def return_incident_sub_type(self):
|
||||||
|
print(self.incident_type.sub_type)
|
||||||
|
listed = []
|
||||||
|
for recs in self.incident_type.sub_type:
|
||||||
|
listed.append(recs.id)
|
||||||
|
return {'domain': {'incident_sub_type': [('id', 'in', listed)]}}
|
||||||
|
|
||||||
|
@api.constrains('incident_type')
|
||||||
|
def create_manage_incidents(self):
|
||||||
|
for rec in self:
|
||||||
|
print('created')
|
||||||
|
self.env['manage.incident'].create({
|
||||||
|
'employee_disciplinary_id': rec.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
@api.constrains('employee')
|
||||||
|
def holds_hr_employee(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.disp_name = rec.employee.employee_code_list1
|
||||||
|
|
||||||
|
|
||||||
|
class IncidentEmployee(models.Model):
|
||||||
|
_name = 'incident.employee'
|
||||||
|
|
||||||
|
name = fields.Char(string='Incident')
|
||||||
|
sub_type = fields.Many2many('incident.sub.employee', string='Sub type')
|
||||||
|
|
||||||
|
|
||||||
|
class IncidentSubEmployee(models.Model):
|
||||||
|
_name = 'incident.sub.employee'
|
||||||
|
|
||||||
|
name = fields.Char(string='Incident Sub')
|
||||||
|
|
||||||
|
class DisciplinaryMistakeType(models.Model):
|
||||||
|
_name = 'disciplinary.mistake.type'
|
||||||
|
_description = 'Disciplinary Mistake Type'
|
||||||
|
|
||||||
|
name = fields.Char(string="Mistake Type", required=True)
|
||||||
|
|
||||||
|
class IncidentSubEmployee(models.Model):
|
||||||
|
_name = 'incident.sub.employee'
|
||||||
|
_description = 'Incident Sub Type'
|
||||||
|
|
||||||
|
name = fields.Char(string="Incident Sub Type", required=True)
|
||||||
|
|
||||||
|
class EmployeeDisciplinaryLines(models.Model):
|
||||||
|
_name = 'employee.disciplinary.line'
|
||||||
|
_rec_name = 'hr_emp_many'
|
||||||
|
|
||||||
|
emp_many = fields.Many2one('employee.disciplinary', string='Employee Disp')
|
||||||
|
hr_emp_many = fields.Many2one('hr.employee', string='Employee Number')
|
||||||
|
hr_emp_many_name = fields.Char(related='hr_emp_many.name', string='Employee Name')
|
||||||
|
|
||||||
|
|
||||||
|
class ManageIncident(models.Model):
|
||||||
|
_name = 'manage.incident'
|
||||||
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||||
|
|
||||||
|
# employee_name_ids = fields.One2many('employee.disciplinary','employee',string="Employee Name")
|
||||||
|
employee_disciplinary_id = fields.Many2one("employee.disciplinary", string="Employee Disp")
|
||||||
|
employee_code_list1 = fields.Many2many("hr.employee", string="Employees Involved in the Incident",
|
||||||
|
related='employee_disciplinary_id.emp_many_disp', tracking=True)
|
||||||
|
incident_dat = fields.Datetime(related='employee_disciplinary_id.incident_date', string='Incident Date & Time',
|
||||||
|
tracking=True)
|
||||||
|
employee_by_code = fields.Many2one(related='employee_disciplinary_id.employee_code',
|
||||||
|
string="Reported By Employee Name")
|
||||||
|
incident_sum = fields.Text(related='employee_disciplinary_id.incident_summary', string='Incident Summary',
|
||||||
|
tracking=True)
|
||||||
|
incident_typ = fields.Many2one(related='employee_disciplinary_id.incident_type', string="Incident Type",
|
||||||
|
tracking=True)
|
||||||
|
incident_sub_typ = fields.Many2many(related='employee_disciplinary_id.incident_sub_type',
|
||||||
|
string="Incident Sub Type", tracking=True)
|
||||||
|
# corrective_action_emp_id = fields.Many2one(related='employee_disciplinary_id.corrective_action_id',
|
||||||
|
# string="Corrective Action", tracking=True)
|
||||||
|
state = fields.Selection(([
|
||||||
|
('pending_inquiry', 'Pending Inquiry'),
|
||||||
|
('in_progress', 'In Process'),
|
||||||
|
('closed', 'Closed')
|
||||||
|
]), string="Status", default='pending_inquiry', tracking=True)
|
||||||
|
emp_incident = fields.Many2one('hr.employee')
|
||||||
|
employee_inquiry = fields.One2many('manage.incident.line', 'employee_inquiry_state')
|
||||||
|
|
||||||
|
def button_in_progress(self):
|
||||||
|
self.state = 'in_progress'
|
||||||
|
|
||||||
|
# def button_closed(self):
|
||||||
|
# for rec in self:
|
||||||
|
# rec.state = 'closed'
|
||||||
|
|
||||||
|
def button_closed(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.state = 'closed'
|
||||||
|
update_into_employee = rec.env['hr.employee'].search([('id', '=', rec.employee_code_list1.id)])
|
||||||
|
records = {
|
||||||
|
}
|
||||||
|
if records:
|
||||||
|
update_into_employee.write(records)
|
||||||
|
|
||||||
|
print('triggered 2')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CorrectiveActions(models.Model):
|
||||||
|
_name = "corrective.actions"
|
||||||
|
|
||||||
|
name = fields.Char(string="Name")
|
||||||
|
|
||||||
|
|
||||||
|
class ManageIncidentLine(models.Model):
|
||||||
|
_name = 'manage.incident.line'
|
||||||
|
_inherit = ['mail.thread']
|
||||||
|
_description = 'Manage Incident Line'
|
||||||
|
|
||||||
|
corrective_action_id = fields.Many2one('corrective.actions', string="Corrective Action", tracking=True,
|
||||||
|
required=True)
|
||||||
|
internal_panel = fields.Many2many('hr.employee', string="Internal Panel Members", tracking=True,
|
||||||
|
required=True)
|
||||||
|
external_panel = fields.Char(string="External Panel Members")
|
||||||
|
due_date = fields.Date(string="Due Date")
|
||||||
|
last_action_date = fields.Datetime(string="Last Action Date", compute='_compute_last_action_date',
|
||||||
|
default=date.today())
|
||||||
|
recommendation = fields.Char(string="Recommendation", tracking=True, required=True)
|
||||||
|
venue = fields.Char(string='Venue')
|
||||||
|
inquiry_summary = fields.Char(string='Inquiry Summary', tracking=True, required=True)
|
||||||
|
is_guilty = fields.Selection(([
|
||||||
|
('yes', 'Yes'),
|
||||||
|
('no', 'No'),
|
||||||
|
]), string="Is the Employee Guilt of the Incident", default='no', tracking=True)
|
||||||
|
inquiry_date = fields.Datetime(string="Inquiry Date and Time", required=True)
|
||||||
|
employee_inquiry_state = fields.Many2one('manage.incident')
|
||||||
|
|
||||||
|
@api.depends('inquiry_date')
|
||||||
|
def _compute_last_action_date(self):
|
||||||
|
for line in self:
|
||||||
|
if not line.employee_inquiry_state or line == line.employee_inquiry_state.employee_inquiry[0]:
|
||||||
|
line.last_action_date = False
|
||||||
|
else:
|
||||||
|
previous_line = line.employee_inquiry_state.employee_inquiry.filtered(lambda l: l.inquiry_date < line.inquiry_date)
|
||||||
|
sorted_previous_line = previous_line.sorted(key=lambda l: l.inquiry_date, reverse=True)
|
||||||
|
if sorted_previous_line:
|
||||||
|
line.last_action_date = sorted_previous_line[0].inquiry_date
|
||||||
|
else:
|
||||||
|
line.last_action_date = False
|
||||||
|
|
@ -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,22 @@
|
||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_employee_disciplinary,employee_disciplinary,model_employee_disciplinary,,1,1,1,1
|
||||||
|
access_incident_employee,incident_employee,model_incident_employee,,1,1,1,1
|
||||||
|
access_incident_sub_employee,incident_sub_employee,model_incident_sub_employee,,1,1,1,1
|
||||||
|
access_employee_disciplinary_line,employee_disciplinary_line,model_employee_disciplinary_line,,1,1,1,1
|
||||||
|
access_manage_incident,manage_incident,model_manage_incident,,1,1,1,1
|
||||||
|
access_manage_incident_line,manage_incident_line,model_manage_incident_line,,1,1,1,1
|
||||||
|
access_corrective_actions,corrective_actions,model_corrective_actions,,1,1,1,1
|
||||||
|
|
||||||
|
access_hr_employee_disciplinary,hr.employee.disciplinary,model_hr_employee_disciplinary,,1,1,1,1
|
||||||
|
access_hr_disciplinary_complaint_line,hr.disciplinary.complaint.line,model_hr_disciplinary_complaint_line,,1,1,1,1
|
||||||
|
access_hr_disciplinary_action_line,hr.disciplinary.action.line,model_hr_disciplinary_action_line,,1,1,1,1
|
||||||
|
access_disciplinary_action_type,disciplinary.action.type,model_disciplinary_action_type,,1,1,1,1
|
||||||
|
access_disciplinary_complaint_type,disciplinary.complaint.type,model_disciplinary_complaint_type,,1,1,1,1
|
||||||
|
access_disciplinary_mistake_type,disciplinary.mistake.type,model_disciplinary_mistake_type,,1,1,1,1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,264 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="employee_disciplinary_list" model="ir.ui.view">
|
||||||
|
<field name="name">Employee Disciplinary list</field>
|
||||||
|
<field name="model">employee.disciplinary</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list>
|
||||||
|
<field name="incident_date"/>
|
||||||
|
<field name="incident_type"/>
|
||||||
|
<field name="incident_sub_type" widget="many2many_tags"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="employee_disciplinary_form" model="ir.ui.view">
|
||||||
|
<field name="name">Employee Disciplinary form</field>
|
||||||
|
<field name="model">employee.disciplinary</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form>
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<field name="incident_date"/>
|
||||||
|
<field name="incident_type" options="{'no_open': True,}"/>
|
||||||
|
<field name="incident_sub_type" widget="many2many_tags" readonly="0"
|
||||||
|
options="{'no_open': True}"/>
|
||||||
|
<label for="employee_code" string="Reported By Employee Code"/>
|
||||||
|
<div class="address_format">
|
||||||
|
<field name="employee_code" style="width: 50%" options="{'no_open': True,}"/>
|
||||||
|
<field name="employee_name" style="width: 50%"/>
|
||||||
|
</div>
|
||||||
|
<field name="incident_details"/>
|
||||||
|
<field name="seized_items"/>
|
||||||
|
<field name="incident_summary"/>
|
||||||
|
<field name="attach" widget="many2many_binary" options="{'preview_image': True}"/>
|
||||||
|
<field name="emp_many_disp" widget="many2many_tags" context="{'new_custom_name': True}"/>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
<chatter/>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="manage_incident_list" model="ir.ui.view">
|
||||||
|
<field name="name">Manage Incident list</field>
|
||||||
|
<field name="model">manage.incident</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list create="0">
|
||||||
|
<field name="employee_code_list1" widget="many2many_tags" context="{'new_custom_name': True}"/>
|
||||||
|
<!-- <field name="incident_dat"/>-->
|
||||||
|
<field name="incident_typ"/>
|
||||||
|
<field name="incident_sub_typ" widget="many2many_tags"/>
|
||||||
|
<field name="incident_sum"/>
|
||||||
|
<field name="state"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="manage_incident_form" model="ir.ui.view">
|
||||||
|
<field name="name">Manage Incident form</field>
|
||||||
|
<field name="model">manage.incident</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form create="0">
|
||||||
|
<header>
|
||||||
|
<button name="button_in_progress" string="In Progress" class="oe_highlight" type="object"/>
|
||||||
|
<!-- states="pending_inquiry"/>-->
|
||||||
|
<!-- attrs="{'invisible' : ('state','!=','pending_inquiry')}"/>-->
|
||||||
|
<button name="button_closed" string="Closed" class="oe_highlight" type="object"/>
|
||||||
|
<!-- states="in_progress"/>-->
|
||||||
|
<!-- attrs="{'invisible' : ('state','!=','in_progress')}"/>-->
|
||||||
|
<field name="state" widget="statusbar"/>
|
||||||
|
</header>
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="employee_code_list1" widget="many2many_tags"
|
||||||
|
context="{'new_custom_name': True}"/>
|
||||||
|
<field name="employee_by_code" options="{'no_open': True,}"/>
|
||||||
|
<!-- <field name="incident_dat"/>-->
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="incident_typ" options="{'no_open': True,}"/>
|
||||||
|
<field name="incident_sub_typ" widget="many2many_tags"/>
|
||||||
|
<field name="incident_sum"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<field name="employee_inquiry" string="Manage Incident">
|
||||||
|
<!-- attrs="{'readonly': [('state', '=','closed')]}">-->
|
||||||
|
<list>
|
||||||
|
<field name="inquiry_date"/>
|
||||||
|
<field name="corrective_action_id"/>
|
||||||
|
<field name="due_date"/>
|
||||||
|
<field name="last_action_date"/>
|
||||||
|
</list>
|
||||||
|
<form>
|
||||||
|
<group>
|
||||||
|
<field name="inquiry_date"/>
|
||||||
|
<field name="venue"/>
|
||||||
|
<field name="internal_panel" widget="many2many_tags"
|
||||||
|
context="{'new_custom_name': True}"/>
|
||||||
|
<field name="external_panel"/>
|
||||||
|
<field name="inquiry_summary"/>
|
||||||
|
<field name="is_guilty" widget="radio" options="{'horizontal':true}"/>
|
||||||
|
<field name="corrective_action_id" options="{'no_open': True,}"/>
|
||||||
|
<field name="recommendation"/>
|
||||||
|
<field name="due_date"/>
|
||||||
|
<field name="last_action_date"/>
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</sheet>
|
||||||
|
<chatter/>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- <record id="career_history_tab_sub_menu" model="ir.ui.view">-->
|
||||||
|
<!-- <field name="name">Career History Tab Sub Menu</field>-->
|
||||||
|
<!-- <field name="model">hr.employee</field>-->
|
||||||
|
<!-- <field name="inherit_id" ref="employee_life_cycle.career_history_tab_menu"/>-->
|
||||||
|
<!-- <field name="arch" type="xml">-->
|
||||||
|
<!-- <xpath expr="//page/field[@name='career_history_field']" position="after">-->
|
||||||
|
<!-- <!– <group name="career_hist_sub_menu" string="Disciplinary Actions">–>-->
|
||||||
|
<!-- <!– <field name="employee_name_ids1" string="Manage Incident">–>-->
|
||||||
|
<!-- <!– <list editable="0" create="0">–>-->
|
||||||
|
<!-- <!– <field name="incident_date"/>–>-->
|
||||||
|
<!-- <!– <field name="incident_type"/>–>-->
|
||||||
|
<!-- <!– <field name="incident_sub_type"/>–>-->
|
||||||
|
<!-- <!–<!– <field name="corrective_action_id"/>–>–>-->
|
||||||
|
<!-- <!– </list>–>-->
|
||||||
|
<!-- <!– </field>–>-->
|
||||||
|
<!-- <!– </group>–>-->
|
||||||
|
<!-- <field name="employee_self_service_line_ids" string="Manage Incident" readonly="1">-->
|
||||||
|
<!-- <list>-->
|
||||||
|
<!-- <field name="incident_dat"/>-->
|
||||||
|
<!-- <field name="incident_typ"/>-->
|
||||||
|
<!-- <field name="incident_sub_typ"/>-->
|
||||||
|
<!-- </list>-->
|
||||||
|
<!-- </field>-->
|
||||||
|
<!-- </xpath>-->
|
||||||
|
<!-- </field>-->
|
||||||
|
<!-- </record>-->
|
||||||
|
|
||||||
|
<!-- <record id="career_history_tab_sub_menu_self" model="ir.ui.view">-->
|
||||||
|
<!-- <field name="name">Career History Tab Sub Menu Self Service</field>-->
|
||||||
|
<!-- <field name="model">hr.employee</field>-->
|
||||||
|
<!-- <field name="inherit_id" ref="employee_self_service.view_employee_form_self_service"/>-->
|
||||||
|
<!-- <field name="arch" type="xml">-->
|
||||||
|
<!-- <xpath expr="//page/field[@name='career_history_field']" position="after">-->
|
||||||
|
<!-- <!– <group name="career_hist_sub_menu" string="Disciplinary Actions">–>-->
|
||||||
|
<!-- <!– <field name="employee_name_ids1" string="Manage Incident">–>-->
|
||||||
|
<!-- <!– <list editable="0" create="0">–>-->
|
||||||
|
<!-- <!– <field name="incident_date"/>–>-->
|
||||||
|
<!-- <!– <field name="incident_type"/>–>-->
|
||||||
|
<!-- <!– <field name="incident_sub_type"/>–>-->
|
||||||
|
<!-- <!– <!– <field name="corrective_action_id"/>–>–>-->
|
||||||
|
<!-- <!– </list>–>-->
|
||||||
|
<!-- <!– </field>–>-->
|
||||||
|
<!-- <!– </group>–>-->
|
||||||
|
<!-- <field name="employee_self_service_line_ids" string="Manage Incident" readonly="1">-->
|
||||||
|
<!-- <list>-->
|
||||||
|
<!-- <field name="incident_dat"/>-->
|
||||||
|
<!-- <field name="incident_typ"/>-->
|
||||||
|
<!-- <field name="incident_sub_typ"/>-->
|
||||||
|
<!-- </list>-->
|
||||||
|
<!-- </field>-->
|
||||||
|
<!-- </xpath>-->
|
||||||
|
<!-- </field>-->
|
||||||
|
<!-- </record>-->
|
||||||
|
|
||||||
|
<record id="incident_employee_list" model="ir.ui.view">
|
||||||
|
<field name="name">incident Employee list</field>
|
||||||
|
<field name="model">incident.employee</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="sub_type" widget="many2many_tags"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="incident_employee_form" model="ir.ui.view">
|
||||||
|
<field name="name">incident Employee form</field>
|
||||||
|
<field name="model">incident.employee</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form>
|
||||||
|
<sheet>
|
||||||
|
<form>
|
||||||
|
<group>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="sub_type" widget="many2many_tags"/>
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="employee_disciplinary_action" model="ir.actions.act_window">
|
||||||
|
<field name="name">Incident Reporting</field>
|
||||||
|
<field name="res_model">employee.disciplinary</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="manage_incident_action" model="ir.actions.act_window">
|
||||||
|
<field name="name">Manage Incident</field>
|
||||||
|
<field name="res_model">manage.incident</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="incident_employee_action" model="ir.actions.act_window">
|
||||||
|
<field name="name">Incident Type</field>
|
||||||
|
<field name="res_model">incident.employee</field>
|
||||||
|
<field name="view_mode">list,form</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>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem id="employee_disciplinary_menu"
|
||||||
|
name="Employee Disciplinary Management"
|
||||||
|
parent="hr.menu_hr_root"
|
||||||
|
action="employee_disciplinary_action"
|
||||||
|
sequence="105"/>
|
||||||
|
|
||||||
|
<!-- Child Menu (moved inside) -->
|
||||||
|
<menuitem id="menu_employee_disciplinary_root"
|
||||||
|
name="Employee Disciplinary Configuration"
|
||||||
|
parent="employee_disciplinary_menu"
|
||||||
|
sequence="10"/>
|
||||||
|
|
||||||
|
<!-- Sub Menu -->
|
||||||
|
<menuitem id="menu_employee_disciplinary"
|
||||||
|
name="Employee Disciplinary"
|
||||||
|
parent="employee_disciplinary_menu"
|
||||||
|
action="action_hr_employee_disciplinary"
|
||||||
|
sequence="01"/>
|
||||||
|
|
||||||
|
<!-- <menuitem id="manage_incident_employee"-->
|
||||||
|
<!-- name="Incident Type"-->
|
||||||
|
<!-- parent="employee_disciplinary_menu"-->
|
||||||
|
<!-- action="incident_employee_action"-->
|
||||||
|
<!-- sequence="3"/>-->
|
||||||
|
|
||||||
|
<!-- <menuitem id="manage_incident_sub_menu"-->
|
||||||
|
<!-- name="Manage Incident"-->
|
||||||
|
<!-- parent="employee_disciplinary_menu"-->
|
||||||
|
<!-- action="manage_incident_action"-->
|
||||||
|
<!-- sequence="2"/>-->
|
||||||
|
|
||||||
|
<!-- <menuitem id="employee_disciplinary_sub_menu"-->
|
||||||
|
<!-- name="Incident Reporting"-->
|
||||||
|
<!-- parent="employee_disciplinary_menu"-->
|
||||||
|
<!-- action="employee_disciplinary_action"-->
|
||||||
|
<!-- sequence="1"/>-->
|
||||||
|
|
||||||
|
</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>
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<!-- list View -->
|
||||||
|
<record id="view_incident_sub_employee_list" model="ir.ui.view">
|
||||||
|
<field name="name">incident.sub.employee.list</field>
|
||||||
|
<field name="model">incident.sub.employee</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list>
|
||||||
|
<field name="name"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Form View -->
|
||||||
|
<record id="view_incident_sub_employee_form" model="ir.ui.view">
|
||||||
|
<field name="name">incident.sub.employee.form</field>
|
||||||
|
<field name="model">incident.sub.employee</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Incident Sub Type">
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<field name="name"/>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Action -->
|
||||||
|
<record id="action_incident_sub_employee" model="ir.actions.act_window">
|
||||||
|
<field name="name">Incident Sub Type</field>
|
||||||
|
<field name="res_model">incident.sub.employee</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Menu -->
|
||||||
|
<!-- <menuitem id="menu_incident_sub_employee"-->
|
||||||
|
<!-- name="Incident Sub Type"-->
|
||||||
|
<!-- parent="employee_disciplinary_menu"-->
|
||||||
|
<!-- action="action_incident_sub_employee"/>-->
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- Tree View -->
|
||||||
|
<record id="view_mistake_type_list" model="ir.ui.view">
|
||||||
|
<field name="name">mistake.type.list</field>
|
||||||
|
<field name="model">disciplinary.mistake.type</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list>
|
||||||
|
<field name="name"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Form View -->
|
||||||
|
<record id="view_mistake_type_form" model="ir.ui.view">
|
||||||
|
<field name="name">mistake.type.form</field>
|
||||||
|
<field name="model">disciplinary.mistake.type</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form>
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<field name="name"/>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Action -->
|
||||||
|
<record id="action_mistake_type" model="ir.actions.act_window">
|
||||||
|
<field name="name">Mistake Type</field>
|
||||||
|
<field name="res_model">disciplinary.mistake.type</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
id="menu_mistake_type"
|
||||||
|
name="Mistake Type"
|
||||||
|
parent="menu_employee_disciplinary_root"
|
||||||
|
action="action_mistake_type"
|
||||||
|
sequence="02"/>
|
||||||
|
</odoo>
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
from odoo import models, fields, api
|
from odoo import models, fields, api
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import ValidationError
|
||||||
import calendar
|
import calendar
|
||||||
|
|
||||||
|
|
||||||
class PayrollPeriod(models.Model):
|
class PayrollPeriod(models.Model):
|
||||||
_name = 'payroll.period'
|
_name = 'payroll.period'
|
||||||
_description = 'Payroll Period'
|
_description = 'Payroll Period'
|
||||||
_rec_name = 'name'
|
_rec_name = 'name'
|
||||||
|
_order = 'id desc'
|
||||||
_sql_constraints = [
|
_sql_constraints = [
|
||||||
('unique_name', 'unique(name)', 'The name must be unique.')
|
('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)
|
from_date = fields.Date(string="From Date", required=True)
|
||||||
to_date = fields.Date(string="To Date", required=True)
|
to_date = fields.Date(string="To Date", required=True)
|
||||||
name = fields.Char(string="Name", required=True)
|
name = fields.Char(string="Name", required=True)
|
||||||
period_line_ids = fields.One2many('payroll.period.line', 'period_id', string="Monthly Periods")
|
period_line_ids = fields.One2many('payroll.period.line', 'period_id', string="Monthly Periods")
|
||||||
|
|
||||||
@api.model_create_multi
|
@api.model_create_multi
|
||||||
def create(self, vals_list):
|
def create(self, vals_list):
|
||||||
periods = super().create(vals_list)
|
periods = super().create(vals_list)
|
||||||
active_investment_types = self.env['it.investment.type'].search([('active', '=', True)])
|
active_investment_types = self.env['it.investment.type'].search([('active', '=', True)])
|
||||||
if active_investment_types:
|
if active_investment_types:
|
||||||
active_investment_types.write({
|
active_investment_types.write({
|
||||||
'period_ids': [(4, period.id) for period in periods],
|
'period_ids': [(4, period.id) for period in periods],
|
||||||
})
|
})
|
||||||
return periods
|
return periods
|
||||||
|
|
||||||
@api.onchange('from_date', 'to_date')
|
@api.onchange('from_date', 'to_date')
|
||||||
def onchange_from_to_date(self):
|
def onchange_from_to_date(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
if rec.from_date and rec.to_date:
|
if rec.from_date and rec.to_date:
|
||||||
rec.name = f"{rec.from_date.year}-{rec.to_date.year}"
|
rec.name = f"{rec.from_date.year}-{rec.to_date.year}"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,11 @@
|
||||||
<field name="payslip_count" readonly="1"/>
|
<field name="payslip_count" readonly="1"/>
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
|
<footer>
|
||||||
|
<button string="Close"
|
||||||
|
special="cancel"
|
||||||
|
class="btn-secondary"/>
|
||||||
|
</footer>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
|
||||||
|
|
@ -179,9 +179,8 @@ class CustomerPortal(portal.CustomerPortal):
|
||||||
('use_website_helpdesk_form', '=', True),
|
('use_website_helpdesk_form', '=', True),
|
||||||
'|',
|
'|',
|
||||||
('company_id', '=', False),
|
('company_id', '=', False),
|
||||||
('company_id', 'in', [request.env.company.id])
|
('company_id', 'in', [request.env.user.company_id.id])
|
||||||
])
|
])
|
||||||
|
|
||||||
selection_dict = dict(
|
selection_dict = dict(
|
||||||
request.env['helpdesk.team']._fields['portal_ticket_type'].selection
|
request.env['helpdesk.team']._fields['portal_ticket_type'].selection
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -483,6 +483,10 @@ class HrRecruitmentAutoDocWizard(models.TransientModel):
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_jd_required_fields(self):
|
def _get_jd_required_fields(self):
|
||||||
|
category_dict = {
|
||||||
|
str(category['id']): category['category_name']
|
||||||
|
for category in self.env['job.category'].sudo().search_read([], ['id', 'category_name'])
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
"request_id": {"type": "string", "description": "Request or requisition identifier"},
|
"request_id": {"type": "string", "description": "Request or requisition identifier"},
|
||||||
"start_date": {"type": "string", "description": "Requested start date"},
|
"start_date": {"type": "string", "description": "Requested start date"},
|
||||||
|
|
@ -495,6 +499,7 @@ class HrRecruitmentAutoDocWizard(models.TransientModel):
|
||||||
"secondary_skills": {"type": "list", "description": "Secondary or nice to have skills"},
|
"secondary_skills": {"type": "list", "description": "Secondary or nice to have skills"},
|
||||||
"budget": {"type": "string", "description": "Budget or salary range"},
|
"budget": {"type": "string", "description": "Budget or salary range"},
|
||||||
"experience_years": {"type": "float", "description": "Expected total years of experience"},
|
"experience_years": {"type": "float", "description": "Expected total years of experience"},
|
||||||
|
"job_category": {"type": "selection", "description": "Based on over all Job description which one matches more accurately give me the key: %s"%(category_dict)}
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_resume_prompt(self):
|
def _get_resume_prompt(self):
|
||||||
|
|
@ -1766,8 +1771,11 @@ class HrRecruitmentAutoDocWizard(models.TransientModel):
|
||||||
"secondary_skill_ids": [(6, 0, secondary_skills.ids)] if secondary_skills else False,
|
"secondary_skill_ids": [(6, 0, secondary_skills.ids)] if secondary_skills else False,
|
||||||
}
|
}
|
||||||
job_category = self._match_job_category(parsed_data, parsed_payload)
|
job_category = self._match_job_category(parsed_data, parsed_payload)
|
||||||
if job_category:
|
|
||||||
write_vals["job_category"] = job_category.id
|
if job_request and job_request.job_category:
|
||||||
|
if job_request.job_id and job_request.job_id.job_category != job_request.job_category:
|
||||||
|
job_request.job_id.job_category = job_request.job_category.id
|
||||||
|
elif job_category:
|
||||||
if job_request.job_id and job_request.job_id.job_category != job_category:
|
if job_request.job_id and job_request.job_id.job_category != job_category:
|
||||||
job_request.job_id.job_category = job_category.id
|
job_request.job_id.job_category = job_category.id
|
||||||
write_vals = {key: value for key, value in write_vals.items() if value not in (False, None, "")}
|
write_vals = {key: value for key, value in write_vals.items() if value not in (False, None, "")}
|
||||||
|
|
@ -1805,7 +1813,14 @@ class HrRecruitmentAutoDocWizard(models.TransientModel):
|
||||||
job_category = self._match_job_category(parsed_data, parsed_payload)
|
job_category = self._match_job_category(parsed_data, parsed_payload)
|
||||||
if job_category and job.job_category != job_category:
|
if job_category and job.job_category != job_category:
|
||||||
job.job_category = job_category.id
|
job.job_category = job_category.id
|
||||||
|
category_dict = {
|
||||||
|
str(category['id']): category['category_name']
|
||||||
|
for category in self.env['job.category'].search_read([], ['id', 'category_name'])
|
||||||
|
}
|
||||||
|
reverse_category = {v: k for k, v in category_dict.items()}
|
||||||
|
|
||||||
|
job_category = parsed_data.get("job_category")
|
||||||
|
job_category_id = reverse_category.get(job_category, job_category)
|
||||||
create_vals = {
|
create_vals = {
|
||||||
"job_id": job.id,
|
"job_id": job.id,
|
||||||
"company_id": self.env.company.id,
|
"company_id": self.env.company.id,
|
||||||
|
|
@ -1813,12 +1828,17 @@ class HrRecruitmentAutoDocWizard(models.TransientModel):
|
||||||
"requirements": parsed_data.get("requirements"),
|
"requirements": parsed_data.get("requirements"),
|
||||||
"target_from": self._parse_date_value(parsed_data.get("start_date")),
|
"target_from": self._parse_date_value(parsed_data.get("start_date")),
|
||||||
"target_to": self._parse_date_value(parsed_data.get("end_date")),
|
"target_to": self._parse_date_value(parsed_data.get("end_date")),
|
||||||
"job_category": job_category.id if job_category else False,
|
"job_category": int(job_category_id) if job_category_id and job_category_id.isdigit() else False,
|
||||||
|
"address_id":False,
|
||||||
|
"recruitment_type": 'external'
|
||||||
|
|
||||||
}
|
}
|
||||||
if request_id:
|
if request_id:
|
||||||
create_vals["recruitment_sequence"] = request_id
|
create_vals["recruitment_sequence"] = request_id
|
||||||
create_vals = {key: value for key, value in create_vals.items() if value not in (False, None, "")}
|
create_vals = {key: value for key, value in create_vals.items() if value not in (False, None, "")}
|
||||||
return job_request_model.create(create_vals), "created"
|
job_request = job_request_model.create(create_vals)
|
||||||
|
job_request.sudo().write({"address_id" : False})
|
||||||
|
return job_request, "created"
|
||||||
|
|
||||||
def _match_existing_job_position(self, job_title):
|
def _match_existing_job_position(self, job_title):
|
||||||
hr_job_model = self.env["hr.job"]
|
hr_job_model = self.env["hr.job"]
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
<field name="model">hr.recruitment.auto.doc.wizard</field>
|
<field name="model">hr.recruitment.auto.doc.wizard</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Parse Recruitment Documents" create="0" edit="1">
|
<form string="Parse Recruitment Documents" create="0" edit="1">
|
||||||
<header>
|
<!-- <header>-->
|
||||||
<button name="action_parse_documents" string="Parse Documents" type="object" class="btn-primary" invisible="not attachment_ids and not resume_file"/>
|
<!-- <button name="action_parse_documents" string="Parse Documents" type="object" class="btn-primary" invisible="not attachment_ids and not resume_file"/>-->
|
||||||
<!-- <button string="Close" special="cancel" class="btn-secondary"/>-->
|
<!--<!– <button string="Close" special="cancel" class="btn-secondary"/>–>-->
|
||||||
</header>
|
<!-- </header>-->
|
||||||
<sheet>
|
<sheet>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
|
|
@ -39,7 +39,15 @@
|
||||||
invisible="1"/>
|
invisible="1"/>
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
<group string="Uploaded Files">
|
<div class="text-end">
|
||||||
|
<button name="action_parse_documents"
|
||||||
|
string="Parse Documents"
|
||||||
|
type="object"
|
||||||
|
class="btn-primary"
|
||||||
|
invisible="not attachment_ids and not resume_file"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<group string="Uploaded Files" invisible="not line_ids">
|
||||||
<field name="line_ids" nolabel="1" readonly="1">
|
<field name="line_ids" nolabel="1" readonly="1">
|
||||||
<kanban class="o_kanban_small_column">
|
<kanban class="o_kanban_small_column">
|
||||||
<templates>
|
<templates>
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
'data/sequence.xml',
|
'data/sequence.xml',
|
||||||
'data/mail_template.xml',
|
'data/mail_template.xml',
|
||||||
'data/templates.xml',
|
'data/templates.xml',
|
||||||
|
'views/submission_share_history.xml',
|
||||||
'views/job_category.xml',
|
'views/job_category.xml',
|
||||||
'views/hr_location.xml',
|
'views/hr_location.xml',
|
||||||
'views/stages.xml',
|
'views/stages.xml',
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<t t-set="user_names"
|
<t t-set="user_names"
|
||||||
t-value="', '.join(object.user_id.mapped('name')) if object.user_id else 'Recruiter'"/>
|
t-value="', '.join(object.user_id.mapped('name')) if object.user_id else 'Recruiter'"/>
|
||||||
<t t-set="location_names"
|
<t t-set="location_names"
|
||||||
t-value="', '.join(object.locations.mapped('name')) if object.locations else 'N/A'"/>
|
t-value="', '.join(object.locations.mapped('location_name')) if object.locations else 'N/A'"/>
|
||||||
|
|
||||||
<div style="font-family: Arial, sans-serif; font-size: 14px; color: #333; line-height: 1.5; padding: 20px;">
|
<div style="font-family: Arial, sans-serif; font-size: 14px; color: #333; line-height: 1.5; padding: 20px;">
|
||||||
|
|
||||||
|
|
@ -669,14 +669,14 @@
|
||||||
<t t-set="locations">
|
<t t-set="locations">
|
||||||
<t t-if="object.hr_job_recruitment.locations">
|
<t t-if="object.hr_job_recruitment.locations">
|
||||||
<t t-set="locations_str"
|
<t t-set="locations_str"
|
||||||
t-value="', '.join(object.hr_job_recruitment.locations.mapped('name'))"/>
|
t-value="', '.join(object.hr_job_recruitment.locations.mapped('location_name'))"/>
|
||||||
<t t-set="locations" t-value="locations_str"/>
|
<t t-set="locations" t-value="locations_str"/>
|
||||||
</t>
|
</t>
|
||||||
<t t-else="">
|
<t t-else="">
|
||||||
<t t-set="locations" t-value="''"/>
|
<t t-set="locations" t-value="''"/>
|
||||||
</t>
|
</t>
|
||||||
</t>
|
</t>
|
||||||
<div style="margin: 0; padding: 0; font-size: 13px; line-height: 1.6;">
|
<div style="margin: 0; padding: 0; font-size: 13px; line-height: 1.6; background:#ffffff; color:#000000;">
|
||||||
<p>Dear Sir/Madam,</p>
|
<p>Dear Sir/Madam,</p>
|
||||||
<p>Please find the applicant details below for your review.</p>
|
<p>Please find the applicant details below for your review.</p>
|
||||||
<table style="width: 100%; border-collapse: collapse; margin: 16px 0;">
|
<table style="width: 100%; border-collapse: collapse; margin: 16px 0;">
|
||||||
|
|
@ -784,10 +784,10 @@
|
||||||
<field name="body_html" type="html">
|
<field name="body_html" type="html">
|
||||||
<t t-set="job_name" t-value="object.job_id.name or object.name or object.display_name or ''"/>
|
<t t-set="job_name" t-value="object.job_id.name or object.name or object.display_name or ''"/>
|
||||||
<t t-set="recruitment_name" t-value="object.recruitment_sequence or object.display_name or ''"/>
|
<t t-set="recruitment_name" t-value="object.recruitment_sequence or object.display_name or ''"/>
|
||||||
<t t-set="locations" t-value="', '.join(object.locations.mapped('name')) if object.locations else ''"/>
|
<t t-set="locations" t-value="', '.join(object.locations.mapped('location_name')) if object.locations else ''"/>
|
||||||
<t t-set="primary_skills" t-value="', '.join(object.skill_ids.mapped('name')) if object.skill_ids else ''"/>
|
<t t-set="primary_skills" t-value="', '.join(object.skill_ids.mapped('name')) if object.skill_ids else ''"/>
|
||||||
<t t-set="secondary_skills" t-value="', '.join(object.secondary_skill_ids.mapped('name')) if object.secondary_skill_ids else ''"/>
|
<t t-set="secondary_skills" t-value="', '.join(object.secondary_skill_ids.mapped('name')) if object.secondary_skill_ids else ''"/>
|
||||||
<div style="margin: 0; padding: 0; font-size: 13px; line-height: 1.6;">
|
<div style="margin: 0; padding: 0; font-size: 13px; line-height: 1.6; background:#ffffff; color:#000000;">
|
||||||
<p>Dear Sir/Madam,</p>
|
<p>Dear Sir/Madam,</p>
|
||||||
<p>Please find the job description and hiring details below for your review and sourcing support.</p>
|
<p>Please find the job description and hiring details below for your review and sourcing support.</p>
|
||||||
<table style="width: 100%; border-collapse: collapse; margin: 16px 0;">
|
<table style="width: 100%; border-collapse: collapse; margin: 16px 0;">
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
from . import submission_share_history
|
||||||
from . import hr_recruitment
|
from . import hr_recruitment
|
||||||
from . import hr_job_recruitment
|
from . import hr_job_recruitment
|
||||||
from . import stages
|
from . import stages
|
||||||
from . import applicant_request_forms
|
from . import applicant_request_forms
|
||||||
from . import hr_applicant_stage_comment
|
from . import hr_applicant_stage_comment
|
||||||
from . import hr_applicant
|
from . import hr_applicant
|
||||||
from . import hr_job
|
from . import hr_job
|
||||||
from . import res_partner
|
from . import res_partner
|
||||||
from . import candidate_experience
|
from . import candidate_experience
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,30 @@ class HRApplicant(models.Model):
|
||||||
)
|
)
|
||||||
stage_comment_count = fields.Integer(compute='_compute_stage_comment_count')
|
stage_comment_count = fields.Integer(compute='_compute_stage_comment_count')
|
||||||
stage_comment_tooltips = fields.Json(compute='_compute_stage_comment_tooltips')
|
stage_comment_tooltips = fields.Json(compute='_compute_stage_comment_tooltips')
|
||||||
|
submission_tracker = fields.One2many('recruitment.share.tracker','applicant_id')
|
||||||
|
submission_count = fields.Integer(
|
||||||
|
string="Submission Count",
|
||||||
|
compute="_compute_submission_count",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _compute_submission_count(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.submission_count = len(rec.submission_tracker)
|
||||||
|
|
||||||
|
def action_open_submissions_wizard(self):
|
||||||
|
self.ensure_one()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"type": "ir.actions.act_window",
|
||||||
|
"name": "Submission History",
|
||||||
|
"res_model": "recruitment.share.tracker",
|
||||||
|
"view_mode": "list",
|
||||||
|
"views": [
|
||||||
|
(self.env.ref("hr_recruitment_extended.view_recruitment_share_tracker_list_popup").id, "list"),
|
||||||
|
],
|
||||||
|
"domain": [("applicant_id", "=", self.id)],
|
||||||
|
"target": "new",
|
||||||
|
}
|
||||||
|
|
||||||
@api.depends('is_on_hold')
|
@api.depends('is_on_hold')
|
||||||
def _compute_hold_state(self):
|
def _compute_hold_state(self):
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,7 @@ class HRJobRecruitment(models.Model):
|
||||||
requested_by = fields.Many2one('res.partner', string="Requested By",
|
requested_by = fields.Many2one('res.partner', string="Requested By",
|
||||||
default=lambda self: self.env.user.partner_id, domain="[('contact_type','=',recruitment_type)]", tracking=True)
|
default=lambda self: self.env.user.partner_id, domain="[('contact_type','=',recruitment_type)]", tracking=True)
|
||||||
|
|
||||||
|
submission_tracker = fields.One2many('recruitment.share.tracker','job_recruitment_id')
|
||||||
def action_toggle_chatter_visibility(self):
|
def action_toggle_chatter_visibility(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
record.hide_chatter_suggestion = not record.hide_chatter_suggestion
|
record.hide_chatter_suggestion = not record.hide_chatter_suggestion
|
||||||
|
|
@ -405,6 +406,7 @@ class HRJobRecruitment(models.Model):
|
||||||
'default_template_id': self.env.ref(
|
'default_template_id': self.env.ref(
|
||||||
'hr_recruitment_extended.job_recruitment_share_email_template'
|
'hr_recruitment_extended.job_recruitment_share_email_template'
|
||||||
).id,
|
).id,
|
||||||
|
'default_is_job_recruitment': True,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class RecruitmentShareTracker(models.Model):
|
||||||
|
_name = "recruitment.share.tracker"
|
||||||
|
_description = "Recruitment Share Tracker"
|
||||||
|
_order = "date desc, id desc"
|
||||||
|
|
||||||
|
date = fields.Datetime(
|
||||||
|
string="Date",
|
||||||
|
required=True,
|
||||||
|
default=fields.Datetime.now,
|
||||||
|
)
|
||||||
|
|
||||||
|
share_type = fields.Selection(
|
||||||
|
[
|
||||||
|
("job", "Job"),
|
||||||
|
("applicant", "Applicant"),
|
||||||
|
],
|
||||||
|
string="Share Type",
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
reference = fields.Char(
|
||||||
|
string="Reference",
|
||||||
|
)
|
||||||
|
|
||||||
|
applicant_id = fields.Many2one(
|
||||||
|
"hr.applicant",
|
||||||
|
string="Applicant",
|
||||||
|
ondelete="set null",
|
||||||
|
)
|
||||||
|
|
||||||
|
job_recruitment_id = fields.Many2one(
|
||||||
|
"hr.job.recruitment",
|
||||||
|
string="Job Position",
|
||||||
|
ondelete="set null",
|
||||||
|
)
|
||||||
|
|
||||||
|
email_from = fields.Char(
|
||||||
|
string="Email From",
|
||||||
|
)
|
||||||
|
|
||||||
|
email_to = fields.Char(
|
||||||
|
string="Email To",
|
||||||
|
)
|
||||||
|
|
||||||
|
is_client_submission = fields.Boolean(
|
||||||
|
string="Client Submission",
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
access_hr_location,hr.location,model_hr_location,base.group_user,1,1,1,1
|
access_hr_location,hr.location,model_hr_location,base.group_user,1,1,1,1
|
||||||
|
|
||||||
|
access_recruitment_share_tracker_user,recruitment.share.tracker.user,model_recruitment_share_tracker,hr_recruitment.group_hr_recruitment_user,1,1,1,1
|
||||||
|
|
||||||
access_job_category_user,job.category.user,model_job_category,base.group_user,1,0,0,0
|
access_job_category_user,job.category.user,model_job_category,base.group_user,1,0,0,0
|
||||||
access_job_category_manager,job.category.manager,model_job_category,hr_recruitment.group_hr_recruitment_user,1,1,1,1
|
access_job_category_manager,job.category.manager,model_job_category,hr_recruitment.group_hr_recruitment_user,1,1,1,1
|
||||||
|
|
@ -35,4 +36,5 @@ access_applicant_stage_comment_wizard,applicant.stage.comment.wizard.user,model_
|
||||||
access_hr_application_public,hr.applicant.public.access,hr_recruitment.model_hr_applicant,base.group_public,1,0,0,0
|
access_hr_application_public,hr.applicant.public.access,hr_recruitment.model_hr_applicant,base.group_public,1,0,0,0
|
||||||
access_hr_application_group_hr,hr.applicant.hr.access,hr_recruitment.model_hr_applicant,hr.group_hr_manager,1,1,0,0
|
access_hr_application_group_hr,hr.applicant.hr.access,hr_recruitment.model_hr_applicant,hr.group_hr_manager,1,1,0,0
|
||||||
access_applicant_request_forms_hr_user,access.applicant.request.forms.hr.user,model_applicant_request_forms,hr.group_hr_user,1,1,1,1
|
access_applicant_request_forms_hr_user,access.applicant.request.forms.hr.user,model_applicant_request_forms,hr.group_hr_user,1,1,1,1
|
||||||
access_hr_skill,access.hr.skill.user,hr_skills.model_hr_skill,base.group_public,1,0,0,0
|
access_hr_skill,access.hr.skill.user,hr_skills.model_hr_skill,base.group_public,1,0,0,0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
|
@ -90,6 +90,10 @@
|
||||||
<button name="action_open_stage_comment_wizard" type="object" class="oe_stat_button" icon="fa-comments">
|
<button name="action_open_stage_comment_wizard" type="object" class="oe_stat_button" icon="fa-comments">
|
||||||
<field name="stage_comment_count" widget="statinfo" string="Stage Notes"/>
|
<field name="stage_comment_count" widget="statinfo" string="Stage Notes"/>
|
||||||
</button>
|
</button>
|
||||||
|
<button name="action_open_submissions_wizard" type="object" class="oe_stat_button" icon="fa-file-text-o" invisible="not submission_tracker">
|
||||||
|
<field name="submission_count" widget="statinfo" string="Share History"/>
|
||||||
|
</button>
|
||||||
|
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//page[@name='application_details']/group[1]" position="after">
|
<xpath expr="//page[@name='application_details']/group[1]" position="after">
|
||||||
<group string="Client Submission">
|
<group string="Client Submission">
|
||||||
|
|
|
||||||
|
|
@ -110,10 +110,10 @@
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="job_category" force_save="1"/>
|
<field name="job_category" force_save="1" placeholder="Select Category"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="job_priority"/>
|
<field name="job_priority" placeholder="Select Priority"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
|
|
@ -201,6 +201,20 @@
|
||||||
<separator string="Process Details"/>
|
<separator string="Process Details"/>
|
||||||
<field name="job_details" nolabel="1"/>
|
<field name="job_details" nolabel="1"/>
|
||||||
</page>
|
</page>
|
||||||
|
<page string="Submission History" name="submission_tracker" invisible="not submission_tracker">
|
||||||
|
<field name="submission_tracker">
|
||||||
|
<list create="0" edit="0" delete="0">
|
||||||
|
<field name="date"/>
|
||||||
|
<field name="share_type" column_invisible="1"/>
|
||||||
|
<field name="reference"/>
|
||||||
|
<field name="applicant_id" column_invisible="1"/>
|
||||||
|
<field name="job_recruitment_id" column_invisible="1"/>
|
||||||
|
<field name="email_from"/>
|
||||||
|
<field name="email_to"/>
|
||||||
|
<field name="is_client_submission" column_invisible="1"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<chatter open_attachments="True" invisible="hide_chatter_suggestion"/>
|
<chatter open_attachments="True" invisible="hide_chatter_suggestion"/>
|
||||||
|
|
@ -429,6 +443,7 @@
|
||||||
<field name="name">Job Positions Recruitment</field>
|
<field name="name">Job Positions Recruitment</field>
|
||||||
<field name="res_model">hr.job.recruitment</field>
|
<field name="res_model">hr.job.recruitment</field>
|
||||||
<field name="view_mode">kanban,list,form</field>
|
<field name="view_mode">kanban,list,form</field>
|
||||||
|
<field name="domain"></field>
|
||||||
<field name="search_view_id" ref="view_job_recruitment_filter"/>
|
<field name="search_view_id" ref="view_job_recruitment_filter"/>
|
||||||
<field name="help" type="html">
|
<field name="help" type="html">
|
||||||
<p class="o_view_nocontent_smiling_face">
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
|
@ -446,6 +461,7 @@
|
||||||
<field name="res_model">hr.job.recruitment</field>
|
<field name="res_model">hr.job.recruitment</field>
|
||||||
<field name="view_mode">kanban,list,form,search</field>
|
<field name="view_mode">kanban,list,form,search</field>
|
||||||
<field name="search_view_id" ref="view_job_recruitment_filter"/>
|
<field name="search_view_id" ref="view_job_recruitment_filter"/>
|
||||||
|
<field name="domain"></field>
|
||||||
<field name="context">{"search_default_open_status":1,"search_default_my_assignments":1}</field>
|
<field name="context">{"search_default_open_status":1,"search_default_my_assignments":1}</field>
|
||||||
<field name="help" type="html">
|
<field name="help" type="html">
|
||||||
<p class="o_view_nocontent_smiling_face">
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
|
@ -482,7 +498,7 @@
|
||||||
active="0"
|
active="0"
|
||||||
sequence="2"/>
|
sequence="2"/>
|
||||||
|
|
||||||
<menuitem name="JP"
|
<menuitem name="Job Position"
|
||||||
id="menu_hr_job_descriptions"
|
id="menu_hr_job_descriptions"
|
||||||
parent="hr_recruitment.menu_hr_recruitment_root"
|
parent="hr_recruitment.menu_hr_recruitment_root"
|
||||||
action="action_hr_job_recruitment_awaiting_published"
|
action="action_hr_job_recruitment_awaiting_published"
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@
|
||||||
<xpath expr="//notebook" position="before">
|
<xpath expr="//notebook" position="before">
|
||||||
<group>
|
<group>
|
||||||
<field name="department_id"/>
|
<field name="department_id"/>
|
||||||
<field name="job_category"/>
|
<field name="job_category" placeholder="Select Category"/>
|
||||||
</group>
|
</group>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//notebook" position="inside">
|
<xpath expr="//notebook" position="inside">
|
||||||
|
|
@ -338,6 +338,7 @@
|
||||||
<record id="hr_recruitment.action_hr_candidate" model="ir.actions.act_window">
|
<record id="hr_recruitment.action_hr_candidate" model="ir.actions.act_window">
|
||||||
<field name="search_view_id" ref="hr_recruitment.hr_candidate_view_search"/>
|
<field name="search_view_id" ref="hr_recruitment.hr_candidate_view_search"/>
|
||||||
<field name="context">{'search_default_my_candidates': 1,'active_test': False}</field>
|
<field name="context">{'search_default_my_candidates': 1,'active_test': False}</field>
|
||||||
|
<field name="view_mode">kanban,list,form,activity</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
<attribute name="required">1</attribute>
|
<attribute name="required">1</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='job_id']" position="after">
|
<xpath expr="//field[@name='job_id']" position="after">
|
||||||
<field name="job_category" required="1" readonly="state not in ['draft']"/>
|
<field name="job_category" placeholder="Select Category" required="1" readonly="state not in ['draft']"/>
|
||||||
<field name="hr_job_recruitment" string="Job Recruitment ID" readonly="not is_hr or state == 'jd_created'" force_save="1" invisible="state not in ['final','jd_created']" options="{'no_quick_create': True, 'no_create_edit': True, 'no_open': True}"/>
|
<field name="hr_job_recruitment" string="Job Recruitment ID" readonly="not is_hr or state == 'jd_created'" force_save="1" invisible="state not in ['final','jd_created']" options="{'no_quick_create': True, 'no_create_edit': True, 'no_open': True}"/>
|
||||||
<field name="recruitment_status" widget="statusbar" readonly="1" force_save="1" invisible="not hr_job_recruitment" options="{'clickable': '1', 'fold_field': 'fold'}"/>
|
<field name="recruitment_status" widget="statusbar" readonly="1" force_save="1" invisible="not hr_job_recruitment" options="{'clickable': '1', 'fold_field': 'fold'}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_recruitment_share_tracker_list_popup" model="ir.ui.view">
|
||||||
|
<field name="name">recruitment.share.tracker.popup.list</field>
|
||||||
|
<field name="model">recruitment.share.tracker</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list create="0"
|
||||||
|
edit="0"
|
||||||
|
delete="0"
|
||||||
|
open_form_view="0">
|
||||||
|
<field name="date"/>
|
||||||
|
<field name="share_type"/>
|
||||||
|
<field name="reference"/>
|
||||||
|
<field name="email_from"/>
|
||||||
|
<field name="email_to"/>
|
||||||
|
<field name="is_client_submission"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
|
|
@ -1,65 +1,128 @@
|
||||||
from odoo import models, fields, api
|
from odoo import models, fields, api
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class ClientSubmissionsMailTemplateWizard(models.TransientModel):
|
class ClientSubmissionsMailTemplateWizard(models.TransientModel):
|
||||||
_name = 'client.submission.mails.template.wizard'
|
_name = 'client.submission.mails.template.wizard'
|
||||||
_description = 'Client Submission Mails Template Wizard'
|
_description = 'Client Submission Mails Template Wizard'
|
||||||
|
|
||||||
template_id = fields.Many2one('mail.template', string='Email Template')
|
template_id = fields.Many2one('mail.template', string='Email Template')
|
||||||
submit_date = fields.Date(string='Submission Date', required=True, default=fields.Date.today())
|
submit_date = fields.Date(string='Submission Date', required=True, default=fields.Date.today())
|
||||||
send_email_from_odoo = fields.Boolean(string="Send Email From Odoo", default=False)
|
is_job_recruitment = fields.Boolean(string='Is Job Recruitment', default=False)
|
||||||
|
is_client_submission = fields.Boolean(string='Is Client Submission?', default=False)
|
||||||
|
send_email_from_odoo = fields.Boolean(string="Send Email", default=True)
|
||||||
email_from = fields.Char('Email From')
|
email_from = fields.Char('Email From')
|
||||||
email_to = fields.Char('Email To')
|
email_to = fields.Char('Email To')
|
||||||
email_cc = fields.Text('Email CC')
|
email_cc = fields.Text('Email CC')
|
||||||
email_subject = fields.Char()
|
email_subject = fields.Char()
|
||||||
email_body = fields.Html(
|
email_body = fields.Html(
|
||||||
'Body', render_engine='qweb', render_options={'post_process': True},
|
'Body',
|
||||||
prefetch=True, translate=True, sanitize='email_outgoing',
|
render_engine='qweb',
|
||||||
|
render_options={'post_process': True},
|
||||||
|
prefetch=True,
|
||||||
|
translate=True,
|
||||||
|
sanitize='email_outgoing',
|
||||||
)
|
)
|
||||||
|
|
||||||
@api.onchange('template_id')
|
@api.onchange('template_id')
|
||||||
def _onchange_template_id(self):
|
def _onchange_template_id(self):
|
||||||
""" Update the email body and recipients based on the selected template. """
|
if not self.template_id:
|
||||||
if self.template_id:
|
return
|
||||||
record_id = self.env.context.get('active_id')
|
|
||||||
if record_id:
|
|
||||||
record = self.env[self.template_id.model].browse(record_id)
|
|
||||||
|
|
||||||
if not record.exists():
|
record_id = self.env.context.get('active_id')
|
||||||
raise UserError("The record does not exist or is not accessible.")
|
active_model = self.env.context.get('active_model')
|
||||||
|
|
||||||
# Fetch email template
|
if not record_id:
|
||||||
email_template = self.env['mail.template'].browse(self.template_id.id)
|
return
|
||||||
|
|
||||||
if not email_template:
|
record = self.env[active_model].browse(record_id)
|
||||||
raise UserError("Email template not found.")
|
|
||||||
|
|
||||||
self.email_from = record.user_id.partner_id.email
|
self.email_from = record.user_id.partner_id.email
|
||||||
self.email_to = record.requested_by.email
|
|
||||||
self.email_body = email_template.body_html # Assign the rendered email bodyc
|
|
||||||
self.email_subject = email_template.subject
|
|
||||||
|
|
||||||
|
if active_model == 'hr.applicant':
|
||||||
|
self.email_to = record.hr_job_recruitment.requested_by.email
|
||||||
|
else:
|
||||||
|
self.email_to = record.requested_by.email
|
||||||
|
|
||||||
|
# Render subject
|
||||||
|
self.email_subject = self.template_id._render_field(
|
||||||
|
'subject',
|
||||||
|
[record.id],
|
||||||
|
)[record.id]
|
||||||
|
|
||||||
|
# Render body
|
||||||
|
self.email_body = self.template_id._render_field(
|
||||||
|
'body_html',
|
||||||
|
[record.id],
|
||||||
|
)[record.id]
|
||||||
|
|
||||||
def action_send_email(self):
|
def action_send_email(self):
|
||||||
""" Send email to the selected partners """
|
"""Send email and create recruitment share tracker."""
|
||||||
|
self.ensure_one()
|
||||||
|
|
||||||
record_id = self.env.context.get('active_id')
|
record_id = self.env.context.get('active_id')
|
||||||
for rec in self:
|
model_name = self.env.context.get('active_model')
|
||||||
record = self.env[self.template_id.model].browse(record_id)
|
|
||||||
if rec.send_email_from_odoo:
|
record = self.env[self.template_id.model].browse(record_id)
|
||||||
template = self.env.ref('hr_recruitment_extended.application_client_submission_email_template')
|
|
||||||
values = {
|
tracker_values = {
|
||||||
'email_from': rec.email_from,
|
'date': fields.Datetime.now(),
|
||||||
'email_to': rec.email_to,
|
'is_client_submission': self.is_client_submission,
|
||||||
'email_cc': rec.email_cc,
|
}
|
||||||
'subject' : rec.email_subject,
|
|
||||||
'body_html': rec.email_body,
|
if model_name == 'hr.applicant':
|
||||||
}
|
tracker_values.update({
|
||||||
render_ctx = dict(client_name=record.hr_job_recruitment.requested_by.name)
|
'share_type': 'applicant',
|
||||||
# Use 'with_context' to override the email template fields dynamically
|
'reference': "%s/%s" % (
|
||||||
template.sudo().with_context(**render_ctx).send_mail(self.env.context.get('active_id'),email_values=values, force_send=True)
|
record.hr_job_recruitment.recruitment_sequence,
|
||||||
|
record.candidate_id.candidate_sequence,
|
||||||
|
),
|
||||||
|
'applicant_id': record.id,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
tracker_values.update({
|
||||||
|
'share_type': 'job',
|
||||||
|
'reference': record.recruitment_sequence,
|
||||||
|
'job_recruitment_id': record.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
if self.send_email_from_odoo:
|
||||||
|
# Use the selected template
|
||||||
|
template = self.template_id
|
||||||
|
|
||||||
|
values = {
|
||||||
|
'email_from': self.email_from,
|
||||||
|
'email_to': self.email_to,
|
||||||
|
'email_cc': self.email_cc,
|
||||||
|
'subject': self.email_subject,
|
||||||
|
'body_html': self.email_body,
|
||||||
|
}
|
||||||
|
|
||||||
|
if model_name == 'hr.applicant':
|
||||||
|
client_name = record.hr_job_recruitment.requested_by.name
|
||||||
|
else:
|
||||||
|
client_name = record.requested_by.name
|
||||||
|
|
||||||
|
render_ctx = {
|
||||||
|
'client_name': client_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
tracker_values['email_from'] = self.email_from
|
||||||
|
tracker_values['email_to'] = self.email_to
|
||||||
|
|
||||||
|
template.sudo().with_context(**render_ctx).send_mail(
|
||||||
|
record.id,
|
||||||
|
email_values=values,
|
||||||
|
force_send=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.is_client_submission and model_name == 'hr.applicant':
|
||||||
record.sudo().write({
|
record.sudo().write({
|
||||||
'submitted_to_client': True,
|
'submitted_to_client': True,
|
||||||
'client_submission_date': rec.submit_date,
|
'client_submission_date': self.submit_date,
|
||||||
'submitted_stage': record.recruitment_stage_id.id,
|
'submitted_stage': record.recruitment_stage_id.id,
|
||||||
})
|
})
|
||||||
return {'type': 'ir.actions.act_window_close'} # Close wizard after sending
|
|
||||||
|
self.env['recruitment.share.tracker'].sudo().create(tracker_values)
|
||||||
|
|
||||||
|
return {'type': 'ir.actions.act_window_close'}
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
<form>
|
<form>
|
||||||
<group>
|
<group>
|
||||||
<field name="submit_date"/>
|
<field name="submit_date"/>
|
||||||
|
<field name="is_job_recruitment" invisible="1"/>
|
||||||
|
<field name="is_client_submission" invisible="is_job_recruitment"/>
|
||||||
<field name="send_email_from_odoo"/>
|
<field name="send_email_from_odoo"/>
|
||||||
<separator string="Section Title"/>
|
<separator string="Section Title"/>
|
||||||
<field name="template_id" options="{'no_create': True}" invisible="not send_email_from_odoo" required="send_email_from_odoo" readonly="1" force_save="1"/>
|
<field name="template_id" options="{'no_create': True}" invisible="not send_email_from_odoo" required="send_email_from_odoo" readonly="1" force_save="1"/>
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
'data': [
|
'data': [
|
||||||
'security/hr_resignation_security.xml',
|
'security/hr_resignation_security.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
|
'security/resignation_groups.xml',
|
||||||
'data/data.xml',
|
'data/data.xml',
|
||||||
'data/ir_sequence_data.xml',
|
'data/ir_sequence_data.xml',
|
||||||
'data/ir_cron_data.xml',
|
'data/ir_cron_data.xml',
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ class HrContract(models.Model):
|
||||||
"""Get the default notice period from the configuration.
|
"""Get the default notice period from the configuration.
|
||||||
:return: The default notice period in days.
|
:return: The default notice period in days.
|
||||||
:rtype: int """
|
:rtype: int """
|
||||||
return self.env['ir.config_parameter'].get_param(
|
return self.env['ir.config_parameter'].sudo().get_param(
|
||||||
'hr_employee_updation.no_of_days') if self.env[
|
'hr_employee_updation.no_of_days') if self.env[
|
||||||
'ir.config_parameter'].get_param(
|
'ir.config_parameter'].sudo().get_param(
|
||||||
'hr_employee_updation.notice_period') else 0
|
'hr_employee_updation.notice_period') else 0
|
||||||
|
|
||||||
notice_days = fields.Integer(string="Notice Period",
|
notice_days = fields.Integer(string="Notice Period",
|
||||||
|
|
|
||||||
|
|
@ -167,8 +167,33 @@ class HrResignation(models.Model):
|
||||||
admin_checklist_submitted = fields.Boolean(tracking=True)
|
admin_checklist_submitted = fields.Boolean(tracking=True)
|
||||||
hr_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')
|
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')
|
@api.depends('employee_id')
|
||||||
def _compute_user_rights(self):
|
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"
|
<field name="employee_id"
|
||||||
readonly="change_employee == False or state != 'draft'"/>
|
readonly="change_employee == False or state != 'draft'"/>
|
||||||
<field name="department_id"/>
|
<field name="department_id"/>
|
||||||
|
<field name="applied_date"/>
|
||||||
<field name="employee_contract" invisible="state == 'draft'"/>
|
<field name="employee_contract" invisible="state == 'draft'"/>
|
||||||
<field name="emp_responded" readonly="1" force_save="1" invisible="resignation_type != 'abosconded'"/>
|
<field name="emp_responded" readonly="1" force_save="1" invisible="resignation_type != 'abosconded'"/>
|
||||||
<field name="show_withdraw" invisible="not is_hr"/>
|
<field name="show_withdraw" invisible="not is_hr"/>
|
||||||
|
|
@ -173,12 +174,30 @@
|
||||||
<field name="reason"
|
<field name="reason"
|
||||||
readonly="state != 'draft'"/>
|
readonly="state != 'draft'"/>
|
||||||
</group>
|
</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">
|
<group string="Checklist Submission Status">
|
||||||
<field name="manager_checklist_submitted" string="Manager" readonly="1" force_save="1"/>
|
<field name="manager_checklist_status" string="Manager" widget="badge"
|
||||||
<field name="it_checklist_submitted" string="IT Manager" readonly="1" force_save="1"/>
|
decoration-success="manager_checklist_status == 'completed'"
|
||||||
<field name="finance_checklist_submitted" string="Finance" readonly="1" force_save="1"/>
|
decoration-warning="manager_checklist_status == 'pending'"/>
|
||||||
<field name="admin_checklist_submitted" string="Admin" readonly="1" force_save="1"/>
|
<field name="it_checklist_status" string="IT Manager" widget="badge"
|
||||||
<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']"/>
|
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>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
|
|
@ -186,7 +205,8 @@
|
||||||
<group>
|
<group>
|
||||||
<field name="emp_comments" readonly="not is_emp" string="Employee"/>
|
<field name="emp_comments" readonly="not is_emp" string="Employee"/>
|
||||||
<field name="manager_comments" readonly="not is_manager" string="Manager"/>
|
<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="it_manager_comments" readonly="not is_it_manager" string="IT Manager"/>
|
||||||
<field name="admin_comments" readonly="not is_admin" string="Admin"/>
|
<field name="admin_comments" readonly="not is_admin" string="Admin"/>
|
||||||
<field name="hr_comments" readonly="not is_hr" string="HR"/>
|
<field name="hr_comments" readonly="not is_hr" string="HR"/>
|
||||||
|
|
@ -387,7 +407,7 @@
|
||||||
<!-- Menu item for Approved Resignation -->
|
<!-- Menu item for Approved Resignation -->
|
||||||
<menuitem id="hr_resignation_menu_approved_request"
|
<menuitem id="hr_resignation_menu_approved_request"
|
||||||
parent="hr_resignation_menu_root"
|
parent="hr_resignation_menu_root"
|
||||||
name="Approved Resignation"
|
name="Resignation Status"
|
||||||
action="hr_resignation_approved_action"
|
action="hr_resignation_approved_action"
|
||||||
groups="hr.group_hr_user"
|
groups="hr.group_hr_user"
|
||||||
sequence="4"/>
|
sequence="4"/>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</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_root" name="Pre-Resignation" parent="menu_hr_resignation_configurations" sequence="100"/>
|
||||||
|
|
||||||
<menuitem id="menu_pre_resignation_requirements" name="Requirements Proceedings"
|
<menuitem id="menu_pre_resignation_requirements" name="Requirements Proceedings"
|
||||||
|
|
|
||||||
|
|
@ -109,9 +109,27 @@
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hrms-icon-button.primary {
|
/*.hrms-icon-button.primary {*/
|
||||||
|
/* background: #16a34a;*/
|
||||||
|
/* border-color: #22c55e;*/
|
||||||
|
/*}*/
|
||||||
|
|
||||||
|
.hrms-icon-button.checkin {
|
||||||
background: #16a34a;
|
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 {
|
.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() {
|
raiseHelpdeskTicket() {
|
||||||
window.open(
|
window.open('/helpdesk/new', '_blank');
|
||||||
'/helpdesk/new',
|
|
||||||
'helpdesk',
|
|
||||||
'width=1200,height=800,resizable=yes,scrollbars=yes'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleAttendance() {
|
async toggleAttendance() {
|
||||||
|
|
@ -309,6 +312,9 @@ class HrmsEmployeeDashboard extends Component {
|
||||||
}
|
}
|
||||||
this.notification.add(response.message, { type: "success" });
|
this.notification.add(response.message, { type: "success" });
|
||||||
await this.loadData();
|
await this.loadData();
|
||||||
|
setTimeout(() =>{
|
||||||
|
window.location.reload();
|
||||||
|
}, 500);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.notification.add("Unable to update attendance", { type: "danger" });
|
this.notification.add("Unable to update attendance", { type: "danger" });
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,21 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="hrms-employee-actions">
|
<div class="hrms-employee-actions">
|
||||||
<div class="hrms-action-buttons">
|
<div class="hrms-action-buttons">
|
||||||
<button class="hrms-icon-button primary" t-on-click="toggleAttendance" t-att-title="statusText">
|
<!-- <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'"/>
|
<!-- <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"/>
|
<span t-esc="statusText"/>
|
||||||
</button>
|
</button>
|
||||||
<button class="hrms-icon-button" t-on-click="downloadPayslip" title="Download Payslip">
|
<button class="hrms-icon-button" t-on-click="downloadPayslip" title="Download Payslip">
|
||||||
<i class="fa fa-download"/>
|
<i class="fa fa-download"/>
|
||||||
<span>Payslip</span>
|
<span>Payslip</span>
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,16 @@
|
||||||
'depends': ['base', 'hr','hr_employee_extended'],
|
'depends': ['base', 'hr','hr_employee_extended'],
|
||||||
|
|
||||||
'data': [
|
'data': [
|
||||||
|
# 'data/reminder_corn.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
|
'security/security_groups.xml',
|
||||||
|
'security/performace_record_rules.xml',
|
||||||
'views/employee_appraisal.xml',
|
'views/employee_appraisal.xml',
|
||||||
'views/employee_evalutor.xml',
|
'views/employee_evalutor.xml',
|
||||||
'views/employee_template_appraisal.xml',
|
'views/employee_template_appraisal.xml',
|
||||||
'views/hr_notice_appraisal.xml',
|
'views/hr_notice_appraisal.xml',
|
||||||
'views/stage_config.xml',
|
'views/stage_config.xml',
|
||||||
|
'views/employee_pip.xml',
|
||||||
'Wizard/cancel_wizard_hr.xml',
|
'Wizard/cancel_wizard_hr.xml',
|
||||||
'Wizard/postpone_hr_appraisal.xml',
|
'Wizard/postpone_hr_appraisal.xml',
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,6 @@ from . import employee_appraisal
|
||||||
from . import apprasial_conf
|
from . import apprasial_conf
|
||||||
from . import kpi_kra
|
from . import kpi_kra
|
||||||
from . import hr_notice_appraisal
|
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):
|
class AppraisalYear(models.Model):
|
||||||
_name = 'employee.appraisal.year'
|
_name = 'employee.appraisal.year'
|
||||||
|
|
@ -9,8 +13,8 @@ class AppraisalYear(models.Model):
|
||||||
year = fields.Integer(string="Performance Period")
|
year = fields.Integer(string="Performance Period")
|
||||||
appraisal_name_id = fields.Char(string="Appraisal Type")
|
appraisal_name_id = fields.Char(string="Appraisal Type")
|
||||||
appraisal_name = fields.Char(string="Appraisal Name")
|
appraisal_name = fields.Char(string="Appraisal Name")
|
||||||
start_month = fields.Datetime('Starting Month')
|
start_month = fields.Date('Starting Month')
|
||||||
end_month = fields.Datetime('End Month')
|
end_month = fields.Date('End Month')
|
||||||
active = fields.Boolean(default=True)
|
active = fields.Boolean(default=True)
|
||||||
year_seq = fields.Integer(string="Sequence")
|
year_seq = fields.Integer(string="Sequence")
|
||||||
appraisal_type_id = fields.Many2one(
|
appraisal_type_id = fields.Many2one(
|
||||||
|
|
@ -18,6 +22,55 @@ class AppraisalYear(models.Model):
|
||||||
string="Appraisal Type"
|
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):
|
class EmployeeAppraisalType(models.Model):
|
||||||
_name = 'employee.appraisal.type'
|
_name = 'employee.appraisal.type'
|
||||||
_description = 'Employee Appraisal Type'
|
_description = 'Employee Appraisal Type'
|
||||||
|
|
@ -36,7 +89,8 @@ class AppraisalTemplate(models.Model):
|
||||||
|
|
||||||
name = fields.Char(string="Name")
|
name = fields.Char(string="Name")
|
||||||
employee_evaluator_name_id = fields.Many2one('employee.appraisal.evaluator', string="Employee Appraisal Evaluator")
|
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")
|
||||||
|
image_template = fields.Image(related='employee_eva_id.image_1920', string="Image")
|
||||||
hr_employee_id = fields.Many2one('hr.employee',string="Employee HR Employee")
|
hr_employee_id = fields.Many2one('hr.employee',string="Employee HR Employee")
|
||||||
employee_department_id = fields.Many2one('hr.department',string="Department")
|
employee_department_id = fields.Many2one('hr.department',string="Department")
|
||||||
company_id = fields.Many2one('res.company', string="Company",default=lambda self: self.env.company)
|
company_id = fields.Many2one('res.company', string="Company",default=lambda self: self.env.company)
|
||||||
|
|
@ -69,39 +123,40 @@ class AppraisalTemplate(models.Model):
|
||||||
rec.kra_ids.mapped('kra_weightage'))
|
rec.kra_ids.mapped('kra_weightage'))
|
||||||
|
|
||||||
def action_sent_employee(self):
|
def action_sent_employee(self):
|
||||||
appraisal_config_obj = self.env['employee.appraisal.template.config']
|
|
||||||
for rec in self:
|
for rec in self:
|
||||||
first_stage = rec.stage_config_ids.sorted(
|
# appraisal_config_obj = self.env['employee.appraisal.template.config']
|
||||||
key=lambda s: s.seq
|
# for rec in self:
|
||||||
)[:1]
|
# first_stage = rec.stage_config_ids.sorted(
|
||||||
for employee in rec.employee_ids:
|
# key=lambda s: s.seq
|
||||||
already_exists = appraisal_config_obj.search([
|
# )[:1]
|
||||||
('template_id', '=', rec.id),
|
# for employee in rec.employee_ids:
|
||||||
('employee_appraisal_id', '=', employee.id)
|
# already_exists = appraisal_config_obj.search([
|
||||||
], limit=1)
|
# ('template_id', '=', rec.id),
|
||||||
if already_exists:
|
# ('employee_appraisal_id', '=', employee.id)
|
||||||
continue
|
# ], limit=1)
|
||||||
appraisal = appraisal_config_obj.create({
|
# if already_exists:
|
||||||
'template_id': rec.id,
|
# continue
|
||||||
'seq': rec.seq,
|
# appraisal = appraisal_config_obj.create({
|
||||||
'employee_appraisal_id': employee.id,
|
# 'template_id': rec.id,
|
||||||
'employee_ids': [(6, 0, rec.employee_ids.ids)],
|
# 'seq': rec.seq,
|
||||||
'manager_ids': [(6, 0, rec.manager_ids.ids)],
|
# 'employee_appraisal_id': employee.id,
|
||||||
'notice_id': rec.notice_id.id,
|
# 'employee_ids': [(6, 0, rec.employee_ids.ids)],
|
||||||
'start_date': rec.start_date,
|
# 'manager_ids': [(6, 0, rec.manager_ids.ids)],
|
||||||
'end_date': rec.end_date,
|
# 'notice_id': rec.notice_id.id,
|
||||||
'appraisal_period_id': rec.appraisal_period_id.id,
|
# 'start_date': rec.start_date,
|
||||||
'hr_apprai_id': rec.hr_employee_id.id,
|
# 'end_date': rec.end_date,
|
||||||
'managerapp_id': rec.employee_eva_id.id,
|
# 'appraisal_period_id': rec.appraisal_period_id.id,
|
||||||
'template_empl_rating_bool': rec.template_rating_bool,
|
# 'hr_apprai_id': rec.hr_employee_id.id,
|
||||||
'template_empl_point_bool': rec.template_point_bool,
|
# 'managerapp_id': rec.employee_eva_id.id,
|
||||||
'available_stage_ids': [
|
# 'template_empl_rating_bool': rec.template_rating_bool,
|
||||||
(6, 0, rec.stage_config_ids.ids)
|
# 'template_empl_point_bool': rec.template_point_bool,
|
||||||
],
|
# 'available_stage_ids': [
|
||||||
'stage_id': first_stage.id if first_stage else False,
|
# (6, 0, rec.stage_config_ids.ids)
|
||||||
# 'state': 'self_evaluation',
|
# ],
|
||||||
})
|
# 'stage_id': first_stage.id if first_stage else False,
|
||||||
appraisal._onchange_template_id()
|
# # 'state': 'self_evaluation',
|
||||||
|
# })
|
||||||
|
# appraisal._onchange_template_id()
|
||||||
employee_emails = rec.employee_ids.mapped('work_email')
|
employee_emails = rec.employee_ids.mapped('work_email')
|
||||||
manager_emails = rec.manager_ids.mapped('work_email')
|
manager_emails = rec.manager_ids.mapped('work_email')
|
||||||
all_emails = employee_emails + manager_emails
|
all_emails = employee_emails + manager_emails
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,13 @@ class EmployeeAppraisal(models.Model):
|
||||||
name = fields.Char(string="Reference", copy=False)
|
name = fields.Char(string="Reference", copy=False)
|
||||||
employee_evaluator_name_id = fields.Many2one('employee.appraisal.evaluator', string="Employee Appraisal Evaluator")
|
employee_evaluator_name_id = fields.Many2one('employee.appraisal.evaluator', string="Employee Appraisal Evaluator")
|
||||||
hr_apprai_id = fields.Many2one('hr.employee')
|
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')])
|
performance_evaluator = fields.Selection([('manager', 'Manager'), ('colleague', 'Colleague'), ('own', 'Own')])
|
||||||
template_id = fields.Many2one('employee.appraisal.template', string="Template")
|
template_id = fields.Many2one('employee.appraisal.template', string="Template")
|
||||||
stage_id = fields.Many2one('employee.stage.config',string='Stage')
|
stage_id = fields.Many2one('employee.stage.config', string='Stage')
|
||||||
available_stage_ids = fields.Many2many('employee.stage.config',compute='_compute_available_stages')
|
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)
|
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)
|
company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.company)
|
||||||
state = fields.Selection([
|
state = fields.Selection([
|
||||||
|
|
@ -43,13 +45,18 @@ class EmployeeAppraisal(models.Model):
|
||||||
employee_appraisal_id = fields.Many2one('hr.employee')
|
employee_appraisal_id = fields.Many2one('hr.employee')
|
||||||
image_1920 = fields.Image(related='employee_appraisal_id.image_1920')
|
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)
|
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)
|
department_appraisal_id = fields.Many2one("hr.department", string="Department",
|
||||||
job_appraisal_id = fields.Many2one("hr.job", string="Job Position", related="employee_appraisal_id.job_id",store=True)
|
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')
|
kra_line_ids = fields.One2many('employee.appraisal.kra.line', 'config_id', string='Kra')
|
||||||
manager_remarks = fields.Char(string="Manager Remarks")
|
manager_remarks = fields.Char(string="Manager Remarks")
|
||||||
hr_remarks = fields.Char(string="HR 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')
|
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)
|
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)
|
creator_email = fields.Char(related='created_by_id.work_email', string="Creator Email", readonly=True)
|
||||||
notice_id = fields.Many2one('hr.notice.appraisal', string="Notice")
|
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")
|
is_readonly = fields.Boolean(compute="_compute_is_readonly")
|
||||||
mail_sent_employee_ids = fields.Many2many('hr.employee', string="Mail Sent Employees")
|
mail_sent_employee_ids = fields.Many2many('hr.employee', string="Mail Sent Employees")
|
||||||
seq = fields.Char(string="Sequence", readonly=True, copy=False)
|
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")
|
employee_ids = fields.Many2many('hr.employee', 'appraisal_config_employee_rel', 'config_id', 'employee_id',
|
||||||
manager_ids = fields.Many2many('hr.employee', 'appraisal_config_manager_rel', 'config_id', 'manager_id',string="Managers")
|
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_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_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)
|
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")
|
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_score = fields.Float(compute="_compute_overall_scores", store=True)
|
||||||
overall_rating = fields.Selection([
|
overall_rating = fields.Selection([
|
||||||
('0', '0'),
|
('0', '0'),
|
||||||
|
|
@ -91,9 +101,9 @@ class EmployeeAppraisal(models.Model):
|
||||||
('4', '4'),
|
('4', '4'),
|
||||||
('5', '5'),
|
('5', '5'),
|
||||||
], string="Overall Stars")
|
], string="Overall Stars")
|
||||||
employee_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)
|
manager_overall_score = fields.Float(compute='_compute_overall_scores', store=True)
|
||||||
hr_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([
|
employee_overall_star = fields.Selection([
|
||||||
('0', '0'),
|
('0', '0'),
|
||||||
('1', '1'),
|
('1', '1'),
|
||||||
|
|
@ -119,14 +129,73 @@ class EmployeeAppraisal(models.Model):
|
||||||
('5', '5'),
|
('5', '5'),
|
||||||
], compute='_compute_overall_scores', store=True)
|
], compute='_compute_overall_scores', store=True)
|
||||||
finance_user_id = fields.Many2one('res.users', string="Finance Approved By", readonly=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_percentage = fields.Float(string="Appraisal %")
|
||||||
appraisal_amount = fields.Float(string="Appraisal Amount")
|
appraisal_amount = fields.Float(string="Appraisal Amount")
|
||||||
new_salary = fields.Float(string="Revised Salary", compute="_compute_new_salary", store=True)
|
new_salary = fields.Float(string="Revised Salary", compute="_compute_new_salary", store=True)
|
||||||
finance_remarks = fields.Text(string="Finance Remarks")
|
finance_remarks = fields.Text(string="Finance Remarks")
|
||||||
finance_date = fields.Datetime(string="Finance Approval Date", readonly=True)
|
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_rating_bool = fields.Boolean('Star Rating')
|
||||||
template_empl_point_bool = fields.Boolean('Point 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')
|
@api.depends('template_id')
|
||||||
def _compute_available_stages(self):
|
def _compute_available_stages(self):
|
||||||
|
|
@ -322,11 +391,20 @@ class EmployeeAppraisal(models.Model):
|
||||||
else:
|
else:
|
||||||
rec.appraisal_percentage = 0
|
rec.appraisal_percentage = 0
|
||||||
|
|
||||||
@api.depends('manager_ids')
|
# @api.depends('manager_ids')
|
||||||
def _compute_manager_email(self):
|
# 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:
|
for rec in self:
|
||||||
emails = rec.manager_ids.mapped('work_email')
|
rec.manager_email = rec.managerapp_id.work_email or ''
|
||||||
rec.manager_email = ",".join(filter(None, emails))
|
|
||||||
|
@api.onchange('employee_appraisal_id')
|
||||||
|
def _onchange_employee_appraisal_id(self):
|
||||||
|
self.managerapp_id = self.employee_appraisal_id.parent_id
|
||||||
|
|
||||||
@api.depends('end_date')
|
@api.depends('end_date')
|
||||||
def _compute_is_readonly(self):
|
def _compute_is_readonly(self):
|
||||||
|
|
@ -373,44 +451,298 @@ class EmployeeAppraisal(models.Model):
|
||||||
@api.depends('current_salary', 'appraisal_amount')
|
@api.depends('current_salary', 'appraisal_amount')
|
||||||
def _compute_new_salary(self):
|
def _compute_new_salary(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
rec.new_salary = (
|
rec.new_salary = rec.current_salary + rec.appraisal_amount
|
||||||
rec.current_salary +
|
|
||||||
rec.appraisal_amount
|
|
||||||
)
|
|
||||||
|
|
||||||
@api.onchange('appraisal_percentage')
|
@api.onchange('appraisal_percentage')
|
||||||
def _onchange_appraisal_percentage(self):
|
def _onchange_appraisal_percentage(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
if rec.current_salary:
|
if rec.current_salary:
|
||||||
rec.appraisal_amount = (
|
rec.appraisal_amount = (
|
||||||
rec.current_salary *
|
rec.current_salary * rec.appraisal_percentage
|
||||||
rec.appraisal_percentage
|
|
||||||
) / 100
|
) / 100
|
||||||
|
|
||||||
def _move_to_next_stage(self):
|
def _move_to_next_stage(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
next_stage = self.env['employee.stage.config'].search(
|
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',
|
order='seq asc',
|
||||||
limit=1
|
limit=1
|
||||||
)
|
)
|
||||||
if next_stage:
|
if next_stage:
|
||||||
self.stage_id = next_stage.id
|
self.stage_id = next_stage.id
|
||||||
|
|
||||||
def action_finance_approve(self):
|
def action_create_pip(self):
|
||||||
for rec in self:
|
self.ensure_one()
|
||||||
rec.write({
|
|
||||||
'state': 'management_team',
|
|
||||||
'finance_user_id': self.env.user.id,
|
|
||||||
'finance_date': fields.Datetime.now()
|
|
||||||
})
|
|
||||||
|
|
||||||
rec.message_post(
|
pip = self.env['employee.pip'].create({
|
||||||
body=_(
|
'employee_id': self.employee_appraisal_id.id,
|
||||||
"Finance appraisal approved."
|
'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):
|
def _send_manager_notification_mail(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
email_to = self.manager_email
|
email_to = self.manager_email
|
||||||
|
|
@ -434,7 +766,7 @@ class EmployeeAppraisal(models.Model):
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>Performance Period</b></td>
|
<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>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
@ -455,81 +787,94 @@ class EmployeeAppraisal(models.Model):
|
||||||
}
|
}
|
||||||
self.env['mail.mail'].create(mail_values).send()
|
self.env['mail.mail'].create(mail_values).send()
|
||||||
|
|
||||||
def check_colleague_feedback_deadline(self):
|
# def check_colleague_feedback_deadline(self):
|
||||||
now = fields.Datetime.now()
|
# now = fields.Datetime.now()
|
||||||
records = self.search([
|
# records = self.search([
|
||||||
('college_end_date_time', '!=', False),
|
# ('college_end_date_time', '!=', False),
|
||||||
('college_end_date_time', '<=', now),
|
# ('college_end_date_time', '<=', now),
|
||||||
('state', '=', 'colleague_feedback')
|
# ('state', '=', 'colleague_feedback')
|
||||||
])
|
# ])
|
||||||
for rec in records:
|
# for rec in records:
|
||||||
rec.write({
|
# rec.write({
|
||||||
'state': 'in_progress'
|
# 'state': 'in_progress'
|
||||||
})
|
# })
|
||||||
rec.message_post(
|
# rec.message_post(
|
||||||
body=_(
|
# body=_(
|
||||||
"Colleague feedback deadline completed automatically. "
|
# "Colleague feedback deadline completed automatically. "
|
||||||
"Stage moved to Manager Evaluation."
|
# "Stage moved to Manager Evaluation."
|
||||||
)
|
# )
|
||||||
)
|
# )
|
||||||
rec._send_manager_notification_mail()
|
# rec._send_manager_notification_mail()
|
||||||
return True
|
# return True
|
||||||
|
|
||||||
def action_sent_employee_appraisal(self):
|
def action_sent_employee_appraisal(self):
|
||||||
self.ensure_one()
|
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 ''
|
employee_email = self.employee_appraisal_id.work_email or ''
|
||||||
creator_email = self.creator_email or ''
|
creator_email = self.creator_email or ''
|
||||||
|
|
||||||
emails = ",".join(
|
emails = ",".join(
|
||||||
filter(None, [employee_email, creator_email])
|
filter(None, [
|
||||||
|
manager_email,
|
||||||
|
employee_email,
|
||||||
|
creator_email
|
||||||
|
])
|
||||||
)
|
)
|
||||||
|
|
||||||
body_html = f"""
|
body_html = f"""
|
||||||
<div>
|
<div>
|
||||||
<p>Hello,Team</p>
|
<p>Hello Team,</p>
|
||||||
<p>
|
|
||||||
Your appraisal evaluation has been initiated.
|
|
||||||
</p>
|
|
||||||
<br/>
|
|
||||||
<table border="1" cellpadding="5" cellspacing="0">
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>Employee</b>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
<p>
|
||||||
{self.employee_appraisal_id.name or ''}
|
The employee has completed the self-assessment as part of the performance appraisal process.
|
||||||
</td>
|
Your feedback and evaluation are now requested.
|
||||||
</tr>
|
</p>
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>Template</b>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
<br/>
|
||||||
{self.template_id.name or ''}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>Performance Period</b>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
<table border="1" cellpadding="5" cellspacing="0">
|
||||||
{self.appraisal_period_id.appraisal_type_id.id or ''}
|
<tr>
|
||||||
</td>
|
<td><b>Employee</b></td>
|
||||||
</tr>
|
<td>{self.employee_appraisal_id.name or ''}</td>
|
||||||
</table>
|
</tr>
|
||||||
<br/>
|
<tr>
|
||||||
<p>
|
<td><b>Department</b></td>
|
||||||
Please complete the self evaluation before deadline.
|
<td>{self.department_appraisal_id.name or ''}</td>
|
||||||
</p>
|
</tr>
|
||||||
<br/>
|
<tr>
|
||||||
<p>
|
<td><b>Appraisal Template</b></td>
|
||||||
Regards,
|
<td>{self.template_id.name or ''}</td>
|
||||||
</p>
|
</tr>
|
||||||
<p>
|
<tr>
|
||||||
HR Team
|
<td><b>Performance Period</b></td>
|
||||||
</p>
|
<td>{self.appraisal_period_id.appraisal_name or ''}</td>
|
||||||
</div>
|
</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 = {
|
ctx = {
|
||||||
'default_model': 'employee.appraisal.template.config',
|
'default_model': 'employee.appraisal.template.config',
|
||||||
|
|
@ -549,17 +894,132 @@ class EmployeeAppraisal(models.Model):
|
||||||
'context': ctx,
|
'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):
|
def action_confirm_hr(self):
|
||||||
for rec in self:
|
self.ensure_one()
|
||||||
rec.state = 'finance_team'
|
|
||||||
|
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):
|
def action_send_colleague_feedback(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
|
|
@ -568,6 +1028,7 @@ class EmployeeAppraisal(models.Model):
|
||||||
('id', '!=', rec.employee_appraisal_id.id)
|
('id', '!=', rec.employee_appraisal_id.id)
|
||||||
])
|
])
|
||||||
vals = []
|
vals = []
|
||||||
|
email_list = []
|
||||||
for emp in employees:
|
for emp in employees:
|
||||||
already_exists = self.env['colleague.feedback'].search([
|
already_exists = self.env['colleague.feedback'].search([
|
||||||
('employee_appraisal_feed_id', '=', rec.id),
|
('employee_appraisal_feed_id', '=', rec.id),
|
||||||
|
|
@ -578,7 +1039,123 @@ class EmployeeAppraisal(models.Model):
|
||||||
'colleague_feed_id': emp.id,
|
'colleague_feed_id': emp.id,
|
||||||
}))
|
}))
|
||||||
rec.colleague_feed_ids = vals
|
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')
|
@api.onchange('template_id')
|
||||||
def _onchange_template_id(self):
|
def _onchange_template_id(self):
|
||||||
|
|
@ -624,7 +1201,6 @@ class ColleagueFeedBack(models.Model):
|
||||||
submitted_date = fields.Datetime()
|
submitted_date = fields.Datetime()
|
||||||
|
|
||||||
def action_submit_feedback(self):
|
def action_submit_feedback(self):
|
||||||
|
|
||||||
for rec in self:
|
for rec in self:
|
||||||
rec.write({
|
rec.write({
|
||||||
'state': 'submitted',
|
'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,122 @@
|
||||||
|
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)
|
||||||
|
image_1920 = fields.Image(related='hr_employee_id.image_1920')
|
||||||
|
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 odoo.exceptions import ValidationError
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
|
import logging
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class HrNoticeAppraisal(models.Model):
|
class HrNoticeAppraisal(models.Model):
|
||||||
_name = 'hr.notice.appraisal'
|
_name = 'hr.notice.appraisal'
|
||||||
|
|
@ -15,10 +17,11 @@ class HrNoticeAppraisal(models.Model):
|
||||||
return self.env.user.employee_id
|
return self.env.user.employee_id
|
||||||
|
|
||||||
hr_employee_id = fields.Many2one('hr.employee', string='Employee', default=_default_employee_get)
|
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)
|
subject = fields.Char(string="Subject", required=True, tracking=True)
|
||||||
body = fields.Html(string="Notice Body", required=True)
|
body = fields.Html(string="Notice Body", required=True)
|
||||||
start_date = fields.Datetime(string="Start Date", required=True)
|
start_date = fields.Date(string="Start Date")
|
||||||
end_date = fields.Datetime(string="End Date", required=True)
|
end_date = fields.Date(string="End Date")
|
||||||
employee_ids = fields.Many2many('hr.employee', 'notice_employee_rel', 'notice_id', 'employee_id',string="Employees")
|
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")
|
manager_ids = fields.Many2many('hr.employee', 'notice_manager_rel', 'notice_id', 'manager_id', string="Managers")
|
||||||
state = fields.Selection([
|
state = fields.Selection([
|
||||||
|
|
@ -44,37 +47,83 @@ class HrNoticeAppraisal(models.Model):
|
||||||
new_end_date = fields.Datetime(string="New End Date")
|
new_end_date = fields.Datetime(string="New End Date")
|
||||||
stage_config = fields.Many2many('employee.stage.config',string='Stages')
|
stage_config = fields.Many2many('employee.stage.config',string='Stages')
|
||||||
hr_department_ids = fields.Many2many('hr.department', string="Departments")
|
hr_department_ids = fields.Many2many('hr.department', string="Departments")
|
||||||
|
image_1920 = fields.Image(related='hr_employee_id.image_1920',string='Employee Image')
|
||||||
|
|
||||||
@api.model
|
# @api.model
|
||||||
def create(self, vals):
|
# def create(self, vals):
|
||||||
if vals.get('seq', 'New') == 'New':
|
# if vals.get('seq', 'New') == 'New':
|
||||||
company = self.env.company
|
# company = self.env.company
|
||||||
company_code = company.short_code or 'CMP'
|
# company_code = company.short_code or 'CMP'
|
||||||
today = fields.Datetime.now()
|
# today = fields.Datetime.now()
|
||||||
month = str(today.month).zfill(2)
|
# month = str(today.month).zfill(2)
|
||||||
year = str(today.year)[-2:]
|
# year = str(today.year)[-2:]
|
||||||
prefix = f"{company_code}/{month}/{year}"
|
# prefix = f"{company_code}/{month}/{year}"
|
||||||
last_record = self.search([
|
# last_record = self.search([
|
||||||
('seq', '=like', f'{prefix}%')
|
# ('seq', '=like', f'{prefix}%')
|
||||||
], order='id desc', limit=1)
|
# ], order='id desc', limit=1)
|
||||||
number = 1
|
# number = 1
|
||||||
if last_record and last_record.seq:
|
# if last_record and last_record.seq:
|
||||||
try:
|
# try:
|
||||||
number = int(
|
# number = int(
|
||||||
last_record.seq.split('/')[-1]
|
# last_record.seq.split('/')[-1]
|
||||||
) + 1
|
# ) + 1
|
||||||
except Exception:
|
# except Exception:
|
||||||
number = 1
|
# number = 1
|
||||||
vals['seq'] = (
|
# vals['seq'] = (
|
||||||
f"{prefix}/{str(number).zfill(3)}"
|
# f"{prefix}/{str(number).zfill(3)}"
|
||||||
)
|
# )
|
||||||
return super().create(vals)
|
# return super().create(vals)
|
||||||
|
|
||||||
@api.constrains('start_date', 'end_date')
|
@api.constrains('start_date', 'end_date','employee_ids','manager_ids','appraisal_notice_id','state')
|
||||||
def _check_dates(self):
|
def _check_appraisal_validations(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
if rec.end_date < rec.start_date:
|
if rec.start_date and rec.end_date:
|
||||||
raise ValidationError(_("End Date must be greater than Start 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')
|
@api.onchange('employee_ids')
|
||||||
def _onchange_employee_ids(self):
|
def _onchange_employee_ids(self):
|
||||||
|
|
@ -89,45 +138,6 @@ class HrNoticeAppraisal(models.Model):
|
||||||
manager_emails = self.manager_ids.mapped('work_email')
|
manager_emails = self.manager_ids.mapped('work_email')
|
||||||
all_emails = employee_emails + manager_emails
|
all_emails = employee_emails + manager_emails
|
||||||
email_to = ",".join(filter(None, all_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"""
|
body_html = f"""
|
||||||
<div>
|
<div>
|
||||||
<p>Hello,</p>
|
<p>Hello,</p>
|
||||||
|
|
@ -226,6 +236,7 @@ class StageConfig(models.Model):
|
||||||
|
|
||||||
name = fields.Char(required=True)
|
name = fields.Char(required=True)
|
||||||
seq = fields.Integer(required=True)
|
seq = fields.Integer(required=True)
|
||||||
|
colour_seq = fields.Integer(required=True)
|
||||||
active = fields.Boolean(default=True)
|
active = fields.Boolean(default=True)
|
||||||
color = fields.Integer('Color', default=_get_default_color_stage)
|
color = fields.Integer('Color', default=_get_default_color_stage)
|
||||||
|
|
||||||
|
|
@ -240,26 +251,157 @@ class MailComposeMessage(models.TransientModel):
|
||||||
model = self.env.context.get('default_model')
|
model = self.env.context.get('default_model')
|
||||||
res_ids = self.env.context.get('default_res_ids')
|
res_ids = self.env.context.get('default_res_ids')
|
||||||
if self.env.context.get('mark_notice_sent'):
|
if self.env.context.get('mark_notice_sent'):
|
||||||
|
|
||||||
if model == 'hr.notice.appraisal' and res_ids:
|
if model == 'hr.notice.appraisal' and res_ids:
|
||||||
records = self.env[model].browse(res_ids)
|
records = self.env[model].browse(res_ids)
|
||||||
|
template_obj = self.env['employee.appraisal.template']
|
||||||
records.write({
|
for rec in records:
|
||||||
'state': 'sent'
|
grouped_employees = {}
|
||||||
})
|
for employee in rec.employee_ids:
|
||||||
if self.env.context.get('mark_appraisal_sent'):
|
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:
|
if model == 'employee.appraisal.template.config' and res_ids:
|
||||||
records = self.env[model].browse(res_ids)
|
records = self.env[model].browse(res_ids)
|
||||||
for record in records:
|
for record in records:
|
||||||
record._move_to_next_stage()
|
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 self.env.context.get('mark_appraisal_sent_appraisal'):
|
||||||
|
|
||||||
if model == 'employee.appraisal.template' and res_ids:
|
if model == 'employee.appraisal.template' and res_ids:
|
||||||
records = self.env[model].browse(res_ids)
|
|
||||||
|
|
||||||
records.write({
|
templates = self.env[model].browse(res_ids)
|
||||||
'employee_state': 'sent'
|
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'),
|
('4', '4'),
|
||||||
('5', '5'),
|
('5', '5'),
|
||||||
], string="Stars", copy=False)
|
], 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([
|
# self_rating = fields.Selection([
|
||||||
# ('0', '0'),
|
# ('0', '0'),
|
||||||
# ('1', '1'),
|
# ('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_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_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="performance_evaluator"/>-->
|
||||||
<field name="template_id" string="Template"/>
|
<field name="template_id" string="Template"/>
|
||||||
<field name="appraisal_period_id" string="Performance Period"/>
|
<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>
|
</list>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</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">
|
<record id="view_employee_appraisal_form" model="ir.ui.view">
|
||||||
<field name="name">employee.appraisal.template.config.form</field>
|
<field name="name">employee.appraisal.template.config.form</field>
|
||||||
<field name="model">employee.appraisal.template.config</field>
|
<field name="model">employee.appraisal.template.config</field>
|
||||||
|
|
@ -32,23 +53,42 @@
|
||||||
domain="[('id', 'in', available_stage_ids)]"/>
|
domain="[('id', 'in', available_stage_ids)]"/>
|
||||||
<button name="action_sent_employee_appraisal" string="Send" type="object"
|
<button name="action_sent_employee_appraisal" string="Send" type="object"
|
||||||
confirm="Do you want to move to next stage?"
|
confirm="Do you want to move to next stage?"
|
||||||
class="btn-primary" invisible="stage_id.name != 'NEW'"/>
|
groups="hrms_employee_appraisal.group_appraisal_manager"
|
||||||
<!-- class="btn-primary" invisible="state != 'new'"/>-->
|
class="btn-primary" invisible="stage_name != 'COLLEAGUES&MANAGER'"/>
|
||||||
<button name="action_send_colleague_feedback"
|
<button name="action_send_colleague_feedback"
|
||||||
string="Send Colleague Feedback & Manager"
|
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?"
|
confirm="Do you want to move to next stage?"
|
||||||
class="btn-primary" invisible="stage_id.name != 'HR'"/>
|
type="object"
|
||||||
<!-- invisible="state != 'colleague_manager'"/>-->
|
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"
|
<button name="action_confirm_hr" string="HR Confirm" type="object"
|
||||||
confirm="Do you want to move to next stage?"
|
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'"/>-->
|
<!-- invisible="state != 'hr_evaluation'"/>-->
|
||||||
<button name="action_finance_approve" string="Finance Appraisal"
|
<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'"/>-->
|
<!-- invisible="state != 'finance_team'"/>-->
|
||||||
<!-- <button name="action_confirm" string="Confirm" type="object"-->
|
<!-- <button name="action_confirm" string="Confirm" type="object"-->
|
||||||
<!-- confirm="Do you want to move to next stage?"-->
|
<!-- confirm="Do you want to move to next stage?"-->
|
||||||
|
|
@ -60,21 +100,38 @@
|
||||||
<!-- invisible="state != 'colleague_feedback'"/>-->
|
<!-- invisible="state != 'colleague_feedback'"/>-->
|
||||||
</header>
|
</header>
|
||||||
<sheet>
|
<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 col="2">
|
||||||
<group>
|
<group>
|
||||||
<field name="seq" string="Performance Id"/>
|
<field name="seq" string="Performance Id"/>
|
||||||
<field name="employee_appraisal_id" string="Employee"/>
|
<field name="employee_appraisal_id" string="Employee" readonly="1"
|
||||||
<field name="job_appraisal_id" string="Current Job Title" readonly="1"/>
|
options="{'no_open': True}"/>
|
||||||
<field name="department_appraisal_id" string="Department" readonly="1"/>
|
<field name="job_appraisal_id" string="Current Job Title" readonly="1"
|
||||||
<field name="template_id" string="Template"/>
|
options="{'no_open': True}"/>
|
||||||
<!-- <field name="available_stage_ids" invisible="0" widget="many2many_tags"/>-->
|
<field name="department_appraisal_id" string="Department" readonly="1"
|
||||||
<field name="appraisal_period_id" string="Performance Period"/>
|
options="{'no_open': True}"/>
|
||||||
<!-- <field name="manager_ids" widget="many2many_tags"/>-->
|
<!-- <field name="template_id" string="Template"/>-->
|
||||||
<field name="managerapp_id"/>
|
<!-- <field name="available_stage_ids" invisible="0" widget="many2many_tags"/>-->
|
||||||
<field name="manager_remarks"/>
|
<field name="appraisal_period_id" string="Performance Period" readonly="1"
|
||||||
<field name="hr_apprai_id" string="HR"/>
|
options="{'no_open': True}"/>
|
||||||
<field name="hr_remarks"/>
|
<!-- <field name="manager_ids" widget="many2many_tags"/>-->
|
||||||
<field name="start_date" readonly="1"/>
|
<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>
|
||||||
<group>
|
<group>
|
||||||
<field name="image_1920" widget="image" class="oe_avatar" nolabel="1"
|
<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_employee_score" readonly="1"/>
|
||||||
<field name="total_manager_score" readonly="1"/>
|
<field name="total_manager_score" readonly="1"/>
|
||||||
<field name="total_hr_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="end_date" readonly="1"/>
|
||||||
<field name="template_empl_rating_bool"/>
|
<field name="template_empl_rating_bool" readonly="1" invisible="1"/>
|
||||||
<field name="template_empl_point_bool"/>
|
<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>
|
||||||
<group string="Performance Standards">
|
<group string="Performance Standards">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -146,27 +206,64 @@
|
||||||
<field name="kpi_line_ids" nolabel="1" string="KPI">
|
<field name="kpi_line_ids" nolabel="1" string="KPI">
|
||||||
<list editable="bottom" delete="0">
|
<list editable="bottom" delete="0">
|
||||||
<field name="sequence" widget="handle"/>
|
<field name="sequence" widget="handle"/>
|
||||||
<field name="question"/>
|
<field name="question" readonly="1"/>
|
||||||
<field name="description"/>
|
<field name="description" readonly="1"/>
|
||||||
<!-- <field name="kpi_line_weightage" sum="Total Weight Age"/>-->
|
<!-- <field name="kpi_line_weightage" sum="Total Weight Age"/>-->
|
||||||
<field name="template_empl_rating_bool" column_invisible="1"/>
|
<field name="template_empl_rating_bool" column_invisible="1"/>
|
||||||
<field name="template_empl_point_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"
|
<field name="employee_score" string="self Rating" sum="Total score"
|
||||||
|
readonly="not is_employee_reviewer"
|
||||||
column_invisible="parent.template_empl_point_bool == False"/>
|
column_invisible="parent.template_empl_point_bool == False"/>
|
||||||
<field name="rating_star" widget="priority" string="Self Rating"
|
<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"/>
|
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"/>
|
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"
|
<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"/>
|
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="manager_score" sum="Total Points"
|
||||||
<field name="hr_score" sum="Total Points" column_invisible="parent.template_empl_point_bool == False"/>
|
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>
|
</list>
|
||||||
</field>
|
</field>
|
||||||
</sheet>
|
</sheet>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</page>
|
</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">
|
<page string="Team Feed Back">
|
||||||
<!-- <field name="colleague_feed_ids" readonly="state != 'colleague_feedback'">-->
|
<!-- <field name="colleague_feed_ids" readonly="state != 'colleague_feedback'">-->
|
||||||
<field name="colleague_feed_ids">
|
<field name="colleague_feed_ids">
|
||||||
|
|
@ -174,47 +271,35 @@
|
||||||
<field name="colleague_feed_id"/>
|
<field name="colleague_feed_id"/>
|
||||||
<field name="feedback"/>
|
<field name="feedback"/>
|
||||||
<!-- <field name="feedback" readonly="state == 'submitted'"/>-->
|
<!-- <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'"/>-->
|
<!-- invisible="state == 'submitted'"/>-->
|
||||||
</list>
|
</list>
|
||||||
</field>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
<page string="Finance Review">
|
<page string="Finance Review">
|
||||||
|
|
||||||
<group>
|
<group>
|
||||||
|
<button name="action_update_contract_salary"
|
||||||
|
string="Update Contract Salary"
|
||||||
|
type="object"
|
||||||
|
class="btn-primary"
|
||||||
|
invisible="salary_update"/>
|
||||||
<group string="Salary Details">
|
<group string="Salary Details">
|
||||||
|
|
||||||
<field name="current_salary"/>
|
<field name="current_salary"/>
|
||||||
|
|
||||||
<field name="appraisal_percentage"/>
|
<field name="appraisal_percentage"/>
|
||||||
|
|
||||||
<field name="appraisal_amount"/>
|
<field name="appraisal_amount"/>
|
||||||
|
|
||||||
<field name="new_salary" readonly="1"/>
|
<field name="new_salary" readonly="1"/>
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<group string="Finance Remarks">
|
<group string="Finance Remarks">
|
||||||
|
<field name="salary_update" readonly="1"/>
|
||||||
<field name="finance_remarks"/>
|
<field name="finance_remarks"/>
|
||||||
|
<field name="finance_head_remarks"/>
|
||||||
<field name="finance_user_id"
|
|
||||||
readonly="1"/>
|
|
||||||
|
|
||||||
<field name="finance_date"
|
|
||||||
readonly="1"/>
|
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
|
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
</page>
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
|
|
@ -228,6 +313,7 @@
|
||||||
<field name="name">Employee Performance Review</field>
|
<field name="name">Employee Performance Review</field>
|
||||||
<field name="res_model">employee.appraisal.template.config</field>
|
<field name="res_model">employee.appraisal.template.config</field>
|
||||||
<field name="view_mode">list,form</field>
|
<field name="view_mode">list,form</field>
|
||||||
|
<field name="search_view_id" ref="view_employee_app_search"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- ROOT MENU -->
|
<!-- ROOT MENU -->
|
||||||
|
|
@ -241,7 +327,7 @@
|
||||||
name="Employee Performance Review"
|
name="Employee Performance Review"
|
||||||
parent="menu_employee_appraisal_root"
|
parent="menu_employee_appraisal_root"
|
||||||
action="action_employee_appraisal_template"
|
action="action_employee_appraisal_template"
|
||||||
sequence="03"/>
|
sequence="04"/>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,23 @@
|
||||||
|
|
||||||
<menuitem id="configuration_id_employee"
|
<menuitem id="configuration_id_employee"
|
||||||
name="Configuration"
|
name="Configuration"
|
||||||
|
groups="group_appraisal_hr_head,group_appraisal_hr,group_appraisal_management"
|
||||||
parent="menu_employee_appraisal_root"
|
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">
|
<record id="view_employee_appraisal_yea_form" model="ir.ui.view">
|
||||||
<field name="name">employee.appraisal.year.form</field>
|
<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,21 +10,27 @@
|
||||||
type="object"
|
type="object"
|
||||||
string="Send To Employee"
|
string="Send To Employee"
|
||||||
class="oe_highlight"
|
class="oe_highlight"
|
||||||
|
groups="hrms_employee_appraisal.group_appraisal_manager,hrms_employee_appraisal.group_appraisal_management"
|
||||||
invisible="employee_state != 'new'"/>
|
invisible="employee_state != 'new'"/>
|
||||||
<field name="employee_state" widget="statusbar"/>
|
<field name="employee_state" widget="statusbar"/>
|
||||||
</header>
|
</header>
|
||||||
<sheet>
|
<sheet>
|
||||||
|
<field name="image_template"
|
||||||
|
widget="image"
|
||||||
|
class="oe_avatar"
|
||||||
|
options="{'preview_image': 'image_template'}"/>
|
||||||
<group string="Details" col="2">
|
<group string="Details" col="2">
|
||||||
<group>
|
<group>
|
||||||
<field name="seq" string="Performance Id"/>
|
<field name="seq" string="Reference"/>
|
||||||
<field name="name" string="Reference" placeholder="Administration Appraisal Template"/>
|
<field name="name" string="Subject" readonly="1" placeholder="Administration Appraisal Template"/>
|
||||||
<field name="manager_ids" widget="many2many_tags" string="Performance Evaluator"/>
|
<field name="manager_ids" widget="many2many_tags" string="Performance Evaluator"
|
||||||
<field name="employee_eva_id"/>
|
invisible="1"/>
|
||||||
<field name="employee_department_id"/>
|
<field name="employee_eva_id" readonly="1" options="{'no_open': True}"/>
|
||||||
<field name="appraisal_period_type_id" string="Performance Type"/>
|
<field name="employee_department_id" readonly="1" options="{'no_open': True}"/>
|
||||||
<field name="appraisal_period_id" string="Performance Period"/>
|
<field name="appraisal_period_type_id" string="Appraisal Type" readonly="1" options="{'no_open' : True}"/>
|
||||||
<field name="hr_employee_id" string="HR"/>
|
<field name="appraisal_period_id" string="Appraisal Period" readonly="1" options="{'no_open' : True}"/>
|
||||||
<field name="stage_config_ids" widget="many2many_tags"/>
|
<field name="hr_employee_id" string="HR" readonly="1" options="{'no_open' : True}"/>
|
||||||
|
<field name="stage_config_ids" widget="many2many_tags" readonly="1"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="company_id" string="Company"/>
|
<field name="company_id" string="Company"/>
|
||||||
|
|
@ -33,8 +39,8 @@
|
||||||
<!-- <field name="hr_email_notify" string="Send Email if HR APPROVE or REJECT Evaluation?"/>-->
|
<!-- <field name="hr_email_notify" string="Send Email if HR APPROVE or REJECT Evaluation?"/>-->
|
||||||
<field name="start_date" readonly="1"/>
|
<field name="start_date" readonly="1"/>
|
||||||
<field name="end_date" readonly="1"/>
|
<field name="end_date" readonly="1"/>
|
||||||
<field name="template_rating_bool"/>
|
<field name="template_rating_bool" string="Employee Rating"/>
|
||||||
<field name="template_point_bool"/>
|
<field name="template_point_bool" string="Employee points"/>
|
||||||
<field name="kra_weightage"/>
|
<field name="kra_weightage"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|
@ -48,8 +54,10 @@
|
||||||
<!-- <field name="kra_weightage" sum="Total Weightage"/>-->
|
<!-- <field name="kra_weightage" sum="Total Weightage"/>-->
|
||||||
<field name="kra_template_rating_bool" column_invisible="1"/>
|
<field name="kra_template_rating_bool" column_invisible="1"/>
|
||||||
<field name="kra_template_point_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_star_rating" widget="priority"
|
||||||
<field name="max_points" column_invisible="parent.template_point_bool == False"/>
|
column_invisible="parent.template_rating_bool == False"/>
|
||||||
|
<field name="max_points"
|
||||||
|
column_invisible="parent.template_point_bool == False"/>
|
||||||
<field name="kpi_count" readonly="1"/>
|
<field name="kpi_count" readonly="1"/>
|
||||||
<button name="action_open_questions"
|
<button name="action_open_questions"
|
||||||
type="object"
|
type="object"
|
||||||
|
|
@ -80,7 +88,10 @@
|
||||||
<field name="appraisal_period_type_id" string="Performance Type"/>
|
<field name="appraisal_period_type_id" string="Performance Type"/>
|
||||||
<field name="appraisal_period_id" string="Performance Period"/>
|
<field name="appraisal_period_id" string="Performance Period"/>
|
||||||
<field name="company_id"/>
|
<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>
|
</list>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
@ -96,9 +107,9 @@
|
||||||
name="Employee Appraisal Templates"
|
name="Employee Appraisal Templates"
|
||||||
parent="menu_employee_appraisal_root"
|
parent="menu_employee_appraisal_root"
|
||||||
action="action_employee_appraisal_template_conf"
|
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">
|
<record id="view_employee_appraisal_kpi_list" model="ir.ui.view">
|
||||||
<field name="name">employee.appraisal.kpi.list</field>
|
<field name="name">employee.appraisal.kpi.list</field>
|
||||||
|
|
@ -119,8 +130,6 @@
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
||||||
<!-- KPI FORM VIEW -->
|
|
||||||
|
|
||||||
<record id="view_employee_appraisal_kpi_form" model="ir.ui.view">
|
<record id="view_employee_appraisal_kpi_form" model="ir.ui.view">
|
||||||
<field name="name">employee.appraisal.kpi.form</field>
|
<field name="name">employee.appraisal.kpi.form</field>
|
||||||
<field name="model">employee.appraisal.kpi</field>
|
<field name="model">employee.appraisal.kpi</field>
|
||||||
|
|
@ -132,22 +141,8 @@
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
<footer>
|
<footer>
|
||||||
|
<button string="Save" type="object" special="save" class="btn-primary"/>
|
||||||
<!-- SAVE -->
|
<button name="action_delete_record" string="Delete" type="object" class="btn-danger"/>
|
||||||
<button string="Save"
|
|
||||||
type="object"
|
|
||||||
special="save"
|
|
||||||
class="btn-primary"/>
|
|
||||||
|
|
||||||
<!-- DELETE -->
|
|
||||||
<button name="action_delete_record"
|
|
||||||
string="Delete"
|
|
||||||
type="object"
|
|
||||||
class="btn-danger"/>
|
|
||||||
|
|
||||||
<!-- CLOSE -->
|
|
||||||
|
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@
|
||||||
<form string="HR Notice">
|
<form string="HR Notice">
|
||||||
<header>
|
<header>
|
||||||
<button name="action_send_notice" string="Send Appraisal Initiation" type="object"
|
<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"
|
<button name="action_open_postpone_wizard" string="Postpone" type="object"
|
||||||
class="btn-warning" invisible="state != 'sent'"/>
|
class="btn-warning" invisible="state != 'sent'"/>
|
||||||
<button name="action_open_cancel_wizard" string="Cancel" type="object"
|
<button name="action_open_cancel_wizard" string="Cancel" type="object"
|
||||||
|
|
@ -14,33 +16,53 @@
|
||||||
<field name="state" widget="statusbar"/>
|
<field name="state" widget="statusbar"/>
|
||||||
</header>
|
</header>
|
||||||
<sheet>
|
<sheet>
|
||||||
|
<!-- <div class="oe_title" style="display:flex; align-items:center; gap:20px;">-->
|
||||||
|
<!-- <field name="image_1920"-->
|
||||||
|
<!-- widget="image"-->
|
||||||
|
<!-- class="oe_avatar"-->
|
||||||
|
<!-- readonly="1"/>-->
|
||||||
|
|
||||||
|
<!-- <h1>-->
|
||||||
|
<!-- <field name="seq" readonly="1"/>-->
|
||||||
|
<!-- </h1>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<field name="image_1920"
|
||||||
|
widget="image"
|
||||||
|
class="oe_avatar"
|
||||||
|
readonly="1"/>
|
||||||
<group col="2">
|
<group col="2">
|
||||||
<group>
|
<group>
|
||||||
<field name="seq"/>
|
<field name="seq"/>
|
||||||
<field name="hr_employee_id" string="Created BY"/>
|
<field name="hr_employee_id" string="Employee" readonly="1" options="{'no_open': True}"/>
|
||||||
<field name="appraisal_type_id"/>
|
<field name="appraisal_type_id"
|
||||||
<field name="appraisal_notice_id"/>
|
options="{'no_edit': True, 'no_create': True, 'no_open': True}"
|
||||||
<field name="subject"/>
|
readonly="1"/>
|
||||||
<field name="start_date"/>
|
<field name="appraisal_notice_id"
|
||||||
<field name="end_date"/>
|
options="{'no_edit': True, 'no_create': True, 'no_open': True}"
|
||||||
|
readonly="1"/>
|
||||||
|
<field name="subject" readonly="1"/>
|
||||||
|
<field name="start_date" readonly="1" force_save="1"/>
|
||||||
|
<field name="end_date" readonly="1" force_save="1"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="employee_ids" widget="many2many_tags"/>
|
<field name="employee_ids" widget="many2many_tags" required="1"
|
||||||
<field name="manager_ids" widget="many2many_tags"/>
|
readonly="state != 'draft'"/>
|
||||||
<field name="hr_department_ids" widget="many2many_tags"/>
|
<field name="manager_ids" widget="many2many_tags" readonly="state != 'draft'"/>
|
||||||
<field name="stage_config" widget="many2many_tags"/>
|
<field name="hr_department_ids" widget="many2many_tags" readonly="state != 'draft'"/>
|
||||||
<field name="employee_rating"/>
|
<field name="stage_config" widget="many2many_tags" required="1"
|
||||||
<field name="employee_points"/>
|
readonly="1"/>
|
||||||
|
<field name="employee_rating" readonly="state != 'draft'"/>
|
||||||
|
<field name="employee_points" readonly="state != 'draft'"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="body" widget="html"/>
|
<field name="body" widget="html" readonly="1"/>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="Postponed Details">
|
<page string="Postponed Details">
|
||||||
<group>
|
<group>
|
||||||
<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="postponed_date" readonly="1"/>
|
||||||
<field name="new_start_date" readonly="1"/>
|
<field name="new_start_date" readonly="1"/>
|
||||||
<field name="new_end_date" readonly="1"/>
|
<field name="new_end_date" readonly="1"/>
|
||||||
|
|
@ -53,7 +75,7 @@
|
||||||
<page string="Cancelled Details">
|
<page string="Cancelled Details">
|
||||||
<group>
|
<group>
|
||||||
<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"/>
|
<field name="cancelled_date" readonly="1"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
|
|
@ -74,6 +96,7 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<list>
|
<list>
|
||||||
<field name="seq"/>
|
<field name="seq"/>
|
||||||
|
<field name="hr_employee_id"/>
|
||||||
<field name="subject"/>
|
<field name="subject"/>
|
||||||
<field name="start_date"/>
|
<field name="start_date"/>
|
||||||
<field name="end_date"/>
|
<field name="end_date"/>
|
||||||
|
|
@ -97,6 +120,105 @@
|
||||||
name="Performance Cycle Notification"
|
name="Performance Cycle Notification"
|
||||||
parent="menu_employee_appraisal_root"
|
parent="menu_employee_appraisal_root"
|
||||||
action="action_hr_notice_appraisal"
|
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_button_box" name="button_box"/>
|
||||||
|
|
||||||
|
<field name="image_1920"
|
||||||
|
widget="image"
|
||||||
|
class="oe_avatar"
|
||||||
|
options="{'preview_image': 'image_1920'}"/>
|
||||||
|
<div class="oe_title">
|
||||||
|
<h1>
|
||||||
|
<field name="name" placeholder="Performance Appraisal Notification" required="1"
|
||||||
|
readonly="state != 'draft'"/>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<group col="2">
|
||||||
|
<group string="Appraisal Details">
|
||||||
|
<field name="seq"/>
|
||||||
|
<field name="hr_employee_id" readonly="1" options="{'no_open':True}"/>
|
||||||
|
<field name="appraisal_type_id" options="{'no_create': True,'no_open': True}"
|
||||||
|
readonly="state != 'draft'"/>
|
||||||
|
<field name="appraisal_period_id" options="{'no_create': True,'no_open': True}"
|
||||||
|
readonly="state != 'draft'"/>
|
||||||
|
<field name="start_date" readonly="state != 'draft'"/>
|
||||||
|
<field name="end_date" readonly="state != 'draft'"/>
|
||||||
|
</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" readonly="state != 'draft'"/>
|
||||||
|
<field name="stage_config_ids" widget="many2many_tags" required="1"
|
||||||
|
readonly="state != 'draft'"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<notebook>
|
||||||
|
<page string="Notification Message">
|
||||||
|
<field name="body" widget="html" readonly="state != 'draft'"/>
|
||||||
|
</page>
|
||||||
|
<page string="Audit">
|
||||||
|
<group>
|
||||||
|
<field name="create_uid" readonly="1" options="{'no_open':True}"/>
|
||||||
|
<field name="create_date" readonly="1"/>
|
||||||
|
<field name="write_uid" readonly="1" options="{'no_open':True}"/>
|
||||||
|
<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"/>
|
sequence="01"/>
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<group>
|
<group>
|
||||||
<field name="seq" invisible="0"/>
|
<field name="seq" invisible="0"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
|
<field name="colour_seq"/>
|
||||||
<field name="color" widget="color_picker"/>
|
<field name="color" widget="color_picker"/>
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
|
|
@ -20,7 +21,7 @@
|
||||||
<field name="model">employee.stage.config</field>
|
<field name="model">employee.stage.config</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<list string="Employee Appraisal Period">
|
<list string="Employee Appraisal Period">
|
||||||
<field name="seq" widget="handle"/>
|
<field name="seq" widget="handle"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="color" widget="color_picker"/>
|
<field name="color" widget="color_picker"/>
|
||||||
</list>
|
</list>
|
||||||
|
|
@ -36,5 +37,43 @@
|
||||||
parent="configuration_id_employee"
|
parent="configuration_id_employee"
|
||||||
action="action_employee_stage_confr"
|
action="action_employee_stage_confr"
|
||||||
sequence="20"/>
|
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>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
@ -5,14 +5,14 @@
|
||||||
<field name="name">Applicant Offer Email Template</field>
|
<field name="name">Applicant Offer Email Template</field>
|
||||||
<field name="model_id" ref="offer_letters.model_offer_letter"/>
|
<field name="model_id" ref="offer_letters.model_offer_letter"/>
|
||||||
<field name="email_from">{{ user.email_formatted }}</field>
|
<field name="email_from">{{ user.email_formatted }}</field>
|
||||||
<field name="email_to">{{ object.candidate_id.email_from or '' }}</field>
|
<field name="email_to">{{ object.main_candidate_id.email_from or '' }}</field>
|
||||||
<field name="subject">Offer Letter - {{ object.position or object.candidate_id.job_id.name or '' }}</field>
|
<field name="subject">Offer Letter - {{ object.position or object.main_candidate_id.job_id.name or '' }}</field>
|
||||||
<field name="description">
|
<field name="description">
|
||||||
Send applicant offer mail with offer letter attachment.
|
Send applicant offer mail with offer letter attachment.
|
||||||
</field>
|
</field>
|
||||||
<field name="body_html" type="html">
|
<field name="body_html" type="html">
|
||||||
<div style="margin: 0; padding: 0; font-size: 13px; line-height: 1.7;">
|
<div style="margin: 0; padding: 0; font-size: 13px; line-height: 1.7;">
|
||||||
<p>Dear <t t-esc="object.candidate_id.partner_name or ''"/>,</p>
|
<p>Dear <t t-esc="object.main_candidate_id.partner_name or ''"/>,</p>
|
||||||
<p>
|
<p>
|
||||||
With reference to the interview and subsequent discussions you had with us, we are pleased to select
|
With reference to the interview and subsequent discussions you had with us, we are pleased to select
|
||||||
you for the position of "<t t-esc="object.position or ''"/>" in our organization with the following
|
you for the position of "<t t-esc="object.position or ''"/>" in our organization with the following
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api, _
|
||||||
|
from odoo.api import readonly
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
|
|
@ -26,8 +27,24 @@ class OfferLetter(models.Model):
|
||||||
default=lambda self: _('New'),
|
default=lambda self: _('New'),
|
||||||
copy=False
|
copy=False
|
||||||
)
|
)
|
||||||
candidate_id = fields.Many2one( 'hr.applicant', string='Candidate', required=True,
|
candidate_id = fields.Many2one( 'hr.applicant', string='Applicant', required=False,
|
||||||
)
|
)
|
||||||
|
main_candidate_id = fields.Many2one('hr.candidate',string='Candidate', readonly=False, required=True)
|
||||||
|
|
||||||
|
@api.onchange('candidate_id')
|
||||||
|
def _onchange_candidate_id(self):
|
||||||
|
if self.candidate_id:
|
||||||
|
self.main_candidate_id = self.candidate_id.candidate_id
|
||||||
|
|
||||||
|
main_candidate_name = fields.Char(compute="_compute_main_candidate_name", readonly=False)
|
||||||
|
|
||||||
|
@api.depends('candidate_id','main_candidate_id')
|
||||||
|
def _compute_main_candidate_name(self):
|
||||||
|
for rec in self:
|
||||||
|
if rec.candidate_id:
|
||||||
|
rec.main_candidate_name = rec.candidate_id.partner_name
|
||||||
|
elif rec.main_candidate_id:
|
||||||
|
rec.main_candidate_name = rec.main_candidate_id.partner_name
|
||||||
requested_by_id = fields.Many2one('res.users', string='Requested By', readonly=True, tracking=True)
|
requested_by_id = fields.Many2one('res.users', string='Requested By', readonly=True, tracking=True)
|
||||||
request_date = fields.Datetime(string='Requested On', readonly=True, tracking=True)
|
request_date = fields.Datetime(string='Requested On', readonly=True, tracking=True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,9 @@
|
||||||
<div style="margin-bottom: 25px;">
|
<div style="margin-bottom: 25px;">
|
||||||
<strong>To,</strong>
|
<strong>To,</strong>
|
||||||
<br/>
|
<br/>
|
||||||
<strong t-esc="o.candidate_id.partner_name"/>
|
<strong t-esc="o.main_candidate_id.partner_name"/>
|
||||||
<br/>
|
<br/>
|
||||||
<div t-if="o.candidate_id.private_street and o.candidate_id.private_city">
|
<div t-if="o.candidate_id and o.candidate_id.private_street and o.candidate_id.private_city">
|
||||||
<t t-esc="o.candidate_id.private_street"/>
|
<t t-esc="o.candidate_id.private_street"/>
|
||||||
<br/>
|
<br/>
|
||||||
<t t-esc="o.candidate_id.private_street2" t-if="o.candidate_id.private_street2"/>
|
<t t-esc="o.candidate_id.private_street2" t-if="o.candidate_id.private_street2"/>
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
<!-- DEAR LINE -->
|
<!-- DEAR LINE -->
|
||||||
<div style="margin-bottom: 20px;">
|
<div style="margin-bottom: 20px;">
|
||||||
<strong>Dear
|
<strong>Dear
|
||||||
<t t-esc="o.candidate_id.partner_name"/>,
|
<t t-esc="o.main_candidate_id.partner_name"/>,
|
||||||
</strong>
|
</strong>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -368,7 +368,7 @@
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<strong t-esc="o.candidate_id.partner_name"/>
|
<strong t-esc="o.main_candidate_id.partner_name"/>
|
||||||
<br/>
|
<br/>
|
||||||
<strong t-esc="o.position"/>
|
<strong t-esc="o.position"/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
@ -486,7 +486,7 @@
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<strong>Employee Name :
|
<strong>Employee Name :
|
||||||
<t t-esc="o.candidate_id.partner_name"/>
|
<t t-esc="o.main_candidate_id.partner_name"/>
|
||||||
</strong>
|
</strong>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
@ -595,7 +595,7 @@
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<strong t-esc="o.candidate_id.partner_name"/>
|
<strong t-esc="o.main_candidate_id.partner_name"/>
|
||||||
<br/>
|
<br/>
|
||||||
<strong t-esc="o.position"/>
|
<strong t-esc="o.position"/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
@ -621,7 +621,7 @@
|
||||||
Company incorporated under Indian Companies Act 1956, having registered office in
|
Company incorporated under Indian Companies Act 1956, having registered office in
|
||||||
Hyderabad,
|
Hyderabad,
|
||||||
India ("Company")
|
India ("Company")
|
||||||
<strong t-esc="o.candidate_id.partner_name"/>
|
<strong t-esc="o.main_candidate_id.partner_name"/>
|
||||||
(Recipient)
|
(Recipient)
|
||||||
</p>
|
</p>
|
||||||
<p>Whereas "Company" wishes to explore the possibility of entering into an employment
|
<p>Whereas "Company" wishes to explore the possibility of entering into an employment
|
||||||
|
|
@ -875,7 +875,7 @@
|
||||||
<strong t-esc="o.joining_date"/>
|
<strong t-esc="o.joining_date"/>
|
||||||
</td>
|
</td>
|
||||||
<td style="padding-top: 20px;">
|
<td style="padding-top: 20px;">
|
||||||
<strong t-esc="o.candidate_id.partner_name"/>
|
<strong t-esc="o.main_candidate_id.partner_name"/>
|
||||||
<br/>
|
<br/>
|
||||||
<strong t-esc="o.position"/>
|
<strong t-esc="o.position"/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<list>
|
<list>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="candidate_id"/>
|
<field name="main_candidate_name"/>
|
||||||
<field name="position"/>
|
<field name="position"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
<field name="sent_date"/>
|
<field name="sent_date"/>
|
||||||
|
|
@ -32,7 +32,9 @@
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="name" readonly="state != 'requested'"/>
|
<field name="name" readonly="state != 'requested'"/>
|
||||||
<field name="candidate_id"/>
|
<field name="main_candidate_name" invisible="1"/>
|
||||||
|
<field name="candidate_id" invisible="not candidate_id" readonly="1" force_save="1"/>
|
||||||
|
<field name="main_candidate_id" invisible="candidate_id" force_save="1"/>
|
||||||
<field name="requested_by_id" readonly="1"/>
|
<field name="requested_by_id" readonly="1"/>
|
||||||
<field name="request_date" readonly="1"/>
|
<field name="request_date" readonly="1"/>
|
||||||
<field name="manager_id"/>
|
<field name="manager_id"/>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
<field name="jd_file" filename="jd_file_name"
|
<field name="jd_file" filename="jd_file_name"
|
||||||
widget="binary" force_save="1"/>
|
widget="binary" force_save="1"/>
|
||||||
<field name="jd_file_name" invisible="1" force_save="1"/>
|
<field name="jd_file_name" invisible="1" force_save="1"/>
|
||||||
</group>
|
</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="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'"/>
|
<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="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_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']"/>
|
<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"/>
|
<field name="notes" placeholder="Remarks" readonly="state == 'jd_created'" invisible="not notes"/>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
|
|
@ -80,10 +80,18 @@
|
||||||
</list>
|
</list>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</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="name">Recruitment Requisitions</field>
|
||||||
<field name="res_model">recruitment.requisition</field>
|
<field name="res_model">recruitment.requisition</field>
|
||||||
<field name="view_mode">list,form</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>
|
</record>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue