started work on bank comparisons.

This commit is contained in:
2024-04-26 21:51:56 -07:00
parent 227acba4e2
commit c8f438f616
10 changed files with 147 additions and 20 deletions

File diff suppressed because one or more lines are too long

View File

@@ -215,6 +215,11 @@
:db/cardinality #:db{:ident :db.cardinality/one},
:db/doc "A precomputed balance for the account",
:db/ident :bank-account/current-balance}
{:db/valueType #:db{:ident :db.type/instant},
:db/noHistory true,
:db/cardinality #:db{:ident :db.cardinality/one},
:db/doc "A precomputed balance for the account",
:db/ident :bank-account/current-balance-synced}
{:db/valueType #:db{:ident :db.type/long},
:db/cardinality #:db{:ident :db.cardinality/one},
:db/doc "The numeric code for the balance sheet",
@@ -1619,6 +1624,11 @@
:db/cardinality #:db{:ident :db.cardinality/one},
:db/doc "Yodlee account id",
:db/ident :yodlee-account/id}
{:db/valueType #:db{:ident :db.type/instant},
:db/noHistory true,
:db/cardinality #:db{:ident :db.cardinality/one},
:db/doc "A precomputed balance for the account",
:db/ident :yodlee-account/last-synced}
{:db/valueType #:db{:ident :db.type/string},
:db/cardinality #:db{:ident :db.cardinality/one},
:db/doc "account name",

View File

@@ -4,6 +4,8 @@
[auto-ap.graphql.utils
:refer [->graphql <-graphql assert-admin attach-tracing-resolvers
can-see-client? is-admin? result->page]]
[clj-time.coerce :as c]
[clj-time.core :as time]
[clojure.set :as set]
[com.brunobonacci.mulog :as mu]
[datomic.api :as dc]))
@@ -13,24 +15,27 @@
(let [db (dc/db conn)
clients (dc/q '[:find (pull ?c [:db/id :client/code {:client/bank-accounts [:db/id :bank-account/code]}])
:where [?c :client/code]]
db )]
(doseq [[{client :db/id code :client/code bank-accounts :client/bank-accounts}] clients
{bank-account :db/id bac :bank-account/code} bank-accounts]
db)]
(doseq [[{client :db/id code :client/code bank-accounts :client/bank-accounts}] clients
{bank-account :db/id bac :bank-account/code} bank-accounts]
@(dc/transact conn [{:db/id bank-account
:bank-account/current-balance
(or
(->> (dc/index-pull db
{:index :avet
:selector [:db/id :journal-entry-line/location :journal-entry-line/account :journal-entry-line/running-balance :journal-entry-line/client+account+location+date {:journal-entry/_line-items [:journal-entry/date :journal-entry/client]}]
:start [:journal-entry-line/client+account+location+date [client bank-account "A" #inst "2030-01-01"]]
:reverse true
})
(filter (fn [{[c b] :journal-entry-line/client+account+location+date}]
(and (= c client)
(= b bank-account))))
(map :journal-entry-line/running-balance)
(first))
0.0)}])))))
:bank-account/current-balance-synced (c/to-date (time/now))
:bank-account/current-balance
(or
(->> (dc/index-pull db
{:index :avet
:selector [:db/id :journal-entry-line/location :journal-entry-line/account :journal-entry-line/running-balance :journal-entry-line/client+account+location+date {:journal-entry/_line-items [:journal-entry/date :journal-entry/client]}]
:start [:journal-entry-line/client+account+location+date [client bank-account "A" #inst "2030-01-01"]]
:reverse true})
(take 3)
(filter (fn [{[c b] :journal-entry-line/client+account+location+date}]
(and (= c client)
(= b bank-account))))
(map :journal-entry-line/running-balance)
(first))
0.0)}])))))
(defn get-client [context _ _]
(->graphql

View File

@@ -96,4 +96,3 @@
:intuit-bank-account/last-synced (coerce/to-date (:last-updated ba))
:intuit-bank-account/current-balance (:current-balance ba)}))
bank-accounts))))

View File

@@ -35,5 +35,39 @@
(require 'auto-ap.time_reader)
(let [start #clj-time/date-time "2024-02-01"
end #clj-time/date-time "2024-04-01"]
(for [[ib ba c] (seq (get-intuit-bank-accounts (dc/db conn) "BCFM"))
:let [raw-transactions (i/get-transactions (atime/unparse-local start atime/iso-date)
(atime/unparse-local end atime/iso-date)
ib)
ideal-transactions (intuits->transactions raw-transactions ba c)
found-transactions (when (seq ideal-transactions)
(into {} (dc/q '[:find ?si (count ?t)
:in $ [?eid ...]
:where
[?t :transaction/id ?eid]
[?t :transaction/approval-status ?s]
[?s :db/ident ?si]]
(dc/db conn)
(map :transaction/id ideal-transactions))))
missing-transaction-ids (when (seq ideal-transactions)
(->>
(dc/q '[:find ?eid
:in $ [?eid ...]
:where (not [_ :transaction/id ?eid])]
(dc/db conn)
(map :transaction/id ideal-transactions))
(map first)
(into #{})))
missing-transactions (filter (comp missing-transaction-ids :transaction/id) ideal-transactions)]]
{:bank-account/name (pull-attr (dc/db conn) :bank-account/name ba)
:external-transaction-count (count raw-transactions)
:integreat-transaction-count (reduce + 0 (vals found-transactions))
:approved-count (:transaction-approval-status/approved found-transactions 0)
:unapproved-count (:transaction-approval-status/unapproved found-transactions 0)
:requires-feedback-count (:transaction-approval-status/requires-feedback found-transactions 0)
:missing-transactions missing-transactions}))

View File

@@ -575,7 +575,6 @@
(refresh-running-balance-accounts accounts-needing-rebuild clients c i db)
(mu/log ::client-completed))))))))
;; TODO only enable once IOL is set up in clod
#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
(mount/defstate running-balance-cache-worker

View File

@@ -15,6 +15,7 @@
[auto-ap.ssr.admin.transaction-rules :as admin-rules]
[auto-ap.ssr.admin.vendors :as admin-vendors]
[auto-ap.ssr.auth :as auth]
[auto-ap.ssr.dashboard :as dashboard]
[auto-ap.ssr.company :as company]
[auto-ap.ssr.company-dropdown :as company-dropdown]
[auto-ap.ssr.company.company-1099 :as company-1099]
@@ -98,6 +99,7 @@
(into admin-vendors/key->handler)
(into admin-clients/key->handler)
(into admin-rules/key->handler)
(into dashboard/key->handler)
(into indicators/key->handler)
(into payments/key->handler)
(into oin/route->handler)))

View File

@@ -0,0 +1,73 @@
(ns auto-ap.ssr.dashboard
(:require [auto-ap.datomic :refer [conn]]
[auto-ap.routes.dashboard :as d-routes]
[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.ui :refer [base-page]]
[auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers]]
[bidi.bidi :as bidi]
[datomic.api :as dc]
[auto-ap.time :as atime]))
(defn- page-contents [request]
[:div
[:h1.text-2xl.font-bold "Bank Accounts"]
(com/card {:class "inline-block"}
[:div.inline-flex.flex-wrap
(for [c (:clients request)
b (:client/bank-accounts (dc/pull (dc/db conn) '[{ :client/bank-accounts
[:bank-account/current-balance
[ :bank-account/current-balance-synced :xform clj-time.coerce/from-date]
:bank-account/name
{:bank-account/intuit-bank-account [:intuit-bank-account/current-balance
[ :intuit-bank-account/last-synced :xform clj-time.coerce/from-date]]}
{:bank-account/yodlee-account [:yodlee-account/available-balance
[:yodlee-account/last-synced :xform clj-time.coerce/from-date]]}]}]
(:db/id c)))]
[:div.flex.flex-col.p-4.border-l-2
[:div (:client/name c)]
[:div (:bank-account/name b)]
[:div.inline-flex.justify-between [:div "Ledger Balance"] (format "$%,.2f" (or (:bank-account/current-balance b) 0.0)) ]
[:div.inline-flex.justify-end.text-xs.text-gray-400.it (some-> (:bank-account/current-balance-synced b)
(atime/unparse-local atime/standard-time)
(#(str "Synced " %))) ]
[:div.inline-flex.justify-between [:div "Source Balance"] (format "$%,.2f" (or (-> b :bank-account/intuit-bank-account :intuit-bank-account/current-balance)
(-> b :bank-account/yodlee-account :yodlee-account/available-balance)
0.0))]
[:div.inline-flex.justify-end.text-xs.text-gray-400.it (or (some-> (:bank-account/intuit-bank-account b)
(:intuit-bank-account/last-synced)
(atime/unparse-local atime/standard-time)
(#(str "Synced " %)))
(some-> (:bank-account/yodlee-account b)
(:yodlee-account/last-synced)
(atime/unparse-local atime/standard-time)
(#(str "Synced " %))))]])]) ])
(defn page [request]
(base-page
request
(com/page {:nav com/main-aside-nav
:client-selection (:client-selection request)
:clients (:clients request)
:client (:client request)
:identity (:identity request)
:app-params {:hx-get (bidi/path-for ssr-routes/only-routes
::d-routes/page)
:hx-trigger "clientSelected from:body"
:hx-select "#app-contents"
:hx-swap "outerHTML swap:300ms"}
:request request}
(com/breadcrumbs {}
[:a {:href (bidi/path-for ssr-routes/only-routes ::d-routes/page)}
"Dashboard"])
(page-contents request))
"Dashboard"))
(def key->handler
( apply-middleware-to-all-handlers
{::d-routes/page page}
(fn [h]
(wrap-client-redirect-unauthenticated (wrap-admin h)))))

View File

@@ -0,0 +1,3 @@
(ns auto-ap.routes.dashboard)
(def routes {""
{:get ::page }})

View File

@@ -6,6 +6,7 @@
[auto-ap.routes.admin.vendors :as v-routes]
[auto-ap.routes.outgoing-invoice :as oi-routes]
[auto-ap.routes.payments :as p-routes]
[auto-ap.routes.dashboard :as d-routes]
[auto-ap.routes.invoice :as i-routes]
[auto-ap.routes.admin.clients :as ac-routes]
[auto-ap.routes.admin.sales-summaries :as ss-routes]
@@ -16,6 +17,7 @@
"search" :search
"indicators" indicator-routes/routes
"dashboard" {:get ::d-routes/page}
"account" {"/search" {:get :account-search}}
"admin" {"" :auto-ap.routes.admin/page
"/client" ac-routes/routes