invoices: let the admin set the payment date
All checks were successful
Build and Deploy to Production / test (push) Successful in 1m40s
Build and Deploy to Production / build (push) Successful in 1m19s
Build and Deploy to Production / deploy (push) Successful in 56s

Payments often arrive before they are recorded, so stamping paid_at
with the click time skews received-per-month and days-to-pay stats.
Mark paid now takes an optional date, and a paid invoice gets a form
to correct it. Past days are stored at 12:00 UTC so the date holds in
any timezone; future and malformed dates are refused. The PDF does not
print the date, so nothing is re-rendered.

Assisted-by: Claude:opus-5-5
Claude-Session: https://claude.ai/code/session_01TCc5TvWnAs5xPvGMQXTJw3
This commit is contained in:
Sergei Poljanski 2026-11-03 01:47:03 +04:00
commit 9d88b8af8f
Signed by: asxpi
GPG key ID: 4F8851660FA4121B
5 changed files with 68 additions and 4 deletions

View file

@ -86,7 +86,7 @@ Admin (HTTP Basic via `ADMIN_USER`/`ADMIN_PASSWORD`):
- `GET /admin/invoices/new` — create form. Dynamic line items via `public/admin-invoice-form.js`.
- `POST /admin/invoices` — validate → allocate number → render PDF → upload to MinIO → persist row.
- `GET /admin/invoices/:uuid` — detail page with public URL + "Mark paid" toggle.
- `POST /admin/invoices/:uuid/paid` — toggles `paid_at`.
- `POST /admin/invoices/:uuid/paid` — toggles `paid_at`; optional `paid_on` (YYYY-MM-DD, no future dates) backdates it to that day 12:00 UTC. `POST …/paid-date` corrects the date of a paid invoice. The PDF doesn't print the date, so neither re-renders.
- `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`.