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