Introduction: What Is a Script Report in Frappe?
A script report in Frappe Framework v15 is a report powered by Python code instead of raw SQL. It allows developers to write server-side logic to fetch, process, and format report data dynamically.
Script reports are ideal when:
- Business logic is complex
- Data requires conditional processing
- Permissions and workflows must be enforced
- SQL alone is not sufficient
Why Use Script Reports Instead of Query Reports?
Script reports are preferred when you need:
- Complex calculations and transformations
- Conditional data generation
- Multi-source data aggregation
- Permission-aware logic
- Cleaner and safer abstraction over SQL
They trade raw performance for flexibility and maintainability.
Types of Reports in Frappe v15 (Context)
Frappe supports:
- Query Reports – SQL-based, read-only
- Script Reports – Python-based logic
- Report Builder Reports – UI-driven, basic
This guide focuses exclusively on Script Reports.
How Script Reports Work in Frappe v15
Answer:
Script reports execute a Python function that returns:
- Column definitions
- Row data
Frappe calls this function whenever the report is loaded or filtered, ensuring real-time, permission-safe results.
How to Create a Script Report (Step-by-Step)
Step 1: Create a New Report
Go to Report List → New and set:
- Report Name
- Ref DocType
- Report Type: Script Report
Save the report.
Step 2: Create the Report Python File
Frappe automatically links the report to a Python module located at:
app_name/app_name/report/report_name/report_name.py
This file contains the report execution logic.
Basic Script Report Structure (Frappe v15)
Every script report must expose an execute function.
def execute(filters=None):
columns = get_columns()
data = get_data(filters)
return columns, data
This structure is mandatory in Frappe v15.
Defining Columns in a Script Report
Columns are defined as dictionaries.
def get_columns():
return [
{
"label": "Customer",
"fieldname": "customer",
"fieldtype": "Link",
"options": "Customer",
"width": 180,
},
{
"label": "Total Amount",
"fieldname": "total",
"fieldtype": "Currency",
"width": 120,
}
]
Each column definition controls display, data type, and formatting.
Fetching Data in Script Reports
Using Frappe ORM (Recommended)
import frappe
def get_data(filters):
return frappe.get_all(
"Sales Invoice",
filters={"docstatus": 1},
fields=["customer", "grand_total as total"]
)
This ensures:
- Permission enforcement
- Cleaner abstraction
- Upgrade safety
Using Filters in Script Reports
Filters are passed automatically to the execute function.
def get_data(filters):
conditions = {}
if filters.get("customer"):
conditions["customer"] = filters["customer"]
return frappe.get_all(
"Sales Invoice",
filters=conditions,
fields=["customer", "grand_total"]
)
Filters must be defined in the Report form.
Adding Filters to the Report
In the Filters section of the report:
- Define fieldname
- Select fieldtype
- Set options (if required)
Frappe handles filter injection automatically.
Permissions and Security in Script Reports
Script reports:
- Respect user permissions
- Follow DocType access rules
- Obey role-based visibility
- Prevent unauthorized data exposure
This makes them safer than raw SQL reports.
Best Practices for Script Reports
Use ORM instead of raw SQL
Improves readability and permission safety.
Keep logic modular
Separate column and data logic.
Avoid heavy loops
Optimize for large datasets.
Validate filters
Never trust unvalidated input.
Common Issues and Troubleshooting
Report loads but shows no data
- Check filter logic
- Verify DocType permissions
- Confirm returned data structure
Columns not rendering
- Ensure fieldname matches data keys
- Validate column dictionary structure
Performance issues
- Limit fetched fields
- Use indexed filters
- Avoid nested loops
Advanced Use Case: Aggregated Script Report
def get_data(filters):
return frappe.db.sql("""
SELECT customer, SUM(grand_total) as total
FROM `tabSales Invoice`
WHERE docstatus = 1
GROUP BY customer
""", as_dict=True)
Use raw SQL only when necessary and with caution.
Industry Relevance and Use Cases
Script reports are widely used for:
- MIS and management dashboards
- Financial analysis
- Operational performance tracking
- Custom business intelligence
They are essential for ERPNext enterprise reporting.
Technical Prerequisites
- Frappe Framework Version 15
- Python knowledge
- Understanding of DocTypes and permissions
- Access to Report and DocType modules
Conclusion
Script reports in Frappe Framework v15 provide maximum flexibility for building dynamic, permission-aware reports using Python. They are ideal for complex business logic where SQL-based query reports fall short.
For ERPNext and Frappe developers, script reports are a core reporting capability that enables advanced analytics while maintaining security and maintainability.