more progress on cash flow.
This commit is contained in:
@@ -231,7 +231,32 @@
|
|||||||
:auto-ap/add-cleared-against {:txes [[{:db/ident :transaction/cleared-against
|
:auto-ap/add-cleared-against {:txes [[{:db/ident :transaction/cleared-against
|
||||||
:db/doc "which entitiy it was cleared against"
|
:db/doc "which entitiy it was cleared against"
|
||||||
:db/valueType :db.type/string
|
:db/valueType :db.type/string
|
||||||
:db/cardinality :db.cardinality/one}]]}}]
|
:db/cardinality :db.cardinality/one}]]}
|
||||||
|
:auto-ap/add-cash-flow-schema {:txes [[{:db/ident :client/weekly-debits
|
||||||
|
:db/doc "How much money gets debited each week"
|
||||||
|
:db/valueType :db.type/double
|
||||||
|
:db/cardinality :db.cardinality/one}
|
||||||
|
{:db/ident :client/weekly-credits
|
||||||
|
:db/doc "How much money gets credited each week"
|
||||||
|
:db/valueType :db.type/double
|
||||||
|
:db/cardinality :db.cardinality/one}
|
||||||
|
{:db/ident :client/forecasted-transactions
|
||||||
|
:db/doc "Regular, planned transactions"
|
||||||
|
:db/valueType :db.type/ref
|
||||||
|
:db/isComponent true
|
||||||
|
:db/cardinality :db.cardinality/many}
|
||||||
|
{:db/ident :forecasted-transaction/amount
|
||||||
|
:db/doc "Amount of a forcested transaction"
|
||||||
|
:db/valueType :db.type/double
|
||||||
|
:db/cardinality :db.cardinality/one}
|
||||||
|
{:db/ident :forecasted-transaction/day-of-month
|
||||||
|
:db/doc "Which day the transaction occurs"
|
||||||
|
:db/valueType :db.type/long
|
||||||
|
:db/cardinality :db.cardinality/one}
|
||||||
|
{:db/ident :forecasted-transaction/identifier
|
||||||
|
:db/doc "An identifier for this forcasted transaction, e.g., 'RENT'"
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/cardinality :db.cardinality/one}]]}}]
|
||||||
(println "Conforming database...")
|
(println "Conforming database...")
|
||||||
(c/ensure-conforms conn norms-map)
|
(c/ensure-conforms conn norms-map)
|
||||||
(when (not (seq args))
|
(when (not (seq args))
|
||||||
|
|||||||
@@ -345,9 +345,14 @@
|
|||||||
:errors {:type '(list :import_ledger_entry_result)}
|
:errors {:type '(list :import_ledger_entry_result)}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
:upcoming_transaction {:fields {:amount {:type :money}
|
||||||
|
:date {:type :iso_date}}}
|
||||||
|
|
||||||
:cash_flow_result {:fields {:beginning_balance {:type :money}
|
:cash_flow_result {:fields {:beginning_balance {:type :money}
|
||||||
:invoices_due_soon {:type '(list :invoice)}
|
:invoices_due_soon {:type '(list :invoice)}
|
||||||
:outstanding_payments {:type :money}}}
|
:outstanding_payments {:type :money}
|
||||||
|
:upcoming_credits {:type '(list :upcoming_transaction)}
|
||||||
|
:upcoming_debits {:type '(list :upcoming_transaction)}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -363,7 +368,7 @@
|
|||||||
|
|
||||||
:run_transaction_rule {:type '(list :transaction)
|
:run_transaction_rule {:type '(list :transaction)
|
||||||
:args {:transaction_rule_id {:type :id}}
|
:args {:transaction_rule_id {:type :id}}
|
||||||
:resolve :run-transaction-rule}
|
:resolve :run-transaction-rule}
|
||||||
|
|
||||||
:invoice_stats {:type '(list :invoice_stat)
|
:invoice_stats {:type '(list :invoice_stat)
|
||||||
:args {:client_id {:type :id}}
|
:args {:client_id {:type :id}}
|
||||||
@@ -893,46 +898,55 @@
|
|||||||
(- total outstanding-balance))})))
|
(- total outstanding-balance))})))
|
||||||
|
|
||||||
(defn get-cash-flow [context {:keys [client_id]} value]
|
(defn get-cash-flow [context {:keys [client_id]} value]
|
||||||
(let [total-cash (reduce
|
(when client_id
|
||||||
(fn [total [credit debit]]
|
(let [total-cash (reduce
|
||||||
(- (+ total credit)
|
(fn [total [credit debit]]
|
||||||
debit))
|
(- (+ total credit)
|
||||||
0.0
|
debit))
|
||||||
(d/query {:query {:find '[?debit ?credit]
|
0.0
|
||||||
:in '[$ ?client]
|
(d/query {:query {:find '[?debit ?credit]
|
||||||
:where ['[?j :journal-entry/client ?client]
|
:in '[$ ?client]
|
||||||
'[?j :journal-entry/line-items ?je]
|
:where ['[?j :journal-entry/client ?client]
|
||||||
'[?je :journal-entry-line/account ?ba]
|
'[?j :journal-entry/line-items ?je]
|
||||||
'[?ba :bank-account/type :bank-account-type/check]
|
'[?je :journal-entry-line/account ?ba]
|
||||||
'[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit]
|
'[?ba :bank-account/type :bank-account-type/check]
|
||||||
'[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]]}
|
'[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit]
|
||||||
:args [(d/db (d/connect uri)) client_id]}))
|
'[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]]}
|
||||||
bills-due-soon (d/query {:query {:find '[?due ?outstanding]
|
:args [(d/db (d/connect uri)) client_id]}))
|
||||||
:in '[$ ?client ?due-before]
|
bills-due-soon (d/query {:query {:find '[?due ?outstanding]
|
||||||
:where ['[?i :invoice/client ?client]
|
:in '[$ ?client ?due-before]
|
||||||
'[?i :invoice/status :invoice-status/unpaid]
|
:where ['[?i :invoice/client ?client]
|
||||||
'[?i :invoice/due ?due]
|
'[?i :invoice/status :invoice-status/unpaid]
|
||||||
'[(<= ?due ?due-before)]
|
'[?i :invoice/due ?due]
|
||||||
'[?i :invoice/outstanding-balance ?outstanding]]}
|
'[(<= ?due ?due-before)]
|
||||||
:args [(d/db (d/connect uri)) client_id (coerce/to-date (t/plus (time/local-now) (t/days 7)))]})
|
'[?i :invoice/outstanding-balance ?outstanding]]}
|
||||||
outstanding-checks (reduce
|
:args [(d/db (d/connect uri)) client_id (coerce/to-date (t/plus (time/local-now) (t/days 7)))]})
|
||||||
+
|
outstanding-checks (reduce
|
||||||
0.0
|
+
|
||||||
(map first (d/query {:query {:find '[?amount]
|
0.0
|
||||||
:in '[$ ?client ?due-before]
|
(map first (d/query {:query {:find '[?amount]
|
||||||
:where ['[?p :payment/client ?client]
|
:in '[$ ?client ?due-before]
|
||||||
'[?p :payment/status :payment-status/pending]
|
:where ['[?p :payment/client ?client]
|
||||||
'[?p :payment/amount ?amount]
|
'[?p :payment/status :payment-status/pending]
|
||||||
'(or
|
'[?p :payment/amount ?amount]
|
||||||
[?p :payment/type :payment-type/debit]
|
'(or
|
||||||
[?p :payment/type :payment-type/check])]}
|
[?p :payment/type :payment-type/debit]
|
||||||
:args [(d/db (d/connect uri)) client_id (coerce/to-date (t/plus (auto-ap.time/local-now) (t/days 7)))]})))]
|
[?p :payment/type :payment-type/check])]}
|
||||||
{:beginning_balance total-cash
|
:args [(d/db (d/connect uri)) client_id (coerce/to-date (t/plus (auto-ap.time/local-now) (t/days 7)))]})))]
|
||||||
:outstanding_payments outstanding-checks
|
{:beginning_balance total-cash
|
||||||
:invoices_due_soon (mapv (fn [[due outstanding]]
|
:outstanding_payments outstanding-checks
|
||||||
{:due (coerce/to-date-time due)
|
:invoices_due_soon (mapv (fn [[due outstanding]]
|
||||||
:outstanding_balance outstanding})
|
{:due (coerce/to-date-time due)
|
||||||
bills-due-soon)}))
|
:outstanding_balance outstanding})
|
||||||
|
bills-due-soon)
|
||||||
|
:upcoming_credits [{:amount 350000.23
|
||||||
|
:date (coerce/to-date-time (t/plus (auto-ap.time/local-now) (t/days 0)))}
|
||||||
|
{:amount 105000.23
|
||||||
|
:date (coerce/to-date-time (t/plus (auto-ap.time/local-now) (t/days 3)))}]
|
||||||
|
:upcoming_debits [{:amount -120000.23
|
||||||
|
:date (coerce/to-date-time (t/plus (auto-ap.time/local-now) (t/days 5)))}
|
||||||
|
{:amount -35000.23
|
||||||
|
:date (coerce/to-date-time (t/plus (auto-ap.time/local-now) (t/days 4)))}]})))
|
||||||
|
|
||||||
(def schema
|
(def schema
|
||||||
(-> integreat-schema
|
(-> integreat-schema
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
(def cell (r/adapt-react-class js/Recharts.Cell))
|
(def cell (r/adapt-react-class js/Recharts.Cell))
|
||||||
(def tool-tip (r/adapt-react-class js/Recharts.Tooltip))
|
(def tool-tip (r/adapt-react-class js/Recharts.Tooltip))
|
||||||
|
|
||||||
(def colors ["hsl(171, 100%, 41%)" "hsl(217, 71%, 53%)" "hsl(141, 71%, 48%)" "hsl(48, 100%, 67%)" "hsl(348, 100%, 61%)" "hsl(217, 71%, 53%)"])
|
(def colors ["hsl(171, 100%, 41%)" "hsl(217, 71%, 53%)" "hsl(141, 71%, 48%)" "hsl(48, 100%, 67%)" "hsl(348, 100%, 61%)" "hsl(217, 71%, 53%)" "hsl(141, 53%, 53%)"])
|
||||||
(def light-colors ["hsl(171, 60%, 80%)" "hsl(217, 71%, 53%)" "hsl(141, 71%, 48%)" "hsl(48, 100%, 67%)" "hsl(348, 100%, 61%)" "hsl(217, 71%, 53%)"])
|
(def light-colors ["hsl(171, 60%, 80%)" "hsl(217, 71%, 53%)" "hsl(141, 71%, 48%)" "hsl(48, 100%, 67%)" "hsl(348, 100%, 61%)" "hsl(217, 71%, 53%)"])
|
||||||
|
|
||||||
(defn make-pie-chart
|
(defn make-pie-chart
|
||||||
@@ -61,7 +61,10 @@
|
|||||||
:on-click redirect-fn}]
|
:on-click redirect-fn}]
|
||||||
[bar {:dataKey "invoices" :fill (get colors 3) :stackId "a" :name "Invoices"
|
[bar {:dataKey "invoices" :fill (get colors 3) :stackId "a" :name "Invoices"
|
||||||
:on-click redirect-fn}]
|
:on-click redirect-fn}]
|
||||||
|
[bar {:dataKey "credits" :fill (get colors 2) :stackId "a" :name "Upcoming Credits"
|
||||||
|
:on-click redirect-fn}]
|
||||||
|
[bar {:dataKey "debits" :fill (get colors 4) :stackId "a" :name "Upcoming Debits"
|
||||||
|
:on-click redirect-fn}]
|
||||||
[x-axis {:dataKey "name"}]
|
[x-axis {:dataKey "name"}]
|
||||||
[y-axis]
|
[y-axis]
|
||||||
[legend]])
|
[legend]])
|
||||||
@@ -98,37 +101,51 @@
|
|||||||
(fn [db]
|
(fn [db]
|
||||||
(::top-expense-categories db)))
|
(::top-expense-categories db)))
|
||||||
|
|
||||||
|
(defn sum-by-date [pairs]
|
||||||
|
(reduce
|
||||||
|
(fn [result [date amount]]
|
||||||
|
(let [due (if (t/before? date (local-now))
|
||||||
|
(local-now)
|
||||||
|
date)]
|
||||||
|
(update result (date->str due)
|
||||||
|
(fn [r] (+ (or r 0.0) (js/parseFloat amount))))))
|
||||||
|
{}
|
||||||
|
pairs))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
::cash-flow
|
::cash-flow
|
||||||
(fn [db]
|
(fn [db]
|
||||||
(let [{:keys [outstanding-payments beginning-balance invoices-due-soon]} (::cash-flow db)
|
(let [{:keys [outstanding-payments beginning-balance invoices-due-soon upcoming-credits upcoming-debits]} (::cash-flow db)
|
||||||
invoices-due-soon (reduce
|
invoices-due-soon (sum-by-date (map (fn [i] [(:due i) (:outstanding-balance i)]) invoices-due-soon))
|
||||||
(fn [result invoice]
|
upcoming-credits (sum-by-date (map (fn [i] [(:date i) (:amount i)]) upcoming-credits))
|
||||||
(let [due (if (t/before? (:due invoice) (local-now))
|
upcoming-debits (sum-by-date (map (fn [i] [(:date i) (:amount i)]) upcoming-debits))
|
||||||
(local-now)
|
|
||||||
(:due invoice))]
|
|
||||||
(update result (date->str due)
|
|
||||||
(fn [r] (+ (or r 0.0) (:outstanding-balance invoice))))))
|
|
||||||
{}
|
|
||||||
invoices-due-soon)
|
|
||||||
start-date (local-now)
|
start-date (local-now)
|
||||||
effective-balance (- beginning-balance outstanding-payments (invoices-due-soon (date->str start-date) 0.0))
|
effective-balance (- beginning-balance outstanding-payments (invoices-due-soon (date->str start-date) 0.0))]
|
||||||
]
|
|
||||||
|
|
||||||
(reverse
|
(reverse
|
||||||
(reduce
|
(reduce
|
||||||
(fn [[{:keys [effective-balance] } :as acc] day]
|
(fn [[{:keys [effective-balance credits-yesterday] } :as acc] day]
|
||||||
(let [invoices-due-today (invoices-due-soon (date->str (t/plus start-date (t/days day))) 0.0)]
|
(let [invoices-due-today (invoices-due-soon (date->str (t/plus start-date (t/days day))) 0.0)
|
||||||
|
credits-due-today (upcoming-credits (date->str (t/plus start-date (t/days day))) 0.0)
|
||||||
|
debits-due-today (upcoming-debits (date->str (t/plus start-date (t/days day))) 0.0)]
|
||||||
(let [today (t/plus start-date (t/days day))]
|
(let [today (t/plus start-date (t/days day))]
|
||||||
(conj acc
|
(conj acc
|
||||||
{:name (date->str today)
|
{:name (date->str today)
|
||||||
:effective-balance (- effective-balance invoices-due-today)
|
:effective-balance (+ (- effective-balance invoices-due-today )
|
||||||
|
debits-due-today
|
||||||
|
credits-yesterday)
|
||||||
|
:credits-yesterday credits-due-today
|
||||||
|
:credits credits-due-today
|
||||||
|
:debits debits-due-today
|
||||||
:invoices (- invoices-due-today)
|
:invoices (- invoices-due-today)
|
||||||
:query-params (cemerick.url/map->query {:due-range {:start (date->str today standard)
|
:query-params (cemerick.url/map->query {:due-range {:start (date->str today standard)
|
||||||
:end (date->str today standard)}})}))))
|
:end (date->str today standard)}})}))))
|
||||||
(list {:name (date->str start-date)
|
(list {:name (date->str start-date)
|
||||||
:effective-balance effective-balance
|
:effective-balance effective-balance
|
||||||
:invoices (- (invoices-due-soon (date->str start-date) 0.0))
|
:invoices (- (invoices-due-soon (date->str start-date) 0.0))
|
||||||
|
:credits (upcoming-credits (date->str start-date) 0.0)
|
||||||
|
:credits-yesterday (upcoming-credits (date->str start-date) 0.0)
|
||||||
|
:debits (upcoming-debits (date->str start-date) 0.0)
|
||||||
:outstanding-payments (- outstanding-payments)
|
:outstanding-payments (- outstanding-payments)
|
||||||
:query-params (cemerick.url/map->query {:due-range {:end (date->str start-date standard)}})})
|
:query-params (cemerick.url/map->query {:due-range {:end (date->str start-date standard)}})})
|
||||||
(range 1 7))))))
|
(range 1 7))))))
|
||||||
@@ -146,7 +163,11 @@
|
|||||||
[:name :paid :unpaid]]
|
[:name :paid :unpaid]]
|
||||||
[:cash-flow
|
[:cash-flow
|
||||||
{:client-id (:id @(re-frame/subscribe [::subs/client]))}
|
{:client-id (:id @(re-frame/subscribe [::subs/client]))}
|
||||||
[:beginning-balance :outstanding-payments [:invoices-due-soon [:due :outstanding-balance]]]]]}
|
[:beginning-balance
|
||||||
|
:outstanding-payments
|
||||||
|
[:invoices-due-soon [:due :outstanding-balance]]
|
||||||
|
[:upcoming-credits [:date :amount]]
|
||||||
|
[:upcoming-debits [:date :amount]]]]]}
|
||||||
:on-success [::received]}}))
|
:on-success [::received]}}))
|
||||||
|
|
||||||
(defn home-content []
|
(defn home-content []
|
||||||
|
|||||||
Reference in New Issue
Block a user