Bulk coding works on multiple clients
This commit is contained in:
@@ -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)}}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user