feat(dashboard): technician performance report + real technician names
Wahab customer request (relay #748 v3 next-wave). 3a. Fix 'Tech #N' display: - FM dashboard's "Technician Workload" card was built from `Tech #${t.assigned_to}`; it now reads Ticket.assigned_technician_name (falling back to 'Unassigned', matching /tickets). - Template sweep confirms no other `Tech #` placeholder exists. 3b. Technician performance dashboard: - New bearer-gated GET /api/tickets/tech-performance aggregating existing ticket columns only (no schema change): per-technician total assigned, completed, in progress, escalated, cancelled, pending, open tasks, completion rate, and created_at -> closed_at resolution time with explicit counts for finished tasks lacking a timestamp. Rows key on user id so same-name technicians stay separate; labels are real names. Fleet totals and an unassigned-ticket count are included. - New /dashboard/tech-performance page (FM + CEO nav and links) with sortable table, completion bars and empty states; same-origin vendored assets only. - Bucket map, service, schemas and tests in app/services/ticket.py, app/schemas/ticket.py, tests/test_tech_performance.py. Tests: 111 passed (101 existing + 10 new).
This commit is contained in:
@@ -89,6 +89,7 @@ number. Covered by `tests/test_whatsapp_demo_number.py`.
|
||||
| GET | `/dashboard/cs` | Client | CS dashboard |
|
||||
| GET | `/dashboard/fm` | Client | FM dashboard |
|
||||
| GET | `/dashboard/ceo` | Client | CEO dashboard |
|
||||
| GET | `/dashboard/tech-performance` | Client | Technician performance report (FM + CEO nav) |
|
||||
| GET | `/tickets` | Client | All Issues filterable table |
|
||||
| GET | `/tickets/new` | Client | Create Issue form |
|
||||
| GET | `/tickets/{id}` | Client | Issue detail with timeline |
|
||||
@@ -96,6 +97,20 @@ number. Covered by `tests/test_whatsapp_demo_number.py`.
|
||||
Frontend: Alpine.js + Tailwind CSS vendored same-origin (no CDN) — see
|
||||
"Frontend assets" below. Auth state in localStorage. Role-based nav routing in `base.html`.
|
||||
|
||||
### Technician performance (Wahab request)
|
||||
`GET /api/tickets/tech-performance` (Bearer) aggregates per-technician workload/outcomes by
|
||||
**real name** using only existing ticket columns (`assigned_to`/`status`/`created_at`/`closed_at`
|
||||
→ `users.full_name`) — no schema change. Aggregation lives in
|
||||
`app/services/ticket.py::get_technician_performance`; bucket map `_TECH_STATUS_BUCKETS` defines
|
||||
`completed` (Completed/Closed), `in_progress`, `escalated`, `cancelled`, and `pending` (remainder),
|
||||
so the buckets always sum to `total_assigned`. `completion_rate = completed/total_assigned`;
|
||||
`avg_resolution_hours` averages `created_at → closed_at` only where `closed_at` is set, with
|
||||
`resolved_without_timestamps` counting finished tasks that lack one. Rows key on user id (same-name
|
||||
techs stay separate), sorted completed desc → workload → name. UI:
|
||||
`app/templates/dashboard/tech-performance.html`, linked from FM + CEO nav and the FM
|
||||
"Technician Workload" card — that card reads `Ticket.assigned_technician_name`, never an id
|
||||
placeholder. Regression: `tests/test_tech_performance.py`.
|
||||
|
||||
### Frontend assets (vendored, LAN-safe)
|
||||
- Alpine.js 3.17.2 + Tailwind Play 3.4.17 are committed under `app/static/vendor/`
|
||||
and served at `/static/vendor/…` (mounted in `app/main.py`, versioned
|
||||
|
||||
Reference in New Issue
Block a user