Bulk coding works on multiple clients

This commit is contained in:
2023-09-14 21:48:00 -07:00
parent 2454695124
commit 12c676629d
6 changed files with 145 additions and 43 deletions

View File

@@ -24,7 +24,6 @@
[clj-time.coerce :as coerce]
[clojure.set :as set]
[clojure.string :as str]
[clojure.tools.logging :as log]
[datomic.api :as dc]
[iol-ion.tx :refer [random-tempid]]
[com.brunobonacci.mulog :as mu]
@@ -96,7 +95,11 @@
all-ids (->> (get-ids-matching-filters args)
all-ids-not-locked)]
(log/info "Unapproving " (count all-ids) args)
(alog/info ::bulk-change-status
:count (count all-ids)
:sample (take 3 all-ids)
:status (:status args)
)
(audit-transact-batch
(->> all-ids
(mapv (fn [t]
@@ -144,28 +147,31 @@
(defn bulk-code-transactions [context args _]
(assert-admin (:id context))
(when-not (:client_id args)
(when-not (seq (:clients context))
(throw (ex-info "Client is required"
{:validation-error "client is required"})))
(let [args (assoc args :clients [(:client_id args)] :id (:id context))
locations (pull-attr (dc/db conn)
:client/locations
(:client_id args))
{:validation-error "Client is required"})))
(let [args (assoc args :clients (:clients context) :id (:id context))
client->locations (->> (:clients context)
(map :db/id )
(dc/q
'[:find (pull ?e [:db/id :client/locations])
:in $ [?e ...]]
(dc/db conn))
(map (fn [[client]]
[(:db/id client) (:client/locations client)]))
(into {}))
all-ids (all-ids-not-locked (get-ids-matching-filters args))
transactions (pull-many (dc/db conn) [:db/id :transaction/amount] (vec all-ids))
transactions (pull-many (dc/db conn) [:db/id :transaction/amount {:transaction/client [:db/id]}] (vec all-ids))
account-total (reduce + 0 (map (fn [x] (:percentage x)) (:accounts args)))]
(alog/info ::bulk-coding-transactions
:count (count transactions)
:sample (take 3 transactions))
(when
(and
(seq (:accounts args))
(not (dollars= 1.0 account-total)))
(let [error (str "Account total (" account-total ") does not reach 100%")]
(throw (ex-info error {:validation-error error}))))
(doseq [a (:accounts args)
:let [{:keys [:account/location :account/name]} (dc/pull (dc/db conn)
[:account/location :account/name]
@@ -173,20 +179,19 @@
(when (and location (not= location (:location a)))
(let [err (str "Account " name " uses location " (:location a) ", but is supposed to be " location)]
(throw (ex-info err {:validation-error err}) )))
(when (and (not location)
(not (get (into #{"Shared"} locations)
(:location a))))
(let [err (str "Account " name " uses location " (:location a) ", but doesn't belong to the client.")]
(throw (ex-info err {:validation-error err}) ))))
(log/info "Bulk coding " (count all-ids) args)
(doseq [[_ locations] client->locations]
(when (and (not location)
(not (get (into #{"Shared"} locations)
(:location a))))
(let [err (str "Account " name " uses location " (:location a) ", but doesn't belong to the client.")]
(throw (ex-info err {:validation-error err}) )))))
(audit-transact-batch
(map (fn [i]
[:upsert-transaction (cond-> i
(:approval_status args) (assoc :transaction/approval-status (enum->keyword (:approval_status args) "transaction-approval-status"))
(:vendor args) (assoc :transaction/vendor (:vendor args))
(seq (:accounts args)) (assoc :transaction/accounts (maybe-code-accounts i (:accounts args) locations)))])
(map (fn [t]
(let [locations (client->locations (-> t :transaction/client :db/id))]
[:upsert-transaction (cond-> t
(:approval_status args) (assoc :transaction/approval-status (enum->keyword (:approval_status args) "transaction-approval-status"))
(:vendor args) (assoc :transaction/vendor (:vendor args))
(seq (:accounts args)) (assoc :transaction/accounts (maybe-code-accounts t (:accounts args) locations)))]))
transactions)
(:id context))
{:message (str "Successfully coded " (count all-ids) " transactions.")}))
@@ -198,7 +203,9 @@
all-ids (all-ids-not-locked (get-ids-matching-filters args))
db (dc/db conn)]
(log/info "Deleting " (count all-ids) args)
(alog/info ::bulk-delete-transactions
:count (count all-ids)
:sample (take 3 all-ids))
(audit-transact-batch
(mapcat (fn [i]
(let [transaction (dc/pull db [:transaction/payment
@@ -261,7 +268,6 @@
_ (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)
payment (-> transaction :transaction/payment )
is-autopay-payment? (some->> (dc/q {:find ['?sp]
:in ['$ '?payment]
@@ -274,9 +280,8 @@
(every? #(instance? java.util.Date %)))
]
(log/info (:db/id payment))
(alog/info ::unlinking :transaction (pr-str transaction) :autopay is-autopay-payment? :payment (pr-str payment))
(log/info "Unlinking " transaction-id " from payment " payment " - Deleting the payment due to autopay? " is-autopay-payment?)
(when (not= :payment-status/cleared (-> payment :payment/status :db/ident))
(throw (ex-info "Payment can't be undone because it isn't cleared." {:validation-error "Payment can't be undone because it isn't cleared."})))
(if is-autopay-payment?
@@ -452,7 +457,8 @@
autopay_invoice_ids)
(:db/id (:transaction/bank-account transaction))
(:db/id (:transaction/client transaction)))]
(log/info "Adding a new payment" payment-tx)
(alog/info ::adding-payment-from-autopay-invoice
:payment (pr-str payment-tx))
(audit-transact payment-tx (:id context)))
(solr/touch-with-ledger transaction_id)
(-> (d-transactions/get-by-id transaction_id)
@@ -598,7 +604,6 @@
:bulk_code_transactions {:type :message
:args {:filters {:type :transaction_filters}
:vendor {:type :id}
:client_id {:type :id}
:approval_status {:type :transaction_approval_status}
:accounts {:type '(list :edit_percentage_account)}
:ids {:type '(list :id)}}

View File

@@ -19,6 +19,7 @@
(defn rough-match [client-id bank-account-id amount]
(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
:amount (- amount)
:status :payment-status/pending})]
@@ -43,6 +44,7 @@
check-number
(or (-> (d-checks/get-graphql {:client-id client-id
:clients [client-id]
:bank-account-id bank-account-id
:check-number check-number
:amount (- amount)

View File

@@ -178,10 +178,9 @@
[:div.buttons
[:button.button.is-outlined.is-primary {:on-click (dispatch-event [::manual/opening])}
"Manual Yodlee Import"]
(when client
[:button.button.is-warning {:on-click (dispatch-event [::bulk/code-requested checked params total])
:disabled (not (seq checked))}
"Code"])
[:button.button.is-warning {:on-click (dispatch-event [::bulk/code-requested checked params total])
:disabled (not (seq checked))}
"Code"]
[:button.button.is-danger {:on-click (dispatch-event [::delete-selected-requested params false])
:disabled (not (seq checked))}
"Delete"]

View File

@@ -42,7 +42,6 @@
:operation/name "BulkCodeTransactions"}
:venia/queries [[:bulk-code-transactions
{:filters (some-> checked-params data-params->query-params)
:client_id (:id client)
:ids specific-transactions
:vendor (:id (:vendor data))
:approval-status (:transaction-approval-status data)

View File

@@ -123,6 +123,7 @@
(let [transaction-result (sut/transaction->txs (assoc base-transaction
:transaction/description-original "CHECK 10001"
:transaction/check-number 10001
:transaction/amount -30.0)
(dc/pull (dc/db conn ) sut/bank-account-pull bank-account-id)
noop-rule)]

View File

@@ -48,7 +48,8 @@
:transaction/approval-status :transaction-approval-status/approved
:transaction/bank-account "test-bank-account-id")])]
(is (= "Succesfully changed 1 transactions to be unapproved."
(:message (sut/bulk-change-status {:id (admin-token)} {:filters {:client_id test-client-id}
(:message (sut/bulk-change-status {:id (admin-token)
:clients [{:db/id test-client-id}]} {:filters {}
:status :unapproved} nil))))
(is (= :transaction-approval-status/unapproved
(:db/ident (:transaction/approval-status (dc/pull (dc/db conn) '[{:transaction/approval-status [:db/ident]}] transaction-id)))))
@@ -68,9 +69,9 @@
:transaction/bank-account "test-bank-account-id"
:transaction/amount 40.0)])]
(is (= "Successfully coded 1 transactions."
(:message (sut/bulk-code-transactions {:id (admin-token)}
(:message (sut/bulk-code-transactions {:id (admin-token)
:clients [{:db/id test-client-id}]}
{:filters {:client_id test-client-id}
:client_id test-client-id
:vendor test-vendor-id
:approval_status :unapproved
:accounts [{:account_id test-account-id
@@ -87,16 +88,111 @@
:transaction/accounts [:transaction-account/account
:transaction-account/location
:transaction-account/amount]}]
transaction-id))))))
transaction-id)))
(testing "for more than one client"
(let [{:strs [transaction-id-1
transaction-id-2
test-client-id-2
test-client-id]} (setup-test-data [
(test-transaction :db/id "transaction-id-1"
:transaction/client "test-client-id"
:transaction/bank-account "test-bank-account-id"
:transaction/amount 40.0)
(test-transaction :db/id "transaction-id-2"
:transaction/client "test-client-id-2"
:transaction/bank-account "test-bank-account-id-2"
:transaction/amount 40.0)
(test-client :db/id "test-client-id-2"
:client/locations ["GR"])
(test-bank-account :db/id "test-bank-account-id-2")])]
(is (= "Successfully coded 2 transactions."
(:message (sut/bulk-code-transactions {:id (admin-token)
:clients [{:db/id test-client-id}
{:db/id test-client-id-2}]}
{:filters {}
:vendor test-vendor-id
:approval_status :unapproved
:accounts [{:account_id test-account-id
:location "Shared"
:percentage 1.0}]} nil))))
(is (= #:transaction{:vendor {:db/id test-vendor-id}
:approval-status {:db/ident :transaction-approval-status/unapproved}
:accounts [#:transaction-account{:account {:db/id test-account-id}
:location "DT"
:amount 40.0}]}
(dc/pull (dc/db conn) '[:transaction/vendor
{:transaction/approval-status [:db/ident]
:transaction/accounts [:transaction-account/account
:transaction-account/location
:transaction-account/amount]}]
transaction-id-1)))
(is (= #:transaction{:vendor {:db/id test-vendor-id}
:approval-status {:db/ident :transaction-approval-status/unapproved}
:accounts [#:transaction-account{:account {:db/id test-account-id}
:location "GR"
:amount 40.0}]}
(dc/pull (dc/db conn) '[:transaction/vendor
{:transaction/approval-status [:db/ident]
:transaction/accounts [:transaction-account/account
:transaction-account/location
:transaction-account/amount]}]
transaction-id-2))))
(testing "should reject a location that doesnt exist"
(let [{:strs [test-client-id-1
test-client-id-2]} (setup-test-data [
(test-transaction :db/id "transaction-id-1"
:transaction/client "test-client-id-1"
:transaction/bank-account "test-bank-account-id"
:transaction/amount 40.0)
(test-transaction :db/id "transaction-id-2"
:transaction/client "test-client-id-2"
:transaction/bank-account "test-bank-account-id-2"
:transaction/amount 40.0)
(test-client :db/id "test-client-id-1"
:client/locations ["DT" "BOTH"])
(test-client :db/id "test-client-id-2"
:client/locations ["GR" "BOTH"])
(test-bank-account :db/id "test-bank-account-id-2")])]
(is (thrown? Exception (sut/bulk-code-transactions {:id (admin-token)
:clients [{:db/id test-client-id}
{:db/id test-client-id-2}]}
{:filters {}
:vendor test-vendor-id
:approval_status :unapproved
:accounts [{:account_id test-account-id
:location "OG"
:percentage 1.0}]} nil)))
(is (thrown? Exception (sut/bulk-code-transactions {:id (admin-token)
:clients [{:db/id test-client-id}
{:db/id test-client-id-2}]}
{:filters {}
:vendor test-vendor-id
:approval_status :unapproved
:accounts [{:account_id test-account-id
:location "DT"
:percentage 1.0}]} nil)))
(is (sut/bulk-code-transactions {:id (admin-token)
:clients [{:db/id test-client-id-1}
{:db/id test-client-id-2}]}
{:filters {}
:vendor test-vendor-id
:approval_status :unapproved
:accounts [{:account_id test-account-id
:location "BOTH"
:percentage 1.0}]} nil))))))))
(deftest edit-transactions
(testing "Should edit transactions"
(let [{:strs [transaction-id
test-account-id
test-vendor-id]} (setup-test-data [(test-transaction :db/id "transaction-id"
:transaction/client "test-client-id"
:transaction/bank-account "test-bank-account-id"
:transaction/amount 40.0)])]
:transaction/client "test-client-id"
:transaction/bank-account "test-bank-account-id"
:transaction/amount 40.0)])]
(sut/edit-transaction {:id (admin-token)}
{:transaction {:id transaction-id
:vendor_id test-vendor-id