Balance sheets work multiple clients

This commit is contained in:
2023-09-02 21:37:12 -07:00
parent a891046084
commit 1d87687949
3 changed files with 204 additions and 89 deletions

View File

@@ -162,15 +162,32 @@
(defn get-balance-sheet [context args _]
(let [client-id (:client_id args)
client-ids (or (some-> client-id vector)
(filter identity (:client_ids args)))
_ (assert-can-see-client (:id context) client-id)
_ (when (not (seq client-ids))
(throw (ex-info "Please select a client." {:validation-error "Please select a client."})))
_ (doseq [client-id client-ids]
(assert-can-see-client (:id context) client-id))
end-date (coerce/to-date (:date args))
comparable-date (coerce/to-date (:comparison_date args))
all-ledger-entries (full-ledger-for-client client-id)
lookup-account (build-account-lookup client-id)]
all-ledger-entries (->> client-ids
(map (fn [client-id]
[client-id (full-ledger-for-client client-id)]))
(into {}))
lookup-account (->> client-ids
(map (fn [client-id]
[client-id (build-account-lookup client-id)]))
(into {}))]
(log/info "Running balance sheet with " args)
(cond-> {:balance-sheet-accounts (roll-up-until lookup-account all-ledger-entries end-date)}
(:include_comparison args) (assoc :comparable-balance-sheet-accounts (roll-up-until lookup-account all-ledger-entries comparable-date))
(cond-> {:balance-sheet-accounts (mapcat
#(roll-up-until (lookup-account %) (all-ledger-entries %) end-date )
client-ids)
}
(:include_comparison args) (assoc :comparable-balance-sheet-accounts (mapcat
#(roll-up-until (lookup-account %) (all-ledger-entries %) comparable-date )
client-ids))
true ->graphql)))
(defn get-profit-and-loss [context args _]
@@ -747,7 +764,7 @@
(def queries
{:balance_sheet {:type :balance_sheet
:args {:client_id {:type :id}
:args {:client_ids {:type '(list :id)}
:include_comparison {:type 'Boolean}
:date {:type :iso_date}
:comparison_date {:type :iso_date}}
@@ -792,7 +809,7 @@
:resolve :cash-flows-pdf}
:balance_sheet_pdf {:type :report_pdf
:args {:client_id {:type :id}
:args {:client_ids {:type '(list :id)}
:include_comparison {:type 'Boolean}
:date {:type :iso_date}
:comparison_date {:type :iso_date}}

View File

@@ -489,14 +489,20 @@
pnl-datas)
)]
(into (for [{:keys [numeric-code name]} account-codes]
(into [{:value name}]
(into [{:value (str name ":" numeric-code)}]
(map
(fn [p]
(let [pnl-data (-> p (filter-numeric-code numeric-code numeric-code))]
(let [pnl-data (-> p (filter-numeric-code numeric-code numeric-code))
this-name-exists? (->> (:data p)
(filter (comp #{name} :name))
seq)]
(merge
{:format :dollar
:filters (:filters pnl-data)
:value (aggregate-accounts pnl-data)}
(if this-name-exists?
{:format :dollar
:filters (:filters pnl-data)
:value (aggregate-accounts pnl-data)}
{:filters (:filters pnl-data)
:value ""})
(:cell-args p))))
pnl-datas))))
@@ -780,9 +786,17 @@
(defn balance-sheet-headers [pnl-data]
[(cond-> [{:value "Period Ending"}
{:value (date->str (:date (:args pnl-data)))}]
(:include-comparison (:args pnl-data)) (into [{:value (date->str (:comparison-date (:args pnl-data)))} {:value "+/-"}]))])
(doto
[(into [{:value "Period Ending"}]
(mapcat identity
(for [client (set (map :client-id (:data pnl-data))) ]
(cond-> [{:value (date->str (:date (:args pnl-data)))}]
(:include-comparison (:args pnl-data))
(into [{:value (date->str (:comparison-date (:args pnl-data)))}
{:value "+/-"}])))))]
println))
(defn append-deltas [table]
(->> table
@@ -793,31 +807,80 @@
:value (- (or (:value a) 0.0)
(or (:value b) 0.0))})]))))
#_(defn summarize-balance-sheet [pnl-data]
(reduce
(fn [result table]
(-> result
(update :header into (:header table))
(update :rows
(fn [current-rows]
(if (seq current-rows)
(map
concat
current-rows
(:rows table))
(:rows table))))))
{:header []
:rows []}
(for [client-id (set (map :client-id (:data pnl-data)))]
(let [pnl-datas (map (fn [p]
(-> pnl-data
(filter-client client-id)
(filter-period p)))
(:periods (:args pnl-data)))
table (-> []
(into (detail-rows pnl-datas
:assets
"Assets"))
(into (detail-rows pnl-datas
:liabilities
"Liabilities"))
(into (detail-rows pnl-datas
:equities
"Owner's Equity"))
(conj (subtotal-by-column-row
(map #(-> %
(filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable])
(negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable}))
pnl-datas)
"Retained Earnings")))
table (if (:include-comparison (:args pnl-data))
(append-deltas table)
table)]
{:header (balance-sheet-headers pnl-data)
:rows table})))
)
(defn summarize-balance-sheet [pnl-data]
(let [pnl-datas (map (fn [p]
(filter-period pnl-data p))
(:periods (:args pnl-data)))
table (-> []
(into (detail-rows pnl-datas
:assets
"Assets"))
(into (detail-rows pnl-datas
:liabilities
"Liabilities"))
(into (detail-rows pnl-datas
:equities
"Owner's Equity"))
(conj (subtotal-by-column-row
(map #(-> %
(filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable])
(negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable}))
pnl-datas)
"Retained Earnings")))
table (if (:include-comparison (:args pnl-data))
(append-deltas table)
table)]
{:header (balance-sheet-headers pnl-data)
:rows table}))
(let [pnl-datas (for [client-id (set (map :client-id (:data pnl-data)))
p (:periods (:args pnl-data))]
(-> pnl-data
(filter-client client-id)
(filter-period p))
)]
(let [table (-> []
(into (detail-rows pnl-datas
:assets
"Assets"))
(into (detail-rows pnl-datas
:liabilities
"Liabilities"))
(into (detail-rows pnl-datas
:equities
"Owner's Equity"))
(conj (subtotal-by-column-row
(map #(-> %
(filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable])
(negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable}))
pnl-datas)
"Retained Earnings")))
table (if (:include-comparison (:args pnl-data))
(append-deltas table)
table)]
{:header (balance-sheet-headers pnl-data)
:rows table}))
)
(defn journal-detail-report [args data client-codes]

View File

@@ -13,12 +13,14 @@
[auto-ap.views.pages.ledger.report-table :as rtable]
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
[auto-ap.views.pages.ledger.table :as ledger-table]
[auto-ap.views.components.buttons :as buttons]
[auto-ap.views.utils
:refer [date-picker dispatch-event local-now with-user date->str standard]]
[cljs-time.core :as t]
[clojure.set :as set]
[clojure.string :as str]
[re-frame.core :as re-frame]
[react-dom :as react-dom]
[reagent.core :as reagent]
[vimsical.re-frame.cofx.inject :as inject]
[vimsical.re-frame.fx.track :as track]))
@@ -68,9 +70,10 @@
:graphql {:token user
:query-obj {:venia/queries [[:balance-sheet
(-> (:data db)
(assoc :client-id (:id client)))
[[:balance-sheet-accounts [:name :amount :account-type :id :numeric-code]]
[:comparable-balance-sheet-accounts [:name :amount :account-type :id :numeric-code]]]]]}
(dissoc :clients)
(assoc :client-ids (map (comp :id :client) (:clients (:data db)))))
[[:balance-sheet-accounts [:name :amount :account-type :id :numeric-code :client-id]]
[:comparable-balance-sheet-accounts [:name :amount :account-type :id :client-id :numeric-code]]]]]}
:owns-state {:single ::page}
:on-success [::received]}}))
@@ -110,7 +113,8 @@ NOTE: Please review the transactions we may have question for you here: https://
:graphql {:token user
:query-obj {:venia/queries [[:balance-sheet-pdf
(-> (:data db)
(assoc :client-id (:id client)))
(dissoc :clients)
(assoc :client-ids (map (comp :id :client) (:clients (:data db)))))
[:url :name]]]}
:owns-state {:single ::page}
@@ -119,9 +123,9 @@ NOTE: Please review the transactions we may have question for you here: https://
(re-frame/reg-event-fx
::investigate-clicked
(fn [{:keys [db]} [_ {:keys [numeric-code date-range]}]]
(fn [{:keys [db]} [_ {:keys [numeric-code date-range client-id]}]]
{:db (-> db (assoc ::ledger-list-active? true))
:dispatch [::data-page/additional-params-changed ::ledger {:client-id (:id @(re-frame/subscribe [::subs/client]))
:dispatch [::data-page/additional-params-changed ::ledger {:client-id client-id
:numeric-code numeric-code
:date-range {:start "2000-01-01"
:end (date->str date-range standard)}}]}))
@@ -168,43 +172,77 @@ NOTE: Please review the transactions we may have question for you here: https://
(fn [{:keys [db]} _]
{:db (forms/start-form db ::form {:date (local-now)
:comparison-date (t/minus (local-now) (t/years 1))
:clients (mapv (fn [c] {:client c :id (random-uuid)})
[(some-> @(re-frame/subscribe [::subs/client]) (select-keys [:name :id]) )])
:include-comparison false})
::track/register {:id ::ledger-params
:subscription [::data-page/params ::ledger]
:event-fn (fn [params] [::ledger-params-change params])}}))
(defn report-control-detail [{:keys [active box which]} children]
(when (and @box
(= which @active))
(react-dom/createPortal (reagent/as-element
[:div.notification.is-light
[:a.delete {:on-click (fn [] (reset! active nil))}]
children
])
@box)))
(defn report-form []
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
[form-builder/builder {:change-event [::change]
:submit-event [::report-requested]
:id ::form}
[:div
[:div.report-controls
[:div.level
[:div.level-left
[:div.level-item
[:div.control
[form-builder/field-v2 {:field :date}
"Date"
[date-picker {:output :cljs-date}]]]]
[:div.level-item
[form-builder/field-v2 {:field :include-comparison}
[:div.mt-5]
[com/switch-input {:id "include-comparison"
:label "Include compariison"}]]]
[:div.level-item
(let [!box (atom nil)
active (reagent/atom nil)]
(fn []
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
[form-builder/builder {:change-event [::change]
:submit-event [::report-requested]
:id ::form}
[:div
[:div.report-controls
[:div.level
[:div.level-left
[:div.level-item
[:div.mt-5
[buttons/dropdown {:on-click (fn [] (reset! active :clients))}
[:span (str "Companies"
(when-let [clients (:clients data)]
(str " (" (str/join ", " (map (comp :name :client) clients)) ")")))]]
[report-control-detail {:active active :box !box :which :clients}
[:div {:style {:width "20em"}}
[:h4.subtitle "Companies"]
[form-builder/raw-field-v2 {:field :clients}
[com/multi-field-v2 {:new-text "Add another company"
:template [[form-builder/raw-field-v2 {:field :client}
[com/entity-typeahead {:entities @(re-frame/subscribe [::subs/clients])
:style {:width "18em"}
:entity->text :name}]]]
:key-fn :id}]]]]]]
[:div.level-item
[:div.control
[form-builder/field-v2 {:field :date}
"Date"
[date-picker {:output :cljs-date}]]]]
[:div.level-item
[form-builder/field-v2 {:field :include-comparison}
[:div.mt-5]
[com/switch-input {:id "include-comparison"
:label "Include compariison"}]]]
[:div.level-item
(when (boolean (:include-comparison data))
[form-builder/field-v2 {:field :comparison-date}
"Comparison Date"
[date-picker {:output :cljs-date}]])]]
[:div.level-right
[:div.buttons
(when (boolean (:include-comparison data))
[form-builder/field-v2 {:field :comparison-date}
"Comparison Date"
[date-picker {:output :cljs-date}]])]]
[:div.level-right
[:div.buttons
(when @(re-frame/subscribe [::subs/is-admin?])
[:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"])
[:button.button.is-primary "Run"]]]]]]]))
(when @(re-frame/subscribe [::subs/is-admin?])
[:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"])
[:button.button.is-primary "Run"]]]]
[:div.report-control-detail {:ref (fn [el]
(when (not= @!box el)
(reset! !box el)))}]]]
]))))
(defn balance-sheet-report [{:keys [args report-data]}]
(let [pnl-data (concat (->> (:balance-sheet-accounts report-data)
@@ -222,9 +260,10 @@ NOTE: Please review the transactions we may have question for you here: https://
[k (:name v)]))
(into {}))
pnl-data (l-reports/->PNLData args pnl-data client-names)
report (l-reports/summarize-balance-sheet pnl-data)]
[rtable/table {:widths (cond-> [30 13]
(:include-comparison args) (into [13 13]))
report (l-reports/summarize-balance-sheet pnl-data)
client-count (count (set (map :client-id (:data pnl-data))))]
[rtable/table {:widths (cond-> (into [30 ] (repeat 13 client-count))
(:include-comparison args) (into (repeat 13 (* 2 client-count))))
:click-event ::investigate-clicked
:table report}]))
@@ -232,21 +271,17 @@ NOTE: Please review the transactions we may have question for you here: https://
(let [current-client @(re-frame/subscribe [::subs/client])
status @(re-frame/subscribe [::status/single ::page])
{params :data report :report} @(re-frame/subscribe [::forms/form ::form])]
(if current-client
[:div.is-inline
[status/status-notification {:statuses [[::status/single ::page]]}]
[report-form]
[:div.is-inline
[status/status-notification {:statuses [[::status/single ::page]]}]
[report-form]
[status/big-loader status]
(when (and (not= :loading (:state status))
report)
[balance-sheet-report {:args (assoc params
:periods (filter identity (cond-> [(:date params)]
(:include-comparison params) (conj (:comparison-date params)))))
:report-data report}])]
[:div
[:h1.title "Balance sheet"]
[:h2.subtitle "Please choose a client first"]])))
[status/big-loader status]
(when (and (not= :loading (:state status))
report)
[balance-sheet-report {:args (assoc params
:periods (filter identity (cond-> [(:date params)]
(:include-comparison params) (conj (:comparison-date params)))))
:report-data report}])]))
(defn ledger-list [_ ]
[:div [:a.delete.is-pulled-right {:on-click (dispatch-event [::ledger-list-closing])}]