feat(transactions): port manual bank-transaction import to SSR

Implement the SSR/alpine/htmx manual transaction import, wiring the
already-declared but unhandled ::external-import-page/parse/import routes.
Mirrors the SSR ledger import: paste the exact master-branch Yodlee
positional-column TSV, review parsed rows in an editable grid with per-row
error/warning badges, and import. Every master validation is preserved and
the existing import.transactions engine is reused unchanged
(via import.manual/import-batch), so core components are untouched.

- New ns auto-ap.ssr.transaction.import (page, paste/parse, editable grid,
  two-tier validation, import handler) + admin-only transactions Import nav.
- Two-tier validation: fixable problems (bad date/amount, unknown client or
  bank-account code, missing fields) are hard errors that block the whole
  batch; inherent skip-conditions (non-POSTED, before start-date/locked,
  already-imported) are warnings computed from the engine's own
  categorize-transaction so the grid preview matches the import result.
- Tests: failing-first Playwright e2e (e2e/transaction-import.spec.ts) plus
  unit/integration coverage (ssr/transaction/import_test.clj, 10 tests).
- Deterministic bank-account code in the e2e seed.

Plan: docs/plans/2026-06-01-001-feat-manual-transaction-import-ssr-plan.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-01 11:18:28 -07:00
parent b6649a3d1d
commit a1098b28f8
8 changed files with 1056 additions and 14 deletions

View File

@@ -19,6 +19,7 @@
grid-page query-schema
wrap-status-from-source]]
[auto-ap.ssr.transaction.edit :as edit :refer [transaction-account-row*]]
[auto-ap.ssr.transaction.import :as t-import]
[auto-ap.ssr.utils
:refer [apply-middleware-to-all-handlers entity-id html-response
many-entity modal-response percentage ref->enum-schema
@@ -101,6 +102,7 @@
(def key->handler
(merge edit/key->handler
bulk-code/key->handler
t-import/key->handler
(apply-middleware-to-all-handlers
{::route/page page
::route/approved-page (-> page (wrap-implied-route-param :status :transaction-approval-status/approved))