Links for ledger, and bank account picker

This commit is contained in:
2024-08-23 23:24:05 -07:00
parent ab5869b4fb
commit 4316ebb34a
5 changed files with 97 additions and 75 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,6 @@
(ns auto-ap.ssr.company-dropdown (ns auto-ap.ssr.company-dropdown
(:require [auto-ap.datomic :refer [conn pull-many]] (:require [auto-ap.datomic :refer [conn pull-many]]
[auto-ap.graphql.utils :refer [cleanse-query]] [auto-ap.graphql.utils :refer [cleanse-query]]
[auto-ap.logging :as alog]
[auto-ap.solr :as solr] [auto-ap.solr :as solr]
[auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr-routes :as ssr-routes]
[auto-ap.ssr.hx :as hx] [auto-ap.ssr.hx :as hx]
@@ -69,7 +68,6 @@
(dropdown-search-results* {:options (get-clients identity (get (:query-params request) "search-text"))}))) (dropdown-search-results* {:options (get-clients identity (get (:query-params request) "search-text"))})))
(defn dropdown [{:keys [client-selection client identity clients]}] (defn dropdown [{:keys [client-selection client identity clients]}]
(alog/peek ::clients clients)
[:div#company-dropdown [:div#company-dropdown
[:script [:script
(hiccup/raw (hiccup/raw

View File

@@ -4,8 +4,7 @@
[auto-ap.ssr.svg :as svg])) [auto-ap.ssr.svg :as svg]))
(defn link-dropdown [links] (defn link-dropdown [links]
(if (> (count links) 0) (when (> (count links) 0)
[:div {:x-data (hx/json {:popper nil [:div {:x-data (hx/json {:popper nil
:show false}) :show false})
"@click.outside" "show=false" "@click.outside" "show=false"
@@ -17,7 +16,7 @@
(com/badge {:color "blue"} (count links))) (com/badge {:color "blue"} (count links)))
[:div.divide-y.divide-gray-200.bg-white.rounded-lg.shadow.z-50 (hx/alpine-appear {:x-ref "tooltip" :x-show "show" :data-key "show"}) [:div.divide-y.divide-gray-200.bg-white.rounded-lg.shadow.z-50 (hx/alpine-appear {:x-ref "tooltip" :x-show "show" :data-key "show"})
[:div {:class "p-3 overflow-y-auto text-sm text-gray-700 dark:text-gray-200"} [:div {:class "p-3 overflow-y-auto text-sm text-gray-700 dark:text-gray-200"}
[:div.flex.flex-col.gap-y-2 [:div.flex.flex-col.gap-y-2 {:class "max-w-[24em]"}
(for [l links] (for [l links]
[:div.flex-initial [:div.flex-initial
[:a {:href (:link l) :target "_blank"} [:a {:href (:link l) :target "_blank"}

View File

@@ -1,54 +1,44 @@
(ns auto-ap.ssr.ledger (ns auto-ap.ssr.ledger
(:require [auto-ap.datomic (:require [auto-ap.client-routes :as client-routes]
[auto-ap.datomic
:refer [add-sorter-fields apply-pagination apply-sort-3 :refer [add-sorter-fields apply-pagination apply-sort-3
audit-transact conn merge-query observable-query audit-transact conn merge-query observable-query
pull-many]] pull-many]]
[auto-ap.datomic.accounts :as d-accounts] [auto-ap.datomic.accounts :as d-accounts]
[auto-ap.datomic.bank-accounts :as d-bank-accounts] [auto-ap.graphql.checks :as gq-checks]
[auto-ap.datomic.invoices :as d-invoices]
[auto-ap.graphql.checks :as gq-checks :refer [base-payment
invoice-payments
print-checks-internal
validate-belonging]]
[auto-ap.graphql.utils :refer [assert-can-see-client [auto-ap.graphql.utils :refer [assert-can-see-client
assert-not-locked exception->4xx assert-not-locked
exception->notification exception->notification
extract-client-ids notify-if-locked]] extract-client-ids notify-if-locked]]
[auto-ap.logging :as alog] [auto-ap.logging :as alog]
[auto-ap.permissions :refer [can?]] [auto-ap.permissions :refer [can?]]
[auto-ap.query-params :refer [wrap-copy-qp-pqp]] [auto-ap.query-params :refer [wrap-copy-qp-pqp]]
[auto-ap.routes.invoice :as invoice-route]
[auto-ap.routes.ledger :as route] [auto-ap.routes.ledger :as route]
[auto-ap.routes.payments :as payment-route]
[auto-ap.routes.utils [auto-ap.routes.utils
:refer [wrap-client-redirect-unauthenticated]] :refer [wrap-client-redirect-unauthenticated]]
[auto-ap.solr :as solr]
[auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr-routes :as ssr-routes]
[auto-ap.ssr.components :as com] [auto-ap.ssr.components :as com]
[auto-ap.ssr.components.multi-modal :as mm] [auto-ap.ssr.components.link-dropdown :refer [link-dropdown]]
[auto-ap.ssr.form-cursor :as fc]
[auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]]
[auto-ap.ssr.hiccup-helper :as hh]
[auto-ap.ssr.hx :as hx] [auto-ap.ssr.hx :as hx]
[auto-ap.ssr.pos.common :refer [date-range-field*]] [auto-ap.ssr.pos.common :refer [date-range-field*]]
[auto-ap.ssr.svg :as svg] [auto-ap.ssr.svg :as svg]
[auto-ap.ssr.utils [auto-ap.ssr.utils
:refer [apply-middleware-to-all-handlers assert-schema :refer [apply-middleware-to-all-handlers clj-date-schema
clj-date-schema dissoc-nil-transformer entity-id dissoc-nil-transformer entity-id html-response
html-response main-transformer modal-response money main-transformer modal-response ref->enum-schema strip
ref->enum-schema round-money strip
wrap-implied-route-param wrap-merge-prior-hx wrap-implied-route-param wrap-merge-prior-hx
wrap-schema-enforce]] wrap-schema-enforce]]
[auto-ap.time :as atime] [auto-ap.time :as atime]
[auto-ap.utils :refer [by dollars-0?]] [auto-ap.utils :refer [dollars-0?]]
[bidi.bidi :as bidi] [bidi.bidi :as bidi]
[clj-time.coerce :as coerce] [clj-time.coerce :as coerce]
[clj-time.core :as time]
[clojure.string :as str] [clojure.string :as str]
[datomic.api :as dc] [datomic.api :as dc]
[hiccup.util :as hu] [hiccup.util :as hu]
[malli.core :as mc] [malli.core :as mc]
[malli.transform :as mt] [malli.transform :as mt]))
[malli.util :as mut]))
@@ -66,6 +56,30 @@
svg/x)]])] svg/x)]])]
[:div {:id "exact-match-id-tag"}])) [:div {:id "exact-match-id-tag"}]))
(defn bank-account-filter* [request]
[:div {:hx-trigger "clientSelected from:body"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::route/bank-account-filter)
:hx-target "this"
:hx-swap "outerHTML"}
(when (:client request)
(let [bank-account-belongs-to-client? (get (set (map :db/id (:client/bank-accounts (:client request))))
(:db/id (:bank-account (:query-params request))))]
(com/field {:label "Bank Account"}
(com/radio-card {:size :small
:name "bank-account"
:value (or (when bank-account-belongs-to-client?
(:db/id (:bank-account (:query-params request))))
"")
:options
(into [{:value ""
:content "All"}]
(for [ba (:client/bank-accounts (:client request))]
{:value (:db/id ba)
:content (:bank-account/name ba)}))}))))])
(defn bank-account-filter [request]
(html-response (bank-account-filter* request)))
(defn filters [request] (defn filters [request]
[:form#ledger-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" [:form#ledger-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes "hx-get" (bidi/path-for ssr-routes/only-routes
@@ -91,6 +105,9 @@
:value-fn :db/id :value-fn :db/id
:content-fn #(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read (:db/id %)) :content-fn #(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read (:db/id %))
(:db/id (:client request))))})) (:db/id (:client request))))}))
(bank-account-filter* request)
(date-range-field* request) (date-range-field* request)
(com/field {:label "Invoice #"} (com/field {:label "Invoice #"}
(com/text-input {:name "invoice-number" (com/text-input {:name "invoice-number"
@@ -170,7 +187,7 @@
(or (seq (:numeric-code args)) (or (seq (:numeric-code args))
(:account args) (:account args)
(:bank-account-id args) (:db/id (:bank-account args))
(not-empty (:location args))) (not-empty (:location args)))
(merge-query {:query {:where ['[?e :journal-entry/line-items ?li]]}}) (merge-query {:query {:where ['[?e :journal-entry/line-items ?li]]}})
@@ -203,10 +220,10 @@
'[(<= ?a ?amount-lte)]]} '[(<= ?a ?amount-lte)]]}
:args [(:amount-lte args)]}) :args [(:amount-lte args)]})
(:bank-account-id args) (:db/id (:bank-account args))
(merge-query {:query {:in ['?a] (merge-query {:query {:in ['?a]
:where ['[?li :journal-entry-line/account ?a]]} :where ['[?li :journal-entry-line/account ?a]]}
:args [(:bank-account-id args)]}) :args [(:db/id (:bank-account args))]})
(:account-id args) (:account-id args)
(merge-query {:query {:in ['?a2] (merge-query {:query {:in ['?a2]
@@ -238,24 +255,28 @@
(merge-query {:query {:find ['?sort-default '?e]}})))] (merge-query {:query {:find ['?sort-default '?e]}})))]
(->> (observable-query query) (->> (observable-query query)
(apply-sort-3 (assoc query-params :default-asc? false)) (apply-sort-3 (assoc query-params :default-asc? true))
(apply-pagination query-params)))) (apply-pagination query-params))))
(def default-read (def default-read
'[:journal-entry/amount '[:journal-entry/amount
:journal-entry/alternate-description
:db/id :db/id
[:journal-entry/date :xform clj-time.coerce/from-date] [:journal-entry/date :xform clj-time.coerce/from-date]
{ {:journal-entry/vendor [:vendor/name :db/id]
:journal-entry/vendor [:vendor/name :db/id] :journal-entry/original-entity [:invoice/invoice-number
:invoice/source-url
:transaction/description-original :db/id]
:journal-entry/client [:client/name :client/code :db/id] :journal-entry/client [:client/name :client/code :db/id]
:journal-entry/line-items [:journal-entry-line/debit :journal-entry/line-items [:journal-entry-line/debit
:journal-entry-line/location :journal-entry-line/location
:journal-entry-line/credit :journal-entry-line/credit
{:journal-entry-line/account [:account/name :db/id :account/numeric-code {:journal-entry-line/account [:account/name :db/id :account/numeric-code
{[ :account/type :xform iol-ion.query/ident] [:db/ident :db/id]} :bank-account/name :bank-account/numeric-code
{[:account/type :xform iol-ion.query/ident] [:db/ident :db/id]}
{:account/client-overrides [:account-client-override/name {:account/client-overrides [:account-client-override/name
{:account-client-override/client [:db/id]}]} {:account-client-override/client [:db/id]}]}
{[ :bank-account/type :xform iol-ion.query/ident] {[:bank-account/type :xform iol-ion.query/ident]
[:db/ident :db/id]}]}]}]) [:db/ident :db/id]}]}]}])
(defn hydrate-results [ids db _] (defn hydrate-results [ids db _]
@@ -311,6 +332,7 @@
[:amount-gte {:optional true} [:maybe :double]] [:amount-gte {:optional true} [:maybe :double]]
[:amount-lte {:optional true} [:maybe :double]] [:amount-lte {:optional true} [:maybe :double]]
[:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]] [:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]]
[:bank-account {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :bank-account/name]}]]]
[:account {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :account/name]}]]] [:account {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :account/name]}]]]
[:check-number {:optional true} [:maybe [:string {:decode/string strip}]]] [:check-number {:optional true} [:maybe [:string {:decode/string strip}]]]
[:invoice-number {:optional true} [:maybe [:string {:decode/string strip}]]] [:invoice-number {:optional true} [:maybe [:string {:decode/string strip}]]]
@@ -353,13 +375,14 @@
(for [jel lines (for [jel lines
:let [account (d-accounts/clientize (:journal-entry-line/account jel) (:db/id client)) :let [account (d-accounts/clientize (:journal-entry-line/account jel) (:db/id client))
account-name (:account/name account)]] account-name (or (:account/name account)
(:bank-account/name (:journal-entry-line/account jel)))]]
(list (list
(if account-name (if account-name
[:div.text-left [:div.text-left
(:journal-entry-line/location jel) ": " (:journal-entry-line/location jel) ": "
(:account/numeric-code account) (or (:account/numeric-code account) (:bank-account/numeric-code account))
" - " account-name] " - " account-name]
[:div.text-left (com/pill {:color :yellow} "Unassigned")]) [:div.text-left (com/pill {:color :yellow} "Unassigned")])
[:div.text-right (format "$%,.2f" (key jel))])) [:div.text-right (format "$%,.2f" (key jel))]))
@@ -439,7 +462,8 @@
{:key "vendor" {:key "vendor"
:name "Vendor" :name "Vendor"
:sort-key "vendor" :sort-key "vendor"
:render #(-> % :journal-entry/vendor :vendor/name)} :render (fn [e] (or (-> e :journal-entry/vendor :vendor/name)
[:span.italic.text-gray-400 (-> e :journal-entry/alternate-description)]))}
{:key "date" {:key "date"
:sort-key "date" :sort-key "date"
:name "Date" :name "Date"
@@ -457,37 +481,32 @@
:sort-key "credit" :sort-key "credit"
:class "text-right" :class "text-right"
:render (partial render-lines :journal-entry-line/credit)} :render (partial render-lines :journal-entry-line/credit)}
#_{:key "links" {:key "links"
:name "Links" :name "Links"
:show-starting "lg" :show-starting "lg"
:class "w-8" :class "w-8"
:render (fn [i] :render (fn [i]
(link-dropdown (link-dropdown
(concat (->> i (cond-> []
:invoice/payments (-> i :journal-entry/original-entity :invoice/invoice-number)
(map :invoice-payment/payment) (conj
(filter (fn [p] {:link (hu/url (bidi/path-for ssr-routes/only-routes
(not= :payment-status/voided ::invoice-route/all-page)
(:payment/status p)))) {:exact-match-id (:db/id (:journal-entry/original-entity i))})
(mapcat (fn [p] :color :primary
(cond-> [{:link (hu/url (bidi/path-for ssr-routes/only-routes :content (format "Invoice '%s'" (-> i :journal-entry/original-entity :invoice/invoice-number))})
::payment-route/all-page) (-> i :journal-entry/original-entity :invoice/source-url)
{:exact-match-id (:db/id p)}) {:link (-> i :journal-entry/original-entity :invoice/source-url)
:content (str (format "$%,.2f" (:payment/amount p))
(some-> (:payment/date p) coerce/to-date-time (atime/unparse-local atime/normal-date) (#(str " payment on " %))))}]
(:payment/transaction p) (conj {:link (hu/url (bidi/path-for client-routes/routes :transactions)
{:exact-match-id (:db/id (first (:payment/transaction p)))})
:color :secondary :color :secondary
:content "Transaction"}))))) :content (str "File")}
(when (:invoice/journal-entry i)
[{:link (hu/url (bidi/path-for client-routes/routes :ledger) (-> i :journal-entry/original-entity :transaction/description-original)
{:exact-match-id (:db/id (first (:invoice/journal-entry i)))}) (conj
:color :yellow {:link (hu/url (bidi/path-for client-routes/routes
:content "Ledger entry"}]) :transactions)
(when (:invoice/source-url i) {:exact-match-id (:db/id (:journal-entry/original-entity i))})
[{:link (:invoice/source-url i) :color :primary
:color :secondary :content (format "Transaction '%s'" (-> i :journal-entry/original-entity :transaction/description-original))}))))}]}))
:content "File"}]))))}]}))
(def row* (partial helper/row* grid-page)) (def row* (partial helper/row* grid-page))
@@ -649,8 +668,15 @@
(defn wrap-ensure-bank-account-belongs [handler]
(fn [{:keys [query-params client] :as request}]
(let [bank-account-belongs? (get (set (map :db/id (:client/bank-accounts client)))
(:db/id (:bank-account query-params)))]
(handler (cond-> request
(not client)
(update :query-params dissoc :bank-account)
(not bank-account-belongs?)
(update :query-params dissoc :bank-account))))))
(defn wrap-status-from-source [handler] (defn wrap-status-from-source [handler]
(fn [{:keys [matched-current-page-route] :as request}] (fn [{:keys [matched-current-page-route] :as request}]
@@ -662,21 +688,19 @@
(handler request)))) (handler request))))
(def key->handler (def key->handler
(apply-middleware-to-all-handlers (apply-middleware-to-all-handlers
(-> (->
{::route/all-page (-> (helper/page-route grid-page :parse-query-params? false) {::route/all-page (-> (helper/page-route grid-page :parse-query-params? false)
(wrap-implied-route-param :status nil)) (wrap-implied-route-param :status nil))
::route/table (helper/table-route grid-page :parse-query-params? false)}) ::route/table (helper/table-route grid-page :parse-query-params? false)
::route/bank-account-filter bank-account-filter})
(fn [h] (fn [h]
(-> h (-> h
(wrap-copy-qp-pqp) (wrap-copy-qp-pqp)
(wrap-status-from-source) (wrap-status-from-source)
(wrap-apply-sort grid-page) (wrap-apply-sort grid-page)
(wrap-ensure-bank-account-belongs)
(wrap-merge-prior-hx) (wrap-merge-prior-hx)
(wrap-schema-enforce :query-schema query-schema) (wrap-schema-enforce :query-schema query-schema)
(wrap-schema-enforce :hx-schema query-schema) (wrap-schema-enforce :hx-schema query-schema)

View File

@@ -1,4 +1,5 @@
(ns auto-ap.routes.ledger) (ns auto-ap.routes.ledger)
(def routes {"" {:get ::all-page} (def routes {"" {:get ::all-page}
"/table" ::table }) "/table" ::table
"/bank-account-filter" ::bank-account-filter})