Makes balance sheet work like pnl, updates pnl as necessary
This commit is contained in:
@@ -1,19 +1,28 @@
|
||||
(ns auto-ap.views.pages.ledger.balance-sheet
|
||||
(:require [auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout appearing-side-bar]]
|
||||
[auto-ap.views.components.switch-field :refer [switch-field]]
|
||||
[auto-ap.views.pages.ledger.table :as ledger-table ]
|
||||
[goog.string :as gstring]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
|
||||
[auto-ap.views.utils :refer [date->str date-picker bind-field local-now standard ->$ str->date dispatch-event with-user]]
|
||||
[cljs-time.core :as t]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[clojure.set :as set]
|
||||
[auto-ap.status :as status]))
|
||||
(:require
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.ledger.reports :as l-reports]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.layouts
|
||||
:refer [appearing-side-bar side-bar-layout]]
|
||||
[auto-ap.views.components.switch-field :refer [switch-field]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
|
||||
[auto-ap.views.pages.ledger.table :as ledger-table]
|
||||
[auto-ap.views.utils
|
||||
:refer [date->str
|
||||
date-picker-friendly
|
||||
dispatch-event
|
||||
local-now
|
||||
standard
|
||||
with-user]]
|
||||
[cljs-time.core :as t]
|
||||
[clojure.set :as set]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.views.pages.ledger.report-table :as rtable]))
|
||||
|
||||
(defn data-params->query-params [params]
|
||||
(when params
|
||||
@@ -27,91 +36,45 @@
|
||||
:date-range (:date-range params)}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::report
|
||||
(fn [db]
|
||||
(-> db ::report)))
|
||||
::can-submit
|
||||
(fn [_]
|
||||
true))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::accounts
|
||||
(fn [db [_ type]]
|
||||
(->> db
|
||||
::report
|
||||
:balance-sheet-accounts
|
||||
(map #(update % :amount js/parseFloat))
|
||||
(filter (fn [{:keys [account-type]}]
|
||||
(= type account-type)))
|
||||
(sort-by :numeric-code))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::accounts-by-id
|
||||
(fn [db [_ type]]
|
||||
(->> db
|
||||
::report
|
||||
:balance-sheet-accounts
|
||||
(map #(update % :amount js/parseFloat))
|
||||
(filter (fn [{:keys [account-type]}]
|
||||
(= type account-type)))
|
||||
(by :id))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::comparable-accounts-by-id
|
||||
(fn [db [_ type]]
|
||||
(->> db
|
||||
::report
|
||||
:comparable-balance-sheet-accounts
|
||||
(map #(update % :amount js/parseFloat))
|
||||
(filter (fn [{:keys [account-type]}]
|
||||
(= type account-type)))
|
||||
(by :id))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::ledger-list-active?
|
||||
(fn [db]
|
||||
(-> db ::ledger-list-active?)))
|
||||
(def groupings
|
||||
{:asset [["1100 Cash and Bank Accounts" 11000 11999]
|
||||
["1200 Accounts Receivable" 12000 12999]
|
||||
["1300 Inventory" 13000 13999]
|
||||
["1400 Prepaid Expenses" 14000 14999]
|
||||
["1500 Property and Equipment" 15000 15999]
|
||||
["1600 Intangible Assets" 16000 16999]
|
||||
["1700 Other Assets" 17000 19999]]
|
||||
:liability [["2000 Accounts Payable" 20100 23999]
|
||||
["2400 Accrued Expenses" 24000 24999]
|
||||
["2500 Other Liabilities" 25000 25999]
|
||||
["2600 Split Accounts" 26000 26999]
|
||||
["2700 Current Portion of Long-Term Debt" 27000 27999]
|
||||
["2800 Notes Payable" 28000 28999]
|
||||
]
|
||||
:equity [["3000 Owner's Equity" 30000 39999]]
|
||||
:revenue [["Retained Earnings" 40000 49999]]})
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::received
|
||||
[(forms/in-form ::form)]
|
||||
(fn [db [_ data]]
|
||||
(-> db
|
||||
(assoc ::report (:balance-sheet data)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::params
|
||||
(fn [db]
|
||||
(-> db ::params)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::include-comparison
|
||||
:<- [::params]
|
||||
(fn [params]
|
||||
(:include-comparison params)))
|
||||
(assoc :report (:balance-sheet data)))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
(fn [cofx [_ params]]
|
||||
{:db (-> (:db cofx)
|
||||
(dissoc ::report)
|
||||
(assoc-in [::params] params))
|
||||
:graphql {:token (-> cofx :db :user)
|
||||
::change
|
||||
[with-user (forms/in-form ::form)]
|
||||
(fn [{:keys [db]} [_ & event]]
|
||||
{:db (dissoc db :report)
|
||||
:dispatch-n [(into [::forms/change ::form] event)
|
||||
[::ledger-list-closing]]}))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::ledger-list-closing
|
||||
(fn [db]
|
||||
(assoc db ::ledger-list-active? false)))
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::report-requested
|
||||
[with-user (forms/in-form ::form)]
|
||||
(fn [{:keys [db user]} [_]]
|
||||
{:db (dissoc db :report)
|
||||
:graphql {:token user
|
||||
:query-obj {:venia/queries [[:balance-sheet
|
||||
(assoc params
|
||||
(assoc (:data db)
|
||||
:client-id (:id @(re-frame/subscribe [::subs/client])))
|
||||
[[:balance-sheet-accounts [:name :amount :account-type :id :numeric-code]]
|
||||
[:comparable-balance-sheet-accounts [:name :amount :account-type :id :numeric-code]]]]]}
|
||||
@@ -119,46 +82,24 @@
|
||||
:owns-state {:single ::page}
|
||||
:on-success [::received]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::date-picked
|
||||
(fn [cofx [_ _ date]]
|
||||
{:dispatch [::params-change (assoc @(re-frame/subscribe [::params])
|
||||
:date
|
||||
date)]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::comparison-date-picked
|
||||
(fn [cofx [_ _ date]]
|
||||
{:dispatch [::params-change (assoc @(re-frame/subscribe [::params])
|
||||
:comparison-date
|
||||
date)]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::include-comparison-changed
|
||||
(fn [cofx [_ include-comparison]]
|
||||
{:dispatch [::params-change (assoc @(re-frame/subscribe [::params])
|
||||
:include-comparison
|
||||
include-comparison)]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::investigate-clicked
|
||||
(fn [{:keys [db]} [_ from-numeric-code to-numeric-code which]]
|
||||
(let [date (if (= :current which)
|
||||
(get @(re-frame/subscribe [::params]) :date)
|
||||
(get @(re-frame/subscribe [::params]) :comparison-date))]
|
||||
{:db (-> db (assoc ::ledger-list-active? true))
|
||||
:dispatch [::data-page/additional-params-changed ::ledger {:client-id (:id @(re-frame/subscribe [::subs/client]))
|
||||
:from-numeric-code from-numeric-code
|
||||
:to-numeric-code to-numeric-code
|
||||
:date-range {:start "2000-01-01"
|
||||
:end date}}]})))
|
||||
(fn [{:keys [db]} [_ {:keys [from-numeric-code to-numeric-code date-range] :as g}]]
|
||||
(println g)
|
||||
|
||||
{:db (-> db (assoc ::ledger-list-active? true))
|
||||
:dispatch [::data-page/additional-params-changed ::ledger {:client-id (:id @(re-frame/subscribe [::subs/client]))
|
||||
:from-numeric-code from-numeric-code
|
||||
:to-numeric-code to-numeric-code
|
||||
:date-range {:start "2000-01-01"
|
||||
:end date-range}}]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::ledger-params-change
|
||||
[with-user]
|
||||
(fn [{:keys [user db]} [_ ledger-params]]
|
||||
|
||||
(if (seq ledger-params)
|
||||
(fn [{:keys [user]} [_ ledger-params]]
|
||||
(when (seq ledger-params)
|
||||
{:graphql {:token user
|
||||
:owns-state {:single [::data-page/page ::ledger]}
|
||||
:query-obj {:venia/queries [[:ledger-page
|
||||
@@ -180,190 +121,116 @@
|
||||
:start
|
||||
:end]]]}
|
||||
:on-success (fn [result]
|
||||
|
||||
[::data-page/received ::ledger (set/rename-keys (:ledger-page result)
|
||||
{:journal-entries :data})])}})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted-balance-sheet
|
||||
(fn [{:keys [db]} _]
|
||||
(fn [_ _]
|
||||
{:dispatch [::data-page/dispose ::ledger]
|
||||
::track/dispose {:id ::ledger-params}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted-balance-sheet
|
||||
(fn [{:keys [db]} _]
|
||||
{::track/register {:id ::ledger-params
|
||||
{:db (forms/start-form db ::form {:date (date->str (local-now) standard)
|
||||
:comparison-date (date->str (t/minus (local-now) (t/years 1)) standard)
|
||||
:include-comparison true})
|
||||
::track/register {:id ::ledger-params
|
||||
:subscription [::data-page/params ::ledger]
|
||||
:event-fn (fn [params] [::ledger-params-change params])}}))
|
||||
|
||||
(defn grouping [{:keys [header accounts comparable-accounts groupings]}]
|
||||
(let [include-comparison @(re-frame/subscribe [::include-comparison])]
|
||||
|
||||
(for [[grouping-name from to] groupings
|
||||
:let [matching-accounts (filter
|
||||
#(<= from (:numeric-code %) to)
|
||||
accounts)]
|
||||
:when (seq matching-accounts)
|
||||
]
|
||||
(list
|
||||
[:tr [:th "---" grouping-name "---"]
|
||||
[:td]
|
||||
(when include-comparison
|
||||
[:td])
|
||||
(when include-comparison
|
||||
[:td])
|
||||
]
|
||||
(for [account matching-accounts]
|
||||
[:tr [:td (:name account)]
|
||||
[:td.has-text-right [:a {:on-click (dispatch-event [::investigate-clicked (:numeric-code account) (:numeric-code account) :current])}
|
||||
(->$ (:amount account))] ]
|
||||
(when include-comparison
|
||||
[:td.has-text-right [:a {:on-click (dispatch-event [::investigate-clicked (:numeric-code account) (:numeric-code account) :comparable])}
|
||||
(->$ (:amount (get comparable-accounts (:id account)) 0))]])
|
||||
(when include-comparison
|
||||
[:td.has-text-right (->$ (- (:amount account ) (:amount (get comparable-accounts (:id account)) 0)))])])
|
||||
[:tr [:th "---" grouping-name "---"]
|
||||
[:th.has-text-right.total [:a {:on-click (dispatch-event [::investigate-clicked from to :current])}
|
||||
(->$ (reduce + 0 (map :amount
|
||||
matching-accounts)))] ]
|
||||
(when include-comparison
|
||||
[:th.has-text-right.total [:a {:on-click (dispatch-event [::investigate-clicked from to :comparable])}
|
||||
(->$ (reduce + 0 (map #(:amount (get comparable-accounts (:id %)) 0)
|
||||
matching-accounts)))]])
|
||||
(when include-comparison
|
||||
[:th.has-text-right.total (->$ (reduce + 0
|
||||
(map #(- (:amount % ) (:amount (get comparable-accounts (:id %)) 0))
|
||||
matching-accounts)))])
|
||||
[:td]
|
||||
]))))
|
||||
|
||||
(defn overall-grouping [type title]
|
||||
(let [include-comparison @(re-frame/subscribe [::include-comparison])]
|
||||
(list
|
||||
[:tr [:th.has-text-centered title]
|
||||
[:td]
|
||||
(when include-comparison
|
||||
[:td])
|
||||
(when include-comparison
|
||||
[:td])]
|
||||
(grouping {:accounts @(re-frame/subscribe [::accounts type])
|
||||
:groupings (type groupings)
|
||||
:comparable-accounts @(re-frame/subscribe [::comparable-accounts-by-id type])
|
||||
})
|
||||
[:tr [:th.has-text-centered title]
|
||||
[:th.has-text-right (->$ (reduce + 0 (map :amount @(re-frame/subscribe [::accounts type]))))]
|
||||
(when include-comparison
|
||||
[:th.has-text-right (->$ (reduce + 0 (map :amount (vals @(re-frame/subscribe [::comparable-accounts-by-id type])))))])
|
||||
(when include-comparison
|
||||
[:th.has-text-right (->$ (- (reduce + 0 (map :amount @(re-frame/subscribe [::accounts type])))
|
||||
(reduce + 0 (map :amount (vals @(re-frame/subscribe [::comparable-accounts-by-id type]))))))])])))
|
||||
(def balance-sheet-form (forms/vertical-form {:can-submit [::can-submit]
|
||||
:change-event [::change]
|
||||
:submit-event [::report-requested]
|
||||
:id ::form}))
|
||||
|
||||
(defn report-form []
|
||||
(let [{:keys [form-inline raw-field]} balance-sheet-form
|
||||
{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
|
||||
(form-inline {}
|
||||
[:div
|
||||
[status/status-notification {:statuses [[::status/single ::page]]}]
|
||||
[:div.report-controls
|
||||
[:div.level
|
||||
[:div.level-left
|
||||
[:div.level-item
|
||||
[:div.control
|
||||
[:p.help "Date"]
|
||||
(raw-field
|
||||
[date-picker-friendly {:type "date"
|
||||
:field [:date]}])]]
|
||||
[:div.level-item
|
||||
[:div.control
|
||||
[:div.mt-3]
|
||||
[switch-field {:id "include-comparison"
|
||||
:checked (:include-comparison data)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::change [:include-comparison] (.-checked (.-target e))]))
|
||||
:label "Include comparison"
|
||||
:type "checkbox"}]]]
|
||||
[:div.level-item
|
||||
|
||||
(defn retained-earnings []
|
||||
|
||||
(let [include-comparison @(re-frame/subscribe [::include-comparison])]
|
||||
(list
|
||||
|
||||
#_(grouping {:accounts @(re-frame/subscribe [::accounts type])
|
||||
:comparable-accounts @(re-frame/subscribe [::comparable-accounts-by-id type])
|
||||
})
|
||||
[:tr [:th.has-text-centered "Retained Earnings"]
|
||||
[:th.has-text-right (->$ (- (reduce + 0 (map :amount @(re-frame/subscribe [::accounts :revenue])))
|
||||
(reduce + 0 (map :amount @(re-frame/subscribe [::accounts :expense])))))]
|
||||
(when include-comparison
|
||||
[:th.has-text-right (->$ (- (reduce + 0 (map :amount (vals @(re-frame/subscribe [::comparable-accounts-by-id :revenue]))))
|
||||
(reduce + 0 (map :amount (vals @(re-frame/subscribe [::comparable-accounts-by-id :expense]))))))])
|
||||
(when include-comparison
|
||||
[:th.has-text-right (->$ (- (- (reduce + 0 (map :amount @(re-frame/subscribe [::accounts :revenue])))
|
||||
(reduce + 0 (map :amount @(re-frame/subscribe [::accounts :expense]))))
|
||||
(- (reduce + 0 (map :amount (vals @(re-frame/subscribe [::comparable-accounts-by-id :revenue]))))
|
||||
(reduce + 0 (map :amount (vals @(re-frame/subscribe [::comparable-accounts-by-id :expense])))))))])])))
|
||||
(when (boolean (:include-comparison data))
|
||||
[:div.control
|
||||
[:p.help "Comparison Date"]
|
||||
(raw-field
|
||||
[date-picker-friendly {:type "date"
|
||||
:field [:comparison-date]}])])]]
|
||||
[:div.level-right
|
||||
[:div.buttons
|
||||
|
||||
(def balance-sheet-content
|
||||
(with-meta
|
||||
(fn []
|
||||
(let [current-client @(re-frame/subscribe [::subs/client])
|
||||
status @(re-frame/subscribe [::status/single ::page])
|
||||
user @(re-frame/subscribe [::subs/user])
|
||||
params @(re-frame/subscribe [::params])]
|
||||
(if current-client
|
||||
[:div.is-inline
|
||||
[:h1.title "Balance Sheet - " (:name current-client)]
|
||||
[status/status-notification {:statuses [[::status/single ::page]]}]
|
||||
(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-controls
|
||||
|
||||
[:div.level
|
||||
[:div.level-left
|
||||
[:div.level-item
|
||||
[:div.control
|
||||
[:p.help "Date"]
|
||||
[bind-field
|
||||
[date-picker {:class-name "input"
|
||||
:class "input"
|
||||
:format-week-number (fn [] "")
|
||||
:previous-month-button-label ""
|
||||
:placeholder "mm/dd/yyyy"
|
||||
:next-month-button-label ""
|
||||
:next-month-label ""
|
||||
:type "date"
|
||||
:field [:date]
|
||||
:event [::date-picked]
|
||||
:popper-props (clj->js {:placement "right"})
|
||||
:subscription params}]]]]
|
||||
[:div.level-item
|
||||
|
||||
(defn balance-sheet-report [{:keys [args report-data]}]
|
||||
(let [pnl-data (concat (->> (:balance-sheet-accounts report-data)
|
||||
(map (fn [b]
|
||||
(assoc b
|
||||
:period (:date args)
|
||||
:amount (js/parseFloat (:amount b))))))
|
||||
(->> (:comparable-balance-sheet-accounts report-data)
|
||||
(map (fn [b]
|
||||
(assoc b
|
||||
:period (:comparison-date args)
|
||||
:amount (js/parseFloat (:amount b)))))))
|
||||
|
||||
client-names (->> @(re-frame/subscribe [::subs/clients-by-id])
|
||||
(map (fn [[k v]]
|
||||
[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 (into [30 13
|
||||
(when (:include-comparison args)
|
||||
13)
|
||||
(when (:include-comparison args)
|
||||
13)])
|
||||
:click-event ::investigate-clicked
|
||||
:table report}]))
|
||||
|
||||
[:div.control
|
||||
[:div.mt-3]
|
||||
[switch-field {:id "include-comparison"
|
||||
:checked (boolean (:include-comparison params))
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::include-comparison-changed (.-checked (.-target e))]))
|
||||
:label "Include comparison"
|
||||
:type "checkbox"}]]]
|
||||
[:div.level-item
|
||||
(defn balance-sheet-content []
|
||||
(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]
|
||||
|
||||
(when (boolean (:include-comparison params))
|
||||
[:div.control
|
||||
|
||||
[:p.help "Comparison Date"]
|
||||
[bind-field
|
||||
[date-picker {:class-name "input"
|
||||
:class "input"
|
||||
:format-week-number (fn [] "")
|
||||
:previous-month-button-label ""
|
||||
:placeholder "mm/dd/yyyy"
|
||||
:next-month-button-label ""
|
||||
:next-month-label ""
|
||||
:type "date"
|
||||
:field [:comparison-date]
|
||||
:event [::comparison-date-picked]
|
||||
:popper-props (clj->js {:placement "right"})
|
||||
:subscription params}]]])
|
||||
]]]]
|
||||
[status/big-loader status]
|
||||
(when (not= :loading (:state status))
|
||||
[:table.table.compact.balance-sheet
|
||||
[:tr
|
||||
[:td.has-text-right "Period ending"]
|
||||
[:td.has-text-right (date->str (str->date (:date params) standard))]
|
||||
(when (:include-comparison params)
|
||||
[:td.has-text-right (when (:date params)
|
||||
(date->str (str->date (:comparison-date params) standard)))])
|
||||
[:td]]
|
||||
(list
|
||||
(overall-grouping :asset "Assets")
|
||||
(overall-grouping :liability "Liabilities" )
|
||||
(overall-grouping :equity "Owner's Equity" )
|
||||
(retained-earnings))])]
|
||||
[:div
|
||||
[:h1.title "Balance sheet"]
|
||||
[:h2.subtitle "Please choose a client first"]])))
|
||||
{:component-will-mount #(re-frame/dispatch-sync [::params-change {:date (date->str (local-now) standard)
|
||||
:comparison-date (date->str (t/minus (local-now) (t/years 1)) standard)
|
||||
:include-comparison true}]) }))
|
||||
|
||||
[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"]])))
|
||||
|
||||
(defn ledger-list [_ ]
|
||||
[:div [:a.delete.is-pulled-right {:on-click (dispatch-event [::ledger-list-closing])}]
|
||||
|
||||
Reference in New Issue
Block a user