supports locking transactions

This commit is contained in:
Bryce Covert
2022-03-14 11:07:41 -07:00
parent ee6669253f
commit 37ea2c7e97
4 changed files with 49 additions and 13 deletions

View File

@@ -13,6 +13,7 @@
<-graphql <-graphql
assert-admin assert-admin
assert-can-see-client assert-can-see-client
assert-not-locked
assert-power-user assert-power-user
enum->keyword enum->keyword
ident->enum-f ident->enum-f
@@ -69,18 +70,29 @@
specific-ids (d-transactions/filter-ids (:ids args))] specific-ids (d-transactions/filter-ids (:ids args))]
(into (set ids) specific-ids))) (into (set ids) specific-ids)))
(defn all-ids-not-locked [all-ids]
(->> all-ids
(d/q '[:find [?t ...]
:in $ [?t ...]
:where
[?t :transaction/client ?c]
[(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu]
[?t :transaction/date ?d]
[(>= ?d ?lu)]]
(d/db conn))))
(defn bulk-change-status [context args _] (defn bulk-change-status [context args _]
(let [_ (assert-admin (:id context)) (let [_ (assert-admin (:id context))
args (assoc args :id (:id context)) args (assoc args :id (:id context))
all-ids (get-ids-matching-filters args)] all-ids (->> (get-ids-matching-filters args)
all-ids-not-locked)]
(log/info "Unapproving " (count all-ids) args) (log/info "Unapproving " (count all-ids) args)
(audit-transact-batch (audit-transact-batch
(mapv (fn [i] (->> all-ids
{:db/id i (mapv (fn [t]
:transaction/approval-status (enum->keyword (:status args) "transaction-approval-status")}) {:db/id t
all-ids) :transaction/approval-status (enum->keyword (:status args) "transaction-approval-status")})))
(:id context)) (:id context))
{:message (str "Succesfully changed " (count all-ids) " transactions to be " (name (:status args) ) ".")})) {:message (str "Succesfully changed " (count all-ids) " transactions to be " (name (:status args) ) ".")}))
@@ -89,7 +101,6 @@
(with-precision 2 (with-precision 2
(let [accounts (vec (mapcat (let [accounts (vec (mapcat
(fn [ar] (fn [ar]
(println ar)
(let [cents-to-distribute (int (Math/round (Math/abs (* (:percentage ar) (let [cents-to-distribute (int (Math/round (Math/abs (* (:percentage ar)
(:transaction/amount transaction) (:transaction/amount transaction)
100))))] 100))))]
@@ -127,7 +138,7 @@
locations (:client/locations (d/pull (d/db conn) locations (:client/locations (d/pull (d/db conn)
[:client/locations] [:client/locations]
(:client_id (:filters args)))) (:client_id (:filters args))))
all-ids (get-ids-matching-filters args) all-ids (all-ids-not-locked (get-ids-matching-filters args))
transactions (d/pull-many (d/db conn) '[:db/id :transaction/amount] (vec all-ids)) transactions (d/pull-many (d/db conn) '[:db/id :transaction/amount] (vec all-ids))
account-total (reduce + 0 (map (fn [x] (:percentage x)) (:accounts args)))] account-total (reduce + 0 (map (fn [x] (:percentage x)) (:accounts args)))]
(when (when
@@ -166,7 +177,7 @@
(defn delete-transactions [context args _] (defn delete-transactions [context args _]
(let [_ (assert-admin (:id context)) (let [_ (assert-admin (:id context))
args (assoc args :id (:id context)) args (assoc args :id (:id context))
all-ids (get-ids-matching-filters args) all-ids (all-ids-not-locked (get-ids-matching-filters args))
db (d/db conn)] db (d/db conn)]
(log/info "Deleting " (count all-ids) args) (log/info "Deleting " (count all-ids) args)
@@ -219,13 +230,17 @@
transaction (d/pull (d/db conn) transaction (d/pull (d/db conn)
[:transaction/approval-status [:transaction/approval-status
:transaction/status :transaction/status
:transaction/date
:transaction/location :transaction/location
:transaction/vendor :transaction/vendor
:transaction/accounts :transaction/accounts
:transaction/client [:db/id] :transaction/client [:db/id]
{:transaction/payment [{:payment/status [:db/ident]} :db/id]} ] {:transaction/payment [:payment/date {:payment/status [:db/ident]} :db/id]} ]
transaction-id) transaction-id)
_ (assert-can-see-client (:id context) (:transaction/client transaction) ) _ (assert-can-see-client (:id context) (:transaction/client transaction) )
_ (assert-not-locked (:db/id (:transaction/client transaction)) (:transaction/date transaction))
_ (when (:transaction/payment transaction)
(assert-not-locked (:db/id (:transaction/client transaction)) (-> transaction :transaction/payment :payment/date)))
_ (log/info "Unlinking" transaction) _ (log/info "Unlinking" transaction)
payment (-> transaction :transaction/payment ) payment (-> transaction :transaction/payment )
is-autopay-payment? (some->> (doto (d/query {:query {:find ['?sp] is-autopay-payment? (some->> (doto (d/query {:query {:find ['?sp]
@@ -330,6 +345,7 @@
(let [existing-transaction (d-transactions/get-by-id id) (let [existing-transaction (d-transactions/get-by-id id)
_ (assert-can-see-client (:id context) (:transaction/client existing-transaction) ) _ (assert-can-see-client (:id context) (:transaction/client existing-transaction) )
_ (assert-valid-expense-accounts accounts) _ (assert-valid-expense-accounts accounts)
_ (assert-not-locked (:db/id (:transaction/client existing-transaction)) (:transaction/date existing-transaction))
deleted (deleted-accounts existing-transaction accounts) deleted (deleted-accounts existing-transaction accounts)
account-total (reduce + 0 (map (fn [x] (:amount x)) accounts)) account-total (reduce + 0 (map (fn [x] (:amount x)) accounts))
missing-locations (seq (set/difference missing-locations (seq (set/difference
@@ -378,7 +394,8 @@
(let [transaction (d-transactions/get-by-id transaction_id) (let [transaction (d-transactions/get-by-id transaction_id)
payment (d-checks/get-by-id payment_id) payment (d-checks/get-by-id payment_id)
_ (assert-can-see-client (:id context) (:transaction/client transaction) ) _ (assert-can-see-client (:id context) (:transaction/client transaction) )
_ (assert-can-see-client (:id context) (:payment/client payment) )] _ (assert-can-see-client (:id context) (:payment/client payment) )
_ (assert-not-locked (:db/id (:transaction/client transaction)) (:transaction/date transaction))]
(when (not= (:db/id (:transaction/client transaction)) (when (not= (:db/id (:transaction/client transaction))
(:db/id (:payment/client payment))) (:db/id (:payment/client payment)))
(throw (ex-info "Clients don't match" {:validation-error "Payment and client do not match."}))) (throw (ex-info "Clients don't match" {:validation-error "Payment and client do not match."})))
@@ -413,7 +430,8 @@
_ (assert-can-see-client (:id context) (:transaction/client transaction) ) _ (assert-can-see-client (:id context) (:transaction/client transaction) )
db (d/db conn) db (d/db conn)
invoice-clients (set (map (comp :db/id :invoice/client #(d/entity db %)) autopay_invoice_ids)) invoice-clients (set (map (comp :db/id :invoice/client #(d/entity db %)) autopay_invoice_ids))
invoice-amount (reduce + 0.0 (map (comp :invoice/total #(d/entity db %)) autopay_invoice_ids))] invoice-amount (reduce + 0.0 (map (comp :invoice/total #(d/entity db %)) autopay_invoice_ids))
_ (assert-not-locked (:db/id (:transaction/client transaction)) (:transaction/date transaction))]
(when (:transaction/payment transaction) (when (:transaction/payment transaction)
(throw (ex-info "Transaction already linked" {:validation-error "Transaction already linked"}))) (throw (ex-info "Transaction already linked" {:validation-error "Transaction already linked"})))
(when (or (> (count invoice-clients) 1) (when (or (> (count invoice-clients) 1)
@@ -452,6 +470,7 @@
transaction (d-transactions/get-by-id transaction_id) transaction (d-transactions/get-by-id transaction_id)
_ (assert-can-see-client (:id context) (:transaction/client transaction) ) _ (assert-can-see-client (:id context) (:transaction/client transaction) )
_ (assert-not-locked (:db/id (:transaction/client transaction)) (:transaction/date transaction))
db (d/db conn) db (d/db conn)
invoice-clients (set (map (comp :db/id :invoice/client #(d/entity db %)) unpaid_invoice_ids)) invoice-clients (set (map (comp :db/id :invoice/client #(d/entity db %)) unpaid_invoice_ids))
invoice-amount (reduce + 0.0 (map (comp :invoice/outstanding-balance #(d/entity db %)) unpaid_invoice_ids))] invoice-amount (reduce + 0.0 (map (comp :invoice/outstanding-balance #(d/entity db %)) unpaid_invoice_ids))]
@@ -494,6 +513,7 @@
transaction_ids) transaction_ids)
transaction_ids (all-ids-not-locked transaction_ids)
transactions (transduce transactions (transduce
(comp (comp
(map d-transactions/get-by-id) (map d-transactions/get-by-id)

View File

@@ -188,6 +188,11 @@
(-> bank-account :bank-account/start-date coerce/to-date-time)))) (-> bank-account :bank-account/start-date coerce/to-date-time))))
:not-ready :not-ready
(and (:client/locked-until (:client/_bank-accounts bank-account))
(not (t/after? (coerce/to-date-time (:transaction/date transaction))
(coerce/to-date-time (:client/locked-until (:client/_bank-accounts bank-account))))))
:not-ready
:else :else
:import)) :import))
@@ -291,7 +296,7 @@
:db/id :db/id
:bank-account/locations :bank-account/locations
:bank-account/start-date :bank-account/start-date
{:client/_bank-accounts [:client/code :client/locations :db/id]} ] {:client/_bank-accounts [:client/code :client/locked-until :client/locations :db/id]} ]
(:transaction/bank-account transaction)) (:transaction/bank-account transaction))
extant (get (swap! extant-cache cache/through-cache (:transaction/bank-account transaction) get-existing) extant (get (swap! extant-cache cache/through-cache (:transaction/bank-account transaction) get-existing)
(:transaction/bank-account transaction)) (:transaction/bank-account transaction))

View File

@@ -119,6 +119,8 @@
(str "extant " extant)) (str "extant " extant))
(when-let [suppressed (:import-batch/suppressed result)] (when-let [suppressed (:import-batch/suppressed result)]
(str "suppressed " suppressed)) (str "suppressed " suppressed))
(when-let [not-ready (:import-batch/not-ready result)]
(str "too early " not-ready))
(when-let [error (:validation-error result)] (when-let [error (:validation-error result)]
(str "errored " error))]) (str "errored " error))])
" transactions." " transactions."

View File

@@ -43,6 +43,15 @@
(sut/categorize-transaction (assoc base-transaction :transaction/date #inst "2020-01-02") (sut/categorize-transaction (assoc base-transaction :transaction/date #inst "2020-01-02")
(assoc bank-account :bank-account/start-date #inst "2020-01-01") (assoc bank-account :bank-account/start-date #inst "2020-01-01")
{})))) {}))))
(t/testing "Should exclude a transaction before locked-until"
(t/is (= :not-ready
(sut/categorize-transaction (assoc base-transaction :transaction/date #inst "2020-01-01")
(assoc-in bank-account [:client/_bank-accounts :client/locked-until] #inst "2030-01-01")
{})))
(t/is (= :import
(sut/categorize-transaction (assoc base-transaction :transaction/date #inst "2020-01-01")
(assoc-in bank-account [:client/_bank-accounts :client/locked-until] #inst "2010-01-01")
{}))))
(t/testing "Should error a transaction without a client" (t/testing "Should error a transaction without a client"
(t/is (= :error (t/is (= :error
(sut/categorize-transaction (dissoc base-transaction :transaction/client) (sut/categorize-transaction (dissoc base-transaction :transaction/client)