Makes another new vendor report
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -8,8 +8,10 @@
|
||||
[auto-ap.ssr.hx :as hx]
|
||||
[auto-ap.ssr.ui :refer [base-page]]
|
||||
[auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers
|
||||
html-response wrap-schema-enforce]]
|
||||
clj-date-schema html-response
|
||||
wrap-schema-enforce]]
|
||||
[auto-ap.time :as atime]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[bidi.bidi :as bidi]
|
||||
[cemerick.url :as url]
|
||||
[clj-time.coerce :as coerce]
|
||||
@@ -17,11 +19,13 @@
|
||||
[datomic.api :as dc]
|
||||
[hiccup2.core :as hiccup]))
|
||||
|
||||
(defn lookup-data [request]
|
||||
(defn lookup-breakdown-data [request]
|
||||
(let [query (cond-> {:query '{:find [?cn ?user-date (sum ?amt)]
|
||||
:with [?e]
|
||||
:in [$ [?clients ?start ?end]]
|
||||
:where
|
||||
[[(iol-ion.query/scan-invoices $ ?clients ?start ?end) [[?e _ ?sort-default] ...]]
|
||||
(not [?e :invoice/status :invoice-status/voided])
|
||||
[?e :invoice/date ?d]
|
||||
[?e :invoice/client ?c]
|
||||
[?e :invoice/expense-accounts ?iea]
|
||||
@@ -49,6 +53,32 @@
|
||||
|
||||
(dc/query query)))
|
||||
|
||||
(defn lookup-invoice-total-data [request]
|
||||
(let [start (:start-date (:query-params request) (time/plus (time/now) (time/days -30)))
|
||||
end (:start-date (:query-params request) (time/now))
|
||||
query (cond-> {:query '{:find [?cn ?vn (sum ?t)]
|
||||
:with [ ?e]
|
||||
:in [$ [?clients ?start ?end]]
|
||||
:where
|
||||
[[(iol-ion.query/scan-invoices $ ?clients ?start ?end) [[?e _ ?sort-default] ...]]
|
||||
(not [?e :invoice/status :invoice-status/voided])
|
||||
[?e :invoice/client ?c]
|
||||
[?e :invoice/total ?t]
|
||||
[?e :invoice/vendor ?v]
|
||||
[?v :vendor/name ?vn]
|
||||
[?c :client/name ?cn]
|
||||
]}
|
||||
:args
|
||||
[(dc/db conn)
|
||||
[(extract-client-ids (:clients request)
|
||||
(:client-id request)
|
||||
(when (:client-code request)
|
||||
[:client/code (:client-code request)]))
|
||||
(some-> start coerce/to-date)
|
||||
(some-> end coerce/to-date)]]})]
|
||||
|
||||
(dc/query query)))
|
||||
|
||||
(defn week-seq
|
||||
([c] (week-seq c (atime/last-monday)))
|
||||
([c starting] (reverse (for [n (range c)
|
||||
@@ -68,14 +98,14 @@
|
||||
weeks))
|
||||
|
||||
|
||||
(defn card* [request]
|
||||
(com/content-card {:class "w-full" :id "report"}
|
||||
(defn expense-breakdown-card* [request]
|
||||
(com/content-card {:class "w-full" :id "expense-breakdown-report"}
|
||||
[:div {:class "flex flex-col px-8 py-8 space-y-3"}
|
||||
[:div
|
||||
[:h1.text-2xl.mb-3.font-bold "Expense report, last 8 weeks"]
|
||||
[:form {:hx-get (bidi.bidi/path-for ssr-routes/only-routes :company-expense-report-card )
|
||||
[:h1.text-2xl.mb-3.font-bold "Expense breakdown report, last 8 weeks"]
|
||||
[:form {:hx-get (bidi.bidi/path-for ssr-routes/only-routes :company-expense-report-breakdown-card )
|
||||
:hx-trigger "change"
|
||||
:hx-target "#report"
|
||||
:hx-target "#expense-breakdown-report"
|
||||
:hx-swap "outerHTML"}
|
||||
(fc/start-form
|
||||
(:query-params request)
|
||||
@@ -100,7 +130,7 @@
|
||||
:value-fn :db/id
|
||||
:content-fn :account/name})))])]
|
||||
[:div
|
||||
(let [data (lookup-data request)
|
||||
(let [data (lookup-breakdown-data request)
|
||||
distinct-accounts (take 5 (->> data
|
||||
(reduce
|
||||
(fn [acc [an _ amount]]
|
||||
@@ -127,8 +157,8 @@
|
||||
series (for [ea distinct-accounts]
|
||||
(for [d weeks]
|
||||
(get-in lookup [ea d] 0)))]
|
||||
(list
|
||||
[:div.flex.gap-2.my-4.flex-wrap
|
||||
(list
|
||||
[:div.flex.gap-2.my-4.flex-wrap
|
||||
(for [[d color] (map vector distinct-accounts ["bg-green-500" "bg-red-500" "bg-blue-500" "bg-yellow-500" "bg-purple-500"])]
|
||||
[:span.px-2.py-1.rounded.rounded-full.text-sm.text-gray-100 {:class color} d])]
|
||||
[:div {:class "w-full h-64"
|
||||
@@ -136,8 +166,60 @@
|
||||
:x-data (hx/json {:chart {:labels x-axis
|
||||
#_["2 years ago" "1 year ago" "today"],
|
||||
:series (alog/peek ::test series)}})
|
||||
:x-init (hiccup/raw "new Chartist.Bar($el, chart, {seriesBarDistance:10}); ")}
|
||||
]))]]]))
|
||||
:x-init (hiccup/raw "new Chartist.Bar($el, chart, {seriesBarDistance:10}); ")}]))]]]))
|
||||
|
||||
(defn vendor-invoice-total-card* [request]
|
||||
(com/content-card {:class "w-full" :id "invoice-totals-report"}
|
||||
[:div {:class "flex flex-col px-8 py-8 space-y-3"}
|
||||
[:div
|
||||
[:h1.text-2xl.mb-3.font-bold "Invoice totals by vendor"]
|
||||
[:form {:hx-get (bidi.bidi/path-for ssr-routes/only-routes :company-expense-report-invoice-total-card )
|
||||
:hx-trigger "change"
|
||||
:hx-target "#invoice-totals-report"
|
||||
:hx-swap "outerHTML"}
|
||||
(fc/start-form
|
||||
(:query-params request)
|
||||
(:form-errors request)
|
||||
[:div.flex.gap-2
|
||||
(fc/with-field :start-date
|
||||
(com/validated-field {:label "Start"
|
||||
:errors (fc/field-errors)}
|
||||
[:div {:class "w-64"}
|
||||
(com/date-input {:name (fc/field-name)
|
||||
:class "w-64"
|
||||
:value (some-> (fc/field-value)
|
||||
(atime/unparse-local atime/normal-date)) })]))
|
||||
(fc/with-field :end-date
|
||||
(com/validated-field {:label "End"
|
||||
:errors (fc/field-errors)}
|
||||
[:div {:class "w-64"}
|
||||
(com/date-input {:name (fc/field-name)
|
||||
:class "w-64"
|
||||
:value (some-> (fc/field-value)
|
||||
(atime/unparse-local atime/normal-date)) })]))])]
|
||||
[:div {:class "overflow-scroll min-w-full max-h-[700px]"}
|
||||
(let [data (lookup-invoice-total-data request)
|
||||
companies (sort (set (map first data)))
|
||||
vendors (sort (set (map second data)))
|
||||
result (by (juxt first second) last data)
|
||||
]
|
||||
(com/data-grid
|
||||
{:headers (into
|
||||
[(com/data-grid-header {:class "sticky left-0 z-60 bg-gray-100"} "Vendor")]
|
||||
(for [company companies]
|
||||
(com/data-grid-header {} company)))
|
||||
:thead-params {:class "sticky top-0 z-50"}}
|
||||
(for [vendor vendors]
|
||||
(com/data-grid-row
|
||||
{}
|
||||
(com/data-grid-cell {:class "sticky left-0 z-0 bg-gray-100"}
|
||||
vendor)
|
||||
(for [company companies]
|
||||
(com/data-grid-cell
|
||||
{}
|
||||
(or (some->> (get result [company vendor])
|
||||
(format "$%,.2f" ))
|
||||
[:span.text-gray-200 "-"])))))))]]]))
|
||||
|
||||
(defn page [request]
|
||||
(base-page
|
||||
@@ -156,29 +238,45 @@
|
||||
"My Company"]
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes :company-expense-report)}
|
||||
"Expense Report"])
|
||||
(card* request))
|
||||
(expense-breakdown-card* request)
|
||||
(vendor-invoice-total-card* request))
|
||||
"My Company"))
|
||||
|
||||
(defn card [request]
|
||||
(html-response
|
||||
(card* request)
|
||||
:headers {"hx-push-url" (str "?" (-> request
|
||||
:query-params
|
||||
(update :vendor-id :db/id)
|
||||
(update :account-id :db/id)
|
||||
url/map->query))}))
|
||||
(defn normalize-query-params [request]
|
||||
(-> request
|
||||
:query-params
|
||||
(update :vendor-id :db/id)
|
||||
(update :account-id :db/id)
|
||||
(update :start-date #(atime/unparse-local % atime/normal-date))
|
||||
(update :end-date #(atime/unparse-local % atime/normal-date))
|
||||
|
||||
(def key->handler
|
||||
(apply-middleware-to-all-handlers
|
||||
{:company-expense-report page
|
||||
:company-expense-report-card card}
|
||||
(fn [h]
|
||||
(-> h
|
||||
(wrap-schema-enforce :query-schema
|
||||
[:map {:default {}}
|
||||
[:vendor-id {:optional true}
|
||||
[:maybe
|
||||
[:entity-map {:pull [:vendor/name :db/id]}]]]
|
||||
[:account-id {:optional true}
|
||||
[:maybe
|
||||
[:entity-map {:pull [:account/name :db/id]}]]]] )))))
|
||||
url/map->query))
|
||||
|
||||
(defn expense-breakdown-card [request]
|
||||
(html-response
|
||||
(expense-breakdown-card* request)
|
||||
:headers {"hx-push-url" (str "?" (normalize-query-params request))}))
|
||||
(defn invoice-total-card [request]
|
||||
(html-response
|
||||
(vendor-invoice-total-card* request)
|
||||
:headers {"hx-push-url" (str "?" (normalize-query-params request))}))
|
||||
|
||||
(def key->handler
|
||||
(apply-middleware-to-all-handlers
|
||||
{:company-expense-report page
|
||||
:company-expense-report-breakdown-card expense-breakdown-card
|
||||
:company-expense-report-invoice-total-card invoice-total-card}
|
||||
(fn [h]
|
||||
(-> h
|
||||
(wrap-schema-enforce :query-schema
|
||||
[:map {:default {}}
|
||||
[:start-date {:optional true}
|
||||
[:maybe clj-date-schema]]
|
||||
[:end-date {:optional true}
|
||||
[:maybe clj-date-schema]]
|
||||
[:vendor-id {:optional true}
|
||||
[:maybe
|
||||
[:entity-map {:pull [:vendor/name :db/id]}]]]
|
||||
[:account-id {:optional true}
|
||||
[:maybe
|
||||
[:entity-map {:pull [:account/name :db/id]}]]]])))))
|
||||
@@ -71,7 +71,7 @@
|
||||
[:div.fixed.inset-0.lg:hidden {:x-show "leftNavShow" :x-transition:enter "transition duration-500" :x-transition:enter-start "opacity-0" :x-transition:enter-end "opacity-100"
|
||||
:x-transition:leave "transition duration-500" :x-transition:leave-start "opacity-100" :x-transition:leave-end "opacity-0"
|
||||
"@click.capture.prevent" "leftNavShow=false"}
|
||||
[:div.fixed.inset-0.bg-gray-800.z-10.opacity-70]]]
|
||||
[:div.fixed.inset-0.bg-gray-800.z-100.opacity-70]]]
|
||||
|
||||
[:div {:class "overflow-y-auto py-5 px-3 h-full bg-gray-50 border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700"}
|
||||
nav
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
(defn data-grid- [{:keys [headers thead-params id] :as params} & rest]
|
||||
[:table (merge {:class "w-full text-sm text-left text-gray-500 dark:text-gray-400"}
|
||||
(dissoc params :headers :thead-params))
|
||||
[:thead (assoc thead-params :class "text-xs text-gray-800 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400")
|
||||
[:thead (update thead-params :class #(-> "text-xs text-gray-800 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"
|
||||
(hh/add-class (or % ""))))
|
||||
(into
|
||||
[:tr]
|
||||
headers)]
|
||||
|
||||
@@ -86,7 +86,8 @@
|
||||
:delete :company-reports-delete}
|
||||
"/table" :company-reports-table
|
||||
"/expense" {:get :company-expense-report
|
||||
"/card" :company-expense-report-card}}
|
||||
"/card" :company-expense-report-breakdown-card
|
||||
"/invoice-total-card" :company-expense-report-invoice-total-card}}
|
||||
"/yodlee" {"" {:get :company-yodlee}
|
||||
"/table" {:get :company-yodlee-table}
|
||||
"/fastlink" {:get :company-yodlee-fastlink-dialog}
|
||||
|
||||
Reference in New Issue
Block a user