Files
lukenyaMarathon_Frape/lukenya_marathon/lukenya_marathon/dashboard.py
T
KabundiNjuki 2217484648
CI / Server (push) Has been cancelled
Initial LuKenya Marathon application
2026-09-24 00:05:12 +03:00

107 lines
3.0 KiB
Python

"""Server-side data for the Lukenya Marathon dashboard page."""
import frappe
from frappe.utils import add_days, flt, getdate, nowdate
CURRENCY = "KES"
PAID_STATUSES = ("Paid", "Reconciled")
def _count(doctype, filters=None):
if not frappe.db.exists("DocType", doctype):
return 0
return frappe.db.count(doctype, filters or {})
def _created_between(doctype, start, end):
return _count(doctype, {"creation": ["between", [start, end]]})
def _revenue(start=None, end=None):
"""Sum of paid/reconciled payments, optionally limited to a date window."""
if not frappe.db.exists("DocType", "Payment Transaction"):
return 0.0
values = {"paid": PAID_STATUSES}
window = ""
if start and end:
window = "and date(coalesce(payment_date, creation)) between %(start)s and %(end)s"
values.update(start=start, end=end)
result = frappe.db.sql(
f"""
select coalesce(sum(amount), 0)
from `tabPayment Transaction`
where status in %(paid)s {window}
""",
values,
)
return flt(result[0][0])
def _trend(current, previous):
"""Percent change against the previous period, or None if there is nothing to compare."""
if not previous:
return None
return round((flt(current) - flt(previous)) / flt(previous) * 100)
def _current_edition():
fields = ["name", "edition_name", "event_date", "status"]
edition = frappe.db.get_value(
"Event Edition", {"status": "Open"}, fields, as_dict=True, order_by="event_date desc"
)
return edition or frappe.db.get_value(
"Event Edition", {}, fields, as_dict=True, order_by="event_date desc"
)
@frappe.whitelist()
def get_dashboard_stats():
frappe.only_for("System Manager")
today = getdate(nowdate())
recent_start, recent_end = add_days(today, -29), today
prior_start, prior_end = add_days(today, -59), add_days(today, -30)
participants_recent = _created_between("Participant", recent_start, recent_end)
participants_prior = _created_between("Participant", prior_start, prior_end)
editions_recent = _created_between("Event Edition", recent_start, recent_end)
editions_prior = _created_between("Event Edition", prior_start, prior_end)
revenue_recent = _revenue(recent_start, recent_end)
revenue_prior = _revenue(prior_start, prior_end)
return {
"currency": CURRENCY,
"edition": _current_edition(),
"kpis": {
"participants": {
"value": _count("Participant"),
"trend": _trend(participants_recent, participants_prior),
},
"editions": {
"value": _count("Event Edition"),
"trend": _trend(editions_recent, editions_prior),
},
"revenue": {
"value": _revenue(),
"trend": _trend(revenue_recent, revenue_prior),
},
"categories": {
"value": _count("Race Category", {"active": 1}),
"trend": None,
},
},
"tiles": {
"event_setup": _count("Event Edition"),
"race_categories": _count("Race Category"),
"registrations": _count("Registration"),
"payments": _count("Payment Transaction"),
"race_day": _count("Bib Allocation"),
"prizes": _count("Prize Award"),
"volunteers": _count("Volunteer"),
},
}