Makes the entire form work but it just looks janky
This commit is contained in:
627
src/clj/auto_ap/ssr/admin/transaction_rules.clj
Normal file
627
src/clj/auto_ap/ssr/admin/transaction_rules.clj
Normal file
@@ -0,0 +1,627 @@
|
||||
(ns auto-ap.ssr.admin.transaction-rules
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
:refer [add-sorter-fields
|
||||
apply-pagination
|
||||
apply-sort-3
|
||||
audit-transact
|
||||
conn
|
||||
merge-query
|
||||
pull-attr
|
||||
pull-many
|
||||
query2]]
|
||||
[auto-ap.datomic.accounts :as d-accounts]
|
||||
[auto-ap.graphql.utils :refer [extract-client-ids]]
|
||||
[auto-ap.query-params :as query-params]
|
||||
[auto-ap.routes.utils
|
||||
:refer [wrap-admin wrap-client-redirect-unauthenticated]]
|
||||
[auto-ap.ssr-routes :as ssr-routes]
|
||||
[auto-ap.ssr.company :refer [bank-account-typeahead*]]
|
||||
[auto-ap.ssr.components :as com]
|
||||
[auto-ap.ssr.grid-page-helper :as helper]
|
||||
[auto-ap.ssr.hx :as hx]
|
||||
[auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[auto-ap.ssr.utils
|
||||
:refer [apply-middleware-to-all-handlers
|
||||
entity-id
|
||||
field-validation-error
|
||||
form-validation-error
|
||||
html-response
|
||||
many-entity
|
||||
money
|
||||
path->name2
|
||||
percentage
|
||||
ref->enum-schema
|
||||
ref->radio-options
|
||||
regex
|
||||
temp-id
|
||||
wrap-form-4xx-2
|
||||
wrap-schema-decode]]
|
||||
[auto-ap.utils :refer [dollars=]]
|
||||
[bidi.bidi :as bidi]
|
||||
[cheshire.core :as cheshire]
|
||||
[clojure.string :as str]
|
||||
[datomic.api :as dc]
|
||||
[hiccup2.core :as hiccup]
|
||||
[iol-ion.query :refer [ident]]
|
||||
[malli.core :as mc]))
|
||||
|
||||
;; TODO with dependencies, I really don't like that you have to be ultra specific in what
|
||||
;; you want to include, and generating the routes and interconnection is weird too.
|
||||
;; I'm tempted to say to include a full snapshot of the form, and the indicator
|
||||
;; as to which one to generate.
|
||||
|
||||
|
||||
;; TODO lots of escaping concerns (urls in javascript), all these weird name filters
|
||||
|
||||
;; TODO better generation of names?
|
||||
|
||||
|
||||
(defn filters [request]
|
||||
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
|
||||
"hx-get" (bidi/path-for ssr-routes/only-routes
|
||||
:admin-transaction-rule-table)
|
||||
"hx-target" "#transaction-rule-table"
|
||||
"hx-indicator" "#transaction-rule-table"}
|
||||
|
||||
[:fieldset.space-y-6
|
||||
(com/field {:label "Vendor"}
|
||||
(com/typeahead {:name "vendor"
|
||||
:placeholder "Search..."
|
||||
:url (bidi/path-for ssr-routes/only-routes
|
||||
:vendor-search)
|
||||
:id (str "vendor-search")
|
||||
:value [(:db/id (:vendor (:parsed-query-params request)))
|
||||
(:vendor/name (:vendor (:parsed-query-params request)))]}))
|
||||
(com/field {:label "Note"}
|
||||
(com/text-input {:name "note"
|
||||
:id "note"
|
||||
:class "hot-filter"
|
||||
:value (:note (:parsed-query-params request))
|
||||
:placeholder "HOME DEPOT lte 250.0"
|
||||
:size :small}))
|
||||
|
||||
(com/field {:label "Description"}
|
||||
(com/text-input {:name "description"
|
||||
:id "description"
|
||||
:class "hot-filter"
|
||||
:value (:description (:parsed-query-params request))
|
||||
:placeholder "LOWES"
|
||||
:size :small}))]])
|
||||
|
||||
(def default-read '[:db/id
|
||||
:transaction-rule/description
|
||||
:transaction-rule/note
|
||||
:transaction-rule/amount-lte
|
||||
:transaction-rule/amount-gte
|
||||
:transaction-rule/dom-lte
|
||||
:transaction-rule/dom-gte
|
||||
{:transaction-rule/client [:client/name :db/id :client/code :client/locations]}
|
||||
{:transaction-rule/bank-account [:db/id :bank-account/name]}
|
||||
{:transaction-rule/yodlee-merchant [:db/id :yodlee-merchant/name :yodlee-merchant/yodlee-id]}
|
||||
{[:transaction-rule/transaction-approval-status :xform iol-ion.query/ident] [:db/id :db/ident]}
|
||||
{:transaction-rule/vendor [:vendor/name :db/id :vendor/default-account]}
|
||||
{:transaction-rule/accounts [:transaction-rule-account/percentage
|
||||
:transaction-rule-account/location
|
||||
{:transaction-rule-account/account [:account/name :db/id :account/numeric-code :account/location
|
||||
{:account/client-overrides [:db/id
|
||||
:account-client-override/name
|
||||
{:account-client-override/client [:db/id :client/name]}]}]}
|
||||
:db/id]}])
|
||||
|
||||
(defn fetch-ids [db request]
|
||||
(let [query-params (:parsed-query-params request)
|
||||
valid-clients (extract-client-ids (:clients request)
|
||||
(:client request)
|
||||
(:client-id query-params)
|
||||
(when (:client-code query-params)
|
||||
[:client/code (:client-code query-params)]))
|
||||
query (cond-> {:query {:find []
|
||||
:in ['$]
|
||||
:where []}
|
||||
:args [db]}
|
||||
(:sort query-params) (add-sorter-fields {"client" ['[?e :transaction-rule/client ?c]
|
||||
'[?c :client/name ?sort-client]]
|
||||
|
||||
"yodlee-merchant" ['[?e :transaction-rule/yodlee-merchant ?ym]
|
||||
'[?ym :yodlee-merchant/name ?sort-yodlee-merchant]]
|
||||
"bank-account" ['[?e :transaction-rule/bank-account ?ba]
|
||||
'[?ba :bank-account/name ?sort-bank-account]]
|
||||
"description" ['[?e :transaction-rule/description ?sort-description]]
|
||||
"note" ['[?e :transaction-rule/note ?sort-note]]
|
||||
"amount-lte" ['[?e :transaction-rule/amount-lte ?sort-amount-lte]]
|
||||
"amount-gte" ['[?e :transaction-rule/amount-gte ?sort-amount-gte]]}
|
||||
query-params)
|
||||
|
||||
(seq valid-clients)
|
||||
(merge-query {:query {:in ['[?xx ...]]
|
||||
:where ['(or-join [?e]
|
||||
(and [?e :transaction-rule/client ?xx])
|
||||
(and (not [?e :transaction-rule/client])
|
||||
[?e :transaction-rule/note]))]}
|
||||
:args [valid-clients]})
|
||||
|
||||
(-> query-params :vendor :db/id)
|
||||
(merge-query {:query {:in ['?vendor-id]
|
||||
:where ['[?e :transaction-rule/vendor ?vendor-id]]}
|
||||
:args [(-> query-params :vendor :db/id)]})
|
||||
|
||||
(not (str/blank? (:note query-params)))
|
||||
(merge-query {:query {:in ['?note-pattern]
|
||||
:where ['[?e :transaction-rule/note ?n]
|
||||
'[(re-find ?note-pattern ?n)]]}
|
||||
:args [(re-pattern (str "(?i)" (:note query-params)))]})
|
||||
|
||||
(not (str/blank? (:description query-params)))
|
||||
(merge-query {:query {:in ['?description]
|
||||
:where ['[?e :transaction-rule/description ?d]
|
||||
'[(clojure.string/lower-case ?d) ?d2]
|
||||
'[(clojure.string/includes? ?d2 ?description)]]}
|
||||
:args [(clojure.string/lower-case (:description query-params))]})
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?e]
|
||||
:where ['[?e :transaction-rule/transaction-approval-status]]}}))]
|
||||
|
||||
(cond->> (query2 query)
|
||||
true (apply-sort-3 query-params)
|
||||
true (apply-pagination query-params))))
|
||||
|
||||
(defn hydrate-results [ids db _]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
refunds (->> ids
|
||||
(map results)
|
||||
(map first))]
|
||||
refunds))
|
||||
|
||||
(defn fetch-page [request]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]
|
||||
|
||||
[(->> (hydrate-results ids-to-retrieve db request))
|
||||
matching-count]))
|
||||
|
||||
(def grid-page
|
||||
(helper/build {:id "transaction-rule-table"
|
||||
:nav (com/admin-aside-nav)
|
||||
:page-specific-nav filters
|
||||
:fetch-page fetch-page
|
||||
:parse-query-params (comp
|
||||
(query-params/parse-key :vendor #(dc/pull (dc/db conn) '[:vendor/name :db/id] (Long/parseLong %)))
|
||||
(helper/default-parse-query-params grid-page))
|
||||
:action-buttons (fn [request]
|
||||
[(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||
:admin-transaction-rule-new-dialog))
|
||||
:hx-target "#modal-holder"
|
||||
:hx-swap "innerHTML"
|
||||
:color :primary}
|
||||
"New Transaction Rule")])
|
||||
:row-buttons (fn [request entity]
|
||||
[(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||
:admin-transaction-rule-edit-dialog
|
||||
:db/id (:db/id entity)))
|
||||
:hx-target "#modal-holder"
|
||||
:hx-swap "innerHTML"}
|
||||
svg/pencil)])
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:admin)}
|
||||
"Admin"]
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:admin-transaction-rules)}
|
||||
"Transaction Rules"]]
|
||||
:title "Rules"
|
||||
:entity-name "Rule"
|
||||
:route :admin-transaction-rule-table
|
||||
:headers [{:key "client"
|
||||
:name "Client"
|
||||
:sort-key "client"
|
||||
:render #(-> % :transaction-rule/client :client/name)}
|
||||
{:key "bank-account"
|
||||
:name "Bank account"
|
||||
:sort-key "bank-account"
|
||||
:render #(-> % :transaction-rule/bank-account :bank-account/name)}
|
||||
{:key "description"
|
||||
:name "Description"
|
||||
:sort-key "description"
|
||||
:render :transaction-rule/description}
|
||||
{:key "amount"
|
||||
:name "Amount"
|
||||
:sort-key "amount"
|
||||
:render (fn [{:transaction-rule/keys [amount-gte amount-lte]}]
|
||||
[:div.flex.gap-2 (when amount-gte
|
||||
(com/pill {:color :red} (format "more than $%.2f" amount-gte)))
|
||||
|
||||
(when amount-lte
|
||||
(com/pill {:color :primary} (format "less than $%.2f" amount-lte)))])}
|
||||
{:key "note"
|
||||
:name "Note"
|
||||
:sort-key "note"
|
||||
:render :transaction-rule/note}
|
||||
]}))
|
||||
|
||||
(def row* (partial helper/row* grid-page))
|
||||
(def table* (partial helper/table* grid-page))
|
||||
|
||||
(defn entity->note [{:transaction-rule/keys [amount-lte amount-gte description client dom-lte dom-gte]}]
|
||||
(str/join " - " (filter (complement str/blank?)
|
||||
[(when client (pull-attr (dc/db conn) :client/code client))
|
||||
description
|
||||
(when (or amount-lte amount-gte)
|
||||
(str (when amount-gte
|
||||
(str amount-gte "<"))
|
||||
"amt"
|
||||
(when amount-lte
|
||||
(str "<" amount-lte))))
|
||||
|
||||
(when (or dom-lte dom-gte)
|
||||
(str (when dom-gte
|
||||
(str dom-gte "<"))
|
||||
"dom"
|
||||
(when dom-lte
|
||||
(str "<" dom-lte))))])))
|
||||
|
||||
(defn bank-account-belongs-to-client? [bank-account-id client-id]
|
||||
(get (->> (dc/pull (dc/db conn) [{:client/bank-accounts [:db/id]}] client-id)
|
||||
:client/bank-accounts
|
||||
(map :db/id)
|
||||
(set))
|
||||
bank-account-id))
|
||||
|
||||
(defn transaction-rule-save [{:keys [form-params request-method identity] :as request}]
|
||||
(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 entity))
|
||||
|
||||
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 entity))
|
||||
|
||||
_ (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 entity))
|
||||
|
||||
|
||||
{:keys [tempids]} (audit-transact [[:upsert-entity entity]]
|
||||
(:identity request))
|
||||
updated-account (dc/pull (dc/db conn)
|
||||
default-read
|
||||
(or (get tempids (:db/id entity)) (:db/id entity)))]
|
||||
(html-response
|
||||
(row* identity updated-account {:flash? true})
|
||||
:headers {"hx-trigger" "modalClosing"
|
||||
"hx-retarget" (format "#transaction-rule-table tr[data-id=\"%d\"]" (:db/id updated-account))})))
|
||||
|
||||
|
||||
|
||||
(defn- location-select*
|
||||
[{:keys [ name account-location client-locations value]}]
|
||||
(com/select {:options (into [["" ""]]
|
||||
(cond account-location
|
||||
[[account-location account-location]]
|
||||
|
||||
(seq client-locations)
|
||||
(into [["Shared" "Shared"]]
|
||||
(for [cl client-locations]
|
||||
[cl cl]))
|
||||
:else
|
||||
[["Shared" "Shared"]]))
|
||||
:name name
|
||||
:value value}))
|
||||
|
||||
(defn- account-typeahead*
|
||||
[{:keys [name value client-id]}]
|
||||
[:div.flex.flex-col
|
||||
(com/typeahead {:name name
|
||||
:placeholder "Search..."
|
||||
:url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id)
|
||||
:id name
|
||||
:value value
|
||||
:value-fn (some-fn :db/id identity)
|
||||
:content-fn (fn [value]
|
||||
(:account/name (d-accounts/clientize (cond->> value
|
||||
(nat-int? value) (dc/pull (dc/db conn) d-accounts/default-read))
|
||||
client-id)))})])
|
||||
|
||||
|
||||
|
||||
(defn- transaction-rule-account-row*
|
||||
[transaction-rule account]
|
||||
(com/data-grid-row {}
|
||||
(let [account-name (path->name2 :transaction-rule/accounts (:db/id account) :transaction-rule-account/account)
|
||||
location-name (path->name2 :transaction-rule/accounts (:db/id account) :transaction-rule-account/location)]
|
||||
(list
|
||||
(com/data-grid-cell {}
|
||||
[:div {:hx-trigger (hx/trigger-field-change :name "transaction-rule/client"
|
||||
:from "#edit-form")
|
||||
:hx-include "#edit-form"
|
||||
:hx-vals (hx/vals {:name account-name})
|
||||
:hx-ext "rename-params"
|
||||
:hx-rename-params-ex (hx/json {:transaction-rule/client "client-id"
|
||||
:name "name"
|
||||
account-name "value"})
|
||||
:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead))
|
||||
:hx-swap "innerHTML"}
|
||||
(account-typeahead* {:value (:transaction-rule-account/account account)
|
||||
:client-id (:db/id (:transaction-rule/client transaction-rule))
|
||||
:name account-name})
|
||||
(com/field-errors {:source account
|
||||
:key :transaction-rule-account/account})])
|
||||
(com/data-grid-cell {}
|
||||
[:div {:hx-trigger (hx/triggers
|
||||
(hx/trigger-field-change :name "transaction-rule/client"
|
||||
:from "#edit-form")
|
||||
(hx/trigger-field-change :name account-name
|
||||
:from "#edit-form"))
|
||||
:hx-include "#edit-form"
|
||||
:hx-vals (hx/vals {:name location-name})
|
||||
:hx-ext "rename-params"
|
||||
:hx-rename-params-ex (hx/json {"transaction-rule/client" "client-id"
|
||||
account-name "account-id"
|
||||
"name" "name"
|
||||
location-name "value"})
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select)
|
||||
:hx-swap "innerHTML"}
|
||||
(location-select* {:name location-name
|
||||
:account-location (:account/location (cond->> (:transaction-rule-account/account account)
|
||||
(nat-int? (:transaction-rule-account/account account)) (dc/pull (dc/db conn)
|
||||
'[:account/location])))
|
||||
:client-locations (:client/locations (:transaction-rule/client transaction-rule))
|
||||
:value (:transaction-rule-account/location account)})
|
||||
(com/field-errors {:source account
|
||||
:key :transaction-rule-account/location})])
|
||||
(com/data-grid-cell (com/money-input {:name (format "transaction-rule/accounts[%s][transaction-rule-account/percentage]" (:db/id account))
|
||||
:class "w-16"
|
||||
:value (some-> account
|
||||
:transaction-rule-account/percentage
|
||||
(* 100 )
|
||||
(long ))})
|
||||
(com/field-errors {:source account
|
||||
:key :transaction-rule-account/percentage}))))
|
||||
(com/data-grid-cell
|
||||
(com/a-icon-button
|
||||
{"_" (hiccup/raw "on click halt the event then transition the closest <tr />'s opacity to 0 then remove closest <tr />")
|
||||
:href "#"}
|
||||
svg/x))))
|
||||
|
||||
|
||||
|
||||
(defn dialog* [& {:keys [ entity form-params]}]
|
||||
(com/modal
|
||||
{:modal-class "max-w-4xl"}
|
||||
(com/modal-card
|
||||
{}
|
||||
[:div.flex [:div.p-2 "Transaction Rule"] ]
|
||||
[:form#edit-form (merge {:hx-ext "response-targets"
|
||||
:hx-swap "outerHTML swap:300ms"
|
||||
:hx-target "#modal-holder"
|
||||
:hx-target-400 "#form-errors .error-content"}
|
||||
form-params)
|
||||
[:fieldset {:class "hx-disable" :hx-disinherit "hx-target"}
|
||||
|
||||
[:div.space-y-6
|
||||
(when-let [id (:db/id entity)]
|
||||
(com/hidden {:name "db/id"
|
||||
:value id}))
|
||||
(com/field {:label "Client"}
|
||||
[:div.w-96
|
||||
(com/typeahead {:name "transaction-rule/client"
|
||||
:class "w-96"
|
||||
:placeholder "Search..."
|
||||
:url (bidi/path-for ssr-routes/only-routes :company-search)
|
||||
:id (str "form-client-search")
|
||||
:value (:transaction-rule/client entity)
|
||||
:value-fn (some-fn :db/id identity)
|
||||
:content-fn (fn [c] (cond->> c
|
||||
(nat-int? c) (dc/pull (dc/db conn) '[:client/name])
|
||||
true :client/name))})])
|
||||
|
||||
|
||||
(com/field {:label "Bank Account"}
|
||||
[:div#bank-account-spot.w-96 {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead)
|
||||
:hx-trigger (hx/trigger-field-change :name "transaction-rule/client"
|
||||
:from "#edit-form")
|
||||
:hx-swap "innerHTML"
|
||||
:hx-ext "rename-params"
|
||||
:hx-include "#edit-form"
|
||||
:hx-vals (hx/vals {:name "transaction-rule/bank-account"})
|
||||
:hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id"
|
||||
"name" "name"})}
|
||||
(bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity))
|
||||
:name "transaction-rule/bank-account"
|
||||
:value (:transaction-rule/bank-account entity)})
|
||||
(com/field-errors {:source entity
|
||||
:key :transaction-rule/bank-account})])
|
||||
|
||||
(com/field {:label "Description"
|
||||
:error-source entity
|
||||
:error-key :transaction-rule/description}
|
||||
(com/text-input {:name "transaction-rule/description"
|
||||
"_" (hiccup/raw "on load call me.focus()")
|
||||
:placeholder "HOME DEPOT"
|
||||
:class "w-96"
|
||||
:value (:transaction-rule/description entity)}))
|
||||
|
||||
|
||||
|
||||
(com/field {:label "Amount"}
|
||||
[:div.flex.gap-2
|
||||
(com/money-input {:name "transaction-rule/amount-gte"
|
||||
:placeholder ">="
|
||||
:class "w-24"
|
||||
:value (:transaction-rule/amount-gte entity)})
|
||||
(com/money-input {:name "transaction-rule/amount-lte"
|
||||
:placeholder "<="
|
||||
:class "w-24"
|
||||
:value (:transaction-rule/amount-lte entity)})])
|
||||
|
||||
(com/field {:label "Day of month"}
|
||||
[:div.flex.gap-2
|
||||
(com/int-input {:name "transaction-rule/dom-gte"
|
||||
:placeholder ">="
|
||||
:class "w-24"
|
||||
:value (:transaction-rule/dom-gte entity)})
|
||||
(com/int-input {:name "transaction-rule/dom-lte"
|
||||
:placeholder "<="
|
||||
:class "w-24"
|
||||
:value (:transaction-rule/dom-lte entity)})])
|
||||
|
||||
[:h2.text-lg "Outcomes"]
|
||||
(com/field {:label "Assign Vendor"
|
||||
:error-source entity
|
||||
:error-key :transaction-rule/vendor}
|
||||
[:div.w-96
|
||||
(com/typeahead {:name "transaction-rule/vendor"
|
||||
:placeholder "Search..."
|
||||
:url (bidi/path-for ssr-routes/only-routes :vendor-search)
|
||||
:id (str "form-vendor-search")
|
||||
:value (:transaction-rule/vendor entity)
|
||||
:value-fn (some-fn :db/id identity)
|
||||
:content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])
|
||||
|
||||
(com/data-grid {:headers [(com/data-grid-header {}
|
||||
"Account")
|
||||
(com/data-grid-header {:class "w-16"} "Location")
|
||||
(com/data-grid-header {:class "w-16"} "%")
|
||||
(com/data-grid-header {:class "w-16"})]
|
||||
:id "transaction-rule-account-table"}
|
||||
(for [tra (:transaction-rule/accounts entity)]
|
||||
(transaction-rule-account-row* entity tra)))
|
||||
(com/field-errors {:source entity
|
||||
:key :transaction-rule/accounts})
|
||||
(com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
:admin-transaction-rule-new-account)
|
||||
:hx-include "#edit-form"
|
||||
:hx-ext "rename-params"
|
||||
:hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id"})
|
||||
:hx-target "#transaction-rule-account-table tbody"
|
||||
:hx-swap "beforeend"}
|
||||
"New account")
|
||||
(com/radio {:options (ref->radio-options "transaction-approval-status")
|
||||
:value (:transaction-rule/transaction-approval-status entity)
|
||||
:name (path->name2 :transaction-rule/transaction-approval-status)})
|
||||
|
||||
[:div#form-errors [:span.error-content
|
||||
(com/field-errors {:source entity})]]
|
||||
(com/button {:color :primary :form "edit-form" :type "submit"}
|
||||
"Save")]]]
|
||||
[:div])))
|
||||
|
||||
(defn new-account [{{:keys [client-id]} :query-params}]
|
||||
(html-response
|
||||
(transaction-rule-account-row*
|
||||
{:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id]
|
||||
client-id)}
|
||||
{:db/id (str (java.util.UUID/randomUUID))
|
||||
:transaction-rule-account/location "shared"})))
|
||||
|
||||
(defn location-select [{{:keys [name account-id client-id value] :as qp} :query-params}]
|
||||
(html-response (location-select* {:name name
|
||||
:value value
|
||||
:account-location (some->> account-id
|
||||
(pull-attr (dc/db conn) :account/location))
|
||||
:client-locations (some->> client-id
|
||||
(pull-attr (dc/db conn) :client/locations))})))
|
||||
|
||||
(defn account-typeahead [{{:keys [name value client-id] :as qp} :query-params}]
|
||||
(let [account (some->> value (dc/pull (dc/db conn) [:account/name :db/id
|
||||
{:account/client-overrides [:db/id
|
||||
:account-client-override/name
|
||||
{:account-client-override/client [:db/id :client/name]}]}]))
|
||||
client-id client-id]
|
||||
(html-response (account-typeahead* {:name name
|
||||
:value account
|
||||
:client-id client-id}))))
|
||||
|
||||
(defn transaction-rule-edit-dialog [request]
|
||||
(let [entity (or
|
||||
(some-> request :last-form)
|
||||
(some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %))))]
|
||||
(html-response (dialog* :entity entity
|
||||
:form-params {:hx-put (str (bidi/path-for ssr-routes/only-routes
|
||||
:admin-transaction-rule-edit-save))})
|
||||
:headers {"hx-trigger" "modalOpening"})))
|
||||
|
||||
(defn transaction-rule-error [request]
|
||||
(let [entity (some-> request :last-form)]
|
||||
(html-response (dialog* :entity entity)
|
||||
:headers {"hx-retarget" "#edit-form fieldset"
|
||||
"hx-reselect" "#edit-form fieldset"})))
|
||||
|
||||
|
||||
(defn account-new-dialog [_]
|
||||
(html-response (dialog* :account nil
|
||||
:form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes
|
||||
:admin-account-new-save))})
|
||||
:headers {"hx-trigger" "modalOpening"}))
|
||||
|
||||
(def transaction-rule-schema (mc/schema
|
||||
[:map
|
||||
[:db/id {:optional true} [:maybe entity-id]]
|
||||
[:transaction-rule/client {:optional true} [:maybe entity-id]]
|
||||
[:transaction-rule/description [:and regex
|
||||
[:string {:min 3}]]]
|
||||
[:transaction-rule/bank-account [:maybe entity-id]]
|
||||
[:transaction-rule/amount-gte {:optional true} [:maybe money]]
|
||||
[:transaction-rule/amount-lte {:optional true} [:maybe money]]
|
||||
[:transaction-rule/dom-gte {:optional true} [:maybe :int]]
|
||||
[:transaction-rule/dom-lte {:optional true} [:maybe :int]]
|
||||
[:transaction-rule/vendor {:optional true} [:maybe entity-id]]
|
||||
[:transaction-rule/transaction-approval-status (ref->enum-schema "transaction-approval-status")]
|
||||
[:transaction-rule/accounts
|
||||
(many-entity {:min 1}
|
||||
[:db/id [:or entity-id temp-id]]
|
||||
[:transaction-rule-account/account entity-id]
|
||||
[:transaction-rule-account/location :string]
|
||||
[:transaction-rule-account/percentage percentage])]]))
|
||||
|
||||
(def key->handler
|
||||
(apply-middleware-to-all-handlers
|
||||
(->>
|
||||
{:admin-transaction-rules (helper/page-route grid-page)
|
||||
:admin-transaction-rule-table (helper/table-route grid-page)
|
||||
:admin-transaction-rule-new-account (-> new-account
|
||||
(wrap-schema-decode :query-schema [:map
|
||||
[:client-id {:optional true}
|
||||
[:maybe entity-id]]])
|
||||
wrap-admin wrap-client-redirect-unauthenticated)
|
||||
:admin-transaction-rule-location-select (-> location-select
|
||||
(wrap-schema-decode :query-schema [:map
|
||||
[:name :string]
|
||||
[:client-id {:optional true}
|
||||
[:maybe entity-id]]
|
||||
[:account-id {:optional true}
|
||||
[:maybe entity-id]]]))
|
||||
:admin-transaction-rule-account-typeahead (-> account-typeahead
|
||||
(wrap-schema-decode :query-schema [:map
|
||||
[:name :string]
|
||||
[:client-id {:optional true}
|
||||
[:maybe entity-id]]
|
||||
[:value {:optional true}
|
||||
[:maybe entity-id]]]))
|
||||
:admin-transaction-rule-save (-> transaction-rule-save
|
||||
(wrap-schema-decode :form-schema transaction-rule-schema)
|
||||
(wrap-nested-form-params)
|
||||
(wrap-form-4xx-2 transaction-rule-error))
|
||||
:admin-transaction-rule-edit-dialog (-> transaction-rule-edit-dialog
|
||||
(wrap-schema-decode :route-schema [:map [:db/id entity-id]]))
|
||||
:admin-transaction-rule-new-dialog account-new-dialog})
|
||||
(fn [h]
|
||||
(-> h
|
||||
(wrap-admin)
|
||||
(wrap-client-redirect-unauthenticated)))))
|
||||
Reference in New Issue
Block a user