diff --git a/src/clj/auto_ap/handler.clj b/src/clj/auto_ap/handler.clj index bef08a6c..f714c293 100644 --- a/src/clj/auto_ap/handler.clj +++ b/src/clj/auto_ap/handler.clj @@ -308,9 +308,9 @@ (fn [request] (let [valid-clients (extract-client-ids (:clients request) (:client request) - (:client-id (:parsed-query-params request)) - (when (:client-code (:parsed-query-params request)) - [:client/code (:client-code (:parsed-query-params request))])) + (:client-id (:query-params request)) + (when (:client-code (:query-params request)) + [:client/code (:client-code (:query-params request))])) trimmed-clients (->> valid-clients (take 20) set)] (handler (assoc request :valid-client-ids valid-clients :valid-trimmed-client-ids trimmed-clients diff --git a/src/clj/auto_ap/query_params.clj b/src/clj/auto_ap/query_params.clj index 9d6c47a1..83895980 100644 --- a/src/clj/auto_ap/query_params.clj +++ b/src/clj/auto_ap/query_params.clj @@ -9,12 +9,6 @@ (fn [request] (handler (assoc request :parsed-query-params (:query-params request))))) -(defn wrap-parse-query-params [handler parser] - (fn parsed-handler [request] - (handler (assoc request :parsed-query-params (parser (->> (concat (:hx-query-params request) (:query-params request)) - (map (fn [[k v]] [(keyword k) v])) - (into {}))))))) - (defn parse-key [k parser] (fn [query-params] (if (contains? query-params k) @@ -24,9 +18,6 @@ (defn parse-date [d] (atime/parse d atime/normal-date)) -(defn parse-keyword [ns name] - (some->> name (keyword ns))) - (defn parse-sort [grid-spec q] (if (not-empty q) (->> diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 8d67176f..3b5ac0a0 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -1,47 +1,39 @@ (ns auto-ap.ssr.admin.accounts (:require [auto-ap.datomic - :refer [add-sorter-fields - apply-pagination - apply-sort-3 - audit-transact - conn - merge-query - pull-attr - pull-many - query2]] - [auto-ap.query-params :as query-params] + :refer [add-sorter-fields apply-pagination apply-sort-3 audit-transact + conn merge-query pull-attr pull-many query2]] + [auto-ap.query-params :as query-params :refer [wrap-copy-qp-pqp]] [auto-ap.routes.utils :refer [wrap-admin wrap-client-redirect-unauthenticated]] [auto-ap.solr :as solr] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] [auto-ap.ssr.form-cursor :as fc] - [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] [auto-ap.ssr.hx :as hx] [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] + [auto-ap.ssr.payments :refer [wrap-status-from-source]] [auto-ap.ssr.svg :as svg] [auto-ap.ssr.utils - :refer [apply-middleware-to-all-handlers - entity-id - field-validation-error - form-validation-error - html-response - main-transformer - many-entity - modal-response - ref->enum-schema - ref->select-options - strip - temp-id - wrap-entity - wrap-form-4xx-2 + :refer [apply-middleware-to-all-handlers clj-date-schema + default-grid-fields-schema entity-id field-validation-error + form-validation-error html-response main-transformer many-entity + modal-response ref->enum-schema ref->select-options strip temp-id + wrap-entity wrap-form-4xx-2 wrap-merge-prior-hx wrap-schema-enforce]] [bidi.bidi :as bidi] [clojure.string :as str] [datomic.api :as dc] [malli.core :as mc])) +(def query-schema (mc/schema + [:maybe + (into [:map {:date-range [:date-range :start-date :end-date]} + [:type {:optional true} [:maybe (ref->enum-schema "account-type")]] + [:name {:optional true} [:maybe [:string {:decode/string strip}]]] + [:code {:optional true} [:maybe nat-int?]]] + default-grid-fields-schema)])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes @@ -54,7 +46,7 @@ (com/text-input {:name "name" :id "name" :class "hot-filter" - :value (:name (:parsed-query-params request)) + :value (:name (:query-params request)) :placeholder "Cash" :size :small})) @@ -62,12 +54,13 @@ (com/text-input {:name "code" :id "code" :class "hot-filter" - :value (:code (:parsed-query-params request)) + :value (:code (:query-params request)) :placeholder "11101" :size :small})) (com/field {:label "Type"} (com/radio-card {:size :small :name "type" + :value (:type (:query-params request)) :options [{:value "" :content "All"} {:value "dividend" @@ -99,7 +92,7 @@ :db/id]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in '[$] :where '[]} @@ -127,10 +120,8 @@ (some->> query-params :type) (merge-query {:query {:find [] - :in ['?rir] - :where ['[?e :account/type ?r] - '[?r :db/ident ?ri] - '[(name ?ri) ?rir] ]} + :in ['?r] + :where ['[?e :account/type ?r] ]} :args [(some->> query-params :type)]}) true @@ -161,9 +152,6 @@ :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page - :parse-query-params (comp - (query-params/parse-key :code query-params/parse-long) - (helper/default-parse-query-params grid-page)) :action-buttons (fn [_] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-account-new-dialog)) @@ -183,6 +171,7 @@ "Accounts"]] :title "Accounts" :entity-name "Account" + :query-schema query-schema :route :admin-account-table :headers [{:key "code" :name "Code" @@ -431,25 +420,31 @@ (def key->handler - (apply-middleware-to-all-handlers - (->> - {:admin-accounts (helper/page-route grid-page) - :admin-account-table (helper/table-route grid-page) - :admin-account-client-override-new (-> new-client-override - (wrap-schema-enforce :query-schema [:map - [:index {:optional true - :default 0} [nat-int? {:default 0}]]]) - wrap-admin wrap-client-redirect-unauthenticated) - :admin-account-save (-> account-save - (wrap-entity [:form-params :db/id] default-read) - (wrap-schema-enforce :form-schema form-schema) - (wrap-nested-form-params) - (wrap-form-4xx-2 (wrap-entity account-dialog [:form-params :db/id] default-read))) - :admin-account-edit-dialog (-> account-dialog - (wrap-entity [:route-params :db/id] default-read) - (wrap-schema-enforce :route-schema [:map [:db/id entity-id]])) - :admin-account-new-dialog account-dialog}) - (fn [h] - (-> h - (wrap-admin) - (wrap-client-redirect-unauthenticated))))) + (apply-middleware-to-all-handlers + (->> + {:admin-accounts (helper/page-route grid-page) + :admin-account-table (helper/table-route grid-page) + :admin-account-client-override-new (-> new-client-override + (wrap-schema-enforce :query-schema [:map + [:index {:optional true + :default 0} [nat-int? {:default 0}]]]) + wrap-admin wrap-client-redirect-unauthenticated) + :admin-account-save (-> account-save + (wrap-entity [:form-params :db/id] default-read) + (wrap-schema-enforce :form-schema form-schema) + (wrap-nested-form-params) + (wrap-form-4xx-2 (wrap-entity account-dialog [:form-params :db/id] default-read))) + :admin-account-edit-dialog (-> account-dialog + (wrap-entity [:route-params :db/id] default-read) + (wrap-schema-enforce :route-schema [:map [:db/id entity-id]])) + :admin-account-new-dialog account-dialog}) + (fn [h] + (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-status-from-source) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) + (wrap-admin) + (wrap-client-redirect-unauthenticated))))) diff --git a/src/clj/auto_ap/ssr/admin/background_jobs.clj b/src/clj/auto_ap/ssr/admin/background_jobs.clj index db060354..b5576aa1 100644 --- a/src/clj/auto_ap/ssr/admin/background_jobs.clj +++ b/src/clj/auto_ap/ssr/admin/background_jobs.clj @@ -85,6 +85,7 @@ (filter is-background-job?) (map ecs-task->job))] [jobs (count jobs)])) +(def query-schema (mc/schema [:map ])) (def grid-page (helper/build {:id "job-table" @@ -104,6 +105,7 @@ "Background Jobs"]] :title "Jobs" :entity-name "Job" + :query-schema query-schema :route :admin-job-table :headers [ {:key "start" diff --git a/src/clj/auto_ap/ssr/admin/clients.clj b/src/clj/auto_ap/ssr/admin/clients.clj index ddc259c7..99cb81dc 100644 --- a/src/clj/auto_ap/ssr/admin/clients.clj +++ b/src/clj/auto_ap/ssr/admin/clients.clj @@ -216,8 +216,6 @@ :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page - :parse-query-params (fn [p] - (mc/decode query-schema p main-transformer)) :action-buttons (fn [_] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/new-dialog)) :color :primary} @@ -237,6 +235,7 @@ "Clients"]] :title "Clients" :entity-name "Client" + :query-schema query-schema :route ::route/table :headers [{:key "name" :name "Name" @@ -1848,8 +1847,8 @@ (def key->handler (apply-middleware-to-all-handlers - {::route/page (helper/page-route grid-page :parse-query-params? false) - ::route/table (helper/table-route grid-page :parse-query-params? false) + {::route/page (helper/page-route grid-page) + ::route/table (helper/table-route grid-page) ::route/new-location (add-new-primitive-handler [:step-params :client/locations] "" location-row) diff --git a/src/clj/auto_ap/ssr/admin/import_batch.clj b/src/clj/auto_ap/ssr/admin/import_batch.clj index 68ae0b8e..5f557c4c 100644 --- a/src/clj/auto_ap/ssr/admin/import_batch.clj +++ b/src/clj/auto_ap/ssr/admin/import_batch.clj @@ -1,31 +1,38 @@ (ns auto-ap.ssr.admin.import-batch (:require + [auto-ap.client-routes :as client-routes] [auto-ap.datomic - :refer [add-sorter-fields - apply-pagination - apply-sort-3 - conn - merge-query - pull-many - query2]] + :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query + pull-many query2]] + [auto-ap.query-params :refer [wrap-copy-qp-pqp]] [auto-ap.routes.admin.import-batch :as route] [auto-ap.routes.utils :refer [wrap-admin wrap-client-redirect-unauthenticated]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] [auto-ap.ssr.components.date-range :refer [date-range-field]] - [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.svg :as svg] [auto-ap.ssr.utils - :refer [apply-middleware-to-all-handlers ref->select-options]] + :refer [apply-middleware-to-all-handlers clj-date-schema + default-grid-fields-schema ref->select-options wrap-merge-prior-hx + wrap-schema-enforce]] [auto-ap.time :as atime] [bidi.bidi :as bidi] - [clj-time.coerce :as coerce] - [datomic.api :as dc] [clj-time.coerce :as c] - [auto-ap.logging :as alog] + [datomic.api :as dc] [hiccup.util :as hu] - [auto-ap.client-routes :as client-routes] - [auto-ap.ssr.svg :as svg])) + [malli.core :as mc])) + +(def query-schema (mc/schema + [:maybe + (into [:map {:date-range [:date-range :start-date :end-date]} + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]] + [:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]]] + default-grid-fields-schema)])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -35,13 +42,13 @@ "hx-indicator" "#entity-table"} [:fieldset.space-y-6 - (date-range-field {:value {:start (:start-date (:parsed-query-params request)) - :end (:end-date (:parsed-query-params request))} + (date-range-field {:value {:start (:start-date (:query-params request)) + :end (:end-date (:query-params request))} :id "date-range"}) (com/field {:label "Source"} (com/select {:name "source" :class "hot-filter w-full" - :value (:source (:parsed-query-params request)) + :value (:source (:query-params request)) :placeholder "" :options (ref->select-options "import-source" :allow-nil? true)})) @@ -49,7 +56,7 @@ (com/text-input {:name "code" :id "code" :class "hot-filter" - :value (:code (:parsed-query-params request)) + :value (:code (:query-params request)) :placeholder "11101" :size :small}))]]) @@ -63,7 +70,7 @@ [:import-batch/status :xform iol-ion.query/ident] [:db/ident]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in '[$ ] :where '[]} @@ -134,11 +141,9 @@ svg/external-link)]) :oob-render (fn [request] - [(assoc-in (date-range-field {:value {:start (:start-date (:parsed-query-params request)) - :end (:end-date (:parsed-query-params request))} + [(assoc-in (date-range-field {:value {:start (:start-date (:query-params request)) + :end (:end-date (:query-params request))} :id "date-range"}) [1 :hx-swap-oob] true)]) - :parse-query-params (comp - (helper/default-parse-query-params grid-page)) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} "Admin"] @@ -148,6 +153,7 @@ "Import Batches"]] :title "Import Batches" :entity-name "Batch" + :query-schema query-schema :route ::route/table :headers [{:key "date" :name "Date" @@ -184,5 +190,11 @@ ::route/table (helper/table-route grid-page)}) (fn [h] (-> h + + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) (wrap-admin) (wrap-client-redirect-unauthenticated))))) diff --git a/src/clj/auto_ap/ssr/admin/sales_summaries.clj b/src/clj/auto_ap/ssr/admin/sales_summaries.clj index df258763..55c67617 100644 --- a/src/clj/auto_ap/ssr/admin/sales_summaries.clj +++ b/src/clj/auto_ap/ssr/admin/sales_summaries.clj @@ -1,32 +1,45 @@ (ns auto-ap.ssr.admin.sales-summaries - (:require [auto-ap.datomic + (:require + [auto-ap.datomic :refer [apply-pagination apply-sort-3 conn merge-query pull-many query2]] - [auto-ap.datomic.accounts :as d-accounts] - [auto-ap.graphql.utils :refer [extract-client-ids]] - [auto-ap.routes.admin.sales-summaries :as route] - [auto-ap.routes.utils + [auto-ap.datomic.accounts :as d-accounts] + [auto-ap.graphql.utils :refer [extract-client-ids]] + [auto-ap.query-params :refer [wrap-copy-qp-pqp]] + [auto-ap.routes.admin.sales-summaries :as route] + [auto-ap.routes.utils :refer [wrap-admin wrap-client-redirect-unauthenticated]] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.ssr.common-handlers :refer [add-new-entity-handler]] - [auto-ap.ssr.components :as com] - [auto-ap.ssr.components.multi-modal :as mm] - [auto-ap.ssr.form-cursor :as fc] - [auto-ap.ssr.grid-page-helper :as helper] - [auto-ap.ssr.hx :as hx] - [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.utils - :refer [apply-middleware-to-all-handlers entity-id html-response - money strip temp-id wrap-schema-enforce]] - [auto-ap.time :as atime] - [bidi.bidi :as bidi] - [clj-time.coerce :as c] - [clojure.string :as str] - [datomic.api :as dc] - [hiccup.util :as hu] - [iol-ion.query :refer [dollars=]] - [malli.core :as mc] - [malli.util :as mut])) + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.common-handlers :refer [add-new-entity-handler]] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.components.multi-modal :as mm] + [auto-ap.ssr.form-cursor :as fc] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils + :refer [apply-middleware-to-all-handlers clj-date-schema + default-grid-fields-schema entity-id html-response money + strip temp-id wrap-merge-prior-hx wrap-schema-enforce]] + [auto-ap.time :as atime] + [bidi.bidi :as bidi] + [clj-time.coerce :as c] + [clojure.string :as str] + [datomic.api :as dc] + [hiccup.util :as hu] + [iol-ion.query :refer [dollars=]] + [malli.core :as mc] + [malli.util :as mut])) + +(def query-schema (mc/schema + [:maybe + (into [:map {:date-range [:date-range :start-date :end-date]} + + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]] ] + default-grid-fields-schema)])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -36,13 +49,13 @@ "hx-indicator" "#entity-table"} #_[:fieldset.space-y-6 - (date-range-field {:value {:start (:start-date (:parsed-query-params request)) - :end (:end-date (:parsed-query-params request))} + (date-range-field {:value {:start (:start-date (:query-params request)) + :end (:end-date (:query-params request))} :id "date-range"}) (com/field {:label "Source"} (com/select {:name "source" :class "hot-filter w-full" - :value (:source (:parsed-query-params request)) + :value (:source (:query-params request)) :placeholder "" :options (ref->select-options "import-source" :allow-nil? true)})) @@ -50,7 +63,7 @@ (com/text-input {:name "code" :id "code" :class "hot-filter" - :value (:code (:parsed-query-params request)) + :value (:code (:query-params request)) :placeholder "11101" :size :small}))]]) @@ -69,7 +82,7 @@ } ]) ;; TODO (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) valid-clients (extract-client-ids (:clients request) (:client request) (:client-id query-params) @@ -159,6 +172,7 @@ :nav com/admin-aside-nav :fetch-page fetch-page :page-specific-nav filters + :query-schema query-schema :row-buttons (fn [_ entity] [(com/icon-button {:hx-get (bidi/path-for ssr-routes/only-routes ::route/edit-wizard @@ -166,11 +180,9 @@ svg/pencil)]) :oob-render (fn [request] - [#_(assoc-in (date-range-field {:value {:start (:start-date (:parsed-query-params request)) - :end (:end-date (:parsed-query-params request))} + [#_(assoc-in (date-range-field {:value {:start (:start-date (:query-params request)) + :end (:end-date (:query-params request))} :id "date-range"}) [1 :hx-swap-oob] true)]) ;; TODO - :parse-query-params (comp - (helper/default-parse-query-params grid-page)) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} "Admin"] @@ -516,26 +528,33 @@ {::route/page (helper/page-route grid-page) ::route/table (helper/table-route grid-page) ::route/edit-wizard (-> mm/open-wizard-handler - (mm/wrap-wizard edit-wizard) - (mm/wrap-init-multi-form-state initial-edit-wizard-state) - (wrap-schema-enforce :route-schema [:map [:db/id entity-id]])) + (mm/wrap-wizard edit-wizard) + (mm/wrap-init-multi-form-state initial-edit-wizard-state) + (wrap-schema-enforce :route-schema [:map [:db/id entity-id]])) ::route/edit-wizard-navigate (-> mm/next-handler - (mm/wrap-wizard edit-wizard) - (mm/wrap-decode-multi-form-state)) + (mm/wrap-wizard edit-wizard) + (mm/wrap-decode-multi-form-state)) ::route/new-summary-item (-> (add-new-entity-handler [:step-params :sales-summary/items] - (fn render [cursor request] - (sales-summary-item-row* - {:value cursor - :client-id (:client-id (:query-params request)) })) - (fn build-new-row [base _] - (assoc base :sales-summary-item/manual? true))) - (wrap-schema-enforce :query-schema [:map - [:client-id {:optional true} - [:maybe entity-id]]])) + (fn render [cursor request] + (sales-summary-item-row* + {:value cursor + :client-id (:client-id (:query-params request))})) + (fn build-new-row [base _] + (assoc base :sales-summary-item/manual? true))) + (wrap-schema-enforce :query-schema [:map + [:client-id {:optional true} + [:maybe entity-id]]])) ::route/edit-wizard-submit (-> mm/submit-handler - (mm/wrap-wizard edit-wizard) - (mm/wrap-decode-multi-form-state))}) + (mm/wrap-wizard edit-wizard) + (mm/wrap-decode-multi-form-state))}) (fn [h] (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) (wrap-admin) (wrap-client-redirect-unauthenticated))))) + + diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 2a9d763c..5aae28cc 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -1,43 +1,49 @@ (ns auto-ap.ssr.admin.transaction-rules - (:require [auto-ap.datomic + (:require + [auto-ap.datomic :refer [add-sorter-fields apply-pagination apply-sort-3 audit-transact conn merge-query pull-attr pull-many query2 remove-nils]] - [auto-ap.datomic.accounts :as d-accounts] - [auto-ap.datomic.transactions :as d-transactions] - [auto-ap.graphql.utils :refer [extract-client-ids]] - [auto-ap.logging :as alog] - [auto-ap.query-params :as query-params] - [auto-ap.routes.admin.transaction-rules :as route] - [auto-ap.routes.utils + [auto-ap.datomic.accounts :as d-accounts] + [auto-ap.datomic.transactions :as d-transactions] + [auto-ap.graphql.utils :refer [extract-client-ids]] + [auto-ap.query-params :as query-params :refer [wrap-copy-qp-pqp]] + [auto-ap.routes.admin.transaction-rules :as route] + [auto-ap.routes.utils :refer [wrap-admin wrap-client-redirect-unauthenticated]] - [auto-ap.rule-matching :as rm] - [auto-ap.solr :as solr] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.ssr.common-handlers :refer [add-new-entity-handler]] - [auto-ap.ssr.company :refer [bank-account-typeahead*]] - [auto-ap.ssr.components :as com] - [auto-ap.ssr.components.multi-modal :as mm] - [auto-ap.ssr.form-cursor :as fc] - [auto-ap.ssr.grid-page-helper :as helper] - [auto-ap.ssr.hx :as hx] - [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.utils - :refer [apply-middleware-to-all-handlers entity-id + [auto-ap.rule-matching :as rm] + [auto-ap.solr :as solr] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.common-handlers :refer [add-new-entity-handler]] + [auto-ap.ssr.company :refer [bank-account-typeahead*]] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.components.multi-modal :as mm] + [auto-ap.ssr.form-cursor :as fc] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils + :refer [apply-middleware-to-all-handlers + default-grid-fields-schema entity-id field-validation-error form-validation-error html-response many-entity modal-response money percentage ref->enum-schema ref->radio-options regex temp-id - wrap-entity wrap-schema-enforce]] - [auto-ap.time :as atime] - [auto-ap.utils :refer [dollars=]] - [bidi.bidi :as bidi] - [clj-time.coerce :as coerce] - [clojure.set :as set] - [clojure.string :as str] - [datomic.api :as dc] - [malli.core :as mc] - [malli.util :as mut])) + wrap-entity wrap-merge-prior-hx wrap-schema-enforce]] + [auto-ap.time :as atime] + [auto-ap.utils :refer [dollars=]] + [bidi.bidi :as bidi] + [clj-time.coerce :as coerce] + [clojure.set :as set] + [clojure.string :as str] + [datomic.api :as dc] + [malli.core :as mc] + [malli.util :as mut])) +(def query-schema (mc/schema + [:maybe + (into [:map {} + [:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]] ] + default-grid-fields-schema)])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes @@ -52,14 +58,14 @@ :url (bidi/path-for ssr-routes/only-routes :vendor-search) :id (str "vendor-search") - :value (:vendor (:parsed-query-params request)) + :value (:vendor (:query-params request)) :value-fn :db/id :content-fn :vendor/name})) (com/field {:label "Note"} (com/text-input {:name "note" :id "note" :class "hot-filter" - :value (:note (:parsed-query-params request)) + :value (:note (:query-params request)) :placeholder "HOME DEPOT lte 250.0" :size :small})) @@ -67,14 +73,14 @@ (com/text-input {:name "description" :id "description" :class "hot-filter" - :value (:description (:parsed-query-params request)) + :value (:description (:query-params request)) :placeholder "LOWES" :size :small})) (com/field {:label "Client group"} (com/text-input {:name "client-group" :id "client-group" :class "hot-filter" - :value (:client-group (:parsed-query-params request)) + :value (:client-group (:query-params request)) :placeholder "NTG" :size :small}))]]) @@ -100,7 +106,7 @@ :db/id]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) valid-clients (extract-client-ids (:clients request) (:client request) (:client-id query-params) @@ -179,9 +185,6 @@ :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page - :parse-query-params (comp - (query-params/parse-key :vendor #(dc/pull (dc/db conn) '[:vendor/name :db/id] (Long/parseLong %))) - (helper/default-parse-query-params grid-page)) :action-buttons (fn [request] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/new-dialog)) :color :primary} @@ -206,6 +209,7 @@ "Transaction Rules"]] :title "Rules" :entity-name "Rule" + :query-schema query-schema :route ::route/table :headers [{:key "client" :name "Client" @@ -999,5 +1003,10 @@ {}))))}) (fn [h] (-> h +(wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) (wrap-admin) (wrap-client-redirect-unauthenticated))))) diff --git a/src/clj/auto_ap/ssr/admin/vendors.clj b/src/clj/auto_ap/ssr/admin/vendors.clj index faf7f455..36a6404d 100644 --- a/src/clj/auto_ap/ssr/admin/vendors.clj +++ b/src/clj/auto_ap/ssr/admin/vendors.clj @@ -1,38 +1,48 @@ (ns auto-ap.ssr.admin.vendors - (:require [auto-ap.cursor :as cursor] - [auto-ap.datomic - :refer [add-sorter-fields apply-pagination apply-sort-3 audit-transact - audit-transact-batch audit-transact-batch conn merge-query - pull-attr pull-many query2]] - [auto-ap.datomic.accounts :as d-accounts] - [auto-ap.logging :as alog] - [auto-ap.query-params :as query-params] - [auto-ap.routes.admin.vendors :as route] - [auto-ap.routes.utils + (:require + [auto-ap.cursor :as cursor] + [auto-ap.datomic + :refer [add-sorter-fields apply-pagination apply-sort-3 + audit-transact audit-transact-batch audit-transact-batch + conn merge-query pull-attr pull-many query2]] + [auto-ap.datomic.accounts :as d-accounts] + [auto-ap.logging :as alog] + [auto-ap.query-params :refer [wrap-copy-qp-pqp]] + [auto-ap.routes.admin.vendors :as route] + [auto-ap.routes.utils :refer [wrap-admin wrap-client-redirect-unauthenticated]] - [auto-ap.solr :as solr] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.ssr.common-handlers :refer [add-new-entity-handler - add-new-primitive-handler]] - [auto-ap.ssr.components :as com] - [auto-ap.ssr.components.multi-modal :as mm] - [auto-ap.ssr.components.timeline :as timeline] - [auto-ap.ssr.form-cursor :as fc] - [auto-ap.ssr.grid-page-helper :as helper] - [auto-ap.ssr.hx :as hx] - [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.utils - :refer [apply-middleware-to-all-handlers entity-id form-validation-error - html-response many-entity modal-response ref->enum-schema - ref->select-options strip temp-id wrap-entity wrap-form-4xx-2 + [auto-ap.solr :as solr] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.common-handlers :refer [add-new-entity-handler + add-new-primitive-handler]] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.components.multi-modal :as mm] + [auto-ap.ssr.components.timeline :as timeline] + [auto-ap.ssr.form-cursor :as fc] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils + :refer [apply-middleware-to-all-handlers + default-grid-fields-schema entity-id + form-validation-error html-response many-entity + modal-response ref->enum-schema ref->select-options strip + temp-id wrap-entity wrap-form-4xx-2 wrap-merge-prior-hx wrap-schema-enforce]] - [bidi.bidi :as bidi] - [clojure.string :as str] - [datomic.api :as dc] - [malli.core :as mc] - [malli.transform :as mt] - [malli.util :as mut])) + [bidi.bidi :as bidi] + [clojure.string :as str] + [datomic.api :as dc] + [malli.core :as mc] + [malli.transform :as mt] + [malli.util :as mut])) +(def query-schema (mc/schema + [:maybe + (into [:map {} + [:name {:optional true :default nil} [:maybe [:string {:string/decode strip}]]] + #_[:role {:optional true} [:maybe (ref->enum-schema "user-role")]] + #_[:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]] ] + default-grid-fields-schema)])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes @@ -45,13 +55,13 @@ (com/text-input {:name "name" :id "name" :class "hot-filter" - :value (:name (:parsed-query-params request)) + :value (:name (:query-params request)) :placeholder "Cash" :size :small})) (com/field {:label "Type"} (com/radio-card {:size :small :name "type" - :value (:type (:parsed-query-params request)) + :value (:type (:query-params request)) :options [{:value "" :content "All"} {:value "only-hidden" @@ -84,7 +94,7 @@ [:vendor/legal-entity-tin-type :xform iol-ion.query/ident] [:db/ident]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in '[$] :where '[]} @@ -139,9 +149,6 @@ :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page - :parse-query-params (comp - (query-params/parse-key :code query-params/parse-long) - (helper/default-parse-query-params grid-page)) :action-buttons (fn [_] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/merge)) @@ -165,6 +172,7 @@ "Vendors"]] :title "Vendors" :entity-name "Vendor" + :query-schema query-schema :route ::route/table :headers [{:key "name" :name "Name" @@ -913,6 +921,11 @@ (fn [cursor _] (account-override-row cursor)))}) (fn [h] (-> h +(wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) (wrap-admin) (wrap-client-redirect-unauthenticated))))) diff --git a/src/clj/auto_ap/ssr/company/company_1099.clj b/src/clj/auto_ap/ssr/company/company_1099.clj index 65e49602..b9709315 100644 --- a/src/clj/auto_ap/ssr/company/company_1099.clj +++ b/src/clj/auto_ap/ssr/company/company_1099.clj @@ -2,32 +2,31 @@ (:require [auto-ap.datomic :refer [apply-pagination-raw conn]] [auto-ap.graphql.utils :refer [assert-can-see-client]] + [auto-ap.query-params :refer [wrap-copy-qp-pqp]] [auto-ap.routes.utils :refer [wrap-client-redirect-unauthenticated wrap-secure]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] [auto-ap.ssr.form-cursor :as fc] - [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] [auto-ap.ssr.svg :as svg] [auto-ap.ssr.utils - :refer [apply-middleware-to-all-handlers - entity-id - html-response - main-transformer - modal-response - ref->enum-schema - ref->select-options - strip - wrap-entity - wrap-form-4xx-2 - wrap-schema-enforce]] + :refer [apply-middleware-to-all-handlers default-grid-fields-schema + entity-id html-response main-transformer modal-response + ref->enum-schema ref->select-options strip wrap-entity + wrap-form-4xx-2 wrap-merge-prior-hx wrap-schema-enforce]] [bidi.bidi :as bidi] [clojure.string :as str] [datomic.api :as dc] [hiccup.util :refer [url]] [malli.core :as mc])) +(def query-schema (mc/schema + [:maybe + (into [:map {} ] + default-grid-fields-schema)])) + (def vendor-read '[:db/id :vendor/name {:vendor/legal-entity-1099-type [:db/ident]} @@ -59,7 +58,7 @@ client-id vendor-id))) -(defn fetch-page [{:keys [trimmed-clients parsed-query-params] :as request user :identity}] +(defn fetch-page [{:keys [trimmed-clients query-params] :as request user :identity}] (let [results (dc/q '[:find (pull ?c [:client/code :db/id]) (pull ?v vendor-read) @@ -83,8 +82,8 @@ (sort-by (fn [[client _ amount]] [(:client/code client ) amount])) (into [])) - paginated (apply-pagination-raw {:start (:start parsed-query-params) - :per-page (:per-page parsed-query-params)} all)] + paginated (apply-pagination-raw {:start (:start query-params) + :per-page (:per-page query-params)} all)] [(:entries paginated) (:count paginated)])) (def grid-page @@ -102,6 +101,7 @@ "1099 Vendor Info"]] :title "1099 Vendors" :entity-name "Vendors" + :query-schema query-schema :route :company-1099-vendor-table :row-buttons (fn [request e] [(com/icon-button {:hx-get (url (bidi/path-for ssr-routes/only-routes @@ -358,27 +358,31 @@ (def page (helper/page-route grid-page)) (def key->handler - (apply-middleware-to-all-handlers - (->> - { - :company-1099 page - :company-1099-vendor-table vendor-table - :company-1099-vendor-dialog (-> vendor-dialog - (wrap-entity [:route-params :vendor-id] default-vendor-read) - (wrap-schema-enforce :route-schema [:map [:vendor-id entity-id]] - :query-schema [:map [:client-id entity-id]])) - :company-1099-vendor-save (-> vendor-save - (wrap-entity [:form-params :db/id] default-vendor-read) - (wrap-schema-enforce :form-schema form-schema - :route-schema [:map [:vendor-id entity-id]] - :query-schema [:map [:client-id entity-id]]) - (wrap-nested-form-params) - (wrap-form-4xx-2 (-> vendor-dialog - (wrap-entity [:form-params :db/id] default-vendor-read) - (wrap-entity [:route-params :vendor-id] default-vendor-read) - (wrap-schema-enforce :route-schema [:map [:vendor-id entity-id]] - :query-schema [:map [:client-id entity-id]]))))}) - (fn [h] - (-> h - (wrap-secure) - (wrap-client-redirect-unauthenticated))))) + (apply-middleware-to-all-handlers + (->> + {:company-1099 page + :company-1099-vendor-table vendor-table + :company-1099-vendor-dialog (-> vendor-dialog + (wrap-entity [:route-params :vendor-id] default-vendor-read) + (wrap-schema-enforce :route-schema [:map [:vendor-id entity-id]] + :query-schema [:map [:client-id entity-id]])) + :company-1099-vendor-save (-> vendor-save + (wrap-entity [:form-params :db/id] default-vendor-read) + (wrap-schema-enforce :form-schema form-schema + :route-schema [:map [:vendor-id entity-id]] + :query-schema [:map [:client-id entity-id]]) + (wrap-nested-form-params) + (wrap-form-4xx-2 (-> vendor-dialog + (wrap-entity [:form-params :db/id] default-vendor-read) + (wrap-entity [:route-params :vendor-id] default-vendor-read) + (wrap-schema-enforce :route-schema [:map [:vendor-id entity-id]] + :query-schema [:map [:client-id entity-id]]))))}) + (fn [h] + (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) + (wrap-secure) + (wrap-client-redirect-unauthenticated))))) diff --git a/src/clj/auto_ap/ssr/company/plaid.clj b/src/clj/auto_ap/ssr/company/plaid.clj index a8b6a954..dbadba64 100644 --- a/src/clj/auto_ap/ssr/company/plaid.clj +++ b/src/clj/auto_ap/ssr/company/plaid.clj @@ -1,23 +1,33 @@ (ns auto-ap.ssr.company.plaid - (:require [auto-ap.datomic + (:require + [auto-ap.datomic :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query pull-attr pull-many-by-id query2]] - [auto-ap.graphql.utils :refer [assert-can-see-client]] - [auto-ap.logging :as alog] - [auto-ap.plaid.core :as p] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.ssr.components :as com] - [auto-ap.ssr.grid-page-helper :as helper] - [auto-ap.ssr.hx :as hx] - [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.utils :refer [html-response]] - [auto-ap.time :as atime] - [bidi.bidi :as bidi] - [clj-time.coerce :as coerce] - [clj-time.core :as time] - [clojure.string :as str] - [datomic.api :as dc] - [hiccup2.core :as hiccup])) + [auto-ap.graphql.utils :refer [assert-can-see-client]] + [auto-ap.logging :as alog] + [auto-ap.plaid.core :as p] + [auto-ap.query-params :refer [wrap-copy-qp-pqp]] + [auto-ap.routes.utils :refer [wrap-client-redirect-unauthenticated + wrap-secure]] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers + default-grid-fields-schema html-response + wrap-merge-prior-hx wrap-schema-enforce]] + [auto-ap.time :as atime] + [bidi.bidi :as bidi] + [clj-time.coerce :as coerce] + [clj-time.core :as time] + [clojure.string :as str] + [datomic.api :as dc] + [hiccup2.core :as hiccup] + [malli.core :as mc])) +(def query-schema (mc/schema + [:maybe + (into [:map {} ] + default-grid-fields-schema)])) (def default-read '[:db/id :plaid-item/external-id @@ -37,21 +47,21 @@ :plaid-account/name]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in ['$ '[?xx ...]] :where ['[?e :plaid-item/client ?xx]]} :args [db (:trimmed-clients request)]} (:sort query-params) (add-sorter-fields {"external-id" ['[?e :plaid-item/external-id ?sort-external-id]] - "status" ['[?e :plaid-item/status ?sort-status]]} - query-params) + "plaid-bank-status" ['[?e :plaid-item/status ?sort-plaid-bank-status]] + "status" ['[?e :plaid-item/status ?sort-status]]} + query-params) true (merge-query {:query {:find ['?e] :where ['[?e :plaid-item/external-id]]}}))] - (clojure.pprint/pprint query-params) (cond->> (query2 query) true (apply-sort-3 query-params) true (apply-pagination query-params)))) @@ -145,6 +155,7 @@ "Plaid"]] :title "Plaid Accounts" :entity-name "Plaid accounts" + :query-schema query-schema :route :company-plaid-table :action-buttons (fn [request] (when-let [client-code (:client/code (:client request))] @@ -172,7 +183,6 @@ :render :plaid-item/external-id} {:key "integreat-plaid-status" :name "Integreat ↔ Plaid status" - :sort-key "integreat-plaid-status" :render (fn [e] (let [bad-integration (->> (:plaid-item/accounts e) @@ -229,3 +239,21 @@ (def page (helper/page-route grid-page)) (def table (helper/table-route grid-page)) +(def key->handler + (apply-middleware-to-all-handlers + { + :company-plaid page + :company-plaid-table table + :company-plaid-link link + :company-plaid-relink relink + + } + (fn [h] + (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) + (wrap-client-redirect-unauthenticated) + (wrap-secure))))) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/company/reports.clj b/src/clj/auto_ap/ssr/company/reports.clj index ed223fe0..416a1d15 100644 --- a/src/clj/auto_ap/ssr/company/reports.clj +++ b/src/clj/auto_ap/ssr/company/reports.clj @@ -1,30 +1,45 @@ (ns auto-ap.ssr.company.reports - (:require [amazonica.aws.s3 :as s3] - [auto-ap.datomic + (:require + [amazonica.aws.s3 :as s3] + [auto-ap.datomic :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query pull-many query2]] - [auto-ap.graphql.utils :refer [assert-can-see-client is-admin?]] - [auto-ap.routes.utils :refer [wrap-client-redirect-unauthenticated - wrap-secure]] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.ssr.company.reports.expense :as company-expense-report] - [auto-ap.ssr.company.reports.reconciliation :as company-reconciliation-report] - [auto-ap.ssr.components :as com] - [auto-ap.ssr.grid-page-helper :as helper] - [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers - html-response]] - [auto-ap.time :as atime] - [bidi.bidi :as bidi] - [clojure.set :as set] - [config.core :refer [env]] - [datomic.api :as dc])) + [auto-ap.graphql.utils :refer [assert-can-see-client is-admin?]] + [auto-ap.query-params :refer [wrap-copy-qp-pqp]] + [auto-ap.routes.utils :refer [wrap-client-redirect-unauthenticated + wrap-secure]] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.company.reports.expense :as company-expense-report] + [auto-ap.ssr.company.reports.reconciliation :as company-reconciliation-report] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers clj-date-schema + default-grid-fields-schema html-response + wrap-merge-prior-hx wrap-schema-enforce]] + [auto-ap.time :as atime] + [bidi.bidi :as bidi] + [clojure.set :as set] + [config.core :refer [env]] + [datomic.api :as dc] + [malli.core :as mc])) +(def query-schema (mc/schema + [:maybe + (into [:map {:date-range [:date-range :start-date :end-date]} + + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]] + [:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]] + ] + default-grid-fields-schema)])) (def default-read '[:db/id :report/client [:report/created :xform clj-time.coerce/from-date] :report/url :report/name :report/creator]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in '[$ [?c ...]] :where '[[?e :report/client ?c]]} @@ -80,6 +95,7 @@ "Reports"]] :title "Reports" :entity-name "Reports" + :query-schema query-schema :route :company-reports-table :row-buttons (fn [request e] [(com/a-icon-button {:href (:report/url e)} @@ -143,5 +159,10 @@ (into company-reconciliation-report/key->handler)) (fn [h] (-> h +(wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) (wrap-secure) (wrap-client-redirect-unauthenticated))))) diff --git a/src/clj/auto_ap/ssr/company/yodlee.clj b/src/clj/auto_ap/ssr/company/yodlee.clj index 4d9267ef..f2e65d0d 100644 --- a/src/clj/auto_ap/ssr/company/yodlee.clj +++ b/src/clj/auto_ap/ssr/company/yodlee.clj @@ -1,19 +1,28 @@ (ns auto-ap.ssr.company.yodlee - (:require [auto-ap.datomic + (:require + [auto-ap.datomic :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query pull-attr pull-many query2]] - [auto-ap.graphql.utils :refer [assert-can-see-client is-admin?]] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.ssr.components :as com] - [auto-ap.ssr.grid-page-helper :as helper] - [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.utils :refer [html-response modal-response]] - [auto-ap.time :as atime] - [auto-ap.yodlee.core2 :as yodlee] - [bidi.bidi :as bidi] - [config.core :refer [env]] - [datomic.api :as dc] - [hiccup2.core :as hiccup])) + [auto-ap.graphql.utils :refer [assert-can-see-client is-admin?]] + [auto-ap.permissions :refer [wrap-must]] + [auto-ap.query-params :refer [wrap-copy-qp-pqp]] + [auto-ap.routes.utils :refer [wrap-client-redirect-unauthenticated + wrap-secure]] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers + default-grid-fields-schema entity-id + html-response modal-response wrap-merge-prior-hx + wrap-schema-enforce]] + [auto-ap.time :as atime] + [auto-ap.yodlee.core2 :as yodlee] + [bidi.bidi :as bidi] + [config.core :refer [env]] + [datomic.api :as dc] + [hiccup2.core :as hiccup] + [malli.core :as mc])) (def default-read '[:db/id [:yodlee-provider-account/last-updated :xform clj-time.coerce/from-date] @@ -23,11 +32,15 @@ {:yodlee-provider-account/accounts [:yodlee-account/name :yodlee-account/number] :yodlee-provider-account/client [:client/code]}]) - +(def query-schema (mc/schema + [:maybe + (into [:map {} + [:client-id {:optional true} [:maybe entity-id]] ] + default-grid-fields-schema)])) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request)] - (->> (cond-> {:query {:find [] + (let [query-params (:query-params request) + query (cond-> {:query {:find [] :in ['$ '[?xx ...]] :where ['[?e :yodlee-provider-account/id] '[?e :yodlee-provider-account/client ?xx]]} @@ -35,11 +48,15 @@ (:sort query-params) (add-sorter-fields {"status" ['[?e :yodlee-provider-account/status ?sort-status]] - "last-updated" ['[?e :yodlee-provider-account/last-updated ?sort-last-updated]]} + "client" ['[?e :yodlee-provider-account/client ?c] + '[?c :client/code ?sort-client]] + "provider-account" ['[?e :yodlee-provider-account/id ?sort-provider-account]] + "last-updated" ['[?e :yodlee-provider-account/last-updated ?sort-last-updated]]} query-params) true (merge-query {:query {:find ['?e ] - :where ['[?e :yodlee-provider-account/id]]}})) + :where ['[?e :yodlee-provider-account/id]]}}))] + (->> query (query2) (apply-sort-3 query-params) @@ -133,6 +150,7 @@ fastlink.open({fastLinkURL: '%s', "Yodlee"]] :title "Yodlee Accounts" :entity-name "Yodlee accounts" + :query-schema query-schema :route :company-yodlee-table :action-buttons (fn [request] [[:div.flex.flex-col.flex-shrink @@ -211,3 +229,21 @@ fastlink.open({fastLinkURL: '%s', identity provider-account {:flash? true})))) + + +(def key->handler + (apply-middleware-to-all-handlers + { + :company-yodlee page + :company-yodlee-table table + :company-yodlee-fastlink-dialog fastlink-dialog + } + (fn [h] + (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) + (wrap-client-redirect-unauthenticated) + (wrap-secure))))) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/components/aside.clj b/src/clj/auto_ap/ssr/components/aside.clj index 144c6c86..ef470d82 100644 --- a/src/clj/auto_ap/ssr/components/aside.clj +++ b/src/clj/auto_ap/ssr/components/aside.clj @@ -210,7 +210,7 @@ (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes :pos-cash-drawer-shifts) "?date-range=week") - :active? (= :cash-drawer-shifts (:matched-route request)) + :active? (= :pos-cash-drawer-shifts (:matched-route request)) :hx-boost "true"} "Cash drawer shifts")))) diff --git a/src/clj/auto_ap/ssr/core.clj b/src/clj/auto_ap/ssr/core.clj index e817932e..12cf76c1 100644 --- a/src/clj/auto_ap/ssr/core.clj +++ b/src/clj/auto_ap/ssr/core.clj @@ -61,15 +61,8 @@ :not-found not-found/page :company (wrap-client-redirect-unauthenticated (wrap-secure company/page)) - :company-plaid (wrap-client-redirect-unauthenticated (wrap-secure company-plaid/page)) - :company-plaid-table (wrap-client-redirect-unauthenticated (wrap-secure company-plaid/table)) - :company-plaid-link (wrap-client-redirect-unauthenticated (wrap-secure company-plaid/link)) - :company-plaid-relink (wrap-client-redirect-unauthenticated (wrap-secure company-plaid/relink)) :company-update-signature (wrap-client-redirect-unauthenticated (wrap-secure company/upload-signature-data)) :company-upload-signature (wrap-client-redirect-unauthenticated (wrap-secure company/upload-signature-file)) - :company-yodlee (wrap-client-redirect-unauthenticated (wrap-secure company-yodlee/page)) - :company-yodlee-table (wrap-client-redirect-unauthenticated (wrap-secure company-yodlee/table)) - :company-yodlee-fastlink-dialog (wrap-client-redirect-unauthenticated (wrap-secure company-yodlee/fastlink-dialog)) :company-yodlee-provider-account-refresh (wrap-client-redirect-unauthenticated (wrap-admin company-yodlee/refresh-provider-account)) :company-yodlee-provider-account-reauthenticate (wrap-client-redirect-unauthenticated (wrap-secure company-yodlee/reauthenticate)) :invoice-glimpse (wrap-client-redirect-unauthenticated (wrap-must (wrap-secure invoice-glimpse/page) {:activity :import :subject :invoice})) @@ -86,7 +79,9 @@ :transaction-insight-explain (wrap-client-redirect-unauthenticated (wrap-admin insights/explain)) :admin-ezcater-xls (wrap-client-redirect-unauthenticated (wrap-admin ezcater-xls/page)) :search (wrap-client-redirect-unauthenticated (wrap-secure search/dialog-contents))} + (into company-plaid/key->handler) (into company-reports/key->handler) + (into company-yodlee/key->handler) (into company-1099/key->handler) (into invoice/key->handler) (into import-batch/key->handler) diff --git a/src/clj/auto_ap/ssr/grid_page_helper.clj b/src/clj/auto_ap/ssr/grid_page_helper.clj index ccec7635..831e4ab7 100644 --- a/src/clj/auto_ap/ssr/grid_page_helper.clj +++ b/src/clj/auto_ap/ssr/grid_page_helper.clj @@ -206,49 +206,6 @@ -(defn default-unparse-query-params [query-params] - (reduce - (fn [query-params [k value]] - (assoc query-params k - (cond (= k :sort) - (sort->query value) - - (instance? org.joda.time.base.AbstractInstant value) - (atime/unparse-local value atime/normal-date) - - (instance? Long value) - (str value) - - (instance? Double value) - (format "%.2f" value) - - (instance? Float value) - (format "%.2f" value) - - (keyword? value) - (name value) - - (and (map? value) - (:db/id value)) - (:db/id value) - - :else - value))) - query-params - query-params)) - -(defn default-parse-query-params [grid-spec] - (comp - (query-params/apply-remove-sort) - (query-params/apply-toggle-sort grid-spec) - (query-params/apply-date-range :date-range :start-date :end-date) - (query-params/parse-key :exact-match-id query-params/parse-long) - (query-params/parse-key :sort #(query-params/parse-sort grid-spec %)) - (query-params/parse-key :per-page query-params/parse-long) - (query-params/parse-key :start query-params/parse-long) - (query-params/parse-key :start-date query-params/parse-date) - (query-params/parse-key :end-date query-params/parse-date))) - (defn wrap-trim-client-ids [handler] (fn trim-client-ids [request] (let [valid-clients (extract-client-ids (:clients request) @@ -262,36 +219,30 @@ (handler (assoc request :trimmed-clients valid-clients))))) -(defn table-route [grid-spec & {:keys [parse-query-params? push-url?] :or {parse-query-params? true push-url? true}}] +(defn table-route [grid-spec & {:keys [push-url?] :or { push-url? true}}] (cond-> (fn table [{:keys [identity] :as request}] - (println "SORT IS") - (clojure.pprint/pprint (sort->query (:sort (:query-params request)))) - (let [unparse-query-params (or (:unparse-query grid-spec) - default-unparse-query-params)] - (html-response (table* - grid-spec - identity - request) - :headers (when push-url? - {"hx-push-url" (str "?" (url/map->query - (dissoc (if (:query-schema grid-spec) - (update (filter-vals #(not (nil? %)) - (m/encode (:query-schema grid-spec) - (:query-params request) - main-transformer)) - "sort" sort->query) - (unparse-query-params (:parsed-query-params request))) - "selected" "all-selected")))}) ;; TODO seems hacky to special case selected and all-selected here - :oob (when-let [oob-render (:oob-render grid-spec)] - (oob-render request))))) - true (wrap-trim-client-ids) - parse-query-params? (query-params/wrap-parse-query-params (or (:parse-query-params grid-spec) - (default-parse-query-params grid-spec))) - true (wrap-secure) - true (wrap-client-redirect-unauthenticated))) + (html-response (table* + grid-spec + identity + request) + :headers (when push-url? + {"hx-push-url" (str "?" (url/map->query + (dissoc (if (:query-schema grid-spec) + (update (filter-vals #(not (nil? %)) + (m/encode (:query-schema grid-spec) + (:query-params request) + main-transformer)) + "sort" sort->query) + {}) + "selected" "all-selected")))}) ;; TODO seems hacky to special case selected and all-selected here + :oob (when-let [oob-render (:oob-render grid-spec)] + (oob-render request)))) + true (wrap-trim-client-ids) + true (wrap-secure) + true (wrap-client-redirect-unauthenticated))) -(defn csv-route [{:keys [fetch-page headers page->csv-entities]} & {:keys [parse-query-params?] :or {parse-query-params? true}}] +(defn csv-route [{:keys [fetch-page headers page->csv-entities]} & {:keys []}] (cond-> (fn csv-route [{:keys [identity] :as request}] (let [page-results (fetch-page (assoc-in request [:query-params :per-page] Long/MAX_VALUE)) @@ -314,7 +265,7 @@ true (wrap-secure) true (wrap-client-redirect-unauthenticated))) -(defn page-route [grid-spec & {:keys [parse-query-params?] :or {parse-query-params? true}}] +(defn page-route [grid-spec & {:keys []}] (cond-> (fn page [{:keys [identity] :as request}] (alog/info ::page-route :pqp (:parsed-query-params request) @@ -346,8 +297,6 @@ (:title grid-spec) ((:title grid-spec) request)))) true (wrap-trim-client-ids) - parse-query-params? (query-params/wrap-parse-query-params (or (:parse-query-params grid-spec) - (default-parse-query-params grid-spec))) true (wrap-secure) true (wrap-client-redirect-unauthenticated))) @@ -376,14 +325,10 @@ [:=> [:cat map?] nat-int?]] + [:query-schema :any] [:fetch-page [:=> [:cat request-spec] [:cat [:vector entity-spec] :int]]] - [:parse-query-params - {:optional true} - [:=> - [:cat [:map-of :keyword :any]] - [:map-of :keyword :any]]] [:above-grid {:optional true :default (fn [request])} diff --git a/src/clj/auto_ap/ssr/invoice/import.clj b/src/clj/auto_ap/ssr/invoice/import.clj index b55ca284..c422374e 100644 --- a/src/clj/auto_ap/ssr/invoice/import.clj +++ b/src/clj/auto_ap/ssr/invoice/import.clj @@ -438,8 +438,6 @@ [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true) (assoc-in (exact-match-id* request) [1 :hx-swap-oob] true)]) :query-schema query-schema - :parse-query-params (fn [p] - (mc/decode query-schema p main-transformer)) :action-buttons (fn [request] (let [[_ _ outstanding total] (:page-results request)] [ @@ -816,10 +814,10 @@ (apply-middleware-to-all-handlers {::route/import-page (-> - (helper/page-route grid-page :parse-query-params? false) + (helper/page-route grid-page) (wrap-implied-route-param :status nil)) ::route/import-table - (-> (helper/table-route grid-page :parse-query-params? false) + (-> (helper/table-route grid-page) (wrap-implied-route-param :status nil)) ::route/disapprove (-> disapprove diff --git a/src/clj/auto_ap/ssr/invoices.clj b/src/clj/auto_ap/ssr/invoices.clj index b4d88ebf..55e1661d 100644 --- a/src/clj/auto_ap/ssr/invoices.clj +++ b/src/clj/auto_ap/ssr/invoices.clj @@ -1275,13 +1275,13 @@ (def key->handler (apply-middleware-to-all-handlers (-> - {::route/all-page (-> (helper/page-route grid-page :parse-query-params? false) + {::route/all-page (-> (helper/page-route grid-page) (wrap-implied-route-param :status nil)) - ::route/paid-page (-> (helper/page-route grid-page :parse-query-params? false) + ::route/paid-page (-> (helper/page-route grid-page) (wrap-implied-route-param :status :invoice-status/paid)) - ::route/unpaid-page (-> (helper/page-route grid-page :parse-query-params? false) + ::route/unpaid-page (-> (helper/page-route grid-page) (wrap-implied-route-param :status :invoice-status/unpaid)) - ::route/voided-page (-> (helper/page-route grid-page :parse-query-params? false) + ::route/voided-page (-> (helper/page-route grid-page) (wrap-implied-route-param :status :invoice-status/voided)) ::route/legacy-invoices (redirect-handler ::route/all-page) ::route/legacy-import-invoices (redirect-handler ::route/import-page) diff --git a/src/clj/auto_ap/ssr/ledger.clj b/src/clj/auto_ap/ssr/ledger.clj index 2dc5b8d9..b58ddf7e 100644 --- a/src/clj/auto_ap/ssr/ledger.clj +++ b/src/clj/auto_ap/ssr/ledger.clj @@ -131,7 +131,7 @@ [:div {:x-data (hx/json { "showTable" false})} [:form {:hx-post (bidi.bidi/path-for ssr-routes/only-routes ::route/external-import-import) - :autocomplete "off" } + :autocomplete "off"} (when (:just-parsed? request) [:div (hx/htmx-transition-appear {:class "bg-green-50 text-green-700 rounded p-4 m-2 max-w-screen-2xl"}) (format "Your data has been parsed. %,d rows found." (count (fc/field-value)))]) @@ -237,20 +237,20 @@ (com/button {:color :primary} "Import")])]]])))]) (defn external-import-text-form* [request] -(fc/start-form - (or (:form-params request) {}) (:form-errors request) - [:form#parse-form {:x-data (hx/json {"clipboard" nil}) - :hx-post (bidi.bidi/path-for ssr-routes/only-routes ::route/external-import-parse) - :hx-swap "outerHTML" - :hx-trigger "pasted"} - (fc/with-field :table - [:div - (com/errors {:errors (fc/field-errors)} ) - (com/text-area {:x-model "clipboard" :name (fc/field-name) :value (fc/field-value) :class "hidden"})]) - (com/button {"@click.prevent" "clipboard = (await getclpboard()); $nextTick(() => $dispatch('pasted'))" - "x-on:paste.document" "clipboard = (await getclpboard()); console.log(clipboard); $nextTick(() => $dispatch('pasted'))" } - "Load from clipboard")]) - ) + (fc/start-form + (or (:form-params request) {}) (:form-errors request) + [:form#parse-form {:x-data (hx/json {"clipboard" nil}) + :hx-post (bidi.bidi/path-for ssr-routes/only-routes ::route/external-import-parse) + :hx-swap "outerHTML" + :hx-trigger "pasted"} + (fc/with-field :table + [:div + (com/errors {:errors (fc/field-errors)}) + (com/text-area {:x-model "clipboard" :name (fc/field-name) :value (fc/field-value) :class "hidden"})]) + (com/button {"@click.prevent" "clipboard = (await getclpboard()); $nextTick(() => $dispatch('pasted'))" + "x-on:paste.document" "clipboard = (await getclpboard()); console.log(clipboard); $nextTick(() => $dispatch('pasted'))"} + "Load from clipboard")])) + (defn external-import-form* [request] [:div#forms {:hx-target "this" :hx-swap "outerHTML"} @@ -291,8 +291,8 @@ var r = await c[0].getType('text/plain') console.log(r) return await r.text() - }") - ] + }")] + (external-import-form* request) [:div #_{:x-data (hx/json {:selected [] :all_selected false :type (:entity-name grid-spec)}) "x-on:copy" "if (selected.length > 0) {$clipboard(JSON.stringify({'type': type, 'selected': selected}))}" @@ -307,14 +307,14 @@ "External Ledger Import" #_(if (string? (:title grid-spec)) (:title grid-spec) - ((:title grid-spec) request))) - ) + ((:title grid-spec) request)))) + (defn trim-header [t] (if (->> t first - (map clojure.string/lower-case ) + (map clojure.string/lower-case) (filter #{"id" "client" "source" "vendor" "date" "account" "location" "debit"}) seq) (drop 1 t) @@ -336,34 +336,34 @@ (def parse-form-schema (mc/schema [:map [:table {:min 1 :error/message "Clipboard should contain rows to import" - :decode/string tsv->import-data } + :decode/string tsv->import-data} [:vector {:coerce? true} [:map { :decode/arbitrary (fn [t] (if (vector? t) (into {} (map vector [:external-id :client-code :source :vendor-name :date :account-code :location :debit :credit] t)) t))} - [:external-id [:string {:title "external id" - :min 1 - :decode/string strip}]] - [:client-code [:string {:title "client code" - :min 1 - :decode/string strip}]] - [:source [:string {:title "source" - :min 1 - :decode/string strip}]] - [:vendor-name [:string {:min 1 :decode/string strip}]] - [:date [:and clj-date-schema - [:any {:title "date"}]]] - [:account-code account-schema] + [:external-id [:string {:title "external id" + :min 1 + :decode/string strip}]] + [:client-code [:string {:title "client code" + :min 1 + :decode/string strip}]] + [:source [:string {:title "source" + :min 1 + :decode/string strip}]] + [:vendor-name [:string {:min 1 :decode/string strip}]] + [:date [:and clj-date-schema + [:any {:title "date"}]]] + [:account-code account-schema] + + [:location [:string { :min 1 + :max 2 + :decode/string strip}]] + [:debit [:maybe money]] + [:credit [:maybe money]]]] - [:location [:string { :min 1 - :max 2 - :decode/string strip}]] - [:debit [:maybe money]] - [:credit [:maybe money]] - ]] #_[:string {:decode/string tsv->import-data - :error/message "Clipboard should contain rows to import"}]] ])) + :error/message "Clipboard should contain rows to import"}]]])) @@ -407,19 +407,19 @@ (not (t/equal? (:date entry) (coerce/to-date-time locked-until))))) (all-row-error (str "Client's data is locked until " locked-until)) - (not (dollars= (reduce (fnil + 0.0 0.0) 0.0 (map :debit (:line-items entry))) - (reduce (fnil + 0.0 0.0) 0.0 (map :credit (:line-items entry))))) - (all-row-error (str "Debits '" - (reduce (fnil + 0.0 0.0) 0 (map :debit (:line-items entry))) - "' and credits '" - (reduce (fnil + 0.0 0.0) 0 (map :credit (:line-items entry))) - "' do not add up.")) - (dollars= (reduce (fnil + 0.0 0.0) 0.0 (map :debit (:line-items entry))) - 0.0) - (all-row-error (str "Cannot have ledger entries that total $0.00") :warn) + (not (dollars= (reduce (fnil + 0.0 0.0) 0.0 (map :debit (:line-items entry))) + (reduce (fnil + 0.0 0.0) 0.0 (map :credit (:line-items entry))))) + (all-row-error (str "Debits '" + (reduce (fnil + 0.0 0.0) 0 (map :debit (:line-items entry))) + "' and credits '" + (reduce (fnil + 0.0 0.0) 0 (map :credit (:line-items entry))) + "' do not add up.")) + (dollars= (reduce (fnil + 0.0 0.0) 0.0 (map :debit (:line-items entry))) + 0.0) + (all-row-error (str "Cannot have ledger entries that total $0.00") :warn) - :else - entry)] + :else + entry)] (update entry :line-items @@ -476,7 +476,7 @@ (defn table->entries [table all-vendors all-accounts client-locked-lookup all-client-bank-accounts all-client-locations] (let [lines-with-indexes (for [[i l] (map vector (range) table)] - (assoc l :index i)) ] + (assoc l :index i))] (into [] (for [ [_ lines] (group-by line->id lines-with-indexes) @@ -629,9 +629,9 @@ good-entries (filter (fn [e] (and (not (:error (entry-error-types e))) (not (:warn (entry-error-types e))))) entries) bad-entries (filter (fn [e] (:error (entry-error-types e))) entries) form-errors (reduce (fn [acc [path m status]] - (update-in acc path conj [ m status])) - {} - errors) + (update-in acc path conj [ m status])) + {} + errors) _ (when (seq bad-entries) (alog/info ::ledger-import-errors :errors errors) (throw+ (ex-info "ledger import errors" @@ -690,13 +690,13 @@ (merge (apply-middleware-to-all-handlers (-> - {::route/all-page (-> (helper/page-route grid-page :parse-query-params? false) + {::route/all-page (-> (helper/page-route grid-page) (wrap-implied-route-param :external? false)) - ::route/external-page (-> (helper/page-route grid-page :parse-query-params? false) + ::route/external-page (-> (helper/page-route grid-page) (wrap-implied-route-param :external? true)) - ::route/table (helper/table-route grid-page :parse-query-params? false) - ::route/csv (helper/csv-route grid-page :parse-query-params? false) + ::route/table (helper/table-route grid-page) + ::route/csv (helper/csv-route grid-page) ::route/external-import-page external-import-page ::route/bank-account-filter bank-account-filter ::route/external-import-parse (-> external-import-parse @@ -719,8 +719,8 @@ (wrap-schema-enforce :hx-schema query-schema) (wrap-must {:activity :import :subject :ledger}) (wrap-client-redirect-unauthenticated)))) - balance-sheet/key->handler - profit-and-loss/key->handler - cash-flows/key->handler - investigate/key->handler - new/key->handler)) \ No newline at end of file + balance-sheet/key->handler + profit-and-loss/key->handler + cash-flows/key->handler + investigate/key->handler + new/key->handler)) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/ledger/common.clj b/src/clj/auto_ap/ssr/ledger/common.clj index d64ffb06..2f6ff9cd 100644 --- a/src/clj/auto_ap/ssr/ledger/common.clj +++ b/src/clj/auto_ap/ssr/ledger/common.clj @@ -439,8 +439,6 @@ args [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true) (assoc-in (exact-match-id* request) [1 :hx-swap-oob] true)]) :query-schema query-schema - :parse-query-params (fn [p] - (mc/decode query-schema p main-transformer)) :action-buttons (fn [request] [(when-not (:external? (:route-params request)) (com/button {:color :primary :hx-get (bidi/path-for ssr-routes/only-routes diff --git a/src/clj/auto_ap/ssr/ledger/investigate.clj b/src/clj/auto_ap/ssr/ledger/investigate.clj index f246051f..cbdefde6 100644 --- a/src/clj/auto_ap/ssr/ledger/investigate.clj +++ b/src/clj/auto_ap/ssr/ledger/investigate.clj @@ -43,8 +43,7 @@ (apply-middleware-to-all-handlers (-> {::route/investigate investigate - ::route/investigate-results (helper/table-route altered-grid-page :parse-query-params? false - :push-url? false)} + ::route/investigate-results (helper/table-route altered-grid-page :push-url? false)} ) (fn [h] (-> h diff --git a/src/clj/auto_ap/ssr/payments.clj b/src/clj/auto_ap/ssr/payments.clj index a95b3754..9c0639b7 100644 --- a/src/clj/auto_ap/ssr/payments.clj +++ b/src/clj/auto_ap/ssr/payments.clj @@ -51,7 +51,6 @@ svg/x)]])] [:div {:id "exact-match-id-tag"}])) -;; TODO use query-params instead of parsed-query-params (defn filters [request] [:form#payment-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes @@ -69,7 +68,7 @@ :value (:vendor (:query-params request)) :value-fn :db/id :content-fn :vendor/name})) - (date-range-field* (assoc request :parsed-query-params (:query-params request))) + (date-range-field* request) (com/field {:label "Check #"} (com/text-input {:name "check-number" :id "check-number" @@ -327,8 +326,6 @@ [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true) (assoc-in (exact-match-id* request) [1 :hx-swap-oob] true)]) :query-schema query-schema - :parse-query-params (fn [p] - (mc/decode query-schema p main-transformer)) :action-buttons (fn [request] (let [[_ _ visible-in-float total-in-float ] (:page-results request)] [(com/pill {:color :primary} " Visible in float " @@ -603,13 +600,13 @@ (def key->handler (apply-middleware-to-all-handlers - {::route/cleared-page (-> (helper/page-route grid-page :parse-query-params? false) + {::route/cleared-page (-> (helper/page-route grid-page) (wrap-implied-route-param :status :payment-status/cleared)) - ::route/pending-page (-> (helper/page-route grid-page :parse-query-params? false) + ::route/pending-page (-> (helper/page-route grid-page) (wrap-implied-route-param :status :payment-status/pending)) - ::route/voided-page (-> (helper/page-route grid-page :parse-query-params? false) + ::route/voided-page (-> (helper/page-route grid-page) (wrap-implied-route-param :status :payment-status/voided)) - ::route/all-page (-> (helper/page-route grid-page :parse-query-params? false) + ::route/all-page (-> (helper/page-route grid-page) (wrap-implied-route-param :status nil)) ::route/delete (-> delete @@ -622,7 +619,7 @@ (wrap-admin)) - ::route/table (helper/table-route grid-page :parse-query-params? false)} + ::route/table (helper/table-route grid-page)} (fn [h] (-> h (wrap-copy-qp-pqp) diff --git a/src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj b/src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj index 8c27993b..4dc52eed 100644 --- a/src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj +++ b/src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj @@ -1,24 +1,32 @@ (ns auto-ap.ssr.pos.cash-drawer-shifts (:require [auto-ap.datomic - :refer [add-sorter-fields - apply-pagination - apply-sort-3 - conn - merge-query - pull-many - query2]] + :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query + pull-many query2]] + [auto-ap.query-params :refer [wrap-copy-qp-pqp]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] - [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] [auto-ap.ssr.pos.common :refer [date-range-field* total-field*]] + [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers clj-date-schema + default-grid-fields-schema wrap-merge-prior-hx + wrap-schema-enforce]] [auto-ap.time :as atime] [bidi.bidi :as bidi] [clj-time.coerce :as c] [datomic.api :as dc] - [malli.core :as m])) + [malli.core :as mc])) ;; always should be fast +(def query-schema (mc/schema + [:maybe + (into [:map {:date-range [:date-range :start-date :end-date]} + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]] + [:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]] ] + default-grid-fields-schema)])) (defn filters [params] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -38,7 +46,7 @@ {:cash-drawer-shift/client [:client/name :db/id :client/code]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in ['$ '[?clients ?start-date ?end-date]] :where '[[(iol-ion.query/scan-cash-drawer-shifts $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]]} @@ -101,6 +109,7 @@ "Cash Drawer Shifts"]] :title "Cash drawer shifts" :entity-name "Cash drawer shift" + :query-schema query-schema :route :pos-cash-drawer-shift-table :headers [{:key "client" :name "Client" @@ -134,5 +143,13 @@ (def table* (partial helper/table* grid-page)) (def key->handler - {:pos-cash-drawer-shifts (helper/page-route grid-page) - :pos-cash-drawer-shift-table (helper/table-route grid-page)}) + (apply-middleware-to-all-handlers + {:pos-cash-drawer-shifts (helper/page-route grid-page) + :pos-cash-drawer-shift-table (helper/table-route grid-page)} + (fn [h] + (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema))))) diff --git a/src/clj/auto_ap/ssr/pos/common.clj b/src/clj/auto_ap/ssr/pos/common.clj index 2419c223..57ef83d5 100644 --- a/src/clj/auto_ap/ssr/pos/common.clj +++ b/src/clj/auto_ap/ssr/pos/common.clj @@ -4,15 +4,15 @@ [auto-ap.time :as atime] [auto-ap.ssr.svg :as svg])) (defn date-range-field* [request] - (dr/date-range-field {:value {:start (:start-date (:parsed-query-params request)) - :end (:end-date (:parsed-query-params request))} + (dr/date-range-field {:value {:start (:start-date (:query-params request)) + :end (:end-date (:query-params request))} :id "date-range"})) (defn processor-field* [request] (com/field {:label "Processor"} (com/radio-card {:size :small :name "processor" - :value (:processor (:parsed-query-params request)) + :value (:processor (:query-params request)) :options [{:value "" :content "All"} {:value "square" @@ -37,7 +37,7 @@ :id "total-gte" :hx-preserve "true" :class "hot-filter w-20" - :value (:total-gte (:parsed-query-params request)) + :value (:total-gte (:query-params request)) :placeholder "0.01" :size :small}) [:div.align-baseline @@ -46,12 +46,12 @@ :hx-preserve "true" :id "total-lte" :class "hot-filter w-20" - :value (:total-lte (:parsed-query-params request)) + :value (:total-lte (:query-params request)) :placeholder "9999.34" :size :small})])) (defn exact-match-id-field* [request] - (when-let [exact-match-id (:exact-match-id (:parsed-query-params request))] + (when-let [exact-match-id (:exact-match-id (:query-params request))] [:div (com/field {:label "Exact match"} (com/pill {:color :primary} diff --git a/src/clj/auto_ap/ssr/pos/expected_deposits.clj b/src/clj/auto_ap/ssr/pos/expected_deposits.clj index e821b827..dc83538c 100644 --- a/src/clj/auto_ap/ssr/pos/expected_deposits.clj +++ b/src/clj/auto_ap/ssr/pos/expected_deposits.clj @@ -1,30 +1,38 @@ (ns auto-ap.ssr.pos.expected-deposits (:require + [auto-ap.client-routes :as client-routes] [auto-ap.datomic - :refer [add-sorter-fields - apply-pagination - apply-sort-3 - conn - merge-query - pull-many - query2]] + :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query + pull-many query2]] [auto-ap.graphql.utils :refer [extract-client-ids]] - [auto-ap.query-params :as query-params] - [auto-ap.routes.utils - :refer [wrap-client-redirect-unauthenticated wrap-secure]] + [auto-ap.query-params :as query-params :refer [wrap-copy-qp-pqp]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] - [auto-ap.ssr.grid-page-helper :as helper] - [auto-ap.ssr.pos.common :refer [date-range-field* total-field* exact-match-id-field*]] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.pos.common :refer [date-range-field* exact-match-id-field*]] [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers clj-date-schema + default-grid-fields-schema ref->enum-schema + wrap-merge-prior-hx wrap-schema-enforce]] [auto-ap.time :as atime] [bidi.bidi :as bidi] [clj-time.coerce :as c] [datomic.api :as dc] - [auto-ap.client-routes :as client-routes] - [malli.core :as m])) + [malli.core :as mc])) + +(def query-schema (mc/schema + [:maybe + (into [:map {:date-range [:date-range :start-date :end-date]} + [:total-gte {:optional true} [:maybe :double]] + [:total-lte {:optional true} [:maybe :double]] + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]] + [:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]] + [:processor {:optional true} [:maybe (ref->enum-schema "ccp-processor")]]] + default-grid-fields-schema)])) -;; make params parsing composable (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -49,7 +57,7 @@ (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) valid-clients (extract-client-ids (:clients request) (:client request) (:client-id query-params) @@ -139,10 +147,6 @@ :nav com/main-aside-nav :page-specific-nav filters :fetch-page fetch-page - :parse-query-params (comp - (query-params/parse-key :total-gte query-params/parse-double) - (query-params/parse-key :total-lte query-params/parse-double) - (helper/default-parse-query-params grid-page)) :oob-render (fn [request] [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)]) @@ -155,6 +159,7 @@ "Expected deposits"]] :title "Expected deposits" :entity-name "Expected deposit" + :query-schema query-schema :route :pos-expected-deposit-table :row-buttons (fn [_ e] [ @@ -192,6 +197,15 @@ (def row* (partial helper/row* grid-page)) (def table* (partial helper/table* grid-page)) + (def key->handler - {:pos-expected-deposits (helper/page-route grid-page) - :pos-expected-deposit-table (helper/table-route grid-page)}) + (apply-middleware-to-all-handlers + {:pos-expected-deposits (helper/page-route grid-page) + :pos-expected-deposit-table (helper/table-route grid-page)} + (fn [h] + (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema))))) diff --git a/src/clj/auto_ap/ssr/pos/refunds.clj b/src/clj/auto_ap/ssr/pos/refunds.clj index 60a4c6e3..c33b6784 100644 --- a/src/clj/auto_ap/ssr/pos/refunds.clj +++ b/src/clj/auto_ap/ssr/pos/refunds.clj @@ -1,23 +1,33 @@ (ns auto-ap.ssr.pos.refunds (:require [auto-ap.datomic - :refer [add-sorter-fields - apply-pagination - apply-sort-3 - conn - merge-query - pull-many - query2]] - [auto-ap.query-params :as query-params] + :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query + pull-many query2]] + [auto-ap.query-params :refer [wrap-copy-qp-pqp]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] - [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] [auto-ap.ssr.pos.common :refer [date-range-field* total-field*]] + [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers clj-date-schema + default-grid-fields-schema wrap-merge-prior-hx + wrap-schema-enforce]] [auto-ap.time :as atime] [bidi.bidi :as bidi] [clj-time.coerce :as c] - [datomic.api :as dc])) + [datomic.api :as dc] + [malli.core :as mc])) +(def query-schema (mc/schema + [:maybe + (into [:map {:date-range [:date-range :start-date :end-date]} + [:total-gte {:optional true} [:maybe :double]] + [:total-lte {:optional true} [:maybe :double]] + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]] + [:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]]] + default-grid-fields-schema)])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes @@ -38,7 +48,7 @@ {:sales-refund/client [:client/name :db/id :client/code]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in ['$ '[?clients ?start-date ?end-date]] :where '[[(iol-ion.query/scan-sales-refunds $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]]} @@ -98,10 +108,6 @@ :nav com/main-aside-nav :page-specific-nav filters :fetch-page fetch-page - :parse-query-params (comp - (query-params/parse-key :total-gte query-params/parse-double) - (query-params/parse-key :total-lte query-params/parse-double) - (helper/default-parse-query-params grid-page)) :oob-render (fn [request] [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)]) @@ -114,6 +120,7 @@ "Refunds"]] :title "Refunds" :entity-name "Refund" + :query-schema query-schema :route :pos-refund-table :headers [{:key "client" :name "Client" @@ -142,5 +149,13 @@ (def table* (partial helper/table* grid-page)) (def key->handler - {:pos-refunds (helper/page-route grid-page) - :pos-refund-table (helper/table-route grid-page)}) + (apply-middleware-to-all-handlers + {:pos-refunds (helper/page-route grid-page) + :pos-refund-table (helper/table-route grid-page)} + (fn [h] + (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema))))) diff --git a/src/clj/auto_ap/ssr/pos/sales_orders.clj b/src/clj/auto_ap/ssr/pos/sales_orders.clj index 85573751..8fb5ec31 100644 --- a/src/clj/auto_ap/ssr/pos/sales_orders.clj +++ b/src/clj/auto_ap/ssr/pos/sales_orders.clj @@ -1,25 +1,37 @@ (ns auto-ap.ssr.pos.sales-orders (:require [auto-ap.datomic - :refer [add-sorter-fields - apply-pagination - apply-sort-3 - conn - merge-query - pull-many - query2]] + :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query + pull-many query2]] [auto-ap.datomic.sales-orders :as d-sales] - [auto-ap.query-params :as query-params] + [auto-ap.query-params :as query-params :refer [wrap-copy-qp-pqp]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] - [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] [auto-ap.ssr.pos.common :refer [date-range-field* processor-field* total-field*]] [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers clj-date-schema + default-grid-fields-schema ref->enum-schema + wrap-merge-prior-hx wrap-schema-enforce]] [auto-ap.time :as atime] [bidi.bidi :as bidi] [clj-time.coerce :as c] - [datomic.api :as dc])) + [datomic.api :as dc] + [malli.core :as mc])) + +(def query-schema (mc/schema + [:maybe + (into [:map {:date-range [:date-range :start-date :end-date]} + [:total-gte {:optional true :default nil} [:maybe :double]] + [:total-lte {:optional true :default nil} [:maybe :double]] + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]] + [:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]] + [:processor {:optional true} [:maybe (ref->enum-schema "ccp-processor")]]] + default-grid-fields-schema)])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -56,7 +68,7 @@ :class "hot-filter" :id "category" :hx-preserve "true" - :value (:category (:parsed-query-params request)) + :value (:category (:query-params request)) :placeholder "Fries" :size :small}))]]]) @@ -89,7 +101,7 @@ {:charge/processor [:db/ident]} {:expected-deposit/_charges [:db/id]}]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in ['$ '[?clients ?start-date ?end-date]] :where '[[(iol-ion.query/scan-sales-orders $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]]} @@ -146,6 +158,7 @@ true (merge-query {:query {:find ['?sort-default '?e]}}))] + (clojure.pprint/pprint (update-in query [:args] #(drop 1 %))) (cond->> (query2 query) true (apply-sort-3 query-params) true (apply-pagination query-params)))) @@ -167,92 +180,93 @@ (def grid-page - (helper/build - {:id "sales-table" - :nav com/main-aside-nav - :page-specific-nav filters - :fetch-page fetch-page - :parse-query-params (comp - (query-params/parse-key :processor #(query-params/parse-keyword "ccp-processor" %)) - (query-params/parse-key :total-gte query-params/parse-double) - (query-params/parse-key :total-lte query-params/parse-double) - (helper/default-parse-query-params grid-page)) - :oob-render - (fn [request] - [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)]) - :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes - :company)} - "POS"] + (helper/build + {:id "sales-table" + :nav com/main-aside-nav + :page-specific-nav filters + :fetch-page fetch-page - [:a {:href (bidi/path-for ssr-routes/only-routes - :pos-sales)} - "Sales"]] - :title "Sales orders" - :entity-name "Sales orders" - :route :pos-sales-table - :action-buttons (fn [request] - (let [{:keys [total tax]} (d-sales/summarize-orders (:ids (fetch-ids (dc/db conn) request)))] - (when (and total tax) - [ - (com/pill {:color :primary} - (format "Total $%.2f" total) - ) - (com/pill {:color :secondary} - (format "Tax $%.2f" tax ) - )]))) - :row-buttons (fn [_ e] - (when (:sales-order/reference-link e) - [(com/a-icon-button {:href (:sales-order/reference-link e)} - svg/external-link)])) - :headers [{:key "client" - :name "Client" - :sort-key "client" - :hide? (fn [args] - (= (count (:clients args)) 1)) - :render #(-> % :sales-order/client :client/code)} - {:key "date" - :name "Date" - :sort-key "date" - :render #(atime/unparse-local (:sales-order/date %) atime/standard-time)} - {:key "source" - :name "Source" - :sort-key "source" - :render (fn [sales-order] - (when (:sales-order/source sales-order) - (com/pill {:color :primary } - (:sales-order/source sales-order))))} - {:key "total" - :name "Total" - :sort-key "total" - :render #(some->> % :sales-order/total (format "$%.2f"))} - {:key "tax" - :name "Tax" - :sort-key "tax" - :render #(some->> % :sales-order/tax (format "$%.2f"))} - {:key "tip" - :name "Tip" - :sort-key "tip" - :render #(some->> % :sales-order/tip (format "$%.2f"))} - {:key "Payment methods" - :name "Payment Methods" - :render (fn [sales-order] - [:div.flex.space-x-2 - (for [payment-method (->> sales-order :sales-order/charges (map :charge/type-name) set)] - (com/pill {:color :primary } - (condp = payment-method - "CASH" "cash" - "" nil - "ALL" nil - "CARD" "card" - "SQUARE_GIFT_CARD" "gift card" - "OTHER" "other" - nil)))])}]} - )) + :query-schema query-schema + :oob-render + (fn [request] + [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)]) + :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes + :company)} + "POS"] + + [:a {:href (bidi/path-for ssr-routes/only-routes + :pos-sales)} + "Sales"]] + :title "Sales orders" + :entity-name "Sales orders" + :route :pos-sales-table + :action-buttons (fn [request] + (let [{:keys [total tax]} (d-sales/summarize-orders (:ids (fetch-ids (dc/db conn) request)))] + (when (and total tax) + [(com/pill {:color :primary} + (format "Total $%.2f" total)) + (com/pill {:color :secondary} + (format "Tax $%.2f" tax))]))) + :row-buttons (fn [_ e] + (when (:sales-order/reference-link e) + [(com/a-icon-button {:href (:sales-order/reference-link e)} + svg/external-link)])) + :headers [{:key "client" + :name "Client" + :sort-key "client" + :hide? (fn [args] + (= (count (:clients args)) 1)) + :render #(-> % :sales-order/client :client/code)} + {:key "date" + :name "Date" + :sort-key "date" + :render #(atime/unparse-local (:sales-order/date %) atime/standard-time)} + {:key "source" + :name "Source" + :sort-key "source" + :render (fn [sales-order] + (when (:sales-order/source sales-order) + (com/pill {:color :primary} + (:sales-order/source sales-order))))} + {:key "total" + :name "Total" + :sort-key "total" + :render #(some->> % :sales-order/total (format "$%.2f"))} + {:key "tax" + :name "Tax" + :sort-key "tax" + :render #(some->> % :sales-order/tax (format "$%.2f"))} + {:key "tip" + :name "Tip" + :sort-key "tip" + :render #(some->> % :sales-order/tip (format "$%.2f"))} + {:key "Payment methods" + :name "Payment Methods" + :render (fn [sales-order] + [:div.flex.space-x-2 + (for [payment-method (->> sales-order :sales-order/charges (map :charge/type-name) set)] + (com/pill {:color :primary} + (condp = payment-method + "CASH" "cash" + "" nil + "ALL" nil + "CARD" "card" + "SQUARE_GIFT_CARD" "gift card" + "OTHER" "other" + nil)))])}]})) (def row* (partial helper/row* grid-page)) (def table* (partial helper/table* grid-page)) (def key->handler - {:pos-sales (helper/page-route grid-page) - :pos-sales-table (helper/table-route grid-page)}) + (apply-middleware-to-all-handlers + {:pos-sales (helper/page-route grid-page) + :pos-sales-table (helper/table-route grid-page)} + (fn [h] + (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema))))) diff --git a/src/clj/auto_ap/ssr/pos/tenders.clj b/src/clj/auto_ap/ssr/pos/tenders.clj index bfad7d53..4b42ec4f 100644 --- a/src/clj/auto_ap/ssr/pos/tenders.clj +++ b/src/clj/auto_ap/ssr/pos/tenders.clj @@ -1,26 +1,23 @@ (ns auto-ap.ssr.pos.tenders (:require [auto-ap.datomic - :refer [add-sorter-fields - apply-pagination - apply-sort-3 - conn - merge-query - pull-many - query2]] - [auto-ap.query-params :as query-params] + :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query + pull-many query2]] + [auto-ap.query-params :as query-params :refer [wrap-copy-qp-pqp]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] - [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] [auto-ap.ssr.pos.common :refer [date-range-field* processor-field* total-field*]] [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers clj-date-schema + default-grid-fields-schema ref->enum-schema + wrap-merge-prior-hx wrap-schema-enforce]] [auto-ap.time :as atime] [bidi.bidi :as bidi] [clj-time.coerce :as c] [datomic.api :as dc] - [malli.core :as m] - [malli.transform :as mt2])) + [malli.core :as mc])) ;; always should be fast @@ -37,6 +34,19 @@ (processor-field* request) (total-field* request)]]) +(def query-schema (mc/schema + [:maybe + (into [:map {:date-range [:date-range :start-date :end-date]} + [:total-gte {:optional true} [:maybe :double]] + [:total-lte {:optional true} [:maybe :double]] + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]] + [:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]] + [:processor {:optional true} [:maybe (ref->enum-schema "ccp-processor")]]] + default-grid-fields-schema)])) + (def default-read '[:db/id :charge/reference-link :charge/total @@ -47,7 +57,7 @@ :expected-deposit/_charges [:expected-deposit/date :db/id]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in ['$ '[?clients ?start-date ?end-date]] :where '[[(iol-ion.query/scan-charges $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]]} @@ -115,11 +125,6 @@ :nav com/main-aside-nav :page-specific-nav filters :fetch-page fetch-page - :parse-query-params (comp - (query-params/parse-key :processor #(query-params/parse-keyword "ccp-processor" %)) - (query-params/parse-key :total-gte query-params/parse-double) - (query-params/parse-key :total-lte query-params/parse-double) - (helper/default-parse-query-params grid-page)) :oob-render (fn [request] [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)]) @@ -132,6 +137,7 @@ "Tenders"]] :title "Tenders" :entity-name "Tender" + :query-schema query-schema :route :pos-tender-table :row-buttons (fn [request e] (when (:charge/reference-link e) @@ -177,5 +183,13 @@ (def table* (partial helper/table* grid-page)) (def key->handler - {:pos-tenders (helper/page-route grid-page) - :pos-tender-table (helper/table-route grid-page)}) + (apply-middleware-to-all-handlers + {:pos-tenders (helper/page-route grid-page) + :pos-tender-table (helper/table-route grid-page)} + (fn [h] + (-> h + (wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema))))) diff --git a/src/clj/auto_ap/ssr/transaction.clj b/src/clj/auto_ap/ssr/transaction.clj index 3612a55b..da413847 100644 --- a/src/clj/auto_ap/ssr/transaction.clj +++ b/src/clj/auto_ap/ssr/transaction.clj @@ -259,8 +259,6 @@ :page-specific-nav filters :fetch-page fetch-page :query-schema query-schema - :parse-query-params (fn [p] - (mc/decode query-schema p main-transformer)) :action-buttons (fn [request] [(com/button {:color :primary :hx-get (bidi/path-for ssr-routes/only-routes @@ -364,12 +362,11 @@ ;; Handlers -(def page (helper/page-route grid-page :parse-query-params? false)) +(def page (helper/page-route grid-page)) -(def table (helper/table-route grid-page :parse-query-params? false)) +(def table (helper/table-route grid-page)) -(defn csv [request] - (helper/csv-route grid-page :parse-query-params? false request)) +(def csv (helper/csv-route grid-page)) (def key->handler (apply-middleware-to-all-handlers diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 84f03fb1..8c2c6107 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -1,45 +1,31 @@ (ns auto-ap.ssr.users (:require [auto-ap.datomic - :refer [add-sorter-fields - apply-pagination - apply-sort-3 - conn - merge-query - pull-attr - pull-many - query2]] - [auto-ap.query-params :as query-params] + :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query + pull-attr pull-many query2]] + [auto-ap.query-params :as query-params :refer [wrap-copy-qp-pqp]] [auto-ap.routes.auth :as auth] [auto-ap.routes.utils :refer [wrap-admin wrap-client-redirect-unauthenticated]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] [auto-ap.ssr.form-cursor :as fc] - [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] [auto-ap.ssr.hx :as hx] [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] [auto-ap.ssr.svg :as svg] [auto-ap.ssr.utils - :refer [apply-middleware-to-all-handlers - entity-id - html-response - main-transformer - many-entity - modal-response - ref->enum-schema - ref->select-options - wrap-entity - wrap-form-4xx-2 - wrap-schema-enforce]] + :refer [apply-middleware-to-all-handlers default-grid-fields-schema + entity-id html-response main-transformer many-entity + modal-response ref->enum-schema ref->select-options wrap-entity + wrap-form-4xx-2 wrap-merge-prior-hx wrap-schema-enforce]] [auto-ap.time :as atime] [bidi.bidi :as bidi] [buddy.sign.jwt :as jwt] [clojure.string :as str] [config.core :refer [env]] [datomic.api :as dc] - [malli.core :as mc] - [auto-ap.logging :as alog])) + [malli.core :as mc])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -53,7 +39,7 @@ (com/text-input {:name "name" :id "name" :class "hot-filter" - :value (:name (:parsed-query-params request)) + :value (:name (:query-params request)) :placeholder "Johnny Testerson" :size :small})) @@ -63,7 +49,7 @@ :url (bidi/path-for ssr-routes/only-routes :company-search) :id (str "client-search") - :value (:client (:parsed-query-params request)) + :value (:client (:query-params request)) :value-fn :db/id :content-fn :client/name})) @@ -71,13 +57,14 @@ (com/text-input {:name "email" :id "email" :class "hot-filter" - :value (:name (:parsed-query-params request)) + :value (:name (:query-params request)) :placeholder "hello@friend.com" :size :small})) (com/field {:label "Role"} (com/radio-card {:size :small :name "role" +:value (:role (:query-params request)) :options [{:value "" :content "All"} {:value "admin" @@ -93,6 +80,13 @@ {:value "none" :content "None"}]}))]]) +(def query-schema (mc/schema + [:maybe + (into [:map {} + [:role {:optional true} [:maybe (ref->enum-schema "user-role")]] + [:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]] ] + default-grid-fields-schema)])) + (def default-read '[:db/id :user/name :user/email @@ -103,7 +97,7 @@ :user/clients [:client/code :db/id :client/locations :client/name]}]) (defn fetch-ids [db request] - (let [query-params (:parsed-query-params request) + (let [query-params (:query-params request) query (cond-> {:query {:find [] :in '[$ ] :where '[]} @@ -121,16 +115,16 @@ (merge-query {:query {:find [] :in ['?ns] :where ['[?e :user/name ?sn] - '[(clojure.string/upper-case ?sn) ?upper-sn] - '[(clojure.string/includes? ?upper-sn ?ns)]]} + '[(clojure.string/upper-case ?sn) ?upper-sn] + '[(clojure.string/includes? ?upper-sn ?ns)]]} :args [(str/upper-case (:name query-params))]}) (some->> query-params :email not-empty) (merge-query {:query {:find [] :in ['?es] :where ['[?e :user/email ?se] - '[(clojure.string/upper-case ?se) ?upper-se] - '[(clojure.string/includes? ?upper-se ?es)]]} + '[(clojure.string/upper-case ?se) ?upper-se] + '[(clojure.string/includes? ?upper-se ?es)]]} :args [(str/upper-case (:email query-params))]}) (some->> query-params :client :db/id) @@ -142,8 +136,7 @@ (some->> query-params :role) (merge-query {:query {:find [] :in ['?r] - :where ['[?e :user/role ?r] - '[?r :db/ident ?ri]]} + :where ['[?e :user/role ?r] ]} :args [(some->> query-params :role)]}) @@ -200,19 +193,12 @@ (com/pill {:color :white} (format "%d more" remainder))))]) -(defn parse-client [client] - (let [client-id (Long/parseLong client)] - (dc/pull (dc/db conn) '[:client/name :db/id] client-id))) (def grid-page (helper/build {:id "user-table" :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page - :parse-query-params (comp - (query-params/parse-key :role #(query-params/parse-keyword "user-role" %)) - (query-params/parse-key :client parse-client) - (helper/default-parse-query-params grid-page)) :row-buttons (fn [request entity] [(com/button {:hx-post (str (bidi/path-for ssr-routes/only-routes :user-impersonate)) @@ -231,6 +217,7 @@ :title "Users" :entity-name "User" :route :user-table + :query-schema query-schema :headers [{:key "name" :name "Name" :sort-key "name" @@ -396,5 +383,10 @@ :params-schema (mc/schema [:map [:db/id entity-id]])))} (fn [h] (-> h +(wrap-copy-qp-pqp) + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) (wrap-admin) (wrap-client-redirect-unauthenticated))))) diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index e804cd89..fa9efebd 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -668,10 +668,7 @@ (with-precision 2 (double (.setScale (bigdec d) 2 java.math.RoundingMode/HALF_UP)))) -(defn or-0 [x] - (if (nil? x) - 0.0 - x)) + (defn wrap-implied-route-param [handler & {:as route-params}] (fn [request] @@ -701,4 +698,11 @@ (= "A" location)) (throw (ex-info "Exception." {:type "'A' not allowed"}))) - true)) \ No newline at end of file + true)) + +(def default-grid-fields-schema + [ + [:sort {:optional true} [:maybe [:any]]] + [:per-page {:optional true :default 25} [:maybe :int]] + [:start {:optional true :default 0} [:maybe :int]] + [:exact-match-id {:optional true} [:maybe entity-id]]]) \ No newline at end of file