From 8f8e4489345675478129d3a7fb986bfcd4e0a34f Mon Sep 17 00:00:00 2001 From: Abishek Murugesan Date: Tue, 7 Apr 2026 18:00:54 +0530 Subject: [PATCH 1/3] feat: filter department and branch dropdowns by company in Monthly Attendance Sheet The Department and Branch filter dropdowns in the Monthly Attendance Sheet now scope their options to the selected Company, consistent with how the Employee filter already behaves. This makes it easier to find the right department or branch when working with large multi-company setups. --- .../monthly_attendance_sheet.js | 20 +++++++++++++++++++ .../monthly_attendance_sheet.py | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/hrms/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.js b/hrms/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.js index 37f35dcc29..408c081320 100644 --- a/hrms/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.js +++ b/hrms/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.js @@ -91,6 +91,26 @@ frappe.query_reports["Monthly Attendance Sheet"] = { default: frappe.defaults.get_user_default("Company"), reqd: 1, }, + { + fieldname: "department", + label: __("Department"), + fieldtype: "Link", + options: "Department", + get_query: () => { + var company = frappe.query_report.get_filter_value("company"); + return { + filters: { + company: company, + }, + }; + }, + }, + { + fieldname: "branch", + label: __("Branch"), + fieldtype: "Link", + options: "Branch", + }, { fieldname: "group_by", label: __("Group By"), diff --git a/hrms/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/hrms/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py index 7ce1b169a8..b2f1c7c980 100644 --- a/hrms/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py +++ b/hrms/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py @@ -374,6 +374,10 @@ def get_employee_related_details(filters: Filters) -> tuple[dict, list]: if filters.employee: query = query.where(Employee.name == filters.employee) + if filters.department and filters.department != "All Departments": + query = query.where(Employee.department == filters.department) + if filters.branch: + query = query.where(Employee.branch == filters.branch) group_by = filters.group_by if group_by: From a0c2ba562bed16cc7fedfc779d053d708b1d7dc3 Mon Sep 17 00:00:00 2001 From: Abishek Murugesan Date: Tue, 7 Apr 2026 20:36:27 +0530 Subject: [PATCH 2/3] test: added additional test case for filter department and branch dropdowns by company in Monthly Attendance Sheet. --- .../test_monthly_attendance_sheet.py | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/hrms/hr/report/monthly_attendance_sheet/test_monthly_attendance_sheet.py b/hrms/hr/report/monthly_attendance_sheet/test_monthly_attendance_sheet.py index 60830e1af3..7b27e7234a 100644 --- a/hrms/hr/report/monthly_attendance_sheet/test_monthly_attendance_sheet.py +++ b/hrms/hr/report/monthly_attendance_sheet/test_monthly_attendance_sheet.py @@ -519,6 +519,112 @@ def test_detailed_view_with_date_range_filter(self): == "L" ) + def test_attendance_with_department_filter(self): + previous_month_first = get_first_day_for_prev_month() + + dept1 = create_department("Test Dept Alpha") + dept2 = create_department("Test Dept Beta") + + emp_dept1 = make_employee("emp_dept1@example.com", company=self.company, department=dept1) + emp_dept2 = make_employee("emp_dept2@example.com", company=self.company, department=dept2) + + mark_attendance(emp_dept1, previous_month_first, "Present") + mark_attendance(emp_dept2, previous_month_first, "Present") + + filters = frappe._dict( + { + "month": previous_month_first.month, + "year": previous_month_first.year, + "company": self.company, + "department": dept1, + "filter_based_on": self.filter_based_on, + } + ) + report = execute(filters=filters) + + employees_in_report = [row.get("employee") for row in report[1] if row.get("employee")] + + # only emp_dept1 should appear; emp_dept2 belongs to a different department + self.assertIn(emp_dept1, employees_in_report) + self.assertNotIn(emp_dept2, employees_in_report) + + def test_attendance_with_branch_filter(self): + previous_month_first = get_first_day_for_prev_month() + + branch1 = create_branch("Test Branch Alpha") + branch2 = create_branch("Test Branch Beta") + + emp_branch1 = make_employee("emp_branch1@example.com", company=self.company, branch=branch1) + emp_branch2 = make_employee("emp_branch2@example.com", company=self.company, branch=branch2) + + mark_attendance(emp_branch1, previous_month_first, "Present") + mark_attendance(emp_branch2, previous_month_first, "Present") + + filters = frappe._dict( + { + "month": previous_month_first.month, + "year": previous_month_first.year, + "company": self.company, + "branch": branch1, + "filter_based_on": self.filter_based_on, + } + ) + report = execute(filters=filters) + + employees_in_report = [row.get("employee") for row in report[1] if row.get("employee")] + + # only emp_branch1 should appear; emp_branch2 belongs to a different branch + self.assertIn(emp_branch1, employees_in_report) + self.assertNotIn(emp_branch2, employees_in_report) + + def test_attendance_with_department_and_branch_filter_combined(self): + previous_month_first = get_first_day_for_prev_month() + + dept = create_department("Test Dept Combined") + branch = create_branch("Test Branch Combined") + + # employee matching both department and branch + emp_match = make_employee( + "emp_match@example.com", company=self.company, department=dept, branch=branch + ) + # employee with correct department but wrong branch + emp_wrong_branch = make_employee( + "emp_wrong_branch@example.com", + company=self.company, + department=dept, + branch=create_branch("Test Branch Other"), + ) + # employee with correct branch but wrong department + emp_wrong_dept = make_employee( + "emp_wrong_dept@example.com", + company=self.company, + department=create_department("Test Dept Other"), + branch=branch, + ) + + mark_attendance(emp_match, previous_month_first, "Present") + mark_attendance(emp_wrong_branch, previous_month_first, "Present") + mark_attendance(emp_wrong_dept, previous_month_first, "Present") + + filters = frappe._dict( + { + "month": previous_month_first.month, + "year": previous_month_first.year, + "company": self.company, + "department": dept, + "branch": branch, + "filter_based_on": self.filter_based_on, + } + ) + report = execute(filters=filters) + + employees_in_report = [row.get("employee") for row in report[1] if row.get("employee")] + + # only the employee matching both department and branch should appear + self.assertIn(emp_match, employees_in_report) + self.assertNotIn(emp_wrong_branch, employees_in_report) + self.assertNotIn(emp_wrong_dept, employees_in_report) + def test_detailed_view_with_date_range_and_group_by_filter(self): today = getdate() mark_attendance(self.employee, today, "Absent", "Day Shift") @@ -589,3 +695,9 @@ def execute_report_with_invalid_filters(invalid_filter_name): def date_key(date_obj): return date_obj.strftime("%d-%m-%Y") + + +def create_branch(branch_name): + if not frappe.db.exists("Branch", branch_name): + frappe.get_doc({"doctype": "Branch", "branch": branch_name}).insert(ignore_permissions=True) + return branch_name From ac335c4e3c749b9f2825669dfbd614a37b5b7e6f Mon Sep 17 00:00:00 2001 From: Abishek Murugesan Date: Wed, 8 Apr 2026 10:47:12 +0530 Subject: [PATCH 3/3] fix: missed to import to create test_company --- .../monthly_attendance_sheet/test_monthly_attendance_sheet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrms/hr/report/monthly_attendance_sheet/test_monthly_attendance_sheet.py b/hrms/hr/report/monthly_attendance_sheet/test_monthly_attendance_sheet.py index 7b27e7234a..9037dddbf5 100644 --- a/hrms/hr/report/monthly_attendance_sheet/test_monthly_attendance_sheet.py +++ b/hrms/hr/report/monthly_attendance_sheet/test_monthly_attendance_sheet.py @@ -15,7 +15,7 @@ make_holiday_list, make_leave_application, ) -from hrms.tests.test_utils import create_company, get_first_day_for_prev_month +from hrms.tests.test_utils import create_company, create_department, get_first_day_for_prev_month from hrms.tests.utils import HRMSTestSuite