diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py index ffd6e42f1b0..43ceda875e1 100755 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py @@ -296,18 +296,27 @@ class LeaveAllocation(Document): def get_previous_allocation(from_date, leave_type, employee): """Returns document properties of previous allocation""" - return frappe.db.get_value( - "Leave Allocation", - filters={ - "to_date": ("<", from_date), - "leave_type": leave_type, - "employee": employee, - "docstatus": 1, - }, - order_by="to_date DESC", - fieldname=["name", "from_date", "to_date", "employee", "leave_type"], - as_dict=1, - ) + Allocation = frappe.qb.DocType("Leave Allocation") + allocations = ( + frappe.qb.from_(Allocation) + .select( + Allocation.name, + Allocation.from_date, + Allocation.to_date, + Allocation.employee, + Allocation.leave_type, + ) + .where( + (Allocation.employee == employee) + & (Allocation.leave_type == leave_type) + & (Allocation.to_date < from_date) + & (Allocation.docstatus == 1) + ) + .orderby(Allocation.to_date, order=frappe.qb.desc) + .limit(1) + ).run(as_dict=True) + + return allocations[0] if allocations else None def get_leave_allocation_for_period( diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index d6f8c25b424..daa5205133e 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -706,19 +706,22 @@ def get_allocation_expiry_for_cf_leaves( employee: str, leave_type: str, to_date: str, from_date: str ) -> str: """Returns expiry of carry forward allocation in leave ledger entry""" - expiry = frappe.get_all( - "Leave Ledger Entry", - filters={ - "employee": employee, - "leave_type": leave_type, - "is_carry_forward": 1, - "transaction_type": "Leave Allocation", - "to_date": ["between", (from_date, to_date)], - "docstatus": 1, - }, - fields=["to_date"], - ) - return expiry[0]["to_date"] if expiry else "" + Ledger = frappe.qb.DocType("Leave Ledger Entry") + expiry = ( + frappe.qb.from_(Ledger) + .select(Ledger.to_date) + .where( + (Ledger.employee == employee) + & (Ledger.leave_type == leave_type) + & (Ledger.is_carry_forward == 1) + & (Ledger.transaction_type == "Leave Allocation") + & (Ledger.to_date.between(from_date, to_date)) + & (Ledger.docstatus == 1) + ) + .limit(1) + ).run() + + return expiry[0][0] if expiry else "" @frappe.whitelist() @@ -1017,7 +1020,7 @@ def get_leaves_for_period( if leave_entry.leaves % 1: half_day = 1 half_day_date = frappe.db.get_value( - "Leave Application", {"name": leave_entry.transaction_name}, ["half_day_date"] + "Leave Application", leave_entry.transaction_name, "half_day_date" ) leave_days += ( diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json index d74760a5cf8..b02e2f18817 100644 --- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json +++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json @@ -27,7 +27,8 @@ "in_list_view": 1, "in_standard_filter": 1, "label": "Employee", - "options": "Employee" + "options": "Employee", + "search_index": 1 }, { "fetch_from": "employee.employee_name", @@ -57,13 +58,15 @@ "fieldtype": "Link", "in_standard_filter": 1, "label": "Transaction Type", - "options": "DocType" + "options": "DocType", + "search_index": 1 }, { "fieldname": "transaction_name", "fieldtype": "Dynamic Link", "label": "Transaction Name", - "options": "transaction_type" + "options": "transaction_type", + "search_index": 1 }, { "fieldname": "leaves", @@ -123,7 +126,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-01-04 18:47:45.146652", + "modified": "2023-11-17 12:36:36.963697", "modified_by": "Administrator", "module": "HR", "name": "Leave Ledger Entry", diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py index fed9f770dfc..396e88e8d3a 100644 --- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py +++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py @@ -225,3 +225,7 @@ def expire_carried_forward_allocation(allocation): to_date=allocation.to_date, ) create_leave_ledger_entry(allocation, args) + + +def on_doctype_update(): + frappe.db.add_index("Leave Ledger Entry", ["transaction_type", "transaction_name"]) diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.json b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.json index 8b47f7e842d..577f6a7b70e 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.json +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.json @@ -1,26 +1,32 @@ { - "add_total_row": 0, - "apply_user_permissions": 1, - "creation": "2013-02-22 15:29:34", - "disabled": 0, - "docstatus": 0, - "doctype": "Report", - "idx": 3, - "is_standard": "Yes", - "modified": "2017-02-24 20:18:04.317397", - "modified_by": "Administrator", - "module": "HR", - "name": "Employee Leave Balance", - "owner": "Administrator", - "ref_doctype": "Employee", - "report_name": "Employee Leave Balance", - "report_type": "Script Report", + "add_total_row": 0, + "columns": [], + "creation": "2013-02-22 15:29:34", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 3, + "is_standard": "Yes", + "letterhead": null, + "modified": "2023-11-17 13:28:40.669200", + "modified_by": "Administrator", + "module": "HR", + "name": "Employee Leave Balance", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Employee", + "report_name": "Employee Leave Balance", + "report_type": "Script Report", "roles": [ { "role": "HR User" - }, + }, { "role": "HR Manager" + }, + { + "role": "Employee" } ] } \ No newline at end of file diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py index 192b255f3e0..c45cb5849ed 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py @@ -85,19 +85,10 @@ def get_columns() -> List[Dict]: def get_data(filters: Filters) -> List: - leave_types = frappe.db.get_list("Leave Type", pluck="name", order_by="name") - conditions = get_conditions(filters) + leave_types = get_leave_types() + active_employees = get_employees(filters) - user = frappe.session.user - department_approver_map = get_department_leave_approver_map(filters.department) - - active_employees = frappe.get_list( - "Employee", - filters=conditions, - fields=["name", "employee_name", "department", "user_id", "leave_approver"], - ) - - precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True)) + precision = cint(frappe.db.get_single_value("System Settings", "float_precision")) consolidate_leave_types = len(active_employees) > 1 and filters.consolidate_leave_types row = None @@ -110,10 +101,6 @@ def get_data(filters: Filters) -> List: row = frappe._dict({"leave_type": leave_type}) for employee in active_employees: - leave_approvers = department_approver_map.get(employee.department_name, []).append( - employee.leave_approver - ) - if consolidate_leave_types: row = frappe._dict() else: @@ -144,6 +131,35 @@ def get_data(filters: Filters) -> List: return data +def get_leave_types() -> List[str]: + LeaveType = frappe.qb.DocType("Leave Type") + leave_types = (frappe.qb.from_(LeaveType).select(LeaveType.name).orderby(LeaveType.name)).run( + as_dict=True + ) + return [leave_type.name for leave_type in leave_types] + + +def get_employees(filters: Filters) -> List[Dict]: + Employee = frappe.qb.DocType("Employee") + query = frappe.qb.from_(Employee).select( + Employee.name, + Employee.employee_name, + Employee.department, + ) + + for field in ["company", "department"]: + if filters.get(field): + query = query.where((getattr(Employee, field) == filters.get(field))) + + if filters.get("employee"): + query = query.where(Employee.name == filters.get("employee")) + + if filters.get("employee_status"): + query = query.where(Employee.status == filters.get("employee_status")) + + return query.run(as_dict=True) + + def get_opening_balance( employee: str, leave_type: str, filters: Filters, carry_forwarded_leaves: float ) -> float: @@ -168,48 +184,6 @@ def get_opening_balance( return opening_balance -def get_conditions(filters: Filters) -> Dict: - conditions = {} - - if filters.employee: - conditions["name"] = filters.employee - - if filters.company: - conditions["company"] = filters.company - - if filters.department: - conditions["department"] = filters.department - - if filters.employee_status: - conditions["status"] = filters.employee_status - - return conditions - - -def get_department_leave_approver_map(department: Optional[str] = None): - # get current department and all its child - department_list = frappe.get_list( - "Department", - filters={"disabled": 0}, - or_filters={"name": department, "parent_department": department}, - pluck="name", - ) - # retrieve approvers list from current department and from its subsequent child departments - approver_list = frappe.get_all( - "Department Approver", - filters={"parentfield": "leave_approvers", "parent": ("in", department_list)}, - fields=["parent", "approver"], - as_list=True, - ) - - approvers = {} - - for k, v in approver_list: - approvers.setdefault(k, []).append(v) - - return approvers - - def get_allocated_and_expired_leaves( from_date: str, to_date: str, employee: str, leave_type: str ) -> Tuple[float, float, float]: @@ -244,7 +218,7 @@ def get_leave_ledger_entries( from_date: str, to_date: str, employee: str, leave_type: str ) -> List[Dict]: ledger = frappe.qb.DocType("Leave Ledger Entry") - records = ( + return ( frappe.qb.from_(ledger) .select( ledger.employee, @@ -270,8 +244,6 @@ def get_leave_ledger_entries( ) ).run(as_dict=True) - return records - def get_chart_data(data: List, filters: Filters) -> Dict: labels = [] diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py index 9750ad4e880..c3203493b9e 100644 --- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py +++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py @@ -6,9 +6,6 @@ import frappe from frappe import _ from erpnext.hr.doctype.leave_application.leave_application import get_leave_details -from erpnext.hr.report.employee_leave_balance.employee_leave_balance import ( - get_department_leave_approver_map, -) def execute(filters=None): @@ -54,17 +51,11 @@ def get_data(filters, leave_types): active_employees = frappe.get_all( "Employee", filters=conditions, - fields=["name", "employee_name", "department", "user_id", "leave_approver"], + fields=["name", "employee_name", "department", "user_id"], ) - department_approver_map = get_department_leave_approver_map(filters.get("department")) - data = [] for employee in active_employees: - leave_approvers = department_approver_map.get(employee.department_name, []) - if employee.leave_approver: - leave_approvers.append(employee.leave_approver) - row = [employee.name, employee.employee_name, employee.department] available_leave = get_leave_details(employee.name, filters.date) for leave_type in leave_types: