You can now see cash flow details
This commit is contained in:
@@ -1020,13 +1020,15 @@
|
||||
'[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit]
|
||||
'[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]]}
|
||||
:args [(d/db (d/connect uri)) client_id]}))
|
||||
bills-due-soon (d/query {:query {:find '[?due ?outstanding]
|
||||
bills-due-soon (d/query {:query {:find '[?due ?outstanding ?invoice-number ?vendor-id]
|
||||
:in '[$ ?client ?due-before]
|
||||
:where ['[?i :invoice/client ?client]
|
||||
'[?i :invoice/status :invoice-status/unpaid]
|
||||
'[?i :invoice/due ?due]
|
||||
'[(<= ?due ?due-before)]
|
||||
'[?i :invoice/outstanding-balance ?outstanding]]}
|
||||
'[?i :invoice/outstanding-balance ?outstanding]
|
||||
'[?i :invoice/invoice-number ?invoice-number]
|
||||
'[?i :invoice/vendor ?vendor-id]]}
|
||||
:args [(d/db (d/connect uri)) client_id (coerce/to-date (t/plus (time/local-now) (t/days 180)))]})
|
||||
outstanding-checks (reduce
|
||||
+
|
||||
@@ -1063,8 +1065,10 @@
|
||||
|
||||
{:beginning_balance total-cash
|
||||
:outstanding_payments outstanding-checks
|
||||
:invoices_due_soon (mapv (fn [[due outstanding]]
|
||||
:invoices_due_soon (mapv (fn [[due outstanding invoice-number vendor-id]]
|
||||
{:due (coerce/to-date-time due)
|
||||
:invoice_number invoice-number
|
||||
:vendor {:id vendor-id}
|
||||
:outstanding_balance outstanding})
|
||||
bills-due-soon)
|
||||
:upcoming_credits (into (mapv
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
(ns auto-ap.views.components.buttons
|
||||
(:require [auto-ap.views.utils :refer [dispatch-event]]))
|
||||
(:require [auto-ap.views.utils :refer [dispatch-event]]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(defn fa-icon [{:keys [event icon class]}]
|
||||
[:a.button {:class class
|
||||
:on-click (dispatch-event event)} [:span.icon [:i.fa {:class icon}]]])
|
||||
:on-click (dispatch-event event)} (into
|
||||
[:<>
|
||||
[:span.icon [:i.fa {:class icon}]]
|
||||
]
|
||||
(r/children (r/current-component)))])
|
||||
|
||||
(defn sl-icon [{:keys [event icon class] :as params}]
|
||||
[:a.button (-> params
|
||||
(dissoc :event :icon)
|
||||
(assoc :on-click (dispatch-event event)))
|
||||
[:span.icon [:span {:class icon :style {:font-weight "400"}}]]])
|
||||
|
||||
(defn new-button [{:keys [event name class ]}]
|
||||
[:a.button.is-outlined {:class class
|
||||
:on-click (dispatch-event event)}
|
||||
[:span.icon [:i.fa.fa-plus]]
|
||||
[:span name]])
|
||||
|
||||
@@ -121,12 +121,13 @@
|
||||
(mapv (fn [c]
|
||||
[:div.level-item c]) children))]]))))]))
|
||||
|
||||
(defn table [{:keys [fullwidth class]}]
|
||||
(defn table [{:keys [fullwidth class style]}]
|
||||
|
||||
(into
|
||||
[:table.table.compact.grid {:class (cond-> []
|
||||
fullwidth (conj "is-fullwidth")
|
||||
class (into class))}]
|
||||
class (into class))
|
||||
:style style}]
|
||||
(r/children (r/current-component))))
|
||||
|
||||
(defn header []
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.pages.invoices.form :as form]
|
||||
[auto-ap.views.pages.invoices.common :refer [invoice-read]]
|
||||
[auto-ap.views.utils :refer [date->str dispatch-event nf]]
|
||||
[auto-ap.views.utils :refer [date->str dispatch-event nf days-until]]
|
||||
[bidi.bidi :as bidi]
|
||||
[cemerick.url :as url]
|
||||
[cljs-time.core :as t]
|
||||
@@ -106,11 +106,7 @@
|
||||
[grid/cell {} (date->str date) ]
|
||||
[grid/cell {}
|
||||
(when due
|
||||
(let [today (t/at-midnight (t/now))
|
||||
due (t/at-midnight due)
|
||||
due-in (if (t/after? today due)
|
||||
(- (t/in-days (t/interval (t/minus due (t/days 1)) today)))
|
||||
(t/in-days (t/interval today due )))]
|
||||
(let [due-in (days-until due)]
|
||||
(if (> due-in 0)
|
||||
[:span.has-text-success due-in " days"]
|
||||
[:span.has-text-danger due-in " days"])
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
[auto-ap.entities.vendors :as vendor]
|
||||
[clojure.string :as str]
|
||||
[reagent.core :as r]
|
||||
[auto-ap.views.components.vendor-dialog :as vendor-dialog]))
|
||||
[auto-ap.views.components.vendor-dialog :as vendor-dialog]
|
||||
[auto-ap.views.components.buttons :as buttons]))
|
||||
|
||||
|
||||
(defn navbar-drop-down-contents [{:keys [id]} children ]
|
||||
@@ -128,9 +129,9 @@
|
||||
(when-not is-initial-loading
|
||||
[:div.navbar-end
|
||||
[:div.navbar-item
|
||||
[:a.button.is-primary.is-outlined
|
||||
{:on-click (dispatch-event [::vendor-dialog/started {}])}
|
||||
[:span.icon [:i.fa.fa-plus] ] [:span "Vendor"]]]
|
||||
[buttons/new-button {:event [::vendor-dialog/started {}]
|
||||
:name "Vendor"
|
||||
:class "is-primary"}]]
|
||||
|
||||
|
||||
(when (> (count @clients) 1)
|
||||
|
||||
@@ -110,10 +110,12 @@
|
||||
[:div
|
||||
[:h1.title "Accounts"]
|
||||
[:div.is-pulled-right
|
||||
[:a.button.is-success {:on-click (dispatch-event [::account-form/editing
|
||||
{:type :asset
|
||||
:account-set "default"}
|
||||
[::edit-completed]])} "New Account"]]
|
||||
[buttons/new-button {:name "Account"
|
||||
:class "is-primary"
|
||||
:event [::account-form/editing
|
||||
{:type :asset
|
||||
:account-set "default"}
|
||||
[::edit-completed]]}]]
|
||||
[accounts-table {:accounts @(re-frame/subscribe [::account-page])}]])
|
||||
|
||||
(defn admin-accounts-page []
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
(ns auto-ap.views.pages.home
|
||||
(:require [auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[re-frame.core :as re-frame]
|
||||
[bidi.bidi :as bidi]
|
||||
[auto-ap.routes :as routes]
|
||||
(:require [auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[auto-ap.views.utils
|
||||
:refer
|
||||
[->$ date->str days-until dispatch-event local-now standard]]
|
||||
[bidi.bidi :as bidi]
|
||||
[cljs-time.coerce :as coerce]
|
||||
[cljs-time.core :as t]
|
||||
[auto-ap.views.utils :refer [local-now date->str standard dispatch-event]]
|
||||
[reagent.core :as r]
|
||||
[pushy.core :as pushy]
|
||||
))
|
||||
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(def pie-chart (r/adapt-react-class js/Recharts.PieChart))
|
||||
(def pie (r/adapt-react-class js/Recharts.Pie))
|
||||
@@ -129,6 +131,16 @@
|
||||
(fn [db]
|
||||
(::cash-flow db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::cash-flow-table-params
|
||||
(fn [db]
|
||||
(::cash-flow-table-params db)))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::cash-flow-table-params-changed
|
||||
(fn [db [_ new]]
|
||||
(assoc db ::cash-flow-table-params new)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::cash-flow
|
||||
:<- [::chart-options]
|
||||
@@ -150,6 +162,7 @@
|
||||
(let [today (t/plus start-date (t/days day))]
|
||||
(conj acc
|
||||
{:name (date->str today)
|
||||
:date today
|
||||
:effective-balance (+ (- effective-balance invoices-due-today )
|
||||
debits-due-today
|
||||
credits-yesterday)
|
||||
@@ -160,6 +173,7 @@
|
||||
:query-params (cemerick.url/map->query {:due-range {:start (date->str today standard)
|
||||
:end (date->str today standard)}})}))))
|
||||
(list {:name (date->str start-date)
|
||||
:date start-date
|
||||
:effective-balance effective-balance
|
||||
:invoices (- (invoices-due-soon (date->str start-date) 0.0))
|
||||
:credits (upcoming-credits (date->str start-date) 0.0)
|
||||
@@ -188,6 +202,38 @@
|
||||
:one-hundred-eighty-days
|
||||
(range 1 181)))))))
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::cash-flow-page
|
||||
:<- [::cash-flow-table-params]
|
||||
:<- [::cash-flow-data]
|
||||
:<- [::subs/vendors-by-id]
|
||||
(fn [[params cash-flow-data vendors-by-id]]
|
||||
(let [ {:keys [outstanding-payments invoices-due-soon upcoming-credits upcoming-debits]} cash-flow-data
|
||||
rows (concat (map (fn [c]
|
||||
{:date (:date c)
|
||||
:days-until (days-until (:date c))
|
||||
:name (or (:identifier c) "Bi-weekly Average")
|
||||
:amount (:amount c)
|
||||
:type "Debit"}) upcoming-debits)
|
||||
(map (fn [c]
|
||||
{:date (:date c)
|
||||
:days-until (days-until (:date c))
|
||||
:amount (:amount c)
|
||||
:name (or (:identifier c) "Bi-weekly Average")
|
||||
:type "Credit"})
|
||||
upcoming-credits)
|
||||
(map (fn [c]
|
||||
{:date (:due c)
|
||||
:days-until (days-until (:due c))
|
||||
:amount (:outstanding-balance c)
|
||||
:name (str (:name (get vendors-by-id (:id (:vendor c)))) " (" (:invoice-number c) ")")
|
||||
:type "Invoice"})
|
||||
invoices-due-soon))]
|
||||
(assoc (grid/virtual-paginate-controls (:start params ) rows)
|
||||
:data (grid/virtual-paginate (:start params)
|
||||
(sort-by (comp coerce/to-date :date) rows))))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [{:keys [db]} _]
|
||||
@@ -203,9 +249,9 @@
|
||||
{:client-id (:id @(re-frame/subscribe [::subs/client]))}
|
||||
[:beginning-balance
|
||||
:outstanding-payments
|
||||
[:invoices-due-soon [:due :outstanding-balance]]
|
||||
[:upcoming-credits [:date :amount]]
|
||||
[:upcoming-debits [:date :amount]]]]]}
|
||||
[:invoices-due-soon [:due :outstanding-balance [:vendor [:id]] :invoice-number]]
|
||||
[:upcoming-credits [:date :amount :identifier]]
|
||||
[:upcoming-debits [:date :amount :identifier]]]]]}
|
||||
:on-success [::received]}}))
|
||||
|
||||
(defn cash-flow-range-button [{:keys [name value chart-options]}]
|
||||
@@ -214,6 +260,40 @@
|
||||
:on-click (dispatch-event [::select-cash-flow-range value])}
|
||||
name])
|
||||
|
||||
(defn cash-flow-grid []
|
||||
(let [page @(re-frame/subscribe [::cash-flow-page])
|
||||
opc (fn [p]
|
||||
(re-frame/dispatch [::cash-flow-table-params-changed p]))
|
||||
params @(re-frame/subscribe [::cash-flow-table-params])]
|
||||
[grid/grid {:status {:state :complete}
|
||||
:on-params-change opc
|
||||
:params params
|
||||
:column-count 4}
|
||||
[grid/controls page]
|
||||
[grid/table {:style {:width "800px"}}
|
||||
[grid/header
|
||||
[grid/row {}
|
||||
[grid/header-cell {} "Date"]
|
||||
[grid/header-cell {} "Type"]
|
||||
[grid/header-cell {} "Name"]
|
||||
[grid/header-cell {:class "has-text-right"} "Amount"]]]
|
||||
[grid/body
|
||||
(for [{:keys [date days-until type name amount] } (:data page)]
|
||||
^{:key date}
|
||||
[grid/row {}
|
||||
[grid/cell {}
|
||||
(if (> days-until 0)
|
||||
[:span.has-text-success days-until " days"]
|
||||
[:span.has-text-danger days-until " days"])
|
||||
[:i.is-size-7 " (" (date->str date) ")"] ]
|
||||
[grid/cell {} (if (> date 0)
|
||||
"Upcoming "
|
||||
"Due ")
|
||||
type]
|
||||
[grid/cell {} name]
|
||||
[grid/cell {:class "has-text-right"} (->$ amount)]
|
||||
])]]]))
|
||||
|
||||
(defn home-content []
|
||||
(let [client-id (-> @(re-frame/subscribe [::subs/client]) :id)
|
||||
chart-options @(re-frame/subscribe [::chart-options])]
|
||||
@@ -256,7 +336,9 @@
|
||||
|
||||
|
||||
(make-cash-flow-chart {:width 800 :height 500
|
||||
:data (clj->js @(re-frame/subscribe [::cash-flow]))})]}]))
|
||||
:data (clj->js @(re-frame/subscribe [::cash-flow]))})
|
||||
|
||||
[cash-flow-grid]]}]))
|
||||
|
||||
|
||||
(defn home-page []
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
[goog.string :as gstring]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as r]
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.views.components.buttons :as buttons]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
@@ -135,7 +136,10 @@
|
||||
[:div
|
||||
[:div.is-pulled-right
|
||||
[:div.buttons
|
||||
[:button.button.is-outlined.is-primary {:on-click (dispatch-event [::new-invoice-clicked])} "New Invoice"]
|
||||
[buttons/new-button {:event [::new-invoice-clicked]
|
||||
:name "Invoice"
|
||||
:class "is-primary"}]
|
||||
|
||||
(when current-client
|
||||
[drop-down {:header [:button.button.is-primary {:aria-haspopup true
|
||||
:on-click (dispatch-event [::events/toggle-menu ::print-checks ])
|
||||
|
||||
@@ -456,3 +456,11 @@
|
||||
|
||||
(defn action-cell-width [cnt]
|
||||
(str (inc (* cnt 51)) "px"))
|
||||
|
||||
(defn days-until [d]
|
||||
(let [today (t/at-midnight (t/now))
|
||||
d (t/at-midnight d)
|
||||
in (if (t/after? today d)
|
||||
(- (t/in-days (t/interval (t/minus d (t/days 1)) today)))
|
||||
(t/in-days (t/interval today d )))]
|
||||
in))
|
||||
|
||||
Reference in New Issue
Block a user