94 lines
4.3 KiB
Markdown
94 lines
4.3 KiB
Markdown
# Finance Phase 2c — Accountant dashboard + Student/Parent portals
|
|
|
|
> Plan: `.harness/plans/hr-finance-fiscalisation.md` §10c
|
|
> Branch: `feature/finance-phase-2c` (worktree `.worktrees/finance-phase-2c/`)
|
|
> Owners: backend-expert (enriched summary + students-fees helper) → frontend-expert (portal rewrites) → code-reviewer.
|
|
|
|
## What landed
|
|
|
|
The last mile: dashboards and student/parent portals that consume
|
|
everything §10a and §10b produced.
|
|
|
|
### Backend
|
|
|
|
- **`server/src/controllers/finance.controller.js`** — `/api/finance/dashboard/summary`
|
|
enriched with six new tiles:
|
|
- `overdue_invoices` (invoices past due, not paid/cancelled)
|
|
- `open_invoices` (issued/partial/overdue count)
|
|
- `upcoming_trips_30d` (published trips departing in next 30 days)
|
|
- `pending_reconciliations` (bank sessions with discrepancies)
|
|
- `installments_due_14d` (student_fees due in next fortnight)
|
|
- `student_groups_count`
|
|
|
|
Shape is **backwards compatible** — the original five fields
|
|
(`collected_mtd`, `outstanding_fees`, `payroll_last_run`,
|
|
`expenses_mtd`, `pending_expenses`) are unchanged.
|
|
|
|
- **`server/src/controllers/students-fees.controller.js`** — new file
|
|
mounted at `/api/students`. Single-student profile endpoint:
|
|
|
|
```
|
|
GET /api/students/:uid/fees
|
|
```
|
|
|
|
Returns `{ student, fees, trips, summary }` where `fees` rows include
|
|
`discount_amount` and a hydrated `discounts[]` array (name, kind,
|
|
amount_applied) and `trips` rows are the user's `trip_payments`
|
|
joined to trips. RBAC gates by parent/child link or by student self.
|
|
This powers the new student and parent view pages.
|
|
|
|
### Frontend
|
|
|
|
| # | File | Route / Role | Notes |
|
|
|---|---|---|---|
|
|
| 1 | `client/src/pages/dashboard/AccountantDashboard.tsx` | `/dashboard/accountant` | Accountant-specific landing with 4 KPI tiles, 3 entry CTAs (plans / discounts / groups), expense-approval summary, and a compact "latest activity" feed. |
|
|
| 2 | `client/src/pages/dashboard/FinanceDashboard.tsx` | `/dashboard/finance` (modified) | Second tile row added — Open Invoices / Trips next 30d / Reconciliations / Student Groups — wired to the enriched summary endpoint. |
|
|
| 3 | `client/src/pages/student/Fees.tsx` | `/student/fees` (new), `/fees` (also mapped) | New student fees portal: fee lines with discount-row expander, trips table below, KPI tiles. Backed by `/api/students/:uid/fees`. |
|
|
| 4 | `client/src/pages/parent/Fees.tsx` | (modified) | Switched data source to `/api/students/:uid/fees`; falls back to legacy `/fees/students` if the new endpoint isn't available. Total-outstanding now subtracts `discount_amount` so partial-paid lines show the correct balance. |
|
|
|
|
### Wiring
|
|
|
|
- `client/src/App.tsx` — registered `/dashboard/accountant` for
|
|
school_admin / systems_admin / principal / bursar, and
|
|
`/student/fees` + `/fees` for the student role.
|
|
- `client/src/components/Nav.tsx` — `accountant` block already pointed at
|
|
`/dashboard/accountant` (§10a). Added "My Fees" entry to the `student`
|
|
block.
|
|
- `SCREENS.md` — Bursar / Accountant / Student nav rows up-to-date via the
|
|
Nav entries; no body edits needed.
|
|
|
|
### Smoke
|
|
|
|
```
|
|
GET /api/finance/dashboard/summary
|
|
→ { collected_mtd, outstanding_fees, payroll_last_run, expenses_mtd,
|
|
pending_expenses,
|
|
overdue_invoices, open_invoices, upcoming_trips_30d,
|
|
pending_reconciliations, installments_due_14d, student_groups_count }
|
|
|
|
GET /api/students/:uid/fees
|
|
→ { student, fees:[...with discounts[]], trips:[...], summary }
|
|
```
|
|
|
|
Logging in as `student@school.com` and fetching `/api/students/:uid/fees`
|
|
returns the same envelope. Login as a random student and self-fetch:
|
|
the self-scope guard passes (200). Login as a random non-parent and
|
|
fetch someone else's: 403 with error message.
|
|
|
|
### Deviations from the plan
|
|
|
|
1. **Single `Students /fees` controller mounted at `/api/students`**
|
|
instead of `/api/student-fees` — keeps the URL hierarchy aligned
|
|
with `/api/students` (which already exists for the Students module).
|
|
2. **Parent fees page keeps the legacy fallback** so a partial rollout
|
|
doesn't break the existing UX. New endpoint wins when present.
|
|
3. **No PDF invoice generation** — kept the existing printable HTML view
|
|
from §10a. PDF generation is §11.
|
|
|
|
### Out of scope
|
|
|
|
- Paynow webhook extension to mark `trip_payments` paid (§11).
|
|
- Burn-down collection reports (§11).
|
|
- PDF invoice generation (§11).
|
|
- Bank-recon auto-match for trip-receipt rows (§11).
|