1 Reports
shad0w edited this page 2026-06-24 10:02:20 +00:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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; 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 AprMar 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 (W1W5).
  • 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).