Hi Frappe Community! ![]()
I’m working on a Leave Overview Report in Frappe Cloud (v16.18.3, ERPNext 16.19.1, HRMS 16.7.1) and need role-based data filtering:
-
HR Manager/HR User → See all employees’ leave records
-
Regular Employee → See only their own leave records
What Didn’t Work:
1. Query Report with %(user)s parameter:
sql
WHERE employee = (SELECT name FROM `tabEmployee` WHERE user_id = %(user)s)
Error: KeyError: b'user' - parameter not auto-injected in Query Reports
2. Script Report with database queries:
python
def execute(filters=None):
data = frappe.db.sql(...) # Returns null
Issue: Custom Script Reports (Is Standard = No) can’t access database in Frappe Cloud’s safe_exec environment
3. User Permissions + “Apply User Permissions”:
-
Set up User Permissions linking users to their Employee records
-
Clicked “Set User Permissions” in Role Permission Manager
-
Result: Query Reports don’t respect User Permissions by default
Working Solution (But Is This the Best Way?):
I created a Server Script (API) + JavaScript in Query Report:
Server Script (API Method: get_filtered_leave_data):
python
user = frappe.session.user
has_hr_role = frappe.db.exists("Has Role", {
"parent": user,
"role": ["in", ["HR Manager", "HR User", "System Manager"]]
})
if has_hr_role:
filters = "docstatus < 2"
else:
employee = frappe.db.get_value("Employee", {"user_id": user}, "name")
if employee:
filters = f"docstatus < 2 AND employee = '{employee}'"
else:
filters = "docstatus < 2 AND 1=0"
data = frappe.db.sql(f"""
SELECT leave_type, custom_leave_subtype, from_date, to_date,
total_leave_days, status, employee_name
FROM `tabLeave Application`
WHERE {filters}
ORDER BY from_date DESC
LIMIT 500
""", as_dict=True)
frappe.response['message'] = data
Query Report JavaScript:
javascript
frappe.query_reports["Leave Overview Report"] = {
onload: function(report) {
report.get_data = function() {
frappe.call({
method: 'get_filtered_leave_data',
callback: function(r) {
if (r.message) {
report.data = r.message;
report.columns = [/* column definitions */];
report.raw_data = {result: r.message, columns: report.columns};
report.render_datatable();
}
}
});
};
report.get_data();
}
};
Query Section:
sql
SELECT leave_type, custom_leave_subtype, from_date, to_date,
total_leave_days, status, employee_name
FROM `tabLeave Application`
WHERE 1=0 LIMIT 1
(Returns nothing; JavaScript overrides it)
This Works Perfectly:
-
HR roles see all records -
Employees see only their own records -
No KeyError issues -
Runs in Frappe Cloud
My Questions:
-
Is there a simpler/standard way to implement role-based filtering in Query Reports for Frappe Cloud?
-
Why doesn’t
%(user)sauto-inject in Query Reports like it does in standard reports? -
Should User Permissions work with Query Reports? The documentation suggests they should, but “Apply User Permissions” doesn’t seem to affect Query Reports.
-
Is the Server Script + JavaScript approach considered a best practice, or is there a more “Frappe-native” way?
Use Case:
This pattern would be useful for many HR reports:
-
Salary slips (employees see own, HR sees all)
-
Attendance records
-
Appraisal reviews
-
Expense claims
-
Timesheet
-
Leave Balance
Would love to hear from the community:
-
Has anyone solved this differently?
-
Is there official documentation I missed?
-
Are there plans to improve role-based filtering in Query Reports for Cloud?
Thanks in advance! ![]()