fix: dedup recent tickets, feedback rating by resolution date, stale dashboard stats

- get_recent_tickets: exclude current + org tickets from the raised_by query
  so a ticket matching both customer and raised_by no longer appears twice.
- Dashboard avg feedback rating: filter on resolution_date instead of
  creation, so every ticket resolved in the period is counted regardless of
  when it was raised.
- Dashboard.vue: drop the static frappe-ui cache keys on the stat resources;
  the shared cached instance stayed bound to a previous mount's filters and
  sent stale params after navigating away and back.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Ritvik Sardana
2026-06-20 17:28:40 +05:30
co-authored by Claude Opus 4.8
parent 7252bbe97e
commit 0629aaeed3
3 changed files with 21 additions and 11 deletions
+3 -3
View File
@@ -335,9 +335,11 @@ const parseFilters = (filters: Filters) => {
};
};
// No `cache` key here: a static cache key makes frappe-ui return the same
// resource instance across navigations, still bound to the previous mount's
// `filters` closure, so reloads after navigating back send stale params.
const numberCards = createResource({
url: "helpdesk.api.dashboard.get_dashboard_data",
cache: ["Analytics", "NumberCards"],
makeParams: () => ({
dashboard_type: "number_card",
filters: parseFilters(filters),
@@ -346,7 +348,6 @@ const numberCards = createResource({
const masterData = createResource({
url: "helpdesk.api.dashboard.get_dashboard_data",
cache: ["Analytics", "MasterCharts"],
makeParams: () => ({
dashboard_type: "master",
filters: parseFilters(filters),
@@ -355,7 +356,6 @@ const masterData = createResource({
const trendData = createResource({
url: "helpdesk.api.dashboard.get_dashboard_data",
cache: ["Analytics", "TrendCharts"],
makeParams: () => ({
dashboard_type: "trend",
filters: parseFilters(filters),
+14 -7
View File
@@ -114,8 +114,9 @@ class HelpdeskDashboard:
)
return conds
def _get_case(self, start, end, value, func, extra_cond=None):
cond = (self.ticket.creation >= start) & (self.ticket.creation < end)
def _get_case(self, start, end, value, func, extra_cond=None, date_field=None):
date_field = date_field or self.ticket.creation
cond = (date_field >= start) & (date_field < end)
if extra_cond:
cond = cond & extra_cond
if self.combined_cond:
@@ -123,12 +124,12 @@ class HelpdeskDashboard:
return func(Case().when(cond, value).else_(None))
def get_metric_data(self, value, func, extra_cond=None):
def get_metric_data(self, value, func, extra_cond=None, date_field=None):
current_expr = self._get_case(
self.from_date, self.to_date_next, value, func, extra_cond
self.from_date, self.to_date_next, value, func, extra_cond, date_field
)
prev_expr = self._get_case(
self.prev_from_date, self.from_date, value, func, extra_cond
self.prev_from_date, self.from_date, value, func, extra_cond, date_field
)
query = frappe.qb.from_(self.ticket).select(
@@ -222,9 +223,15 @@ class HelpdeskDashboard:
}
def get_avg_feedback_score(self):
# Feedback belongs to the period a ticket was resolved in, not when it
# was raised, so include every ticket resolved within the date range
# regardless of its creation date.
extra_cond = self.ticket.feedback_rating > 0
current, prev = self.get_metric_data(
self.ticket.feedback_rating, Avg, extra_cond
self.ticket.feedback_rating,
Avg,
extra_cond,
date_field=self.ticket.resolution_date,
)
return {
@@ -233,7 +240,7 @@ class HelpdeskDashboard:
"suffix": "/5",
"delta": (current - prev) * 5,
"deltaSuffix": " " + _("stars"),
"tooltip": _("Avg. feedback rating for the tickets resolved"),
"tooltip": _("Avg. feedback rating for tickets resolved in this period"),
}
def get_trend_data(self):
+4 -1
View File
@@ -718,11 +718,14 @@ def get_recent_tickets(ticket: str):
)
if raised_by:
# Exclude the current ticket and any already picked up as org tickets,
# otherwise a ticket matching both `customer` and `raised_by` shows twice.
excluded = [ticket] + [t.name for t in org_tickets]
user_tickets = (
frappe.get_list(
"HD Ticket",
filters={
"name": ["!=", ticket],
"name": ["not in", excluded],
"raised_by": raised_by,
},
fields=fields,