A better way to allow bulk select.

This commit is contained in:
Bryce Covert
2020-08-25 12:10:55 -07:00
parent bd2d10cf52
commit 4ac3e31e91
5 changed files with 142 additions and 51 deletions

View File

@@ -1,6 +1,6 @@
(ns auto-ap.datomic.transactions (ns auto-ap.datomic.transactions
(:require [datomic.api :as d] (:require [datomic.api :as d]
[auto-ap.datomic :refer [uri merge-query apply-sort-3 apply-pagination add-sorter-fields]] [auto-ap.datomic :refer [uri merge-query apply-sort-3 apply-pagination add-sorter-fields conn]]
[auto-ap.graphql.utils :refer [limited-clients]] [auto-ap.graphql.utils :refer [limited-clients]]
[clj-time.coerce :as c] [clj-time.coerce :as c]
[clj-time.coerce :as coerce])) [clj-time.coerce :as coerce]))
@@ -149,6 +149,17 @@
[(->> (graphql-results ids-to-retrieve db args)) [(->> (graphql-results ids-to-retrieve db args))
matching-count])) matching-count]))
(defn filter-ids [ids]
(if ids
(->> {:query {:find ['?e]
:in ['$ '[?e ...]]
:where ['[?e :transaction/date]]}
:args [(d/db conn) ids]}
(d/query)
(map first)
vec)
[]))
(defn get-by-id [id] (defn get-by-id [id]
(-> (->
(d/pull (d/db (d/connect uri)) (d/pull (d/db (d/connect uri))
@@ -168,9 +179,17 @@
(dissoc :transaction/id))) (dissoc :transaction/id)))
(defn unapprove [ids] (defn unapprove [ids]
(doseq [x (partition-all 1000 ids)] (doseq [x (partition-all 100 ids)]
@(d/transact (d/connect uri) @(d/transact (d/connect uri)
(mapv (fn [i] (mapv (fn [i]
{:db/id i {:db/id i
:transaction/approval-status :transaction-approval-status/unapproved}) :transaction/approval-status :transaction-approval-status/unapproved})
x)))) x))))
(defn delete [ids]
(doseq [x (partition-all 100 ids)]
@(d/transact (d/connect uri)
(mapcat (fn [i]
[[:db/retractEntity i]
[:db/retractEntity [:journal-entry/original-entity i]]])
x))))

View File

@@ -64,6 +64,8 @@
%))}} %))}}
:objects :objects
{ {
:message
{:fields {:message {:type 'String}}}
:location_match :location_match
{:fields {:location {:type 'String} {:fields {:location {:type 'String}
:match {:type 'String} :match {:type 'String}
@@ -554,6 +556,7 @@
:resolve :get-vendor} :resolve :get-vendor}
:user {:type '(list :user) :user {:type '(list :user)
:resolve :get-user} :resolve :get-user}
} }
:input-objects :input-objects
@@ -781,19 +784,14 @@
:args {:invoices {:type '(list :id)}} :args {:invoices {:type '(list :id)}}
:resolve :mutation/approve-invoices} :resolve :mutation/approve-invoices}
:unapprove_transactions {:type '(list :transaction_page) :unapprove_transactions {:type :message
:args {:client_id {:type :id} :args {:filters {:type :transaction_filters}
:vendor_id {:type :id} :ids {:type '(list :id)}}
:bank_account_id {:type :id}
:date_range {:type :date_range}
:amount_lte {:type :money}
:amount_gte {:type :money}
:description {:type 'String}
:start {:type 'Int}
:sort {:type '(list :sort_item)}
:approval_status {:type :transaction_approval_status}}
:resolve :mutation/unapprove-transactions} :resolve :mutation/unapprove-transactions}
:delete_transactions {:type :message
:args {:filters {:type :transaction_filters}
:ids {:type '(list :id)}}
:resolve :mutation/delete-transactions}
:delete_transaction_rule {:type :id :delete_transaction_rule {:type :id
:args {:transaction_rule_id {:type :id}} :args {:transaction_rule_id {:type :id}}
:resolve :mutation/delete-transaction-rule} :resolve :mutation/delete-transaction-rule}
@@ -1129,6 +1127,7 @@
:mutation/edit-invoice gq-invoices/edit-invoice :mutation/edit-invoice gq-invoices/edit-invoice
:mutation/edit-transaction gq-transactions/edit-transaction :mutation/edit-transaction gq-transactions/edit-transaction
:mutation/unapprove-transactions gq-transactions/unapprove-transactions :mutation/unapprove-transactions gq-transactions/unapprove-transactions
:mutation/delete-transactions gq-transactions/delete-transactions
:mutation/upsert-transaction-rule gq-transaction-rules/upsert-transaction-rule :mutation/upsert-transaction-rule gq-transaction-rules/upsert-transaction-rule
:test-transaction-rule gq-transaction-rules/test-transaction-rule :test-transaction-rule gq-transaction-rules/test-transaction-rule
:run-transaction-rule gq-transaction-rules/run-transaction-rule :run-transaction-rule gq-transaction-rules/run-transaction-rule

View File

@@ -17,7 +17,8 @@
[auto-ap.datomic.accounts :as a] [auto-ap.datomic.accounts :as a]
[auto-ap.datomic.transaction-rules :as tr] [auto-ap.datomic.transaction-rules :as tr]
[auto-ap.rule-matching :as rm] [auto-ap.rule-matching :as rm]
[clj-time.coerce :as coerce])) [clj-time.coerce :as coerce]
[clojure.tools.logging :as log]))
(def approval-status->graphql (ident->enum-f :transaction/approval-status)) (def approval-status->graphql (ident->enum-f :transaction/approval-status))
@@ -32,10 +33,37 @@
:end (+ (:start (:filters args) 0) (count transactions))})) :end (+ (:start (:filters args) 0) (count transactions))}))
(defn unapprove-transactions [context args value] (defn unapprove-transactions [context args value]
(let [args (assoc args :id (:id context)) (let [_ (assert-admin (:id context))
ids (:ids (d-transactions/raw-graphql-ids (update (<-graphql args) :approval-status enum->keyword "transaction-approval-status")))] args (assoc args :id (:id context))
(d-transactions/unapprove ids) ids (some-> (:filters args)
(get-transaction-page context args value))) (<-graphql)
(update :approval-status enum->keyword "transaction-approval-status")
(assoc :per-page Integer/MAX_VALUE)
(d-transactions/raw-graphql-ids )
:ids)
specific-ids (d-transactions/filter-ids (:ids args))
all-ids (into (set ids) specific-ids)]
(log/info "Unapproving " (count all-ids) args)
(d-transactions/unapprove all-ids)
{:message (str "Succesfully unapproved " (count all-ids) " transactions.")}))
(defn delete-transactions [context args value]
(let [_ (assert-admin (:id context))
args (assoc args :id (:id context))
ids (some-> (:filters args)
(<-graphql)
(update :approval-status enum->keyword "transaction-approval-status")
(assoc :per-page Integer/MAX_VALUE)
(d-transactions/raw-graphql-ids )
:ids)
specific-ids (d-transactions/filter-ids (:ids args))
all-ids (into (set ids) specific-ids)]
(log/info "Deleting " (count all-ids) args)
(d-transactions/delete all-ids)
{:message (str "Succesfully deleted " (count all-ids) " transactions.")}))
(defn transaction-account->entity [{:keys [id account_id amount location]}] (defn transaction-account->entity [{:keys [id account_id amount location]}]
(remove-nils #:transaction-account {:amount (Double/parseDouble amount) (remove-nils #:transaction-account {:amount (Double/parseDouble amount)

View File

@@ -54,29 +54,53 @@
:query/alias :result}]} :query/alias :result}]}
:on-success (fn [result] :on-success (fn [result]
[::data-page/received ::page (:result result)])}})) [::data-page/received ::page (:result result)])}}))
(re-frame/reg-event-fx (re-frame/reg-event-fx
::unapprove-all ::unapprove-selected
(fn [cofx [_ params]] (fn [cofx [_ params]]
(let [checked @(re-frame/subscribe [::data-page/checked ::page])
{:db (-> (:db cofx) checked-params (get checked "header")
(assoc-in [:status :loading] true)) specific-transactions (map :id (vals (dissoc checked "header")))]
:graphql {:token (-> cofx :db :user) (println checked-params)
:owns-state {:single ::unapprove-all} {:db (-> (:db cofx)
:query-obj (assoc-in [:status :loading] true))
{:venia/operation {:operation/type :mutation :graphql {:token (-> cofx :db :user)
:operation/name "UnapproveTransactions"} :owns-state {:single ::unapprove-selected}
:venia/queries [{:query/data :query-obj
[:unapprove-transactions {:venia/operation {:operation/type :mutation
(data-params->query-params params) :operation/name "UnapproveTransactions"}
[[:transactions transaction-read] :venia/queries [{:query/data
:total [:unapprove-transactions
:start {:filters (some-> checked-params data-params->query-params)
:end]]}]} :ids specific-transactions}
:on-success (fn [result] [:message]]}]}
[::data-page/received ::page (set/rename-keys (first (:unapprove-transactions result)) :on-success (fn [result]
{:transactions :data})])}})) [::params-change params]
#_[::data-page/received ::page (:result result)])}})))
(re-frame/reg-event-fx
::delete-selected
(fn [cofx [_ params]]
(let [checked @(re-frame/subscribe [::data-page/checked ::page])
checked-params (get checked "header")
specific-transactions (map :id (vals (dissoc checked "header")))]
(println checked-params)
{:db (-> (:db cofx)
(assoc-in [:status :loading] true))
:graphql {:token (-> cofx :db :user)
:owns-state {:single ::delete-selected}
:query-obj
{:venia/operation {:operation/type :mutation
:operation/name "UnapproveTransactions"}
:venia/queries [{:query/data
[:delete-transactions
{:filters (some-> checked-params data-params->query-params)
:ids specific-transactions}
[:message]]}]}
:on-success (fn [result]
[::params-change params])}})))
(re-frame/reg-event-fx (re-frame/reg-event-fx
::unmounted ::unmounted
@@ -105,22 +129,41 @@
(defn content [] (defn content []
(let [user @(re-frame/subscribe [::subs/user]) (let [is-admin? @(re-frame/subscribe [::subs/is-admin?])
params @(re-frame/subscribe [::data-page/params ::page])] params @(re-frame/subscribe [::data-page/params ::page])
checked @(re-frame/subscribe [::data-page/checked ::page])]
[:div [:div
[:h1.title "Transactions"] [:h1.title "Transactions"]
[status/status-notification {:statuses [[::status/single ::unapprove-all] [status/status-notification {:statuses [[::status/single ::unapprove-selected]
[::status/single ::delete-selected]
[::status/single ::manual-import]]}] [::status/single ::manual-import]]}]
(when (= "admin" (:user/role user)) (when is-admin?
[:div.is-pulled-right [:div.is-pulled-right
[:div.buttons [:div.buttons
(into [:div.tags ] (map (fn [[z {:keys [id]}]]
(if (= "header" z)
[:span.tag.is-medium {:on-click
(dispatch-event [::data-page/remove-check ::page "header"])}
"All visible transactions"]
[:span.tag.is-medium id
[:button.delete.is-small {:on-click
(dispatch-event [::data-page/remove-check ::page id])}]]))
checked))
[:button.button.is-outlined.is-primary {:on-click (dispatch-event [::manual/opening])} [:button.button.is-outlined.is-primary {:on-click (dispatch-event [::manual/opening])}
"Manual Yodlee Import"] "Manual Yodlee Import"]
[:button.button.is-warning {:on-click (dispatch-event [::unapprove-all params]) [:button.button.is-warning {:on-click (dispatch-event [::unapprove-selected params])
:class (status/class-for @(re-frame/subscribe [::status/single ::unapprove-all])) :class (status/class-for @(re-frame/subscribe [::status/single ::unapprove-selected]))
:disabled (status/disabled-for @(re-frame/subscribe [::status/single ::unapprove-all]))} :disabled (or (status/disabled-for @(re-frame/subscribe [::status/single ::unapprove-selected]))
"Unapprove all"]]]) (not (seq checked)))}
"Unapprove selected"]
[:button.button.is-danger {:on-click (dispatch-event [::delete-selected params])
:class (status/class-for @(re-frame/subscribe [::status/single ::delete-selected]))
:disabled (or (status/disabled-for @(re-frame/subscribe [::status/single ::delete-selected]))
(not (seq checked)))}
"Delete selected"]]])
[table/table {:id :transactions [table/table {:id :transactions
:check-boxes? is-admin?
:data-page ::page}]])) :data-page ::page}]]))

View File

@@ -55,16 +55,18 @@
(fn [{table-params :db} [_ params :as z]] (fn [{table-params :db} [_ params :as z]]
{:db (merge table-params params)})) {:db (merge table-params params)}))
(defn table [{:keys [id data-page ]}] (defn table [{:keys [id data-page check-boxes?]}]
(let [selected-client @(re-frame/subscribe [::subs/client]) (let [selected-client @(re-frame/subscribe [::subs/client])
{:keys [data status]} @(re-frame/subscribe [::data-page/page data-page]) {:keys [data status params]} @(re-frame/subscribe [::data-page/page data-page])
states @(re-frame/subscribe [::status/multi ::edits])] states @(re-frame/subscribe [::status/multi ::edits])]
[grid/grid {:data-page data-page [grid/grid {:data-page data-page
:column-count (if selected-client 6 7)} :column-count (if selected-client 6 7)
:check-boxes? check-boxes?}
[grid/controls data] [grid/controls data]
[grid/table {:fullwidth true} [grid/table {:fullwidth true}
[grid/header {} [grid/header {}
[grid/row {} [grid/row {:id "header"
:entity params}
(when-not selected-client (when-not selected-client
[grid/sortable-header-cell {:sort-key "client" :sort-name "Client"} "Client"]) [grid/sortable-header-cell {:sort-key "client" :sort-name "Client"} "Client"])
[grid/sortable-header-cell {:sort-key "account" :sort-name "Bank Account"} "Bank Account"] [grid/sortable-header-cell {:sort-key "account" :sort-name "Bank Account"} "Bank Account"]
@@ -76,7 +78,7 @@
[grid/body [grid/body
(for [{:keys [client account vendor approval-status payment status bank-account description-original date amount id yodlee-merchant ] :as i} (:data data)] (for [{:keys [client account vendor approval-status payment status bank-account description-original date amount id yodlee-merchant ] :as i} (:data data)]
^{:key id} ^{:key id}
[grid/row {:class (:class i) :id id} [grid/row {:class (:class i) :id id :entity i}
(when-not selected-client (when-not selected-client
[grid/cell {} (:name client)]) [grid/cell {} (:name client)])