diff --git a/erpnext/hr/dashboard_fixtures.py b/erpnext/hr/dashboard_fixtures.py new file mode 100644 index 00000000000..004477c26cc --- /dev/null +++ b/erpnext/hr/dashboard_fixtures.py @@ -0,0 +1,228 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe +import erpnext +import json +from frappe import _ + +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": "Outgoing Salary", "width": "Full"}, + { "chart": "Gender Diversity Ratio", "width": "Half"}, + { "chart": "Job Application Status", "width": "Half"}, + { "chart": 'Designation Wise Employee Count', "width": "Half"}, + { "chart": 'Department Wise Employee Count', "width": "Half"}, + { "chart": 'Designation Wise Openings', "width": "Half"}, + { "chart": 'Department Wise Openings', "width": "Half"}, + { "chart": "Attendance Count", "width": "Full"} + ], + "cards": [ + {"card": "Total Employees"}, + {"card": "New Joinees (Last year)"}, + {'card': "Employees Left (Last year)"}, + {'card': "Total Job Openings (Last month)"}, + {'card': "Total Applicants (Last month)"}, + {'card': "Shortlisted Candidates (Last month)"}, + {'card': "Rejected Candidates (Last month)"}, + {'card': "Total Job Offered (Last month)"}, + ] + } + +def get_recruitment_dashboard(): + pass + + +def get_charts(): + company = erpnext.get_default_company() + date = frappe.utils.get_datetime() + + month_map = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov","Dec"] + + + if not company: + company = frappe.db.get_value("Company", {"is_group": 0}, "name") + + dashboard_charts = [ + get_dashboards_chart_doc('Gender Diversity Ratio', "Group By", "Pie", + document_type = "Employee", group_by_type="Count", group_by_based_on="gender", + filters_json = json.dumps([["Employee", "status", "=", "Active"]])) + ] + + dashboard_charts.append( + get_dashboards_chart_doc('Job Application Status', "Group By", "Pie", + document_type = "Job Applicant", group_by_type="Count", group_by_based_on="status", + filters_json = json.dumps([["Job Applicant", "creation", "Previous", "1 month"]])) + ) + + dashboard_charts.append( + get_dashboards_chart_doc('Outgoing Salary', "Sum", "Line", + document_type = "Salary Slip", 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": "line", + "axisOptions": { + "shortenYAxisNumbers": 1 + }, + "tooltipOptions": {} + }''' + + filters_json = json.dumps({ + "month": month_map[date.month - 1], + "year": str(date.year), + "company":company + }) + + dashboard_charts.append( + get_dashboards_chart_doc('Attendance Count', "Report", "Line", + report_name = "Monthly Attendance Sheet", is_custom =1, group_by_type="Count", + filters_json = filters_json, custom_options=custom_options) + ) + + dashboard_charts.append( + get_dashboards_chart_doc('Department Wise Employee Count', "Group By", "Donut", + document_type = "Employee", group_by_type="Count", group_by_based_on="department", + filters_json = json.dumps([["Employee", "status", "=", "Active"]])) + ) + + dashboard_charts.append( + get_dashboards_chart_doc('Designation Wise Employee Count', "Group By", "Donut", + document_type = "Employee", group_by_type="Count", group_by_based_on="designation", + filters_json = json.dumps([["Employee", "status", "=", "Active"]])) + ) + + dashboard_charts.append( + get_dashboards_chart_doc('Designation Wise Openings', "Group By", "Bar", + document_type = "Job Opening", group_by_type="Sum", group_by_based_on="designation", + time_interval = "Monthly", aggregate_function_based_on = "planned_vacancies") + ) + dashboard_charts.append( + get_dashboards_chart_doc('Department Wise Openings', "Group By", "Bar", + document_type = "Job Opening", group_by_type="Sum", group_by_based_on="department", + time_interval = "Monthly", aggregate_function_based_on = "planned_vacancies") + ) + return dashboard_charts + + +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 (Last year)", filters_json = json.dumps([ + ["Employee","date_of_joining","Previous","1 year"], + ["Employee","status","=","Active"] + ]) + ) + ) + + number_cards.append( + get_number_cards_doc("Employee", "Employees Left (Last year)", filters_json = json.dumps([ + ["Employee", "modified", "Previous", "1 year"], + ["Employee", "status", "=", "Left"] + ]) + ) + ) + + number_cards.append( + get_number_cards_doc("Job Applicant", "Total Applicants (Last month)", filters_json = json.dumps([ + ["Job Applicant", "creation", "Previous", "1 month"] + ]) + ) + ) + + number_cards.append( + get_number_cards_doc("Job Opening", "Total Job Openings (Last month)", func = "Sum", + aggregate_function_based_on = "planned_vacancies", + filters_json = json.dumps([["Job Opening", "creation", "Previous", "1 month"]]) + ) + ) + number_cards.append( + get_number_cards_doc("Job Applicant", "Shortlisted Candidates (Last month)", filters_json = json.dumps([ + ["Job Applicant", "status", "=", "Accepted"], + ["Job Applicant", "creation", "Previous", "1 month"] + ]) + ) + ) + number_cards.append( + get_number_cards_doc("Job Applicant", "Rejected Candidates (Last month)", filters_json = json.dumps([ + ["Job Applicant", "status", "=", "Rejected"], + ["Job Applicant", "creation", "Previous", "1 month"] + ]) + ) + ) + number_cards.append( + get_number_cards_doc("Job Offer", "Total Job Offered (Last month)", + filters_json = json.dumps([["Job Offer", "creation", "Previous", "1 month"]]) + ) + ) + + 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 '[]', + "aggregate_function_based_on": args.aggregate_function_based_on or None + } + +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", + "aggregate_function_based_on": args.aggregate_function_based_on or None + } \ No newline at end of file diff --git a/erpnext/hr/desk_page/hr/hr.json b/erpnext/hr/desk_page/hr/hr.json index 22aa170744c..2d0e8857cab 100644 --- a/erpnext/hr/desk_page/hr/hr.json +++ b/erpnext/hr/desk_page/hr/hr.json @@ -77,21 +77,27 @@ } ], "category": "Modules", - "charts": [], + "charts": [ + { + "chart_name": "Outgoing Salary", + "label": "Outgoing Salary" + } + ], "creation": "2020-03-02 15:48:58.322521", "developer_mode_only": 0, "disable_user_customization": 0, "docstatus": 0, "doctype": "Desk Page", "extends_another_page": 0, - "icon": "", + "hide_custom": 0, "idx": 0, "is_standard": 1, "label": "HR", - "modified": "2020-04-29 20:29:22.114309", + "modified": "2020-05-20 11:20:54.255557", "modified_by": "Administrator", "module": "HR", "name": "HR", + "onboarding": "Human Resource", "owner": "Administrator", "pin_to_bottom": 0, "pin_to_top": 0, @@ -104,33 +110,33 @@ "type": "DocType" }, { - "format": "{} Unpaid", - "label": "Expense Claim", - "link_to": "Expense Claim", - "stats_filter": "{\"approval_status\":\"Draft\"}", - "type": "DocType" - }, - { - "format": "{} Open", - "label": "Job Applicant", - "link_to": "Job Applicant", - "stats_filter": "{\n \"status\": \"Open\"\n}", - "type": "DocType" - }, - { - "label": "Salary Structure", - "link_to": "Salary Structure", + "label": "Attendance", + "link_to": "Attendance", + "stats_filter": "", "type": "DocType" }, { "label": "Leave Application", "link_to": "Leave Application", + "stats_filter": "{\"status\":\"Open\"}", + "type": "DocType" + }, + { + "label": "Salary Structure", + "link_to": "Payroll Entry", "type": "DocType" }, { "label": "Salary Register", - "link_to": "Salary Register", + "link_to": "Monthly Attendance Sheet", "type": "Report" + }, + { + "format": "{} Open", + "label": "HR Dashboard", + "link_to": "Human Resource", + "stats_filter": "{\n \"status\": \"Open\"\n}", + "type": "Dashboard" } ] } \ No newline at end of file diff --git a/erpnext/hr/doctype/attendance/attendance.py b/erpnext/hr/doctype/attendance/attendance.py index 6c7ee002db4..45b7060610d 100644 --- a/erpnext/hr/doctype/attendance/attendance.py +++ b/erpnext/hr/doctype/attendance/attendance.py @@ -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] ]) diff --git a/erpnext/hr/doctype/leave_application/leave_application.json b/erpnext/hr/doctype/leave_application/leave_application.json index 74707a24b86..7f50ace7663 100644 --- a/erpnext/hr/doctype/leave_application/leave_application.json +++ b/erpnext/hr/doctype/leave_application/leave_application.json @@ -174,7 +174,8 @@ "label": "Status", "no_copy": 1, "options": "Open\nApproved\nRejected\nCancelled", - "permlevel": 1 + "permlevel": 1, + "reqd": 1 }, { "fieldname": "sb10", @@ -189,14 +190,14 @@ "reqd": 1 }, { + "fetch_from": "employee.company", "fieldname": "company", "fieldtype": "Link", "label": "Company", "options": "Company", "read_only": 1, "remember_last_selected_value": 1, - "reqd": 1, - "fetch_from": "employee.company" + "reqd": 1 }, { "allow_on_submit": 1, @@ -249,7 +250,7 @@ "is_submittable": 1, "links": [], "max_attachments": 3, - "modified": "2020-03-10 22:40:43.487721", + "modified": "2020-05-18 13:00:41.577327", "modified_by": "Administrator", "module": "HR", "name": "Leave Application", @@ -334,4 +335,4 @@ "sort_order": "DESC", "timeline_field": "employee", "title_field": "employee_name" -} +} \ No newline at end of file diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index d2620bec919..84f2c836cc6 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -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 diff --git a/erpnext/hr/module_onboarding/human_resource/human_resource.json b/erpnext/hr/module_onboarding/human_resource/human_resource.json new file mode 100644 index 00000000000..e64582b407c --- /dev/null +++ b/erpnext/hr/module_onboarding/human_resource/human_resource.json @@ -0,0 +1,51 @@ +{ + "allow_roles": [ + { + "role": "HR Manager" + }, + { + "role": "HR User" + } + ], + "creation": "2020-05-14 11:51:45.050242", + "docstatus": 0, + "doctype": "Module Onboarding", + "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/human-resources", + "idx": 0, + "is_complete": 0, + "modified": "2020-05-20 11:20:07.992597", + "modified_by": "Administrator", + "module": "HR", + "name": "Human Resource", + "owner": "Administrator", + "steps": [ + { + "step": "Create Department" + }, + { + "step": "Create Designation" + }, + { + "step": "Create Holiday list" + }, + { + "step": "Create Employee" + }, + { + "step": "Create Leave Type" + }, + { + "step": "Create Leave Allocation" + }, + { + "step": "Create Leave Application" + }, + { + "step": "HR Settings" + } + ], + "subtitle": "Employee, Leaves and more.", + "success_message": "The HR Module is all set up!", + "title": "Let's Setup the Human Resource Module. ", + "user_can_dismiss": 0 +} \ No newline at end of file diff --git a/erpnext/hr/onboarding_step/create_department/create_department.json b/erpnext/hr/onboarding_step/create_department/create_department.json new file mode 100644 index 00000000000..66a54cfc268 --- /dev/null +++ b/erpnext/hr/onboarding_step/create_department/create_department.json @@ -0,0 +1,19 @@ +{ + "action": "Create Entry", + "creation": "2020-05-14 11:44:34.682115", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 0, + "is_single": 0, + "is_skipped": 0, + "modified": "2020-05-14 12:22:26.448420", + "modified_by": "Administrator", + "name": "Create Department", + "owner": "Administrator", + "reference_document": "Department", + "show_full_form": 0, + "title": "Create Department", + "validate_action": 0 +} \ No newline at end of file diff --git a/erpnext/hr/onboarding_step/create_designation/create_designation.json b/erpnext/hr/onboarding_step/create_designation/create_designation.json new file mode 100644 index 00000000000..c4e9cc77986 --- /dev/null +++ b/erpnext/hr/onboarding_step/create_designation/create_designation.json @@ -0,0 +1,19 @@ +{ + "action": "Create Entry", + "creation": "2020-05-14 11:45:07.514193", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 0, + "is_single": 0, + "is_skipped": 0, + "modified": "2020-05-14 12:22:41.500795", + "modified_by": "Administrator", + "name": "Create Designation", + "owner": "Administrator", + "reference_document": "Designation", + "show_full_form": 0, + "title": "Create Designation", + "validate_action": 0 +} \ No newline at end of file diff --git a/erpnext/hr/onboarding_step/create_employee/create_employee.json b/erpnext/hr/onboarding_step/create_employee/create_employee.json new file mode 100644 index 00000000000..3aa33c6d862 --- /dev/null +++ b/erpnext/hr/onboarding_step/create_employee/create_employee.json @@ -0,0 +1,19 @@ +{ + "action": "Create Entry", + "creation": "2020-05-14 11:43:25.561152", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 1, + "is_single": 0, + "is_skipped": 0, + "modified": "2020-05-14 12:26:28.629074", + "modified_by": "Administrator", + "name": "Create Employee", + "owner": "Administrator", + "reference_document": "Employee", + "show_full_form": 0, + "title": "Create Employee", + "validate_action": 0 +} \ No newline at end of file diff --git a/erpnext/hr/onboarding_step/create_holiday_list/create_holiday_list.json b/erpnext/hr/onboarding_step/create_holiday_list/create_holiday_list.json new file mode 100644 index 00000000000..25cb9febd00 --- /dev/null +++ b/erpnext/hr/onboarding_step/create_holiday_list/create_holiday_list.json @@ -0,0 +1,19 @@ +{ + "action": "Create Entry", + "creation": "2020-05-14 11:47:34.700174", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 1, + "is_single": 0, + "is_skipped": 0, + "modified": "2020-05-14 12:25:38.068582", + "modified_by": "Administrator", + "name": "Create Holiday list", + "owner": "Administrator", + "reference_document": "Holiday List", + "show_full_form": 0, + "title": "Create Holiday list", + "validate_action": 0 +} \ No newline at end of file diff --git a/erpnext/hr/onboarding_step/create_leave_allocation/create_leave_allocation.json b/erpnext/hr/onboarding_step/create_leave_allocation/create_leave_allocation.json new file mode 100644 index 00000000000..fa9941e6b97 --- /dev/null +++ b/erpnext/hr/onboarding_step/create_leave_allocation/create_leave_allocation.json @@ -0,0 +1,19 @@ +{ + "action": "Create Entry", + "creation": "2020-05-14 11:48:56.123718", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 1, + "is_single": 0, + "is_skipped": 0, + "modified": "2020-05-14 11:48:56.123718", + "modified_by": "Administrator", + "name": "Create Leave Allocation", + "owner": "Administrator", + "reference_document": "Leave Allocation", + "show_full_form": 0, + "title": "Create Leave Allocation", + "validate_action": 0 +} \ No newline at end of file diff --git a/erpnext/hr/onboarding_step/create_leave_application/create_leave_application.json b/erpnext/hr/onboarding_step/create_leave_application/create_leave_application.json new file mode 100644 index 00000000000..1ed074e9a1d --- /dev/null +++ b/erpnext/hr/onboarding_step/create_leave_application/create_leave_application.json @@ -0,0 +1,19 @@ +{ + "action": "Create Entry", + "creation": "2020-05-14 11:49:45.400764", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 1, + "is_single": 0, + "is_skipped": 0, + "modified": "2020-05-14 11:49:45.400764", + "modified_by": "Administrator", + "name": "Create Leave Application", + "owner": "Administrator", + "reference_document": "Leave Application", + "show_full_form": 0, + "title": "Create Leave Application", + "validate_action": 0 +} \ No newline at end of file diff --git a/erpnext/hr/onboarding_step/create_leave_type/create_leave_type.json b/erpnext/hr/onboarding_step/create_leave_type/create_leave_type.json new file mode 100644 index 00000000000..e8b97c2e5ba --- /dev/null +++ b/erpnext/hr/onboarding_step/create_leave_type/create_leave_type.json @@ -0,0 +1,19 @@ +{ + "action": "Create Entry", + "creation": "2020-05-20 11:17:31.119312", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 1, + "is_single": 0, + "is_skipped": 0, + "modified": "2020-05-20 11:17:31.119312", + "modified_by": "Administrator", + "name": "Create Leave Type", + "owner": "Administrator", + "reference_document": "Leave Type", + "show_full_form": 0, + "title": "Create Leave Type", + "validate_action": 0 +} \ No newline at end of file diff --git a/erpnext/hr/onboarding_step/hr_settings/hr_settings.json b/erpnext/hr/onboarding_step/hr_settings/hr_settings.json new file mode 100644 index 00000000000..a8c96fb6827 --- /dev/null +++ b/erpnext/hr/onboarding_step/hr_settings/hr_settings.json @@ -0,0 +1,19 @@ +{ + "action": "Update Settings", + "creation": "2020-05-14 13:13:52.427711", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 0, + "is_single": 1, + "is_skipped": 0, + "modified": "2020-05-20 11:16:42.430974", + "modified_by": "Administrator", + "name": "HR Settings", + "owner": "Administrator", + "reference_document": "HR Settings", + "show_full_form": 0, + "title": "HR settings", + "validate_action": 0 +} \ No newline at end of file diff --git a/erpnext/hr/report/department_analytics/department_analytics.json b/erpnext/hr/report/department_analytics/department_analytics.json deleted file mode 100644 index 1e26b33c530..00000000000 --- a/erpnext/hr/report/department_analytics/department_analytics.json +++ /dev/null @@ -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" - } - ] -} \ No newline at end of file diff --git a/erpnext/hr/report/department_analytics/__init__.py b/erpnext/hr/report/employee_analytics/__init__.py similarity index 100% rename from erpnext/hr/report/department_analytics/__init__.py rename to erpnext/hr/report/employee_analytics/__init__.py diff --git a/erpnext/hr/report/department_analytics/department_analytics.js b/erpnext/hr/report/employee_analytics/employee_analytics.js similarity index 55% rename from erpnext/hr/report/department_analytics/department_analytics.js rename to erpnext/hr/report/employee_analytics/employee_analytics.js index 29fedcd7350..8620a65a909 100644 --- a/erpnext/hr/report/department_analytics/department_analytics.js +++ b/erpnext/hr/report/employee_analytics/employee_analytics.js @@ -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 + } ] -}; \ No newline at end of file +}; diff --git a/erpnext/hr/report/employee_analytics/employee_analytics.json b/erpnext/hr/report/employee_analytics/employee_analytics.json new file mode 100644 index 00000000000..5a7ab9a251e --- /dev/null +++ b/erpnext/hr/report/employee_analytics/employee_analytics.json @@ -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" + } + ] +} \ No newline at end of file diff --git a/erpnext/hr/report/department_analytics/department_analytics.py b/erpnext/hr/report/employee_analytics/employee_analytics.py similarity index 51% rename from erpnext/hr/report/department_analytics/department_analytics.py rename to erpnext/hr/report/employee_analytics/employee_analytics.py index b28eac43f8b..df64006c1be 100644 --- a/erpnext/hr/report/department_analytics/department_analytics.py +++ b/erpnext/hr/report/employee_analytics/employee_analytics.py @@ -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(["Not Set"]) + 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 diff --git a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py index 82ed27715f7..efc43bf1d1b 100644 --- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py +++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py @@ -30,8 +30,11 @@ day_abbr = [ def execute(filters=None): if not filters: filters = {} + if filters.hide_year_field == 1: + filters.year = 2020 + 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 +63,67 @@ 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([ ""+ parameter + ""]) - 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): + labels = [] + datasets = [ + {"name": "Absent", "values": []}, + {"name": "Present", "values": []}, + {"name": "Leave", "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 + 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 -def add_data(employee_map, att_map, filters, holiday_map, conditions, leave_list=None): + datasets[0]["values"].append(total_absent_on_day) + datasets[1]["values"].append(total_present_on_day) + datasets[2]["values"].append(total_leave_on_day) + + + chart = { + "data": { + 'labels': labels, + 'datasets': datasets + } + } + + chart["type"] = "line" + + 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 +135,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 +152,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 +203,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 +218,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, diff --git a/erpnext/manufacturing/report/production_analytics/production_analytics.py b/erpnext/manufacturing/report/production_analytics/production_analytics.py index f62cd255b5e..79af8a1e39b 100644 --- a/erpnext/manufacturing/report/production_analytics/production_analytics.py +++ b/erpnext/manufacturing/report/production_analytics/production_analytics.py @@ -55,32 +55,27 @@ def get_periodic_data(filters, entry): if d.status == 'Completed': if getdate(d.actual_end_date) < getdate(from_date) or getdate(d.modified) < getdate(from_date): periodic_data = update_periodic_data(periodic_data, "Completed", period) - elif getdate(d.actual_start_date) < getdate(from_date) : periodic_data = update_periodic_data(periodic_data, "Pending", period) - 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) elif d.status == 'In Process': if getdate(d.actual_start_date) < getdate(from_date) : periodic_data = update_periodic_data(periodic_data, "Pending", period) - 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) elif d.status == 'Not Started': if 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) + return periodic_data def update_periodic_data(periodic_data, status, period): diff --git a/erpnext/patches.txt b/erpnext/patches.txt index bb9bb97e64a..af7cb8eeda9 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -690,3 +690,4 @@ execute:frappe.delete_doc_if_exists('Dashboard', 'Accounts') erpnext.patches.v13_0.update_actual_start_and_end_date_in_wo erpnext.patches.v13_0.set_company_field_in_healthcare_doctypes erpnext.patches.v12_0.update_bom_in_so_mr +execute:frappe.delete_doc("Report", "Department Analytics")