Balance sheets work multiple clients
This commit is contained in:
@@ -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}}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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])}]
|
||||
|
||||
Reference in New Issue
Block a user