From 7d251c8398d85c0b6b8019235b6d00325503bd94 Mon Sep 17 00:00:00 2001 From: Bryce Date: Thu, 31 Aug 2023 23:24:42 -0700 Subject: [PATCH] fixes --- src/clj/auto_ap/datomic/checks.clj | 1 - src/clj/auto_ap/datomic/clients.clj | 10 +- src/clj/auto_ap/datomic/invoices.clj | 9 +- src/clj/auto_ap/datomic/ledger.clj | 4 - src/clj/auto_ap/datomic/reports.clj | 4 - src/clj/auto_ap/graphql/checks.clj | 3 +- src/clj/auto_ap/graphql/invoices.clj | 6 +- src/clj/auto_ap/graphql/ledger.clj | 16 ++- src/clj/auto_ap/graphql/reports.clj | 5 +- src/clj/auto_ap/graphql/transactions.clj | 9 +- src/clj/auto_ap/handler.clj | 72 ++++++++++- src/clj/auto_ap/pdf/ledger.clj | 2 - src/clj/auto_ap/routes/ezcater_xls.clj | 3 +- src/clj/auto_ap/routes/graphql.clj | 31 +---- src/clj/auto_ap/ssr/admin/history.clj | 3 +- src/clj/auto_ap/ssr/company.clj | 5 +- src/clj/auto_ap/ssr/company/company_1099.clj | 17 +-- src/clj/auto_ap/ssr/company/plaid.clj | 4 +- src/clj/auto_ap/ssr/company/reports.clj | 3 +- src/clj/auto_ap/ssr/company_dropdown.clj | 114 ++++++++---------- src/clj/auto_ap/ssr/components/navbar.clj | 4 +- src/clj/auto_ap/ssr/components/page.clj | 5 +- src/clj/auto_ap/ssr/grid_page_helper.clj | 18 +-- src/clj/auto_ap/ssr/invoice/glimpse.clj | 3 +- src/clj/auto_ap/ssr/transaction/insights.clj | 27 ++--- src/cljs/auto_ap/events.cljs | 114 +++++++++++------- src/cljs/auto_ap/subs.cljs | 47 +++++--- .../views/components/invoice_table.cljs | 5 +- .../auto_ap/views/components/layouts.cljs | 11 +- src/cljs/auto_ap/views/main.cljs | 2 +- src/cljs/auto_ap/views/pages/data_page.cljs | 20 +-- src/cljs/auto_ap/views/pages/ledger.cljs | 1 - .../views/pages/ledger/external_ledger.cljs | 1 - src/cljs/auto_ap/views/pages/payments.cljs | 4 +- .../auto_ap/views/pages/pos/sales_orders.cljs | 3 +- src/cljs/auto_ap/views/pages/reports.cljs | 3 +- src/cljs/auto_ap/views/pages/scratch | 7 ++ .../auto_ap/views/pages/transactions.cljs | 5 +- .../views/pages/transactions/common.cljs | 4 +- .../auto_ap/views/pages/unpaid_invoices.cljs | 14 ++- 40 files changed, 333 insertions(+), 286 deletions(-) create mode 100644 src/cljs/auto_ap/views/pages/scratch diff --git a/src/clj/auto_ap/datomic/checks.clj b/src/clj/auto_ap/datomic/checks.clj index 4da6eb8d..94122b8c 100644 --- a/src/clj/auto_ap/datomic/checks.clj +++ b/src/clj/auto_ap/datomic/checks.clj @@ -177,7 +177,6 @@ payments)) (defn get-graphql [args] - (log/info (:id args)) (let [db (dc/db conn) {ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)] diff --git a/src/clj/auto_ap/datomic/clients.clj b/src/clj/auto_ap/datomic/clients.clj index da73b70f..7ab7681d 100644 --- a/src/clj/auto_ap/datomic/clients.clj +++ b/src/clj/auto_ap/datomic/clients.clj @@ -165,15 +165,7 @@ :else nil) - matching-ids (cond - (and name-like-ids (limited-clients (:id args))) - (set/intersection name-like-ids (limited-clients (:id args))) - - name-like-ids - name-like-ids - - :else - nil) + matching-ids name-like-ids valid-ids (if matching-ids (set/intersection (set (map :db/id (:clients args))) matching-ids) diff --git a/src/clj/auto_ap/datomic/invoices.clj b/src/clj/auto_ap/datomic/invoices.clj index 0a40ea28..f071004e 100644 --- a/src/clj/auto_ap/datomic/invoices.clj +++ b/src/clj/auto_ap/datomic/invoices.clj @@ -60,10 +60,7 @@ :where ['[?e :invoice/client]]} :args [db]} - (seq (:clients args)) - (merge-query {:query {:in ['[?xx ...]] - :where ['[?e :invoice/client ?xx]]} - :args [ (map :db/id (:clients args))]}) + (:client-id args) (merge-query {:query {:in ['?client-id] :where ['[?e :invoice/client ?client-id]]} @@ -102,6 +99,10 @@ :where ['[?e :invoice/due ?due] '[(<= ?due ?end-due)]]} :args [(coerce/to-date (:end (:due-range args)))]}) + (seq (:clients args)) + (merge-query {:query {:in ['[?xx ...]] + :where ['[?e :invoice/client ?xx]]} + :args [ (map :db/id (:clients args))]}) (:import-status args) (merge-query {:query {:in ['?import-status] diff --git a/src/clj/auto_ap/datomic/ledger.clj b/src/clj/auto_ap/datomic/ledger.clj index bdad1365..c20e8d2d 100644 --- a/src/clj/auto_ap/datomic/ledger.clj +++ b/src/clj/auto_ap/datomic/ledger.clj @@ -119,10 +119,6 @@ :where ['[?li :journal-entry-line/location ?location]]} :args [(:locations args)]}) - (limited-clients (:id args)) - (merge-query {:query {:in ['[?xx ...]] - :where ['[?e :journal-entry/client ?xx]]} - :args [(set (map :db/id (limited-clients (:id args))))]}) (:sort args) (add-sorter-fields {"client" ['[?e :journal-entry/client ?c] '[?c :client/name ?sort-client]] "date" ['[?e :journal-entry/date ?sort-date]] diff --git a/src/clj/auto_ap/datomic/reports.clj b/src/clj/auto_ap/datomic/reports.clj index 6ee700ee..472ab0d0 100644 --- a/src/clj/auto_ap/datomic/reports.clj +++ b/src/clj/auto_ap/datomic/reports.clj @@ -26,10 +26,6 @@ :where ['[?e :report/client ?xx]]} :args [(set (map :db/id (:clients args)))]}) - (limited-clients (:id args)) - (merge-query {:query {:in ['[?xx ...]] - :where ['[?e :report/client ?xx]]} - :args [(set (map :db/id (limited-clients (:id args))))]}) (:sort args) (add-sorter-fields {"client" ['[?e :report/client ?c] '[?c :client/name ?sort-client]] "created" ['[?e :report/created ?sort-created]] diff --git a/src/clj/auto_ap/graphql/checks.clj b/src/clj/auto_ap/graphql/checks.clj index 5c0e8a44..b7dfd5a3 100644 --- a/src/clj/auto_ap/graphql/checks.clj +++ b/src/clj/auto_ap/graphql/checks.clj @@ -732,8 +732,7 @@ (def input-objects {:invoice_payment_amount {:fields {:invoice_id {:type :id} :amount {:type :money}}} - :payment_filters {:fields {:client_id {:type :id} - :vendor_id {:type :id} + :payment_filters {:fields {:vendor_id {:type :id} :payment_type {:type :payment_type} :status {:type :payment_status} :exact_match_id {:type :id} diff --git a/src/clj/auto_ap/graphql/invoices.clj b/src/clj/auto_ap/graphql/invoices.clj index b00bfb0a..6bbd3f6b 100644 --- a/src/clj/auto_ap/graphql/invoices.clj +++ b/src/clj/auto_ap/graphql/invoices.clj @@ -255,7 +255,6 @@ (defn get-ids-matching-filters [args] (let [ids (some-> args :filters - (assoc :id (:id args)) (<-graphql) (update :status enum->keyword "invoice-status") (assoc :per-page Integer/MAX_VALUE) @@ -278,7 +277,7 @@ (defn void-invoices [context args _] (let [_ (assert-admin (:id context)) - args (assoc args :id (:id context)) + args (assoc args :clients (:clients context)) all-ids (all-ids-not-locked (get-ids-matching-filters args)) voidable-cash-payments (->> (dc/q '[:find ?p :in $ [?i ...] @@ -445,7 +444,7 @@ (when-not (:client_id args) (throw (ex-info "Client is required" {:validation-error "client is required"}))) - (let [args (assoc args :id (:id context)) + (let [args (assoc args :clients [{:db/id (:client_id args)}]) locations (pull-attr (dc/db conn) :client/locations (:client_id args)) @@ -602,7 +601,6 @@ :status {:type :invoice_status} :unresolved {:type 'Boolean} :scheduled_payments {:type 'Boolean} - :client_id {:type :id} :vendor_id {:type :id} :account_id {:type :id} :amount_lte {:type :money} diff --git a/src/clj/auto_ap/graphql/ledger.clj b/src/clj/auto_ap/graphql/ledger.clj index c2d0ed04..140f0f2e 100644 --- a/src/clj/auto_ap/graphql/ledger.clj +++ b/src/clj/auto_ap/graphql/ledger.clj @@ -35,8 +35,14 @@ (defn get-ledger-page [context args _] (let [args (assoc args :id (:id context)) + _ (when (:client_id (:filters args)) + (assert-can-see-client (:id context) (:client_id (:filters args)))) + clients (or (and (:client_id (:filters args)) + [{:db/id (:client_id (:filters args))}]) + (:clients context)) + [journal-entries journal-entries-count] (l/get-graphql (assoc (<-graphql (:filters args)) - :clients (:clients context))) + :clients clients)) journal-entries (mapv (fn [je] @@ -49,7 +55,7 @@ (let [args (assoc args :id (:id context)) [journal-entries journal-entries-count] (l/get-graphql (assoc (<-graphql (:filters args)) :per-page Integer/MAX_VALUE - :id (:id context))) + :clients (:clients context))) ] @@ -561,9 +567,9 @@ location (:client/locations c) category (:categories input) :let [category (<-graphql category) - all-journal-entries (->> (get-ledger-page context - {:filters {:client_id client-id - :location location + all-journal-entries (->> (get-ledger-page (assoc context + :clients [{:db/id client-id}]) + {:filters {:location location :date_range (:date_range input) :from_numeric_code (l-reports/min-numeric-code category ) :to_numeric_code (l-reports/max-numeric-code category ) diff --git a/src/clj/auto_ap/graphql/reports.clj b/src/clj/auto_ap/graphql/reports.clj index 94245dab..7975db6d 100644 --- a/src/clj/auto_ap/graphql/reports.clj +++ b/src/clj/auto_ap/graphql/reports.clj @@ -9,7 +9,7 @@ [datomic.api :as dc])) (defn get-report-page [context args _] - (let [args (assoc args :id (:id context)) + (let [args (assoc args :clients (:clients context)) [reports reports-count] (r/get-graphql (assoc (<-graphql (:filters args)) :clients (:clients context)))] (result->page reports reports-count :reports (:filters args))) @@ -58,8 +58,7 @@ (def input-objects {:report_filters - {:fields {:client_id {:type :id} - :start {:type 'Int} + {:fields {:start {:type 'Int} :per_page {:type 'Int} :sort {:type '(list :sort_item)}}}}) diff --git a/src/clj/auto_ap/graphql/transactions.clj b/src/clj/auto_ap/graphql/transactions.clj index 5883c53e..77a0db41 100644 --- a/src/clj/auto_ap/graphql/transactions.clj +++ b/src/clj/auto_ap/graphql/transactions.clj @@ -41,7 +41,7 @@ (when-not (seq (->> filters (filter (fn [[_ v]] (not (nil? v)))) - (filter (comp (complement #{:id :start :sort :client_id :bank_account_id :potential_duplicates :per_page}) + (filter (comp (complement #{:id :start :sort :bank_account_id :potential_duplicates :per_page}) first)) (filter (fn [[k v]] (if (= :date_range k) @@ -141,8 +141,7 @@ (when-not (seq (:client_id args)) (throw (ex-info "Client is required" {:validation-error "client is required"}))) - ;; TODO FIX THIS TO WORK WITH MULTIPLE - (let [args (assoc args :clients (:clients context)) + (let [args (assoc args :clients [{:db/id [(:client_id args)]}]) locations (pull-attr (dc/db conn) :client/locations (:client_id args)) @@ -589,7 +588,6 @@ :resolve :mutation/bulk-change-transaction-status} :bulk_code_transactions {:type :message :args {:filters {:type :transaction_filters} - :client_id {:type :id} :vendor {:type :id} :approval_status {:type :transaction_approval_status} :accounts {:type '(list :edit_percentage_account)} @@ -630,8 +628,7 @@ :resolve :mutation/match-transaction-rules}}) (def input-objects - {:transaction_filters {:fields {:client_id {:type :id} - :exact_match_id {:type :id} + {:transaction_filters {:fields {:exact_match_id {:type :id} :import_batch_id {:type :id} :potential_duplicates {:type 'Boolean} :vendor_id {:type :id} diff --git a/src/clj/auto_ap/handler.clj b/src/clj/auto_ap/handler.clj index da43b0df..df2c97ac 100644 --- a/src/clj/auto_ap/handler.clj +++ b/src/clj/auto_ap/handler.clj @@ -2,7 +2,9 @@ (:require [amazonica.core :refer [defcredential]] [auto-ap.client-routes :as client-routes] - [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.datomic :refer [conn pull-many]] + [auto-ap.datomic.clients :as d-clients] + [auto-ap.graphql.utils :refer [assert-can-see-client limited-clients]] [auto-ap.logging :as alog] [auto-ap.routes.auth :as auth] [auto-ap.routes.exports :as exports] @@ -12,15 +14,21 @@ [auto-ap.routes.invoices :as invoices] [auto-ap.routes.queries :as queries] [auto-ap.routes.yodlee2 :as yodlee2] + [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.core :as ssr] [bidi.bidi :as bidi] [bidi.ring :refer [->ResourcesMaybe make-handler]] [buddy.auth.backends.session :refer [session-backend]] [buddy.auth.backends.token :refer [jws-backend]] [buddy.auth.middleware :refer [wrap-authentication wrap-authorization]] + [cemerick.url :as url] + [clj-time.coerce :as coerce] + [clj-time.core :as time] [clojure.string :as str] + [clojure.edn :as edn] [com.brunobonacci.mulog :as mu] [config.core :refer [env]] + [datomic.api :as dc] [ring.middleware.edn :refer [wrap-edn-params]] [ring.middleware.multipart-params :as mp] [ring.middleware.params :refer [wrap-params]] @@ -29,9 +37,7 @@ [ring.middleware.session.cookie :refer [cookie-store]] [ring.util.response :as response] [unilog.context :as lc] - [clj-time.coerce :as coerce] - [clj-time.core :as time] - [cemerick.url :as url])) + [clojure.set :as set])) (when (:aws-access-key-id env) (defcredential (:aws-access-key-id env) (:aws-secret-access-key env) (:aws-region env))) @@ -169,13 +175,67 @@ request (assoc request :hx-query-params query-params)] (handler request)))) +(defn wrap-hydrate-clients + [handler] + (fn [request] + (let [x-clients (-> request :session :client-selection) + identity (-> request :session :identity) + ideal-ids (set (cond + (or (= :all x-clients) + (nil? x-clients)) + (->> (dc/q '[:find ?c + :where [?c :client/code]] + (dc/db conn)) + (map first)) + + (= :mine x-clients) + (map :db/id (:user/clients identity)) + + (seq x-clients) + x-clients)) + limited-clients (some->> (limited-clients identity) + (map :db/id ) + set) + + client-ids (if (set? limited-clients) + (set/intersection ideal-ids + limited-clients) + ideal-ids) + clients (pull-many (dc/db conn) + d-clients/full-read + client-ids)] + (lc/with-context {:clients (map :client/code clients)} + (handler (assoc request + :clients clients + :client (when (= 1 (count clients)) + (first clients)))))))) + +(defn wrap-store-client-in-session + [handler] + (fn [{:keys [headers identity] :as request}] + (let [x-clients (edn/read-string (get headers "x-clients")) + _ (when-let [client-id (and x-clients + (sequential? x-clients) + (first x-clients))] + (assert-can-see-client identity client-id)) + new-request (if x-clients + (assoc-in request [:session :client-selection] x-clients) + request)] + (cond-> (handler new-request) + x-clients (update :session + (fn [new-session] + (-> (:session request) + (into new-session) + (assoc :client-selection x-clients)))))))) + #_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (def app (-> route-handler (wrap-hx-current-url-params) (wrap-guess-route) - (wrap-authorization auth-backend - ) + (wrap-hydrate-clients) + (wrap-store-client-in-session) + (wrap-authorization auth-backend) (wrap-authentication auth-backend (session-backend {:authfn (fn [auth] (dissoc auth :exp))})) diff --git a/src/clj/auto_ap/pdf/ledger.clj b/src/clj/auto_ap/pdf/ledger.clj index 11104af2..2aaab4ac 100644 --- a/src/clj/auto_ap/pdf/ledger.clj +++ b/src/clj/auto_ap/pdf/ledger.clj @@ -272,8 +272,6 @@ (.toByteArray output-stream))) (defn make-journal-detail-report [args data] - - (println args) (let [data (<-graphql data) args (<-graphql args) clients (pull-many (dc/db conn) '[:client/code :client/name :db/id] (:client-ids args)) diff --git a/src/clj/auto_ap/routes/ezcater_xls.clj b/src/clj/auto_ap/routes/ezcater_xls.clj index fc2253da..734351c4 100644 --- a/src/clj/auto_ap/routes/ezcater_xls.clj +++ b/src/clj/auto_ap/routes/ezcater_xls.clj @@ -193,7 +193,8 @@ (base-page request (com/page {:nav (com/admin-aside-nav) - :active-client (:client (:session request)) + :client-selection (:client-selection (:session request)) + :client (:client request) :identity (:identity request) :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :admin-ezcater-xls) diff --git a/src/clj/auto_ap/routes/graphql.clj b/src/clj/auto_ap/routes/graphql.clj index 277a550e..048d36df 100644 --- a/src/clj/auto_ap/routes/graphql.clj +++ b/src/clj/auto_ap/routes/graphql.clj @@ -12,37 +12,10 @@ [clojure.tools.logging :as log] [datomic.api :as dc])) -(defn headers->clients [identity headers] - (let [x-clients (clojure.edn/read-string (get headers "x-clients")) - ideal-ids (set (cond - (or (= :all x-clients) - (nil? x-clients)) - (->> (dc/q '[:find ?c - :where [?c :client/code]] - (dc/db conn)) - (map first)) - (= :mine x-clients) - (map :db/id (:user/clients identity)) - (seq x-clients) - x-clients)) - _ (println "X-CLIENSTT" x-clients) - _ (println "IDEAL" ideal-ids) - _ (println "LIMITS" (limited-clients identity)) - limited-clients (some->> (limited-clients identity) - (map :db/id ) - set) - client-ids (if (set? limited-clients) - (set/intersection ideal-ids - limited-clients) - ideal-ids)] - (pull-many (dc/db conn) - d-clients/full-read - client-ids))) - -(defn handle-graphql [{:keys [request-method query-params] :as r}] +(defn handle-graphql [{:keys [request-method query-params clients] :as r}] (when (= "none" (:user/role (:identity r))) (throw-unauthorized)) @@ -54,7 +27,7 @@ {:status 200 :body (pr-str (ql/query (:identity r) (if (= request-method :get) (query-params "query") body) (assoc variables :clients - (headers->clients (:identity r) (:headers r))) )) + clients) )) :headers {"Content-Type" "application/edn"}}) (catch Throwable e (log/info "here we are " (.getCause e)) diff --git a/src/clj/auto_ap/ssr/admin/history.clj b/src/clj/auto_ap/ssr/admin/history.clj index f1796a6f..0929e728 100644 --- a/src/clj/auto_ap/ssr/admin/history.clj +++ b/src/clj/auto_ap/ssr/admin/history.clj @@ -166,7 +166,8 @@ (some-> route-params (get :entity-id) Long/parseLong))] (base-page request (com/page {:nav (com/admin-aside-nav) - :active-client (:client (:session request)) + :client-selection (:client-selection (:session request)) + :client (:client request) :identity (:identity request) :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :admin-history) diff --git a/src/clj/auto_ap/ssr/company.clj b/src/clj/auto_ap/ssr/company.clj index d3b657ab..058bacb0 100644 --- a/src/clj/auto_ap/ssr/company.clj +++ b/src/clj/auto_ap/ssr/company.clj @@ -50,7 +50,8 @@ (base-page request (com/page {:nav (com/company-aside-nav) - :active-client (:client (:session request)) + :client-selection (:client-selection (:session request)) + :client (:client request) :identity (:identity request) :app-params { :hx-get (bidi/path-for ssr-routes/only-routes @@ -62,6 +63,6 @@ [:a {:href (bidi/path-for ssr-routes/only-routes :company)} "My Company"]) - (main-content* {:client (:client (:session request))})) + (main-content* {:client (:client request)})) "My Company")) diff --git a/src/clj/auto_ap/ssr/company/company_1099.clj b/src/clj/auto_ap/ssr/company/company_1099.clj index 09f8a410..b92e5f1e 100644 --- a/src/clj/auto_ap/ssr/company/company_1099.clj +++ b/src/clj/auto_ap/ssr/company/company_1099.clj @@ -44,23 +44,16 @@ client-id vendor-id))) -(defn get-1099-companies [user {:keys [client-id] :as args}] - (let [clients (->> (dc/q '[:find ?c - :in $ ?user - :where [?c :client/code] - [(iol-ion.query/can-see-client? ?user ?c)]] - (dc/db conn) user) - (map first) - set) +(defn get-1099-companies [user {:keys [clients] :as args}] + (let [ results (cond - (and client-id - (can-see-client? user client-id)) + clients (dc/q '[:find (pull ?c [:client/code :db/id]) (pull ?v vendor-read) (sum ?a) :with ?d - :in $ ?c vendor-read + :in $ [?c ...] vendor-read :where [?p :payment/client ?c] [?p :payment/date ?d ] @@ -70,7 +63,7 @@ [?p :payment/amount ?a] [?p :payment/vendor ?v]] (dc/db conn) - client-id + (set (map :db/id clients)) vendor-read) (is-admin? user) diff --git a/src/clj/auto_ap/ssr/company/plaid.clj b/src/clj/auto_ap/ssr/company/plaid.clj index 61d5b48f..389baa1b 100644 --- a/src/clj/auto_ap/ssr/company/plaid.clj +++ b/src/clj/auto_ap/ssr/company/plaid.clj @@ -45,10 +45,10 @@ "status" ['[?e :plaid-item/status ?sort-status]]} args) - (limited-clients (:id args)) + (:clients args) (merge-query {:query {:in ['[?xx ...]] :where ['[?e :plaid-item/client ?xx]]} - :args [ (set (map :db/id (limited-clients (:id args))))]}) + :args [ (set (map :db/id (:clients args)))]}) (:client-id args) (merge-query {:query {:in '[?client-id] diff --git a/src/clj/auto_ap/ssr/company/reports.clj b/src/clj/auto_ap/ssr/company/reports.clj index 7da733c7..62c93e72 100644 --- a/src/clj/auto_ap/ssr/company/reports.clj +++ b/src/clj/auto_ap/ssr/company/reports.clj @@ -12,7 +12,8 @@ [auto-ap.time :as atime] [bidi.bidi :as bidi] [config.core :refer [env]] - [datomic.api :as dc])) + [datomic.api :as dc] + [com.brunobonacci.mulog :as mu])) (def grid-page {:id "report-table" :nav (com/company-aside-nav) diff --git a/src/clj/auto_ap/ssr/company_dropdown.clj b/src/clj/auto_ap/ssr/company_dropdown.clj index d8fd19d9..976a59d2 100644 --- a/src/clj/auto_ap/ssr/company_dropdown.clj +++ b/src/clj/auto_ap/ssr/company_dropdown.clj @@ -1,8 +1,7 @@ (ns auto-ap.ssr.company-dropdown (:require - [auto-ap.datomic :refer [conn pull-many]] - [auto-ap.graphql.utils - :refer [assert-can-see-client cleanse-query is-admin?]] + [auto-ap.datomic :refer [conn pull-attr pull-many]] + [auto-ap.graphql.utils :refer [assert-can-see-client cleanse-query]] [auto-ap.solr :as solr] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.svg :as svg] @@ -17,10 +16,14 @@ (for [{:keys [id name]} options] [:li [:div {:class "flex items-center pl-2 rounded hover:bg-green-100 dark:hover:bg-green-600"} - - [:a {:href "#" :class "w-full py-2 ml-2 text-sm font-medium text-gray-900 rounded dark:text-gray-300" - "_" (hiccup/raw "on click set value of <#company-search-value/> to @data-value then send selected to #company-dropdown") - :data-value id} + [:a {:href "#" :class "w-full py-2 ml-2 text-sm font-medium text-gray-900 rounded dark:text-gray-300" + :hx-put (bidi/path-for ssr-routes/only-routes + :active-client + :request-method :put) + :hx-target "#company-dropdown" + :hx-headers (format "{\"x-clients\": \"[%d]\"}" id) + :hx-swap "outerHTML" + :hx-trigger "click"} name]]])]) @@ -41,27 +44,29 @@ (defn dropdown-search-results [{:keys [identity] :as request}] (html-response - (dropdown-search-results* {:options (get-clients identity (get (:query-params request) "search-text")) - :client (:client (:session request))}))) + (dropdown-search-results* {:options (get-clients identity (get (:query-params request) "search-text"))}))) -(defn dropdown [{:keys [client]}] +(defn dropdown [{:keys [client-selection client identity]}] [:div#company-dropdown - {:hx-put (bidi/path-for ssr-routes/only-routes - :active-client - :request-method :put) - :hx-target "#company-dropdown" - :hx-include "#company-search-value" - :hx-swap "outerHTML" - :hx-trigger "selected"} [:script (hiccup/raw - "localStorage.setItem(\"last-client-id\", \""(:db/id client)"\")")] + "localStorage.setItem(\"last-client-id\", \"" (:db/id client) "\")" "\n" + "localStorage.setItem(\"last-selected-clients\", \"" client-selection "\")" + )] [:div [:button#company-dropdown-button { :class "text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2.5 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" :type "button"} - (if client - (:client/name client) - "All Companies") + (cond + (= :mine client-selection) + "My Companies" + (= :all client-selection) + "All Companies" + (and (sequential? client-selection) + (= 1 (count client-selection))) + (pull-attr (dc/db conn) :client/name (first client-selection)) + + :else + (str (count client-selection) " Companies")) [:div.w-4.h-4.ml-2 svg/drop-down]] [:div#company-dropdown-list.hidden {"_" (hiccup/raw "init call initCompanyDropdown()") @@ -84,9 +89,21 @@ :hx-target "#company-search-results" :hx-swap "innerHTML"} ]] [:input#company-search-value {:type "hidden" - :name "search-client"}]] + :name "x-clients"}]] [:div.divide-y.divide-gray-100 [:div#company-search-results {:class "h-48 px-3 pb-3 overflow-y-auto text-sm text-gray-700 dark:text-gray-200"}] + (when (= "admin" (:user/role identity)) + [:div {:class "flex items-center pl-2 rounded hover:bg-green-100 dark:hover:bg-green-600"} + + [:button {:class "w-full py-2 ml-2 text-sm font-medium text-gray-900 rounded dark:text-gray-300" + :hx-put (bidi/path-for ssr-routes/only-routes + :active-client + :request-method :put) + :hx-target "#company-dropdown" + :hx-headers "{\"x-clients\": \":mine\"}" + :hx-swap "outerHTML" + :hx-trigger "click"} + "Mine"]]) [:div {:class "flex items-center pl-2 rounded hover:bg-green-100 dark:hover:bg-green-600"} [:button {:class "w-full py-2 ml-2 text-sm font-medium text-gray-900 rounded dark:text-gray-300" @@ -94,6 +111,7 @@ :active-client :request-method :put) :hx-target "#company-dropdown" + :hx-headers "{\"x-clients\": \":all\"}" :hx-swap "outerHTML" :hx-trigger "click"} "All"]]] @@ -126,48 +144,10 @@ function initCompanyDropdown() { ")]]]) (defn active-client [{:keys [identity params] :as request}] - (let [client-search (or (:search-client params) - (get params "search-client")) - client-id (try (some-> client-search - (not-empty ) - Long/parseLong) - (catch Exception _ - nil))] - (when client-id - (assert-can-see-client identity client-id)) - - (let [new-session (assoc (:session request) - - :client - (when client-id - (dc/pull (dc/db conn) [:db/id :client/name :client/code] client-id)) - - :clients - (cond (int? client-id) - [(dc/pull (dc/db conn) [:db/id :client/name :client/code] client-id)] - - (= ":mine" client-search) - (->> (dc/q '[:find (pull ?c [:db/id :client/name :client/code]) - :in $ ?u - :where [?u :user/clients ?c]] - (dc/db conn) - (:db/id identity)) - (map first)) - - (and (or (empty? client-search) - (= ":all" client-search)) - (is-admin? identity)) - (->> (dc/q '[:find (pull ?c [:db/id :client/name :client/code]) - :in $ ?u - :where [?c :client/code]] - (dc/db conn) - (:db/id identity)) - (map first))))] - (assoc - (html-response - (dropdown {:client (:client new-session) - :identity identity})) - :session - new-session - :headers - {"hx-trigger" "clientSelected"})))) + (assoc + (html-response + (dropdown {:client-selection (:client-selection (:session request)) + :client (:client request) + :identity identity})) + :headers + {"hx-trigger" "clientSelected"})) diff --git a/src/clj/auto_ap/ssr/components/navbar.clj b/src/clj/auto_ap/ssr/components/navbar.clj index 692b4cc8..e08d9c73 100644 --- a/src/clj/auto_ap/ssr/components/navbar.clj +++ b/src/clj/auto_ap/ssr/components/navbar.clj @@ -8,7 +8,7 @@ [auto-ap.ssr.svg :as svg] [bidi.bidi :as bidi])) -(defn navbar- [{:keys [client identity]}] +(defn navbar- [{:keys [client-selection client identity]}] [:nav {:class "fixed z-30 w-full bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700"} [:div {:class "px-3 py-3 lg:px-5 lg:pl-3"} [:div {:class "flex items-center justify-between"} @@ -40,6 +40,6 @@ :hx-target "#modal-holder" :hx-swap "outerHTML"} svg/search) - (cd/dropdown {:client client :identity identity}) + (cd/dropdown {:client-selection client-selection :client client :identity identity}) (user-dropdown/dropdown {:identity identity})]]]]) diff --git a/src/clj/auto_ap/ssr/components/page.clj b/src/clj/auto_ap/ssr/components/page.clj index 426d1ee4..e6df4eac 100644 --- a/src/clj/auto_ap/ssr/components/page.clj +++ b/src/clj/auto_ap/ssr/components/page.clj @@ -5,9 +5,10 @@ [hiccup2.core :as hiccup] [auto-ap.ssr.svg :as svg])) -(defn page- [{:keys [nav page-specific active-client identity app-params] :or {app-params {}}} & children] +(defn page- [{:keys [nav page-specific client client-selection identity app-params] :or {app-params {}}} & children] [:div#app - (navbar- {:client active-client + (navbar- {:client-selection client-selection + :client client :identity identity}) [:div#app-contents.flex.pt-16.overflow-hidden (assoc app-params :hx-disinherit "*") (left-aside- {:nav nav diff --git a/src/clj/auto_ap/ssr/grid_page_helper.clj b/src/clj/auto_ap/ssr/grid_page_helper.clj index 8fc6f931..fddf6b99 100644 --- a/src/clj/auto_ap/ssr/grid_page_helper.clj +++ b/src/clj/auto_ap/ssr/grid_page_helper.clj @@ -8,7 +8,9 @@ [auto-ap.ssr-routes :as ssr-routes] [cemerick.url :as url] [clojure.string :as str] - [auto-ap.ssr.svg :as svg])) + [auto-ap.ssr.svg :as svg] + [unilog.context :as lc] + [com.brunobonacci.mulog :as mu])) (defn row* [gridspec user entity {:keys [flash? delete-after-settle?] :as options}] (let [cells (mapv (fn [header] @@ -51,16 +53,15 @@ )) "default sort")) -(defn table* [grid-spec user {:keys [start per-page client flash-id sort request] :as params}] +(defn table* [grid-spec user {:keys [start per-page clients flash-id sort] :as params}] (let [start (or start 0) per-page (or per-page 30) [entities total] ((:fetch-page grid-spec) user {:start start :per-page per-page - :client-id (:db/id client) - :sort sort - :request request})] + :clients clients + :sort sort})] (com/data-grid-card {:id (:id grid-spec) :title (:title grid-spec) :route (:route grid-spec) @@ -161,7 +162,9 @@ q-sort (assoc :sort (parse-sort grid-spec q-sort)) (not-empty q-toggle-sort) (update :sort #(toggle-sort grid-spec % q-toggle-sort) ) (:session request) (assoc :session (:session request)) - (:client (:session request)) (assoc :client (:client (:session request)))))) + (:client-selection (:session request)) (assoc :client-selection (:client-selection (:session request))) + (:clients request) (assoc :clients (:clients request)) + (:client request) (assoc :client (:client request))))) (defn table [grid-spec {:keys [query-params hx-query-params identity session] :as request}] (let [params (extract-params grid-spec request) @@ -177,7 +180,8 @@ (base-page request (com/page {:nav (:nav grid-spec) - :active-client (:client (:session request)) + :client-selection (:client-selection (:session request)) + :client (:client request) :identity (:identity request)} (apply com/breadcrumbs {} (:breadcrumbs grid-spec)) (table* grid-spec diff --git a/src/clj/auto_ap/ssr/invoice/glimpse.clj b/src/clj/auto_ap/ssr/invoice/glimpse.clj index ad632103..1881c8da 100644 --- a/src/clj/auto_ap/ssr/invoice/glimpse.clj +++ b/src/clj/auto_ap/ssr/invoice/glimpse.clj @@ -419,7 +419,8 @@ invoice_dropzone = new Dropzone(\"#invoice\", { (base-page request (com/page {:nav (com/admin-aside-nav) - :active-client (:client (:session request)) + :client-selection (:client-selection (:session request)) + :client (:client request) :identity (:identity request) :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :invoice-glimpse) diff --git a/src/clj/auto_ap/ssr/transaction/insights.clj b/src/clj/auto_ap/ssr/transaction/insights.clj index 1f9188b0..f4a25a94 100644 --- a/src/clj/auto_ap/ssr/transaction/insights.clj +++ b/src/clj/auto_ap/ssr/transaction/insights.clj @@ -41,7 +41,7 @@ :seen-by-client? s}) ors)))) -(defn transaction-recommendations [identity selected-client & {:keys [after]}] +(defn transaction-recommendations [identity clients & {:keys [after]}] (let [visible-clients (visible-clients identity)] (->> (dc/qseq {:query '[:find (pull ?t pull-expr) @@ -56,9 +56,8 @@ :args [(dc/db conn) (iol-ion.query/recent-date 120) - (if selected-client - [selected-client] - visible-clients) + (map :db/id clients) + pull-expr]}) (map first) (drop-while (fn [x] @@ -273,8 +272,8 @@ [:td (format "%.1f%%" (* 100 (double score)))]]))]] [:div]))))) -(defn transaction-rows* [{:keys [selected-client identity after]}] - (let [recommendations (transaction-recommendations identity selected-client :after after)] +(defn transaction-rows* [{:keys [clients identity after]}] + (let [recommendations (transaction-recommendations identity clients :after after)] (if (seq recommendations) (for [r recommendations :let [last? (= r (last recommendations))]] @@ -282,13 +281,13 @@ [:tr [:td.has-text-centered.has-text-gray {:colspan 7 } [:i "That's the last of 'em!"]]]))) -(defn transaction-rows [{:keys [session identity route-params]}] - (html-response (transaction-rows* {:selected-client (-> session :client :db/id) +(defn transaction-rows [{:keys [session identity route-params clients]}] + (html-response (transaction-rows* {:clients clients :identity identity :after (:after route-params)}))) -(defn insight-table* [{:keys [selected-client identity]}] - (let [recommendations (transaction-recommendations identity selected-client)] +(defn insight-table* [{:keys [clients identity]}] + (let [recommendations (transaction-recommendations identity clients)] (com/data-grid-card {:id "insight-table" :title "Transaction Insights" :route :transaction-insight-table @@ -305,16 +304,16 @@ (com/data-grid-header {:style {:width "8em"}} "Amount") (com/data-grid-header {})]}))) -(defn insight-table [{:keys [session identity]}] - (html-response (insight-table* {:selected-client - (-> session :client :db/id) +(defn insight-table [{:keys [session identity clients]}] + (html-response (insight-table* {:clients clients :identity identity}))) (defn page [{:keys [identity matched-route session] :as request}] (base-page request (com/page {:nav (com/main-aside-nav) - :active-client (:client (:session request)) + :client-selection (:client-selection (:session request)) + :client (:client request) :identity (:identity request) :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :transaction-insights) diff --git a/src/cljs/auto_ap/events.cljs b/src/cljs/auto_ap/events.cljs index 343c3c70..81ad69a0 100644 --- a/src/cljs/auto_ap/events.cljs +++ b/src/cljs/auto_ap/events.cljs @@ -7,6 +7,7 @@ [auto-ap.views.utils :refer [parse-jwt with-user]] [bidi.bidi :as bidi] [clojure.string :as str] + [clojure.edn :as edn] [goog.crypt.base64 :as b64] [re-frame.core :as re-frame] [auto-ap.ssr-routes :as ssr-routes] @@ -46,39 +47,64 @@ (re-frame/reg-event-fx ::initialize-db (fn [{:keys [_]} [_ token]] - (let [handler (:handler (bidi/match-route routes/routes (.. js/window -location -pathname)))] + (let [handler (:handler (bidi/match-route routes/routes (.. js/window -location -pathname))) + last-client-id (.getItem js/localStorage "last-client-id") + last-selected-clients (edn/read-string (.getItem js/localStorage "last-selected-clients")) + jwt-data (jwt->data token) + selected-client-assignment (cond (and token + (= "admin" (get jwt-data "user/role")) + (not last-selected-clients)) + :mine + + (and token + last-client-id + (not last-selected-clients)) + [(js/parseInt last-client-id)] + + :else + nil)] + + (cond (= :login handler) - {:db (assoc db/default-db - :active-route :login - :last-client-id (.getItem js/localStorage "last-client-id") - :user nil)} + {:db (cond-> (assoc db/default-db + :active-route :login + :last-client-id last-client-id + :selected-clients last-selected-clients + :user nil))} (and (not= :login handler) (not token)) {:redirect "/login" :db (assoc db/default-db :active-route :login - :last-client-id (.getItem js/localStorage "last-client-id") + :last-client-id last-client-id + :selected-clients last-selected-clients :user token)} - (and token (= "none" (or (get (jwt->data token) "role") (get (jwt->data token) "user/role")) )) + (and token (= "none" (or (get jwt-data "role") (get jwt-data "user/role")) )) {:redirect "/needs-activation" :db (assoc db/default-db :active-route :needs-activation - :last-client-id (.getItem js/localStorage "last-client-id") + :last-client-id last-client-id + :selected-clients last-selected-clients :user token)} :else - {:db (assoc db/default-db - :active-route handler - :is-initial-loading? true - :last-client-id (.getItem js/localStorage "last-client-id") - :query-params (auto-ap.views.utils/query-params) - :user token) - :graphql {:token token - :query-obj {:venia/queries [[:client (client-query)]]} - :on-success [::received-initial] - :on-error [::failed-initial]}})))) + (cond-> {:db (cond-> (assoc db/default-db + :active-route handler + :is-initial-loading? true + :last-client-id last-client-id + :selected-clients last-selected-clients + :query-params (auto-ap.views.utils/query-params) + :user token) + selected-client-assignment + (assoc :selected-clients selected-client-assignment)) + :graphql {:token token + :query-obj {:venia/queries [[:client (client-query)]]} + :on-success [::received-initial] + :on-error [::failed-initial]}} + selected-client-assignment + (assoc :set-local-storage ["last-selected-clients" selected-client-assignment])))))) (re-frame/reg-event-db @@ -124,40 +150,46 @@ :is-initial-loading? false :active-route :initial-error))) +(re-frame/reg-event-fx + ::swapped-client + (fn [{:keys [db]} [_ client client-identifier]] + (when (:id client) + (.setItem js/localStorage "last-client-id" (:id client))) + (.setItem js/localStorage "last-selected-clients" + (condp = client-identifier + :all + :all + + :mine + :mine + + (pr-str [(js/parseInt (:id client))]))) + + {:db (assoc db :client (:id client) + :selected-clients + (condp = client-identifier + :all + :all + + :mine + :mine + + [(js/parseInt (:id client))]))})) + (re-frame/reg-event-fx ::swap-client [with-user] (fn [{:keys [db user]} [_ client]] (let [client-identifier (or (:id client) client)] - (when (:id client) - (.setItem js/localStorage "last-client-id" (:id client))) - (.setItem js/localStorage "last-selected-clients" - (condp = client-identifier - :all - :all - :mine - :mine - - (pr-str [(js/parseInt (:id client))]))) - - {:db (assoc db :client (:id client) - :selected-clients - (condp = client-identifier - :all - :all - - :mine - :mine - - [(js/parseInt (:id client))])) - :http {:token user + {:http {:token user :method :put :uri (str (bidi/path-for ssr-routes/only-routes :active-client :request-method :put) "?" - (url/map->query {:search-client client-identifier}))}}))) + (url/map->query {:search-client client-identifier})) + :on-success [::swapped-client client client-identifier]}}))) (re-frame/reg-event-fx ::set-active-route diff --git a/src/cljs/auto_ap/subs.cljs b/src/cljs/auto_ap/subs.cljs index 444cf7e3..20f30c46 100644 --- a/src/cljs/auto_ap/subs.cljs +++ b/src/cljs/auto_ap/subs.cljs @@ -5,7 +5,8 @@ [auto-ap.views.utils :refer [parse-jwt]] [clojure.string :as str] [goog.crypt.base64 :as base64] - [minisearch :as ms])) + [minisearch :as ms] + [clojure.set :as set])) (set! *warn-on-infer* true) #_{:clj-kondo/ignore [:clojure-lsp/unused-public-var :unresolved-symbol]} @@ -14,8 +15,10 @@ (re-frame/reg-sub ::client - (fn [db] - (get (:clients db) (:client db)))) + :<- [::selected-clients] + (fn [selected-clients] + (when (= 1 (count selected-clients)) + (first selected-clients)))) (re-frame/reg-sub ::clients @@ -24,26 +27,32 @@ (sort-by :name (vals (:clients db)))))) (re-frame/reg-sub - ::selected-clients + ::selected-clients-raw (fn [db] - (let [selected-clients (:selected-clients db)] - (cond (= :mine selected-clients) - (sort-by :name - (:user/clients (parse-jwt (:user db)))) + (:selected-clients db))) - (or (and (sequential? selected-clients) - (empty? selected-clients)) - (= :all selected-clients) - (nil? selected-clients)) - (sort-by :name - (vals - (:clients db))) +(re-frame/reg-sub + ::selected-clients + :<- [::selected-clients-raw] + :<- [::user] + :<- [::clients] + (fn [[selected-clients user clients]] + + (cond (= :mine selected-clients) + (sort-by :name + (:user/clients user)) - (sequential? selected-clients) - selected-clients + (or (and (sequential? selected-clients) + (empty? selected-clients)) + (= :all selected-clients) + (nil? selected-clients)) + clients - :else - nil)))) + (sequential? selected-clients) + (filter (comp (set selected-clients) js/parseInt :id) clients) + + :else + nil))) (re-frame/reg-sub ::client-refs diff --git a/src/cljs/auto_ap/views/components/invoice_table.cljs b/src/cljs/auto_ap/views/components/invoice_table.cljs index db401501..bf757c4a 100644 --- a/src/cljs/auto_ap/views/components/invoice_table.cljs +++ b/src/cljs/auto_ap/views/components/invoice_table.cljs @@ -21,8 +21,7 @@ (defn data-params->query-params [params] (if (:exact-match-id params) - {:exact-match-id (some-> params :exact-match-id str) - :client-id (:id @(re-frame/subscribe [::subs/client]))} + {:exact-match-id (some-> params :exact-match-id str)} {:exact-match-id (some-> params :exact-match-id str) :start (:start params 0) :sort (:sort params) @@ -38,7 +37,6 @@ :unresolved (:unresolved params) :scheduled-payments (:scheduled-payments params) :invoice-number-like (:invoice-number-like params) - :client-id (:id @(re-frame/subscribe [::subs/client])) :import-status (:import-status params) :status (condp = @(re-frame/subscribe [::subs/active-page]) :invoices nil @@ -241,6 +239,7 @@ (defn invoice-table [{:keys [check-boxes overrides actions data-page checkable-fn action-buttons]}] (let [{:keys [data status params table-params]} @(re-frame/subscribe [::data-page/page data-page]) selected-client @(re-frame/subscribe [::subs/client]) + x @(re-frame/subscribe [::subs/selected-clients]) is-loading? (= :loading (:state status)) is-sorted-by-vendor? (and (= "vendor" (:sort-key (first (:sort table-params)))) (not is-loading?) diff --git a/src/cljs/auto_ap/views/components/layouts.cljs b/src/cljs/auto_ap/views/components/layouts.cljs index 924def3a..718495cd 100644 --- a/src/cljs/auto_ap/views/components/layouts.cljs +++ b/src/cljs/auto_ap/views/components/layouts.cljs @@ -94,12 +94,19 @@ (defn client-dropdown [] (let [client (re-frame/subscribe [::subs/client]) clients @(re-frame/subscribe [::subs/selected-clients]) + selected-client-raw @(re-frame/subscribe [::subs/selected-clients-raw]) matching-clients @(re-frame/subscribe [::matching-clients]) user (re-frame/subscribe [::subs/user])] [navbar-drop-down {:header (str "Company: " (cond @client (:name @client) + (= :mine selected-client-raw) + "My Companies" + + (= :all selected-client-raw) + "All Companies" + :else (str (count (or clients [])) " Clients"))) :id ::select-client} @@ -126,8 +133,8 @@ ^{:key id } [:a {:class "navbar-item" :on-click (fn [] - (re-frame/dispatch [::events/toggle-menu ::select-client]) - (re-frame/dispatch [::events/swap-client client])) + (re-frame/dispatch-sync [::events/toggle-menu ::select-client]) + (re-frame/dispatch-sync [::events/swap-client client])) } name])]])) (defn navbar [] diff --git a/src/cljs/auto_ap/views/main.cljs b/src/cljs/auto_ap/views/main.cljs index 83d65e75..b98ddb68 100644 --- a/src/cljs/auto_ap/views/main.cljs +++ b/src/cljs/auto_ap/views/main.cljs @@ -155,7 +155,7 @@ (defn active-page [] (let [ap (re-frame/subscribe [::subs/active-page]) - current-client @(re-frame/subscribe [::subs/client]) + current-client (pr-str @(re-frame/subscribe [::subs/selected-clients-raw])) is-loading? @(re-frame/subscribe [::subs/is-initial-loading?])] (when @ap (if is-loading? diff --git a/src/cljs/auto_ap/views/pages/data_page.cljs b/src/cljs/auto_ap/views/pages/data_page.cljs index b4a50525..76f8d2e3 100644 --- a/src/cljs/auto_ap/views/pages/data_page.cljs +++ b/src/cljs/auto_ap/views/pages/data_page.cljs @@ -66,23 +66,23 @@ ::params (fn [[_ id]] [ #_(re-frame/subscribe [::subs/active-page]) - (re-frame/subscribe [::subs/client]) (re-frame/subscribe [::settled-filters id]) (re-frame/subscribe [::table-params id]) - (re-frame/subscribe [::additional-params id])]) - (fn [[client filters table-params additional-params]] + (re-frame/subscribe [::additional-params id]) + (re-frame/subscribe [::subs/selected-clients])]) + (fn [[filters table-params additional-params selected-clients]] (let [query-params (u/query-params)] - (cond-> {} - client (assoc :client-id (:id client)) - (seq query-params) (merge query-params) - (seq filters) (merge filters) - (seq table-params) (merge table-params) - (seq additional-params) (merge additional-params))))) + (cond-> {:selected-clients selected-clients} + (seq query-params) (merge query-params) + (seq filters) (merge filters) + (seq table-params) (merge table-params) + (seq additional-params) (merge additional-params) + )))) (re-frame/reg-event-fx ::received (fn [{:keys [db]} [_ id data]] - (let [uri-params (dissoc @(re-frame/subscribe [::params id]) :client-id) + (let [uri-params (dissoc @(re-frame/subscribe [::params id]) :selected-clients) current-uri-params (u/query-params)] (cond-> {:db (-> db (assoc-in [::data id] data) (assoc :query-params uri-params))} diff --git a/src/cljs/auto_ap/views/pages/ledger.cljs b/src/cljs/auto_ap/views/pages/ledger.cljs index 0be4d622..7e1efbfc 100644 --- a/src/cljs/auto_ap/views/pages/ledger.cljs +++ b/src/cljs/auto_ap/views/pages/ledger.cljs @@ -22,7 +22,6 @@ :sort (:sort params) :exact-match-id (:exact-match-id params) :per-page (:per-page params) - :client-id (:id @(re-frame/subscribe [::subs/client])) :vendor-id (:id (:vendor params)) :date-range (:date-range params) :account-id (:id (:account params)) diff --git a/src/cljs/auto_ap/views/pages/ledger/external_ledger.cljs b/src/cljs/auto_ap/views/pages/ledger/external_ledger.cljs index 4fa6f330..3ffdc9fd 100644 --- a/src/cljs/auto_ap/views/pages/ledger/external_ledger.cljs +++ b/src/cljs/auto_ap/views/pages/ledger/external_ledger.cljs @@ -21,7 +21,6 @@ {:start (:start params 0) :sort (:sort params) :per-page (:per-page params) - :client-id (:id @(re-frame/subscribe [::subs/client])) :vendor-id (:id (:vendor params)) :date-range (:date-range params) :account-id (:id (:account params)) diff --git a/src/cljs/auto_ap/views/pages/payments.cljs b/src/cljs/auto_ap/views/pages/payments.cljs index d4456d04..beb244df 100644 --- a/src/cljs/auto_ap/views/pages/payments.cljs +++ b/src/cljs/auto_ap/views/pages/payments.cljs @@ -18,12 +18,10 @@ (defn data-params->query-params [params] (if (:exact-match-id params) - {:client-id (:id @(re-frame/subscribe [::subs/client])) - :exact-match-id (some-> (:exact-match-id params) str)} + {:exact-match-id (some-> (:exact-match-id params) str)} {:start (:start params 0) :per-page (:per-page params) :sort (:sort params) - :client-id (:id @(re-frame/subscribe [::subs/client])) :vendor-id (:id (:vendor params)) :payment-type (:payment-type params) :status (:status params) diff --git a/src/cljs/auto_ap/views/pages/pos/sales_orders.cljs b/src/cljs/auto_ap/views/pages/pos/sales_orders.cljs index 09e954b7..65e41d35 100644 --- a/src/cljs/auto_ap/views/pages/pos/sales_orders.cljs +++ b/src/cljs/auto_ap/views/pages/pos/sales_orders.cljs @@ -30,8 +30,7 @@ :total-gte (:amount-gte (:total-range params)) :total-lte (:amount-lte (:total-range params)) :date-range (:date-range params) - :processor (some-> (:processor params) keyword) - :client-id (:id @(re-frame/subscribe [::subs/client]))} + :processor (some-> (:processor params) keyword)} [[:sales-orders [:id :source :total :tax :tip :reference-link :discount :service-charge :returns :date [:charges [:type-name :note :reference-link :total :processor :id [:expected-deposit [:id]] ]] [:line-items [:item-name :total :category]] diff --git a/src/cljs/auto_ap/views/pages/reports.cljs b/src/cljs/auto_ap/views/pages/reports.cljs index 9afceff2..ac408388 100644 --- a/src/cljs/auto_ap/views/pages/reports.cljs +++ b/src/cljs/auto_ap/views/pages/reports.cljs @@ -16,8 +16,7 @@ (defn data-params->query-params [params] {:start (:start params 0) :sort (:sort params) - :per-page (:per-page params) - :client-id (:id @(re-frame/subscribe [::subs/client]))}) + :per-page (:per-page params)}) (re-frame/reg-event-fx diff --git a/src/cljs/auto_ap/views/pages/scratch b/src/cljs/auto_ap/views/pages/scratch new file mode 100644 index 00000000..a680eaf5 --- /dev/null +++ b/src/cljs/auto_ap/views/pages/scratch @@ -0,0 +1,7 @@ +, kq5hoyos artstyle, sylart artstyle, , vibrant, by artgerm and greg rutkowski, {Crystal Arborium, trees with gemstone leaves casting prismatic light, crystal fruits that chime when touched, iridescent fireflies, harmonious tinkling of colors. | Wandering Whirlpools, pools of water that spin like whirlpools, leading to other realms, aquatic creatures spiraling within, shimmering reflections, aquatic crossroads.| Quicksilver Quicksands, silver sand that shifts in patterns, forming silver statues, mercury-like ripples, mesmerizing shimmer, sparkling quicksand traps, surreal terrain.| Gossamer Gorge, suspension bridges made of spider silk, luminescent spiders weaving intricate patterns, delicate dewdrop nets, moonlit ambiance, treetop pathways.| Enchanted Atrium, blooming crystal flowers that change color with music, sentient vines creating harmonious melodies, ethereal aromas, botanical symphony.| Bubble Bay, floating soap bubbles as boats, underwater bubble tunnels, bubble architecture, rainbow-bubble sea, aquatic creatures wearing bubble helmets, joyful buoyancy.| Paradox Plaza, constantly shifting architecture, impossible angles, staircases that lead to themselves, topsy-turvy doorways, endless loops, reality-defying environment.| Cogwheel Cathedral, cathedral made entirely of interlocking gears, stained glass windows of rotating mechanisms, mechanical choir, divine clockwork wonders.| Mirthful Mirage, desert of shimmering illusions, mirage creatures that interact with visitors, playfully puzzling paths, oasis mirages with real refreshments, enchanting delusions.| Blossom Blizzard, cherry blossom trees with petals that swirl like snow, magical blizzard of petals, fleeting cherry blossom creatures, ephemeral beauty, delicate storms.| Umbra Underground, subterranean realm with glowing shadow creatures, walls that shift with darkness, pools of liquid shadow, eerie bioluminescence, mystical gloom.| Constellation Cove, beach with sand that glows like stars, tide pools with celestial creatures, skyward-reaching palms, galaxies reflected in tidal mirrors, cosmic tranquility.| Labyrinth of Illusions, maze of shifting walls, mirage-like turns, optical illusion pathways, confusing realities, enchanted whispers guiding the lost, captivating confusion.| Aurora Archipelago, floating islands in the sky, colorful auroras that connect the islands, luminous clouds, gravity-defying flora, radiant night skies, breathtaking horizons.| Zephyr Zenith, floating sky temple with transparent floors, wispy clouds as seating, gentle winds carrying soothing mantras, meditation platforms suspended in air.| Prism Prism, valley of prismatic crystals, sunlight refracting into rainbows, vibrant hues dancing on every surface, gemstone creatures, kaleidoscopic beauty, mesmerizing charm.| Mirage Mirage (Yes, a different one!), shifting desert dunes with mirages of fantastical landscapes, illusory oases with genuine refreshments, playful mirage creatures, captivating trickery.| Celestial Caravan, caravan of flying creatures carrying mobile homes, aerial nomad community, skyward campfires, twinkling starlight, whimsical stargazing gatherings.| Echoing Embrace, enchanted cavern with walls that mimic and amplify sounds, harmonic echoes creating otherworldly music, chamber of sonorous enchantment.| Twilight Tapestry, woven sky tapestries that depict tales of constellations, animate and interact upon touch, storytelling threads, celestial artistry, living myths in the heavens.}, {close-up shot| extreme close-up shot|wide-angle shot|medium shot}, {high angle|low angle|eye level|}, {2$$cheerful|mysterious|friendly|peaceful|weird|creepy|dark|bright|exquisite|whimsical|illustration|mysterious|mystical|daft|evil|spirited|magical|pensive|cute|dystopian|utopian}, acrylic painting,masterpiece, trending or artstation, scene from a 2d point and click adventure game, , classipeint, {by rhads|by cyril rolando|by tyler edlin|} + + + + +, kq5hoyos artstyle, sylart artstyle, , vibrant, by artgerm and greg rutkowski, {A dense jungle filled with towering palm trees and vines hanging from every branch. The ground is covered in bright green moss and ferns, and the air is thick with humidity. You can hear birds chirping in the distance as you follow a dirt path leading deeper into the forest. | A clearing surrounded by tall oak trees, their leaves rustling in the wind. In the center of the space sits an old wooden picnic bench, partially covered with moss. Nearby, you can see the remnants of a campfire from last night's bonfire party - embers glowing red amidst ashes and twigs. | A narrow path winding through dense undergrowth. You can hear running water nearby; following it leads to a small clearing with a babbling brook flowing over rocks. Tall trees surround the area, their leaves rustling in the gentle breeze. | A sun-dappled meadow filled with wildflowers of every color: yellow daisies, purple clover and blue forget-me-nots sway gently in the wind. The ground is soft beneath your feet as you follow a winding dirt path leading to an old stone well surrounded by mossy rocks. | A dark forest filled with ancient trees whose branches reach skyward, their leaves blocking out much of the sunlight that filters through the canopy above. As you make your way along the dimly lit forest floor, you can hear the sounds of rustling leaves and twigs breaking underfoot - it's easy to imagine creatures lurking just beyond your sight line. | A dense fog rolling in from a nearby lake envelopes everything within its reach; visibility is limited to just a few feet ahead. The ground beneath your feet is damp and squishy, filled with moss and fallen leaves - it's almost like walking on sponges. As you push forward through the mist, be careful not to step into hidden puddles or sink too deeply in muddy ruts left by previous travelers. | A hillside covered in wildflowers and tall grass swaying gently in the wind. Nearby, a stone tower stands sentinel - its entrance hidden behind overgrown vines that seem to wrap themselves around it like a second skin. As you make your way up towards it, be careful not to step on any of the snakes sunning themselves on warm rocks or disturbing nests filled with baby birds waiting for their parents' return. | A forest glade surrounded by tall oak trees whose branches form an arch overhead, casting dappled shadows onto the grassy floor below. In the center sits a small wooden hut - it looks like someone has been living here in solitude for years. Nearby, you can see the remains of a campfire from last night's dinner; embers glowing red amidst ashes and twigs. | A rocky outcropping overlooking an old stone quarry where ancient blocks of granite are strewn about like discarded toys by giant hands long since departed the scene. The ground is littered with broken rocks, while tall trees grow from cracks in their sides - it's almost as if nature itself has reclaimed this abandoned place once used for industrial purposes. | A sunlit meadow surrounded by towering spruce trees whose branches form a canopy overhead; the ground is covered in soft moss that absorbs every step taken upon it. In the distance, you can see a quaint little village - its wooden cottages nestled amongst tall pines like eggs in a nest filled with greenery and sunshine. | A clearing surrounded by ancient oak trees whose trunks are covered in moss-covered vines that hang down like gnarly beards. In the center of the space, an old wooden bench sits beneath a canopy of leaves overhead; nearby, you can see the remnants of last night's campfire still smoldering amidst embers and ashes. | A dense forest filled with towering spruce trees whose branches form a thick canopy overhead - it's almost like walking through a green tunnel with sunlight filtering in from above. The ground is soft beneath your feet, covered in layers of fallen pine needles that crunch underfoot as you make your way deeper into the forest. }, {close-up shot| extreme close-up shot|wide-angle shot|medium shot}, {high angle|low angle|eye level|}, {2$$cheerful|mysterious|friendly|peaceful|weird|creepy|dark|bright|exquisite|whimsical|illustration|mysterious|mystical|daft|evil|spirited|magical|pensive|cute|dystopian|utopian}, acrylic painting,masterpiece, trending or artstation, scene from a 2d point and click adventure game, , classipeint, {by rhads|by cyril rolando|by tyler edlin|} + diff --git a/src/cljs/auto_ap/views/pages/transactions.cljs b/src/cljs/auto_ap/views/pages/transactions.cljs index 07f93fbd..7ec355a5 100644 --- a/src/cljs/auto_ap/views/pages/transactions.cljs +++ b/src/cljs/auto_ap/views/pages/transactions.cljs @@ -156,7 +156,8 @@ (let [is-admin? @(re-frame/subscribe [::subs/is-admin?]) params @(re-frame/subscribe [::data-page/params ::page]) checked @(re-frame/subscribe [::data-page/checked ::page]) - {:keys [total]} @(re-frame/subscribe [::data-page/data ::page])] + {:keys [total]} @(re-frame/subscribe [::data-page/data ::page]) + client @(re-frame/subscribe [::subs/client])] (when is-admin? [:<> [:div.level-item @@ -177,7 +178,7 @@ [:div.buttons [:button.button.is-outlined.is-primary {:on-click (dispatch-event [::manual/opening])} "Manual Yodlee Import"] - (when (:client-id params) + (when client [:button.button.is-warning {:on-click (dispatch-event [::bulk/code-requested checked params total]) :disabled (not (seq checked))} "Code"]) diff --git a/src/cljs/auto_ap/views/pages/transactions/common.cljs b/src/cljs/auto_ap/views/pages/transactions/common.cljs index fba49e12..c4c94eee 100644 --- a/src/cljs/auto_ap/views/pages/transactions/common.cljs +++ b/src/cljs/auto_ap/views/pages/transactions/common.cljs @@ -26,12 +26,10 @@ (defn data-params->query-params [params] (if (:exact-match-id params) - {:client-id (:id @(re-frame/subscribe [::subs/client])) - :exact-match-id (some-> (:exact-match-id params) str)} + {:exact-match-id (some-> (:exact-match-id params) str)} {:start (:start params 0) :per-page (:per-page params) :sort (:sort params) - :client-id (:id @(re-frame/subscribe [::subs/client])) :vendor-id (:id (:vendor params)) :date-range (:date-range params) :account-id (:id (:account params)) diff --git a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs index 703ba126..835ac734 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -24,14 +24,15 @@ [auto-ap.views.pages.invoices.form :as form] [auto-ap.views.pages.invoices.handwritten-checks :as handwritten-checks] [auto-ap.views.utils - :refer [dispatch-event dispatch-event-with-propagation with-user]] + :refer [dispatch-event dispatch-event-with-propagation with-user date->str standard]] [clojure.set :as set] [clojure.string :as str] [goog.string :as gstring] [re-frame.core :as re-frame] [reagent.core :as r] [vimsical.re-frame.cofx.inject :as inject] - [vimsical.re-frame.fx.track :as track])) + [vimsical.re-frame.fx.track :as track] + [cljs-time.core :as time])) (re-frame/reg-event-fx ::params-change @@ -60,7 +61,7 @@ (re-frame/reg-event-fx ::mounted - (fn [_ _] + (fn [{:keys [db]} _] {::track/register [{:id ::params :subscription [::data-page/params :invoices] :event-fn (fn [params] @@ -72,7 +73,9 @@ {:id ::checks-printed :events #{::form/checks-printed ::advanced-print-checks/checks-printed ::handwritten-checks/succeeded} :event-fn (fn [[_ invoices pdf-url]] - [::checks-printed invoices pdf-url])}]})) + [::checks-printed invoices pdf-url])}] + :db (assoc-in db [::data-page/settled-filters :invoices :date-range] {:start (date->str (time/plus (time/now) (time/months -6)) + standard)})})) (defn print-checks-query [invoice-payments bank-account-id type client-id] @@ -289,7 +292,8 @@ (defn unpaid-invoices-content [{:keys [status]}] (let [page @(re-frame/subscribe [::data-page/page :invoices]) - _ @(re-frame/subscribe [::subs/client])] + _ @(re-frame/subscribe [::subs/client]) + _ @(re-frame/subscribe [::subs/selected-clients])] [:div [:h1.title (str (str/capitalize (name (or status :all))) " invoices")] [status/status-notification {:statuses [[::status/single ::print-checks]