consolidate sales summary ledger entry creation into upsert-sales-summary tx

Move journal entry calculation and creation from the reconcile-ledger
background job into the upsert-sales-summary tx function. Now any save
of a sales summary (job recalculation, admin edit wizard, or manual
touch) automatically creates the journal entry if balanced with all
accounts mapped, or retracts it if conditions no longer hold. Eliminates
the need for a separate upsert-sales-summary-ledger call and the
reconcile ledger pass for sales summaries.
This commit is contained in:
2026-05-01 14:05:23 -07:00
parent 2bcebc4424
commit af66049f39
5 changed files with 34 additions and 86 deletions

View File

@@ -50,7 +50,7 @@
(datomic-fn :upsert-invoice #'iol-ion.tx.upsert-invoice/upsert-invoice) (datomic-fn :upsert-invoice #'iol-ion.tx.upsert-invoice/upsert-invoice)
(datomic-fn :upsert-ledger #'iol-ion.tx.upsert-ledger/upsert-ledger) (datomic-fn :upsert-ledger #'iol-ion.tx.upsert-ledger/upsert-ledger)
(datomic-fn :upsert-transaction #'iol-ion.tx.upsert-transaction/upsert-transaction) (datomic-fn :upsert-transaction #'iol-ion.tx.upsert-transaction/upsert-transaction)
(datomic-fn :upsert-sales-summary-ledger #'iol-ion.tx.upsert-sales-summary-ledger/upsert-sales-summary-ledger)]))) (datomic-fn :upsert-sales-summary #'iol-ion.tx.upsert-sales-summary-ledger/upsert-sales-summary)])))
(comment (comment
(regenerate-literals) (regenerate-literals)

View File

@@ -1,28 +1,7 @@
(ns iol-ion.tx.upsert-sales-summary-ledger (ns iol-ion.tx.upsert-sales-summary-ledger
(:import [java.util UUID Date]) (:require [datomic.api :as dc]
(:require [datomic.api :as dc])) [iol-ion.tx.upsert-entity :as upsert-entity]
[iol-ion.tx.upsert-ledger :as upsert-ledger]))
(defn -random-tempid []
(dc/tempid :db.part/user))
(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 current-date [db]
(let [last-tx (dc/t->tx (dc/basis-t db))
[[date]] (seq (dc/q '[:find ?ti :in $ ?tx
:where [?tx :db/txInstant ?ti]]
db
last-tx))]
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 summary->journal-entry [db summary-id] (defn summary->journal-entry [db summary-id]
(let [summary (dc/pull db '[:sales-summary/client (let [summary (dc/pull db '[:sales-summary/client
@@ -42,37 +21,40 @@
(update m (:ledger-mapped/ledger-side item) (fnil + 0.0) (:ledger-mapped/amount item 0.0))) (update m (:ledger-mapped/ledger-side item) (fnil + 0.0) (:ledger-mapped/amount item 0.0)))
{:account account} {:account account}
acc-items)))) acc-items))))
line-items (mapv (fn [{:keys [account] :as m}] line-items (mapv (fn [{:keys [account] :as m}]
(cond-> {:db/id (str (java.util.UUID/randomUUID)) (cond-> {:db/id (str (java.util.UUID/randomUUID))
:journal-entry-line/account account} :journal-entry-line/account account
:journal-entry-line/location "A"}
(get m :ledger-side/debit) (assoc :journal-entry-line/debit (get m :ledger-side/debit)) (get m :ledger-side/debit) (assoc :journal-entry-line/debit (get m :ledger-side/debit))
(get m :ledger-side/credit) (assoc :journal-entry-line/credit (get m :ledger-side/credit)))) (get m :ledger-side/credit) (assoc :journal-entry-line/credit (get m :ledger-side/credit))))
aggregated) aggregated)
total-amount (reduce + 0.0 (map #(get % :ledger-side/debit 0.0) aggregated))] total-debits (reduce + 0.0 (map #(get % :ledger-side/debit 0.0) aggregated))
(when (seq line-items) total-credits (reduce + 0.0 (map #(get % :ledger-side/credit 0.0) aggregated))]
(when (and (seq line-items)
(= (Math/round (* 1000 total-debits))
(Math/round (* 1000 total-credits))))
{:journal-entry/source "sales-summary" {:journal-entry/source "sales-summary"
:journal-entry/client (:db/id (:sales-summary/client summary)) :journal-entry/client (:db/id (:sales-summary/client summary))
:journal-entry/date (:sales-summary/date summary) :journal-entry/date (:sales-summary/date summary)
:journal-entry/original-entity summary-id :journal-entry/original-entity summary-id
:journal-entry/amount total-amount :journal-entry/amount total-debits
:journal-entry/line-items line-items}))) :journal-entry/line-items line-items})))
(defn upsert-sales-summary-ledger [db summary] (defn upsert-sales-summary [db summary]
(assert (:db/id summary) "Must provide summary id") (let [upserted-summary [[:upsert-entity summary]]
(let [upserted-entity [[:upsert-entity {:db/id (:db/id summary)}]] db-after (-> (dc/with db upserted-summary) :db-after)
with-summary (dc/with db upserted-entity) summary-id (:db/id summary)
summary-id (:db/id summary) client-id (-> (dc/pull db-after [{:sales-summary/client [:db/id]}] summary-id)
journal-entry (summary->journal-entry (:db-after with-summary) summary-id)
client-id (-> (dc/pull (:db-after with-summary)
[{:sales-summary/client [:db/id]}]
summary-id)
:sales-summary/client :sales-summary/client
:db/id)] :db/id)
(into upserted-entity journal-entry (summary->journal-entry db-after summary-id)]
(into upserted-summary
(if journal-entry (if journal-entry
[[:upsert-ledger journal-entry] [[:upsert-ledger journal-entry]]
{:db/id client-id (let [existing-je-id (ffirst (dc/q '[:find ?je . :in $ ?ss
:client/ledger-last-change (current-date db)}] :where [?je :journal-entry/original-entity ?ss]]
[[:db/retractEntity [:journal-entry/original-entity summary-id]] db-after summary-id))]
{:db/id client-id (concat
:client/ledger-last-change (current-date db)}])))) (when existing-je-id [[:db/retractEntity existing-je-id]])
(when client-id [{:db/id client-id
:client/ledger-last-change (upsert-ledger/current-date db)}])))))))

View File

@@ -276,40 +276,6 @@
:ledger-mapped/amount amount :ledger-mapped/amount amount
:ledger-mapped/ledger-side :ledger-side/debit})) :ledger-mapped/ledger-side :ledger-side/debit}))
(defn- summary->journal-entry [db summary-id]
(let [summary (dc/pull db '[:sales-summary/client
:sales-summary/date
{:sales-summary/items [:sales-summary-item/category
:ledger-mapped/account
:ledger-mapped/amount
:ledger-mapped/ledger-side]}]
summary-id)
items (:sales-summary/items summary)
;; Aggregate items by account and ledger side
aggregated (->> items
(filter :ledger-mapped/account)
(group-by :ledger-mapped/account)
(map (fn [[account acc-items]]
(reduce
(fn [m item]
(update m (:ledger-mapped/ledger-side item) (fnil + 0.0) (:ledger-mapped/amount item 0.0)))
{:account account}
acc-items))))
line-items (mapv (fn [{:keys [account] :as m}]
(cond-> {:db/id (str (java.util.UUID/randomUUID))
:journal-entry-line/account account}
(get m :ledger-side/debit) (assoc :journal-entry-line/debit (get m :ledger-side/debit))
(get m :ledger-side/credit) (assoc :journal-entry-line/credit (get m :ledger-side/credit))))
aggregated)
total-amount (reduce + 0.0 (map #(get % :ledger-side/debit 0.0) aggregated))]
(when (seq line-items)
{:journal-entry/source "sales-summary"
:journal-entry/client (:db/id (:sales-summary/client summary))
:journal-entry/date (:sales-summary/date summary)
:journal-entry/original-entity summary-id
:journal-entry/amount total-amount
:journal-entry/line-items line-items})))
(defn- calc-aggregate-totals [items] (defn- calc-aggregate-totals [items]
(reduce (reduce
(fn [acc item] (fn [acc item]
@@ -376,7 +342,7 @@
(do (do
(alog/info ::upserting-summaries (alog/info ::upserting-summaries
:category-count (count (:sales-summary/items result))) :category-count (count (:sales-summary/items result)))
@(dc/transact conn [[:upsert-entity result]])) @(dc/transact conn [[:upsert-sales-summary result]]))
@(dc/transact conn [{:db/id id :sales-summary/dirty false}])))))) @(dc/transact conn [{:db/id id :sales-summary/dirty false}]))))))

View File

@@ -61,7 +61,7 @@
(dc/db conn) start-date) (dc/db conn) start-date)
(map first) (map first)
(mapv (fn [ss] (mapv (fn [ss]
[:upsert-sales-summary-ledger {:db/id ss}]))) [:upsert-sales-summary {:db/id ss}])))
repairs (vec (concat txes-missing-ledger-entries invoices-missing-ledger-entries sales-summaries-missing-ledger-entries))] repairs (vec (concat txes-missing-ledger-entries invoices-missing-ledger-entries sales-summaries-missing-ledger-entries))]
(when (seq repairs) (when (seq repairs)

View File

@@ -483,7 +483,7 @@
edit-schema) edit-schema)
(submit [this {:keys [multi-form-state request-method identity] :as request}] (submit [this {:keys [multi-form-state request-method identity] :as request}]
(let [result (:snapshot multi-form-state ) (let [result (:snapshot multi-form-state )
transaction [:upsert-entity {:db/id (:db/id result) transaction [:upsert-sales-summary {:db/id (:db/id result)
:sales-summary/items (map :sales-summary/items (map
(fn [i] (fn [i]
(if (:sales-summary-item/manual? i) (if (:sales-summary-item/manual? i)