frappe-report-generator
Generate Frappe reports (query/script) with filters, charts, HTML templates, and JS customization.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Generate Frappe reports (query/script) with filters, charts, HTML templates, and JS customization.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Use when configuring hooks.py — doc_events, scheduler_events, override_whitelisted_methods, override_doctype_class, jinja, boot_session, permission_query_conditions, has_permission, and fixtures. Prevents silent hook failures from wrong paths or missing migrate after scheduler changes. Covers full hooks.py reference beyond document lifecycle events. Keywords: hooks.py, doc_events, scheduler_events, override method, permission query conditions, boot session, fixtures, override_doctype_class, extend_doctype_class.
Use when building or consuming Frappe REST APIs — auto /api/resource CRUD, @frappe.whitelist endpoints, token vs session auth, file uploads, and response handling. Prevents unauthorized exposure from missing permission checks on whitelisted methods. Covers /api/resource, /api/method, token auth, OAuth, file upload, error mapping. Keywords: whitelist API, /api/resource, /api/method, Frappe REST, token auth, api_key api_secret, call Frappe from outside, expand, filters.
Use when reading or writing Frappe data safely — get_doc, get_all, get_list, frappe.db.get_value, parameterized frappe.db.sql, transactions, bulk ops, and performance. Prevents SQL injection and permission leaks from wrong API choice. Covers ORM reads/writes, raw SQL, transactions, bulk_update, N+1 avoidance. Keywords: frappe.db.sql, frappe.get_all, get_value, set_value, bulk update, N+1, db transaction, get_list, SQL injection, parameterized query.
Use when implementing Frappe's permission model — roles, perm levels, user permissions, share, permission_query_conditions, has_permission hooks, and in-code checks. Prevents unauthorized access from missing server-side checks or broken row-level filters. Covers role permissions, field-level perm_level, User Permissions, share, hooks, frappe.has_permission. Keywords: permissions, role, user permission, perm level, restrict rows, frappe.has_permission, field level security, permission query conditions, share, PermissionError.
Use when debugging Frappe errors, using bench console for live inspection, analyzing tracebacks, or reading Frappe log files. Prevents wasted debugging time from ignoring log context, misreading tracebacks, and not using bench console effectively. Covers bench console, frappe.logger, error log DocType, traceback analysis, common error patterns, log file locations, pdb/debugger integration, VS Code DAP, profiling, Frappe Recorder, mariadb diagnostics. Keywords: debug, bench console, traceback, error log, frappe.logger, pdb, debugging, log analysis, inspect, VS Code, DAP, profiling, recorder, mariadb, monitor, ERPNext error, how to debug, find the bug, what went wrong, stack trace, error message..
Use when receiving vague or unclear ERPNext/Frappe development requests that need interpretation. Transforms requirements like 'make invoice auto-calculate' or 'add approval workflow' into concrete technical specifications. Determines which Frappe mechanisms to use and maps to the full 61-skill catalog. Keywords: vague requirement, clarify scope, translate business need, technical spec, implementation plan, what does this mean, unclear requirement, translate to code, how to build this.
| name | frappe-report-generator |
| description | Generate Frappe reports (query/script) with filters, charts, HTML templates, and JS customization. |
Create custom reports for data analysis, dashboards, and business intelligence in Frappe.
Query Report: SQL-based, fast for large datasets Script Report: Python-based, full flexibility Report Builder: No-code, user-configurable
JSON:
{
"name": "Sales Analysis",
"report_type": "Query Report",
"ref_doctype": "Sales Order",
"module": "Selling"
}
Python:
import frappe
from frappe import _
def execute(filters=None):
return get_columns(), get_data(filters)
def get_columns():
return [
{"fieldname": "customer", "label": _("Customer"), "fieldtype": "Link", "options": "Customer", "width": 150},
{"fieldname": "grand_total", "label": _("Total"), "fieldtype": "Currency", "width": 120}
]
def get_data(filters):
return frappe.db.sql("""
SELECT customer, grand_total
FROM `tabSales Order`
WHERE docstatus = 1
AND posting_date BETWEEN %(from_date)s AND %(to_date)s
""", filters, as_dict=1)
def execute(filters=None):
columns = get_columns()
data = get_data(filters)
chart = get_chart_data(data)
summary = get_report_summary(data)
return columns, data, None, chart, summary
def get_chart_data(data):
return {
"data": {"labels": [...], "datasets": [{"name": "Sales", "values": [...]}]},
"type": "bar"
}
def get_report_summary(data):
return [
{"label": "Total", "value": sum(...), "indicator": "Green"},
{"label": "Count", "value": len(data), "indicator": "Blue"}
]
{
"filters": [
{"fieldname": "from_date", "fieldtype": "Date", "label": "From Date", "reqd": 1},
{"fieldname": "to_date", "fieldtype": "Date", "label": "To Date", "reqd": 1},
{"fieldname": "customer", "fieldtype": "Link", "options": "Customer"}
]
}
Pattern: Use Jinja2-like syntax for custom layouts
Reference: See projectnext/report/project_cost_and_time_report/project_cost_and_time_report.html
def execute(filters=None):
# ... get data
html = None # HTML file auto-loaded if exists
return columns, data, None, chart, summary, html
Key HTML patterns:
{{ data[0].field }} - Access data{{ filters.field }} - Access filters{% for row in data %} - Iterate{% var blocks = {} %} - GroupingPattern: Client-side formatting and interactions
Reference: See projectnext/report/project_cost_and_time_report/project_cost_and_time_report.js
frappe.query_reports["Report Name"] = {
"formatter": function(value, row, column, data, default_formatter) {
if (column.fieldname === "delay" && value > 5) {
return `<span style="color: red;">${value}</span>`;
}
return default_formatter(value, row, column, data);
}
};
Pattern: Combine bars and lines for multi-metric visualization
Reference: See projectnext/report/project_cost_and_time_report/project_cost_and_time_report.py:120-196
chart = {
"data": {
"labels": labels,
"datasets": [
{"name": "Cost", "values": costs, "chartType": "bar"},
{"name": "Progress", "values": progress, "chartType": "line"}
]
},
"type": "axis-mixed",
"colors": ["#7cd6fd", "#5cb85c"]
}
Pattern: Color-coded indicators based on values
Reference: See projectnext/report/project_cost_and_time_report/project_cost_and_time_report.py:67-118
summary = [
{
"label": "Completion",
"value": f"{percentage:.1f}%",
"indicator": "Red" if percentage < 30 else "Orange" if percentage < 70 else "Green"
}
]
Pattern: Organize complex queries in controller modules
from projectnext.controllers.queries.reports.costandtimereport import get_project_report
def get_report_data(filters):
return get_project_report("Project", "project", "", 0, 200, filters)
def validate_filters(filters):
if not filters.get("project"):
frappe.throw(_("Project is required"))
if filters.get("start") > filters.get("end"):
frappe.throw(_("Start Date cannot be after End Date"))
# Group by category
blocks = {}
for row in data:
block = row.get("block_name") or "Unassigned"
if block not in blocks:
blocks[block] = []
blocks[block].append(row)
apps/<app>/<module>/report/<report_name>/
├── __init__.py
├── <report_name>.json
├── <report_name>.py
├── <report_name>.js (optional)
└── <report_name>.html (optional)
Complex Joins: Use INNER JOIN with GROUP BY for aggregations
Dynamic Columns: Build columns list programmatically
Caching: Use frappe.cache().get_value() for expensive queries
Permissions: Check with frappe.has_permission() before data access
Performance: Add indexes, use LIMIT, filter early in WHERE clause
Simple Report: See ERPNext erpnext/selling/report/sales_analysis/
Complex Report: See projectnext/report/project_cost_and_time_report/
Remember: This skill is model-invoked. Claude will use it autonomously when detecting report development tasks.
Source: consolidated from frappe-syntax-reports and frappe-impl-reports (Frappe Claude Skill Package).
Need a report?
├─ Simple list / group by on one DocType → Report Builder (UI-only; Group By: Count/Sum/Avg)
├─ Direct SQL, no Python logic → Query Report (legacy column aliases in SQL)
├─ Complex logic, charts, summaries, trees → Script Report (standard: .py + .js; needs Developer Mode)
└─ Quick Python without deploying an app → Script Report — Custom (Python in Report UI; System Manager)
Additional signals (Desk / product):
End user builds their own report? → Report Builder
Realtime KPI tile on workspace? → Number Card or Dashboard Chart (not a report substitute)
Huge dataset (>~100k rows) or timeouts? → enable Prepared Report (background job)
execute() return shapeWhat to return?
├─ Data only → columns, data
├─ + HTML message above grid → columns, data, message
├─ + chart → columns, data, None, chart
├─ + summary cards → columns, data, None, None, report_summary
└─ Full → columns, data, message, chart, report_summary, skip_total_row
Positional order must stay: columns, data, message, chart, report_summary, skip_total_row / skip_total_rows (Frappe expects this sequence).
| Type | Code | Typical use | Access notes |
|---|---|---|---|
| Report Builder | None | Single DocType listing, filters, group by | Broader user access |
| Query Report | SQL | Legacy SQL reports | Often System Manager–level |
| Script Report (standard) | Python + JS | Charts, summaries, complex logic | Administrator + Developer Mode |
| Script Report (custom) | Python in UI | One-offs without shipping code | System Manager |
| Prepared Report | flag on report | Slow / huge result sets | Background generation, cached |
.js filters)| Fieldtype | Options | Behavior |
|---|---|---|
Link | DocType | Autocomplete |
Select | newline-separated values | Fixed dropdown |
Date | — | Date picker |
DateRange | — | [from_date, to_date] |
Check | — | Boolean |
Dynamic Link | fieldname of driving filter | Depends on another filter |
Data | — | Free text |
Int | — | Integer |
MultiSelectList | DocType | Multi-select |
type (standard): bar, line, pie, donut, percentage — plus mixed/axis setups when using per-dataset chartType.chart.data: labels length must match each dataset’s values length (otherwise rendering breaks).fieldtype, options, currency, colors, height, barOptions (e.g. stacked), etc., as needed for formatting.report_summary entries: value, label, datatype (e.g. Currency, Int), optional currency, indicator (Green, Blue, Orange, Red, Grey).columns and data as lists — use [], not None, when empty.fieldname, label, fieldtype (and width). Query Reports only: use legacy "Label:Fieldtype/Options:Width" in SQL SELECT aliases — not the dict format._(...) / translatable helpers for user-visible labels in columns and summaries.frappe.db.sql / query builder; never interpolate untrusted filter input into the SQL string.SELECT * or load full documents inside tight loops for report rows — select columns in SQL or light APIs.width on column dicts if you care about readable layout in the grid.