From 85597fd9ebbab41fb3dc01e240aca320378d1827 Mon Sep 17 00:00:00 2001 From: Bryce Date: Thu, 14 Sep 2023 22:45:05 -0700 Subject: [PATCH] ssr sales --- iol_ion/src/iol_ion/query.clj | 11 ++ src/clj/auto_ap/datomic/sales_orders.clj | 17 ++- src/clj/auto_ap/ssr/components/paginator.clj | 8 +- src/clj/auto_ap/ssr/core.clj | 77 ++++++------- src/clj/auto_ap/ssr/grid_page_helper.clj | 64 ++++++----- src/clj/auto_ap/ssr/pos/sales_orders.clj | 107 +++++++++++++++++++ src/cljc/auto_ap/ssr_routes.cljc | 2 + 7 files changed, 212 insertions(+), 74 deletions(-) create mode 100644 src/clj/auto_ap/ssr/pos/sales_orders.clj diff --git a/iol_ion/src/iol_ion/query.clj b/iol_ion/src/iol_ion/query.clj index ba4159fc..9449d845 100644 --- a/iol_ion/src/iol_ion/query.clj +++ b/iol_ion/src/iol_ion/query.clj @@ -48,6 +48,8 @@ [client end])))) + + (defn can-see-client? [identity client] (when (not client) (println "WARNING - permission checking for null client")) @@ -72,6 +74,15 @@ (time/plus (time/days 1)) coerce/to-date)) +(defn scan-sales-orders [db clients start end] + (for [c clients + :let [c (entid db c)] + r (seq (dc/index-range db + :sales-order/client+date + [c (or start #inst "2001-01-01T08:00:00.000-00:00") ] + [c (or (next-day end) #inst "2030-03-05T08:00:00.000-00:00") ]))] + [(:e r) (first (:v r)) (second (:v r))])) + (defn scan-invoices [db clients start end] (for [c clients :let [c (entid db c)] diff --git a/src/clj/auto_ap/datomic/sales_orders.clj b/src/clj/auto_ap/datomic/sales_orders.clj index f5e383c2..36c5fe00 100644 --- a/src/clj/auto_ap/datomic/sales_orders.clj +++ b/src/clj/auto_ap/datomic/sales_orders.clj @@ -70,22 +70,17 @@ :else visible-clients) - (take 3) + (take 10) set) _ (mu/log ::selected-clients :selected-clients selected-clients) query (cond-> {:query {:find [] - :in ['$ '[?c ...]] - :where []} - :args [db selected-clients]} + :in ['$ '[?clients ?start-date ?end-date]] + :where '[[(iol-ion.query/scan-sales-orders $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]]} + :args [db [selected-clients + (some-> (:start (:date-range args)) c/to-date) + (some-> (:end (:date-range args)) c/to-date )]]} - - true - (merge-query {:query {:in ['?start-date '?end-date] - :where '[[(iol-ion.query/sales-orders-in-range $ ?c ?start-date ?end-date) [?e ...]]]} - :args [(or (some-> (:start (:date-range args)) c/to-date) (iol-ion.query/recent-date 5)) - (or (some-> (:end (:date-range args)) c/to-date ) - (c/to-date (time/now)))]}) (:sort args) (add-sorter-fields-2 {"client" ['[?e :sales-order/client ?c] '[?c :client/name ?sort-client]] "location" ['[?e :sales-order/location ?sort-location]] diff --git a/src/clj/auto_ap/ssr/components/paginator.clj b/src/clj/auto_ap/ssr/components/paginator.clj index c89caffb..6a27ff20 100644 --- a/src/clj/auto_ap/ssr/components/paginator.clj +++ b/src/clj/auto_ap/ssr/components/paginator.clj @@ -1,4 +1,5 @@ -(ns auto-ap.ssr.components.paginator) +(ns auto-ap.ssr.components.paginator + (:require [auto-ap.ssr.svg :as svg])) (defn bound [x y z] (cond @@ -34,7 +35,10 @@ (not= current-page x) (str " text-gray-500 bg-white border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"))) (assoc :href "#")) - (inc x)]])) + [:div.htmx-indicator.flex.items-center + (svg/spinner {:class "inline w-4 h-4 text-black"})] + [:div.htmx-indicator-hidden + (inc x)]]])) last-page-button (Math/min (long total-pages) (long (+ max-buttons first-page-button))) diff --git a/src/clj/auto_ap/ssr/core.clj b/src/clj/auto_ap/ssr/core.clj index 8dc4bd5d..a32a3bf2 100644 --- a/src/clj/auto_ap/ssr/core.clj +++ b/src/clj/auto_ap/ssr/core.clj @@ -12,47 +12,50 @@ [auto-ap.ssr.company-dropdown :as company-dropdown] [auto-ap.ssr.company.reports :as company-reports] [auto-ap.ssr.invoice.glimpse :as invoice-glimpse] + [auto-ap.ssr.pos.sales-orders :as pos-sales] [auto-ap.routes.ezcater-xls :as ezcater-xls] [auto-ap.ssr.company :as company])) ;; from auto-ap.ssr-routes, because they're shared -(def key->handler {:logout auth/logout - :admin-history (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin history/page))) - :admin-history-search (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin history/page))) - :admin-history-inspect (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin history/inspect))) - :active-client (wrap-client-redirect-unauthenticated (wrap-secure (wrap-secure company-dropdown/active-client))) - :company-dropdown-search-results - (wrap-client-redirect-unauthenticated (wrap-secure company-dropdown/dropdown-search-results)) - :company (wrap-client-redirect-unauthenticated (wrap-secure company/page)) - :company-1099 (wrap-client-redirect-unauthenticated (wrap-secure company-1099/page)) - :company-1099-vendor-table (wrap-client-redirect-unauthenticated (wrap-secure company-1099/vendor-table)) - :company-1099-vendor-dialog (wrap-client-redirect-unauthenticated (wrap-secure company-1099/vendor-dialog)) - :company-1099-vendor-save (wrap-client-redirect-unauthenticated (wrap-secure company-1099/vendor-save)) - :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-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-admin company-yodlee/reauthenticate)) - :company-reports (wrap-client-redirect-unauthenticated (wrap-secure company-reports/page)) - :company-reports-table (wrap-client-redirect-unauthenticated (wrap-secure company-reports/table)) - :company-reports-delete (wrap-client-redirect-unauthenticated (wrap-admin company-reports/delete-report)) - :invoice-glimpse (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/page)) - :invoice-glimpse-upload (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/upload)) - :invoice-glimpse-textract-invoice (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/textract-invoice)) - :invoice-glimpse-create-invoice (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/create-invoice)) - :invoice-glimpse-update-textract-invoice (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/update-textract-invoice)) - :transaction-insights (wrap-client-redirect-unauthenticated (wrap-admin insights/page)) - :transaction-insight-table (wrap-client-redirect-unauthenticated (wrap-admin insights/insight-table)) - :transaction-insight-rows (wrap-client-redirect-unauthenticated (wrap-admin insights/transaction-rows)) - :transaction-insight-code (wrap-client-redirect-unauthenticated (wrap-admin insights/code)) - :transaction-insight-disapprove (wrap-client-redirect-unauthenticated (wrap-admin insights/disapprove)) - :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))}) +(def key->handler (into {:logout auth/logout + :admin-history (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin history/page))) + :admin-history-search (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin history/page))) + :admin-history-inspect (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin history/inspect))) + :active-client (wrap-client-redirect-unauthenticated (wrap-secure (wrap-secure company-dropdown/active-client))) + :company-dropdown-search-results + (wrap-client-redirect-unauthenticated (wrap-secure company-dropdown/dropdown-search-results)) + :company (wrap-client-redirect-unauthenticated (wrap-secure company/page)) + :company-1099 (wrap-client-redirect-unauthenticated (wrap-secure company-1099/page)) + :company-1099-vendor-table (wrap-client-redirect-unauthenticated (wrap-secure company-1099/vendor-table)) + :company-1099-vendor-dialog (wrap-client-redirect-unauthenticated (wrap-secure company-1099/vendor-dialog)) + :company-1099-vendor-save (wrap-client-redirect-unauthenticated (wrap-secure company-1099/vendor-save)) + :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-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-admin company-yodlee/reauthenticate)) + :company-reports (wrap-client-redirect-unauthenticated (wrap-secure company-reports/page)) + :company-reports-table (wrap-client-redirect-unauthenticated (wrap-secure company-reports/table)) + :company-reports-delete (wrap-client-redirect-unauthenticated (wrap-admin company-reports/delete-report)) + :invoice-glimpse (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/page)) + :invoice-glimpse-upload (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/upload)) + :invoice-glimpse-textract-invoice (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/textract-invoice)) + :invoice-glimpse-create-invoice (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/create-invoice)) + :invoice-glimpse-update-textract-invoice (wrap-client-redirect-unauthenticated (wrap-admin invoice-glimpse/update-textract-invoice)) + :transaction-insights (wrap-client-redirect-unauthenticated (wrap-admin insights/page)) + :transaction-insight-table (wrap-client-redirect-unauthenticated (wrap-admin insights/insight-table)) + :transaction-insight-rows (wrap-client-redirect-unauthenticated (wrap-admin insights/transaction-rows)) + :transaction-insight-code (wrap-client-redirect-unauthenticated (wrap-admin insights/code)) + :transaction-insight-disapprove (wrap-client-redirect-unauthenticated (wrap-admin insights/disapprove)) + :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))} + + pos-sales/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 4f3068d8..e104e602 100644 --- a/src/clj/auto_ap/ssr/grid_page_helper.clj +++ b/src/clj/auto_ap/ssr/grid_page_helper.clj @@ -12,13 +12,19 @@ [unilog.context :as lc] [com.brunobonacci.mulog :as mu])) -(defn row* [gridspec user entity {:keys [flash? delete-after-settle?] :as options}] - (let [cells (mapv (fn [header] - (com/data-grid-cell {:class (if-let [show-starting (:show-starting header)] - (format "hidden %s:table-cell" show-starting) - (:class header))} - ((:render header) entity))) - (:headers gridspec)) +(defn row* [gridspec user entity {:keys [flash? delete-after-settle? params] :as options}] + (let [cells (->> gridspec + :headers + (filter (fn [h] + (if (and (:hide? h) + ((:hide? h) params)) + nil + h))) + (mapv (fn [header] + (com/data-grid-cell {:class (if-let [show-starting (:show-starting header)] + (format "hidden %s:table-cell" show-starting) + (:class header))} + ((:render header) entity))))) cells (conj cells (com/data-grid-right-stack-cell {} (into [:form [:input {:type :hidden :name "id" :value ((:id-fn gridspec) entity)}]] @@ -73,7 +79,7 @@ (sort-by-list sort)] :action-buttons ((:action-buttons grid-spec) user params) :rows (for [entity entities] - (row* grid-spec user entity {:flash? (= flash-id ((:id-fn grid-spec) entity))})) + (row* grid-spec user entity {:flash? (= flash-id ((:id-fn grid-spec) entity)) :params params})) :thead-params {:hx-get (bidi/path-for ssr-routes/only-routes (:route grid-spec)) :hx-target (str "#" (:id grid-spec)) @@ -81,25 +87,35 @@ :hx-vals "js:{\"toggle-sort\": event.detail.key || \"\"}"} :headers (conj - (mapv - (fn [h] - (if (:sort-key h) - (com/data-grid-sort-header {:class (if-let [show-starting (:show-starting h)] + (->> grid-spec + :headers + (map + (fn [h] + (cond + (and (:hide? h) + ((:hide? h) params)) + nil + + (:sort-key h) + (com/data-grid-sort-header {:class (if-let [show-starting (:show-starting h)] + (format "hidden %s:table-cell" show-starting) + (:class h)) + :sort-key (:sort-key h)} + + [:div.flex.gap-4.items-center + (:name h) + [:div.h-6.w-6.text-gray-400.dark:text-gray-500 (sort-icon sort (:sort-key h))]]) + + :else + (com/data-grid-header {:class (if-let [show-starting (:show-starting h)] (format "hidden %s:table-cell" show-starting) (:class h)) :sort-key (:sort-key h)} + (:name h)) - [:div.flex.gap-4.items-center - (:name h) - [:div.h-6.w-6.text-gray-400.dark:text-gray-500 (sort-icon sort (:sort-key h))]]) - (com/data-grid-header {:class (if-let [show-starting (:show-starting h)] - (format "hidden %s:table-cell" show-starting) - (:class h)) - :sort-key (:sort-key h)} - (:name h)) - - )) - (:headers grid-spec)) + ))) + (filter identity) + (into [])) (com/data-grid-header {}))}))) @@ -146,7 +162,7 @@ (defn params->query-string [q] (-> q - (dissoc :client :session) + (dissoc :client :session :client-selection :clients) (update :sort sort->query) (url/map->query))) diff --git a/src/clj/auto_ap/ssr/pos/sales_orders.clj b/src/clj/auto_ap/ssr/pos/sales_orders.clj new file mode 100644 index 00000000..086b04c7 --- /dev/null +++ b/src/clj/auto_ap/ssr/pos/sales_orders.clj @@ -0,0 +1,107 @@ +(ns auto-ap.ssr.pos.sales-orders + (:require + [auto-ap.datomic.sales-orders :as d-sales] + [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] + [auto-ap.ssr.svg :as svg] + [auto-ap.time :as atime] + [bidi.bidi :as bidi] + [clj-time.coerce :as coerce])) + +(def grid-page {:id "sales-table" + :nav (com/main-aside-nav) + :id-fn :db/id + :fetch-page (fn [user args] + (d-sales/get-graphql (-> args + (assoc :date-range {:start (coerce/to-date-time #inst "2023-05-01")})))) + :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 [user _] + nil) + :row-buttons (fn [user e] + + (when (:sales-order/reference-link e) + [(com/a-icon-button {:href (:sales-order/reference-link e)} + svg/external-link) + #_(when (is-admin? user) + (com/icon-button {:hx-delete (str (bidi/path-for ssr-routes/only-routes + :company-reports-delete + :request-method :delete)) + :hx-target "closest tr"} + svg/trash))])) + :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] + (println ) + (for [method (->> sales-order :sales-order/charges (map :charge/type-name) set)] + (com/pill {:color :primary } + method)))}]}) + +(def row* (partial helper/row* grid-page)) +(def table* (partial helper/table* grid-page)) +(def table (partial helper/table grid-page)) +(def page (partial helper/page grid-page)) + +#_(defn delete-report [{:keys [form-params identity]}] + + (let [[id-to-delete key] (first (dc/q '[:find ?i ?k + :in $ ?i + :where [?i :report/key ?k]] + (dc/db conn) + (some-> (get form-params "id") not-empty Long/parseLong))) + report (dc/pull (dc/db conn) r/default-read id-to-delete)] + (assert-can-see-client identity (:report/client report)) + (when id-to-delete + (s3/delete-object :bucket-name (:data-bucket env) + :key key) + @(dc/transact conn [[:db/retractEntity id-to-delete]])) + (html-response + (row* identity + report + {:flash? true + :delete-after-settle? true})))) + +(def key->handler + {:pos-sales (wrap-client-redirect-unauthenticated (wrap-secure page)) + :pos-sales-table (wrap-client-redirect-unauthenticated (wrap-secure table))}) diff --git a/src/cljc/auto_ap/ssr_routes.cljc b/src/cljc/auto_ap/ssr_routes.cljc index cd0d1949..c6698efc 100644 --- a/src/cljc/auto_ap/ssr_routes.cljc +++ b/src/cljc/auto_ap/ssr_routes.cljc @@ -19,6 +19,8 @@ ["/disapprove/" [#"\d+" :transaction-id]] {:delete :transaction-insight-disapprove} ["/rows/" [#"\d+" :after]] {:get :transaction-insight-rows} ["/explain/" [#"\d+" :transaction-id]] {:get :transaction-insight-explain}}} + "pos" {"/sales" {"" {:get :pos-sales} + "/table" {:get :pos-sales-table}}} "company" {"" :company "/dropdown" :company-dropdown-search-results "/active" {:put :active-client}