Add e2e tests for bulk coding transactions and fix SSR location validation

- Create requirements document based on master cljs implementation
- Add Playwright e2e tests covering happy path, validation, and distribution
- Fix hiccup id syntax in SSR bulk code form (div#id.class order)
- Add missing account location validation to SSR bulk code submit
- Enhance test server with multiple transactions and fixed-location account
This commit is contained in:
2026-05-21 13:21:22 -07:00
parent 76c6eaddb9
commit 8bd0cee1b1
9 changed files with 543 additions and 632 deletions

View File

@@ -210,7 +210,7 @@
[:div.col-span-2.pt-4
[:h3.text-lg.font-medium.mb-3 "Expense Accounts"]
[:div.space-y-3#account-entries
[:div#account-entries.space-y-3
(fc/with-field :accounts
(com/validated-field
{:errors (fc/field-errors)}
@@ -271,49 +271,62 @@
bulk-code-schema)
(submit [this {:keys [multi-form-state request-method identity] :as request}]
(let [ ids (selected->ids (assoc request :query-params (:search-params (:snapshot multi-form-state))) (:search-params (:snapshot multi-form-state)))
all-ids (all-ids-not-locked ids)
vendor (-> request :multi-form-state :snapshot :vendor)
approval-status (-> request :multi-form-state :snapshot :approval-status)
accounts (-> request :multi-form-state :snapshot :accounts) ]
(when (seq accounts)
(assert-percentages-add-up (:snapshot multi-form-state)))
(alog/peek ::ACCOUNTS (-> request :multi-form-state :snapshot))
all-ids (all-ids-not-locked ids)
vendor (-> request :multi-form-state :snapshot :vendor)
approval-status (-> request :multi-form-state :snapshot :approval-status)
accounts (-> request :multi-form-state :snapshot :accounts) ]
(when (seq accounts)
(assert-percentages-add-up (:snapshot multi-form-state)))
(alog/peek ::ACCOUNTS (-> request :multi-form-state :snapshot))
;; Get transactions and filter for locked ones
(let [db (dc/db conn)
transactions (pull-many db [:db/id :transaction/amount {:transaction/client [:db/id]}] (vec all-ids))
;; Get transactions and filter for locked ones
(let [db (dc/db conn)
transactions (pull-many db [:db/id :transaction/amount {:transaction/client [:db/id]}] (vec all-ids))
;; Get client locations
client->locations (->> (map (comp :db/id :transaction/client) transactions)
(distinct)
(dc/q '[:find (pull ?e [:db/id :client/locations])
:in $ [?e ...]]
db)
(map (fn [[client]]
[(:db/id client) (:client/locations client)]))
(into {}))]
;; Get client locations
client->locations (->> (map (comp :db/id :transaction/client) transactions)
(distinct)
(dc/q '[:find (pull ?e [:db/id :client/locations])
:in $ [?e ...]]
db)
(map (fn [[client]]
[(:db/id client) (:client/locations client)]))
(into {}))]
(audit-transact-batch
(map (fn [t]
(let [locations (client->locations (-> t :transaction/client :db/id))]
[:upsert-transaction (cond-> t
approval-status
(assoc :transaction/approval-status approval-status)
;; Validate account locations
(doseq [a accounts
:let [{:keys [:account/location :account/name]} (dc/pull db
[:account/location :account/name]
(:account a))]]
(when (and location (not= location (:location a)))
(form-validation-error (str "Account " name " uses location " (:location a) ", but is supposed to be " location)))
(doseq [[_ locations] client->locations]
(when (and (not location)
(not (get (into #{"Shared"} locations)
(:location a))))
(form-validation-error (str "Account " name " uses location " (:location a) ", but doesn't belong to the client.")))))
vendor
(assoc :transaction/vendor vendor)
(audit-transact-batch
(map (fn [t]
(let [locations (client->locations (-> t :transaction/client :db/id))]
[:upsert-transaction (cond-> t
approval-status
(assoc :transaction/approval-status approval-status)
(seq accounts)
(assoc :transaction/accounts
(maybe-code-accounts t accounts locations)))]))
transactions)
(:identity request))
vendor
(assoc :transaction/vendor vendor)
;; Return success modal
(html-response
(com/success-modal {:title "Transactions Coded"}
[:p (str "Successfully coded " (count all-ids) " transactions.")])
:headers {"hx-trigger" "refreshTable"})))))
(seq accounts)
(assoc :transaction/accounts
(maybe-code-accounts t accounts locations)))]))
transactions)
(:identity request))
;; Return success modal
(html-response
(com/success-modal {:title "Transactions Coded"}
[:p (str "Successfully coded " (count all-ids) " transactions.")])
:headers {"hx-trigger" "refreshTable"})))))
(def bulk-code-wizard (->BulkCodeWizard nil nil))