geocrop-platform./apps/nextgen/.harness/changelogs/2026-07-06-phase2c.md

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).