(cloud) makes ledger running balances fast and smooth
This commit is contained in:
@@ -60,11 +60,13 @@
|
||||
|
||||
;; TODO unit test this
|
||||
(defn upsert-entity [db entity]
|
||||
(assert (:db/id entity) "Cannot upsert without :db/id")
|
||||
(let [e (:db/id entity)
|
||||
(assert (or (:db/id entity)
|
||||
(:db/ident entity))
|
||||
(str "Cannot upsert without :db/id or :db/ident, " entity))
|
||||
(let [e (or (:db/id entity) (:db/ident entity))
|
||||
is-new? (string? e)
|
||||
extant-entity (when-not is-new?
|
||||
(dc/pull db (keys entity) (:db/id entity)))
|
||||
(dc/pull db (keys entity) (or (:db/id entity) (:db/ident entity))))
|
||||
ident->value-type (by :db/ident (comp :db/ident
|
||||
:db/valueType)
|
||||
(pull-many
|
||||
@@ -78,6 +80,9 @@
|
||||
(= :db/id a)
|
||||
ops
|
||||
|
||||
(= :db/ident a)
|
||||
ops
|
||||
|
||||
(or (= v (a extant-entity))
|
||||
(= v (:db/ident (a extant-entity) :nope))
|
||||
(= v (:db/id (a extant-entity)) :nope))
|
||||
@@ -92,6 +97,10 @@
|
||||
ops
|
||||
|
||||
;; reset relationships if it's refs, and not a lookup (i.e., seq of maps, or empty seq)
|
||||
|
||||
(and (sequential? v) (= :db.type/tuple (ident->value-type a)))
|
||||
(conj ops [:db/add e a v])
|
||||
|
||||
(and (sequential? v) (= :db.type/ref (ident->value-type a)) (every? map? v))
|
||||
(into ops (reset-rels db e a v))
|
||||
|
||||
@@ -111,3 +120,101 @@
|
||||
[]))]
|
||||
ops))
|
||||
|
||||
(defn min-by [sorter]
|
||||
(->> sorter
|
||||
sort
|
||||
last
|
||||
last))
|
||||
|
||||
(defn get-line-items-after [db journal-entry]
|
||||
(for [jel (:journal-entry/line-items journal-entry)
|
||||
:let [next-jel (->> (dc/index-pull db {:index :avet
|
||||
:selector [:db/id :journal-entry-line/client+account+location+date]
|
||||
:start [:journal-entry-line/client+account+location+date
|
||||
(:journal-entry-line/client+account+location+date jel)
|
||||
(:db/id jel)]
|
||||
:limit 3
|
||||
})
|
||||
(filter (fn line-must-match-client-account-location [result]
|
||||
(and
|
||||
(= (take 3 (:journal-entry-line/client+account+location+date result))
|
||||
(take 3 (:journal-entry-line/client+account+location+date jel)))
|
||||
(not= (:db/id jel)
|
||||
(:db/id result)))
|
||||
))
|
||||
first
|
||||
:db/id)]
|
||||
:when next-jel]
|
||||
next-jel))
|
||||
|
||||
(def extant-read '[:db/id :journal-entry/date :journal-entry/client {:journal-entry/line-items [:journal-entry-line/account :journal-entry-line/location :db/id :journal-entry-line/client+account+location+date]}])
|
||||
|
||||
|
||||
(defn calc-client+account+location+date [je jel]
|
||||
[(or
|
||||
(:db/id (:journal-entry/client je))
|
||||
(:journal-entry/client je))
|
||||
(or (:db/id (:journal-entry-line/account jel))
|
||||
(:journal-entry-line/account jel))
|
||||
(-> jel :journal-entry-line/location)
|
||||
(-> je :journal-entry/date)])
|
||||
|
||||
(defn upsert-ledger [db ledger-entry]
|
||||
(assert (:journal-entry/date ledger-entry) "Must at least provide date when updating ledger")
|
||||
(assert (:journal-entry/client ledger-entry) "Must at least provide client when updating ledger")
|
||||
(assert (every? :journal-entry-line/account (:journal-entry/line-items ledger-entry)) "must at least provide account when updating ledger")
|
||||
(assert (every? :journal-entry-line/location (:journal-entry/line-items ledger-entry)) "Must at least provide location when updating ledger")
|
||||
(let [
|
||||
extant-entry (or (when-let [original-entity (:journal-entry/original-entity ledger-entry)]
|
||||
(dc/pull db extant-read [:journal-entry/original-entity original-entity]))
|
||||
(when-let [external-id (:journal-entry/external-id ledger-entry)]
|
||||
(dc/pull db extant-read [:journal-entry/external-id external-id])))
|
||||
extant-entry-exists? (:db/id extant-entry)]
|
||||
|
||||
(cond->
|
||||
(upsert-entity db (into (-> ledger-entry
|
||||
(assoc :db/id (or
|
||||
(:db/id ledger-entry)
|
||||
(:db/id extant-entry)
|
||||
(random-tempid)))
|
||||
(update :journal-entry/line-items
|
||||
(fn [lis]
|
||||
(mapv #(-> %
|
||||
(assoc :journal-entry-line/dirty true)
|
||||
(assoc :journal-entry-line/client+account+location+date
|
||||
(calc-client+account+location+date ledger-entry %)))
|
||||
lis))))
|
||||
))
|
||||
extant-entry-exists? (into (map (fn [li]
|
||||
{:journal-entry-line/dirty true
|
||||
:db/id li})
|
||||
(get-line-items-after db extant-entry))))))
|
||||
|
||||
(defn remove-nils [m]
|
||||
(let [result (reduce-kv
|
||||
(fn [m k v]
|
||||
(if (not (nil? v))
|
||||
(assoc m k v)
|
||||
m
|
||||
))
|
||||
{}
|
||||
m)]
|
||||
(if (seq result)
|
||||
result
|
||||
nil)))
|
||||
|
||||
(defn propose-invoice [db invoice]
|
||||
(let [existing? (boolean (seq (dc/q '[:find ?i
|
||||
:in $ ?invoice-number ?client ?vendor
|
||||
:where
|
||||
[?i :invoice/invoice-number ?invoice-number]
|
||||
[?i :invoice/client ?client]
|
||||
[?i :invoice/vendor ?vendor]
|
||||
(not [?i :invoice/status :invoice-status/voided])]
|
||||
db
|
||||
(:invoice/invoice-number invoice)
|
||||
(:invoice/client invoice)
|
||||
(:invoice/vendor invoice))))]
|
||||
(if existing?
|
||||
[]
|
||||
[(remove-nils invoice)])))
|
||||
|
||||
Reference in New Issue
Block a user