Splits out by legal entity

This commit is contained in:
2022-03-17 12:49:09 -07:00
parent 77455f6ef6
commit 6e41ada061

View File

@@ -57,18 +57,24 @@
:periods :periods
(mapcat :accounts) (mapcat :accounts)
(filter (comp in-range? :numeric-code)) (filter (comp in-range? :numeric-code))
(group-by :location) (group-by (juxt :client-id :location))
(filter (fn [[k as]] (filter (fn [[k as]]
(not (dollars-0? (reduce + 0 (map :amount as)))))) (not (dollars-0? (reduce + 0 (map :amount as))))))
(mapcat second) (mapcat second)
(map :location) (map (fn [a]
(map not-empty) (if (or (not (:client-id a))
(empty? (:location a)))
nil
[(:client-id a)
(:location a)])))
(filter identity) (filter identity)
(set) (set)
(sort-by (fn [x] (if (= x "HQ" ) (sort-by (fn [x]
"ZZZZZZ" [(:client-id x)
x)))))) (if (= (:location x) "HQ" )
"ZZZZZZ"
(:location x))])))))
(re-frame/reg-sub (re-frame/reg-sub
::multi-client? ::multi-client?
@@ -119,13 +125,15 @@
(map #(update % :amount js/parseFloat) a)))) (map #(update % :amount js/parseFloat) a))))
(defn filter-accounts [accounts period [from to] only-location] (defn filter-accounts [accounts period [from to] only-client only-location]
(->> (get accounts period) (->> (get accounts period)
vals vals
(filter (fn [{:keys [location numeric-code]}] (filter (fn [{:keys [location client-id numeric-code]}]
(and (or (nil? only-location) (and (or (nil? only-location)
(= only-location location)) (= only-location location))
(or (nil? only-client)
(= only-client client-id))
(<= from numeric-code to)))) (<= from numeric-code to))))
(sort-by :numeric-code))) (sort-by :numeric-code)))
@@ -140,7 +148,7 @@
(comp (comp
(map parse-amounts) (map parse-amounts)
(map #(->> (:accounts %) (map #(->> (:accounts %)
(group-by (juxt :numeric-code :location)) (group-by (juxt :numeric-code :client-id :location))
(map (fn [[k v]] (map (fn [[k v]]
[k [k
(reduce (fn [a n] (reduce (fn [a n]
@@ -420,17 +428,18 @@
["97000 Taxes" 97000 97999] ["97000 Taxes" 97000 97999]
["98000 Other Expenses" 98000 98999]]}) ["98000 Other Expenses" 98000 98999]]})
(defn percent-of-sales [amount accounts which location] (defn percent-of-sales [amount accounts which client-id location]
(let [sales (aggregate-accounts (filter-accounts accounts which (get ranges :sales) location))] (let [sales (aggregate-accounts (filter-accounts accounts which (get ranges :sales) client-id location))]
(if (not (dollars-0? sales)) (if (not (dollars-0? sales))
(/ amount (/ amount
sales) sales)
0.0))) 0.0)))
(defn used-accounts [accounts [from to] location] (defn used-accounts [accounts [from to] client-id location]
(->> accounts (->> accounts
(mapcat vals) (mapcat vals)
(filter #(<= from (:numeric-code %) to)) (filter #(<= from (:numeric-code %) to))
(filter #(= client-id (:client-id %)))
(filter #(= location (:location %))) (filter #(= location (:location %)))
(map #(select-keys % [:numeric-code :name])) (map #(select-keys % [:numeric-code :name]))
(set) (set)
@@ -448,17 +457,15 @@
{:key (str "between-" i)}))])) {:key (str "between-" i)}))]))
;; TODO Allow choosing more than one client
;; TODO allow "sandwhiching" clients data ;; TODO allow "sandwhiching" clients data
;; TODO do we need squashing locations?
(defn grouping [{:keys [header type groupings location periods all-accounts]}] (defn grouping [{:keys [header type groupings client-id location periods all-accounts]}]
(let [include-deltas @(re-frame/subscribe [::include-deltas]) (let [include-deltas @(re-frame/subscribe [::include-deltas])
multi-client? @(re-frame/subscribe [::multi-client?])] multi-client? @(re-frame/subscribe [::multi-client?])]
[:<> [:<>
(doall (doall
(for [[grouping-name from to] groupings (for [[grouping-name from to] groupings
:let [account-codes (used-accounts all-accounts [from to] location)] :let [account-codes (used-accounts all-accounts [from to] client-id location)]
:when (seq account-codes)] :when (seq account-codes)]
^{:key grouping-name} ^{:key grouping-name}
[:<> [:<>
@@ -479,17 +486,17 @@
[:td name] [:td name]
(map-periods (map-periods
(fn [i] (fn [i]
(let [amount (get-in all-accounts [i [numeric-code location] :amount] 0.0)] (let [amount (get-in all-accounts [i [numeric-code client-id location] :amount] 0.0)]
[:<> [:<>
[:td.has-text-right (if multi-client? [:td.has-text-right (if multi-client?
[:span (->$ amount)] [:span (->$ amount)]
[:a {:on-click (dispatch-event [::investigate-clicked location numeric-code numeric-code i :current]) [:a {:on-click (dispatch-event [::investigate-clicked location numeric-code numeric-code i :current])
:disabled (boolean multi-client?)} :disabled (boolean multi-client?)}
(->$ amount)])] (->$ amount)])]
[:td.has-text-right (->% (percent-of-sales amount all-accounts i location))]])) [:td.has-text-right (->% (percent-of-sales amount all-accounts i client-id location))]]))
(fn [i] (fn [i]
[:td.has-text-right (->$ (- (get-in all-accounts [i [numeric-code location] :amount] 0.0) [:td.has-text-right (->$ (- (get-in all-accounts [i [numeric-code client-id location] :amount] 0.0)
(get-in all-accounts [(dec i) [numeric-code location] :amount] 0.0)))]) (get-in all-accounts [(dec i) [numeric-code client-id location] :amount] 0.0)))])
periods periods
include-deltas)])] include-deltas)])]
@@ -497,22 +504,22 @@
[:th] [:th]
(map-periods (map-periods
(fn [i] (fn [i]
(let [amount (aggregate-accounts (filter-accounts all-accounts i [from to] location))] (let [amount (aggregate-accounts (filter-accounts all-accounts i [from to] client-id location))]
[:<> [:<>
[:th.has-text-right.total (if multi-client? [:th.has-text-right.total (if multi-client?
[:span (->$ amount)] [:span (->$ amount)]
[:a {:on-click (dispatch-event [::investigate-clicked location from to i])} [:a {:on-click (dispatch-event [::investigate-clicked location from to i])}
(->$ amount)])] (->$ amount)])]
[:th.has-text-right.total (->% (percent-of-sales amount all-accounts i location))]])) [:th.has-text-right.total (->% (percent-of-sales amount all-accounts i client-id location))]]))
(fn [i] (fn [i]
[:th.has-text-right.total (->$ (- (aggregate-accounts (filter-accounts all-accounts i [from to] location)) [:th.has-text-right.total (->$ (- (aggregate-accounts (filter-accounts all-accounts i [from to] client-id location))
(aggregate-accounts (filter-accounts all-accounts (dec i) [from to] location))))]) (aggregate-accounts (filter-accounts all-accounts (dec i) [from to] client-id location))))])
periods periods
include-deltas)]]))])) include-deltas)]]))]))
(defn overall-grouping [type title location] (defn overall-grouping [type title client-id location]
(let [all-accounts @(re-frame/subscribe [::all-accounts]) (let [all-accounts @(re-frame/subscribe [::all-accounts])
periods @(re-frame/subscribe [::periods]) periods @(re-frame/subscribe [::periods])
[min-numeric-code max-numeric-code] (ranges type) [min-numeric-code max-numeric-code] (ranges type)
@@ -522,6 +529,7 @@
[:tr [:th.is-size-5 title]] [:tr [:th.is-size-5 title]]
[grouping {:location location [grouping {:location location
:client-id client-id
:groupings (type groupings) :groupings (type groupings)
:periods periods :periods periods
:all-accounts all-accounts}] :all-accounts all-accounts}]
@@ -529,43 +537,44 @@
[:tr [:th.is-size-5 title] [:tr [:th.is-size-5 title]
(map-periods (map-periods
(fn [i] (fn [i]
(let [amount (aggregate-accounts (filter-accounts all-accounts i [min-numeric-code max-numeric-code] location))] (let [amount (aggregate-accounts (filter-accounts all-accounts i [min-numeric-code max-numeric-code] client-id location))]
[:<> [:<>
[:th.has-text-right (if multi-client? [:th.has-text-right (if multi-client?
[:span (->$ amount)] [:span (->$ amount)]
[:a [:a
{:on-click (dispatch-event [::investigate-clicked location min-numeric-code max-numeric-code i])} {:on-click (dispatch-event [::investigate-clicked location min-numeric-code max-numeric-code i])}
(->$ amount)])] (->$ amount)])]
[:th.has-text-right (->% (percent-of-sales amount all-accounts i location))] [:th.has-text-right (->% (percent-of-sales amount all-accounts i client-id location))]
])) ]))
(fn [i] (fn [i]
[:th.has-text-right (->$ (- (aggregate-accounts (filter-accounts all-accounts i [min-numeric-code max-numeric-code] location)) [:th.has-text-right (->$ (- (aggregate-accounts (filter-accounts all-accounts i [min-numeric-code max-numeric-code] client-id location))
(aggregate-accounts (filter-accounts all-accounts (dec i) [min-numeric-code max-numeric-code] location))))]) (aggregate-accounts (filter-accounts all-accounts (dec i) [min-numeric-code max-numeric-code] client-id location))))])
periods periods
include-deltas)]])) include-deltas)]]))
(defn subtotal [types negs title location] (defn subtotal [types negs title client-id location]
(let [all-accounts @(re-frame/subscribe [::all-accounts]) (let [all-accounts @(re-frame/subscribe [::all-accounts])
periods @(re-frame/subscribe [::periods]) periods @(re-frame/subscribe [::periods])
include-deltas @(re-frame/subscribe [::include-deltas])] include-deltas @(re-frame/subscribe [::include-deltas])]
(println title client-id)
[:tr [:th.is-size-5 title] [:tr [:th.is-size-5 title]
(map-periods (map-periods
(fn [i] (fn [i]
(let [amount (aggregate-accounts (mapcat (fn [t] (let [amount (aggregate-accounts (mapcat (fn [t]
(cond->> (filter-accounts all-accounts i (ranges t) location) (cond->> (filter-accounts all-accounts i (ranges t) client-id location)
(negs t) (map #(update % :amount -)))) (negs t) (map #(update % :amount -))))
types))] types))]
[:<> [:<>
[:td.has-text-right [:span (->$ amount)]] [:td.has-text-right [:span (->$ amount)]]
[:td.has-text-right (->% (percent-of-sales amount all-accounts i location))]])) [:td.has-text-right (->% (percent-of-sales amount all-accounts i client-id location))]]))
(fn [i] (fn [i]
[:td.has-text-right (->$ (- (aggregate-accounts (mapcat (fn [t] [:td.has-text-right (->$ (- (aggregate-accounts (mapcat (fn [t]
(cond->> (filter-accounts all-accounts i (ranges t) location) (cond->> (filter-accounts all-accounts i (ranges t) client-id location)
(negs t) (map #(update % :amount -)))) (negs t) (map #(update % :amount -))))
types)) types))
(aggregate-accounts (mapcat (fn [t] (aggregate-accounts (mapcat (fn [t]
(cond->> (filter-accounts all-accounts (dec i) (ranges t) location) (cond->> (filter-accounts all-accounts (dec i) (ranges t) client-id location)
(negs t) (map #(update % :amount -)))) (negs t) (map #(update % :amount -))))
types))))]) types))))])
periods periods
@@ -600,22 +609,22 @@
periods periods
include-deltas)]]) include-deltas)]])
(defn location-rows [location] (defn location-rows [client-id location]
[:<> [:<>
[overall-grouping :sales (str location " Sales") location] [overall-grouping :sales (str location " Sales") client-id location]
[overall-grouping :cogs (str location " COGS") location] [overall-grouping :cogs (str location " COGS") client-id location]
[overall-grouping :payroll (str location " Payroll") location] [overall-grouping :payroll (str location " Payroll") client-id location]
[subtotal [:payroll :cogs] #{} (str location " Prime Costs") location] [subtotal [:payroll :cogs] #{} (str location " Prime Costs") client-id location]
[subtotal [:sales :payroll :cogs] #{:payroll :cogs} (str location " Gross Profits") location] [subtotal [:sales :payroll :cogs] #{:payroll :cogs} (str location " Gross Profits") client-id location]
[overall-grouping :controllable (str location " Controllable Expenses") location] [overall-grouping :controllable (str location " Controllable Expenses") client-id location]
[overall-grouping :fixed-overhead (str location " Fixed Overhead") location] [overall-grouping :fixed-overhead (str location " Fixed Overhead") client-id location]
[overall-grouping :ownership-controllable (str location " Ownership Controllable") location] [overall-grouping :ownership-controllable (str location " Ownership Controllable") client-id location]
[subtotal [:controllable :fixed-overhead :ownership-controllable] #{} (str location " Overhead") location] [subtotal [:controllable :fixed-overhead :ownership-controllable] #{} (str location " Overhead") client-id location]
[subtotal [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable] #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable} (str location " Net Income") location] [subtotal [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable] #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable} (str location " Net Income") client-id location]
[subtotal [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable] #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable} "Net Income" nil]]) [subtotal [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable] #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable} "Net Income" client-id nil]])
(defn location-summary [location include-deltas] (defn location-summary [client-id location include-deltas]
(let [periods @(re-frame/subscribe [::periods])] (let [periods @(re-frame/subscribe [::periods])]
[:div [:div
[:h2.title.is-4.mb-4 location " Summary"] [:h2.title.is-4.mb-4 location " Summary"]
@@ -625,12 +634,12 @@
:periods periods}] :periods periods}]
[subtotal [:sales ] #{} "Sales" location] [subtotal [:sales ] #{} "Sales" client-id location]
[subtotal [:cogs ] #{} "Cogs" location] [subtotal [:cogs ] #{} "Cogs" client-id location]
[subtotal [:payroll ]#{} "Payroll" location] [subtotal [:payroll ]#{} "Payroll" client-id location]
[subtotal [:sales :payroll :cogs] #{:payroll :cogs} "Gross Profits" location] [subtotal [:sales :payroll :cogs] #{:payroll :cogs} "Gross Profits" client-id location]
[subtotal [:controllable :fixed-overhead :ownership-controllable] #{} "Overhead" location] [subtotal [:controllable :fixed-overhead :ownership-controllable] #{} "Overhead" client-id location]
[subtotal [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable] #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable} "Net Income" location]]]])) [subtotal [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable] #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable} "Net Income" client-id location]]]]))
(re-frame/reg-sub (re-frame/reg-sub
::can-submit ::can-submit
@@ -876,6 +885,7 @@
(defn profit-and-loss-content [] (defn profit-and-loss-content []
(let [status @(re-frame/subscribe [::status/single ::page]) (let [status @(re-frame/subscribe [::status/single ::page])
unresolved-accounts @(re-frame/subscribe [::uncategorized-accounts]) unresolved-accounts @(re-frame/subscribe [::uncategorized-accounts])
clients-by-id @(re-frame/subscribe [::subs/clients-by-id])
{:keys [data report active? error id]} @(re-frame/subscribe [::forms/form ::form]) {:keys [data report active? error id]} @(re-frame/subscribe [::forms/form ::form])
{:keys [form-inline field raw-field error-notification submit-button ]} pnl-form {:keys [form-inline field raw-field error-notification submit-button ]} pnl-form
periods (:periods data)] periods (:periods data)]
@@ -899,9 +909,9 @@
(:location %))) (:location %)))
unresolved-accounts))]) unresolved-accounts))])
[:<> [:<>
(for [location @(re-frame/subscribe [::locations])] (for [[client-id location] @(re-frame/subscribe [::locations])]
^{:key (str location "-summary")} ^{:key (str client-id "-" location "-summary")}
[location-summary location (:include-deltas data)] [location-summary client-id location (:include-deltas data)]
)] )]
[:h2.title.is-4 {:style {:margin-bottom "1rem"}} "Detail"] [:h2.title.is-4 {:style {:margin-bottom "1rem"}} "Detail"]
[:table.table.compact.balance-sheet [:table.table.compact.balance-sheet
@@ -910,9 +920,11 @@
:periods periods}] :periods periods}]
[:<> [:<>
(for [location @(re-frame/subscribe [::locations])] (for [[client-id location] @(re-frame/subscribe [::locations])]
^{:key location} ^{:key (str client-id "-" location)}
[location-rows location])]]]])]))) [:<>
[:tr [:th.is-size-3 (:name (clients-by-id client-id))]]
[location-rows client-id location]])]]]])])))
(re-frame/reg-event-fx (re-frame/reg-event-fx
::unmounted-pnl ::unmounted-pnl