fix: new dashboard and report
This commit is contained in:
parent
f6c7461eb8
commit
36aea71fd7
154
erpnext/hr/dashboard_fixtures.py
Normal file
154
erpnext/hr/dashboard_fixtures.py
Normal file
@ -0,0 +1,154 @@
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
import frappe
|
||||
import erpnext
|
||||
import json
|
||||
|
||||
def get_data():
|
||||
return frappe._dict({
|
||||
"dashboards": get_dashboards(),
|
||||
"charts": get_charts(),
|
||||
"number_cards": get_number_cards(),
|
||||
})
|
||||
|
||||
def get_dashboards():
|
||||
dashboards = []
|
||||
dashboards.append(get_human_resource_dashboard())
|
||||
return dashboards
|
||||
|
||||
def get_human_resource_dashboard():
|
||||
return {
|
||||
"name": "Human Resource",
|
||||
"dashboard_name": "Human Resource",
|
||||
"is_default": 1,
|
||||
"charts": [
|
||||
{ "chart": "Gender Diversity Ratio", "width": "Half"},
|
||||
{ "chart": "Employee Count", "width": "Half"},
|
||||
{ "chart": "Outgoing Salary", "width": "Full"},
|
||||
{ "chart": "Attendance Count", "width": "Full"}
|
||||
],
|
||||
"cards": [
|
||||
{"card": "Total Employees"},
|
||||
{"card": "New Joinees"},
|
||||
{'card': "Job Applicants"},
|
||||
{'card': "Employees Left"}
|
||||
]
|
||||
}
|
||||
|
||||
def get_recruitment_dashboard():
|
||||
pass
|
||||
# return {
|
||||
# "name": "Human Resource",
|
||||
# "dashboard_name": "Human Resource",
|
||||
# "is_default": 1,
|
||||
# "charts": [
|
||||
# ],
|
||||
# "cards": [
|
||||
# ]
|
||||
# }
|
||||
|
||||
|
||||
def get_charts():
|
||||
company = erpnext.get_default_company()
|
||||
|
||||
if not company:
|
||||
company = frappe.db.get_value("Company", {"is_group": 0}, "name")
|
||||
|
||||
dashboard_charts = [
|
||||
get_dashboards_chart_doc('Gender Diversity Ratio', "Group By", "Donut",document_type = "Employee", group_by_type="Count", group_by_based_on="gender", filters_json = json.dumps([["Employee","status","=","Active"]]), time_interval = "Monthly")
|
||||
]
|
||||
|
||||
dashboard_charts.append(
|
||||
get_dashboards_chart_doc('Outgoing salary', "Sum", "Line",document_type = "Salary Slip", group_by_type="Count", based_on="end_date", value_based_on = "rounded_total", time_interval = "Monthly", timeseries = 1 , filters_json = json.dumps([["Salary Slip","docstatus","=","1"]]))
|
||||
)
|
||||
|
||||
custom_options = '''{"type": "bar", "axisOptions": {"shortenYAxisNumbers": 1}, "tooltipOptions": {}, "barOptions":{"stacked": 1}}'''
|
||||
filters_json = json.dumps({"month":"May","year":"2020","company":company})
|
||||
|
||||
dashboard_charts.append(
|
||||
get_dashboards_chart_doc('Attendance Count', "Report", "Bar",report_name = "Monthly Attendance Sheet", is_custom =1,group_by_type="Count", timeseries = 1 , filters_json = filters_json, custom_options=custom_options)
|
||||
)
|
||||
|
||||
custom_options = """{"type": "donut", "axisOptions": {"shortenYAxisNumbers": 1}}"""
|
||||
filters_json = json.dumps({"company":company ,"parameter":"Department"})
|
||||
|
||||
dashboard_charts.append(
|
||||
get_dashboards_chart_doc('Employee Count', "Report", "Donut",report_name = "Employee Analytics", is_custom =1, group_by_type="Count", timeseries = 1 , filters_json = filters_json, custom_options=custom_options)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
def get_number_cards():
|
||||
number_cards = []
|
||||
|
||||
number_cards = [
|
||||
get_number_cards_doc("Employee", "Total Employees", filters_json = json.dumps([
|
||||
["Employee","status","=","Active"]
|
||||
])
|
||||
)
|
||||
]
|
||||
number_cards.append(
|
||||
get_number_cards_doc("Employee", "New Joinees", filters_json = json.dumps([
|
||||
["Employee","date_of_joining","Previous","6 months"],
|
||||
["Employee","status","=","Active"]
|
||||
]),
|
||||
stats_time_interval = "Daily")
|
||||
)
|
||||
number_cards.append(
|
||||
get_number_cards_doc("Employee", "Employees Left", filters_json = json.dumps([
|
||||
["Employee","status","=","Left"]
|
||||
])
|
||||
)
|
||||
)
|
||||
number_cards.append(
|
||||
get_number_cards_doc("Job Applicant", "Job Applicants", filters_json = json.dumps([
|
||||
["Job Applicant","status","!=","Rejected"]
|
||||
])
|
||||
)
|
||||
)
|
||||
|
||||
return number_cards
|
||||
|
||||
|
||||
def get_number_cards_doc(document_type, label, **args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
return {
|
||||
"doctype": "Number Card",
|
||||
"document_type": document_type,
|
||||
"function": args.func or "Count",
|
||||
"is_public": args.is_public or 1,
|
||||
"label": label,
|
||||
"name": args.name or label,
|
||||
"show_percentage_stats": args.show_percentage_stats or 1,
|
||||
"stats_time_interval": args.stats_time_interval or 'Monthly',
|
||||
"filters_json": args.filters_json or '[]',
|
||||
}
|
||||
|
||||
def get_dashboards_chart_doc(name, chart_type, graph_type, **args):
|
||||
|
||||
args = frappe._dict(args)
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
"chart_name": args.chart_name or name,
|
||||
"chart_type": chart_type,
|
||||
"document_type": args.document_type or None,
|
||||
"report_name": args.report_name or None,
|
||||
"is_custom": args.is_custom or 0,
|
||||
"group_by_type": args.group_by_type or None,
|
||||
"group_by_based_on": args.group_by_based_on or None,
|
||||
"based_on": args.based_on or None,
|
||||
"value_based_on": args.value_based_on or None,
|
||||
"number_of_groups": args.number_of_groups or 0,
|
||||
"is_public": args.is_public or 1,
|
||||
"timespan": args.timespan or "Last Year",
|
||||
"time_interval": args.time_interval or "Yearly",
|
||||
"timeseries": args.timeseries or 0,
|
||||
"filters_json": args.filters_json or '[]',
|
||||
"type": graph_type,
|
||||
"custom_options": args.custom_options or '',
|
||||
"doctype": "Dashboard Chart",
|
||||
}
|
@ -41,7 +41,7 @@ class Attendance(Document):
|
||||
leave_record = frappe.db.sql("""
|
||||
select leave_type, half_day, half_day_date
|
||||
from `tabLeave Application`
|
||||
where employee = %s
|
||||
where employee = %s
|
||||
and %s between from_date and to_date
|
||||
and status = 'Approved'
|
||||
and docstatus = 1
|
||||
@ -172,8 +172,8 @@ def get_unmarked_days(employee, month):
|
||||
|
||||
|
||||
records = frappe.get_all("Attendance", fields = ['attendance_date', 'employee'] , filters = [
|
||||
["attendance_date", ">", month_start],
|
||||
["attendance_date", "<", month_end],
|
||||
["attendance_date", ">=", month_start],
|
||||
["attendance_date", "<=", month_end],
|
||||
["employee", "=", employee],
|
||||
["docstatus", "!=", 2]
|
||||
])
|
||||
|
@ -131,6 +131,8 @@ class LeaveApplication(Document):
|
||||
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
|
||||
date = dt.strftime("%Y-%m-%d")
|
||||
status = "Half Day" if getdate(date) == getdate(self.half_day_date) else "On Leave"
|
||||
print("-------->>>", status)
|
||||
# frappe.throw("Hello")
|
||||
|
||||
attendance_name = frappe.db.exists('Attendance', dict(employee = self.employee,
|
||||
attendance_date = date, docstatus = ('!=', 2)))
|
||||
@ -596,7 +598,7 @@ def get_leave_entries(employee, leave_type, from_date, to_date):
|
||||
is_carry_forward, is_expired
|
||||
FROM `tabLeave Ledger Entry`
|
||||
WHERE employee=%(employee)s AND leave_type=%(leave_type)s
|
||||
AND docstatus=1
|
||||
AND docstatus=1
|
||||
AND (leaves<0
|
||||
OR is_expired=1)
|
||||
AND (from_date between %(from_date)s AND %(to_date)s
|
||||
|
@ -1,28 +0,0 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2018-05-15 15:37:20.883263",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2018-05-15 17:19:32.934321",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Department Analytics",
|
||||
"owner": "Administrator",
|
||||
"ref_doctype": "Employee",
|
||||
"report_name": "Department Analytics",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Employee"
|
||||
},
|
||||
{
|
||||
"role": "HR User"
|
||||
},
|
||||
{
|
||||
"role": "HR Manager"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Department Analytics"] = {
|
||||
frappe.query_reports["Employee Analytics"] = {
|
||||
"filters": [
|
||||
{
|
||||
"fieldname":"company",
|
||||
@ -11,5 +12,12 @@ frappe.query_reports["Department Analytics"] = {
|
||||
"default": frappe.defaults.get_user_default("Company"),
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"parameter",
|
||||
"label": __("Parameter"),
|
||||
"fieldtype": "Select",
|
||||
"options": ["Branch","Grade","Department","Designation", "Employment Type"],
|
||||
"reqd": 1
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
30
erpnext/hr/report/employee_analytics/employee_analytics.json
Normal file
30
erpnext/hr/report/employee_analytics/employee_analytics.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2020-05-12 13:52:50.631086",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2020-05-12 13:52:50.631086",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Analytics",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Employee",
|
||||
"report_name": "Employee Analytics",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Employee"
|
||||
},
|
||||
{
|
||||
"role": "HR User"
|
||||
},
|
||||
{
|
||||
"role": "HR Manager"
|
||||
}
|
||||
]
|
||||
}
|
@ -13,12 +13,13 @@ def execute(filters=None):
|
||||
|
||||
columns = get_columns()
|
||||
employees = get_employees(filters)
|
||||
departments_result = get_department(filters)
|
||||
departments = []
|
||||
if departments_result:
|
||||
for department in departments_result:
|
||||
departments.append(department)
|
||||
chart = get_chart_data(departments,employees)
|
||||
parameters_result = get_parameters(filters)
|
||||
parameters = []
|
||||
if parameters_result:
|
||||
for department in parameters_result:
|
||||
parameters.append(department)
|
||||
|
||||
chart = get_chart_data(parameters,employees, filters)
|
||||
return columns, employees, None, chart
|
||||
|
||||
def get_columns():
|
||||
@ -29,10 +30,8 @@ def get_columns():
|
||||
]
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = ""
|
||||
if filters.get("department"): conditions += " and department = '%s'" % \
|
||||
filters["department"].replace("'", "\\'")
|
||||
|
||||
conditions = " and "+filters.get("parameter").lower().replace(" ","_")+" IS NOT NULL "
|
||||
|
||||
if filters.get("company"): conditions += " and company = '%s'" % \
|
||||
filters["company"].replace("'", "\\'")
|
||||
return conditions
|
||||
@ -43,25 +42,38 @@ def get_employees(filters):
|
||||
branch, department, designation,
|
||||
gender, company from `tabEmployee` where status = 'Active' %s""" % conditions, as_list=1)
|
||||
|
||||
def get_department(filters):
|
||||
return frappe.db.sql("""select name from `tabDepartment` where company = %s""", (filters["company"]), as_list=1)
|
||||
|
||||
def get_chart_data(departments,employees):
|
||||
if not departments:
|
||||
departments = []
|
||||
def get_parameters(filters):
|
||||
return frappe.db.sql("""select name from `tab"""+filters.get("parameter")+"""` """, as_list=1)
|
||||
|
||||
def get_chart_data(parameters,employees, filters):
|
||||
if not parameters:
|
||||
parameters = []
|
||||
datasets = []
|
||||
for department in departments:
|
||||
if department:
|
||||
total_employee = frappe.db.sql("""select count(*) from \
|
||||
`tabEmployee` where \
|
||||
department = %s""" ,(department[0]), as_list=1)
|
||||
parameter_field_name = filters.get("parameter").lower().replace(" ","_")
|
||||
label = []
|
||||
for parameter in parameters:
|
||||
if parameter:
|
||||
total_employee = frappe.db.sql("""select count(*) from
|
||||
`tabEmployee` where """+
|
||||
parameter_field_name + """ = %s and company = %s""" ,( parameter[0], filters.get("company")), as_list=1)
|
||||
if total_employee[0][0]:
|
||||
label.append(parameter)
|
||||
datasets.append(total_employee[0][0])
|
||||
|
||||
values = [ value for value in datasets if value !=0]
|
||||
|
||||
total_employee = frappe.db.count('Employee', {'status':'Active'})
|
||||
others = total_employee - sum(values)
|
||||
|
||||
label.append(["Others"])
|
||||
values.append(others)
|
||||
|
||||
chart = {
|
||||
"data": {
|
||||
'labels': departments,
|
||||
'datasets': [{'name': 'Employees','values': datasets}]
|
||||
'labels': label,
|
||||
'datasets': [{'name': 'Employees','values': values}]
|
||||
}
|
||||
}
|
||||
chart["type"] = "bar"
|
||||
chart["type"] = "donut"
|
||||
return chart
|
||||
|
@ -31,7 +31,7 @@ def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
|
||||
conditions, filters = get_conditions(filters)
|
||||
columns = get_columns(filters)
|
||||
columns, days = get_columns(filters)
|
||||
att_map = get_attendance_list(conditions, filters)
|
||||
|
||||
if filters.group_by:
|
||||
@ -60,20 +60,77 @@ def execute(filters=None):
|
||||
columns.extend([_("Total Late Entries") + ":Float:120", _("Total Early Exits") + ":Float:120"])
|
||||
|
||||
if filters.group_by:
|
||||
emp_att_map = {}
|
||||
for parameter in group_by_parameters:
|
||||
data.append([ "<b>"+ parameter + "</b>"])
|
||||
record = add_data(emp_map[parameter], att_map, filters, holiday_map, conditions, leave_list=leave_list)
|
||||
record, aaa = add_data(emp_map[parameter], att_map, filters, holiday_map, conditions, leave_list=leave_list)
|
||||
emp_att_map.update(aaa)
|
||||
data += record
|
||||
else:
|
||||
record = add_data(emp_map, att_map, filters, holiday_map, conditions, leave_list=leave_list)
|
||||
record, emp_att_map = add_data(emp_map, att_map, filters, holiday_map, conditions, leave_list=leave_list)
|
||||
data += record
|
||||
|
||||
return columns, data
|
||||
chart_data = get_chart_data(emp_att_map, days)
|
||||
|
||||
return columns, data, None, chart_data
|
||||
|
||||
def get_chart_data(emp_att_map, days):
|
||||
from pprint import pprint
|
||||
pprint(emp_att_map)
|
||||
labels = []
|
||||
datasets = [
|
||||
{"name": "Absent", "values": []},
|
||||
{"name": "Present", "values": []},
|
||||
{"name": "Leave", "values": []},
|
||||
{"name": "Unmarked", "values": []}
|
||||
]
|
||||
for idx, day in enumerate(days, start=0):
|
||||
p = day.replace("::65", "")
|
||||
labels.append(day.replace("::65", ""))
|
||||
total_absent_on_day = 0
|
||||
total_leave_on_day = 0
|
||||
total_present_on_day = 0
|
||||
total_holiday = 0
|
||||
total_unmarked_on_day = 0
|
||||
for emp in emp_att_map.keys():
|
||||
if emp_att_map[emp][idx]:
|
||||
if emp_att_map[emp][idx] == "A":
|
||||
total_absent_on_day += 1
|
||||
if emp_att_map[emp][idx] in ["P", "WFH"]:
|
||||
total_present_on_day += 1
|
||||
if emp_att_map[emp][idx] == "HD":
|
||||
total_present_on_day += 0.5
|
||||
total_leave_on_day += 0.5
|
||||
if emp_att_map[emp][idx] == "L":
|
||||
total_leave_on_day += 1
|
||||
|
||||
total_marked = total_absent_on_day + total_present_on_day + total_leave_on_day
|
||||
|
||||
datasets[0]["values"].append(total_absent_on_day)
|
||||
datasets[1]["values"].append(total_present_on_day)
|
||||
datasets[2]["values"].append(total_leave_on_day)
|
||||
datasets[3]["values"].append(frappe.db.count('Employee', {'status':'Active'}) - total_marked)
|
||||
|
||||
|
||||
def add_data(employee_map, att_map, filters, holiday_map, conditions, leave_list=None):
|
||||
chart = {
|
||||
"data": {
|
||||
'labels': labels,
|
||||
'datasets': datasets
|
||||
}
|
||||
}
|
||||
|
||||
chart["type"] = "bar"
|
||||
# chart["spaceRatio"] = 0.1
|
||||
|
||||
|
||||
return chart
|
||||
|
||||
|
||||
|
||||
def add_data(employee_map, att_map, filters, holiday_map, conditions,leave_list=None):
|
||||
|
||||
record = []
|
||||
emp_att_map = {}
|
||||
for emp in employee_map:
|
||||
emp_det = employee_map.get(emp)
|
||||
if not emp_det or emp not in att_map:
|
||||
@ -85,6 +142,7 @@ def add_data(employee_map, att_map, filters, holiday_map, conditions, leave_list
|
||||
row += [emp, emp_det.employee_name]
|
||||
|
||||
total_p = total_a = total_l = total_h = total_um= 0.0
|
||||
ggg = []
|
||||
for day in range(filters["total_days_in_month"]):
|
||||
status = None
|
||||
status = att_map.get(emp).get(day + 1)
|
||||
@ -101,19 +159,12 @@ def add_data(employee_map, att_map, filters, holiday_map, conditions, leave_list
|
||||
status = "Holiday"
|
||||
total_h += 1
|
||||
|
||||
|
||||
# if emp_holiday_list in holiday_map and (day+1) in holiday_map[emp_holiday_list][0]:
|
||||
# if holiday_map[emp_holiday_list][1]:
|
||||
# status= "Weekly Off"
|
||||
# else:
|
||||
# status = "Holiday"
|
||||
|
||||
# += 1
|
||||
ggg.append(status_map.get(status, ""))
|
||||
|
||||
if not filters.summarized_view:
|
||||
row.append(status_map.get(status, ""))
|
||||
row += ggg
|
||||
else:
|
||||
if status == "Present":
|
||||
if status == "Present" or status == "Work From Home":
|
||||
total_p += 1
|
||||
elif status == "Absent":
|
||||
total_a += 1
|
||||
@ -159,10 +210,10 @@ def add_data(employee_map, att_map, filters, holiday_map, conditions, leave_list
|
||||
row.append("0.0")
|
||||
|
||||
row.extend([time_default_counts[0][0],time_default_counts[0][1]])
|
||||
emp_att_map[emp] = ggg
|
||||
record.append(row)
|
||||
|
||||
|
||||
return record
|
||||
return record, emp_att_map
|
||||
|
||||
def get_columns(filters):
|
||||
|
||||
@ -174,15 +225,17 @@ def get_columns(filters):
|
||||
columns += [
|
||||
_("Employee") + ":Link/Employee:120", _("Employee Name") + ":Link/Employee:120"
|
||||
]
|
||||
|
||||
days = []
|
||||
for day in range(filters["total_days_in_month"]):
|
||||
date = str(filters.year) + "-" + str(filters.month)+ "-" + str(day+1)
|
||||
day_name = day_abbr[getdate(date).weekday()]
|
||||
days.append(cstr(day+1)+ " " +day_name +"::65")
|
||||
if not filters.summarized_view:
|
||||
for day in range(filters["total_days_in_month"]):
|
||||
date = str(filters.year) + "-" + str(filters.month)+ "-" + str(day+1)
|
||||
day_name = day_abbr[getdate(date).weekday()]
|
||||
columns.append(cstr(day+1)+ " " +day_name +"::65")
|
||||
else:
|
||||
columns += days
|
||||
|
||||
if filters.summarized_view:
|
||||
columns += [_("Total Present") + ":Float:120", _("Total Leaves") + ":Float:120", _("Total Absent") + ":Float:120", _("Total Holidays") + ":Float:120", _("Unmarked Days")+ ":Float:120"]
|
||||
return columns
|
||||
return columns, days
|
||||
|
||||
def get_attendance_list(conditions, filters):
|
||||
attendance_list = frappe.db.sql("""select employee, day(attendance_date) as day_of_month,
|
||||
|
@ -61,7 +61,6 @@ def get_periodic_data(filters, entry):
|
||||
|
||||
elif getdate(d.planned_start_date) < getdate(from_date) :
|
||||
periodic_data = update_periodic_data(periodic_data, "Overdue", period)
|
||||
|
||||
else:
|
||||
periodic_data = update_periodic_data(periodic_data, "Not Started", period)
|
||||
|
||||
|
@ -680,3 +680,4 @@ erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
|
||||
erpnext.patches.v12_0.retain_permission_rules_for_video_doctype
|
||||
erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive
|
||||
execute:frappe.delete_doc_if_exists("Page", "appointment-analytic")
|
||||
execute:frappe.delete_doc("Report", "Department Analytics")
|
||||
|
Loading…
Reference in New Issue
Block a user