Merge branch 'ssr-sales'
This commit is contained in:
@@ -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,51 @@
|
||||
(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-charges [db clients start end]
|
||||
(for [c clients
|
||||
:let [c (entid db c)]
|
||||
r (seq (dc/index-range db
|
||||
:charge/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-sales-refunds [db clients start end]
|
||||
(for [c clients
|
||||
:let [c (entid db c)]
|
||||
r (seq (dc/index-range db
|
||||
:sales-refund/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-expected-deposits [db clients start end]
|
||||
(for [c clients
|
||||
:let [c (entid db c)]
|
||||
r (seq (dc/index-range db
|
||||
:expected-deposit/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-cash-drawer-shifts [db clients start end]
|
||||
(for [c clients
|
||||
:let [c (entid db c)]
|
||||
r (seq (dc/index-range db
|
||||
:cash-drawer-shift/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)]
|
||||
@@ -107,3 +154,6 @@
|
||||
[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 ident [x]
|
||||
(:db/ident x))
|
||||
|
||||
1
resources/datomic/extensions.edn
Normal file
1
resources/datomic/extensions.edn
Normal file
@@ -0,0 +1 @@
|
||||
{:xforms [clj-time.coerce/to-date clj-time.coerce/from-date iol-ion.query/ident ]}
|
||||
@@ -16,3 +16,7 @@ htmx.defineExtension('disable-submit', {
|
||||
*/
|
||||
}
|
||||
})
|
||||
|
||||
initDatepicker = function(elem) {
|
||||
elem.dp = new Datepicker(elem, {format: "mm/dd/yyyy", autohide: true});
|
||||
}
|
||||
@@ -1075,6 +1075,10 @@ input:checked + .toggle-bg {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.left-1\/2 {
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.right-0 {
|
||||
right: 0px;
|
||||
}
|
||||
@@ -1091,6 +1095,10 @@ input:checked + .toggle-bg {
|
||||
top: 0.5rem;
|
||||
}
|
||||
|
||||
.top-2\/4 {
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.top-5 {
|
||||
top: 1.25rem;
|
||||
}
|
||||
@@ -1348,6 +1356,10 @@ input:checked + .toggle-bg {
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.w-48 {
|
||||
width: 12rem;
|
||||
}
|
||||
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
@@ -1408,11 +1420,21 @@ input:checked + .toggle-bg {
|
||||
flex-basis: 25%;
|
||||
}
|
||||
|
||||
.-translate-x-1\/2 {
|
||||
--tw-translate-x: -50%;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.-translate-x-full {
|
||||
--tw-translate-x: -100%;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.-translate-y-1\/2 {
|
||||
--tw-translate-y: -50%;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.-translate-y-full {
|
||||
--tw-translate-y: -100%;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
@@ -1446,6 +1468,16 @@ input:checked + .toggle-bg {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
50% {
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-pulse {
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
@@ -1476,6 +1508,12 @@ input:checked + .toggle-bg {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.appearance-none {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.grid-cols-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
@@ -1520,6 +1558,10 @@ input:checked + .toggle-bg {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.items-baseline {
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.items-stretch {
|
||||
align-items: stretch;
|
||||
}
|
||||
@@ -1585,6 +1627,18 @@ input:checked + .toggle-bg {
|
||||
margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
|
||||
}
|
||||
|
||||
.space-y-1 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
|
||||
margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
|
||||
}
|
||||
|
||||
.space-y-1\.5 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-top: calc(0.375rem * calc(1 - var(--tw-space-y-reverse)));
|
||||
margin-bottom: calc(0.375rem * var(--tw-space-y-reverse));
|
||||
}
|
||||
|
||||
.space-y-2 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
|
||||
@@ -1662,6 +1716,10 @@ input:checked + .toggle-bg {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.rounded-md {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
.rounded-l-lg {
|
||||
border-top-left-radius: 0.5rem;
|
||||
border-bottom-left-radius: 0.5rem;
|
||||
@@ -1677,6 +1735,11 @@ input:checked + .toggle-bg {
|
||||
border-top-right-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.rounded-t-lg {
|
||||
border-top-left-radius: 0.5rem;
|
||||
border-top-right-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-width: 1px;
|
||||
}
|
||||
@@ -2052,6 +2115,10 @@ input:checked + .toggle-bg {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.align-baseline {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
@@ -2114,10 +2181,19 @@ input:checked + .toggle-bg {
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
.leading-none {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.leading-tight {
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.text-black {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(0 0 0 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-blue-400 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(51 176 238 / var(--tw-text-opacity));
|
||||
@@ -2511,6 +2587,10 @@ input:checked + .toggle-bg {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.focus\:z-10:focus {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.focus\:border-blue-500:focus {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(0 156 234 / var(--tw-border-opacity));
|
||||
@@ -2521,6 +2601,11 @@ input:checked + .toggle-bg {
|
||||
border-color: rgb(121 181 46 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.focus\:text-green-700:focus {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(73 109 28 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.focus\:outline-none:focus {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
@@ -2573,6 +2658,11 @@ input:checked + .toggle-bg {
|
||||
--tw-ring-color: rgb(175 211 130 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
.focus\:ring-green-700:focus {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(73 109 28 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
.focus\:ring-primary-500:focus {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(121 181 46 / var(--tw-ring-opacity));
|
||||
@@ -2714,6 +2804,11 @@ input:checked + .toggle-bg {
|
||||
--tw-bg-opacity: 0.8;
|
||||
}
|
||||
|
||||
:is(.dark .dark\:text-blue-200) {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(153 215 247 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
:is(.dark .dark\:text-blue-300) {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(102 196 242 / var(--tw-text-opacity));
|
||||
@@ -2794,6 +2889,10 @@ input:checked + .toggle-bg {
|
||||
color: rgb(156 163 175 / var(--tw-placeholder-opacity));
|
||||
}
|
||||
|
||||
:is(.dark .dark\:ring-offset-gray-700) {
|
||||
--tw-ring-offset-color: #374151;
|
||||
}
|
||||
|
||||
:is(.dark .dark\:ring-offset-gray-800) {
|
||||
--tw-ring-offset-color: #1F2937;
|
||||
}
|
||||
@@ -2868,11 +2967,21 @@ input:checked + .toggle-bg {
|
||||
border-color: rgb(121 181 46 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
:is(.dark .dark\:focus\:text-white:focus) {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
:is(.dark .dark\:focus\:ring-blue-500:focus) {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(0 156 234 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
:is(.dark .dark\:focus\:ring-blue-600:focus) {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(0 125 187 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
:is(.dark .dark\:focus\:ring-blue-800:focus) {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(0 62 94 / var(--tw-ring-opacity));
|
||||
@@ -2883,6 +2992,11 @@ input:checked + .toggle-bg {
|
||||
--tw-ring-color: rgb(75 85 99 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
:is(.dark .dark\:focus\:ring-green-500:focus) {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(121 181 46 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
:is(.dark .dark\:focus\:ring-green-800:focus) {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(48 72 18 / var(--tw-ring-opacity));
|
||||
@@ -2898,6 +3012,10 @@ input:checked + .toggle-bg {
|
||||
--tw-ring-color: rgb(97 145 37 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
:is(.dark .dark\:focus\:ring-offset-gray-700:focus) {
|
||||
--tw-ring-offset-color: #374151;
|
||||
}
|
||||
|
||||
:is(.dark .group:hover .dark\:group-hover\:text-white) {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
|
||||
@@ -1806,6 +1806,28 @@
|
||||
:db/valueType :db.type/tuple
|
||||
:db/tupleAttrs [ :payment/client :payment/date]
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/index true}
|
||||
|
||||
{:db/ident :charge/client+date
|
||||
:db/valueType :db.type/tuple
|
||||
:db/tupleAttrs [ :charge/client :charge/date]
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/index true}
|
||||
|
||||
{:db/ident :sales-refund/client+date
|
||||
:db/valueType :db.type/tuple
|
||||
:db/tupleAttrs [ :sales-refund/client :sales-refund/date]
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/index true}
|
||||
{:db/ident :cash-drawer-shift/client+date
|
||||
:db/valueType :db.type/tuple
|
||||
:db/tupleAttrs [ :cash-drawer-shift/client :cash-drawer-shift/date]
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/index true}
|
||||
{:db/ident :expected-deposit/client+date
|
||||
:db/valueType :db.type/tuple
|
||||
:db/tupleAttrs [ :expected-deposit/client :expected-deposit/date]
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/index true}]
|
||||
|
||||
|
||||
|
||||
@@ -180,4 +180,48 @@
|
||||
|
||||
{:user/name "hydrate-tuples"})
|
||||
|
||||
(auto-ap.datomic/audit-transact-batch (->> (dc/q '[:find ?e ?c
|
||||
:in $
|
||||
:where [?e :charge/client ?c]]
|
||||
(dc/db conn)
|
||||
)
|
||||
(map (fn [[i c]]
|
||||
{:db/id i
|
||||
:charge/client c})))
|
||||
|
||||
{:user/name "hydrate-tuples"})
|
||||
|
||||
(auto-ap.datomic/audit-transact-batch (->> (dc/q '[:find ?e ?c
|
||||
:in $
|
||||
:where [?e :cash-drawer-shift/client ?c]]
|
||||
(dc/db conn)
|
||||
)
|
||||
(map (fn [[i c]]
|
||||
{:db/id i
|
||||
:cash-drawer-shift/client c})))
|
||||
|
||||
{:user/name "hydrate-tuples"})
|
||||
|
||||
(auto-ap.datomic/audit-transact-batch (->> (dc/q '[:find ?e ?c
|
||||
:in $
|
||||
:where [?e :sales-refund/client ?c]]
|
||||
(dc/db conn)
|
||||
)
|
||||
(map (fn [[i c]]
|
||||
{:db/id i
|
||||
:sales-refund/client c})))
|
||||
|
||||
{:user/name "hydrate-tuples"})
|
||||
|
||||
(auto-ap.datomic/audit-transact-batch (->> (dc/q '[:find ?e ?c
|
||||
:in $
|
||||
:where [?e :expected-deposit/client ?c]]
|
||||
(dc/db conn)
|
||||
)
|
||||
(map (fn [[i c]]
|
||||
{:db/id i
|
||||
:expected-deposit/client c})))
|
||||
|
||||
{:user/name "hydrate-tuples"})
|
||||
|
||||
)
|
||||
|
||||
@@ -623,14 +623,16 @@
|
||||
|
||||
(defn apply-pagination-raw [args results]
|
||||
{:entries (->> results
|
||||
(drop (:start args 0))
|
||||
(take (:count args (or (:per-page args) default-pagination-size))))
|
||||
(drop (or (:start args) 0))
|
||||
(take (or (:count args) (:per-page args) default-pagination-size)))
|
||||
:count (count results)})
|
||||
|
||||
(defn apply-pagination [args results]
|
||||
{:ids (->> results
|
||||
(drop (:start args 0))
|
||||
(take (:count args (or (:per-page args) default-pagination-size)))
|
||||
(drop (or (:start args) 0))
|
||||
(take (or (:count args )
|
||||
(:per-page args)
|
||||
default-pagination-size))
|
||||
(map last))
|
||||
:count (count results)})
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
(ns auto-ap.datomic.reports
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
:refer [add-sorter-fields
|
||||
apply-pagination
|
||||
apply-sort-3
|
||||
conn
|
||||
merge-query
|
||||
pull-many
|
||||
query2]]
|
||||
[auto-ap.graphql.utils :refer [can-see-client? extract-client-ids]]
|
||||
[clj-time.coerce :as c]
|
||||
[datomic.api :as dc]))
|
||||
|
||||
(def default-read '[:db/id :report/client :report/created :report/url :report/name :report/creator])
|
||||
|
||||
(defn raw-graphql-ids [db args]
|
||||
|
||||
(let [valid-clients (extract-client-ids (:clients args)
|
||||
(:client-id args)
|
||||
(when (:client-code args)
|
||||
[:client/code (:client-code args)]))
|
||||
query (cond-> {:query {:find []
|
||||
:in ['$ ]
|
||||
:where []}
|
||||
:args [db]}
|
||||
|
||||
|
||||
(seq (:clients args))
|
||||
(merge-query {:query {:in ['[?xx ...]]
|
||||
:where ['[?e :report/client ?xx]]}
|
||||
:args [valid-clients]})
|
||||
|
||||
(:sort args) (add-sorter-fields {"client" ['[?e :report/client ?c]
|
||||
'[?c :client/name ?sort-client]]
|
||||
"created" ['[?e :report/created ?sort-created]]
|
||||
"creator" ['[?e :report/creator ?sort-creator]]
|
||||
"name" ['[?e :report/name ?sort-name]
|
||||
]}
|
||||
args)
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e] :where ['[?e :report/created ?sort-default]]}}))]
|
||||
(->> (query2 query)
|
||||
(apply-sort-3 (update args :sort conj {:sort-key "default-2" :asc true}))
|
||||
(apply-pagination args))))
|
||||
|
||||
(defn graphql-results [ids db args]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(map #(update % :report/created c/from-date))
|
||||
(group-by :db/id))]
|
||||
(->> ids
|
||||
(map results)
|
||||
(filter identity)
|
||||
|
||||
(map first)
|
||||
(filter (fn [r]
|
||||
(every?
|
||||
#(can-see-client? (:id args) %)
|
||||
(map :db/id (:report/client r))))))))
|
||||
|
||||
(defn get-graphql [args]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
|
||||
[(->> (graphql-results ids-to-retrieve db args))
|
||||
matching-count]))
|
||||
@@ -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]]
|
||||
@@ -169,3 +164,8 @@
|
||||
matching-count
|
||||
(summarize-orders ids-to-retrieve)]))
|
||||
|
||||
(defn summarize-graphql [args]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (mu/trace ::get-sales-order-ids [] (raw-graphql-ids db args))]
|
||||
(summarize-orders ids-to-retrieve)))
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
(ns auto-ap.datomic.yodlee2
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
:refer [add-sorter-fields
|
||||
apply-pagination
|
||||
apply-sort-3
|
||||
conn
|
||||
merge-query
|
||||
pull-many
|
||||
query2]]
|
||||
[auto-ap.graphql.utils :refer [extract-client-ids]]
|
||||
[clj-time.coerce :as c]
|
||||
[datomic.api :as dc]))
|
||||
|
||||
(def default-read '[*])
|
||||
|
||||
(defn <-datomic [x]
|
||||
(-> x (update :yodlee-provider-account/last-updated c/from-date)))
|
||||
|
||||
(defn raw-graphql-ids [db args]
|
||||
(let [valid-clients (extract-client-ids (:clients args)
|
||||
(:client-id args)
|
||||
(when (:client-code args)
|
||||
[:client/code (:client-code args)]))]
|
||||
(->> (cond-> {:query {:find []
|
||||
:in ['$ '[?xx ...]]
|
||||
:where ['[?e :yodlee-provider-account/id]
|
||||
'[?e :yodlee-provider-account/client ?xx]]}
|
||||
:args [db valid-clients]}
|
||||
|
||||
|
||||
(:client-id args)
|
||||
(merge-query {:query {:in ['?client-id]
|
||||
:where ['[?e :yodlee-provider-account/client ?client-id]]}
|
||||
:args [ (:client-id args)]})
|
||||
|
||||
(:client-code args)
|
||||
(merge-query {:query {:in ['?client-code]
|
||||
:where ['[?e :yodlee-provider-account/client ?client-id]
|
||||
'[?client-id :client/code ?client-code]]}
|
||||
:args [ (:client-code args)]})
|
||||
|
||||
(:sort args) (add-sorter-fields {"status" ['[?e :yodlee-provider-account/status ?sort-status]]}
|
||||
args)
|
||||
true
|
||||
(merge-query {:query {:find ['?e ]
|
||||
:where ['[?e :yodlee-provider-account/id]]}}) )
|
||||
|
||||
(query2)
|
||||
(apply-sort-3 args)
|
||||
(apply-pagination args))))
|
||||
|
||||
|
||||
(defn graphql-results [ids db _]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))]
|
||||
(->> ids
|
||||
(map results)
|
||||
(map first)
|
||||
(mapv <-datomic))))
|
||||
|
||||
|
||||
(defn get-graphql [args]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
[(->> (graphql-results ids-to-retrieve db args))
|
||||
matching-count]))
|
||||
|
||||
119
src/clj/auto_ap/query_params.clj
Normal file
119
src/clj/auto_ap/query_params.clj
Normal file
@@ -0,0 +1,119 @@
|
||||
(ns auto-ap.query-params
|
||||
(:require [auto-ap.time :as atime]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[clj-time.core :as time]
|
||||
[clojure.string :as str]))
|
||||
|
||||
|
||||
(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)
|
||||
(update query-params k #(some-> % not-empty parser))
|
||||
query-params)))
|
||||
|
||||
(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)
|
||||
(->>
|
||||
(str/split q #",")
|
||||
(map (fn [k]
|
||||
(let [[key asc?] (str/split k #":")
|
||||
matching-header (first (filter #(= (str key) (:sort-key %)) (:headers grid-spec)))]
|
||||
{:sort-key (str key)
|
||||
:asc (boolean (= "asc" asc?))
|
||||
:matching-header matching-header
|
||||
:name (:name matching-header)
|
||||
:sort-icon (if (= (boolean (= "asc" asc?)) true)
|
||||
svg/sort-down
|
||||
svg/sort-up)})))
|
||||
(filter :matching-header)
|
||||
(into []))
|
||||
[]))
|
||||
|
||||
(defn parse-long [l]
|
||||
(try
|
||||
(Long/parseLong l)
|
||||
(catch Exception e
|
||||
nil)))
|
||||
|
||||
(defn parse-double [l]
|
||||
(try
|
||||
(Double/parseDouble l)
|
||||
(catch Exception e
|
||||
nil)))
|
||||
|
||||
(defn apply-date-range [source-key start-date-key end-date-key]
|
||||
(fn [query-params]
|
||||
(dissoc
|
||||
(condp = (source-key query-params)
|
||||
"week"
|
||||
(assoc query-params
|
||||
start-date-key (time/plus (time/now) (time/days -7))
|
||||
end-date-key (time/now))
|
||||
|
||||
"month"
|
||||
(assoc query-params
|
||||
start-date-key (time/plus (time/now) (time/months -1))
|
||||
end-date-key (time/now))
|
||||
|
||||
"year"
|
||||
(assoc query-params
|
||||
start-date-key (time/plus (time/now) (time/years -1))
|
||||
end-date-key (time/now))
|
||||
|
||||
"all"
|
||||
(assoc query-params
|
||||
start-date-key (time/plus (time/now) (time/years -3))
|
||||
end-date-key (time/now))
|
||||
|
||||
query-params)
|
||||
:date-range)))
|
||||
|
||||
(defn apply-toggle-sort [grid-spec]
|
||||
(fn toggle-sort [query-params]
|
||||
(if (:toggle-sort query-params)
|
||||
(let [key-to-toggle (:toggle-sort query-params)
|
||||
current-sort (:sort query-params)
|
||||
presently-sorted? ((set (map :sort-key current-sort)) key-to-toggle)
|
||||
new-sort (if presently-sorted?
|
||||
(mapv
|
||||
(fn [s]
|
||||
(if (= (:sort-key s)
|
||||
key-to-toggle)
|
||||
(-> s
|
||||
(update :asc
|
||||
#(boolean (not %)))
|
||||
(update :sort-icon (fn [x]
|
||||
(if (= x svg/sort-down)
|
||||
svg/sort-up
|
||||
svg/sort-down))))
|
||||
s))
|
||||
current-sort)
|
||||
(conj current-sort {:sort-key key-to-toggle
|
||||
:asc true
|
||||
:name (:name (first (filter #(= (str key-to-toggle) (:sort-key %)) (:headers grid-spec))))
|
||||
:sort-icon svg/sort-down}))]
|
||||
(-> query-params
|
||||
(assoc :sort new-sort)
|
||||
(dissoc :toggle-sort)))
|
||||
query-params)))
|
||||
|
||||
(defn apply-remove-sort []
|
||||
(fn remove-sort [query-params]
|
||||
(if-let [remove-sort-key (:remove-sort query-params)]
|
||||
(-> query-params
|
||||
(update :sort (fn [current-sort]
|
||||
(filterv (comp (complement #{remove-sort-key}) :sort-key) current-sort)))
|
||||
(dissoc :remove-sort))
|
||||
query-params)))
|
||||
@@ -1,6 +1,16 @@
|
||||
(ns auto-ap.ssr.auth)
|
||||
(ns auto-ap.ssr.auth
|
||||
(:require [buddy.sign.jwt :as jwt]
|
||||
[config.core :refer [env]]))
|
||||
|
||||
(defn logout [request]
|
||||
{:status 301
|
||||
:headers {"Location" "/login"}
|
||||
:session {}})
|
||||
|
||||
|
||||
(defn impersonate [request]
|
||||
{:status 200
|
||||
:session {:identity (dissoc (jwt/unsign (get-in request [:query-params "jwt"])
|
||||
(:jwt-secret env)
|
||||
{:alg :hs512})
|
||||
:exp)}})
|
||||
|
||||
@@ -44,161 +44,117 @@
|
||||
client-id
|
||||
vendor-id)))
|
||||
|
||||
(defn get-1099-companies [user {:keys [clients] :as args}]
|
||||
(let [valid-clients (extract-client-ids (:clients args)
|
||||
(:client-id args)
|
||||
(when (:client-code args)
|
||||
[:client/code (:client-code args)]))
|
||||
results (cond
|
||||
clients
|
||||
(dc/q '[:find
|
||||
(pull ?c [:client/code :db/id])
|
||||
(pull ?v vendor-read)
|
||||
(sum ?a)
|
||||
:with ?d
|
||||
:in $ [?c ...] vendor-read
|
||||
:where
|
||||
[?p :payment/client ?c]
|
||||
[?p :payment/date ?d ]
|
||||
[(>= ?d #inst "2022-01-01T08:00")]
|
||||
[(< ?d #inst "2023-01-01T08:00")]
|
||||
[?p :payment/type :payment-type/check]
|
||||
[?p :payment/amount ?a]
|
||||
[?p :payment/vendor ?v]]
|
||||
(dc/db conn)
|
||||
valid-clients
|
||||
vendor-read)
|
||||
|
||||
(is-admin? user)
|
||||
(dc/q '[:find
|
||||
(pull ?c [:client/code :db/id])
|
||||
(pull ?v vendor-read)
|
||||
(sum ?a)
|
||||
:with ?d
|
||||
:in $ vendor-read
|
||||
:where
|
||||
[?p :payment/date ?d ]
|
||||
[(>= ?d #inst "2022-01-01T08:00")]
|
||||
[(< ?d #inst "2023-01-01T08:00")]
|
||||
[?p :payment/type :payment-type/check]
|
||||
[?p :payment/client ?c]
|
||||
[?p :payment/amount ?a]
|
||||
[?p :payment/vendor ?v]]
|
||||
(dc/db conn)
|
||||
vendor-read)
|
||||
|
||||
:else
|
||||
(dc/q '[:find
|
||||
(pull ?c [:client/code :db/id])
|
||||
(pull ?v vendor-read)
|
||||
(sum ?a)
|
||||
:with ?d
|
||||
:in $ [?c ...] vendor-read
|
||||
:where
|
||||
[?p :payment/client ?c]
|
||||
[?p :payment/date ?d ]
|
||||
[(>= ?d #inst "2022-01-01T08:00")]
|
||||
[(< ?d #inst "2023-01-01T08:00")]
|
||||
[?p :payment/type :payment-type/check]
|
||||
[?p :payment/amount ?a]
|
||||
[?p :payment/vendor ?v]]
|
||||
(dc/db conn)
|
||||
valid-clients
|
||||
vendor-read))
|
||||
(defn fetch-page [{:keys [trimmed-clients parsed-query-params] :as request user :identity}]
|
||||
(let [results (dc/q '[:find
|
||||
(pull ?c [:client/code :db/id])
|
||||
(pull ?v vendor-read)
|
||||
(sum ?a)
|
||||
:with ?d
|
||||
:in $ [?c ...] vendor-read
|
||||
:where
|
||||
[?p :payment/client ?c]
|
||||
[?p :payment/date ?d ]
|
||||
[(>= ?d #inst "2022-01-01T08:00")]
|
||||
[(< ?d #inst "2023-01-01T08:00")]
|
||||
[?p :payment/type :payment-type/check]
|
||||
[?p :payment/amount ?a]
|
||||
[?p :payment/vendor ?v]]
|
||||
(dc/db conn)
|
||||
trimmed-clients
|
||||
vendor-read)
|
||||
all (->> results
|
||||
(filter (fn [[_ _ a]]
|
||||
(>= (or a 0.0) 600.0)))
|
||||
(sort-by (fn [[client _ amount]]
|
||||
[(:client/code client ) amount]))
|
||||
(into []))
|
||||
paginated (apply-pagination-raw args all)]
|
||||
paginated (apply-pagination-raw {:start (:start parsed-query-params)
|
||||
:per-page (:per-page parsed-query-params)} all)]
|
||||
[(:entries paginated) (:count paginated)]))
|
||||
|
||||
(def grid-page {:id "vendor-table"
|
||||
:nav (com/company-aside-nav)
|
||||
:id-fn (comp :db/id second)
|
||||
:fetch-page (fn [user args]
|
||||
(get-1099-companies user args)
|
||||
#_(r/get-graphql (into args {:id user})))
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"My Company"]
|
||||
(def grid-page
|
||||
(helper/build
|
||||
{:id "vendor-table"
|
||||
:nav (com/company-aside-nav)
|
||||
:id-fn (comp :db/id second)
|
||||
:fetch-page fetch-page
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"My Company"]
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company-1099)}
|
||||
"1099 Vendor Info"]]
|
||||
:title "1099 Vendors"
|
||||
:entity-name "Vendors"
|
||||
:route :company-1099-vendor-table
|
||||
:action-buttons (fn [user _]
|
||||
nil)
|
||||
:row-buttons (fn [user e]
|
||||
[(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||
:company-1099-vendor-dialog
|
||||
:vendor-id (:db/id (second e)))
|
||||
"?"
|
||||
(url/map->query {:client-id (:db/id (first e))}))
|
||||
:hx-ext "debug"
|
||||
:hx-target "#modal-holder"
|
||||
:hx-swap "outerHTML"}
|
||||
svg/pencil)])
|
||||
:headers [{:key "Client"
|
||||
:name "Client"
|
||||
:sort-key "client"
|
||||
:render (comp :client/code first)}
|
||||
{:key "vendor-name"
|
||||
:name "Vendor Name"
|
||||
:sort-key "vendor"
|
||||
:render (fn [[_ vendor]]
|
||||
[:div.flex.whitespace-nowrap.items-center.gap-4
|
||||
[:div [:div (:vendor/name vendor)]
|
||||
[:div.text-sm.text-gray-400
|
||||
(or (-> vendor :vendor/legal-entity-name not-empty)
|
||||
(str (-> vendor :vendor/legal-entity-first-name) " "
|
||||
(-> vendor :vendor/legal-entity-middle-name) " "
|
||||
(-> vendor :vendor/legal-entity-last-name)))]]
|
||||
(when-let [t99-type (some-> vendor :vendor/legal-entity-1099-type :db/ident name)]
|
||||
(com/pill
|
||||
{:class "text-xs font-medium"
|
||||
:color :primary}
|
||||
(str/capitalize t99-type))
|
||||
)])}
|
||||
{:key "tin"
|
||||
:name "TIN"
|
||||
:sort-key "tin"
|
||||
:show-starting "md"
|
||||
:render (fn [[_ vendor]]
|
||||
[:div.flex.gap-4
|
||||
(when-let [tin (-> vendor :vendor/legal-entity-tin)]
|
||||
[:span {:class "text-xs font-medium py-0.5 "}
|
||||
tin])
|
||||
(when-let [tin-type (some-> vendor :vendor/legal-entity-tin-type :db/ident name)]
|
||||
(com/pill {:class "text-xs font-medium"
|
||||
:color :yellow}
|
||||
(name tin-type)))]
|
||||
)}
|
||||
{:key "address"
|
||||
:name "Address"
|
||||
:sort-key "address"
|
||||
:show-starting "lg"
|
||||
:render (fn [[_ vendor]]
|
||||
(if (-> vendor :vendor/address :address/street1)
|
||||
[:div
|
||||
[:div (-> vendor :vendor/address :address/street1)] " "
|
||||
[:div
|
||||
(-> vendor :vendor/address :address/street2)] " "
|
||||
[:div
|
||||
(-> vendor :vendor/address :address/city) " "
|
||||
(-> vendor :vendor/address :address/state) ","
|
||||
(-> vendor :vendor/address :address/zip)]]
|
||||
[:p.text-sm.italic.text-gray-400 "No address"]))}
|
||||
{:key "paid"
|
||||
:name "Paid"
|
||||
:sort-key "paid"
|
||||
:render (fn [[_ _ paid]]
|
||||
(com/pill {:class "text-xs font-medium"
|
||||
:color :primary}
|
||||
"Paid $" (Math/round paid)))}]})
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company-1099)}
|
||||
"1099 Vendor Info"]]
|
||||
:title "1099 Vendors"
|
||||
:entity-name "Vendors"
|
||||
:route :company-1099-vendor-table
|
||||
:row-buttons (fn [request e]
|
||||
[(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||
:company-1099-vendor-dialog
|
||||
:vendor-id (:db/id (second e)))
|
||||
"?"
|
||||
(url/map->query {:client-id (:db/id (first e))}))
|
||||
:hx-ext "debug"
|
||||
:hx-target "#modal-holder"
|
||||
:hx-swap "outerHTML"}
|
||||
svg/pencil)])
|
||||
:headers [{:key "Client"
|
||||
:name "Client"
|
||||
:sort-key "client"
|
||||
:render (comp :client/code first)}
|
||||
{:key "vendor-name"
|
||||
:name "Vendor Name"
|
||||
:sort-key "vendor"
|
||||
:render (fn [[_ vendor]]
|
||||
[:div.flex.whitespace-nowrap.items-center.gap-4
|
||||
[:div [:div (:vendor/name vendor)]
|
||||
[:div.text-sm.text-gray-400
|
||||
(or (-> vendor :vendor/legal-entity-name not-empty)
|
||||
(str (-> vendor :vendor/legal-entity-first-name) " "
|
||||
(-> vendor :vendor/legal-entity-middle-name) " "
|
||||
(-> vendor :vendor/legal-entity-last-name)))]]
|
||||
(when-let [t99-type (some-> vendor :vendor/legal-entity-1099-type :db/ident name)]
|
||||
(com/pill
|
||||
{:class "text-xs font-medium"
|
||||
:color :primary}
|
||||
(str/capitalize t99-type))
|
||||
)])}
|
||||
{:key "tin"
|
||||
:name "TIN"
|
||||
:sort-key "tin"
|
||||
:show-starting "md"
|
||||
:render (fn [[_ vendor]]
|
||||
[:div.flex.gap-4
|
||||
(when-let [tin (-> vendor :vendor/legal-entity-tin)]
|
||||
[:span {:class "text-xs font-medium py-0.5 "}
|
||||
tin])
|
||||
(when-let [tin-type (some-> vendor :vendor/legal-entity-tin-type :db/ident name)]
|
||||
(com/pill {:class "text-xs font-medium"
|
||||
:color :yellow}
|
||||
(name tin-type)))]
|
||||
)}
|
||||
{:key "address"
|
||||
:name "Address"
|
||||
:sort-key "address"
|
||||
:show-starting "lg"
|
||||
:render (fn [[_ vendor]]
|
||||
(if (-> vendor :vendor/address :address/street1)
|
||||
[:div
|
||||
[:div (-> vendor :vendor/address :address/street1)] " "
|
||||
[:div
|
||||
(-> vendor :vendor/address :address/street2)] " "
|
||||
[:div
|
||||
(-> vendor :vendor/address :address/city) " "
|
||||
(-> vendor :vendor/address :address/state) ","
|
||||
(-> vendor :vendor/address :address/zip)]]
|
||||
[:p.text-sm.italic.text-gray-400 "No address"]))}
|
||||
{:key "paid"
|
||||
:name "Paid"
|
||||
:sort-key "paid"
|
||||
:render (fn [[_ _ paid]]
|
||||
(com/pill {:class "text-xs font-medium"
|
||||
:color :primary}
|
||||
"Paid $" (Math/round paid)))}]}))
|
||||
|
||||
|
||||
|
||||
@@ -317,5 +273,5 @@
|
||||
"Save")]]]
|
||||
[:div])]]))))
|
||||
|
||||
(def vendor-table (partial helper/table grid-page))
|
||||
(def page (partial helper/page grid-page))
|
||||
(def vendor-table (helper/table-route grid-page))
|
||||
(def page (helper/page-route grid-page))
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
pull-attr
|
||||
pull-many-by-id
|
||||
query2]]
|
||||
[auto-ap.graphql.utils
|
||||
:refer [assert-can-see-client extract-client-ids]]
|
||||
[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]
|
||||
@@ -36,43 +35,36 @@
|
||||
:plaid-account/balance
|
||||
:plaid-account/name]}])
|
||||
|
||||
(defn raw-graphql-ids [db args]
|
||||
(let [valid-clients (extract-client-ids (:clients args)
|
||||
(:client-id args)
|
||||
(when (:client-code args)
|
||||
[:client/code (:client-code args)]))
|
||||
(defn fetch-ids [db request]
|
||||
(let [query-params (:parsed-query-params request)
|
||||
query (cond-> {:query {:find []
|
||||
:in ['$ '[?xx ...]]
|
||||
:where ['[?e :plaid-item/client ?xx]]}
|
||||
:args [db valid-clients]}
|
||||
:args [db (:trimmed-clients request)]}
|
||||
|
||||
(:sort args) (add-sorter-fields {"external-id" ['[?e :plaid-item/external-id ?sort-external-id]]
|
||||
(:sort query-params) (add-sorter-fields {"external-id" ['[?e :plaid-item/external-id ?sort-external-id]]
|
||||
"status" ['[?e :plaid-item/status ?sort-status]]}
|
||||
args)
|
||||
|
||||
(:client-id args)
|
||||
(merge-query {:query {:in '[?client-id]
|
||||
:where ['[?e :plaid-item/client ?client-id]]}
|
||||
:args [(:client-id args)]})
|
||||
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 args)
|
||||
true (apply-pagination args))))
|
||||
true (apply-sort-3 query-params)
|
||||
true (apply-pagination query-params))))
|
||||
|
||||
|
||||
(defn graphql-results [ids db _]
|
||||
(defn hydrate-results [ids db _]
|
||||
(let [results (pull-many-by-id db default-read ids)]
|
||||
(->> ids
|
||||
(map results))))
|
||||
|
||||
(defn get-page [args]
|
||||
(defn fetch-page [request]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
[(graphql-results ids-to-retrieve db args)
|
||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]
|
||||
[(hydrate-results ids-to-retrieve db request)
|
||||
matching-count]))
|
||||
|
||||
|
||||
@@ -138,60 +130,61 @@
|
||||
"Start relink")])))
|
||||
|
||||
|
||||
(def grid-page {:id "plaid-table"
|
||||
:nav (com/company-aside-nav)
|
||||
:id-fn :db/id
|
||||
:fetch-page (fn [user args]
|
||||
(get-page (assoc args :id user)))
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"My Company"]
|
||||
(def grid-page
|
||||
(helper/build
|
||||
{:id "plaid-table"
|
||||
:nav (com/company-aside-nav)
|
||||
:fetch-page fetch-page
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"My Company"]
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company-plaid)}
|
||||
"Plaid"]]
|
||||
:title "Plaid Accounts"
|
||||
:entity-name "Plaid accounts"
|
||||
:route :company-plaid-table
|
||||
:action-buttons (fn [user params]
|
||||
(when-let [client-code (:client/code (:client params))]
|
||||
[[:div {:hx-post (str (bidi/path-for ssr-routes/only-routes
|
||||
:company-plaid-link
|
||||
:request-method :post))
|
||||
:hx-vals (hiccup/raw (format "js:{client_code: \"%s\", public_token: event.detail.public_token}", client-code))
|
||||
:hx-trigger "linked"}
|
||||
[:script (hiccup/raw (plaid-link-script (p/get-link-token client-code)))]
|
||||
(com/button {:color :primary
|
||||
:id "link-account"
|
||||
:onClick "window.plaid.open()"}
|
||||
(com/button-icon {} svg/refresh)
|
||||
"Link new account")]]))
|
||||
:row-buttons (fn [user e]
|
||||
[[:div (com/button {:hx-put (str (bidi/path-for ssr-routes/only-routes
|
||||
:company-plaid-relink)
|
||||
"?plaid-item-id=" (:db/id e))
|
||||
:color :primary
|
||||
:hx-target "closest div"}
|
||||
"Reauthenticate")]])
|
||||
:headers [{:key "plaid-item"
|
||||
:name "Plaid Item"
|
||||
:sort-key "id"
|
||||
:render :db/id}
|
||||
{:key "status"
|
||||
:name "Status"
|
||||
:sort-key "status"
|
||||
:render #(when-let [status (:plaid-item/status %)]
|
||||
[:div [:div (com/pill {:color :primary}
|
||||
status)]
|
||||
[:div (atime/unparse-local (coerce/to-date-time (:plaid-item/last-updated %)) atime/normal-date)]])}
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company-plaid)}
|
||||
"Plaid"]]
|
||||
:title "Plaid Accounts"
|
||||
:entity-name "Plaid accounts"
|
||||
:route :company-plaid-table
|
||||
:action-buttons (fn [request]
|
||||
(when-let [client-code (:client/code (:client request))]
|
||||
[[:div {:hx-post (str (bidi/path-for ssr-routes/only-routes
|
||||
:company-plaid-link
|
||||
:request-method :post))
|
||||
:hx-vals (hiccup/raw (format "js:{client_code: \"%s\", public_token: event.detail.public_token}", client-code))
|
||||
:hx-trigger "linked"}
|
||||
[:script (hiccup/raw (plaid-link-script (p/get-link-token client-code)))]
|
||||
(com/button {:color :primary
|
||||
:id "link-account"
|
||||
:onClick "window.plaid.open()"}
|
||||
(com/button-icon {} svg/refresh)
|
||||
(format "Link %s account" client-code))]]))
|
||||
:row-buttons (fn [request e]
|
||||
[[:div (com/button {:hx-put (str (bidi/path-for ssr-routes/only-routes
|
||||
:company-plaid-relink)
|
||||
"?plaid-item-id=" (:db/id e))
|
||||
:color :primary
|
||||
:hx-target "closest div"}
|
||||
"Reauthenticate")]])
|
||||
:headers [{:key "plaid-item"
|
||||
:name "Plaid Item"
|
||||
:sort-key "external-id"
|
||||
:render :plaid-item/external-id}
|
||||
{:key "status"
|
||||
:name "Status"
|
||||
:sort-key "status"
|
||||
:render #(when-let [status (:plaid-item/status %)]
|
||||
[:div [:div (com/pill {:color :primary}
|
||||
status)]
|
||||
[:div (atime/unparse-local (coerce/to-date-time (:plaid-item/last-updated %)) atime/normal-date)]])}
|
||||
|
||||
{:key "accounts"
|
||||
:name "Accounts"
|
||||
:show-starting "md"
|
||||
:render (fn [e]
|
||||
[:ul
|
||||
(for [a (:plaid-item/accounts e)]
|
||||
[:li (:plaid-account/name a) " - " (:plaid-account/number a)])])}]})
|
||||
{:key "accounts"
|
||||
:name "Accounts"
|
||||
:show-starting "md"
|
||||
:render (fn [e]
|
||||
[:ul
|
||||
(for [a (:plaid-item/accounts e)]
|
||||
[:li (:plaid-account/name a) " - " (:plaid-account/number a)])])}]}))
|
||||
|
||||
(def page (partial helper/page grid-page))
|
||||
(def table (partial helper/table grid-page))
|
||||
|
||||
(def page (helper/page-route grid-page))
|
||||
(def table (helper/table-route grid-page))
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
(ns auto-ap.ssr.company.reports
|
||||
(:require
|
||||
[amazonica.aws.s3 :as s3]
|
||||
[auto-ap.datomic :refer [conn]]
|
||||
[auto-ap.datomic
|
||||
:refer [add-sorter-fields
|
||||
apply-pagination
|
||||
apply-sort-3
|
||||
conn
|
||||
merge-query
|
||||
pull-many
|
||||
query2]]
|
||||
[auto-ap.datomic.reports :as r]
|
||||
[auto-ap.graphql.utils :refer [assert-can-see-client is-admin?]]
|
||||
[auto-ap.ssr-routes :as ssr-routes]
|
||||
@@ -11,57 +18,101 @@
|
||||
[auto-ap.ssr.utils :refer [html-response]]
|
||||
[auto-ap.time :as atime]
|
||||
[bidi.bidi :as bidi]
|
||||
[clojure.set :as set]
|
||||
[config.core :refer [env]]
|
||||
[datomic.api :as dc]
|
||||
[com.brunobonacci.mulog :as mu]))
|
||||
[datomic.api :as dc]))
|
||||
|
||||
(def grid-page {:id "report-table"
|
||||
:nav (com/company-aside-nav)
|
||||
:id-fn :db/id
|
||||
:fetch-page (fn [user args]
|
||||
(r/get-graphql (into args {:id user})))
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"My Company"]
|
||||
(def default-read '[:db/id :report/client [:report/created :xform clj-time.coerce/from-date] :report/url :report/name :report/creator])
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company-reports)}
|
||||
"Reports"]]
|
||||
:title "Reports"
|
||||
:entity-name "Reports"
|
||||
:route :company-reports-table
|
||||
:action-buttons (fn [user _]
|
||||
nil)
|
||||
:row-buttons (fn [user e]
|
||||
(com/a-icon-button {:href (:report/url e)}
|
||||
svg/download)[
|
||||
(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 "name"
|
||||
:name "Name"
|
||||
:sort-key "name"
|
||||
:render :report/name}
|
||||
{:key "created-by"
|
||||
:name "Created by"
|
||||
:sort-key "creator"
|
||||
:render (fn [report]
|
||||
(when (:report/creator report)
|
||||
(com/pill {:color :primary }
|
||||
(:report/creator report))))}
|
||||
{:key "created"
|
||||
:name "Created"
|
||||
:sort-key "created"
|
||||
:render #(atime/unparse-local (:report/created %)
|
||||
atime/normal-date)}]})
|
||||
(defn fetch-ids [db request]
|
||||
|
||||
(let [query-params (:parsed-query-params request)
|
||||
query (cond-> {:query {:find []
|
||||
:in '[$ [?c ...]]
|
||||
:where '[[?e :report/client ?c]]}
|
||||
:args [db (:trimmed-clients request)]}
|
||||
|
||||
|
||||
(:sort query-params) (add-sorter-fields {"client" ['[?e :report/client ?c]
|
||||
'[?c :client/name ?sort-client]]
|
||||
"created" ['[?e :report/created ?sort-created]]
|
||||
"creator" ['[?e :report/creator ?sort-creator]]
|
||||
"name" ['[?e :report/name ?sort-name]
|
||||
]}
|
||||
query-params)
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e] :where ['[?e :report/created ?sort-default]]}}))]
|
||||
(->> (query2 query)
|
||||
(apply-sort-3 (update query-params :sort conj {:sort-key "default-2" :asc true}))
|
||||
(apply-pagination query-params))))
|
||||
|
||||
(defn hydrate-results [ids db request]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
valid-clients (:trimmed-clients request)]
|
||||
(->> ids
|
||||
(map results)
|
||||
(filter identity)
|
||||
|
||||
(map first)
|
||||
(filter (fn [r]
|
||||
(let [used-clients (set (map :db/id (:report/client r)))]
|
||||
(= used-clients
|
||||
(set/intersection valid-clients
|
||||
used-clients))))))))
|
||||
|
||||
(defn fetch-page [args]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db args)]
|
||||
|
||||
[(->> (hydrate-results ids-to-retrieve db args))
|
||||
matching-count]))
|
||||
|
||||
(def grid-page
|
||||
(helper/build {:id "report-table"
|
||||
:nav (com/company-aside-nav)
|
||||
:fetch-page fetch-page
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"My Company"]
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company-reports)}
|
||||
"Reports"]]
|
||||
:title "Reports"
|
||||
:entity-name "Reports"
|
||||
:route :company-reports-table
|
||||
:row-buttons (fn [request e]
|
||||
[(com/a-icon-button {:href (:report/url e)}
|
||||
svg/download)
|
||||
(when (is-admin? (:identity request))
|
||||
(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 "name"
|
||||
:name "Name"
|
||||
:sort-key "name"
|
||||
:render :report/name}
|
||||
{:key "created-by"
|
||||
:name "Created by"
|
||||
:sort-key "creator"
|
||||
:render (fn [report]
|
||||
(when (:report/creator report)
|
||||
(com/pill {:color :primary }
|
||||
(:report/creator report))))}
|
||||
{:key "created"
|
||||
:name "Created"
|
||||
:sort-key "created"
|
||||
:render #(atime/unparse-local (:report/created %)
|
||||
atime/normal-date)}]}))
|
||||
|
||||
(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))
|
||||
(def table (helper/table-route grid-page))
|
||||
(def page (helper/page-route grid-page))
|
||||
|
||||
(defn delete-report [{:keys [form-params identity]}]
|
||||
|
||||
@@ -70,7 +121,7 @@
|
||||
: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)]
|
||||
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)
|
||||
|
||||
@@ -1,32 +1,73 @@
|
||||
(ns auto-ap.ssr.company.yodlee
|
||||
(:require
|
||||
[auto-ap.datomic :refer [conn]]
|
||||
[auto-ap.datomic.yodlee2 :as yodlee2]
|
||||
[auto-ap.graphql.utils :refer [is-admin?]]
|
||||
[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.svg :as svg]
|
||||
[auto-ap.ssr.ui :refer [base-page]]
|
||||
[auto-ap.ssr.grid-page-helper :as helper]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[auto-ap.ssr.utils :refer [html-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.datomic :refer [pull-attr]]))
|
||||
[hiccup2.core :as hiccup]))
|
||||
|
||||
(def default-read '[:db/id
|
||||
:yodlee-provider-account/last-updated
|
||||
[:yodlee-provider-account/last-updated :xform clj-time.coerce/from-date]
|
||||
:yodlee-provider-account/status
|
||||
:yodlee-provider-account/id
|
||||
:yodlee-provider-account/detailed-status
|
||||
{:yodlee-provider-account/accounts [:yodlee-account/name :yodlee-account/number]
|
||||
:yodlee-provider-account/client [:client/code]}])
|
||||
:yodlee-provider-account/client [:client/code]}])
|
||||
|
||||
|
||||
|
||||
(defn fetch-ids [db request]
|
||||
(let [query-params (:parsed-query-params request)]
|
||||
(->> (cond-> {:query {:find []
|
||||
:in ['$ '[?xx ...]]
|
||||
:where ['[?e :yodlee-provider-account/id]
|
||||
'[?e :yodlee-provider-account/client ?xx]]}
|
||||
:args [db (:trimmed-clients request)]}
|
||||
|
||||
|
||||
(: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]]}
|
||||
query-params)
|
||||
true
|
||||
(merge-query {:query {:find ['?e ]
|
||||
:where ['[?e :yodlee-provider-account/id]]}}))
|
||||
|
||||
(query2)
|
||||
(apply-sort-3 query-params)
|
||||
(apply-pagination query-params))))
|
||||
|
||||
|
||||
(defn hydrate-results [ids db _]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))]
|
||||
(->> ids
|
||||
(map results)
|
||||
(map first))))
|
||||
|
||||
|
||||
(defn fetch-page [request]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]
|
||||
[(->> (hydrate-results ids-to-retrieve db request))
|
||||
matching-count]))
|
||||
|
||||
|
||||
(defn fastlink-dialog [{:keys [client]}]
|
||||
(html-response
|
||||
(com/modal
|
||||
@@ -53,7 +94,10 @@ fastlink.open({fastLinkURL: '%s',
|
||||
]
|
||||
[:div]))))
|
||||
|
||||
(defn reauthenticate [{:keys [form-params]}]
|
||||
(defn reauthenticate [{:keys [form-params identity]}]
|
||||
(assert-can-see-client identity (-> (dc/pull (dc/db conn) '[{:yodlee-provider-account/client [:db/id]}] (Long/parseLong (get form-params "id")))
|
||||
:yodlee-provider-account/client
|
||||
:db/id))
|
||||
(html-response
|
||||
(com/modal
|
||||
{}
|
||||
@@ -82,27 +126,27 @@ fastlink.open({fastLinkURL: '%s',
|
||||
(pull-attr (dc/db conn) :yodlee-provider-account/id (Long/parseLong (get form-params "id")))))]]
|
||||
[:div]))))
|
||||
|
||||
(def grid-page {:id "yodlee-table"
|
||||
:nav (com/company-aside-nav)
|
||||
:id-fn :db/id
|
||||
:fetch-page (fn [user args]
|
||||
(yodlee2/get-graphql (assoc args :id user)))
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"My Company"]
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company-yodlee)}
|
||||
"Yodlee"]]
|
||||
:title "Yodlee Accounts"
|
||||
:entity-name "Yodlee accounts"
|
||||
:route :company-yodlee-table
|
||||
:action-buttons (fn [user args]
|
||||
[[:div.flex.flex-col.flex-shrink
|
||||
(def grid-page
|
||||
(helper/build
|
||||
{:id "yodlee-table"
|
||||
:nav (com/company-aside-nav)
|
||||
:id-fn :db/id
|
||||
:fetch-page fetch-page
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"My Company"]
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company-yodlee)}
|
||||
"Yodlee"]]
|
||||
:title "Yodlee Accounts"
|
||||
:entity-name "Yodlee accounts"
|
||||
:route :company-yodlee-table
|
||||
:action-buttons (fn [request]
|
||||
[[:div.flex.flex-col.flex-shrink
|
||||
[:div.flex-shrink
|
||||
(com/button {:color :primary
|
||||
:on-click "openFastlink()"
|
||||
:disabled (if (:client args)
|
||||
:disabled (if (:client request)
|
||||
false
|
||||
true)
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
@@ -110,53 +154,59 @@ fastlink.open({fastLinkURL: '%s',
|
||||
:hx-target "#modal-holder"}
|
||||
(com/button-icon {} svg/refresh)
|
||||
"Link new account")]
|
||||
(when-not (:client args)
|
||||
(when-not (:client request)
|
||||
[:div.text-xs "Note: please select a specific customer to link a new account."])]])
|
||||
:row-buttons (fn [user e]
|
||||
[
|
||||
(com/button {:hx-put (bidi/path-for ssr-routes/only-routes
|
||||
:company-yodlee-provider-account-reauthenticate)
|
||||
:color :primary
|
||||
:hx-target "#modal-holder"}
|
||||
"Reauthenticate")
|
||||
(when (is-admin? user)
|
||||
(com/icon-button {:hx-put (bidi/path-for ssr-routes/only-routes
|
||||
:company-yodlee-provider-account-refresh)
|
||||
:hx-target "closest tr"}
|
||||
svg/refresh))])
|
||||
:headers [{:key "provider-account"
|
||||
:name "Provider Account"
|
||||
:sort-key "provider-account"
|
||||
:render :yodlee-provider-account/id}
|
||||
{:key "status"
|
||||
:name "Status"
|
||||
:sort-key "status"
|
||||
:render #(when-let [status (:yodlee-provider-account/status %)]
|
||||
(com/pill {:color (if (not= status "SUCCESS")
|
||||
:yellow
|
||||
:primary) }
|
||||
status))}
|
||||
{:key "detailed-status"
|
||||
:name "Detailed Status"
|
||||
:sort-key "detailed-status"
|
||||
:render #(when-let [status (:yodlee-provider-account/detailed-status %)]
|
||||
status)}
|
||||
:row-buttons (fn [request _]
|
||||
[
|
||||
(com/button {:hx-put (bidi/path-for ssr-routes/only-routes
|
||||
:company-yodlee-provider-account-reauthenticate)
|
||||
:color :primary
|
||||
:hx-target "#modal-holder"}
|
||||
"Reauthenticate")
|
||||
(when (is-admin? (:identity request))
|
||||
(com/icon-button {:hx-put (bidi/path-for ssr-routes/only-routes
|
||||
:company-yodlee-provider-account-refresh)
|
||||
:hx-target "closest tr"}
|
||||
svg/refresh))])
|
||||
:headers [{:key "client"
|
||||
:name "Client"
|
||||
:sort-key "client"
|
||||
:hide? (fn [args]
|
||||
(= (count (:clients args)) 1))
|
||||
:render #(-> % :yodlee-provider-account/client :client/code)}
|
||||
{:key "provider-account"
|
||||
:name "Provider Account"
|
||||
:sort-key "provider-account"
|
||||
:render :yodlee-provider-account/id}
|
||||
{:key "status"
|
||||
:name "Status"
|
||||
:sort-key "status"
|
||||
:render #(when-let [status (:yodlee-provider-account/status %)]
|
||||
(com/pill {:color (if (not= status "SUCCESS")
|
||||
:yellow
|
||||
:primary) }
|
||||
status))}
|
||||
{:key "detailed-status"
|
||||
:name "Detailed Status"
|
||||
:sort-key "detailed-status"
|
||||
:render #(when-let [status (:yodlee-provider-account/detailed-status %)]
|
||||
status)}
|
||||
|
||||
{:key "last-updated"
|
||||
:name "Last Updated"
|
||||
:sort-key "last-updated"
|
||||
:render #(atime/unparse-local (:yodlee-provider-account/last-updated %)
|
||||
atime/normal-date)}
|
||||
{:key "accounts"
|
||||
:name "Accounts"
|
||||
:show-starting "md"
|
||||
:render (fn [e]
|
||||
[:ul
|
||||
(for [a (:yodlee-provider-account/accounts e)]
|
||||
[:li (:yodlee-account/name a) " - " (:yodlee-account/number a)])])}]})
|
||||
{:key "last-updated"
|
||||
:name "Last Updated"
|
||||
:sort-key "last-updated"
|
||||
:render #(atime/unparse-local (:yodlee-provider-account/last-updated %)
|
||||
atime/normal-date)}
|
||||
{:key "accounts"
|
||||
:name "Accounts"
|
||||
:show-starting "md"
|
||||
:render (fn [e]
|
||||
[:ul
|
||||
(for [a (:yodlee-provider-account/accounts e)]
|
||||
[:li (:yodlee-account/name a) " - " (:yodlee-account/number a)])])}]}))
|
||||
|
||||
(def page (partial helper/page grid-page))
|
||||
(def table (partial helper/table grid-page))
|
||||
(def page (helper/page-route grid-page))
|
||||
(def table (helper/table-route grid-page))
|
||||
|
||||
;; TODO delete-after-settle
|
||||
(defn refresh-provider-account [{:keys [form-params identity]}]
|
||||
|
||||
@@ -9,14 +9,18 @@
|
||||
[auto-ap.ssr.components.page :as page]
|
||||
[auto-ap.ssr.components.data-grid :as data-grid]
|
||||
[auto-ap.ssr.components.tags :as tags]
|
||||
[auto-ap.ssr.components.paginator :as paginator]))
|
||||
[auto-ap.ssr.components.paginator :as paginator]
|
||||
[auto-ap.ssr.components.radio :as radio]))
|
||||
|
||||
|
||||
(def breadcrumbs breadcrumbs/breadcrumbs-)
|
||||
(def button buttons/button-)
|
||||
(def a-button buttons/a-button-)
|
||||
(def button-icon buttons/button-icon-)
|
||||
(def icon-button buttons/icon-button-)
|
||||
(def a-icon-button buttons/a-icon-button-)
|
||||
(def button-group buttons/group-)
|
||||
(def button-group-button buttons/group-button-)
|
||||
(def modal dialog/modal-)
|
||||
(def modal-card dialog/modal-card-)
|
||||
|
||||
@@ -36,6 +40,7 @@
|
||||
(def navbar navbar/navbar-)
|
||||
|
||||
(def page page/page-)
|
||||
(def radio radio/radio-)
|
||||
|
||||
(def pill tags/pill-)
|
||||
(def badge tags/badge-)
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
[:a (-> params
|
||||
(dissoc :icon)
|
||||
(assoc :type "button")
|
||||
(update :class str " cursor-pointer flex items-center p-2 w-full text-sm text-gray-600 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")
|
||||
(update :class str " cursor-pointer flex items-center p-2 w-full text-xs text-gray-600 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")
|
||||
(assoc :hx-indicator "find .htmx-indicator")
|
||||
(assoc :hx-boost "true")
|
||||
(assoc :hx-select "#app-contents")
|
||||
(assoc :hx-target "#app-contents")
|
||||
(assoc :hx-swap "outerHTML"))
|
||||
@@ -28,7 +29,7 @@
|
||||
(svg/spinner-primary {:class "inline w-4 h-4 text-white"})]]])
|
||||
|
||||
(defn sub-menu- [params & children]
|
||||
[:ul {:id (:id params) :class "hidden py-2 space-y-2"}
|
||||
[:ul {:id (:id params) :class "hidden py-2 space-y-1.5"}
|
||||
(for [c children]
|
||||
[:li
|
||||
(update-in c [1 1 :class ] str " flex items-center p-2 pl-11 w-full text-base font-normal text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")])])
|
||||
@@ -148,7 +149,7 @@
|
||||
")]])
|
||||
|
||||
(defn main-aside-nav- []
|
||||
[:ul {:class "space-y-2"}
|
||||
[:ul {:class "space-y-1"}
|
||||
|
||||
[:li
|
||||
(menu-button- {:icon svg/pie
|
||||
@@ -178,10 +179,22 @@
|
||||
:icon svg/receipt-register-1}
|
||||
"Sales")
|
||||
(sub-menu- {:id "dropdown-sales"}
|
||||
(menu-button- {:href (bidi/path-for client-routes/routes
|
||||
:sales-orders)} "Sales")
|
||||
(menu-button- {:href (bidi/path-for client-routes/routes
|
||||
:expected-deposits)} "Expected Deposits")
|
||||
(menu-button- {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
:pos-sales)
|
||||
"?date-range=week")} "Sales")
|
||||
(menu-button- {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
:pos-expected-deposits)
|
||||
"?date-range=week")} "Expected Deposits")
|
||||
(menu-button- {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
:pos-tenders)
|
||||
"?date-range=week")} "Tenders")
|
||||
|
||||
(menu-button- {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
:pos-refunds)
|
||||
"?date-range=week")} "Refunds")
|
||||
(menu-button- {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
:pos-cash-drawer-shifts)
|
||||
"?date-range=week")} "Cash drawer shifts")
|
||||
#_(menu-button- {:href "Sales"} "Cash Shifts")
|
||||
#_(menu-button- {:href "Sales"} "Tenders"))]
|
||||
[:li
|
||||
|
||||
@@ -96,7 +96,20 @@
|
||||
(svg/spinner {:class "inline w-4 h-4 text-white"})
|
||||
[:div.ml-3 "Loading..."]]
|
||||
(into [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center] children)])
|
||||
;; => #'auto-ap.ssr.components.buttons/button-;; => #'auto-ap.ssr.components.buttons/button-
|
||||
|
||||
(defn a-button- [params & children]
|
||||
[:a (update params
|
||||
:class #(cond-> %
|
||||
true (str " focus:ring-4 font-bold rounded-lg text-xs p-3 text-center mr-2 inline-flex items-center hover:scale-105 transition duration-100 justify-center")
|
||||
(= :secondary (:color params)) (str " text-white bg-blue-500 hover:bg-blue-600 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700")
|
||||
(= :primary (:color params)) (str " text-white bg-green-500 hover:bg-green-600 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 ")
|
||||
(nil? (:color params))
|
||||
(str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700")))
|
||||
[:div.htmx-indicator.flex.items-center
|
||||
(svg/spinner {:class "inline w-4 h-4 text-white"})
|
||||
[:div.ml-3 "Loading..."]]
|
||||
(into [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center] children)])
|
||||
|
||||
(defn icon-button- [params & children]
|
||||
(into
|
||||
[:button
|
||||
@@ -126,3 +139,31 @@
|
||||
(svg/spinner {:class "inline w-4 h-4 text-white"})
|
||||
[:div.ml-3 "Loading..."]]
|
||||
(into [:div.htmx-indicator-hidden ] children)])
|
||||
|
||||
|
||||
|
||||
(defn group-button- [{:keys [size] :or {size :normal} :as params} & children]
|
||||
(into [:button (cond-> params
|
||||
true (assoc :type (or (:type params) "button"))
|
||||
true (update :class (fn [c]
|
||||
(cond-> c
|
||||
true (str " font-medium text-gray-900 bg-white border border-gray-200 hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:ring-2 focus:ring-green-700 focus:text-green-700 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-green-500 dark:focus:text-white")
|
||||
|
||||
(= :small size)
|
||||
(str " text-xs px-3 py-2")
|
||||
|
||||
(= :normal size)
|
||||
(str " text-sm px-4 py-2")
|
||||
)
|
||||
))
|
||||
true (dissoc :size))] children ))
|
||||
|
||||
(defn group- [{:keys [name]} & children]
|
||||
(let [children (-> children
|
||||
vec
|
||||
(update-in [0 1 :class] str " rounded-l-lg")
|
||||
(update-in [(dec (count children)) 1 :class] str " rounded-r-lg"))]
|
||||
(into [:div {:class "inline-flex rounded-md shadow-sm", :role "group"
|
||||
:hx-on:click "this.querySelector(\"input\").value = event.target.value; this.querySelector(\"input\").dispatchEvent(new Event('change', {bubbles: true}));"}
|
||||
[:input {:type "hidden" :name name}]]
|
||||
children)))
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
:hx-trigger "clientSelected from:body"
|
||||
:hx-swap "outerHTML swap:300ms"
|
||||
:id id}
|
||||
|
||||
(content-card-
|
||||
{}
|
||||
[:div {:class "flex flex-col px-4 py-3 space-y-3 lg:flex-row lg:items-center lg:justify-between lg:space-y-0 lg:space-x-4 text-gray-800 dark:text-gray-100"}
|
||||
@@ -97,4 +98,8 @@
|
||||
:request-method :get)
|
||||
"?start=" (* page per-page))
|
||||
:hx-target (str "#" id)
|
||||
:hx-swap "outerHTML show:#app:top"})})))])
|
||||
:hx-swap "outerHTML show:#app:top"
|
||||
:hx-indicator (str "#" id)})}))
|
||||
[:div {:class "htmx-indicator absolute -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2 overflow-hidden w-full h-full"}
|
||||
[:div {:class "flex items-center justify-center w-full h-full border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700 bg-opacity-50" }
|
||||
[:div {:class "px-3 py-1 text-xs font-medium leading-none text-center text-blue-800 bg-blue-200 rounded-full animate-pulse dark:bg-blue-900 dark:text-blue-200"} "loading..."]]])])
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
(ns auto-ap.ssr.components.inputs)
|
||||
(ns auto-ap.ssr.components.inputs
|
||||
(:require [hiccup2.core :as hiccup]))
|
||||
|
||||
(defn select- [params & children]
|
||||
(into
|
||||
@@ -11,28 +12,43 @@
|
||||
(:allow-blank? params) (conj [:option {:value "" :selected (not (:value params))} ""]))]
|
||||
children))
|
||||
|
||||
(defn text-input- [params]
|
||||
(defn use-size [size]
|
||||
(if (= :small size)
|
||||
(str " " "text-xs p-2")
|
||||
(str " " "text-sm p-2.25")))
|
||||
(defn text-input- [{:keys [size] :as params}]
|
||||
[:input
|
||||
(update params
|
||||
:class str " bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500")
|
||||
(-> params
|
||||
(update
|
||||
:class str " bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500")
|
||||
(update :class #(str % (use-size size)))
|
||||
)
|
||||
])
|
||||
|
||||
(defn money-input- [params]
|
||||
(defn money-input- [{:keys [size] :as params}]
|
||||
[:input
|
||||
(-> params
|
||||
(update
|
||||
:class str " bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 text-right"
|
||||
:class str " bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 text-right appearance-none"
|
||||
)
|
||||
(update :class #(str % (use-size size)))
|
||||
(assoc :type "number"
|
||||
:step "0.01"))
|
||||
:step "0.01")
|
||||
(dissoc :size))
|
||||
])
|
||||
|
||||
(defn date-input- [params]
|
||||
[:input
|
||||
(-> params
|
||||
(update
|
||||
:class str " bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500")
|
||||
(assoc :type "date"))])
|
||||
(defn date-input- [{:keys [size] :as params}]
|
||||
[:div
|
||||
[:input
|
||||
(-> params
|
||||
(update
|
||||
:class str " bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500")
|
||||
(assoc :type "text")
|
||||
(assoc "_" (hiccup/raw "init initDatepicker(me)"))
|
||||
(assoc "hx-on" (hiccup/raw "changeDate: htmx.trigger(this, \"change\")
|
||||
htmx:beforeCleanupElement: this.dp.destroy()"))
|
||||
(update :class #(str % (use-size size)))
|
||||
(dissoc :size))]])
|
||||
|
||||
(defn field- [params & rest]
|
||||
(into
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
[auto-ap.ssr.svg :as svg]))
|
||||
|
||||
(defn page- [{:keys [nav page-specific client client-selection identity app-params] :or {app-params {}}} & children]
|
||||
[:div#app
|
||||
[:div#app {"_" (hiccup/raw "
|
||||
on notification put event.detail.value into #notification-details then add .htmx-added to #notification-holder then remove .hidden from #notification-holder then wait 30ms then remove .htmx-added from #notification-holder
|
||||
on htmx:responseError put event.detail.xhr.response into #error-details then add .htmx-added to #error-holder then remove .hidden from #error-holder then wait 30ms then remove .htmx-added from #error-holder"
|
||||
)}
|
||||
(navbar- {:client-selection client-selection
|
||||
:client client
|
||||
:identity identity})
|
||||
@@ -14,10 +17,7 @@
|
||||
(left-aside- {:nav nav
|
||||
:page-specific page-specific})
|
||||
[:div#main-content {:class "relative w-full h-full lg:pl-64 overflow-y-auto px-4 bg-gray-100 dark:bg-gray-900 min-h-content "
|
||||
"_" (hiccup/raw "
|
||||
on notification put event.detail.value into #notification-details then add .htmx-added to #notification-holder then remove .hidden from #notification-holder then wait 30ms then remove .htmx-added from #notification-holder
|
||||
on htmx:responseError put event.detail.xhr.response into #error-details then add .htmx-added to #error-holder then remove .hidden from #error-holder then wait 30ms then remove .htmx-added from #error-holder"
|
||||
)}
|
||||
}
|
||||
[:div#notification-holder.hidden
|
||||
[:div.fixed.top-0.right-0.left-0.z-30.mx-auto.max-w-screen-lg.w-screen-lg.my-0.pt-8.rounded-lg
|
||||
[:div.relative
|
||||
|
||||
@@ -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)))
|
||||
|
||||
27
src/clj/auto_ap/ssr/components/radio.clj
Normal file
27
src/clj/auto_ap/ssr/components/radio.clj
Normal file
@@ -0,0 +1,27 @@
|
||||
(ns auto-ap.ssr.components.radio)
|
||||
|
||||
(defn radio- [{:keys [options name title size] :or {size :medium}}]
|
||||
[:h3 {:class "mb-4 font-semibold text-gray-900 dark:text-white"} title]
|
||||
[:ul {:class "w-48 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white"}
|
||||
(for [{:keys [value content]} options]
|
||||
[:li {:class "w-full border-b border-gray-200 rounded-t-lg dark:border-gray-600"}
|
||||
[:div {:class "flex items-center pl-3"}
|
||||
[:input {:id (str "list-" name "-" value)
|
||||
:type "radio",
|
||||
:value value
|
||||
:name name
|
||||
:class
|
||||
(cond-> "w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-700 dark:focus:ring-offset-gray-700 focus:ring-2 dark:bg-gray-600 dark:border-gray-500"
|
||||
(= size :small)
|
||||
(str " " "text-xs")
|
||||
|
||||
(= size :medium)
|
||||
(str " " "text-sm"))}]
|
||||
[:label {:for (str "list-" name "-" value)
|
||||
:class
|
||||
(cond-> "w-full ml-2 font-medium text-gray-900 dark:text-gray-300"
|
||||
(= size :small)
|
||||
(str " " "text-xs py-2")
|
||||
|
||||
(= size :medium)
|
||||
(str " " "text-sm py-3"))} content]]])])
|
||||
@@ -12,47 +12,59 @@
|
||||
[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.ssr.pos.refunds :as pos-refunds]
|
||||
[auto-ap.ssr.pos.expected-deposits :as pos-expected-deposits]
|
||||
[auto-ap.ssr.pos.cash-drawer-shifts :as pos-cash-drawer-shifts]
|
||||
[auto-ap.ssr.pos.tenders :as pos-tenders]
|
||||
[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
|
||||
(-> {:logout auth/logout
|
||||
:impersonate (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin auth/impersonate)))
|
||||
: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-secure 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))}
|
||||
(into pos-sales/key->handler)
|
||||
(into pos-expected-deposits/key->handler)
|
||||
(into pos-tenders/key->handler)
|
||||
(into pos-cash-drawer-shifts/key->handler)
|
||||
(into pos-refunds/key->handler)))
|
||||
|
||||
|
||||
@@ -1,28 +1,39 @@
|
||||
(ns auto-ap.ssr.grid-page-helper
|
||||
(:require
|
||||
[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.ssr-routes :as ssr-routes]
|
||||
[auto-ap.ssr.components :as com]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[auto-ap.ssr.ui :refer [base-page]]
|
||||
[auto-ap.ssr.utils :refer [html-response]]
|
||||
[hiccup2.core :as hiccup]
|
||||
[auto-ap.time :as atime]
|
||||
[malli.core :as m]
|
||||
[bidi.bidi :as bidi]
|
||||
[auto-ap.ssr-routes :as ssr-routes]
|
||||
[cemerick.url :as url]
|
||||
[clojure.string :as str]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[unilog.context :as lc]
|
||||
[com.brunobonacci.mulog :as mu]))
|
||||
[hiccup2.core :as hiccup]
|
||||
[malli.transform :as mt2]))
|
||||
|
||||
(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? request] :as options}]
|
||||
(let [cells (->> gridspec
|
||||
:headers
|
||||
(filter (fn [h]
|
||||
(if (and (:hide? h)
|
||||
((:hide? h) request))
|
||||
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)}]]
|
||||
((:row-buttons gridspec) user entity))))]
|
||||
((:row-buttons gridspec) request entity))))] ;; TODO double check usage of row buttons user and identity in callers
|
||||
(apply com/data-grid-row
|
||||
{:class (when flash?
|
||||
"live-added")
|
||||
@@ -38,154 +49,241 @@
|
||||
first
|
||||
:sort-icon))
|
||||
|
||||
(defn sort-by-list [sort]
|
||||
(defn sort-by-list [grid-spec sort]
|
||||
(if (seq sort)
|
||||
(into
|
||||
[:div.flex.gap-2.items-center
|
||||
|
||||
"sorted by"
|
||||
|
||||
]
|
||||
(for [{:keys [name sort-icon ]} sort]
|
||||
(for [{:keys [name sort-icon sort-key ]} sort]
|
||||
[:div.py-1.px-3.text-sm.rounded.bg-gray-100.dark:bg-gray-600.flex.items-center.gap-2.relative name [:div.h-4.w-4.mr-3 sort-icon]
|
||||
[:div {:class "absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white hover:scale-110 transition-all duration-300 bg-gray-400 border-2 border-white rounded-full -top-2 -right-2 dark:border-gray-900"}
|
||||
[:div.h-4.w-4 svg/x]
|
||||
[:a {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
(:route grid-spec)) "?remove-sort=" sort-key)
|
||||
:hx-boost "true"
|
||||
:hx-target (str "#" (:id grid-spec))
|
||||
|
||||
}
|
||||
[:div.h-4.w-4 svg/x]]
|
||||
]]
|
||||
))
|
||||
"default sort"))
|
||||
|
||||
(defn table* [grid-spec user {:keys [start per-page clients flash-id sort] :as params}]
|
||||
(defn table* [grid-spec user {{:keys [start per-page flash-id sort]} :parsed-query-params :as request}]
|
||||
(let [start (or start 0)
|
||||
per-page (or per-page 30)
|
||||
[entities total] ((:fetch-page grid-spec)
|
||||
user
|
||||
{:start start
|
||||
:per-page per-page
|
||||
:clients clients
|
||||
:sort sort})]
|
||||
request)]
|
||||
|
||||
(com/data-grid-card {:id (:id grid-spec)
|
||||
:title (:title grid-spec)
|
||||
:route (:route grid-spec)
|
||||
:start start
|
||||
:per-page per-page
|
||||
:total total
|
||||
:subtitle [:div.flex.items-center.gap-2
|
||||
[:span (format "Total %s: %d, " (:entity-name grid-spec) total)]
|
||||
(sort-by-list sort)]
|
||||
:action-buttons ((:action-buttons grid-spec) user params)
|
||||
:subtitle [:div.flex.items-center.gap-2
|
||||
[:span (format "Total %s: %d, " (:entity-name grid-spec) total)]
|
||||
(sort-by-list grid-spec sort)]
|
||||
:action-buttons ((:action-buttons grid-spec) request)
|
||||
: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)) :request request}))
|
||||
:thead-params {:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
(:route grid-spec))
|
||||
:hx-target (str "#" (:id grid-spec))
|
||||
:hx-indicator (str "#" (:id grid-spec))
|
||||
:hx-trigger "sorted once"
|
||||
: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) request))
|
||||
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 {}))})))
|
||||
|
||||
|
||||
|
||||
(defn parse-sort [grid-spec q]
|
||||
(if (not-empty q)
|
||||
(into []
|
||||
(map (fn [k]
|
||||
(let [[k v] (str/split k #":")]
|
||||
{:sort-key (str k)
|
||||
:asc (boolean (= "asc" v))
|
||||
:name (:name (first (filter #(= (str k) (:sort-key %)) (:headers grid-spec))))
|
||||
:sort-icon (if (= (boolean (= "asc" v)) true)
|
||||
svg/sort-down
|
||||
svg/sort-up)}))
|
||||
(str/split q #",")))
|
||||
[]))
|
||||
|
||||
(defn toggle-sort [grid-spec q k]
|
||||
(if ((set (map :sort-key q)) k)
|
||||
(mapv
|
||||
(fn [s]
|
||||
(if (= (:sort-key s)
|
||||
k)
|
||||
(-> s
|
||||
(update :asc
|
||||
#(boolean (not %)))
|
||||
(update :sort-icon (fn [x]
|
||||
(if (= x svg/sort-down)
|
||||
svg/sort-up
|
||||
svg/sort-down))))
|
||||
s))
|
||||
q)
|
||||
(conj q {:sort-key k
|
||||
:asc true
|
||||
:name (:name (first (filter #(= (str k) (:sort-key %)) (:headers grid-spec))))
|
||||
:sort-icon svg/sort-down})))
|
||||
|
||||
(defn sort->query [s]
|
||||
(str/join "," (map (fn [k] (format "%s:%s" (:sort-key k) (if (= true (:asc k))
|
||||
"asc"
|
||||
"desc")))
|
||||
s)))
|
||||
|
||||
(defn params->query-string [q]
|
||||
(-> q
|
||||
(dissoc :client :session)
|
||||
(update :sort sort->query)
|
||||
(url/map->query)))
|
||||
(defn default-unparse-query-params [query-params]
|
||||
(reduce
|
||||
(fn [query-params [k value]]
|
||||
(assoc query-params k
|
||||
(cond (= k :sort)
|
||||
(sort->query value)
|
||||
|
||||
(defn extract-params [grid-spec {:keys [query-params hx-query-params identity session] :as request}]
|
||||
(let [{hx-start "start" hx-per-page "per-page" hx-sort "sort" } hx-query-params
|
||||
{q-start "start" q-per-page "per-page" q-sort "sort" q-toggle-sort "toggle-sort"} query-params]
|
||||
(cond-> {}
|
||||
hx-start (assoc :start (some-> hx-start not-empty (Long/parseLong )))
|
||||
q-start (assoc :start (some-> q-start not-empty (Long/parseLong )))
|
||||
hx-per-page (assoc :per-page (some-> hx-per-page not-empty (Long/parseLong )))
|
||||
q-per-page (assoc :per-page (some-> q-per-page not-empty (Long/parseLong )))
|
||||
hx-sort (assoc :sort (parse-sort grid-spec hx-sort))
|
||||
q-sort (assoc :sort (parse-sort grid-spec q-sort))
|
||||
(not-empty q-toggle-sort) (update :sort #(toggle-sort grid-spec % q-toggle-sort) )
|
||||
(:session request) (assoc :session (:session request))
|
||||
(:client-selection (:session request)) (assoc :client-selection (:client-selection (:session request)))
|
||||
(:clients request) (assoc :clients (:clients request))
|
||||
(:client request) (assoc :client (:client request)))))
|
||||
(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)
|
||||
|
||||
: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)
|
||||
(:client request)
|
||||
(:client-id (:parsed-query-params request))
|
||||
(when (:client-code (:parsed-query-params request))
|
||||
[:client/code (:client-code (:parsed-query-params request))]))
|
||||
valid-clients (->> valid-clients
|
||||
(take 20)
|
||||
set)]
|
||||
(println "VALID CLIENTS ARE" valid-clients)
|
||||
(handler (assoc request :trimmed-clients valid-clients)))))
|
||||
|
||||
(defn table-route [grid-spec]
|
||||
(-> (fn table [{:keys [identity] :as request}]
|
||||
(let [unparse-query-params (or (:unparse-query grid-spec)
|
||||
default-unparse-query-params)]
|
||||
(html-response (table*
|
||||
grid-spec
|
||||
identity
|
||||
request)
|
||||
:headers {"hx-push-url" (str "?" (url/map->query (unparse-query-params (:parsed-query-params request))))}
|
||||
:oob (when-let [oob-render (:oob-render grid-spec)]
|
||||
(oob-render request)))))
|
||||
(wrap-trim-client-ids)
|
||||
(query-params/wrap-parse-query-params (or (:parse-query-params grid-spec)
|
||||
(default-parse-query-params grid-spec)))
|
||||
(wrap-secure)
|
||||
(wrap-client-redirect-unauthenticated)))
|
||||
|
||||
(defn page-route [grid-spec ]
|
||||
(-> (fn page [{:keys [identity] :as request}]
|
||||
(base-page
|
||||
request
|
||||
(com/page {:nav (:nav grid-spec)
|
||||
:page-specific (when-let [page-specific-nav (:page-specific-nav grid-spec)]
|
||||
[:div#page-specific-nav (page-specific-nav request)])
|
||||
:client-selection (:client-selection (:session request))
|
||||
:clients (:clients request)
|
||||
:client (:client request)
|
||||
:identity (:identity request)}
|
||||
(apply com/breadcrumbs {} (:breadcrumbs grid-spec))
|
||||
(table* grid-spec
|
||||
identity
|
||||
request))
|
||||
(:title grid-spec)))
|
||||
(wrap-trim-client-ids)
|
||||
(query-params/wrap-parse-query-params (or (:parse-query-params grid-spec)
|
||||
(default-parse-query-params grid-spec)))
|
||||
(wrap-secure)
|
||||
(wrap-client-redirect-unauthenticated)))
|
||||
|
||||
(def request-spec (m/schema [:map]))
|
||||
(def entity-spec (m/schema [:map]))
|
||||
(def header-spec (m/schema [:map
|
||||
[:key :string]
|
||||
[:name :string]
|
||||
[:sort-key {:optional true} :string]
|
||||
[:render [:=> [:cat entity-spec] :any]]
|
||||
[:hide? {:optional true} [:=> [:cat entity-spec] :boolean]]]))
|
||||
(def grid-spec (m/schema [:map
|
||||
[:id :string]
|
||||
[:nav vector?]
|
||||
[:page-specific-nav
|
||||
{:optional true
|
||||
:default (fn [request])}
|
||||
[:maybe [:=>
|
||||
[:cat request-spec]
|
||||
vector?]]]
|
||||
[:id-fn {:default :db/id
|
||||
:optional true}
|
||||
[:=>
|
||||
[:cat map?]
|
||||
nat-int?]]
|
||||
[:fetch-page [:=>
|
||||
[:cat request-spec]
|
||||
[:cat [:vector entity-spec] :int]]]
|
||||
[:parse-query-params
|
||||
{:optional true}
|
||||
[:=>
|
||||
[:cat [:map-of :keyword :any]]
|
||||
[:map-of :keyword :any]]]
|
||||
[:oob-render
|
||||
{:optional true
|
||||
:default (fn [request])}
|
||||
[:=>
|
||||
[:cat request-spec]
|
||||
vector?]]
|
||||
[:breadcrumbs [:vector vector?]]
|
||||
[:title :string]
|
||||
[:entity-name :string]
|
||||
[:route :keyword]
|
||||
[:action-buttons
|
||||
{:default (fn [request])
|
||||
:optional true}
|
||||
[:=>
|
||||
[:cat request-spec]
|
||||
[:maybe [:vector vector?]]]]
|
||||
[:row-buttons
|
||||
{:default (fn [request entity])
|
||||
:optional true}
|
||||
[:=>
|
||||
[:cat request-spec entity-spec]
|
||||
[:maybe [:vector vector?]]]]
|
||||
[:headers [:vector header-spec]]]))
|
||||
|
||||
(defn build [grid-page]
|
||||
(when-not (m/validate grid-spec grid-page)
|
||||
(throw (ex-info "Could not validate grid"
|
||||
(m/explain grid-spec grid-page))))
|
||||
(m/decode grid-spec grid-page (mt2/default-value-transformer {::mt2/add-optional-keys true})))
|
||||
|
||||
(defn table [grid-spec {:keys [query-params hx-query-params identity session] :as request}]
|
||||
(let [params (extract-params grid-spec request)
|
||||
query-string (params->query-string params)]
|
||||
(html-response (table*
|
||||
grid-spec
|
||||
identity
|
||||
params
|
||||
)
|
||||
:headers {"hx-push-url" (str "?" query-string)})))
|
||||
|
||||
(defn page [grid-spec {:keys [identity] :as request}]
|
||||
(base-page
|
||||
request
|
||||
(com/page {:nav (:nav grid-spec)
|
||||
:client-selection (:client-selection (:session request))
|
||||
:clients (:clients request)
|
||||
:client (:client request)
|
||||
:identity (:identity request)}
|
||||
(apply com/breadcrumbs {} (:breadcrumbs grid-spec))
|
||||
(table* grid-spec
|
||||
identity
|
||||
(extract-params grid-spec request)))
|
||||
(:title grid-spec)))
|
||||
|
||||
139
src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj
Normal file
139
src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj
Normal file
@@ -0,0 +1,139 @@
|
||||
(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]]
|
||||
[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*]]
|
||||
[auto-ap.time :as atime]
|
||||
[bidi.bidi :as bidi]
|
||||
[clj-time.coerce :as c]
|
||||
[datomic.api :as dc]
|
||||
[malli.core :as m]))
|
||||
|
||||
;; always should be fast
|
||||
|
||||
(defn filters [params]
|
||||
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
|
||||
"hx-get" (bidi/path-for ssr-routes/only-routes
|
||||
:pos-cash-drawer-shift-table)
|
||||
"hx-target" "#cash-drawer-shift-table"
|
||||
"hx-indicator" "#cash-drawer-shift-table"
|
||||
#_#_:hx-disabled-elt "find fieldset"}
|
||||
|
||||
[:fieldset.space-y-6
|
||||
(date-range-field* params)
|
||||
(total-field* params)]])
|
||||
|
||||
(def default-read '[:db/id
|
||||
:cash-drawer-shift/paid-in :cash-drawer-shift/paid-out :cash-drawer-shift/expected-cash :cash-drawer-shift/opened-cash
|
||||
[:cash-drawer-shift/date :xform clj-time.coerce/from-date]
|
||||
{:cash-drawer-shift/client [:client/name :db/id :client/code]}])
|
||||
|
||||
(defn fetch-ids [db request]
|
||||
(let [query-params (:parsed-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] ...]]]}
|
||||
:args [db [(:trimmed-clients request)
|
||||
(some-> (:start-date query-params) c/to-date)
|
||||
(some-> (:end-date query-params) c/to-date )]]}
|
||||
(:sort query-params) (add-sorter-fields {"client" ['[?e :cash-drawer-shift/client ?c]
|
||||
'[?c :client/name ?sort-client]]
|
||||
"date" ['[?e :cash-drawer-shift/date ?sort-date]]
|
||||
"paid-in" ['[?e :cash-drawer-shift/paid-in ?sort-paid-in]]
|
||||
"paid-out" ['[?e :cash-drawer-shift/paid-out ?sort-paid-out]]
|
||||
"expected-cash" ['[?e :cash-drawer-shift/expected-cash ?sort-expected-cash]]
|
||||
"opened-cash" ['[?e :cash-drawer-shift/opened-cash ?sort-opened-cash]]
|
||||
}
|
||||
query-params)
|
||||
|
||||
(:exact-match-id query-params)
|
||||
(merge-query {:query {:in ['?e]
|
||||
:where []}
|
||||
:args [(:exact-match-id query-params)]})
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e]
|
||||
:where ['[?e :cash-drawer-shift/date ?sort-default]]}}))]
|
||||
|
||||
(cond->> (query2 query)
|
||||
true (apply-sort-3 query-params)
|
||||
true (apply-pagination query-params))))
|
||||
|
||||
(defn hydrate-results [ids db _]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
cash-drawer-shifts (->> ids
|
||||
(map results)
|
||||
(map first))]
|
||||
cash-drawer-shifts))
|
||||
|
||||
(defn fetch-page [request]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]
|
||||
|
||||
[(->> (hydrate-results ids-to-retrieve db request))
|
||||
matching-count]))
|
||||
|
||||
(def grid-page
|
||||
(helper/build
|
||||
{:id "cash-drawer-shift-table"
|
||||
:nav (com/main-aside-nav)
|
||||
:page-specific-nav filters
|
||||
:fetch-page fetch-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"]
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:pos-cash-drawer-shifts)}
|
||||
"Cash Drawer Shifts"]]
|
||||
:title "Cash drawer shifts"
|
||||
:entity-name "Cash drawer shift"
|
||||
:route :pos-cash-drawer-shift-table
|
||||
:headers [{:key "client"
|
||||
:name "Client"
|
||||
:sort-key "client"
|
||||
:hide? (fn [args]
|
||||
(= (count (:clients args)) 1))
|
||||
:render #(-> % :cash-drawer-shift/client :client/code)}
|
||||
{:key "date"
|
||||
:name "Date"
|
||||
:sort-key "date"
|
||||
:render #(atime/unparse-local (:cash-drawer-shift/date %) atime/standard-time)}
|
||||
{:key "paid-in"
|
||||
:name "Paid in"
|
||||
:sort-key "paid-in"
|
||||
:render #(some->> % :cash-drawer-shift/paid-in (format "$%.2f"))}
|
||||
{:key "paid-out"
|
||||
:name "Paid out"
|
||||
:sort-key "paid-out"
|
||||
:render #(some->> % :cash-drawer-shift/paid-out (format "$%.2f"))}
|
||||
{:key "expected-cash"
|
||||
:name "Expected cash"
|
||||
:sort-key "expected-cash"
|
||||
:render #(some->> % :cash-drawer-shift/expected-cash (format "$%.2f"))}
|
||||
{:key "opened-cash"
|
||||
:name "Opened cash"
|
||||
:sort-key "opened-cash"
|
||||
:render #(some->> % :cash-drawer-shift/opened-cash (format "$%.2f"))}
|
||||
]}))
|
||||
|
||||
|
||||
(def row* (partial helper/row* grid-page))
|
||||
(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)})
|
||||
86
src/clj/auto_ap/ssr/pos/common.clj
Normal file
86
src/clj/auto_ap/ssr/pos/common.clj
Normal file
@@ -0,0 +1,86 @@
|
||||
(ns auto-ap.ssr.pos.common
|
||||
(:require [auto-ap.ssr.components :as com]
|
||||
[auto-ap.time :as atime]
|
||||
[auto-ap.ssr.svg :as svg]))
|
||||
|
||||
;; TODO make date-input take clj date
|
||||
;; TODO make total fields take decimals
|
||||
|
||||
(defn date-range-field* [request]
|
||||
[:div#date-range {}
|
||||
(com/field {:label "Date Range"}
|
||||
[:div.space-y-4
|
||||
[:div
|
||||
(com/button-group {:name "date-range"}
|
||||
(com/button-group-button {:size :small :value "all" :hx-trigger "click"} "All")
|
||||
(com/button-group-button {:size :small :value "week" :hx-trigger "click"} "Week")
|
||||
(com/button-group-button {:size :small :value "month" :hx-trigger "click"} "Month")
|
||||
(com/button-group-button {:size :small :value "year" :hx-trigger "click"} "Year"))
|
||||
]
|
||||
[:div.flex.space-x-1.items-baseline
|
||||
(com/date-input {:name "start-date"
|
||||
:value (some-> request
|
||||
:parsed-query-params
|
||||
:start-date
|
||||
(atime/unparse-local atime/normal-date))
|
||||
:placeholder "Date"
|
||||
:size :small})
|
||||
|
||||
(com/date-input {:name "end-date"
|
||||
:value (some-> request
|
||||
:parsed-query-params
|
||||
:end-date
|
||||
(atime/unparse-local atime/normal-date))
|
||||
:placeholder "Date"
|
||||
:size :small})]])])
|
||||
|
||||
(defn processor-field* [request]
|
||||
(com/field {:label "Processor"}
|
||||
(com/radio {:size :small
|
||||
:name "processor"
|
||||
:options [{:value ""
|
||||
:content "All"}
|
||||
{:value "square"
|
||||
:content [:div.flex.space-x-2 [:img.align-center {:src "/img/square.png" :style {:width "16px" :height "16px"}}] [:div "Square"]]}
|
||||
{:value "doordash"
|
||||
:content [:div.flex.space-x-2 [:img.align-center {:src "/img/doordash.png" :style {:width "16px" :height "16px"}}] [:div "Doordash"]]}
|
||||
{:value "uber-eats"
|
||||
:content [:div.flex.space-x-2 [:img.align-center {:src "/img/ubereats.png" :style {:width "16px" :height "16px"}}] [:div "Uber eats"]]}
|
||||
{:value "grubhub"
|
||||
:content [:div.flex.space-x-2 [:img.align-center {:src "/img/grubhub.png" :style {:width "16px" :height "16px"}}] [:div "Grubhub"]]}
|
||||
{:value "koala"
|
||||
:content [:div.flex.space-x-2 [:img.align-center {:src "/img/koala.png" :style {:width "16px" :height "16px"}}] [:div "Koala"]]}
|
||||
{:value "ezcater"
|
||||
:content [:div.flex.space-x-2 [:img.align-center {:src "/img/ezcater.png" :style {:width "16px" :height "16px"}}] [:div "EZCater"]]}
|
||||
{:value "na"
|
||||
:content "No Processor"}]})))
|
||||
|
||||
(defn total-field* [request]
|
||||
(com/field {:label "Total"}
|
||||
[:div.flex.space-x-4.items-baseline
|
||||
(com/money-input {:name "total-gte"
|
||||
:id "total-gte"
|
||||
:hx-preserve "true"
|
||||
:class "hot-filter"
|
||||
:value (:total-gte (:parsed-query-params request))
|
||||
:placeholder "0.01"
|
||||
:size :small})
|
||||
[:div.align-baseline
|
||||
"to"]
|
||||
(com/money-input {:name "total-lte"
|
||||
:hx-preserve "true"
|
||||
:id "total-lte"
|
||||
:class "hot-filter"
|
||||
:value (:total-lte (:parsed-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))]
|
||||
[:div
|
||||
(com/field {:label "Exact match"}
|
||||
(com/pill {:color :primary}
|
||||
[:span.inline-flex.gap-2
|
||||
exact-match-id
|
||||
[:a {:href "?exact-match-id="}
|
||||
[:div.h-4.w-4 svg/x]]]))]))
|
||||
197
src/clj/auto_ap/ssr/pos/expected_deposits.clj
Normal file
197
src/clj/auto_ap/ssr/pos/expected_deposits.clj
Normal file
@@ -0,0 +1,197 @@
|
||||
(ns auto-ap.ssr.pos.expected-deposits
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
: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.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.svg :as svg]
|
||||
[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]))
|
||||
|
||||
;; make params parsing composable
|
||||
|
||||
(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
|
||||
:pos-expected-deposit-table)
|
||||
"hx-target" "#expected-deposit-table"
|
||||
"hx-indicator" "#expected-deposit-table"
|
||||
#_#_:hx-disabled-elt "find fieldset"}
|
||||
|
||||
[:fieldset.space-y-6
|
||||
(date-range-field* request)
|
||||
(exact-match-id-field* request)]])
|
||||
|
||||
(def default-read '[:db/id
|
||||
:expected-deposit/location
|
||||
:expected-deposit/total
|
||||
:expected-deposit/fee
|
||||
[:expected-deposit/date :xform clj-time.coerce/from-date]
|
||||
{:expected-deposit/client [:client/name :db/id :client/code]
|
||||
[:expected-deposit/status :xform iol-ion.query/ident] [:db/ident]
|
||||
:transaction/_expected-deposit [:transaction/date :db/id]}])
|
||||
|
||||
(defn fetch-ids [db request]
|
||||
|
||||
(let [query-params (:parsed-query-params request)
|
||||
valid-clients (extract-client-ids (:clients request)
|
||||
(:client request)
|
||||
(:client-id query-params)
|
||||
(when (:client-code query-params)
|
||||
[:client/code (:client-code query-params)]))
|
||||
query (cond-> {:query {:find []
|
||||
:in ['$ '[?clients ?start-date ?end-date]]
|
||||
:where '[[(iol-ion.query/scan-expected-deposits $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]]}
|
||||
:args [db [valid-clients
|
||||
(some-> (:start-date query-params) c/to-date)
|
||||
(some-> (:end-date query-params) c/to-date)]]}
|
||||
(:sort query-params) (add-sorter-fields {"client" ['[?e :expected-deposit/client ?c]
|
||||
'[?c :client/name ?sort-client]]
|
||||
"location" ['[?e :expected-deposit/location ?sort-location]]
|
||||
"date" ['[?e :expected-deposit/date ?sort-date]]
|
||||
"total" ['[?e :expected-deposit/total ?sort-total]]
|
||||
"fee" ['[?e :expected-deposit/fee ?sort-fee]]}
|
||||
query-params)
|
||||
|
||||
(:exact-match-id query-params)
|
||||
(merge-query {:query {:in ['?e]
|
||||
:where []}
|
||||
:args [(:exact-match-id query-params)]})
|
||||
|
||||
|
||||
(:total-gte query-params)
|
||||
(merge-query {:query {:in ['?total-gte]
|
||||
:where ['[?e :expected-deposit/total ?a]
|
||||
'[(>= ?a ?total-gte)]]}
|
||||
:args [(:total-gte query-params)]})
|
||||
|
||||
(:total-lte query-params)
|
||||
(merge-query {:query {:in ['?total-lte]
|
||||
:where ['[?e :expected-deposit/total ?a]
|
||||
'[(<= ?a ?total-lte)]]}
|
||||
:args [(:total-lte query-params)]})
|
||||
|
||||
(:total query-params)
|
||||
(merge-query {:query {:in ['?total]
|
||||
:where ['[?e :expected-deposit/total ?expected-deposit-total]
|
||||
'[(iol-ion.query/dollars= ?expected-deposit-total ?total)]]}
|
||||
:args [(:total query-params)]})
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e]
|
||||
:where ['[?e :expected-deposit/date ?sort-default]]}}))]
|
||||
|
||||
(cond->> (query2 query)
|
||||
true (apply-sort-3 query-params)
|
||||
true (apply-pagination query-params))))
|
||||
|
||||
(defn hydrate-results [ids db _]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
payments (->> ids
|
||||
(map results)
|
||||
(map first)
|
||||
(map (fn get-totals [ed]
|
||||
(assoc ed :totals
|
||||
(->> (dc/q '[:find ?d4 (count ?c) (sum ?a)
|
||||
:in $ ?ed
|
||||
:where [?ed :expected-deposit/charges ?c]
|
||||
[?c :charge/total ?a]
|
||||
[?o :sales-order/charges ?c]
|
||||
[?o :sales-order/date ?d]
|
||||
[(clj-time.coerce/from-date ?d) ?d2]
|
||||
[(auto-ap.time/localize ?d2) ?d3]
|
||||
[(clj-time.coerce/to-local-date ?d3) ?d4]]
|
||||
(dc/db conn)
|
||||
(:db/id ed))
|
||||
(map (fn [[date count amount]]
|
||||
{:date (c/to-date-time date)
|
||||
:count count
|
||||
:amount amount})))))))]
|
||||
payments))
|
||||
|
||||
(defn fetch-page [args]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db args)]
|
||||
|
||||
[(->> (hydrate-results ids-to-retrieve db args))
|
||||
matching-count]))
|
||||
|
||||
(def grid-page
|
||||
(helper/build
|
||||
{:id "expected-deposit-table"
|
||||
: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)])
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"POS"]
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:pos-expected-deposits)}
|
||||
"Expected deposits"]]
|
||||
:title "Expected deposits"
|
||||
:entity-name "Expected deposit"
|
||||
:route :pos-expected-deposit-table
|
||||
:row-buttons (fn [_ e]
|
||||
[
|
||||
(when (:expected-deposit/reference-link e)
|
||||
(com/a-icon-button {:href (:expected-deposit/reference-link e)}
|
||||
svg/external-link))
|
||||
(when-let [transaction-id (-> e (:transaction/_expected-deposit) first :db/id)]
|
||||
(com/a-button {:href (str (bidi/path-for client-routes/routes
|
||||
:transactions)
|
||||
"?exact-match-id="
|
||||
transaction-id)} "Transaction"))])
|
||||
:headers [{:key "client"
|
||||
:name "Client"
|
||||
:sort-key "client"
|
||||
:hide? (fn [args]
|
||||
(= (count (:clients args)) 1))
|
||||
:render #(-> % :expected-deposit/client :client/code)}
|
||||
{:key "date"
|
||||
:name "Date"
|
||||
:sort-key "date"
|
||||
:render #(atime/unparse-local (:expected-deposit/date %) atime/standard-time)}
|
||||
{:key "sales-date"
|
||||
:name "Sales Date"
|
||||
:sort-key "sales-date"
|
||||
:render #(atime/unparse-local (:expected-deposit/sales-date %) atime/standard-time)}
|
||||
{:key "total"
|
||||
:name "Total"
|
||||
:sort-key "total"
|
||||
:render #(some->> % :expected-deposit/total (format "$%.2f"))}
|
||||
{:key "fee"
|
||||
:name "Fee"
|
||||
:sort-key "fee"
|
||||
:render #(some->> % :expected-deposit/fee (format "$%.2f"))}]}))
|
||||
|
||||
(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)})
|
||||
156
src/clj/auto_ap/ssr/pos/refunds.clj
Normal file
156
src/clj/auto_ap/ssr/pos/refunds.clj
Normal file
@@ -0,0 +1,156 @@
|
||||
(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.graphql.utils :refer [extract-client-ids]]
|
||||
[auto-ap.routes.utils
|
||||
:refer [wrap-client-redirect-unauthenticated wrap-secure]]
|
||||
[auto-ap.ssr.pos.common :refer [date-range-field* processor-field* total-field*]]
|
||||
[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 c]
|
||||
[datomic.api :as dc]
|
||||
[clojure.set :as set]
|
||||
[auto-ap.query-params :as query-params]
|
||||
[malli.core :as m]))
|
||||
|
||||
;; TODO refunds
|
||||
;; always should be fast
|
||||
;; make params parsing composable
|
||||
|
||||
(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
|
||||
:pos-refund-table)
|
||||
"hx-target" "#refund-table"
|
||||
"hx-indicator" "#refund-table"
|
||||
#_#_:hx-disabled-elt "find fieldset"}
|
||||
|
||||
[:fieldset.space-y-6
|
||||
(date-range-field* request)
|
||||
(total-field* request)]])
|
||||
|
||||
(def default-read '[:db/id
|
||||
:sales-refund/total
|
||||
:sales-refund/fee
|
||||
:sales-refund/type
|
||||
[:sales-refund/date :xform clj-time.coerce/from-date]
|
||||
{:sales-refund/client [:client/name :db/id :client/code]}])
|
||||
|
||||
(defn fetch-ids [db request]
|
||||
(let [query-params (:parsed-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] ...]]]}
|
||||
:args [db [(:trimmed-clients request)
|
||||
(some-> query-params :start-date c/to-date)
|
||||
(some-> query-params :end-date c/to-date )]]}
|
||||
(:sort query-params) (add-sorter-fields {"client" ['[?e :sales-refund/client ?c]
|
||||
'[?c :client/name ?sort-client]]
|
||||
"date" ['[?e :sales-refund/date ?sort-date]]
|
||||
"total" ['[?e :sales-refund/total ?sort-total]]
|
||||
"fee" ['[?e :sales-refund/fee ?sort-tip]]
|
||||
"type" ['[?e :sales-refund/type ?sort-type]]}
|
||||
query-params)
|
||||
|
||||
(:exact-match-id query-params)
|
||||
(merge-query {:query {:in ['?e]
|
||||
:where []}
|
||||
:args [(:exact-match-id query-params)]})
|
||||
|
||||
(:total-gte query-params)
|
||||
(merge-query {:query {:in ['?total-gte]
|
||||
:where ['[?e :sales-refund/total ?a]
|
||||
'[(>= ?a ?total-gte)]]}
|
||||
:args [(:total-gte query-params)]})
|
||||
|
||||
(:total-lte query-params)
|
||||
(merge-query {:query {:in ['?total-lte]
|
||||
:where ['[?e :sales-refund/total ?a]
|
||||
'[(<= ?a ?total-lte)]]}
|
||||
:args [(:total-lte query-params)]})
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e]
|
||||
:where ['[?e :sales-refund/date ?sort-default]]}}))]
|
||||
|
||||
(cond->> (query2 query)
|
||||
true (apply-sort-3 query-params)
|
||||
true (apply-pagination query-params))))
|
||||
|
||||
(defn hydrate-results [ids db _]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
refunds (->> ids
|
||||
(map results)
|
||||
(map first))]
|
||||
refunds))
|
||||
|
||||
(defn fetch-page [request]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]
|
||||
|
||||
[(->> (hydrate-results ids-to-retrieve db request))
|
||||
matching-count]))
|
||||
|
||||
(def grid-page
|
||||
(helper/build {:id "refund-table"
|
||||
: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)])
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:company)}
|
||||
"POS"]
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:pos-refunds)}
|
||||
"Refunds"]]
|
||||
:title "Refunds"
|
||||
:entity-name "Refund"
|
||||
:route :pos-refund-table
|
||||
:headers [{:key "client"
|
||||
:name "Client"
|
||||
:sort-key "client"
|
||||
:hide? (fn [args]
|
||||
(= (count (:clients args)) 1))
|
||||
:render #(-> % :sales-refund/client :client/code)}
|
||||
{:key "date"
|
||||
:name "Date"
|
||||
:sort-key "date"
|
||||
:render #(atime/unparse-local (:sales-refund/date %) atime/standard-time)}
|
||||
{:key "total"
|
||||
:name "Total"
|
||||
:sort-key "total"
|
||||
:render #(some->> % :sales-refund/total (format "$%.2f"))}
|
||||
{:key "type"
|
||||
:name "Type"
|
||||
:sort-key "type"
|
||||
:render :sales-refund/type}
|
||||
{:key "fee"
|
||||
:name "Fee"
|
||||
:sort-key "fee"
|
||||
:render #(some->> % :sales-refund/fee (format "$%.2f"))}]}))
|
||||
|
||||
(def row* (partial helper/row* grid-page))
|
||||
(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)})
|
||||
263
src/clj/auto_ap/ssr/pos/sales_orders.clj
Normal file
263
src/clj/auto_ap/ssr/pos/sales_orders.clj
Normal file
@@ -0,0 +1,263 @@
|
||||
(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]]
|
||||
[auto-ap.datomic.sales-orders :as d-sales]
|
||||
[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.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* processor-field* total-field*]]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[auto-ap.time :as atime]
|
||||
[bidi.bidi :as bidi]
|
||||
[clj-time.coerce :as c]
|
||||
[datomic.api :as dc]
|
||||
[malli.core :as m]))
|
||||
|
||||
(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
|
||||
:pos-sales-table)
|
||||
"hx-target" "#sales-table"
|
||||
"hx-indicator" "#sales-table"
|
||||
#_#_:hx-disabled-elt "find fieldset"}
|
||||
|
||||
[:fieldset.space-y-6
|
||||
(date-range-field* request)
|
||||
(total-field* request)
|
||||
[:div
|
||||
(com/field {:label "Payment Method"}
|
||||
(com/radio {:size :small
|
||||
:name "payment-method"
|
||||
:options [{:value ""
|
||||
:content "All"}
|
||||
{:value "CASH"
|
||||
:content "Cash"}
|
||||
{:value "CARD"
|
||||
:content "Card"}
|
||||
{:value "SQUARE_GIFT_CARD"
|
||||
:content "Gift Card"}
|
||||
{:value "OTHER"
|
||||
:content "Other"}
|
||||
]}))]
|
||||
[:div
|
||||
(processor-field* request)]
|
||||
|
||||
[:div
|
||||
(com/field {:label "Category"}
|
||||
(com/text-input {:name "category"
|
||||
:class "hot-filter"
|
||||
:id "category"
|
||||
:hx-preserve "true"
|
||||
:value (:category (:parsed-query-params request))
|
||||
:placeholder "Fries"
|
||||
:size :small}))]]])
|
||||
|
||||
(def default-read '[:db/id
|
||||
:sales-order/external-id,
|
||||
:sales-order/location,
|
||||
[:sales-order/date, :xform clj-time.coerce/from-date]
|
||||
:sales-order/total,
|
||||
:sales-order/tax,
|
||||
:sales-order/tip,
|
||||
:sales-order/line-items,
|
||||
:sales-order/discount,
|
||||
:sales-order/returns,
|
||||
:sales-order/service-charge,
|
||||
:sales-order/vendor,
|
||||
:sales-order/source,
|
||||
:sales-order/reference-link,
|
||||
{:sales-order/client [:client/name :db/id :client/code]
|
||||
:sales-order/charges [
|
||||
:charge/type-name,
|
||||
:charge/total,
|
||||
:charge/tax,
|
||||
:charge/tip,
|
||||
:charge/external-id,
|
||||
:charge/note,
|
||||
:charge/date,
|
||||
:charge/client,
|
||||
:charge/location,
|
||||
:charge/reference-link,
|
||||
{:charge/processor [:db/ident]} {:expected-deposit/_charges [:db/id]}]}])
|
||||
|
||||
(defn fetch-ids [db request]
|
||||
(let [query-params (:parsed-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] ...]]]}
|
||||
:args [db [(:trimmed-clients request)
|
||||
(some-> (:start-date query-params) c/to-date)
|
||||
(some-> (:end-date query-params) c/to-date)]]}
|
||||
(:sort query-params) (add-sorter-fields {"client" ['[?e :sales-order/client ?c]
|
||||
'[?c :client/name ?sort-client]]
|
||||
"date" ['[?e :sales-order/date ?sort-date]]
|
||||
"total" ['[?e :sales-order/total ?sort-total]]
|
||||
"tax" ['[?e :sales-order/tax ?sort-tax]]
|
||||
"tip" ['[?e :sales-order/tip ?sort-tip]]
|
||||
"source" ['[?e :sales-order/source ?sort-source]]
|
||||
"processor" ['[?e :sales-order/processor ?p]
|
||||
'[?p :db/ident ?p2]
|
||||
'[(name ?p2) ?sort-processor]]}
|
||||
query-params)
|
||||
|
||||
(:exact-match-id query-params)
|
||||
(merge-query {:query {:in ['?e]
|
||||
:where []}
|
||||
:args [(:exact-match-id query-params)]})
|
||||
|
||||
(:total-gte query-params)
|
||||
(merge-query {:query {:in ['?total-gte]
|
||||
:where ['[?e :sales-order/total ?a]
|
||||
'[(>= ?a ?total-gte)]]}
|
||||
:args [(:total-gte query-params)]})
|
||||
|
||||
(:total-lte query-params)
|
||||
(merge-query {:query {:in ['?total-lte]
|
||||
:where ['[?e :sales-order/total ?a]
|
||||
'[(<= ?a ?total-lte)]]}
|
||||
:args [(:total-lte query-params)]})
|
||||
|
||||
(not-empty (:payment-method query-params))
|
||||
(merge-query {:query {:in ['?type-name]
|
||||
:where ['[?e :sales-order/charges ?chg]
|
||||
'[?chg :charge/type-name ?type-name]]}
|
||||
:args [(:payment-method query-params)]})
|
||||
|
||||
(not-empty (:category query-params))
|
||||
(merge-query {:query {:in ['?category]
|
||||
:where ['[?e :sales-order/line-items ?li]
|
||||
'[?li :order-line-item/category ?category]]}
|
||||
:args [(:category query-params)]})
|
||||
|
||||
(:processor query-params)
|
||||
(merge-query {:query {:in ['?processor]
|
||||
:where ['[?e :sales-order/charges ?chg]
|
||||
'[?chg :charge/processor ?processor]]}
|
||||
:args [(:processor query-params)]})
|
||||
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e]}}))]
|
||||
(clojure.pprint/pprint query)
|
||||
(cond->> (query2 query)
|
||||
true (apply-sort-3 query-params)
|
||||
true (apply-pagination query-params))))
|
||||
|
||||
(defn hydrate-results [ids db _]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
charges (->> ids
|
||||
(map results)
|
||||
(map first))]
|
||||
charges))
|
||||
|
||||
(defn fetch-page [request]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]
|
||||
|
||||
[(->> (hydrate-results ids-to-retrieve db request))
|
||||
matching-count]))
|
||||
|
||||
|
||||
(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"]
|
||||
|
||||
[: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)})
|
||||
181
src/clj/auto_ap/ssr/pos/tenders.clj
Normal file
181
src/clj/auto_ap/ssr/pos/tenders.clj
Normal file
@@ -0,0 +1,181 @@
|
||||
(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]
|
||||
[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* processor-field* total-field*]]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[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]))
|
||||
|
||||
;; always should be fast
|
||||
|
||||
(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
|
||||
:pos-tender-table)
|
||||
"hx-target" "#tender-table"
|
||||
"hx-indicator" "#tender-table"
|
||||
#_#_:hx-disabled-elt "find fieldset"}
|
||||
|
||||
[:fieldset.space-y-6
|
||||
(date-range-field* request)
|
||||
(processor-field* request)
|
||||
(total-field* request)]])
|
||||
|
||||
(def default-read '[:db/id
|
||||
:charge/reference-link
|
||||
:charge/total
|
||||
:charge/tip
|
||||
[:charge/date :xform clj-time.coerce/from-date]
|
||||
{:charge/client [:client/name :db/id :client/code]
|
||||
[:charge/processor :xform iol-ion.query/ident] [:db/ident]
|
||||
:expected-deposit/_charges [:expected-deposit/date :db/id]}])
|
||||
|
||||
(defn fetch-ids [db request]
|
||||
(let [query-params (:parsed-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] ...]]]}
|
||||
:args [db [(:trimmed-clients request)
|
||||
(some-> (:start-date query-params) c/to-date)
|
||||
(some-> (:end-date query-params) c/to-date)]]}
|
||||
(:sort query-params) (add-sorter-fields {"client" ['[?e :charge/client ?c]
|
||||
'[?c :client/name ?sort-client]]
|
||||
"date" ['[?e :charge/date ?sort-date]]
|
||||
"total" ['[?e :charge/total ?sort-total]]
|
||||
"tip" ['[?e :charge/tip ?sort-tip]]
|
||||
"processor" ['[?e :charge/processor ?p]
|
||||
'[?p :db/ident ?p2]
|
||||
'[(name ?p2) ?sort-processor]]}
|
||||
query-params)
|
||||
|
||||
(:exact-match-id query-params)
|
||||
(merge-query {:query {:in ['?e]
|
||||
:where []}
|
||||
:args [(:exact-match-id query-params)]})
|
||||
|
||||
(:total-gte query-params)
|
||||
(merge-query {:query {:in ['?total-gte]
|
||||
:where ['[?e :charge/total ?a]
|
||||
'[(>= ?a ?total-gte)]]}
|
||||
:args [(:total-gte query-params)]})
|
||||
|
||||
(:total-lte query-params)
|
||||
(merge-query {:query {:in ['?total-lte]
|
||||
:where ['[?e :charge/total ?a]
|
||||
'[(<= ?a ?total-lte)]]}
|
||||
:args [(:total-lte query-params)]})
|
||||
|
||||
(:processor query-params)
|
||||
(merge-query {:query {:in '[?processor]
|
||||
:where ['[?e :charge/processor ?processor]]}
|
||||
:args [(:processor query-params)]})
|
||||
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e]}}))]
|
||||
|
||||
(cond->> (query2 query)
|
||||
true (apply-sort-3 query-params)
|
||||
true (apply-pagination query-params))))
|
||||
|
||||
(defn hydrate-results [ids db _]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
charges (->> ids
|
||||
(map results)
|
||||
(map first))]
|
||||
charges))
|
||||
|
||||
(defn fetch-page [request]
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]
|
||||
|
||||
[(->> (hydrate-results ids-to-retrieve db request))
|
||||
matching-count]))
|
||||
|
||||
(def grid-page
|
||||
(helper/build
|
||||
{:id "tender-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"]
|
||||
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:pos-tenders)}
|
||||
"Tenders"]]
|
||||
:title "Tenders"
|
||||
:entity-name "Tender"
|
||||
:route :pos-tender-table
|
||||
:row-buttons (fn [request e]
|
||||
(when (:charge/reference-link e)
|
||||
[(com/a-icon-button {:href (:charge/reference-link e)}
|
||||
svg/external-link)]))
|
||||
:headers [{:key "client"
|
||||
:name "Client"
|
||||
:sort-key "client"
|
||||
:hide? (fn [request]
|
||||
(= (count (:clients request)) 1))
|
||||
:render #(-> % :charge/client :client/code)}
|
||||
{:key "date"
|
||||
:name "Date"
|
||||
:sort-key "date"
|
||||
:render #(atime/unparse-local (:charge/date %) atime/standard-time)}
|
||||
{:key "total"
|
||||
:name "Total"
|
||||
:sort-key "total"
|
||||
:render #(some->> % :charge/total (format "$%.2f"))}
|
||||
{:key "processor"
|
||||
:name "Processor"
|
||||
:sort-key "processor"
|
||||
:render (fn [sales-order]
|
||||
(when (:charge/processor sales-order)
|
||||
(com/pill {:color :primary }
|
||||
(name (:charge/processor sales-order)))))}
|
||||
{:key "tip"
|
||||
:name "Tip"
|
||||
:sort-key "tip"
|
||||
:render #(some->> % :charge/tip (format "$%.2f"))}
|
||||
{:key "links"
|
||||
:name "Links"
|
||||
:render (fn [entity]
|
||||
(when-let [expected-deposit-id (some->> entity :expected-deposit/_charges first :db/id)]
|
||||
[:a {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
:pos-expected-deposits)
|
||||
"?exact-match-id=" expected-deposit-id)
|
||||
:hx-boost "true"}
|
||||
(com/pill {:color :secondary} "expected deposit")]))}]}))
|
||||
|
||||
|
||||
(def row* (partial helper/row* grid-page))
|
||||
(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)})
|
||||
@@ -21,7 +21,7 @@
|
||||
[:title (str "Integreat | " page-name)]
|
||||
[:link {:href "/css/font.min.css", :rel "stylesheet"}]
|
||||
[:link {:rel "icon" :type "image/png" :href "/favicon.png"}]
|
||||
[:link {:rel "stylesheet", :href "/css/react-datepicker.min.inc.css"}]
|
||||
#_[:link {:rel "stylesheet", :href "/css/react-datepicker.min.inc.css"}]
|
||||
[:link {:rel "stylesheet", :href "/output.css"}]
|
||||
|
||||
[:script {:src "https://unpkg.com/hyperscript.org@0.9.7/dist/_hyperscript.min.js"}]
|
||||
@@ -30,14 +30,32 @@
|
||||
#_[:script {:src "https://unpkg.com/htmx.org@1.8.4"
|
||||
:integrity "sha384-wg5Y/JwF7VxGk4zLsJEcAojRtlVp1FKKdGy1qN+OMtdq72WRvX/EdRdqg/LOhYeV"
|
||||
:crossorigin= "anonymous"}]
|
||||
[:script {:src "https://unpkg.com/htmx.org@1.9.0/dist/htmx.js"
|
||||
[:script {:src "https://unpkg.com/htmx.org@1.9.6/dist/htmx.min.js"
|
||||
:crossorigin= "anonymous"}]
|
||||
[:script {:src "https://unpkg.com/htmx.org/dist/ext/debug.js"}]
|
||||
[:script {:src "/js/htmx-disable.js"}]
|
||||
[:script {:type "text/javascript", :src "https://cdn.yodlee.com/fastlink/v4/initialize.js", :async "async"}]]
|
||||
[:link {:rel "stylesheet" :href "https://cdn.jsdelivr.net/npm/vanillajs-datepicker@1.1.4/dist/css/datepicker.min.css"}]
|
||||
|
||||
[:script {:type "text/javascript" :src "https://cdn.jsdelivr.net/npm/vanillajs-datepicker@1.1.4/dist/js/datepicker-full.min.js"}]
|
||||
[:script {:type "text/javascript", :src "https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.7/dist/autoComplete.min.js"}]
|
||||
[:script {:src "https://unpkg.com/dropzone@5.9.3/dist/min/dropzone.min.js"}]
|
||||
[:link {:rel "stylesheet" :href "https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" :type "text/css"}]
|
||||
[:style
|
||||
"
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
/* display: none; <- Crashes Chrome on hover */
|
||||
-webkit-appearance: none;
|
||||
margin: 0; /* <-- Apparently some margin are still there even though it's hidden */
|
||||
}
|
||||
input[type=number] {
|
||||
-moz-appearance:textfield; /* Firefox */
|
||||
}
|
||||
|
||||
"
|
||||
|
||||
]
|
||||
[:body {:hx-ext "disable-submit"}
|
||||
contents
|
||||
[:script {:src "/js/flowbite.min.js"}]]]))
|
||||
|
||||
@@ -5,14 +5,21 @@
|
||||
[hiccup2.core :as hiccup]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn html-response [hiccup & {:keys [status headers] :or {status 200 headers {}}}]
|
||||
(defn html-response [hiccup & {:keys [status headers oob] :or {status 200 headers {} oob []}}]
|
||||
{:status status
|
||||
:headers (into {"Content-Type" "text/html"}
|
||||
headers)
|
||||
:body (str
|
||||
(hiccup/html
|
||||
{}
|
||||
hiccup))})
|
||||
hiccup)
|
||||
"\n"
|
||||
(str/join "\n"
|
||||
(map (fn [o]
|
||||
(hiccup/html
|
||||
{}
|
||||
o))
|
||||
oob)))})
|
||||
|
||||
(defn wrap-error-response [handler]
|
||||
(fn [request]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns auto-ap.ssr-routes)
|
||||
|
||||
(def routes {"logout" :logout
|
||||
(def routes {"impersonate" :impersonate
|
||||
"logout" :logout
|
||||
"search" :search
|
||||
"invoice" {"/glimpse" {"" {:get :invoice-glimpse
|
||||
:post :invoice-glimpse-upload
|
||||
@@ -19,6 +20,17 @@
|
||||
["/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}}
|
||||
"/expected-deposit" {"" {:get :pos-expected-deposits}
|
||||
"/table" {:get :pos-expected-deposit-table}}
|
||||
"/tenders" {"" {:get :pos-tenders}
|
||||
"/table" {:get :pos-tender-table}}
|
||||
"/refunds" {"" {:get :pos-refunds}
|
||||
"/table" {:get :pos-refund-table}}
|
||||
"/cash-drawer-shifts" {"" {:get :pos-cash-drawer-shifts}
|
||||
"/table" {:get :pos-cash-drawer-shift-table}}}
|
||||
|
||||
"company" {"" :company
|
||||
"/dropdown" :company-dropdown-search-results
|
||||
"/active" {:put :active-client}
|
||||
|
||||
@@ -173,8 +173,8 @@
|
||||
:href (bidi/path-for routes/routes :payments)}
|
||||
"Payments" ]
|
||||
(when (= "admin" (:user/role @user))
|
||||
[:a.navbar-item {:class [(active-when ap = :sales-orders)]
|
||||
:href (bidi/path-for routes/routes :sales-orders)}
|
||||
[:a.navbar-item {:class [(active-when ap = :pos-sales)]
|
||||
:href (str (bidi/path-for ssr-routes/only-routes :pos-sales) "?date-range=week")}
|
||||
"POS" ])
|
||||
[:a.navbar-item {:class [(active-when ap = :transactions)]
|
||||
:href (bidi/path-for routes/routes :transactions)}
|
||||
|
||||
@@ -1,11 +1,32 @@
|
||||
(ns auto-ap.views.pages.admin.users.table
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.views.utils :refer [action-cell-width]]
|
||||
[auto-ap.views.pages.admin.users.form :as form]
|
||||
(:require
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.views.components.grid :as grid]))
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.pages.admin.users.form :as form]
|
||||
[auto-ap.views.utils
|
||||
:refer [action-cell-width dispatch-event with-user]]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::impersonated
|
||||
(fn [_ [_ impersonate-jwt]]
|
||||
(println "SUCCESED")
|
||||
(.setItem js/localStorage "jwt" impersonate-jwt)
|
||||
(.removeItem js/localStorage "last-client-id" nil)
|
||||
(.removeItem js/localStorage "last-selected-clients" nil)
|
||||
(.reload (.-location js/document ) true)
|
||||
{}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::impersonate
|
||||
[with-user]
|
||||
(fn [{:keys [db user]} [_ impersonate-jwt]]
|
||||
(js/alert "HI")
|
||||
|
||||
{:http {:method "GET"
|
||||
:uri (str "/impersonate?jwt=" impersonate-jwt)
|
||||
:on-success [::impersonated impersonate-jwt]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-changed
|
||||
@@ -50,11 +71,7 @@
|
||||
[grid/cell {} role]
|
||||
[grid/cell {} (str/join ", " (map :name clients))]
|
||||
[grid/cell {}
|
||||
[:a.button {:on-click (fn []
|
||||
(.setItem js/localStorage "jwt" (:impersonate-jwt c))
|
||||
(.removeItem js/localStorage "last-client-id" nil)
|
||||
(.removeItem js/localStorage "last-selected-clients" nil)
|
||||
(.reload (.-location js/document ) true))}
|
||||
[:a.button {:on-click (dispatch-event [::impersonate (:impersonate-jwt c)])}
|
||||
"Impersonate"]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user