diff --git a/Reports.md b/Reports.md new file mode 100644 index 0000000..94ebcd3 --- /dev/null +++ b/Reports.md @@ -0,0 +1,68 @@ +# Reports — Purchasing spend analytics + +The implemented spend-analytics section, reached via **Reports → Purchasing** in +the sidebar. (The original UX proposal — annotated screens — is on +[Reports Mockup](Reports-Mockup); this page documents what shipped.) + +## Access + +Gated by the **`view_analytics`** permission — **Manager, SuperUser, Auditor, +Admin**. CSV export uses the same gate. The sidebar **Reports** section carries a +**“Purchasing”** subheading so other domains (e.g. Crewing) can add their own +report groups later. + +## Report families + +Each is an **index → drill / detail** pair: + +- **Cost Centres** (`/reports/cost-centres`) — approved spend compared across + **vessels** (the PO cost centre). A row opens **`/reports/cost-centres/[id]`**: + KPI tiles, a spend-trend chart, and a **Top accounting codes** breakdown + re-pivotable by tier (Heading / Sub-heading / Leaf) and Top-N. +- **Accounting Codes** (`/reports/accounting-codes`) — drills the `Account` + tree (headings → sub-headings → leaves) via a `?parent=` query; a leaf opens + **`/reports/accounting-codes/[id]`**: trend + breakdown **by cost centre** (or, + for a non-leaf, by sub-account). + +## What counts as spend + +A PO is counted once it reaches `POST_APPROVAL_STATUSES` (MGR_APPROVED … CLOSED), +dated by **`approvedAt`**, valued at **`totalAmount`** — the same basis as the +dashboard tiles. Financial year is the Indian **Apr–Mar** year. Each PO's amount is +**allocated across the accounting codes its line items carry** (falling back to the +PO-level account), proportionally so the per-PO pieces sum back to the total — so +multi-account POs attribute correctly. PO counts are **distinct POs**. Sites are +**not** cost centres; only vessels are. + +The aggregation is a pure, unit-tested core in **`lib/reports.ts`** — one query in +`getReportDataset()`, everything else pure functions over it. + +## Filters (URL-driven, shareable) + +All filters live in the **URL query**, so the server component re-renders and any +view is bookmarkable — no client-side fetching: + +- **Granularity** — Weekly / Monthly / Yearly. Weekly focuses one FY **month** and + buckets by week-of-month (W1–W5). +- **Financial Year**, plus **Month** (weekly only). +- **Show** — Top 5 / Top 10 / Bottom 5 / All. +- **Add to graph** — tick rows (`?sel=`) and compare just the selected set + (`?cmp=1`); export honours the selection. +- Accounting drill-down (`?parent=`) and detail re-pivot controls + (`tier` / `break` / `topn`). + +Charts use **recharts**; the comparison chart draws **one colour per item** (cost +centre / accounting code) in every granularity, including the yearly grouped-bars +view. KPI tiles, tables and breadcrumbs are server-rendered. + +## Export + +The toolbar **Export** links to `/api/reports/spend?dim=…` — a CSV mirroring the +on-screen view (including a custom `?sel=` selection). + +## Code + +`lib/reports.ts` (aggregation), `lib/report-colors.ts` (shared palette, kept out of +the `"use client"` charts module so server components receive the real array), +`app/(portal)/reports/**` (pages), `components/reports/**` (toolbar + charts), +`app/api/reports/spend/` (CSV export).