Implementing running balance, fixing it so A accounts won't show up unless miscoded

This commit is contained in:
Bryce Covert
2020-09-29 13:12:45 -07:00
parent bf17e9582f
commit b4755840ae
6 changed files with 151 additions and 10 deletions

View File

@@ -3990,3 +3990,32 @@ o
[:db/retract 17592232578099 :transaction/location "A"]
[:db/retract 17592232578099 :transaction/vendor 17592232789952]
[:db/retractEntity 17592233413525]])
(def z
(with-open [output-stream (java.io.ByteArrayOutputStream.)
writer (io/writer output-stream)]
(csv/write-csv writer (->> (d/query {:query {:find ['(pull ?e [:journal-entry/amount
:journal-entry/date
:journal-entry/external-id
{:journal-entry/client [:client/code]
:journal-entry/line-items [:journal-entry-line/debit
:journal-entry-line/credit
{:journal-entry-line/account [:account/name]}]}])]
:in ['$]
:where ['[?e :journal-entry/line-items ?jel]
'[?e :journal-entry/amount ?jamt]
'[(get-else $ ?jel :journal-entry-line/debit 0.0) ?debit]
'[(get-else $ ?jel :journal-entry-line/credit 0.0) ?credit]
'[(= ?jamt 0.0)]]}
:args [(d/db auto-ap.datomic/conn)]})
(map first)
(map (fn [x]
[(:journal-entry/external-id x)
(:journal-entry/amount x)
(:journal-entry/date x)
(:client/code (:journal-entry/client x))
(str/join ", " (map (comp :account/name :journal-entry-line/account) (:journal-entry/line-items x)))]))))
(.flush output-stream)
(.toString output-stream)
))

View File

@@ -183,7 +183,8 @@
:account {:type :account}
:location {:type 'String}
:debit {:type 'String}
:credit {:type 'String}}}
:credit {:type 'String}
:running_balance {:type :money}}}
:journal_entry
{:fields {:id {:type :id}
:source {:type 'String}

View File

@@ -1,5 +1,5 @@
(ns auto-ap.graphql.ledger
(:require [auto-ap.datomic :refer [audit-transact-batch remove-nils uri]]
(:require [auto-ap.datomic :refer [audit-transact-batch remove-nils uri conn]]
[auto-ap.datomic.accounts :as a]
[auto-ap.datomic.clients :as d-clients]
[auto-ap.datomic.ledger :as l]
@@ -14,11 +14,31 @@
[clojure.string :as str]
[clojure.tools.logging :as log]
[datomic.api :as d]
[unilog.context :as lc]))
[unilog.context :as lc]
[yang.scheduler :as scheduler]
[mount.core :as mount]))
(mount/defstate running-balance-cache
:start (atom {}))
(defn get-ledger-page [context args value]
(let [args (assoc args :id (:id context))
[journal-entries journal-entries-count] (l/get-graphql (<-graphql args))]
[journal-entries journal-entries-count] (l/get-graphql (<-graphql args))
journal-entries (mapv
(fn [je]
(update je :journal-entry/line-items
(fn [jels]
(mapv
(fn [jel]
(log/info (get-in @running-balance-cache [(:db/id (:journal-entry/client je))
(:db/id jel)]))
(assoc jel :running-balance (get-in @running-balance-cache [(:db/id (:journal-entry/client je))
(:db/id jel)])))
jels)
))
)
journal-entries)]
(result->page journal-entries journal-entries-count :journal_entries args)))
;; TODO a better way to do this might be to accumulate ALL credits and ALL debits, and then just do for credits: balance = credits - debits. and for debits balance = debits - credits
@@ -299,3 +319,79 @@
:errors (map (fn [x] {:external_id (:external_id x)
:error (:error x)}) errors)})))
(defn build-running-balance
([lookup-account all-ledger-entries]
(->> all-ledger-entries
(reduce
(fn [[rollup cache] [_ jel account location debit credit]]
(let [rollup (-> rollup
(update-in [[location account] :debit] (fnil + 0.0) debit)
(update-in [[location account] :credit] (fnil + 0.0) credit)
(update-in [[location account] :count] (fnil + 0) 1))]
[rollup
(assoc cache jel (assoc (get rollup [location account]) :account-id account))]))
[{} {}])
(second)
(reduce-kv
(fn [acc jel {:keys [debit credit count account-id]}]
(let [account (lookup-account account-id)
account-type (:account_type account)]
(assoc acc jel
(if account-type (if (#{:account-type/asset
:account-type/dividend
:account-type/expense} account-type)
(- debit credit)
(- credit debit))
0.0))))
{}))))
(defn running-balance-for [client-id]
(let [lookup-account (build-account-lookup client-id)]
(->> (d/query
{:query {:find ['?d '?jel '?account '?location '?debit '?credit]
:in ['$ '?client-id]
:where '[[?e :journal-entry/client ?client-id]
[?e :journal-entry/date ?d]
[?e :journal-entry/line-items ?jel]
(or-join [?e]
(and [?e :journal-entry/original-entity ?i]
(or-join [?e ?i]
(and
[?i :transaction/bank-account ?b]
(or [?b :bank-account/include-in-reports true]
(not [?b :bank-account/include-in-reports])))
(not [?i :transaction/bank-account])))
(not [?e :journal-entry/original-entity ]))
[(get-else $ ?jel :journal-entry-line/account :account/unknown) ?account]
[(get-else $ ?jel :journal-entry-line/debit 0.0) ?debit ]
[(get-else $ ?jel :journal-entry-line/credit 0.0) ?credit]
[(get-else $ ?jel :journal-entry-line/location "") ?location]]
}
:args [(d/db conn) client-id]})
(sort-by first)
(build-running-balance lookup-account))))
(defn build-running-balance-cache []
(reduce
(fn [acc client]
(log/info "Computing running balance cache for " (:client/code client))
(assoc acc (:db/id client) (running-balance-for (:db/id client))))
{}
(d-clients/get-all)))
(defn refresh-running-balance-cache []
(lc/with-context {:source "running-balance-cache"}
(try
(log/info "Refreshing running balance cache")
(reset! running-balance-cache (build-running-balance-cache))
(catch Exception e
(log/error e)))))
(mount/defstate running-balance-cache-worker
:start (scheduler/every (* 5 60 1000) refresh-running-balance-cache)
:stop (scheduler/stop running-balance-cache-worker))

View File

@@ -54,7 +54,7 @@
[:client
[:name :id]]
[:line-items
[:id :debit :credit :location
[:id :debit :credit :location :running-balance
[:account [:id]]]]
:date]]
:total

View File

@@ -30,6 +30,17 @@
[[from to]
[(t/minus from (t/years 1)) (t/minus to (t/years 1))]])
(defn in-range? [code]
(reduce
(fn [acc [start end]]
(if (<= start code end)
(reduced true)
acc))
false
(vals ranges)))
;; SUBS
(re-frame/reg-sub
::locations
@@ -38,6 +49,7 @@
::report
:periods
(mapcat :accounts)
(filter (comp in-range? :numeric-code))
(group-by :location)
(filter (fn [[k as]]
(not (dollars-0? (reduce + 0 (map :amount as))))))
@@ -242,7 +254,7 @@
[:client
[:name :id]]
[:line-items
[:id :debit :credit :location
[:id :debit :credit :location :running-balance
[:account [:id :name]]]]
:date]]
:total

View File

@@ -22,9 +22,10 @@
[grid/cell {} (date->str date) ]
[grid/cell {} ]
[grid/cell {:class "has-text-right"} (nf amount )]
[grid/cell {:class "has-text-right"} (nf amount )]]
[grid/cell {:class "has-text-right"} (nf amount )]
#_[grid/cell {}]]
[:<>
(for [{:keys [debit credit location account id]} line-items
(for [{:keys [debit credit location account id running-balance]} line-items
:let [account (or (accounts-by-id (:id account))
(bank-accounts-by-id (:id account)))]]
^{:key id}
@@ -37,7 +38,8 @@
(str location ": " (:name account))
[:i "unknown"])]
[grid/cell {:class "has-text-right"} (when debit (nf debit ))]
[grid/cell {:class "has-text-right"} (when credit (nf credit ))]])]])
[grid/cell {:class "has-text-right"} (when credit (nf credit ))]
#_[grid/cell {:class "has-text-right"} (when running-balance (nf running-balance ))]])]])
(defn table [{:keys [id data-page status vendors on-check-changed expense-event]}]
(let [{:keys [data status]} @(re-frame/subscribe [::data-page/page data-page])
@@ -56,7 +58,8 @@
[grid/sortable-header-cell {:sort-key "date" :sort-name "Date" :style {:width "8em"}} "Date"]
[grid/header-cell {} "Account"]
[grid/sortable-header-cell {:sort-key "amount" :sort-name "Amount" :class "has-text-right" :style {:width "7em"}} "Debit"]
[grid/sortable-header-cell {:sort-key "amount" :sort-name "Amount" :class "has-text-right" :style {:width "7em"}} "Credit"]]]
[grid/sortable-header-cell {:sort-key "amount" :sort-name "Amount" :class "has-text-right" :style {:width "7em"}} "Credit"]
#_[grid/header-cell {:class "has-text-right" :style {:width "10em"}} "Running Balance"]]]
[grid/body
(for [{:keys [client vendor status date amount id line-items] :as i} (:data data)]
^{:key id}