(cloud) big performance improvements for page load.
This commit is contained in:
@@ -1,10 +1,46 @@
|
||||
(ns auto-ap.datomic.clients
|
||||
(:require
|
||||
[auto-ap.datomic :refer [conn]]
|
||||
[auto-ap.datomic :refer [add-sorter-fields
|
||||
apply-pagination
|
||||
apply-sort-3
|
||||
conn
|
||||
merge-query
|
||||
pull-many]]
|
||||
[auto-ap.graphql.utils :refer [can-see-client? limited-clients]]
|
||||
[auto-ap.search :as search]
|
||||
[clj-time.coerce :as coerce]
|
||||
[clojure.string :as str]
|
||||
[datomic.client.api :as dc]))
|
||||
[datomic.client.api :as dc]
|
||||
[com.brunobonacci.mulog :as mu]))
|
||||
|
||||
(def full-read '[*
|
||||
{:client/square-integration-status [:integration-status/message
|
||||
:integration-status/last-attempt
|
||||
:integration-status/last-updated
|
||||
:db/id
|
||||
{:integration-status/state [:db/ident]}]}
|
||||
{:client/address [*]}
|
||||
{:client/square-locations [:square-location/square-id
|
||||
:square-location/name
|
||||
:square-location/client-location
|
||||
:db/id]}
|
||||
|
||||
{:client/ezcater-locations [{:ezcater-location/caterer [:ezcater-caterer/name :db/id]}
|
||||
:ezcater-location/location
|
||||
:db/id]}
|
||||
{:client/bank-accounts [* {:bank-account/type [*]
|
||||
:bank-account/yodlee-account [:yodlee-account/name :yodlee-account/id :yodlee-account/number]
|
||||
:bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance]
|
||||
:bank-account/intuit-bank-account [:intuit-bank-account/name :intuit-bank-account/external-id :db/id]
|
||||
:bank-account/integration-status [:integration-status/message
|
||||
:db/id
|
||||
:integration-status/last-attempt
|
||||
:integration-status/last-updated
|
||||
{:integration-status/state [:db/ident]}]}
|
||||
]}
|
||||
{:yodlee-provider-account/_client [*]}
|
||||
{:plaid-item/_client [*]}
|
||||
{:client/emails [:db/id :email-contact/email :email-contact/description]}])
|
||||
|
||||
(defn cleanse [e]
|
||||
(-> e
|
||||
@@ -29,52 +65,25 @@
|
||||
(update :bank-account/sort-order (fn [so] (or so i)))))
|
||||
(range) bas)))))
|
||||
(defn get-all []
|
||||
(->> (dc/q '[:find (pull ?e [*
|
||||
{:client/square-integration-status [:integration-status/message
|
||||
:integration-status/last-attempt
|
||||
:integration-status/last-updated
|
||||
:db/id
|
||||
{:integration-status/state [:db/ident]}]}
|
||||
{:client/address [*]}
|
||||
{:client/square-locations [:square-location/square-id
|
||||
:square-location/name
|
||||
:square-location/client-location
|
||||
:db/id]}
|
||||
|
||||
{:client/ezcater-locations [{:ezcater-location/caterer [:ezcater-caterer/name :db/id]}
|
||||
:ezcater-location/location
|
||||
:db/id]}
|
||||
{:client/bank-accounts [* {:bank-account/type [*]
|
||||
:bank-account/yodlee-account [:yodlee-account/name :yodlee-account/id :yodlee-account/number]
|
||||
:bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance]
|
||||
:bank-account/intuit-bank-account [:intuit-bank-account/name :intuit-bank-account/external-id :db/id]
|
||||
:bank-account/integration-status [:integration-status/message
|
||||
:db/id
|
||||
:integration-status/last-attempt
|
||||
:integration-status/last-updated
|
||||
{:integration-status/state [:db/ident]}]}
|
||||
]}
|
||||
{:yodlee-provider-account/_client [*]}
|
||||
{:plaid-item/_client [*]}
|
||||
{:client/emails [:db/id :email-contact/email :email-contact/description]}])
|
||||
(->> (dc/q '[:find (pull ?e ?r)
|
||||
:in $ ?r
|
||||
:where [?e :client/name]]
|
||||
(dc/db conn))
|
||||
(dc/db conn)
|
||||
full-read)
|
||||
(map first)
|
||||
(map cleanse)))
|
||||
|
||||
(defn get-minimal []
|
||||
(->> (dc/q '[:find (pull ?e [:client/name :client/code :client/locations :db/id {:client/bank-accounts [{:bank-account/type [:db/ident]} :bank-account/name :bank-account/code :db/id]}])
|
||||
:where [?e :client/name]]
|
||||
(dc/db conn))
|
||||
(map first)
|
||||
(map cleanse)))
|
||||
|
||||
(defn get-by-id [id]
|
||||
(->>
|
||||
(dc/pull (dc/db conn )
|
||||
'[* {:client/bank-accounts [* {:bank-account/type [*]
|
||||
:bank-account/yodlee-account [:yodlee-account/name :yodlee-account/id :yodlee-account/number]
|
||||
:bank-account/intuit-bank-account [:intuit-bank-account/name :intuit-bank-account/external-id :db/id]
|
||||
:bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance]}]
|
||||
:client/emails [:db/id :email-contact/email :email-contact/description]}
|
||||
{:client/ezcater-locations [{:ezcater-location/caterer [:ezcater-caterer/name :db/id]}
|
||||
:ezcater-location/location
|
||||
:db/id]}
|
||||
{:yodlee-provider-account/_client [*]}
|
||||
{:plaid-item/_client [*]}]
|
||||
full-read
|
||||
id)
|
||||
(cleanse)))
|
||||
|
||||
@@ -105,3 +114,54 @@
|
||||
:text match
|
||||
:exact-match (str/upper-case match)})
|
||||
"client"))
|
||||
|
||||
|
||||
(defn raw-graphql-ids [db args]
|
||||
(let [query (cond-> {:query {:find []
|
||||
:in ['$ ]
|
||||
:where []}
|
||||
:args [db]}
|
||||
|
||||
|
||||
(not (str/blank? (:code args)))
|
||||
(merge-query {:query {:in ['?client-code]
|
||||
:where ['[?e :client/code ?client-code]]}
|
||||
:args [(:code args)]})
|
||||
|
||||
(not (str/blank? (:name-like args)))
|
||||
(merge-query {:query {:in ['?name-like]
|
||||
:where ['[?e :client/name ?name]
|
||||
'[(clojure.string/includes? ?name ?name-like)]]}
|
||||
:args [(:name-like args)]})
|
||||
|
||||
(limited-clients (:id args))
|
||||
(merge-query {:query {:in ['[?e ...]]
|
||||
:where []}
|
||||
:args [(set (map :db/id (limited-clients (:id args))))]})
|
||||
|
||||
|
||||
(:sort args) (add-sorter-fields {"name" ['[?e :client/name ?sort-name]]}
|
||||
args)
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e] :where ['[?e :client/name ?sort-default]]}}))]
|
||||
(mu/log ::q
|
||||
:query query)
|
||||
(->> query
|
||||
(dc/q)
|
||||
(apply-sort-3 (update args :sort conj {:sort-key "default-2" :asc true}))
|
||||
(apply-pagination args))))
|
||||
|
||||
(defn graphql-results [ids db args]
|
||||
(let [results (->> (pull-many db full-read
|
||||
ids)
|
||||
(map cleanse))]
|
||||
results))
|
||||
|
||||
|
||||
(defn get-graphql-page [args]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
|
||||
[(->> (graphql-results ids-to-retrieve db args))
|
||||
matching-count]))
|
||||
|
||||
@@ -9,11 +9,10 @@
|
||||
pull-many
|
||||
visible-clients
|
||||
conn]]
|
||||
[auto-ap.graphql.utils :refer [limited-clients]]
|
||||
[iol-ion.query]
|
||||
[clj-time.coerce :as c]
|
||||
[clj-time.core :as time]
|
||||
[clojure.set :as set]
|
||||
[clojure.tools.logging :as log]
|
||||
[datomic.client.api :as dc]
|
||||
[com.brunobonacci.mulog :as mu]
|
||||
))
|
||||
|
||||
@@ -699,15 +699,14 @@
|
||||
(- (+ total credit)
|
||||
debit))
|
||||
0.0
|
||||
(dc/q {:query {:find '[?debit ?credit]
|
||||
:in '[$ ?client]
|
||||
:where ['[?j :journal-entry/client ?client]
|
||||
'[?j :journal-entry/line-items ?je]
|
||||
'[?je :journal-entry-line/account ?ba]
|
||||
'[?ba :bank-account/type :bank-account-type/check]
|
||||
'[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit]
|
||||
'[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]]}
|
||||
:args [(dc/db conn) client_id]}))
|
||||
(dc/q {:query {:find '[?debit ?credit]
|
||||
:in '[$ ?client]
|
||||
:where ['[?client :client/bank-accounts ?ba]
|
||||
'[?ba :bank-account/type :bank-account-type/check]
|
||||
'[?je :journal-entry-line/account ?ba]
|
||||
'[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit]
|
||||
'[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]]}
|
||||
:args [(dc/db conn) client_id]}))
|
||||
bills-due-soon (dc/q {:query {:find '[?due ?outstanding ?invoice-number ?vendor-id ?vendor-name]
|
||||
:in '[$ ?client ?due-before]
|
||||
:where ['[?i :invoice/client ?client]
|
||||
@@ -734,8 +733,8 @@
|
||||
recent-fulfillments (dc/q {:query {:find '[?f ?d]
|
||||
:in '[$ ?client ?min-date]
|
||||
:where ['[?t :transaction/forecast-match ?f]
|
||||
'[?t :transaction/date ?d]
|
||||
'[?t :transaction/client ?client]
|
||||
'[?t :transaction/date ?d]
|
||||
'[(>= ?d ?min-date)]]}
|
||||
:args [(dc/db conn) client_id (coerce/to-date (t/plus (time/local-now) (t/months -2)))]})
|
||||
forecasted-transactions (for [{:forecasted-transaction/keys [amount identifier day-of-month]
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
[amazonica.aws.s3 :as s3]
|
||||
[auto-ap.datomic :refer [audit-transact conn]]
|
||||
[auto-ap.datomic.clients :as d-clients]
|
||||
[iol-ion.tx :refer [upsert-entity]]
|
||||
[auto-ap.graphql.utils
|
||||
:refer [->graphql
|
||||
assert-admin
|
||||
attach-tracing-resolvers
|
||||
can-see-client?
|
||||
<-graphql
|
||||
result->page
|
||||
is-admin?]]
|
||||
[auto-ap.routes.queries :as q]
|
||||
[auto-ap.square.core :as square]
|
||||
@@ -18,12 +19,12 @@
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
[clojure.tools.logging :as log]
|
||||
[com.brunobonacci.mulog :as mu]
|
||||
[datomic.client.api :as dc]
|
||||
[unilog.context :as lc]
|
||||
[iol-ion.tx :refer [random-tempid upsert-entity]]
|
||||
[mount.core :as mount]
|
||||
[yang.scheduler :as scheduler]
|
||||
[iol-ion.tx :refer [random-tempid]]
|
||||
[com.brunobonacci.mulog :as mu])
|
||||
[unilog.context :as lc]
|
||||
[yang.scheduler :as scheduler])
|
||||
(:import
|
||||
(java.util UUID)
|
||||
(org.apache.commons.codec.binary Base64)))
|
||||
@@ -200,23 +201,39 @@
|
||||
|
||||
(defn get-client [context _ _]
|
||||
(->graphql
|
||||
(->> (d-clients/get-all)
|
||||
(filter #(can-see-client? (:id context) %))
|
||||
(map (fn [c]
|
||||
(update c :client/bank-accounts (fn [bas]
|
||||
(map #(set/rename-keys % {:bank-account/use-date-instead-of-post-date? :use-date-instead-of-post-date}) bas)))))
|
||||
(map (fn [c]
|
||||
(if (is-admin? (:id context))
|
||||
c
|
||||
(-> c
|
||||
(dissoc :client/yodlee-provider-accounts)
|
||||
(dissoc :client/plaid-items)))))
|
||||
(map (fn [c]
|
||||
(update c :client/bank-accounts
|
||||
(fn [bank-accounts]
|
||||
(mapv (fn [ba]
|
||||
(assoc ba :bank-account/yodlee-balance-old nil))
|
||||
bank-accounts))))))))
|
||||
(->> (d-clients/get-minimal)
|
||||
(filter #(can-see-client? (:id context) %)))))
|
||||
|
||||
(defn get-admin-client [context {:keys [id]} _]
|
||||
(assert-admin (:id context))
|
||||
(->graphql
|
||||
(-> (d-clients/get-by-id id)
|
||||
(update :client/bank-accounts (fn [bas]
|
||||
(map #(set/rename-keys % {:bank-account/use-date-instead-of-post-date? :use-date-instead-of-post-date}) bas))))))
|
||||
|
||||
(defn get-client-page [context args _]
|
||||
(assert-admin (:id context))
|
||||
(let [args (assoc args :id (:id context))
|
||||
[clients clients-count] (d-clients/get-graphql-page (assoc (<-graphql (:filters args))
|
||||
:id (:id context)))
|
||||
clients (->> clients
|
||||
|
||||
(map (fn [c]
|
||||
(update c :client/bank-accounts (fn [bas]
|
||||
(map #(set/rename-keys % {:bank-account/use-date-instead-of-post-date? :use-date-instead-of-post-date}) bas)))))
|
||||
(map (fn [c]
|
||||
(if (is-admin? (:id context))
|
||||
c
|
||||
(-> c
|
||||
(dissoc :client/yodlee-provider-accounts)
|
||||
(dissoc :client/plaid-items)))))
|
||||
(map (fn [c]
|
||||
(update c :client/bank-accounts
|
||||
(fn [bank-accounts]
|
||||
(mapv (fn [ba]
|
||||
(assoc ba :bank-account/yodlee-balance-old nil))
|
||||
bank-accounts))))))]
|
||||
(result->page clients clients-count :clients (:filters args))))
|
||||
|
||||
(def sales-summary-query
|
||||
"[:find ?d4 (sum ?total) (sum ?tax) (sum ?tip) (sum ?service-charge) (sum ?discount) (sum ?returns)
|
||||
@@ -437,6 +454,15 @@
|
||||
:yodlee_provider_accounts {:type '(list :yodlee_provider_account)}
|
||||
:plaid_items {:type '(list :plaid_item)}}}
|
||||
|
||||
:client_page
|
||||
{:fields {:clients {:type '(list :client)}
|
||||
:count {:type 'Int}
|
||||
:total {:type 'Int}
|
||||
:start {:type 'Int}
|
||||
:end {:type 'Int}}}
|
||||
|
||||
|
||||
|
||||
:bank_account
|
||||
{:fields {:id {:type :id}
|
||||
:integration_status {:type :integration_status}
|
||||
@@ -471,7 +497,14 @@
|
||||
|
||||
(def queries
|
||||
{:client {:type '(list :client)
|
||||
:resolve :get-client}})
|
||||
:resolve :get-client}
|
||||
|
||||
:admin_client {:type :client
|
||||
:args {:id {:type :id}}
|
||||
:resolve :get-admin-client}
|
||||
:client_page {:type :client_page
|
||||
:args {:filters {:type :client_filters}}
|
||||
:resolve :get-client-page}})
|
||||
|
||||
(def mutations
|
||||
{:edit_client {:type :client
|
||||
@@ -486,6 +519,13 @@
|
||||
:match {:type 'String}
|
||||
:id {:type :id}}}
|
||||
|
||||
:client_filters
|
||||
{:fields {:code {:type 'String}
|
||||
:name_like {:type 'String}
|
||||
:start {:type 'Int}
|
||||
:per_page {:type 'Int}
|
||||
:sort {:type '(list :sort_item)}}}
|
||||
|
||||
:edit_square_location {:fields {:client_location {:type 'String}
|
||||
:id {:type :id}}}
|
||||
|
||||
@@ -551,6 +591,8 @@
|
||||
|
||||
(def resolvers
|
||||
{:get-client get-client
|
||||
:get-admin-client get-admin-client
|
||||
:get-client-page get-client-page
|
||||
:mutation/edit-client edit-client
|
||||
:mutation/setup-sales-queries setup-sales-queries})
|
||||
|
||||
|
||||
@@ -16,7 +16,13 @@
|
||||
(js->clj (.parse js/JSON (b64/decodeString (second (str/split token #"\." ))))))
|
||||
|
||||
|
||||
(defn client-query [token]
|
||||
(defn client-query []
|
||||
(cond-> [:id :name :code :email :locations :feature-flags
|
||||
[:emails [:id :email :description]]
|
||||
[:bank-accounts [:id :code :bank-name :name :type :visible
|
||||
:locations :include-in-reports :current-balance]]]))
|
||||
|
||||
(defn client-detail-query [token]
|
||||
(cond-> [:id :name :signature-file :code :email :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits :locations :locked-until :square-auth-token :feature-flags
|
||||
[:square-integration-status [:last-updated :last-attempt :message :state :id]]
|
||||
[:square-locations [:square-id :id :name :client-location]]
|
||||
@@ -68,7 +74,7 @@
|
||||
:query-params (auto-ap.views.utils/query-params)
|
||||
:user token)
|
||||
:graphql {:token token
|
||||
:query-obj {:venia/queries [[:client (client-query token)]]}
|
||||
:query-obj {:venia/queries [[:client (client-query)]]}
|
||||
:on-success [::received-initial]
|
||||
:on-error [::failed-initial]}}))))
|
||||
|
||||
@@ -100,7 +106,7 @@
|
||||
(fn [{:keys [db]}]
|
||||
(let [token (-> db :user)]
|
||||
{:graphql {:token token
|
||||
:query-obj {:venia/queries [[:client (client-query token)]]}
|
||||
:query-obj {:venia/queries [[:client (client-query)]]}
|
||||
:on-success [::received-refreshed-clients]}})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.shared-views.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[auto-ap.views.pages.admin.clients.form :as form]
|
||||
@@ -13,8 +14,12 @@
|
||||
[auto-ap.views.utils :refer [with-user]]
|
||||
[bidi.bidi :as bidi]
|
||||
[clojure.string :as str]
|
||||
[clojure.set :as set]
|
||||
[re-frame.core :as re-frame]
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.db :as db]))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::received-intuit-bank-accounts
|
||||
@@ -24,10 +29,15 @@
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
[with-user]
|
||||
(fn [{:keys [user]} _]
|
||||
{::track/register {:id ::params
|
||||
:subscription [::params]
|
||||
:event-fn (fn [params] [::params-change params])}
|
||||
(fn [{:keys [user db]} _]
|
||||
{::track/register [{:id ::params
|
||||
:subscription [::data-page/params ::page]
|
||||
:event-fn (fn [params] [::params-change params])}
|
||||
{:id ::active-route
|
||||
:subscription [::subs/active-route]
|
||||
:event-fn (fn [params] [::params-change params])}]
|
||||
:db (-> db
|
||||
(forms/stop-form [::form/form]))
|
||||
:graphql {:token user
|
||||
:query-obj {:venia/queries [[:intuit_bank_accounts [:external_id :id :name]]]}
|
||||
:owns-state {:single [::load-intuit-bank-accounts]}
|
||||
@@ -37,34 +47,31 @@
|
||||
::unmounted
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (dissoc db ::table/params ::side-bar/filter-params)
|
||||
::track/dispose {:id ::params}}))
|
||||
::track/dispose [{:id ::params}
|
||||
{:id ::active-route}]}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::params
|
||||
:<- [::table/params]
|
||||
:<- [::side-bar/filter-params]
|
||||
(fn [[table-params filter-params]]
|
||||
(cond-> {}
|
||||
(seq filter-params) (merge filter-params)
|
||||
(seq table-params) (merge table-params))))
|
||||
(defn data-params->query-params [params]
|
||||
{:start (:start params 0)
|
||||
:per-page (:per-page params)
|
||||
:sort (:sort params)
|
||||
:name-like (:name-like params)
|
||||
:code (:code params)})
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
(fn [_ [_ params]]
|
||||
{:set-uri-params params}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::page
|
||||
:<- [::params]
|
||||
:<- [::subs/clients]
|
||||
(fn [[params all-clients]]
|
||||
(let [matching-clients (cond->> all-clients
|
||||
(not-empty (:name params)) (filter #(str/includes? (str/lower-case (or (:name %) ""))
|
||||
(str/lower-case (:name params))))
|
||||
(not-empty (:code params)) (filter #(= (str/lower-case (or (:code %) ""))
|
||||
(str/lower-case (:code params)))))]
|
||||
(assoc (grid/virtual-paginate-controls (:start params ) (:per-page params) matching-clients)
|
||||
:data (grid/virtual-paginate (:start params) (:per-page params) matching-clients)))))
|
||||
[with-user]
|
||||
(fn [{:keys [user]} [_ params]]
|
||||
{:graphql {:token user
|
||||
:owns-state {:single [::data-page/page ::page]}
|
||||
:query-obj {:venia/queries [[:client-page
|
||||
{:filters (data-params->query-params params)}
|
||||
[[:clients (events/client-detail-query user)]
|
||||
:total
|
||||
:start
|
||||
:end]]]}
|
||||
:on-success (fn [result]
|
||||
[::data-page/received ::page (set/rename-keys (:client-page result)
|
||||
{:clients :data})])}}))
|
||||
|
||||
(def admin-clients-content
|
||||
(with-meta
|
||||
@@ -77,14 +84,14 @@
|
||||
:content [:<>
|
||||
[:div.is-pulled-right
|
||||
[:a.button.is-primary.is-outlined {:href (bidi/path-for routes/routes :admin-specific-client :id "new")} "New client"]]
|
||||
[table/clients-table {:page @(re-frame/subscribe [::page])
|
||||
:status @(re-frame/subscribe [::status/single ::page])}]]}
|
||||
[table/clients-table {:data-page ::page
|
||||
:id :clients}]]}
|
||||
|
||||
{:key :admin-specific-client
|
||||
:breadcrumb [:span [:a {:href (bidi/path-for routes/routes :admin-clients)}
|
||||
"Clients"]
|
||||
" / "
|
||||
(or (:name @(re-frame/subscribe [::form/client]))
|
||||
(or (:name (:data @(re-frame/subscribe [::forms/form ::form/form])))
|
||||
[:i "New client"])]
|
||||
:content [form/new-client-form]}
|
||||
]}]])
|
||||
@@ -94,6 +101,6 @@
|
||||
|
||||
(defn admin-clients-page []
|
||||
[side-bar-layout {:side-bar [admin-side-bar {}
|
||||
[side-bar/client-side-bar]]
|
||||
[side-bar/client-side-bar {:data-page ::page}]]
|
||||
:main [admin-clients-content]}])
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.utils
|
||||
:refer [date-picker
|
||||
with-user
|
||||
dispatch-event]]
|
||||
[bidi.bidi :as bidi]
|
||||
[cljs-time.coerce :as coerce]
|
||||
@@ -206,42 +207,46 @@
|
||||
:bank-code bank-code})
|
||||
(:bank-accounts new-client-data))})))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::client
|
||||
:<- [::subs/route-params]
|
||||
:<- [::subs/clients-by-id]
|
||||
(fn [[rp clients-by-id]]
|
||||
(or (get clients-by-id (:id rp))
|
||||
{})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
[(re-frame/inject-cofx ::inject/sub [::client])]
|
||||
(fn [{:keys [db] ::keys [client]} _]
|
||||
{:db (-> db
|
||||
(forms/stop-form ::form)
|
||||
(forms/start-form ::form (-> client
|
||||
(assoc :selected-square-locations (->> (:square-locations client)
|
||||
(filter :client-location )
|
||||
(mapv (fn [sl]
|
||||
{:id (:id sl)
|
||||
:square-location sl
|
||||
:client-location (:client-location sl)}))))
|
||||
(update :locations #(mapv (fn [l] {:location l
|
||||
:id (random-uuid)}) %))
|
||||
[with-user (re-frame/inject-cofx ::inject/sub [::subs/route-params])]
|
||||
(fn [{:keys [user db] ::subs/keys [route-params]} _]
|
||||
{:graphql {:token user
|
||||
:query-obj {:venia/queries [[:admin-client
|
||||
{:id (js/parseInt (:id route-params))}
|
||||
(events/client-detail-query user)]]}
|
||||
:on-success (fn [result]
|
||||
[::received (:admin-client result)])}
|
||||
:db (-> db
|
||||
(forms/stop-form ::form))}))
|
||||
|
||||
(update :feature-flags #(mapv (fn [l] {:feature-flag l
|
||||
:id (random-uuid)}) %))
|
||||
(update :matches #(mapv (fn [l] {:match l
|
||||
:id (random-uuid)}) %))
|
||||
(update :bank-accounts
|
||||
(fn [bas]
|
||||
(mapv (fn [ba]
|
||||
(update ba :locations (fn [ls]
|
||||
(map (fn [l] {:location l
|
||||
:id (random-uuid)})
|
||||
ls))))
|
||||
bas))))))}))
|
||||
(re-frame/reg-event-db
|
||||
::received
|
||||
(fn [db [_ client]]
|
||||
(-> db
|
||||
(forms/stop-form ::form)
|
||||
(forms/start-form ::form (-> client
|
||||
(assoc :selected-square-locations (->> (:square-locations client)
|
||||
(filter :client-location )
|
||||
(mapv (fn [sl]
|
||||
{:id (:id sl)
|
||||
:square-location sl
|
||||
:client-location (:client-location sl)}))))
|
||||
(update :locations #(mapv (fn [l] {:location l
|
||||
:id (random-uuid)}) %))
|
||||
|
||||
(update :feature-flags #(mapv (fn [l] {:feature-flag l
|
||||
:id (random-uuid)}) %))
|
||||
(update :matches #(mapv (fn [l] {:match l
|
||||
:id (random-uuid)}) %))
|
||||
(update :bank-accounts
|
||||
(fn [bas]
|
||||
(mapv (fn [ba]
|
||||
(update ba :locations (fn [ls]
|
||||
(map (fn [l] {:location l
|
||||
:id (random-uuid)})
|
||||
ls))))
|
||||
bas))))))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::save-new-client
|
||||
@@ -249,7 +254,7 @@
|
||||
(fn [_ _]
|
||||
|
||||
(let [new-client-req @(re-frame/subscribe [::new-client-request])
|
||||
user @(re-frame/subscribe [::subs/token])]
|
||||
user @(re-frame/subscribe [::subs/token])]
|
||||
|
||||
{:graphql
|
||||
{:token user
|
||||
@@ -258,7 +263,7 @@
|
||||
:operation/name "EditClient"}
|
||||
:venia/queries [{:query/data [:edit-client
|
||||
{:edit-client new-client-req}
|
||||
(events/client-query user)]}]}
|
||||
(events/client-detail-query user)]}]}
|
||||
:on-success [::save-complete]
|
||||
:on-error [::forms/save-error ::form]}})))
|
||||
|
||||
@@ -727,8 +732,7 @@
|
||||
|
||||
|
||||
(defn form-content []
|
||||
(let [_ @(re-frame/subscribe [::client])
|
||||
{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
||||
(let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
||||
|
||||
^{:key (or (:id new-client)
|
||||
"new")}
|
||||
@@ -750,5 +754,6 @@
|
||||
(def new-client-form
|
||||
(with-meta
|
||||
(fn []
|
||||
[form-content])
|
||||
(let [_ @(re-frame/subscribe [::subs/route-params])]
|
||||
[form-content]))
|
||||
{:component-did-mount #(re-frame/dispatch [::mounted])}))
|
||||
|
||||
@@ -2,78 +2,22 @@
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.views.utils :refer [dispatch-value-change]]
|
||||
[auto-ap.subs :as subs]))
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::specific-filters
|
||||
(fn [db ]
|
||||
(::filters db nil)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::filters
|
||||
:<- [::specific-filters]
|
||||
:<- [::subs/query-params]
|
||||
(fn [[specific-filters _ query-params] ]
|
||||
(let [url-filters (-> query-params
|
||||
(select-keys #{:name
|
||||
:code}))
|
||||
url-filters {:name (str (:name url-filters))
|
||||
:code (str (:code url-filters))}]
|
||||
(merge url-filters specific-filters ))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::filter
|
||||
:<- [::filters]
|
||||
(fn [filters [_ which]]
|
||||
(get filters which)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::filter-params
|
||||
:<- [::settled-filters]
|
||||
:<- [::filters]
|
||||
:<- [::subs/active-page]
|
||||
(fn [[settled-filters filters _ ]]
|
||||
(let [filters (or settled-filters filters)]
|
||||
{:name (:name filters)
|
||||
:code (:code filters)})))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::settled-filters
|
||||
(fn [db ]
|
||||
(::settled-filters db)))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::filters-settled
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (assoc db ::settled-filters @(re-frame/subscribe [::filters]))}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::filter-changed
|
||||
(fn [{:keys [db]} [_ & params]]
|
||||
(let [[a b c] params
|
||||
[which val] (if (= 3 (count params))
|
||||
[(into [a] b) c]
|
||||
[[a] b])]
|
||||
{:db (assoc-in db (into [::filters] which) val)
|
||||
:dispatch-debounce {:event [::filters-settled]
|
||||
:time 800
|
||||
:key ::filters}})))
|
||||
|
||||
|
||||
(defn client-side-bar []
|
||||
(defn client-side-bar [{:keys [data-page]}]
|
||||
[:div
|
||||
[:p.menu-label "Name"]
|
||||
|
||||
[:div.field
|
||||
[:div.control [:input.input {:placeholder "Harry's Food Products"
|
||||
:value @(re-frame/subscribe [::filter :name])
|
||||
:on-change (dispatch-value-change [::filter-changed :name])} ]]]
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :name-like])
|
||||
:on-change (dispatch-value-change [::data-page/filter-changed data-page :name-like])} ]]]
|
||||
|
||||
[:p.menu-label "Code"]
|
||||
|
||||
[:div.field
|
||||
[:div.control [:input.input {:placeholder "CBC"
|
||||
:value @(re-frame/subscribe [::filter :code])
|
||||
:on-change (dispatch-value-change [::filter-changed :code])} ]]]])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :code])
|
||||
:on-change (dispatch-value-change [::data-page/filter-changed data-page :code])} ]]]])
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.status :as status]
|
||||
[bidi.bidi :as bidi]
|
||||
[auto-ap.routes :as routes]))
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::specific-params
|
||||
@@ -76,14 +77,16 @@
|
||||
nil
|
||||
))
|
||||
|
||||
(defn clients-table [{:keys [page status]}]
|
||||
(let [states @(re-frame/subscribe [::status/multi ::setup-sales-queries])]
|
||||
(defn clients-table [{:keys [data-page status]}]
|
||||
(let [states @(re-frame/subscribe [::status/multi ::setup-sales-queries])
|
||||
{:keys [data]} @(re-frame/subscribe [::data-page/page data-page])]
|
||||
[grid/grid {:on-params-change (fn [p]
|
||||
(re-frame/dispatch [::params-changed p]))
|
||||
:data-page data-page
|
||||
:status status
|
||||
:params @(re-frame/subscribe [::params])
|
||||
:column-count 5}
|
||||
[grid/controls page]
|
||||
[grid/controls data]
|
||||
[grid/table {:fullwidth true}
|
||||
[grid/header
|
||||
[grid/row {}
|
||||
@@ -95,7 +98,7 @@
|
||||
[grid/header-cell {:style {:width (action-cell-width 2)}}]]
|
||||
]
|
||||
[grid/body
|
||||
(for [{:keys [id name email square-integration-status locked-until code locations bank-accounts]} (:data page)]
|
||||
(for [{:keys [id name email square-integration-status locked-until code locations bank-accounts]} (:data data)]
|
||||
^{:key (str name "-" id )}
|
||||
[grid/row {:id id}
|
||||
[grid/cell {} name]
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[recharts]
|
||||
[reagent.core :as r]
|
||||
[react]))
|
||||
[react]
|
||||
[vimsical.re-frame.cofx.inject :as inject]
|
||||
[auto-ap.status :as status]))
|
||||
|
||||
(def pie-chart (r/adapt-react-class recharts/PieChart))
|
||||
(def pie (r/adapt-react-class recharts/Pie))
|
||||
@@ -238,23 +240,28 @@
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (assoc db ::top-expense-categories nil)
|
||||
:graphql {:token (-> db :user)
|
||||
:query-obj {:venia/queries [[:expense_account_stats
|
||||
{:client-id (:id @(re-frame/subscribe [::subs/client]))}
|
||||
[[:account [:id :name]] :total]]
|
||||
[:invoice_stats
|
||||
{:client-id (:id @(re-frame/subscribe [::subs/client]))}
|
||||
[:name :paid :unpaid]]
|
||||
[:cash-flow
|
||||
{:client-id (:id @(re-frame/subscribe [::subs/client]))}
|
||||
[:beginning-balance
|
||||
:outstanding-payments
|
||||
[:invoices-due-soon [:due :outstanding-balance [:vendor [:id :name]] :invoice-number]]
|
||||
[:upcoming-credits [:date :amount :identifier]]
|
||||
[:upcoming-debits [:date :amount :identifier]]]]]}
|
||||
:on-success [::received]}}))
|
||||
[(re-frame/inject-cofx ::inject/sub [::subs/client])]
|
||||
(fn [{:keys [db] ::subs/keys [client]} _]
|
||||
(cond->
|
||||
{:db (assoc db ::top-expense-categories nil
|
||||
::cash-flow nil
|
||||
::invoice-stats nil)}
|
||||
client (assoc :graphql {:token (-> db :user)
|
||||
:owns-state {:single ::page}
|
||||
:query-obj {:venia/queries [[:expense_account_stats
|
||||
{:client-id (:id client)}
|
||||
[[:account [:id :name]] :total]]
|
||||
[:invoice_stats
|
||||
{:client-id (:id client)}
|
||||
[:name :paid :unpaid]]
|
||||
[:cash-flow
|
||||
{:client-id (:id client)}
|
||||
[:beginning-balance
|
||||
:outstanding-payments
|
||||
[:invoices-due-soon [:due :outstanding-balance [:vendor [:id :name]] :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]}]
|
||||
[:a.button {:class (when (= value (:cash-flow-range chart-options))
|
||||
@@ -298,51 +305,56 @@
|
||||
|
||||
(defn home-content []
|
||||
(let [client-id (-> @(re-frame/subscribe [::subs/client]) :id)
|
||||
chart-options @(re-frame/subscribe [::chart-options])]
|
||||
chart-options @(re-frame/subscribe [::chart-options])
|
||||
state @(re-frame/subscribe [::status/single ::page])]
|
||||
^{:key client-id}
|
||||
[side-bar-layout {:side-bar [:div
|
||||
|
||||
]
|
||||
:main [:div [:h1.title "Home"]
|
||||
[:h1.title.is-4 "Top expense categories"]
|
||||
(let [expense-categories @(re-frame/subscribe [::top-expense-categories])]
|
||||
(make-pie-chart {:width 800 :height 500 :data (clj->js
|
||||
(map (fn [x] {:name (:name (:account x)) :value (:total x)}) expense-categories))}))
|
||||
[:h1.title.is-4 "Upcoming Bills"]
|
||||
(make-bar-chart {:width 800 :height 500 :data (clj->js
|
||||
@(re-frame/subscribe [::invoice-stats]))})
|
||||
(if client-id
|
||||
(if (= :loading (:state state))
|
||||
[:div.loader.is-loading.big.is-centered]
|
||||
|
||||
[:h1.title.is-4 "Cash Flow"]
|
||||
[:div.buttons.has-addons
|
||||
[cash-flow-range-button {:name "7 days"
|
||||
:value :seven-days
|
||||
:chart-options chart-options}]
|
||||
[cash-flow-range-button {:name "30 days"
|
||||
:value :thirty-days
|
||||
:chart-options chart-options}]
|
||||
[:<>
|
||||
[:h1.title.is-4 "Top expense categories"]
|
||||
(let [expense-categories @(re-frame/subscribe [::top-expense-categories])]
|
||||
(make-pie-chart {:width 800 :height 500 :data (clj->js
|
||||
(map (fn [x] {:name (:name (:account x)) :value (:total x)}) expense-categories))}))
|
||||
[:h1.title.is-4 "Upcoming Bills"]
|
||||
(make-bar-chart {:width 800 :height 500 :data (clj->js
|
||||
@(re-frame/subscribe [::invoice-stats]))})
|
||||
|
||||
[cash-flow-range-button {:name "60 days"
|
||||
:value :sixty-days
|
||||
:chart-options chart-options}]
|
||||
[:h1.title.is-4 "Cash Flow"]
|
||||
[:div.buttons.has-addons
|
||||
[cash-flow-range-button {:name "7 days"
|
||||
:value :seven-days
|
||||
:chart-options chart-options}]
|
||||
[cash-flow-range-button {:name "30 days"
|
||||
:value :thirty-days
|
||||
:chart-options chart-options}]
|
||||
|
||||
[cash-flow-range-button {:name "90 days"
|
||||
:value :ninety-days
|
||||
:chart-options chart-options}]
|
||||
[cash-flow-range-button {:name "120 days"
|
||||
:value :one-hundred-twenty-days
|
||||
:chart-options chart-options}]
|
||||
[cash-flow-range-button {:name "150 days"
|
||||
:value :one-hundred-fifty-days
|
||||
:chart-options chart-options}]
|
||||
[cash-flow-range-button {:name "180 days"
|
||||
:value :one-hundred-eighty-days
|
||||
:chart-options chart-options}]]
|
||||
|
||||
|
||||
(make-cash-flow-chart {:width 800 :height 500
|
||||
:data (clj->js @(re-frame/subscribe [::cash-flow]))})
|
||||
[cash-flow-range-button {:name "60 days"
|
||||
:value :sixty-days
|
||||
:chart-options chart-options}]
|
||||
|
||||
[cash-flow-grid]]}]))
|
||||
[cash-flow-range-button {:name "90 days"
|
||||
:value :ninety-days
|
||||
:chart-options chart-options}]
|
||||
[cash-flow-range-button {:name "120 days"
|
||||
:value :one-hundred-twenty-days
|
||||
:chart-options chart-options}]
|
||||
[cash-flow-range-button {:name "150 days"
|
||||
:value :one-hundred-fifty-days
|
||||
:chart-options chart-options}]
|
||||
[cash-flow-range-button {:name "180 days"
|
||||
:value :one-hundred-eighty-days
|
||||
:chart-options chart-options}]]
|
||||
|
||||
(make-cash-flow-chart {:width 800 :height 500
|
||||
:data (clj->js @(re-frame/subscribe [::cash-flow]))})
|
||||
|
||||
[cash-flow-grid]])
|
||||
[:h2.title.is-6 "Please select a customer to see reports."])]}]))
|
||||
|
||||
|
||||
(defn home-page []
|
||||
|
||||
Reference in New Issue
Block a user