Makes testing of transaction rules work

This commit is contained in:
2023-10-26 21:23:52 -07:00
parent 5ed23f26be
commit 7f7458d54a
12 changed files with 196 additions and 40 deletions

View File

@@ -41,6 +41,7 @@
wrap-entity
wrap-form-4xx-2
wrap-schema-decode]]
[auto-ap.time :as atime]
[auto-ap.utils :refer [dollars=]]
[bidi.bidi :as bidi]
[clojure.string :as str]
@@ -258,33 +259,31 @@
(set))
bank-account-id))
(defn validate-transaction-rule [form-params]
(doseq [[{:transaction-rule-account/keys [account location]} i] (map vector (:transaction-rule/accounts form-params) (range))
:let [account-location (pull-attr (dc/db conn) :account/location account)]
:when (and account-location (not= account-location location))]
(field-validation-error (str "must be " account-location)
[:transaction-rule/accounts i :transaction-rule-account/location]
:form form-params))
(let [total (reduce + 0.0 (map :transaction-rule-account/percentage (:transaction-rule/accounts form-params)))]
(when-not (dollars= 1.0 total)
(form-validation-error (format "Expense accounts total (%d%%) must add to 100%%" (int (* 100.0 total)))
:form form-params)))
(when (and (:transaction-rule/bank-account form-params)
(not (bank-account-belongs-to-client? (:transaction-rule/bank-account form-params)
(:transaction-rule/client form-params))))
(field-validation-error "does not belong to client"
[:transaction-rule/bank-account]
:form form-params)))
(defn transaction-rule-save [{:keys [form-params request-method identity] :as request}]
(validate-transaction-rule form-params)
(let [entity (cond-> form-params
(= :post request-method) (assoc :db/id "new")
true (assoc :transaction-rule/note (entity->note form-params)))
_ (doseq [[{:transaction-rule-account/keys [account location]} i] (map vector (:transaction-rule/accounts entity) (range))
:let [account-location (pull-attr (dc/db conn) :account/location account)]
:when (and account-location (not= account-location location))]
(field-validation-error (str "must be " account-location)
[:transaction-rule/accounts i :transaction-rule-account/location]
:form form-params))
total (reduce +
0.0
(map :transaction-rule-account/percentage
(:transaction-rule/accounts entity)))
_ (when-not (dollars= 1.0 total)
(form-validation-error (format "Expense accounts total (%d%%) must add to 100%%" (int (* 100.0 total)))
:form form-params))
_ (when (and (:transaction-rule/bank-account entity)
(not (bank-account-belongs-to-client? (:transaction-rule/bank-account entity)
(:transaction-rule/client entity))))
(field-validation-error "does not belong to client"
[:transaction-rule/bank-account]
:form form-params))
{:keys [tempids]} (audit-transact [[:upsert-entity entity]]
(:identity request))
updated-rule (dc/pull (dc/db conn)
@@ -295,7 +294,112 @@
:headers (cond-> {"hx-trigger" "modalclose"}
(= :post request-method) (assoc "hx-retarget" "#entity-table tbody"
"hx-reswap" "afterbegin")
(= :put request-method) (assoc "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id updated-rule)))))))
(= :put request-method) (assoc "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id updated-rule))
"hx-reswap" "outerHTML")))))
(def transaction-read '[{:transaction/client [:client/name]
:transaction/bank-account [:bank-account/name]}
:transaction/description-original
[:transaction/date :xform clj-time.coerce/from-date]])
(defn transaction-rule-test [{:keys [form-params request-method identity] :as request
{:transaction-rule/keys [description client bank-account amount-lte amount-gte dom-lte dom-gte yodlee-merchant]} :form-params}]
(validate-transaction-rule form-params)
(let [valid-clients (extract-client-ids (:clients request)
client)
query (cond-> {:query {:find ['(pull ?e read)]
:in ['$ 'read]
:where []}
:args [(dc/db conn) transaction-read]}
description
(merge-query {:query {:in ['?descr]
:where ['[(iol-ion.query/->pattern ?descr) ?description-regex]]}
:args [description]})
valid-clients
(merge-query {:query {:in ['[?xx ...]]
:where ['[?e :transaction/client ?xx]]}
:args [(set valid-clients)]})
bank-account
(merge-query {:query {:in ['?bank-account-id]
:where ['[?e :transaction/bank-account ?bank-account-id]]}
:args [bank-account]})
description
(merge-query {:query {:where ['[?e :transaction/description-original ?do]
'[(re-find ?description-regex ?do)]]}})
amount-gte
(merge-query {:query {:in ['?amount-gte]
:where ['[?e :transaction/amount ?ta]
'[(>= ?ta ?amount-gte)]]}
:args [amount-gte]})
amount-lte
(merge-query {:query {:in ['?amount-lte]
:where ['[?e :transaction/amount ?ta]
'[(<= ?ta ?amount-lte)]]}
:args [amount-lte]})
dom-lte
(merge-query {:query {:in ['?dom-lte]
:where ['[?e :transaction/date ?transaction-date]
'[(iol-ion.query/dom ?transaction-date) ?dom]
'[(<= ?dom ?dom-lte)]]}
:args [dom-lte]})
dom-gte
(merge-query {:query {:in ['?dom-gte]
:where ['[?e :transaction/date ?transaction-date]
'[(iol-ion.query/dom ?transaction-date) ?dom]
'[(>= ?dom ?dom-gte)]]}
:args [dom-gte]})
client
(merge-query {:query {:in ['?client-id]
:where ['[?e :transaction/client ?client-id]]}
:args [client]})
true
(merge-query {:query {:where ['[?e :transaction/id]]}}))
results (->>
(query2 query)
(map first))]
(html-response
(com/modal-card {:class "fade-in transition duration-300"}
[:div.p-2.flex.space-x-4 [:div "Transaction Rule"] [:div ">"] [:div "Results"] [:div.ml-4.relative (com/badge {} (count results))]]
(com/data-grid
{:headers [(com/data-grid-header {} "Client")
(com/data-grid-header {} "Bank")
(com/data-grid-header {} "Date")
(com/data-grid-header {} "Description")]}
(for [r (take 15 results)]
(com/data-grid-row
{}
(com/data-grid-cell {} (-> r :transaction/client :client/name))
(com/data-grid-cell {} (-> r :transaction/bank-account :bank-account/name))
(com/data-grid-cell {} (some-> r :transaction/date (atime/unparse-local atime/normal-date)))
(com/data-grid-cell {} (some-> r :transaction/description-original )))))
[:div
(com/button (cond-> {:color :primary
:hx-vals (hx/json (:raw-form-params request))
}
(:db/id form-params) (assoc :hx-put (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-save))
(not (:db/id form-params)) (assoc :hx-post (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-save)))
"Save")
(com/button {:hx-vals (hx/json (:raw-form-params request))
:hx-put (bidi/path-for ssr-routes/only-routes
:admin-transaction-rule-filled-account
)} "Back")
])
:headers (-> {}
(assoc "hx-retarget" ".modal-card")
(assoc "hx-reswap" "outerHTML")))))
@@ -366,6 +470,7 @@
:x-data (hx/json {:location (fc/field-value)})}
[:div {:hx-trigger "changed"
:hx-target "next *"
:hx-swap "outerHTML"
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || '', value: event.detail.location}" (fc/field-name) )
:hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select)
:x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data) )"}]
@@ -554,7 +659,11 @@
]]
[:div
(com/form-errors {:errors (:errors fc/*form-errors*)})
(com/validated-save-button {:errors form-errors} "Save rule")])])))
(com/validated-save-button {:errors form-errors} "Save rule")
(com/validated-save-button {:errors form-errors :color :secondary
:hx-post (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-test)}
"Test rule")])])))
(defn new-account [{{:keys [client-id index]} :query-params}]
@@ -607,6 +716,7 @@
[:transaction-rule-account/percentage percentage])]]))
(defn transaction-dialog [{:keys [entity form-params form-errors]}]
(clojure.pprint/pprint form-params)
(modal-response (dialog* {:entity entity
:form-params (or (when (seq form-params)
form-params)
@@ -649,6 +759,19 @@
(wrap-nested-form-params)
(wrap-form-4xx-2 (-> transaction-dialog
(wrap-entity [:form-params :db/id] default-read))))
:admin-transaction-rule-test (-> transaction-rule-test
(wrap-entity [:form-params :db/id] default-read)
(wrap-schema-decode :form-schema form-schema)
(wrap-nested-form-params)
(wrap-form-4xx-2 (-> transaction-dialog
(wrap-entity [:form-params :db/id] default-read))))
:admin-transaction-rule-filled-account (-> transaction-dialog
(wrap-entity [:form-params :db/id] default-read)
(wrap-schema-decode :form-schema form-schema)
(wrap-nested-form-params)
(wrap-form-4xx-2 (-> transaction-dialog
(wrap-entity [:form-params :db/id] default-read))))
:admin-transaction-rule-edit-dialog (-> transaction-dialog
(wrap-entity [:route-params :db/id] default-read)
(wrap-schema-decode :route-schema [:map [:db/id entity-id]]))