Skip to content

Commit 8f7b014

Browse files
committed
feat(employee_leave_balance): add branch filter/column and consolidate by option
Add a Branch filter and column, and change the Consolidate Leave Types checkbox to a Consolidate By select with Leave Type and Employee options. Falls back to Leave Type consolidation when only the legacy consolidate_leave_types filter is present.
1 parent 51c2d3b commit 8f7b014

2 files changed

Lines changed: 99 additions & 51 deletions

File tree

hrms/hr/report/employee_leave_balance/employee_leave_balance.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ frappe.query_reports["Employee Leave Balance"] = {
3232
fieldtype: "Link",
3333
options: "Department",
3434
},
35+
{
36+
fieldname: "branch",
37+
label: __("Branch"),
38+
fieldtype: "Link",
39+
options: "Branch",
40+
},
3541
{
3642
fieldname: "employee",
3743
label: __("Employee"),
@@ -59,10 +65,11 @@ frappe.query_reports["Employee Leave Balance"] = {
5965
default: "Active",
6066
},
6167
{
62-
fieldname: "consolidate_leave_types",
63-
label: __("Consolidate Leave Types"),
64-
fieldtype: "Check",
65-
default: 1,
68+
fieldname: "consolidate_by",
69+
label: __("Consolidate By"),
70+
fieldtype: "Select",
71+
options: "\nLeave Type\nEmployee",
72+
default: "Leave Type",
6673
depends_on: "eval: !doc.employee",
6774
},
6875
],

hrms/hr/report/employee_leave_balance/employee_leave_balance.py

Lines changed: 88 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,21 @@ def execute(filters: Filters | None = None) -> tuple:
2222
if filters.to_date <= filters.from_date:
2323
frappe.throw(_('"From Date" can not be greater than or equal to "To Date"'))
2424

25-
columns = get_columns()
25+
columns = get_columns(filters)
2626
data = get_data(filters)
2727
charts = get_chart_data(data, filters)
2828
return columns, data, None, charts
2929

3030

31-
def get_columns() -> list[dict]:
32-
return [
33-
{
34-
"label": _("Leave Type"),
35-
"fieldtype": "Link",
36-
"fieldname": "leave_type",
37-
"width": 200,
38-
"options": "Leave Type",
39-
},
31+
def get_columns(filters: Filters) -> list[dict]:
32+
leave_type_column = {
33+
"label": _("Leave Type"),
34+
"fieldtype": "Link",
35+
"fieldname": "leave_type",
36+
"width": 200,
37+
"options": "Leave Type",
38+
}
39+
employee_columns = [
4040
{
4141
"label": _("Employee"),
4242
"fieldtype": "Link",
@@ -51,6 +51,22 @@ def get_columns() -> list[dict]:
5151
"width": 100,
5252
"options": "employee",
5353
},
54+
{
55+
"label": _("Branch"),
56+
"fieldtype": "Link",
57+
"fieldname": "branch",
58+
"width": 120,
59+
"options": "Branch",
60+
},
61+
]
62+
63+
if filters.get("consolidate_by") == "Employee":
64+
first_columns = [*employee_columns, leave_type_column]
65+
else:
66+
first_columns = [leave_type_column, *employee_columns]
67+
68+
return [
69+
*first_columns,
5470
{
5571
"label": _("Opening Balance"),
5672
"fieldtype": "float",
@@ -89,54 +105,79 @@ def get_data(filters: Filters) -> list:
89105
active_employees = get_employees(filters)
90106

91107
precision = cint(frappe.db.get_single_value("System Settings", "float_precision"))
92-
consolidate_leave_types = len(active_employees) > 1 and filters.consolidate_leave_types
93-
row = None
108+
109+
consolidate_by = filters.get("consolidate_by")
110+
if not consolidate_by and filters.get("consolidate_leave_types"):
111+
consolidate_by = "Leave Type"
112+
113+
consolidate_leave_types = len(active_employees) > 1 and consolidate_by == "Leave Type"
114+
consolidate_by_employee = len(leave_types) > 1 and consolidate_by == "Employee"
94115

95116
data = []
96117

118+
if consolidate_by_employee:
119+
for employee in active_employees:
120+
data.append(
121+
{
122+
"employee": employee.name,
123+
"employee_name": employee.employee_name,
124+
"branch": employee.branch,
125+
}
126+
)
127+
128+
for leave_type in leave_types:
129+
row = get_leave_balance_row(employee, leave_type, filters, precision)
130+
del row.employee
131+
del row.employee_name
132+
del row.branch
133+
data.append(row)
134+
135+
return data
136+
97137
for leave_type in leave_types:
98138
if consolidate_leave_types:
99139
data.append({"leave_type": leave_type})
100-
else:
101-
row = frappe._dict({"leave_type": leave_type})
102140

103141
for employee in active_employees:
142+
row = get_leave_balance_row(employee, leave_type, filters, precision)
104143
if consolidate_leave_types:
105-
row = frappe._dict()
106-
else:
107-
row = frappe._dict({"leave_type": leave_type})
144+
del row.leave_type
145+
data.append(row)
108146

109-
row.employee = employee.name
110-
row.employee_name = employee.employee_name
147+
return data
111148

112-
leaves_taken = (
113-
get_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) * -1
114-
)
115149

116-
new_allocation, expired_leaves, carry_forwarded_leaves = get_allocated_and_expired_leaves(
117-
filters.from_date, filters.to_date, employee.name, leave_type
118-
)
119-
on_allocation_boundary = is_opening_balance_on_allocation_boundary(
120-
employee.name, leave_type, filters
121-
)
122-
opening = get_opening_balance(
123-
employee.name, leave_type, filters, carry_forwarded_leaves, on_allocation_boundary
124-
)
125-
allocated_leaves = new_allocation + carry_forwarded_leaves
126-
if on_allocation_boundary:
127-
allocated_leaves -= carry_forwarded_leaves
128-
129-
row.leaves_allocated = flt(allocated_leaves, precision)
130-
row.leaves_expired = flt(expired_leaves, precision)
131-
row.opening_balance = flt(opening, precision)
132-
row.leaves_taken = flt(leaves_taken, precision)
133-
134-
closing = allocated_leaves + opening - (row.leaves_expired + leaves_taken)
135-
row.closing_balance = flt(closing, precision)
136-
row.indent = 1
137-
data.append(row)
150+
def get_leave_balance_row(employee: dict, leave_type: str, filters: Filters, precision: int) -> frappe._dict:
151+
row = frappe._dict(
152+
leave_type=leave_type,
153+
employee=employee.name,
154+
employee_name=employee.employee_name,
155+
branch=employee.branch,
156+
)
138157

139-
return data
158+
leaves_taken = get_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) * -1
159+
160+
new_allocation, expired_leaves, carry_forwarded_leaves = get_allocated_and_expired_leaves(
161+
filters.from_date, filters.to_date, employee.name, leave_type
162+
)
163+
on_allocation_boundary = is_opening_balance_on_allocation_boundary(employee.name, leave_type, filters)
164+
opening = get_opening_balance(
165+
employee.name, leave_type, filters, carry_forwarded_leaves, on_allocation_boundary
166+
)
167+
allocated_leaves = new_allocation + carry_forwarded_leaves
168+
if on_allocation_boundary:
169+
allocated_leaves -= carry_forwarded_leaves
170+
171+
row.leaves_allocated = flt(allocated_leaves, precision)
172+
row.leaves_expired = flt(expired_leaves, precision)
173+
row.opening_balance = flt(opening, precision)
174+
row.leaves_taken = flt(leaves_taken, precision)
175+
176+
closing = allocated_leaves + opening - (row.leaves_expired + leaves_taken)
177+
row.closing_balance = flt(closing, precision)
178+
row.indent = 1
179+
180+
return row
140181

141182

142183
def get_leave_types() -> list[str]:
@@ -147,7 +188,7 @@ def get_leave_types() -> list[str]:
147188
def get_employees(filters: Filters) -> list[dict]:
148189
conditions = {}
149190

150-
for field in ["company", "department"]:
191+
for field in ["company", "department", "branch"]:
151192
if filters.get(field):
152193
conditions[field] = filters.get(field)
153194

@@ -160,7 +201,7 @@ def get_employees(filters: Filters) -> list[dict]:
160201
return frappe.get_list(
161202
"Employee",
162203
filters=conditions,
163-
fields=["name", "employee_name", "department"],
204+
fields=["name", "employee_name", "department", "branch"],
164205
)
165206

166207

0 commit comments

Comments
 (0)