Balance sheets work multiple clients
This commit is contained in:
@@ -162,15 +162,32 @@
|
|||||||
|
|
||||||
(defn get-balance-sheet [context args _]
|
(defn get-balance-sheet [context args _]
|
||||||
(let [client-id (:client_id 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)
|
_ (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))
|
end-date (coerce/to-date (:date args))
|
||||||
comparable-date (coerce/to-date (:comparison_date args))
|
comparable-date (coerce/to-date (:comparison_date args))
|
||||||
all-ledger-entries (full-ledger-for-client client-id)
|
all-ledger-entries (->> client-ids
|
||||||
lookup-account (build-account-lookup client-id)]
|
(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)
|
(log/info "Running balance sheet with " args)
|
||||||
|
|
||||||
(cond-> {:balance-sheet-accounts (roll-up-until lookup-account all-ledger-entries end-date)}
|
(cond-> {:balance-sheet-accounts (mapcat
|
||||||
(:include_comparison args) (assoc :comparable-balance-sheet-accounts (roll-up-until lookup-account all-ledger-entries comparable-date))
|
#(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)))
|
true ->graphql)))
|
||||||
|
|
||||||
(defn get-profit-and-loss [context args _]
|
(defn get-profit-and-loss [context args _]
|
||||||
@@ -747,7 +764,7 @@
|
|||||||
|
|
||||||
(def queries
|
(def queries
|
||||||
{:balance_sheet {:type :balance_sheet
|
{:balance_sheet {:type :balance_sheet
|
||||||
:args {:client_id {:type :id}
|
:args {:client_ids {:type '(list :id)}
|
||||||
:include_comparison {:type 'Boolean}
|
:include_comparison {:type 'Boolean}
|
||||||
:date {:type :iso_date}
|
:date {:type :iso_date}
|
||||||
:comparison_date {:type :iso_date}}
|
:comparison_date {:type :iso_date}}
|
||||||
@@ -792,7 +809,7 @@
|
|||||||
:resolve :cash-flows-pdf}
|
:resolve :cash-flows-pdf}
|
||||||
|
|
||||||
:balance_sheet_pdf {:type :report_pdf
|
:balance_sheet_pdf {:type :report_pdf
|
||||||
:args {:client_id {:type :id}
|
:args {:client_ids {:type '(list :id)}
|
||||||
:include_comparison {:type 'Boolean}
|
:include_comparison {:type 'Boolean}
|
||||||
:date {:type :iso_date}
|
:date {:type :iso_date}
|
||||||
:comparison_date {:type :iso_date}}
|
:comparison_date {:type :iso_date}}
|
||||||
|
|||||||
@@ -489,14 +489,20 @@
|
|||||||
pnl-datas)
|
pnl-datas)
|
||||||
)]
|
)]
|
||||||
(into (for [{:keys [numeric-code name]} account-codes]
|
(into (for [{:keys [numeric-code name]} account-codes]
|
||||||
(into [{:value name}]
|
(into [{:value (str name ":" numeric-code)}]
|
||||||
(map
|
(map
|
||||||
(fn [p]
|
(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
|
(merge
|
||||||
|
(if this-name-exists?
|
||||||
{:format :dollar
|
{:format :dollar
|
||||||
:filters (:filters pnl-data)
|
:filters (:filters pnl-data)
|
||||||
:value (aggregate-accounts pnl-data)}
|
:value (aggregate-accounts pnl-data)}
|
||||||
|
{:filters (:filters pnl-data)
|
||||||
|
:value ""})
|
||||||
(:cell-args p))))
|
(:cell-args p))))
|
||||||
|
|
||||||
pnl-datas))))
|
pnl-datas))))
|
||||||
@@ -780,9 +786,17 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn balance-sheet-headers [pnl-data]
|
(defn balance-sheet-headers [pnl-data]
|
||||||
[(cond-> [{:value "Period Ending"}
|
(doto
|
||||||
{:value (date->str (:date (:args pnl-data)))}]
|
[(into [{:value "Period Ending"}]
|
||||||
(:include-comparison (:args pnl-data)) (into [{:value (date->str (:comparison-date (:args pnl-data)))} {:value "+/-"}]))])
|
|
||||||
|
(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]
|
(defn append-deltas [table]
|
||||||
(->> table
|
(->> table
|
||||||
@@ -793,9 +807,27 @@
|
|||||||
:value (- (or (:value a) 0.0)
|
:value (- (or (:value a) 0.0)
|
||||||
(or (:value b) 0.0))})]))))
|
(or (:value b) 0.0))})]))))
|
||||||
|
|
||||||
(defn summarize-balance-sheet [pnl-data]
|
|
||||||
|
#_(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]
|
(let [pnl-datas (map (fn [p]
|
||||||
(filter-period pnl-data p))
|
(-> pnl-data
|
||||||
|
(filter-client client-id)
|
||||||
|
(filter-period p)))
|
||||||
(:periods (:args pnl-data)))
|
(:periods (:args pnl-data)))
|
||||||
table (-> []
|
table (-> []
|
||||||
(into (detail-rows pnl-datas
|
(into (detail-rows pnl-datas
|
||||||
@@ -816,8 +848,39 @@
|
|||||||
table (if (:include-comparison (:args pnl-data))
|
table (if (:include-comparison (:args pnl-data))
|
||||||
(append-deltas table)
|
(append-deltas table)
|
||||||
table)]
|
table)]
|
||||||
|
{:header (balance-sheet-headers pnl-data)
|
||||||
|
:rows table})))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn summarize-balance-sheet [pnl-data]
|
||||||
|
(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)
|
{:header (balance-sheet-headers pnl-data)
|
||||||
:rows table}))
|
:rows table}))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
(defn journal-detail-report [args data client-codes]
|
(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.report-table :as rtable]
|
||||||
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
|
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
|
||||||
[auto-ap.views.pages.ledger.table :as ledger-table]
|
[auto-ap.views.pages.ledger.table :as ledger-table]
|
||||||
|
[auto-ap.views.components.buttons :as buttons]
|
||||||
[auto-ap.views.utils
|
[auto-ap.views.utils
|
||||||
:refer [date-picker dispatch-event local-now with-user date->str standard]]
|
:refer [date-picker dispatch-event local-now with-user date->str standard]]
|
||||||
[cljs-time.core :as t]
|
[cljs-time.core :as t]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[react-dom :as react-dom]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[vimsical.re-frame.cofx.inject :as inject]
|
[vimsical.re-frame.cofx.inject :as inject]
|
||||||
[vimsical.re-frame.fx.track :as track]))
|
[vimsical.re-frame.fx.track :as track]))
|
||||||
@@ -68,9 +70,10 @@
|
|||||||
:graphql {:token user
|
:graphql {:token user
|
||||||
:query-obj {:venia/queries [[:balance-sheet
|
:query-obj {:venia/queries [[:balance-sheet
|
||||||
(-> (:data db)
|
(-> (:data db)
|
||||||
(assoc :client-id (:id client)))
|
(dissoc :clients)
|
||||||
[[:balance-sheet-accounts [:name :amount :account-type :id :numeric-code]]
|
(assoc :client-ids (map (comp :id :client) (:clients (:data db)))))
|
||||||
[:comparable-balance-sheet-accounts [:name :amount :account-type :id :numeric-code]]]]]}
|
[[: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}
|
:owns-state {:single ::page}
|
||||||
:on-success [::received]}}))
|
:on-success [::received]}}))
|
||||||
@@ -110,7 +113,8 @@ NOTE: Please review the transactions we may have question for you here: https://
|
|||||||
:graphql {:token user
|
:graphql {:token user
|
||||||
:query-obj {:venia/queries [[:balance-sheet-pdf
|
:query-obj {:venia/queries [[:balance-sheet-pdf
|
||||||
(-> (:data db)
|
(-> (:data db)
|
||||||
(assoc :client-id (:id client)))
|
(dissoc :clients)
|
||||||
|
(assoc :client-ids (map (comp :id :client) (:clients (:data db)))))
|
||||||
[:url :name]]]}
|
[:url :name]]]}
|
||||||
|
|
||||||
:owns-state {:single ::page}
|
: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
|
(re-frame/reg-event-fx
|
||||||
::investigate-clicked
|
::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))
|
{: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
|
:numeric-code numeric-code
|
||||||
:date-range {:start "2000-01-01"
|
:date-range {:start "2000-01-01"
|
||||||
:end (date->str date-range standard)}}]}))
|
:end (date->str date-range standard)}}]}))
|
||||||
@@ -168,13 +172,27 @@ NOTE: Please review the transactions we may have question for you here: https://
|
|||||||
(fn [{:keys [db]} _]
|
(fn [{:keys [db]} _]
|
||||||
{:db (forms/start-form db ::form {:date (local-now)
|
{:db (forms/start-form db ::form {:date (local-now)
|
||||||
:comparison-date (t/minus (local-now) (t/years 1))
|
: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})
|
:include-comparison false})
|
||||||
::track/register {:id ::ledger-params
|
::track/register {:id ::ledger-params
|
||||||
:subscription [::data-page/params ::ledger]
|
:subscription [::data-page/params ::ledger]
|
||||||
:event-fn (fn [params] [::ledger-params-change params])}}))
|
: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 []
|
(defn report-form []
|
||||||
|
(let [!box (atom nil)
|
||||||
|
active (reagent/atom nil)]
|
||||||
|
(fn []
|
||||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
|
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
|
||||||
[form-builder/builder {:change-event [::change]
|
[form-builder/builder {:change-event [::change]
|
||||||
:submit-event [::report-requested]
|
:submit-event [::report-requested]
|
||||||
@@ -183,6 +201,22 @@ NOTE: Please review the transactions we may have question for you here: https://
|
|||||||
[:div.report-controls
|
[:div.report-controls
|
||||||
[:div.level
|
[:div.level
|
||||||
[:div.level-left
|
[: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.level-item
|
||||||
[:div.control
|
[:div.control
|
||||||
[form-builder/field-v2 {:field :date}
|
[form-builder/field-v2 {:field :date}
|
||||||
@@ -204,7 +238,11 @@ NOTE: Please review the transactions we may have question for you here: https://
|
|||||||
|
|
||||||
(when @(re-frame/subscribe [::subs/is-admin?])
|
(when @(re-frame/subscribe [::subs/is-admin?])
|
||||||
[:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"])
|
[:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"])
|
||||||
[:button.button.is-primary "Run"]]]]]]]))
|
[: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]}]
|
(defn balance-sheet-report [{:keys [args report-data]}]
|
||||||
(let [pnl-data (concat (->> (:balance-sheet-accounts 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)]))
|
[k (:name v)]))
|
||||||
(into {}))
|
(into {}))
|
||||||
pnl-data (l-reports/->PNLData args pnl-data client-names)
|
pnl-data (l-reports/->PNLData args pnl-data client-names)
|
||||||
report (l-reports/summarize-balance-sheet pnl-data)]
|
report (l-reports/summarize-balance-sheet pnl-data)
|
||||||
[rtable/table {:widths (cond-> [30 13]
|
client-count (count (set (map :client-id (:data pnl-data))))]
|
||||||
(:include-comparison args) (into [13 13]))
|
[rtable/table {:widths (cond-> (into [30 ] (repeat 13 client-count))
|
||||||
|
(:include-comparison args) (into (repeat 13 (* 2 client-count))))
|
||||||
:click-event ::investigate-clicked
|
:click-event ::investigate-clicked
|
||||||
:table report}]))
|
:table report}]))
|
||||||
|
|
||||||
@@ -232,7 +271,6 @@ NOTE: Please review the transactions we may have question for you here: https://
|
|||||||
(let [current-client @(re-frame/subscribe [::subs/client])
|
(let [current-client @(re-frame/subscribe [::subs/client])
|
||||||
status @(re-frame/subscribe [::status/single ::page])
|
status @(re-frame/subscribe [::status/single ::page])
|
||||||
{params :data report :report} @(re-frame/subscribe [::forms/form ::form])]
|
{params :data report :report} @(re-frame/subscribe [::forms/form ::form])]
|
||||||
(if current-client
|
|
||||||
[:div.is-inline
|
[:div.is-inline
|
||||||
[status/status-notification {:statuses [[::status/single ::page]]}]
|
[status/status-notification {:statuses [[::status/single ::page]]}]
|
||||||
[report-form]
|
[report-form]
|
||||||
@@ -243,10 +281,7 @@ NOTE: Please review the transactions we may have question for you here: https://
|
|||||||
[balance-sheet-report {:args (assoc params
|
[balance-sheet-report {:args (assoc params
|
||||||
:periods (filter identity (cond-> [(:date params)]
|
:periods (filter identity (cond-> [(:date params)]
|
||||||
(:include-comparison params) (conj (:comparison-date params)))))
|
(:include-comparison params) (conj (:comparison-date params)))))
|
||||||
:report-data report}])]
|
:report-data report}])]))
|
||||||
[:div
|
|
||||||
[:h1.title "Balance sheet"]
|
|
||||||
[:h2.subtitle "Please choose a client first"]])))
|
|
||||||
|
|
||||||
(defn ledger-list [_ ]
|
(defn ledger-list [_ ]
|
||||||
[:div [:a.delete.is-pulled-right {:on-click (dispatch-event [::ledger-list-closing])}]
|
[:div [:a.delete.is-pulled-right {:on-click (dispatch-event [::ledger-list-closing])}]
|
||||||
|
|||||||
Reference in New Issue
Block a user