From 21c71c71722ad75f6c12919fef7a932d32ab6ff4 Mon Sep 17 00:00:00 2001 From: A R R R Associates Date: Sun, 5 Jul 2026 20:04:56 +0530 Subject: [PATCH] Upgrade manager dashboard and wizards to v2 --- app/modules/manager_dashboard/__init__.py | 2 +- app/modules/manager_dashboard/service.py | 62 +++++++++++++++++-- .../manager_dashboard/dashboard.html | 4 +- .../partials/_task_table.html | 4 +- .../partials/due_calendar.html | 27 ++++++++ .../partials/escalations.html | 20 ++++++ .../manager_dashboard/partials/overview.html | 4 +- app/modules/manager_dashboard/ui.py | 4 +- 8 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 app/modules/manager_dashboard/templates/manager_dashboard/partials/due_calendar.html create mode 100644 app/modules/manager_dashboard/templates/manager_dashboard/partials/escalations.html diff --git a/app/modules/manager_dashboard/__init__.py b/app/modules/manager_dashboard/__init__.py index 2832114..8ef2d31 100644 --- a/app/modules/manager_dashboard/__init__.py +++ b/app/modules/manager_dashboard/__init__.py @@ -1 +1 @@ -"""Manager Dashboard V1 module.""" +"""Manager Dashboard V2 module.""" diff --git a/app/modules/manager_dashboard/service.py b/app/modules/manager_dashboard/service.py index 957694a..7b60066 100644 --- a/app/modules/manager_dashboard/service.py +++ b/app/modules/manager_dashboard/service.py @@ -101,6 +101,28 @@ def _status_label(status: str | None) -> str: return (status or "pending").replace("_", " ").replace("-", " ").title() + + +def _days_overdue(due_date) -> int: + if not due_date: + return 0 + delta = (date.today() - due_date).days + return delta if delta > 0 else 0 + + +def _age_bucket(days: int) -> str: + if days >= 30: + return "30+ days" + if days >= 15: + return "15-29 days" + if days >= 8: + return "8-14 days" + if days >= 4: + return "4-7 days" + if days >= 1: + return "1-3 days" + return "Current" + def _task_href(task: ClientServiceTaskInstance) -> str: task_id = getattr(task, "id", None) if task_id: @@ -136,6 +158,8 @@ def _task_row(task: ClientServiceTaskInstance) -> dict[str, Any]: "comment_count": len([c for c in getattr(task, "comments", []) if not getattr(c, "is_deleted", False)]), "is_overdue": bool(due_date and due_date < today and _is_open(status)), "is_due_today": bool(due_date and due_date == today and _is_open(status)), + "days_overdue": _days_overdue(due_date) if _is_open(status) else 0, + "age_bucket": _age_bucket(_days_overdue(due_date)) if _is_open(status) else "Closed", "href": _task_href(task), } @@ -239,9 +263,10 @@ def _client_rows(db: Session, scope, task_rows: list[dict[str, Any]]) -> list[di def _report_cards() -> list[dict[str, str]]: return [ {"group": "Execution", "title": "Team Work Status", "desc": "Open, overdue, in-progress and blocked assignments for the active branch/team.", "href": "/manager/dashboard?tab=team-work"}, - {"group": "Execution", "title": "Due Today / This Week", "desc": "Work requiring immediate attention and allocation follow-up.", "href": "/manager/dashboard?tab=team-work"}, + {"group": "Due Control", "title": "Due Calendar", "desc": "Due today, due this week and overdue work in one control view.", "href": "/manager/dashboard?tab=due-calendar"}, {"group": "Review", "title": "Manager Review Queue", "desc": "Completed or review-ready work waiting for manager action.", "href": "/manager/dashboard?tab=review-queue"}, {"group": "Client Follow-up", "title": "Client Pending Report", "desc": "Tasks blocked due to documents, clarification or client data pending.", "href": "/manager/dashboard?tab=client-pending"}, + {"group": "Escalation", "title": "Escalation Register", "desc": "Unassigned, overdue and aged client-pending items requiring manager intervention.", "href": "/manager/dashboard?tab=escalations"}, {"group": "Team", "title": "Staff Workload Report", "desc": "Staff-wise active, overdue, review and client-pending workload.", "href": "/manager/dashboard?tab=team-work"}, {"group": "Documents", "title": "Document Checklist Report", "desc": "Document-related blocked tasks and communication timeline shortcuts.", "href": "/manager/dashboard?tab=documents"}, ] @@ -249,10 +274,12 @@ def _report_cards() -> list[dict[str, str]]: def _wizard_cards() -> list[dict[str, str]]: return [ - {"title": "Task Assignment Wizard", "desc": "Open the detailed allocation board to assign or reassign staff.", "href": "/manager/work"}, - {"title": "Review Wizard", "desc": "Review completed work and send corrections through the task timeline.", "href": "/manager/dashboard?tab=review-queue"}, - {"title": "Client Query Wizard", "desc": "Handle client-pending tasks and record clarification requirements.", "href": "/manager/dashboard?tab=client-pending"}, - {"title": "Document Checklist Wizard", "desc": "Verify pending documents and open engagement document storage.", "href": "/documents"}, + {"title": "Task Assignment Wizard", "desc": "Allocate unassigned tasks and rebalance heavy workload using the existing manager work board.", "href": "/manager/work"}, + {"title": "Due Control Wizard", "desc": "Review due today, due this week and overdue items before escalation.", "href": "/manager/dashboard?tab=due-calendar"}, + {"title": "Review Wizard", "desc": "Open review-ready tasks and proceed through the existing task communication timeline.", "href": "/manager/dashboard?tab=review-queue"}, + {"title": "Client Query Wizard", "desc": "Handle client-pending items and record clarification/document requirements.", "href": "/manager/dashboard?tab=client-pending"}, + {"title": "Document Checklist Wizard", "desc": "Verify document-related blocked tasks and open the existing documents area.", "href": "/documents"}, + {"title": "Escalation Wizard", "desc": "Review aged overdue, unassigned and client-pending items requiring partner/branch attention.", "href": "/manager/dashboard?tab=escalations"}, {"title": "Work Closure Wizard", "desc": "Open engagement progress and close work after review completion.", "href": "/employees/progress"}, {"title": "Alert / Follow-up Wizard", "desc": "Open alerts for reminders, escalations and follow-up actions.", "href": "/alerts"}, ] @@ -279,6 +306,26 @@ def build_manager_dashboard_payload(db: Session, request, current_user) -> dict[ tenant = getattr(scope, "tenant", None) branch = getattr(scope, "branch", None) + age_buckets = [ + {"label": "1-3 days", "count": len([r for r in overdue_rows if r.get("age_bucket") == "1-3 days"])}, + {"label": "4-7 days", "count": len([r for r in overdue_rows if r.get("age_bucket") == "4-7 days"])}, + {"label": "8-14 days", "count": len([r for r in overdue_rows if r.get("age_bucket") == "8-14 days"])}, + {"label": "15-29 days", "count": len([r for r in overdue_rows if r.get("age_bucket") == "15-29 days"])}, + {"label": "30+ days", "count": len([r for r in overdue_rows if r.get("age_bucket") == "30+ days"])}, + ] + + status_summary: dict[str, int] = {} + service_summary: dict[str, int] = {} + for row in open_rows: + status_summary[row.get("status_label") or "Pending"] = status_summary.get(row.get("status_label") or "Pending", 0) + 1 + service_summary[row.get("service_name") or "Service"] = service_summary.get(row.get("service_name") or "Service", 0) + 1 + + escalation_rows = sorted( + (unassigned_rows + overdue_rows + client_pending_rows), + key=lambda r: (r.get("days_overdue") or 0, r.get("is_overdue") or False, r.get("due_date") or date.max), + reverse=True, + ) + overview = { "tenant": tenant, "branch": branch, @@ -296,6 +343,7 @@ def build_manager_dashboard_payload(db: Session, request, current_user) -> dict[ "review_pending_count": len(review_rows), "staff_count": len(staff_rows), "client_count": len(client_rows), + "escalation_count": len(escalation_rows), "today": today, } @@ -311,6 +359,10 @@ def build_manager_dashboard_payload(db: Session, request, current_user) -> dict[ "review_queue": review_rows[:60], "client_pending": client_pending_rows[:60], "documents_pending": client_pending_rows[:40], + "escalations": escalation_rows[:80], + "age_buckets": age_buckets, + "status_summary": sorted([{"label": k, "count": v} for k, v in status_summary.items()], key=lambda x: x["count"], reverse=True)[:10], + "service_summary": sorted([{"label": k, "count": v} for k, v in service_summary.items()], key=lambda x: x["count"], reverse=True)[:10], "staff_rows": staff_rows, "clients": client_rows, "reports": _report_cards(), diff --git a/app/modules/manager_dashboard/templates/manager_dashboard/dashboard.html b/app/modules/manager_dashboard/templates/manager_dashboard/dashboard.html index a9a217e..0c0afb5 100644 --- a/app/modules/manager_dashboard/templates/manager_dashboard/dashboard.html +++ b/app/modules/manager_dashboard/templates/manager_dashboard/dashboard.html @@ -5,7 +5,7 @@

Manager Execution Control

-

Manager Dashboard

+

Manager Dashboard V2

Control team allocation, review queue, client pending items, documents and execution reports for the active branch/team.

FY: {{ overview.financial_year or 'All' }}{% if overview.branch %} ยท Branch: {{ overview.branch.name or overview.branch.code }}{% endif %}

@@ -19,9 +19,11 @@ {% set tabs = [ ('overview','Overview'), ('team-work','Team Work'), + ('due-calendar','Due Calendar'), ('review-queue','Review Queue'), ('client-pending','Client Pending'), ('documents','Documents'), + ('escalations','Escalations'), ('reports','Reports'), ('wizards','Wizards') ] %} diff --git a/app/modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html b/app/modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html index e0585db..d76d703 100644 --- a/app/modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html +++ b/app/modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html @@ -5,7 +5,7 @@ Client Task Service / Period - Due + Due / Age Assigned Status Action @@ -17,7 +17,7 @@
{{ row.client_name }}
{{ row.client_code or '-' }}
{{ row.task_name }}
{{ row.comment_count }} timeline item(s)
{{ row.service_name }}
{{ row.period }}
- {{ row.due_date or '-' }} + {{ row.due_date or '-' }}{% if row.days_overdue %}
{{ row.days_overdue }} day(s) overdue
{% endif %} {{ row.assigned_to }} {{ row.status_label }} Open diff --git a/app/modules/manager_dashboard/templates/manager_dashboard/partials/due_calendar.html b/app/modules/manager_dashboard/templates/manager_dashboard/partials/due_calendar.html new file mode 100644 index 0000000..4a6d173 --- /dev/null +++ b/app/modules/manager_dashboard/templates/manager_dashboard/partials/due_calendar.html @@ -0,0 +1,27 @@ +
+
+
Due Today
{{ overview.due_today_count }}
Must be controlled today
+
Due This Week
{{ overview.due_week_count }}
Upcoming workload
+
Overdue
{{ overview.overdue_count }}
Escalation required
+
Unassigned
{{ overview.unassigned_count }}
Allocation pending
+
+ +
+
+
+

Due Today

Tasks that should be completed or reviewed today.

Work Board
+ {% set rows = due_today %} + {% include 'modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html' %} +
+
+

Due This Week

Upcoming work due within the next seven days.

+ {% set rows = due_week %} + {% include 'modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html' %} +
+
+ +
+
diff --git a/app/modules/manager_dashboard/templates/manager_dashboard/partials/escalations.html b/app/modules/manager_dashboard/templates/manager_dashboard/partials/escalations.html new file mode 100644 index 0000000..2a183eb --- /dev/null +++ b/app/modules/manager_dashboard/templates/manager_dashboard/partials/escalations.html @@ -0,0 +1,20 @@ +
+
+
Overdue
{{ overview.overdue_count }}
Ageing risk
+
Unassigned
{{ overview.unassigned_count }}
Manager action
+
Client Pending
{{ overview.client_pending_count }}
Follow-up needed
+
Escalation Items
{{ overview.escalation_count }}
Combined attention list
+
+ +
+
+

Escalation Register

Unassigned, overdue and client-pending tasks sorted by urgency.

Open Alerts
+ {% set rows = escalations %} + {% include 'modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html' %} +
+ +
+
diff --git a/app/modules/manager_dashboard/templates/manager_dashboard/partials/overview.html b/app/modules/manager_dashboard/templates/manager_dashboard/partials/overview.html index ab490c8..48557f2 100644 --- a/app/modules/manager_dashboard/templates/manager_dashboard/partials/overview.html +++ b/app/modules/manager_dashboard/templates/manager_dashboard/partials/overview.html @@ -5,7 +5,7 @@
In Progress
{{ overview.in_progress_count }}
Being worked
Client Pending
{{ overview.client_pending_count }}
Needs follow-up
Review Queue
{{ overview.review_pending_count }}
Review-ready
-
Overdue
{{ overview.overdue_count }}
Escalate
+
Escalations
{{ overview.escalation_count }}
Combined risk items
@@ -19,7 +19,7 @@

Team Snapshot

Staff visible
{{ overview.staff_count }}
Clients visible
{{ overview.client_count }}
Due today
{{ overview.due_today_count }}
Due week
{{ overview.due_week_count }}
- +
diff --git a/app/modules/manager_dashboard/ui.py b/app/modules/manager_dashboard/ui.py index df70226..2582a32 100644 --- a/app/modules/manager_dashboard/ui.py +++ b/app/modules/manager_dashboard/ui.py @@ -11,14 +11,16 @@ from app.core.templating import templates from app.modules.core.rbac.deps import get_user_permissions, get_user_roles from app.modules.manager_dashboard.service import build_manager_dashboard_payload, can_access_manager_dashboard -router = APIRouter(prefix="/manager", tags=["manager-dashboard-v1-ui"]) +router = APIRouter(prefix="/manager", tags=["manager-dashboard-v2-ui"]) VALID_TABS = { "overview": "modules/manager_dashboard/templates/manager_dashboard/partials/overview.html", "team-work": "modules/manager_dashboard/templates/manager_dashboard/partials/team_work.html", + "due-calendar": "modules/manager_dashboard/templates/manager_dashboard/partials/due_calendar.html", "review-queue": "modules/manager_dashboard/templates/manager_dashboard/partials/review_queue.html", "client-pending": "modules/manager_dashboard/templates/manager_dashboard/partials/client_pending.html", "documents": "modules/manager_dashboard/templates/manager_dashboard/partials/documents.html", + "escalations": "modules/manager_dashboard/templates/manager_dashboard/partials/escalations.html", "reports": "modules/manager_dashboard/templates/manager_dashboard/partials/reports.html", "wizards": "modules/manager_dashboard/templates/manager_dashboard/partials/wizards.html", }