balance sheet prep

This commit is contained in:
2024-10-12 19:24:31 -07:00
parent 427f50fb6b
commit 06a23d4d10
4 changed files with 154 additions and 142 deletions

View File

@@ -217,7 +217,7 @@
"@mouseout" "active = -1" "@mouseout" "active = -1"
"@click.prevent" "value.push({value: element.value, label: element.label});" "@click.prevent" "value.push({value: element.value, label: element.label});"
} }
[ :input {:type "checkbox" ":checked" "value.includes(element.value)"} ] [ :input {:type "checkbox" ":checked" "value.map(i=>i.value).includes(element.value)"} ]
[:span {"x-html" "element.label"}]]]] [:span {"x-html" "element.label"}]]]]
[:template {:x-if "elements.length == 0"} [:template {:x-if "elements.length == 0"}
[:li {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500 text-gray-800 dark:text-gray-100 text-xs "} [:li {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500 text-gray-800 dark:text-gray-100 text-xs "}

View File

@@ -252,18 +252,11 @@
request) request)
:headers {"hx-push-url" (str "?" (url/map->query :headers {"hx-push-url" (str "?" (url/map->query
(dissoc (if (:query-schema grid-spec) (dissoc (if (:query-schema grid-spec)
(do (update (filter-vals #(not (nil? %))
(alog/peek ::setup4 (m/encode (:query-schema grid-spec)
(pr-str (update (filter-vals #(not (nil? %)) (:query-params request)
(m/encode (:query-schema grid-spec) main-transformer))
(:query-params request) "sort" sort->query)
main-transformer))
"sort" sort->query)))
(update (filter-vals #(not (nil? %))
(m/encode (:query-schema grid-spec)
(:query-params request)
main-transformer))
"sort" sort->query))
(unparse-query-params (:parsed-query-params request))) (unparse-query-params (:parsed-query-params request)))
"selected" "all-selected")))} ;; TODO seems hacky to special case selected and all-selected here "selected" "all-selected")))} ;; TODO seems hacky to special case selected and all-selected here
:oob (when-let [oob-render (:oob-render grid-spec)] :oob (when-let [oob-render (:oob-render grid-spec)]

View File

@@ -6,7 +6,6 @@
[auto-ap.ledger.reports :as l-reports] [auto-ap.ledger.reports :as l-reports]
[auto-ap.logging :as alog] [auto-ap.logging :as alog]
[auto-ap.permissions :refer [wrap-must]] [auto-ap.permissions :refer [wrap-must]]
[auto-ap.query-params :refer [wrap-copy-qp-pqp]]
[auto-ap.routes.ledger :as route] [auto-ap.routes.ledger :as route]
[auto-ap.routes.utils [auto-ap.routes.utils
:refer [wrap-client-redirect-unauthenticated]] :refer [wrap-client-redirect-unauthenticated]]
@@ -17,8 +16,9 @@
[auto-ap.ssr.ui :refer [base-page]] [auto-ap.ssr.ui :refer [base-page]]
[auto-ap.ssr.utils [auto-ap.ssr.utils
:refer [apply-middleware-to-all-handlers clj-date-schema :refer [apply-middleware-to-all-handlers clj-date-schema
entity-id html-response wrap-form-4xx-2 field-validation-error html-response wrap-form-4xx-2
wrap-merge-prior-hx wrap-schema-enforce]] wrap-merge-prior-hx wrap-schema-decode
wrap-schema-enforce]]
[auto-ap.time :as atime] [auto-ap.time :as atime]
[bidi.bidi :as bidi] [bidi.bidi :as bidi]
[clj-time.coerce :as coerce] [clj-time.coerce :as coerce]
@@ -55,18 +55,25 @@
(def query-schema (mc/schema (def query-schema (mc/schema
[:maybe [:map [:maybe [:and [:map
[:client {} [:client {}
[:vector {:coerce? true :min 1 } [:vector {:coerce? true :min 1 }
[:entity-map {:pull [:db/id :client/name]}]]] [:entity-map {:pull [:db/id :client/name]}]]]
[:date {} [:date {}
clj-date-schema] clj-date-schema]
[:comparison-date {:optional true} [:comparison-date {:optional true}
[:maybe clj-date-schema]] [:maybe clj-date-schema]]
[:include-comparison {:optional true :default false} [:include-comparison {:optional true :default false}
[ :boolean {:decode/string {:enter #(if (= % "on") true [ :boolean {:decode/string {:enter #(if (= % "on") true
(boolean %))}}]]]])) (boolean %))}}]]]
[:fn {:error/message "required"
:error/path [:comparison-date]}
(fn [x]
(if (and (not (:comparison-date x))
(:include-comparison x))
false
true))]]]))
@@ -187,126 +194,131 @@
;; 4. Review ledger dialog ;; 4. Review ledger dialog
(defn run-balance-sheet [{:keys [query-params] :as request}] (defn balance-sheet* [{ {:keys [date comparison-date include-comparison client] } :query-params :as request}]
(let [client-ids (map :db/id (:client (:query-params request))) [:div#report
(when (and date client)
(let [client-ids (map :db/id client)
_ (when (not (seq client-ids)) _ (doseq [client-id client-ids]
(throw (ex-info "Please select a client." {:validation-error "Please select a client."}))) (assert-can-see-client (:identity request) client-id))
_ (doseq [client-id client-ids]
(assert-can-see-client (:identity request) client-id))
end-date (coerce/to-date (:date (:query-params request)))
comparable-date (coerce/to-date (:comparison-date (:query-params request)))
include-comparison (:include-comparison (:query-params request))
lookup-account (->> client-ids
(map (fn build-lookup [client-id]
[client-id (build-account-lookup client-id)]))
(into {}))
data (cond-> {:balance-sheet-accounts (into []
(mapcat
(fn calculate-accounts [client-id ]
(for [
[client-id account-id location debits credits balance count] (iol-ion.query/detailed-account-snapshot (dc/db conn) client-id end-date)
:let [account ( (or (lookup-account client-id) {}) account-id)]]
{:client-id client-id
:account-id account-id
:location location
:debits debits
:credits credits
:count count
:amount balance
:account-type (:account_type account)
:numeric-code (:numeric_code account)
:name (:name account) }))
client-ids))} end-date (coerce/to-date date)
include-comparison (assoc :comparable-balance-sheet-accounts comparable-date (coerce/to-date comparison-date)
(into [] lookup-account (->> client-ids
(mapcat (map (fn build-lookup [client-id]
(fn calculate-accounts [client-id ] [client-id (build-account-lookup client-id)]))
(for [ (into {}))
[client-id account-id location debits credits balance count] (iol-ion.query/detailed-account-snapshot (dc/db conn) client-id comparable-date) data (cond-> {:balance-sheet-accounts (into []
:let [account ( (or (lookup-account client-id) {}) account-id)]] (mapcat
{:client-id client-id (fn calculate-accounts [client-id ]
:account-id account-id (for [
:location location [client-id account-id location debits credits balance count] (iol-ion.query/detailed-account-snapshot (dc/db conn) client-id end-date)
:debits debits :let [account ( (or (lookup-account client-id) {}) account-id)]]
:credits credits {:client-id client-id
:count count :account-id account-id
:amount balance :location location
:account-type (:account_type account) :debits debits
:numeric-code (:numeric_code account) :credits credits
:name (:name account) })) :count count
:amount balance
:account-type (:account_type account)
:numeric-code (:numeric_code account)
:name (:name account) }))
client-ids))) client-ids))}
) (and include-comparison comparison-date)
args (assoc query-params (assoc :comparable-balance-sheet-accounts
:periods (filter identity (cond-> [(:date query-params)] (into []
include-comparison (conj (:comparison-date query-params))))) (mapcat
clients (pull-many (dc/db conn) [:client/code :client/name :db/id] client-ids) (fn calculate-accounts [client-id ]
(for [
[client-id account-id location debits credits balance count] (iol-ion.query/detailed-account-snapshot (dc/db conn) client-id comparable-date)
:let [account ( (or (lookup-account client-id) {}) account-id)]]
{:client-id client-id
:account-id account-id
:location location
:debits debits
:credits credits
:count count
:amount balance
:account-type (:account_type account)
:numeric-code (:numeric_code account)
:name (:name account) }))
data (concat (->> (:balance-sheet-accounts data) client-ids)))
(map (fn [b] )
(assoc b args (assoc (:query-params request)
:period (:date args))))) :periods (filter identity (cond-> [date]
(->> (:comparable-balance-sheet-accounts data) include-comparison (conj comparison-date))))
(map (fn [b] clients (pull-many (dc/db conn) [:client/code :client/name :db/id] client-ids)
(assoc b
:period (:comparison-date args)))))) data (concat (->> (:balance-sheet-accounts data)
pnl-data (l-reports/->PNLData args data (by :db/id :client/code clients)) (map (fn [b]
client-count (count (set (map :client-id (:data pnl-data)))) (assoc b
report (l-reports/summarize-balance-sheet pnl-data) ] :period (:date args)))))
(alog/info ::balance-sheet :params args) (->> (:comparable-balance-sheet-accounts data)
(html-response (map (fn [b]
(list (assoc b
[:div.text-2xl.font-bold.text-gray-600 (str "Balance Sheet - " (str/join ", " (map :client/name clients))) ] :period (:comparison-date args))))))
(table {:widths (cond-> (into [30 ] (repeat 13 client-count)) pnl-data (l-reports/->PNLData args data (by :db/id :client/code clients))
(:include-comparison args) (into (repeat 13 (* 2 client-count)))) client-count (count (set (map :client-id (:data pnl-data))))
:click-event ::investigate-clicked report (l-reports/summarize-balance-sheet pnl-data) ]
:table report} ))))) (alog/info ::balance-sheet :params args)
(list
[:div.text-2xl.font-bold.text-gray-600 (str "Balance Sheet - " (str/join ", " (map :client/name clients))) ]
(table {:widths (cond-> (into [30 ] (repeat 13 client-count))
(:include-comparison args) (into (repeat 13 (* 2 client-count))))
:click-event ::investigate-clicked
:table report} ))))])
(defn form* [request] (defn form* [request]
(fc/start-form
(:form-params request) (let [params (merge (:query-params request) (:form-params request) {})]
(:form-errors request) (fc/start-form
[:div#balance-sheet-form.flex.flex-col.gap-4.mt-4
[:form {:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::route/run-balance-sheet) params
:hx-target "#report"} (:form-errors request)
[:div.flex.gap-8 {:x-data (hx/json {:comparison (boolean (:comparison-date (:form-params request)))})} [:div#balance-sheet-form.flex.flex-col.gap-4.mt-4
(fc/with-field :client [:form {:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::route/run-balance-sheet)
:hx-target "#balance-sheet-form"
:hx-swap "outerHTML"}
[:div.flex.gap-8 {:x-data (hx/json {:comparison (boolean (:include-comparison params))})}
(fc/with-field :client
(com/validated-inline-field (com/validated-inline-field
{:label "Customers" :errors (fc/field-errors)} {:label "Customers" :errors (fc/field-errors)}
(com/multi-typeahead {:name (fc/field-name) (com/multi-typeahead {:name (fc/field-name)
:class "w-64" :class "w-64"
:id "client" :id "client"
:url (bidi/path-for ssr-routes/only-routes :company-search) :url (bidi/path-for ssr-routes/only-routes :company-search)
:value (fc/field-value) :value (fc/field-value)
:value-fn :db/id :value-fn :db/id
:content-fn :client/name}))) :content-fn :client/name})))
(fc/with-field :date (fc/with-field :date
(com/validated-inline-field {:label "Date" (com/validated-inline-field {:label "Date"
:errors (fc/field-errors)} :errors (fc/field-errors)}
(com/date-input {:placeholder "12/21/2020" (com/date-input {:placeholder "12/21/2020"
:name (fc/field-name) :name (fc/field-name)
:value (some-> (fc/field-value) :value (some-> (fc/field-value)
(atime/unparse-local atime/normal-date))}))) (atime/unparse-local atime/normal-date))})))
(fc/with-field :include-comparison (fc/with-field :include-comparison
(com/toggle {:x-model "comparison" :name (fc/field-name) :checked (boolean (fc/field-value))} "Compare")) (com/toggle {:x-model "comparison" :name (fc/field-name) :checked (boolean (fc/field-value))} "Compare"))
[:div (hx/alpine-appear {:x-show "comparison"}) [:div (hx/alpine-appear {:x-show "comparison"})
(fc/with-field :comparison-date (fc/with-field :comparison-date
(com/validated-inline-field {:label "Previous Date" (com/validated-inline-field {:label "Previous Date"
:errors (fc/field-errors)} :errors (fc/field-errors)}
(com/date-input {:placeholder "12/21/2020" (com/date-input {:placeholder "12/21/2020"
:name (fc/field-name) :name (fc/field-name)
:value (some-> (fc/field-value) :value (some-> (fc/field-value)
(atime/unparse-local atime/normal-date))})))] (atime/unparse-local atime/normal-date))})))]
(com/button {:color :primary :class "w-32"} (com/button {:color :primary :class "w-32"}
"Run")]] "Run")]]
[:div#report]])) (balance-sheet* request)])))
(defn form [request] (defn form [request]
(html-response (form* request) (html-response (form* request)
:headers {"hx-retarget" "#balance-sheet-form"})) :headers {"hx-retarget" "#balance-sheet-form"
"hx-push-url" (str "?" (:query-string request))}))
(defn balance-sheet [request] (defn balance-sheet [request]
(base-page (base-page
@@ -326,8 +338,10 @@
(def key->handler (def key->handler
(apply-middleware-to-all-handlers (apply-middleware-to-all-handlers
(-> (->
{::route/balance-sheet balance-sheet {::route/balance-sheet (-> balance-sheet
::route/run-balance-sheet (-> run-balance-sheet (wrap-schema-enforce :query-schema query-schema)
(wrap-form-4xx-2 balance-sheet))
::route/run-balance-sheet (-> form
(wrap-schema-enforce :query-schema query-schema) (wrap-schema-enforce :query-schema query-schema)
(wrap-form-4xx-2 form))}) (wrap-form-4xx-2 form))})
(fn [h] (fn [h]

View File

@@ -172,7 +172,12 @@
s)) s))
(defn keyword->str [k] (defn keyword->str [k]
(subs (str k) 1)) (cond (keyword? k)
(subs (str k) 1)
(string? k)
k
:else
k))
;; TODO make this bubble the form data automatically ;; TODO make this bubble the form data automatically