Merge pull request #31178 from ruthra-kumar/analytics_on_prepared_reports

feat: Analytics on prepared reports
This commit is contained in:
ruthra kumar 2025-03-05 15:37:47 +05:30 committed by GitHub
commit fba36d57e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 157 additions and 0 deletions

View file

@ -0,0 +1,24 @@
// Copyright (c) 2024, Frappe Technologies and contributors
// For license information, please see license.txt
frappe.query_reports["Prepared Report Analytics"] = {
filters: [
{
fieldname: "report",
label: __("Report"),
fieldtype: "Data",
},
{
fieldname: "top_10",
label: __("Top 10"),
fieldtype: "Check",
default: 0,
},
{
fieldname: "in_minutes",
label: __("In Minutes"),
fieldtype: "Check",
default: 0,
},
],
};

View file

@ -0,0 +1,27 @@
{
"add_total_row": 0,
"columns": [],
"creation": "2024-12-18 11:58:00.693755",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"letterhead": null,
"modified": "2025-02-07 17:27:53.441631",
"modified_by": "Administrator",
"module": "Core",
"name": "Prepared Report Analytics",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Prepared Report",
"report_name": "Prepared Report Analytics",
"report_type": "Script Report",
"roles": [
{
"role": "System Manager"
}
],
"timeout": 0
}

View file

@ -0,0 +1,106 @@
# Copyright (c) 2024, Frappe Technologies and contributors
# For license information, please see license.txt
from pypika import Order
import frappe
from frappe import _, qb
from frappe.query_builder import Criterion
from frappe.utils import add_months, nowdate
def execute(filters: dict | None = None):
"""Return columns and data for the report.
This is the main entry point for the report. It accepts the filters as a
dictionary and should return columns and data. It is called by the framework
every time the report is refreshed or a filter is updated.
"""
columns = get_columns(filters)
data = get_data(filters=filters)
return columns, data
def get_columns(filters) -> list[dict]:
"""Return columns for the report.
One field definition per column, just like a DocType field definition.
"""
return [
{
"label": _("Prepared Report"),
"fieldname": "name",
"fieldtype": "Link",
"options": "Prepared Report",
"width": 250,
},
{
"label": _("Report Name"),
"fieldname": "report_name",
"fieldtype": "Data",
"width": 250,
},
{
"label": _("Start"),
"fieldname": "creation",
"fieldtype": "DateTime",
"width": 250,
},
{
"label": _("End"),
"fieldname": "report_end_time",
"fieldtype": "DateTime",
"width": 250,
},
{
"label": _("Runtime in Minutes") if filters.in_minutes else _("Runtime in Seconds"),
"fieldname": "runtime",
"fieldtype": "float",
"width": 250,
},
{
"label": _("Memory Usage in MB"),
"fieldname": "peak_memory_usage",
"fieldtype": "float",
"width": 250,
},
]
def get_data(filters) -> list[list]:
"""Return data for the report.
The report data is a list of rows, with each row being a list of cell values.
"""
pr = qb.DocType("Prepared Report")
conditions = [pr.status.eq("Completed"), pr.creation.gte(add_months(nowdate(), -2))]
if filters.report:
conditions.append(pr.report_name.like(f"%{filters.report}%"))
divisor = 1
if filters.in_minutes:
divisor = 60
query = (
qb.from_(pr)
.select(
pr.name,
pr.report_name,
pr.creation,
pr.report_end_time,
(pr.peak_memory_usage / 1024).as_("peak_memory_usage"),
)
.select(((pr.report_end_time - pr.creation) / divisor).as_("runtime"))
.where(Criterion.all(conditions))
.orderby(qb.Field("runtime"), order=Order.desc)
)
if filters.top_10:
query = query.limit(10)
res = query.run(as_dict=True)
return res