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