mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-01 11:19:09 +00:00
feat: Employee Exits report
This commit is contained in:
0
erpnext/hr/report/employee_exits/__init__.py
Normal file
0
erpnext/hr/report/employee_exits/__init__.py
Normal file
77
erpnext/hr/report/employee_exits/employee_exits.js
Normal file
77
erpnext/hr/report/employee_exits/employee_exits.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.query_reports["Employee Exits"] = {
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
"fieldname": "from_date",
|
||||||
|
"label": __("From Date"),
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"default": frappe.datetime.add_months(frappe.datetime.nowdate(), -12)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "to_date",
|
||||||
|
"label": __("To Date"),
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"default": frappe.datetime.nowdate()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "company",
|
||||||
|
"label": __("Company"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Company"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "department",
|
||||||
|
"label": __("Department"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Department"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "designation",
|
||||||
|
"label": __("Designation"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Designation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "employee",
|
||||||
|
"label": __("Employee"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Employee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "reports_to",
|
||||||
|
"label": __("Reports To"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Employee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "interview_status",
|
||||||
|
"label": __("Interview Status"),
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"options": ["", "Pending", "Scheduled", "Completed"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "final_decision",
|
||||||
|
"label": __("Final Decision"),
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"options": ["", "Employee Retained", "Exit Confirmed"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "exit_interview_pending",
|
||||||
|
"label": __("Exit Interview Pending"),
|
||||||
|
"fieldtype": "Check"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "questionnaire_pending",
|
||||||
|
"label": __("Exit Questionnaire Pending"),
|
||||||
|
"fieldtype": "Check"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "fnf_pending",
|
||||||
|
"label": __("FnF Pending"),
|
||||||
|
"fieldtype": "Check"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
33
erpnext/hr/report/employee_exits/employee_exits.json
Normal file
33
erpnext/hr/report/employee_exits/employee_exits.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"columns": [],
|
||||||
|
"creation": "2021-12-05 19:47:18.332319",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"filters": [],
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"letter_head": "Test",
|
||||||
|
"modified": "2021-12-05 19:47:18.332319",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "HR",
|
||||||
|
"name": "Employee Exits",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "Exit Interview",
|
||||||
|
"report_name": "Employee Exits",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "System Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "HR Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "HR User"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
231
erpnext/hr/report/employee_exits/employee_exits.py
Normal file
231
erpnext/hr/report/employee_exits/employee_exits.py
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# License: MIT. See LICENSE
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import getdate
|
||||||
|
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
columns = get_columns()
|
||||||
|
data = get_data(filters)
|
||||||
|
chart = get_chart_data(data)
|
||||||
|
report_summary = get_report_summary(data)
|
||||||
|
|
||||||
|
return columns, data, None, chart, report_summary
|
||||||
|
|
||||||
|
def get_columns():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'label': _('Employee'),
|
||||||
|
'fieldname': 'employee',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Employee',
|
||||||
|
'width': 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Employee Name'),
|
||||||
|
'fieldname': 'employee_name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Date of Joining'),
|
||||||
|
'fieldname': 'date_of_joining',
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Relieving Date'),
|
||||||
|
'fieldname': 'relieving_date',
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Department'),
|
||||||
|
'fieldname': 'department',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Department',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Designation'),
|
||||||
|
'fieldname': 'designation',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Designation',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Reports To'),
|
||||||
|
'fieldname': 'reports_to',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Employee',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Exit Interview'),
|
||||||
|
'fieldname': 'exit_interview',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Exit Interview',
|
||||||
|
'width': 98
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Interview Status'),
|
||||||
|
'fieldname': 'interview_status',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 98
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Final Decision'),
|
||||||
|
'fieldname': 'employee_status',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 98
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Full and Final Statement'),
|
||||||
|
'fieldname': 'full_and_final_statement',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Full and Final Statement',
|
||||||
|
'width': 150
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_data(filters):
|
||||||
|
data = []
|
||||||
|
|
||||||
|
employee = frappe.qb.DocType('Employee')
|
||||||
|
interview = frappe.qb.DocType('Exit Interview')
|
||||||
|
fnf = frappe.qb.DocType('Full and Final Statement')
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.qb.from_(employee)
|
||||||
|
.left_join(interview).on(interview.employee == employee.name)
|
||||||
|
.left_join(fnf).on(fnf.employee == employee.name)
|
||||||
|
.select(
|
||||||
|
employee.name.as_('employee'), employee.employee_name.as_('employee_name'),
|
||||||
|
employee.date_of_joining.as_('date_of_joining'), employee.relieving_date.as_('relieving_date'),
|
||||||
|
employee.department.as_('department'), employee.designation.as_('designation'),
|
||||||
|
employee.reports_to.as_('reports_to'), interview.name.as_('exit_interview'),
|
||||||
|
interview.status.as_('interview_status'), interview.employee_status.as_('employee_status'),
|
||||||
|
interview.reference_document_name.as_('questionnaire'), fnf.name.as_('full_and_final_statement')
|
||||||
|
).distinct()
|
||||||
|
.where(
|
||||||
|
((employee.relieving_date.isnotnull()) | (employee.relieving_date != ''))
|
||||||
|
& ((interview.name.isnull()) | ((interview.name.isnotnull()) & (interview.docstatus != 2)))
|
||||||
|
& ((fnf.name.isnull()) | ((fnf.name.isnotnull()) & (fnf.docstatus != 2)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
query = get_conditions(filters, query, employee, interview, fnf)
|
||||||
|
result = query.run(as_dict=True)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_conditions(filters, query, employee, interview, fnf):
|
||||||
|
if filters.get('from_date') and filters.get('to_date'):
|
||||||
|
query = query.where(employee.relieving_date[getdate(filters.get('from_date')):getdate(filters.get('to_date'))])
|
||||||
|
|
||||||
|
elif filters.get('from_date'):
|
||||||
|
query = query.where(employee.relieving_date >= filters.get('from_date'))
|
||||||
|
|
||||||
|
elif filters.get('to_date'):
|
||||||
|
query = query.where(employee.relieving_date <= filters.get('to_date'))
|
||||||
|
|
||||||
|
if filters.get('company'):
|
||||||
|
query = query.where(employee.company == filters.get('company'))
|
||||||
|
|
||||||
|
if filters.get('department'):
|
||||||
|
query = query.where(employee.department == filters.get('department'))
|
||||||
|
|
||||||
|
if filters.get('designation'):
|
||||||
|
query = query.where(employee.designation == filters.get('designation'))
|
||||||
|
|
||||||
|
if filters.get('employee'):
|
||||||
|
query = query.where(employee.name == filters.get('employee'))
|
||||||
|
|
||||||
|
if filters.get('reports_to'):
|
||||||
|
query = query.where(employee.reports_to == filters.get('reports_to'))
|
||||||
|
|
||||||
|
if filters.get('interview_status'):
|
||||||
|
query = query.where(interview.status == filters.get('interview_status'))
|
||||||
|
|
||||||
|
if filters.get('final_decision'):
|
||||||
|
query = query.where(interview.employee_status == filters.get('final_decision'))
|
||||||
|
|
||||||
|
if filters.get('exit_interview_pending'):
|
||||||
|
query = query.where((interview.name == '') | (interview.name.isnull()))
|
||||||
|
|
||||||
|
if filters.get('questionnaire_pending'):
|
||||||
|
query = query.where((interview.reference_document_name == '') | (interview.reference_document_name.isnull()))
|
||||||
|
|
||||||
|
if filters.get('fnf_pending'):
|
||||||
|
query = query.where((fnf.name == '') | (interview.name.isnull()))
|
||||||
|
|
||||||
|
return query
|
||||||
|
|
||||||
|
|
||||||
|
def get_chart_data(data):
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
retained = 0
|
||||||
|
exit_confirmed = 0
|
||||||
|
pending = 0
|
||||||
|
|
||||||
|
for entry in data:
|
||||||
|
if entry.employee_status == 'Employee Retained':
|
||||||
|
retained += 1
|
||||||
|
elif entry.employee_status == 'Exit Confirmed':
|
||||||
|
exit_confirmed += 1
|
||||||
|
else:
|
||||||
|
pending += 1
|
||||||
|
|
||||||
|
chart = {
|
||||||
|
'data': {
|
||||||
|
'labels': [_('Retained'), _('Exit Confirmed'), _('Decision Pending')],
|
||||||
|
'datasets': [{'name': _('Employee Status'), 'values': [retained, exit_confirmed, pending]}]
|
||||||
|
},
|
||||||
|
'type': 'donut',
|
||||||
|
'colors': ['green', 'red', 'blue'],
|
||||||
|
}
|
||||||
|
|
||||||
|
return chart
|
||||||
|
|
||||||
|
|
||||||
|
def get_report_summary(data):
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
total_resignations = len(data)
|
||||||
|
interviews_pending = len([entry.name for entry in data if not entry.exit_interview])
|
||||||
|
fnf_pending = len([entry.name for entry in data if not entry.full_and_final_statement])
|
||||||
|
questionnaires_pending = len([entry.name for entry in data if not entry.questionnaire])
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'value': total_resignations,
|
||||||
|
'label': _('Total Resignations'),
|
||||||
|
'indicator': 'Red' if total_resignations > 0 else 'Green',
|
||||||
|
'datatype': 'Int',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'value': interviews_pending,
|
||||||
|
'label': _('Pending Interviews'),
|
||||||
|
'indicator': 'Blue' if interviews_pending > 0 else 'Green',
|
||||||
|
'datatype': 'Int',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'value': fnf_pending,
|
||||||
|
'label': _('Pending FnF'),
|
||||||
|
'indicator': 'Blue' if fnf_pending > 0 else 'Green',
|
||||||
|
'datatype': 'Int',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'value': questionnaires_pending,
|
||||||
|
'label': _('Pending Questionnaires'),
|
||||||
|
'indicator': 'Blue' if questionnaires_pending > 0 else 'Green',
|
||||||
|
'datatype': 'Int'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
Reference in New Issue
Block a user