2021-12-05 16:25:13 +00:00
|
|
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
|
|
|
# License: MIT. See LICENSE
|
|
|
|
|
|
|
|
import frappe
|
|
|
|
from frappe import _
|
2021-12-12 17:50:04 +00:00
|
|
|
from frappe.query_builder import Order
|
2021-12-05 16:25:13 +00:00
|
|
|
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
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2021-12-05 16:25:13 +00:00
|
|
|
def get_columns():
|
|
|
|
return [
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"label": _("Employee"),
|
|
|
|
"fieldname": "employee",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"options": "Employee",
|
|
|
|
"width": 150,
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
2022-03-28 13:22:46 +00:00
|
|
|
{"label": _("Employee Name"), "fieldname": "employee_name", "fieldtype": "Data", "width": 150},
|
2021-12-05 16:25:13 +00:00
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"label": _("Date of Joining"),
|
|
|
|
"fieldname": "date_of_joining",
|
|
|
|
"fieldtype": "Date",
|
|
|
|
"width": 120,
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
2022-03-28 13:22:46 +00:00
|
|
|
{"label": _("Relieving Date"), "fieldname": "relieving_date", "fieldtype": "Date", "width": 120},
|
2021-12-05 16:25:13 +00:00
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"label": _("Exit Interview"),
|
|
|
|
"fieldname": "exit_interview",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"options": "Exit Interview",
|
|
|
|
"width": 150,
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"label": _("Interview Status"),
|
|
|
|
"fieldname": "interview_status",
|
|
|
|
"fieldtype": "Data",
|
|
|
|
"width": 130,
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"label": _("Final Decision"),
|
|
|
|
"fieldname": "employee_status",
|
|
|
|
"fieldtype": "Data",
|
|
|
|
"width": 150,
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"label": _("Full and Final Statement"),
|
|
|
|
"fieldname": "full_and_final_statement",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"options": "Full and Final Statement",
|
|
|
|
"width": 180,
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"label": _("Department"),
|
|
|
|
"fieldname": "department",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"options": "Department",
|
|
|
|
"width": 120,
|
2021-12-07 09:32:00 +00:00
|
|
|
},
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"label": _("Designation"),
|
|
|
|
"fieldname": "designation",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"options": "Designation",
|
|
|
|
"width": 120,
|
2021-12-07 09:32:00 +00:00
|
|
|
},
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"label": _("Reports To"),
|
|
|
|
"fieldname": "reports_to",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"options": "Employee",
|
|
|
|
"width": 120,
|
2021-12-07 09:32:00 +00:00
|
|
|
},
|
2021-12-05 16:25:13 +00:00
|
|
|
]
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2021-12-05 16:25:13 +00:00
|
|
|
def get_data(filters):
|
2022-03-28 13:22:46 +00:00
|
|
|
employee = frappe.qb.DocType("Employee")
|
|
|
|
interview = frappe.qb.DocType("Exit Interview")
|
|
|
|
fnf = frappe.qb.DocType("Full and Final Statement")
|
2021-12-05 16:25:13 +00:00
|
|
|
|
|
|
|
query = (
|
|
|
|
frappe.qb.from_(employee)
|
2022-03-28 13:22:46 +00:00
|
|
|
.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)))
|
|
|
|
)
|
|
|
|
.orderby(employee.relieving_date, order=Order.asc)
|
2021-12-05 16:25:13 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
query = get_conditions(filters, query, employee, interview, fnf)
|
|
|
|
result = query.run(as_dict=True)
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
def get_conditions(filters, query, employee, interview, fnf):
|
2022-03-28 13:22:46 +00:00
|
|
|
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"))]
|
|
|
|
)
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
elif filters.get("from_date"):
|
|
|
|
query = query.where(employee.relieving_date >= filters.get("from_date"))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
elif filters.get("to_date"):
|
|
|
|
query = query.where(employee.relieving_date <= filters.get("to_date"))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("company"):
|
|
|
|
query = query.where(employee.company == filters.get("company"))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("department"):
|
|
|
|
query = query.where(employee.department == filters.get("department"))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("designation"):
|
|
|
|
query = query.where(employee.designation == filters.get("designation"))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("employee"):
|
|
|
|
query = query.where(employee.name == filters.get("employee"))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("reports_to"):
|
|
|
|
query = query.where(employee.reports_to == filters.get("reports_to"))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("interview_status"):
|
|
|
|
query = query.where(interview.status == filters.get("interview_status"))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("final_decision"):
|
|
|
|
query = query.where(interview.employee_status == filters.get("final_decision"))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("exit_interview_pending"):
|
|
|
|
query = query.where((interview.name == "") | (interview.name.isnull()))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("questionnaire_pending"):
|
|
|
|
query = query.where(
|
|
|
|
(interview.reference_document_name == "") | (interview.reference_document_name.isnull())
|
|
|
|
)
|
2021-12-05 16:25:13 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if filters.get("fnf_pending"):
|
|
|
|
query = query.where((fnf.name == "") | (fnf.name.isnull()))
|
2021-12-05 16:25:13 +00:00
|
|
|
|
|
|
|
return query
|
|
|
|
|
|
|
|
|
|
|
|
def get_chart_data(data):
|
|
|
|
if not data:
|
|
|
|
return None
|
|
|
|
|
|
|
|
retained = 0
|
|
|
|
exit_confirmed = 0
|
|
|
|
pending = 0
|
|
|
|
|
|
|
|
for entry in data:
|
2022-03-28 13:22:46 +00:00
|
|
|
if entry.employee_status == "Employee Retained":
|
2021-12-05 16:25:13 +00:00
|
|
|
retained += 1
|
2022-03-28 13:22:46 +00:00
|
|
|
elif entry.employee_status == "Exit Confirmed":
|
2021-12-05 16:25:13 +00:00
|
|
|
exit_confirmed += 1
|
|
|
|
else:
|
|
|
|
pending += 1
|
|
|
|
|
|
|
|
chart = {
|
2022-03-28 13:22:46 +00:00
|
|
|
"data": {
|
|
|
|
"labels": [_("Retained"), _("Exit Confirmed"), _("Decision Pending")],
|
|
|
|
"datasets": [{"name": _("Employee Status"), "values": [retained, exit_confirmed, pending]}],
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
2022-03-28 13:22:46 +00:00
|
|
|
"type": "donut",
|
|
|
|
"colors": ["green", "red", "blue"],
|
2021-12-05 16:25:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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 [
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"value": total_resignations,
|
|
|
|
"label": _("Total Resignations"),
|
|
|
|
"indicator": "Red" if total_resignations > 0 else "Green",
|
|
|
|
"datatype": "Int",
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"value": interviews_pending,
|
|
|
|
"label": _("Pending Interviews"),
|
|
|
|
"indicator": "Blue" if interviews_pending > 0 else "Green",
|
|
|
|
"datatype": "Int",
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"value": fnf_pending,
|
|
|
|
"label": _("Pending FnF"),
|
|
|
|
"indicator": "Blue" if fnf_pending > 0 else "Green",
|
|
|
|
"datatype": "Int",
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
|
|
|
{
|
2022-03-28 13:22:46 +00:00
|
|
|
"value": questionnaires_pending,
|
|
|
|
"label": _("Pending Questionnaires"),
|
|
|
|
"indicator": "Blue" if questionnaires_pending > 0 else "Green",
|
|
|
|
"datatype": "Int",
|
2021-12-05 16:25:13 +00:00
|
|
|
},
|
|
|
|
]
|