Commit Graph

10 Commits (0adce5844be107b1ca13fad1e6709e7be6646dc0)

Author SHA1 Message Date
Thomas Joise 8c653eb41a fix(payments): exclude draft proformas from outstanding (owner decision)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2 days ago
Thomas Joise fdf31b4dbd feat(payments): ledger exposes outstanding docs + per-payment allocations
clientLedger now attaches allocations (docNo + amount) to each payment and
returns an outstanding[] list — issued invoices with outstandingPaise > 0
plus open (draft/sent/accepted) proformas, oldest-first by docNo. Read-only
extension over the existing settlement math (outstandingPaise, allocations);
no money/allocation logic changed. Mirrors the widened Payment/Ledger shapes
onto apps/hq-web/src/api.ts for the upcoming Payments tab.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2 days ago
Thomas Joise 70234161dc fix(d24): pg allocation row-lock + index ordering; docs (D24 record, 389 tests)
- recordPayment locks the target invoice row (SELECT ... FOR UPDATE, Postgres
  only — SQLite is serialized by the connection mutex) before reading
  outstanding, so concurrent payments cannot over-allocate on prod.
- INDEX_DDL now runs AFTER migrate() in openDb, so indexes referencing
  migrate-added columns (owner_id, lockout cols) build on older DBs.
- D24 remediation recorded in 06-DECISIONS; test counts 377 -> 389.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4 days ago
Thomas Joise f812555528 fix(sec/d24): money-integrity guards — CN cap, atomic doc-no, qty, TDS, markStatus
Red-team money findings:
- createCreditNote caps the CN to the invoice's remaining creditable value
  (invoice payable − already-credited by non-cancelled CNs), read+insert in
  one txn. Blocks a CN exceeding its invoice / unlimited CNs flipping it 'paid'.
- nextDocNo allocates via one atomic UPDATE ... RETURNING (row lock) instead of
  read-then-bump — no duplicate/burned numbers under concurrent issue (Postgres).
- markStatus rejects accepted/lost on non-QUOTATION docs — an issued invoice can
  no longer be hidden from overdue chasing via a quote-only transition.
- computeBill bounds qty magnitude (keeps fractional for weighed Store goods);
  HQ buildLines additionally requires whole-unit integer qty (SMS/module seats).
- recordPayment rejects TDS greater than the cash received — no fabricated-TDS
  'settlement' with no money.
money-guards test locks all four. Suite money paths green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4 days ago
Thomas Joise 5f9f961d20 feat(db): D19 P1-P3 — async DB interface, dual engines, Postgres adapter
P1: every repo, route, scheduler path and test now speaks one async DB
interface (all/get/run/exec/transaction). better-sqlite3 stays underneath
for dev/tests via SqliteDb (statement cache, manual BEGIN/SAVEPOINT
nesting); openDb stays sync so fixtures remain one-liners. Zero behavior
change: 346/346 tests, typecheck clean.

P2: migrations-pg.ts — numbered Postgres migration set (001-init: bigint
paise, integer flags, TEXT ISO dates, TEXT JSON; reminder CHECK born in
final widened form) + schema_migrations runner.

P3: db-pg.ts — pg Pool behind the same interface: ?->$n rewrite outside
string literals, transactions pinned to one pooled client via
AsyncLocalStorage with savepoint nesting, int8/numeric parsed to JS
numbers so paise math is identical on both engines.

Also: reminder upsert INSERT OR IGNORE -> ON CONFLICT DO NOTHING
(portable, same changes-count semantics).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5 days ago
Thomas Joise 584fb291f8 feat(documents): paginated register with honest total + Documents page (Phase 2, WS-D)
listDocuments now returns { documents, total, page, pageSize } (default 50,
cap 200, newest first) with the client name joined server-side — no N+1.
GET /documents passes page/pageSize through; type/status/clientId filters
compose against the same WHERE for both count and page (rule 8: no silent
caps). clientLedger walks the paginated repo in 200-row batches so the
ledger still surfaces every document. New /documents screen: type chips,
status filter, mono doc numbers, amount column, pager honouring the server
total; rows open /documents/:id. Nav entry under WORK (exact-match so New
Document keeps its own highlight).

Note: the GET /documents route hunk itself landed via 8861b46, swept into
a concurrent commit from the same working tree; this commit carries the
repo/ledger/web halves and the tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5 days ago
Thomas Joise b7085ce56e feat(hq): payment receipts — own RCT/ series, zero-GST acknowledgment PDF
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 weeks ago
Thomas Joise 42cfa3d0b2 feat(hq): reports — dues aging, module revenue, client profitability with margin
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 weeks ago
Thomas Joise 2d3b1a52a9 feat(hq): daily scan detection rules with idempotent reminders
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 weeks ago
Thomas Joise 5fc07b97ed feat(hq): payments with allocation, TDS and advances (HQ-1 task 9)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 weeks ago