invoices: statistics page

Add /admin/invoices/stats with a year filter: invoiced, received and
outstanding totals in GEL at each invoice's captured rate (the one
currency every invoice has), overdue count, average days to pay, money
received per month by payment date as a bar chart with the same figures
in a table, per-currency totals, top clients and crypto option usage.
Cancelled invoices are left out of every amount; hidden ones follow the
usual superuser-only visibility.

Assisted-by: Claude:opus-5
This commit is contained in:
Sergei Poljanski 2026-10-10 09:12:21 +04:00
commit 9128867a33
Signed by: asxpi
GPG key ID: 4F8851660FA4121B
7 changed files with 282 additions and 1 deletions

View file

@ -89,6 +89,7 @@ Admin (HTTP Basic via `ADMIN_USER`/`ADMIN_PASSWORD`):
- `POST /admin/invoices/:uuid/paid` — toggles `paid_at`.
- `POST /admin/invoices/:uuid/cancel` (optional `reason`) — sets `cancelled_at`/`cancel_reason`, renders and uploads a third PDF variant (`…-cancelled.pdf`, diagonal CANCELLED stamp + date/reason line) which becomes current, so the client link and download switch over. Status precedence: cancelled > paid > pending; marking paid is refused while cancelled. `POST …/reinstate` clears it.
- `POST /admin/invoices/:uuid/hide` — superuser-only toggle of `hidden`: hidden invoices are left out of the admin list, dashboard and admin invoice pages for everyone but superusers (`visible_invoices` / `admin_invoice!` helpers). The public `/i/:uuid` link is unaffected.
- `GET /admin/invoices/stats[?year=YYYY]` — `lib/invoice_stats.rb`: invoiced / received / outstanding in GEL at each invoice's captured rate (cancelled excluded), overdue, average days to pay, received per month by payment date (bar chart, `--chart-bar` validated with the dataviz skill against the dark surface) plus the same figures as a table, per-currency totals, top clients, crypto usage. Respects `visible_invoices`.
Public: