560 lines
34 KiB
Clojure
560 lines
34 KiB
Clojure
(ns auto-ap.ssr.payments
|
|
(:require [auto-ap.client-routes :as client-routes]
|
|
[auto-ap.datomic
|
|
:refer [add-sorter-fields apply-pagination apply-sort-3
|
|
audit-transact conn merge-query observable-query
|
|
pull-many]]
|
|
[auto-ap.graphql.utils :refer [assert-can-see-client
|
|
exception->notification
|
|
extract-client-ids notify-if-locked]]
|
|
[auto-ap.logging :as alog]
|
|
[auto-ap.permissions :refer [can?]]
|
|
[auto-ap.routes.invoice :as invoice-route]
|
|
[auto-ap.routes.payments :as route]
|
|
[auto-ap.routes.utils
|
|
:refer [wrap-admin wrap-client-redirect-unauthenticated]]
|
|
[auto-ap.ssr-routes :as ssr-routes]
|
|
[auto-ap.ssr.components :as com]
|
|
[auto-ap.ssr.components.bank-account-icon :as bank-account-icon]
|
|
[auto-ap.ssr.components.link-dropdown :refer [link-dropdown]]
|
|
[auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]]
|
|
[auto-ap.ssr.hx :as hx]
|
|
[auto-ap.ssr.pos.common :refer [date-range-field*]]
|
|
[auto-ap.ssr.svg :as svg]
|
|
[auto-ap.ssr.utils
|
|
:refer [apply-middleware-to-all-handlers clj-date-schema
|
|
dissoc-nil-transformer entity-id html-response
|
|
main-transformer modal-response ref->enum-schema strip
|
|
wrap-entity wrap-implied-route-param wrap-merge-prior-hx
|
|
wrap-schema-enforce]]
|
|
[auto-ap.time :as atime]
|
|
[bidi.bidi :as bidi]
|
|
[clj-time.coerce :as coerce]
|
|
[clojure.string :as str]
|
|
[datomic.api :as dc]
|
|
[hiccup.util :as hu]
|
|
[iol-ion.query :refer [dollars-0?]]
|
|
[malli.core :as mc]
|
|
[malli.transform :as mt]))
|
|
|
|
(defn exact-match-id* [request]
|
|
(if (nat-int? (:exact-match-id (:parsed-query-params request)))
|
|
[:div {:x-data (hx/json {:exact_match (:exact-match-id (:parsed-query-params request))}) :id "exact-match-id-tag"}
|
|
(com/hidden {:name "exact-match-id"
|
|
"x-model" "exact_match"})
|
|
(com/pill {:color :primary}
|
|
[:span.inline-flex.space-x-2.items-center
|
|
[:div "exact match"]
|
|
[:div.w-3.h-3
|
|
(com/link {"@click" "exact_match=null; $nextTick(() => $dispatch('change'))"}
|
|
svg/x)]])]
|
|
[:div {:id "exact-match-id-tag"}]))
|
|
|
|
;; TODO use query-params instead of parsed-query-params
|
|
(defn filters [request]
|
|
[:form#payment-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
|
|
"hx-get" (bidi/path-for ssr-routes/only-routes
|
|
::route/table)
|
|
"hx-target" "#entity-table"
|
|
"hx-indicator" "#entity-table"}
|
|
|
|
(com/hidden {:name "status"
|
|
:value (some-> (:status (:query-params request)) name)})
|
|
[:fieldset.space-y-6
|
|
(com/field {:label "Vendor"}
|
|
(com/typeahead {:name "vendor"
|
|
:id "vendor"
|
|
:url (bidi/path-for ssr-routes/only-routes :vendor-search)
|
|
:value (:vendor (:query-params request))
|
|
:value-fn :db/id
|
|
:content-fn :vendor/name}))
|
|
(date-range-field* request)
|
|
(com/field {:label "Check #"}
|
|
(com/text-input {:name "check-number"
|
|
:id "check-number"
|
|
:class "hot-filter"
|
|
:value (:check-number (:query-params request))
|
|
:placeholder "10001"
|
|
:size :small}))
|
|
(com/field {:label "Invoice #"}
|
|
(com/text-input {:name "invoice-number"
|
|
:id "invoice-number"
|
|
:class "hot-filter"
|
|
:value (:invoice-number (:query-params request))
|
|
:placeholder "10001"
|
|
:size :small}))
|
|
|
|
(com/field {:label "Amount"}
|
|
[:div.flex.space-x-4.items-baseline
|
|
(com/money-input {:name "amount-gte"
|
|
:id "amount-gte"
|
|
:hx-preserve "true"
|
|
:class "hot-filter w-20"
|
|
:value (:amount-gte (:query-params request))
|
|
:placeholder "0.01"
|
|
:size :small})
|
|
[:div.align-baseline
|
|
"to"]
|
|
(com/money-input {:name "amount-lte"
|
|
:hx-preserve "true"
|
|
:id "amount-lte"
|
|
:class "hot-filter w-20"
|
|
:value (:amount-lte (:query-params request))
|
|
:placeholder "9999.34"
|
|
:size :small})])
|
|
(com/field {:label "Payment Type"}
|
|
(com/radio-card {:size :small
|
|
:name "payment-type"
|
|
:value (:payment-type (:query-params request))
|
|
:options [{:value ""
|
|
:content "All"}
|
|
{:value "cash"
|
|
:content "Cash"}
|
|
{:value "check"
|
|
:content "Check"}
|
|
{:value "debit"
|
|
:content "Debit"}]}))
|
|
(exact-match-id* request)]])
|
|
|
|
|
|
(def default-read '[*
|
|
[:payment/date :xform clj-time.coerce/from-date]
|
|
{:invoice-payment/_payment [* {:invoice-payment/invoice [*]}]}
|
|
{:payment/client [:client/name :db/id :client/code]}
|
|
{:payment/bank-account [* {[:bank-account/type :xform iol-ion.query/ident] [:db/ident]}]}
|
|
{:payment/invoices [:db/id :invoice/invoice-number]}
|
|
{:payment/vendor [:vendor/name {:vendor/default-account
|
|
[:account/name :account/numeric-code :db/id]} :db/id {:vendor/primary-contact [*]} {:vendor/address [*]}]}
|
|
{[:payment/status :xform iol-ion.query/ident] [:db/ident]}
|
|
{[:payment/type :xform iol-ion.query/ident] [:db/ident]}
|
|
{:transaction/_payment [:db/id :transaction/date]}])
|
|
|
|
(defn fetch-ids [db {:keys [query-params route-params] :as request}]
|
|
(let [ valid-clients (extract-client-ids (:clients request)
|
|
(:client request)
|
|
(:client-id query-params)
|
|
(when (:client-code query-params)
|
|
[:client/code (:client-code query-params)]))
|
|
|
|
check-number-like (try (Long/parseLong (:check-number query-params)) (catch Exception _ nil))
|
|
query (if (:exact-match-id query-params)
|
|
{:query {:find '[?e]
|
|
:in '[$ ?e [?c ...]]
|
|
:where '[[?e :payment/client ?c]]}
|
|
:args [db
|
|
(:exact-match-id query-params)
|
|
valid-clients]}
|
|
(cond-> {:query {:find []
|
|
:in '[$ [?clients ?start ?end]]
|
|
:where '[[(iol-ion.query/scan-payments $ ?clients ?start ?end) [[?e _ ?sort-default] ...]]]}
|
|
:args [db
|
|
[valid-clients
|
|
(some-> (:start-date query-params) coerce/to-date)
|
|
(some-> (:end-date query-params) coerce/to-date)]]}
|
|
(:sort query-params) (add-sorter-fields {"client" ['[?e :payment/client ?c]
|
|
'[?c :client/name ?sort-client]]
|
|
"vendor" ['[?e :payment/vendor ?v]
|
|
'[?v :vendor/name ?sort-vendor]]
|
|
"bank-account" ['[?e :payment/bank-account ?ba]
|
|
'[?ba :bank-account/name ?sort-bank-account]]
|
|
"check-number" ['[(get-else $ ?e :payment/check-number 0) ?sort-check-number]]
|
|
"date" ['[?e :payment/date ?sort-date]]
|
|
"amount" ['[?e :payment/amount ?sort-amount]]
|
|
"status" ['[?e :payment/status ?sort-status]]}
|
|
query-params)
|
|
(:exact-match-id query-params)
|
|
(merge-query {:query {:in ['?e]
|
|
:where []}
|
|
:args [(:exact-match-id query-params)]})
|
|
|
|
(:vendor query-params)
|
|
(merge-query {:query {:in ['?vendor-id]
|
|
:where ['[?e :payment/vendor ?vendor-id]]}
|
|
:args [(:db/id (:vendor query-params))]})
|
|
|
|
(:original-id query-params)
|
|
(merge-query {:query {:in ['?original-id]
|
|
:where ['[?e :payment/client ?c]
|
|
'[?c :client/original-id ?original-id]]}
|
|
:args [(:original-id query-params)]})
|
|
|
|
(:check-number-like query-params)
|
|
(merge-query {:query {:in ['?check-number]
|
|
:where ['[?e :payment/check-number ?check-number]]}
|
|
:args [(:check-number-like query-params)]})
|
|
|
|
(not-empty (:invoice-number query-params))
|
|
(merge-query {:query {:in ['?invoice-number]
|
|
:where ['[?e :payment/invoices ?i]
|
|
'[?i :invoice/invoice-number ?invoice-number]]}
|
|
:args [(:invoice-number query-params)]})
|
|
|
|
(:bank-account-id query-params)
|
|
(merge-query {:query {:in ['?bank-account-id]
|
|
:where ['[?e :payment/bank-account ?bank-account-id]]}
|
|
:args [(:bank-account-id query-params)]})
|
|
|
|
(:amount-gte query-params)
|
|
(merge-query {:query {:in ['?amount-gte]
|
|
:where ['[?e :payment/amount ?a]
|
|
'[(>= ?a ?amount-gte)]]}
|
|
:args [(:amount-gte query-params)]})
|
|
|
|
(:amount-lte query-params)
|
|
(merge-query {:query {:in ['?amount-lte]
|
|
:where ['[?e :payment/amount ?a]
|
|
'[(<= ?a ?amount-lte)]]}
|
|
:args [(:amount-lte query-params)]})
|
|
|
|
(:amount query-params)
|
|
(merge-query {:query {:in ['?amount]
|
|
:where ['[?e :payment/amount ?transaction-amount]
|
|
'[(iol-ion.query/dollars= ?transaction-amount ?amount)]]}
|
|
:args [(:amount query-params)]})
|
|
|
|
|
|
(:status route-params)
|
|
(merge-query {:query {:in ['?status]
|
|
:where ['[?e :payment/status ?status]]}
|
|
:args [(:status route-params)]})
|
|
|
|
(:payment-type query-params)
|
|
(merge-query {:query {:in '[?payment-type]
|
|
:where ['[?e :payment/type ?payment-type]]}
|
|
:args [(:payment-type query-params)]})
|
|
|
|
check-number-like
|
|
(merge-query {:query {:in '[?check-number-like]
|
|
:where ['[?e :payment/check-number ?check-number-like]]}
|
|
:args [check-number-like]})
|
|
|
|
true
|
|
(merge-query {:query {:find ['?sort-default '?e]}})))]
|
|
(cond->> (observable-query 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 query-schema (mc/schema
|
|
[:maybe [:map {:date-range [:date-range :start-date :end-date]}
|
|
[:sort {:optional true} [:maybe [:any]]]
|
|
[:per-page {:optional true :default 25} [:maybe :int]]
|
|
[:start {:optional true :default 0} [:maybe :int]]
|
|
[:amount-gte {:optional true} [:maybe :double]]
|
|
[:amount-lte {:optional true} [:maybe :double]]
|
|
[:payment-type {:optional true} [:maybe (ref->enum-schema "payment-type")]]
|
|
[:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]]
|
|
[:check-number {:optional true} [:maybe [:string {:decode/string strip}]]]
|
|
[:invoice-number {:optional true} [:maybe [:string {:decode/string strip}]]]
|
|
[:status {:optional true} [:maybe (ref->enum-schema "payment-status")]]
|
|
[:exact-match-id {:optional true} [:maybe entity-id]]
|
|
[:all-selected {:optional true :default nil} [:maybe :boolean]]
|
|
[:selected {:optional true :default nil} [:maybe [:vector {:coerce? true}
|
|
entity-id]]]
|
|
[:start-date {:optional true}
|
|
[:maybe clj-date-schema]]
|
|
[:end-date {:optional true}
|
|
[:maybe clj-date-schema]]]]))
|
|
|
|
(comment
|
|
(mc/decode query-schema
|
|
{:start " "}
|
|
main-transformer))
|
|
|
|
;; TODO fix parsing of query params
|
|
(def grid-page
|
|
(helper/build {:id "entity-table"
|
|
:nav com/main-aside-nav
|
|
:check-boxes? true
|
|
:page-specific-nav filters
|
|
:fetch-page fetch-page
|
|
:oob-render
|
|
(fn [request]
|
|
[(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)
|
|
(assoc-in (exact-match-id* request) [1 :hx-swap-oob] true)])
|
|
:query-schema query-schema
|
|
:parse-query-params (fn [p]
|
|
(mc/decode query-schema p main-transformer))
|
|
:action-buttons (fn [request]
|
|
[(when (can? (:identity request) {:subject :payment :activity :bulk-delete})
|
|
(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/bulk-delete))
|
|
"x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})"
|
|
"hx-include" "#payment-filters"
|
|
:color :red}
|
|
"Void selected"))])
|
|
:row-buttons (fn [_ entity]
|
|
[(when (not= :payment-status/voided (:payment/status entity))
|
|
(com/icon-button {:hx-delete (bidi/path-for ssr-routes/only-routes
|
|
::route/delete
|
|
:db/id (:db/id entity))
|
|
:hx-confirm "Are you sure you want to void this payment?"}
|
|
svg/trash))])
|
|
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes ::route/page)}
|
|
"Payments"]]
|
|
:title (fn [r]
|
|
(str
|
|
(some-> r :rout-params :status name str/capitalize (str " "))
|
|
"Payments"))
|
|
:entity-name "payments"
|
|
:route ::route/table
|
|
:headers [{:key "client"
|
|
:name "Client"
|
|
:sort-key "client"
|
|
:hide? (fn [args]
|
|
(= (count (:clients args)) 1))
|
|
:render #(-> % :payment/client :client/code)}
|
|
{:key "vendor"
|
|
:name "Vendor"
|
|
:sort-key "vendor"
|
|
:render #(-> % :payment/vendor :vendor/name)}
|
|
{:key "bank-account"
|
|
:name "Bank account"
|
|
:sort-key "bank-account"
|
|
:show-starting "xl"
|
|
:render (fn [p]
|
|
[:div.flex.items-center
|
|
(when (:payment/bank-account p)
|
|
(bank-account-icon/icon (:payment/bank-account p)))
|
|
[:div (-> p :payment/bank-account :bank-account/name)]])}
|
|
{:key "check-number"
|
|
:name "Check #"
|
|
:sort-key "check-number"
|
|
:render (fn [{:payment/keys [s3-url check-number]}]
|
|
(if s3-url
|
|
(com/link {:href s3-url :target "_new"} [:div.flex.items-center.gap-x-2 check-number [:div.w-4.h-4 svg/external-link]])
|
|
check-number))}
|
|
{:key "status"
|
|
:name "Status"
|
|
:render (fn [{:payment/keys [status]}]
|
|
(condp = status
|
|
:payment-status/cleared
|
|
(com/pill {:color :primary} "cleared")
|
|
|
|
:payment-status/pending
|
|
(com/pill {:color :secondary} "pending")
|
|
:payment-status/voided
|
|
(com/pill {:color :red} "voided")
|
|
nil
|
|
""))}
|
|
{:key "date"
|
|
:name "Date"
|
|
:show-starting "lg"
|
|
:render (fn [{:payment/keys [date]}]
|
|
(some-> date (atime/unparse-local atime/normal-date)))}
|
|
{:key "amount"
|
|
:name "Amount"
|
|
:render (fn [{:payment/keys [amount]}]
|
|
(some->> amount (format "$%.2f")))}
|
|
{:key "links"
|
|
:name "Links"
|
|
:class "w-8"
|
|
:render (fn [p]
|
|
(link-dropdown (concat (->> p :payment/invoices (map (fn [invoice]
|
|
{:link (hu/url (bidi/path-for ssr-routes/only-routes
|
|
::invoice-route/all-page)
|
|
{:exact-match-id (:db/id invoice)})
|
|
:content (str "Inv. " (:invoice/invoice-number invoice))})))
|
|
(some-> p :transaction/_payment ((fn [t]
|
|
[{:link (hu/url (bidi/path-for client-routes/routes
|
|
:transactions)
|
|
{:exact-match-id (:db/id (first t))})
|
|
:color :secondary
|
|
:content "Transaction"}]))))))}]}))
|
|
|
|
(def row* (partial helper/row* grid-page))
|
|
|
|
|
|
|
|
(comment
|
|
(mc/decode query-schema {"exact-match-id" "123"} (mt/transformer main-transformer mt/strip-extra-keys-transformer))
|
|
(mc/decode query-schema {} (mt/transformer main-transformer mt/strip-extra-keys-transformer))
|
|
(mc/decode query-schema {"exact-match-id" nil} (mt/transformer main-transformer mt/strip-extra-keys-transformer))
|
|
(mc/decode query-schema {"exact-match-id" ""} (mt/transformer main-transformer mt/strip-extra-keys-transformer))
|
|
(mc/decode query-schema {"start-date" "12/21/2023"} (mt/transformer main-transformer mt/strip-extra-keys-transformer))
|
|
(mc/decode query-schema {"payment-type" "food"} (mt/transformer main-transformer mt/strip-extra-keys-transformer))
|
|
(mc/decode query-schema {"vendor" "87"} (mt/transformer main-transformer mt/strip-extra-keys-transformer))
|
|
|
|
|
|
(mc/decode query-schema {"start-date" #inst "2023-12-21T08:00:00.000-00:00"} (mt/transformer main-transformer mt/strip-extra-keys-transformer)))
|
|
|
|
(defn delete [{check :entity :as request identity :identity}]
|
|
(alog/peek ::check-type check)
|
|
(exception->notification
|
|
#(when-not (or (= :payment-status/pending (:payment/status check))
|
|
(#{:payment-type/cash :payment-type/debit :payment-type/balance-credit} (:payment/type check)))
|
|
(throw (ex-info "Payment must be pending." {}))))
|
|
|
|
(exception->notification
|
|
#(assert-can-see-client identity (:db/id (:payment/client check))))
|
|
(notify-if-locked (:db/id (:payment/client check))
|
|
(:payment/date check))
|
|
(let [removing-payments (mapcat (fn [x]
|
|
(let [invoice (:invoice-payment/invoice x)
|
|
new-balance (+ (:invoice/outstanding-balance invoice)
|
|
(:invoice-payment/amount x))]
|
|
[[:db/retractEntity (:db/id x)]
|
|
[:upsert-invoice {:db/id (:db/id invoice)
|
|
:invoice/outstanding-balance new-balance
|
|
:invoice/status (if (dollars-0? new-balance)
|
|
(:invoice/status invoice)
|
|
:invoice-status/unpaid)}]]))
|
|
(:invoice-payment/_payment check))
|
|
updated-payment {:db/id (:db/id check)
|
|
:payment/amount 0.0
|
|
:payment/status :payment-status/voided}]
|
|
(audit-transact (conj removing-payments updated-payment)
|
|
identity)
|
|
|
|
(html-response (row* (:identity request) updated-payment {:delete-after-settle? true :class "live-removed"
|
|
:request request})
|
|
:headers {"hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id check))})))
|
|
|
|
;; TODO use decoding here
|
|
(defn bulk-delete-dialog [request]
|
|
(alog/peek :selected (pr-str (:selected (:query-params request))))
|
|
(let [all-selected (:all-selected (:query-params request))
|
|
selected (:selected (:query-params request))
|
|
ids (cond
|
|
all-selected
|
|
(:ids (fetch-ids (dc/db conn) (-> request
|
|
(assoc-in [:query-params :start] 0)
|
|
(assoc-in [:query-params :per-page] 250))))
|
|
:else
|
|
selected)]
|
|
(modal-response
|
|
(com/modal {}
|
|
(com/modal-card-advanced
|
|
{}
|
|
|
|
(com/modal-body {}
|
|
[:div.flex.flex-col.mt-4.space-y-4.items-center
|
|
[:div.w-24.h-24.bg-red-50.rounded-full.p-4.text-red-300
|
|
|
|
svg/alert]
|
|
[:div "You are about to void " (count ids) " payments. Are you sure you want to do this?"]])
|
|
(com/modal-footer {} [:div.flex.justify-end (com/button {:color :primary
|
|
:hx-vals (hx/json (mc/encode
|
|
query-schema
|
|
(dissoc (:query-params request) :sort)
|
|
(mt/transformer
|
|
main-transformer
|
|
dissoc-nil-transformer
|
|
mt/strip-extra-keys-transformer)))
|
|
:hx-delete (hu/url (bidi/path-for ssr-routes/only-routes
|
|
::route/bulk-delete-confirm))}
|
|
"Void payments")])))
|
|
:headers (-> {}
|
|
(assoc "hx-retarget" ".modal-stack")
|
|
(assoc "hx-reswap" "beforeend")))))
|
|
|
|
(defn void-payments-internal [all-ids id]
|
|
(let [payments-to-update (->> all-ids
|
|
(dc/q '[:find (pull ?p [:db/id
|
|
{:invoice-payment/_payment [:invoice-payment/amount
|
|
:db/id
|
|
{:invoice-payment/invoice [:db/id :invoice/outstanding-balance]}]}])
|
|
:in $ [?p ...]
|
|
:where
|
|
(not [_ :transaction/payment ?p])
|
|
(not [?p :payment/status :payment-status/voided])
|
|
[?p :payment/client ?c]
|
|
[(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu]
|
|
[?p :payment/date ?d]
|
|
[(>= ?d ?lu)]]
|
|
(dc/db conn))
|
|
(map first))]
|
|
(audit-transact (->> payments-to-update
|
|
(mapcat (fn [{:keys [:db/id]
|
|
invoices :invoice-payment/_payment}]
|
|
(into
|
|
[{:db/id id
|
|
:payment/amount 0.0
|
|
:payment/status :payment-status/voided}]
|
|
(->> invoices
|
|
(mapcat (fn [{:keys [:invoice-payment/invoice :db/id :invoice-payment/amount]}]
|
|
(let [new-balance (+ (:invoice/outstanding-balance invoice)
|
|
amount)]
|
|
[[:db.fn/retractEntity id]
|
|
[:upsert-invoice {:db/id (:db/id invoice)
|
|
:invoice/outstanding-balance new-balance
|
|
:invoice/status (if (dollars-0? new-balance)
|
|
(:invoice/status invoice)
|
|
:invoice-status/unpaid)}]]))))))))
|
|
id)
|
|
(count payments-to-update)))
|
|
|
|
(defn bulk-delete-dialog-confirm [request]
|
|
(alog/peek (:form-params request))
|
|
(let [all-selected (:all-selected (:form-params request))
|
|
selected (:selected (:form-params request))
|
|
ids (cond
|
|
all-selected
|
|
(:ids (fetch-ids (dc/db conn) (-> request
|
|
(assoc :query-params (:form-params request))
|
|
(assoc-in [:query-params :start] 0)
|
|
(assoc-in [:query-params :per-page] 250))))
|
|
|
|
|
|
:else
|
|
selected)
|
|
updated-count (void-payments-internal ids (:identity request))]
|
|
|
|
(html-response [:div]
|
|
:headers {"hx-trigger" (hx/json {:modalclose ""
|
|
:notification (format "Successfully voided %d of %d payments."
|
|
updated-count
|
|
(count ids))})})))
|
|
|
|
(defn wrap-status-from-source [handler]
|
|
(fn [{:keys [matched-current-page-route] :as request}]
|
|
(let [ request (cond-> request
|
|
(= ::route/cleared-page matched-current-page-route) (assoc-in [:route-params :status] :payment-status/cleared)
|
|
(= ::route/pending-page matched-current-page-route) (assoc-in [:route-params :status] :payment-status/pending)
|
|
(= ::route/voided-page matched-current-page-route) (assoc-in [:route-params :status] :payment-status/voided)
|
|
(= ::route/all-page matched-current-page-route) (assoc-in [:route-params :status] nil))]
|
|
(handler request))))
|
|
|
|
(def key->handler
|
|
(apply-middleware-to-all-handlers
|
|
{::route/cleared-page (-> (helper/page-route grid-page)
|
|
(wrap-implied-route-param :status :payment-status/cleared))
|
|
::route/pending-page (-> (helper/page-route grid-page)
|
|
(wrap-implied-route-param :status :payment-status/pending))
|
|
::route/voided-page (-> (helper/page-route grid-page)
|
|
(wrap-implied-route-param :status :payment-status/voided))
|
|
::route/all-page (-> (helper/page-route grid-page)
|
|
(wrap-implied-route-param :status nil))
|
|
|
|
::route/delete (-> delete
|
|
(wrap-entity [:route-params :db/id] default-read)
|
|
(wrap-schema-enforce :route-params [:map [:db/id entity-id]]))
|
|
::route/bulk-delete-confirm (-> bulk-delete-dialog-confirm
|
|
(wrap-schema-enforce :form-schema query-schema)
|
|
(wrap-admin))
|
|
::route/bulk-delete (-> bulk-delete-dialog
|
|
(wrap-admin))
|
|
|
|
|
|
::route/table (helper/table-route grid-page)}
|
|
(fn [h]
|
|
(-> h
|
|
(wrap-apply-sort grid-page)
|
|
(wrap-merge-prior-hx)
|
|
(wrap-status-from-source)
|
|
(wrap-schema-enforce :query-schema query-schema)
|
|
(wrap-schema-enforce :hx-schema query-schema)
|
|
(wrap-client-redirect-unauthenticated))))) |