Add vendor pre-population for bulk code and individual edit forms

- Add vendor-changed HTMX handlers for both bulk code and individual edit
- Pre-populate default account at 100% when vendor is selected and no accounts exist
- Fix render-accounts-section to render from step-params correctly
- Change bulk code vendor-changed from hx-get to hx-post to include form data
- Add routes for vendor-changed endpoints
- Update e2e tests to cover vendor pre-population
- Run lein cljfmt fix across codebase
This commit is contained in:
2026-05-21 14:45:19 -07:00
parent 8bd0cee1b1
commit ba87805d4c
210 changed files with 8694 additions and 9627 deletions

View File

@@ -21,7 +21,7 @@
(if (and client-id bank-account-id amount)
(let [[matching-checks] (d-checks/get-graphql {:client-id client-id
:clients [client-id]
:bank-account-id bank-account-id
:bank-account-id bank-account-id
:amount (- amount)
:status :payment-status/pending})]
(if (= 1 (count matching-checks))
@@ -29,7 +29,6 @@
nil))
nil))
(defn transaction->existing-payment [_ check-number client-id bank-account-id amount id]
(alog/info ::searching
:client-id client-id
@@ -46,7 +45,7 @@
check-number
(-> (d-checks/get-graphql {:client-id client-id
:clients [client-id]
:bank-account-id bank-account-id
:bank-account-id bank-account-id
:check-number check-number
:amount (- amount)
:status :payment-status/pending})
@@ -70,12 +69,12 @@
(group-by first) ;; group by vendors
vals)
considerations (for [candidate-invoices candidate-invoices-vendor-groups
invoice-count (range 1 32)
consideration (partition invoice-count 1 candidate-invoices)
:when (dollars= (reduce (fn [acc [_ _ amount]]
(+ acc amount)) 0.0 consideration)
(- amount))]
consideration)]
invoice-count (range 1 32)
consideration (partition invoice-count 1 candidate-invoices)
:when (dollars= (reduce (fn [acc [_ _ amount]]
(+ acc amount)) 0.0 consideration)
(- amount))]
consideration)]
(alog/info ::unfulfilled-autoapayment-considerations
:count (count considerations)
:amount amount)
@@ -85,13 +84,13 @@
(alog/info ::searching-unpaid-invoice
:client-id client-id
:amount amount)
(try
(try
(let [candidate-invoices-vendor-groups (->> (dc/q {:find ['?vendor-id '?e '?outstanding-balance '?d]
:in ['$ '?client-id]
:where ['[?e :invoice/client ?client-id]
'[?e :invoice/status :invoice-status/unpaid]
'(not [_ :invoice-payment/invoice ?e])
'[?e :invoice/vendor ?vendor-id]
'[?e :invoice/vendor ?vendor-id]
'[?e :invoice/outstanding-balance ?outstanding-balance]
'[?e :invoice/date ?d]]}
(dc/db conn) client-id)
@@ -110,10 +109,10 @@
:amount amount
:count (count considerations))
considerations)
(catch Exception e
(alog/error ::cant-get-considerations
:error e)
[])))
(catch Exception e
(alog/error ::cant-get-considerations
:error e)
[])))
(defn match-transaction-to-single-unfulfilled-autopayments [amount client-id]
(let [considerations (match-transaction-to-unfulfilled-autopayments amount client-id)]
@@ -134,10 +133,10 @@
:transaction/location "A"
:transaction/accounts
[#:transaction-account
{:db/id (random-tempid)
:account (:db/id (a/get-account-by-numeric-code-and-sets 21000 ["default"]))
:location "A"
:amount (Math/abs (:transaction/amount transaction))}])]]
{:db/id (random-tempid)
:account (:db/id (a/get-account-by-numeric-code-and-sets 21000 ["default"]))
:location "A"
:amount (Math/abs (:transaction/amount transaction))}])]]
(conj {:payment/bank-account bank-account-id
:payment/client client-id
@@ -169,30 +168,26 @@
(= 1234 (extract-check-number {:transaction/description-original "Check abc 1234"}))
(= 1234 (extract-check-number {:transaction/description-original "Check abc 4/10 1234"}))
(= 1234 (extract-check-number {:transaction/description-original "Check abc 4/10 1234 12/3"}))
(= 1234 (extract-check-number {:transaction/description-original "Check abc 4/10 1234"}))
(= 1234 (extract-check-number {:transaction/description-original "Check abc 4/10 1234 12/3"}))
(not= 1234 (extract-check-number {:transaction/description-original "Checkcard 4/10 1234"}))
)
(not= 1234 (extract-check-number {:transaction/description-original "Checkcard 4/10 1234"})))
(defn find-expected-deposit [client-id amount date]
(when date
(when date
(-> (dc/q
'[:find (pull ?ed [:db/id {:expected-deposit/vendor [:db/id]}])
:in $ ?c ?a ?d-start
'[:find (pull ?ed [:db/id {:expected-deposit/vendor [:db/id]}])
:in $ ?c ?a ?d-start
:where
[?ed :expected-deposit/client ?c]
(not [?ed :expected-deposit/status :expected-deposit-status/cleared])
[?ed :expected-deposit/date ?d]
[(>= ?d ?d-start)]
[?ed :expected-deposit/total ?a2]
[(auto-ap.utils/dollars= ?a2 ?a)]
]
[(auto-ap.utils/dollars= ?a2 ?a)]]
(dc/db conn) client-id amount (coerce/to-date (t/plus date (t/days -10))))
ffirst)))
(defn categorize-transaction [transaction bank-account existing]
(cond (= :transaction-approval-status/suppressed (existing (:transaction/id transaction)))
:suppressed
@@ -235,7 +230,6 @@
(assoc transaction :transaction/check-number check-number)
transaction))
(defn maybe-clear-payment [{:transaction/keys [check-number client bank-account amount id] :as transaction}]
(when-let [existing-payment (transaction->existing-payment transaction check-number client bank-account amount id)]
(assoc transaction
@@ -245,10 +239,10 @@
:transaction/vendor (:db/id (:payment/vendor existing-payment))
:transaction/location "A"
:transaction/accounts [#:transaction-account
{:db/id (random-tempid)
:account (:db/id (a/get-account-by-numeric-code-and-sets 21000 ["default"]))
:location "A"
:amount (Math/abs (double amount))}])))
{:db/id (random-tempid)
:account (:db/id (a/get-account-by-numeric-code-and-sets 21000 ["default"]))
:location "A"
:amount (Math/abs (double amount))}])))
#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
(defn maybe-autopay-invoices [{:transaction/keys [amount client bank-account] :as transaction}]
@@ -266,8 +260,7 @@
:transaction-account/amount amount
:transaction-account/location "A"}]
:transaction/approval-status :transaction-approval-status/approved
:transaction/vendor (:db/id (:expected-deposit/vendor expected-deposit))
))))
:transaction/vendor (:db/id (:expected-deposit/vendor expected-deposit))))))
(defn maybe-code [{:transaction/keys [client amount] :as transaction} apply-rules valid-locations]
(mu/trace
@@ -304,7 +297,6 @@
(maybe-apply-default-vendor)
remove-nils)))
(defn get-existing [bank-account]
(into {}
(dc/q '[:find ?tid ?as2
@@ -317,7 +309,7 @@
(defprotocol ImportBatch
(import-transaction! [this transaction])
(get-stats [this ])
(get-stats [this])
(get-pending-balance [this bank-account])
(finish! [this])
(fail! [this error]))
@@ -326,21 +318,21 @@
:db/id
:bank-account/locations
:bank-account/start-date
{:client/_bank-accounts [:client/code :client/locked-until :client/locations :db/id]} ])
{:client/_bank-accounts [:client/code :client/locked-until :client/locations :db/id]}])
(defn start-import-batch [source user]
(let [stats (atom {:import-batch/imported 0
:import-batch/suppressed 0
:import-batch/error 0
:import-batch/not-ready 0
:import-batch/extant 0})
:import-batch/suppressed 0
:import-batch/error 0
:import-batch/not-ready 0
:import-batch/extant 0})
pending-balance (atom {})
extant-cache (atom (cache/ttl-cache-factory {} :ttl 60000 ))
extant-cache (atom (cache/ttl-cache-factory {} :ttl 60000))
import-id (get (:tempids @(dc/transact-async conn [{:db/id "import-batch"
:import-batch/date (coerce/to-date (t/now))
:import-batch/source source
:import-batch/status :import-status/started
:import-batch/user-name user}])) "import-batch")
:import-batch/date (coerce/to-date (t/now))
:import-batch/source source
:import-batch/status :import-status/started
:import-batch/user-name user}])) "import-batch")
rule-applying-function (rm/rule-applying-fn (tr/get-all))]
(alog/info ::starting-transaction-import
:source source)
@@ -349,17 +341,17 @@
(import-transaction! [_ transaction]
(let [bank-account (dc/pull (dc/db conn)
bank-account-pull
(:transaction/bank-account transaction))
(:transaction/bank-account transaction))
extant (get (swap! extant-cache cache/through-cache (:transaction/bank-account transaction) get-existing)
(:transaction/bank-account transaction))
action (categorize-transaction transaction bank-account extant)]
(try
(try
(when (not= "POSTED" (:transaction/status transaction))
(swap! pending-balance (fn [pb]
(update pb
(update pb
(:transaction/bank-account transaction)
(fnil + 0.0)
(fnil + 0.0)
(:transaction/amount transaction)))))
(catch Exception e
(alog/warn ::cant-capture-pending
@@ -372,7 +364,7 @@
:error :import-batch/error
:not-ready :import-batch/not-ready) inc))
(when (= :import action)
(try
(try
(let [result (audit-transact [[:upsert-transaction (transaction->txs transaction bank-account rule-applying-function)]
{:db/id import-id
:import-batch/entry (:db/id transaction)}]
@@ -390,14 +382,14 @@
(get-stats [_]
@stats)
(get-pending-balance [_ bank-account]
(or (get @pending-balance bank-account)
0.0))
(or (get @pending-balance bank-account)
0.0))
(fail! [_ error]
(alog/error ::cant-complete-import
:import-id import-id
:error error)
@(dc/transact-async conn [(merge {:db/id import-id
:import-batch/status :import-status/completed
:import-batch/error-message (str error)}
@@ -407,12 +399,10 @@
(alog/info ::finished :import-id import-id :source source :stats (pr-str @stats))
@(dc/transact conn [(merge {:db/id import-id
:import-batch/status :import-status/completed}
@stats)])))))
:import-batch/status :import-status/completed}
@stats)])))))
(defn synthetic-key [{:transaction/keys [date bank-account description-original amount client] } index]
(defn synthetic-key [{:transaction/keys [date bank-account description-original amount client]} index]
(str (str (some-> date coerce/to-date-time atime/localize)) "-" bank-account "-" description-original "-" amount "-" index "-" client))
(defn apply-synthetic-ids [transactions]
@@ -424,7 +414,7 @@
(let [raw-id (synthetic-key transaction index)]
(assoc transaction
:transaction/id #_{:clj-kondo/ignore [:unresolved-var]}
(di/sha-256 raw-id)
(di/sha-256 raw-id)
:transaction/raw-id raw-id
:db/id (random-tempid))))
(range)