supports locking transactions
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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."
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user