Addes expense report card

This commit is contained in:
2024-04-29 20:08:11 -07:00
parent cb5028948e
commit 8afbc124c4
4 changed files with 111 additions and 87 deletions

File diff suppressed because one or more lines are too long

View File

@@ -99,74 +99,87 @@
(defn expense-breakdown-card* [request] (defn expense-breakdown-card* [request]
(com/content-card {:class "w-full" :id "expense-breakdown-report"} (com/card {:class "w-full h-full" :id "expense-breakdown-report"}
[:div {:class "flex flex-col px-8 py-8 space-y-3"} [:div {:class "flex flex-col px-8 py-8 space-y-3 w-full h-full"}
[:div
[: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 "#expense-breakdown-report"
:hx-swap "outerHTML"}
(fc/start-form
(:query-params request)
(:form-errors request)
[:div
(fc/with-field :vendor-id
(com/validated-field {:label "Vendor"
:errors (fc/field-errors)}
(com/typeahead {:name (fc/field-name)
:class "w-64"
:url (bidi/path-for ssr-routes/only-routes :vendor-search)
:value (fc/field-value)
:value-fn :db/id
:content-fn :vendor/name})))
(fc/with-field :account-id
(com/validated-field {:label "Account"
:errors (fc/field-errors)}
(com/typeahead {:name (fc/field-name)
:class "w-64"
:url (bidi/path-for ssr-routes/only-routes :account-search)
:value (fc/field-value)
:value-fn :db/id
:content-fn :account/name})))])]
[:div
(let [data (lookup-breakdown-data request)
distinct-accounts (take 5 (->> data
(reduce
(fn [acc [an _ amount]]
(update acc an (fnil + 0.0) amount))
{})
(sort-by last)
(reverse)
(map first)
(take 5)))
weeks (week-seq 8)
x-axis (for [[start end] weeks]
(str (iol-ion.query/excel-date (coerce/to-date start))
" - "
(iol-ion.query/excel-date (coerce/to-date end))))
lookup (->> [:form {:hx-get (bidi.bidi/path-for ssr-routes/only-routes :company-expense-report-breakdown-card)
(reduce :hx-trigger "change"
(fn [acc [a d v]] :hx-target "#expense-breakdown-report"
(update-in acc [a (best-week d weeks)] (fnil + 0.0) v)) :hx-swap "outerHTML"}
{} (fc/start-form
data)) (:query-params request)
(:form-errors request)
[:div.flex.justify-between
[:h1.text-2xl.mb-3.font-bold "Expense breakdown report, last 8 weeks"]
[:div.flex.gap-2
(fc/with-field :vendor-id
(com/validated-field {:label "Vendor"
:errors (fc/field-errors)}
(com/typeahead {:name (fc/field-name)
:class "w-64"
:url (bidi/path-for ssr-routes/only-routes :vendor-search)
:value (fc/field-value)
:value-fn :db/id
:content-fn :vendor/name})))
(fc/with-field :account-id
(com/validated-field {:label "Account"
:errors (fc/field-errors)}
(com/typeahead {:name (fc/field-name)
:class "w-64"
:url (bidi/path-for ssr-routes/only-routes :account-search)
:value (fc/field-value)
:value-fn :db/id
:content-fn :account/name})))]])]
[:div.flex-grow
(let [data (lookup-breakdown-data request)
distinct-accounts (->> data
(reduce
(fn [acc [an _ amount]]
(update acc an (fnil + 0.0) amount))
{})
(sort-by last)
(reverse)
(map first)
(take 20))
weeks (week-seq 8)
x-axis (for [[start end] weeks]
(str (iol-ion.query/excel-date (coerce/to-date start))
" - "
(iol-ion.query/excel-date (coerce/to-date end))))
_ (alog/peek ::Lookup lookup) lookup (->>
series (for [ea distinct-accounts] (reduce
(for [d weeks] (fn [acc [a d v]]
(get-in lookup [ea d] 0)))] (update-in acc [a (best-week d weeks)] (fnil + 0.0) v))
(list {}
[:div.flex.gap-2.my-4.flex-wrap data))
(for [[d color] (map vector distinct-accounts ["bg-green-500" "bg-red-500" "bg-blue-500" "bg-yellow-500" "bg-purple-500"])] series (for [ea distinct-accounts]
[:span.px-2.py-1.rounded.rounded-full.text-sm.text-gray-100 {:class color} d])] (for [d weeks]
[:div {:class "w-full h-64" (get-in lookup [ea d] 0)))]
:id "client-chart" [:canvas {:x-data (hx/json {:chart nil
:x-data (hx/json {:chart {:labels x-axis :labels x-axis
#_["2 years ago" "1 year ago" "today"], :datasets (map (fn [s a] {:label a
:series (alog/peek ::test series)}}) :data s
:x-init (hiccup/raw "new Chartist.Bar($el, chart, {seriesBarDistance:10}); ")}]))]]])) :borderWidth 1})
series
distinct-accounts)})
:x-init
"new Chart($el, {
type: 'bar',
data: {
labels: labels,
datasets: datasets
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});"}])]]))
(defn vendor-invoice-total-card* [request] (defn vendor-invoice-total-card* [request]
(com/content-card {:class "w-full" :id "invoice-totals-report"} (com/content-card {:class "w-full" :id "invoice-totals-report"}

View File

@@ -9,6 +9,7 @@
[auto-ap.routes.utils :refer [wrap-admin [auto-ap.routes.utils :refer [wrap-admin
wrap-client-redirect-unauthenticated]] wrap-client-redirect-unauthenticated]]
[auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr-routes :as ssr-routes]
[auto-ap.ssr.company.reports.expense :refer [expense-breakdown-card]]
[auto-ap.ssr.components :as com] [auto-ap.ssr.components :as com]
[auto-ap.ssr.hiccup-helper :as hh] [auto-ap.ssr.hiccup-helper :as hh]
[auto-ap.ssr.hx :as hx] [auto-ap.ssr.hx :as hx]
@@ -26,11 +27,10 @@
(defn bank-accounts-card [request] (defn bank-accounts-card [request]
(html-response (html-response
(com/card {:class "inline-block " } (com/card {:class "h-full"}
[:div.p-4 [:div.p-4.h-full
[:h1.text-2xl.font-bold "Bank Accounts"] [:h1.text-2xl.font-bold "Bank Accounts"]
[:div (hx/alpine-mount-then-appear {:class "max-h-[900px] overflow-scroll" [:div (hx/htmx-transition-appear {:class "h-full overflow-scroll" })
:data-key "show"})
(for [c (:valid-trimmed-client-ids request) (for [c (:valid-trimmed-client-ids request)
b (:client/bank-accounts (dc/pull (dc/db conn) '[{:client/bank-accounts b (:client/bank-accounts (dc/pull (dc/db conn) '[{:client/bank-accounts
@@ -218,10 +218,10 @@
(defn tasks-card [request] (defn tasks-card [request]
(html-response (html-response
(com/card {:class "w-full h-full p-4 space-y-2"} (com/card {:class "w-full h-full p-4"}
[:h1.text-2xl.font-bold.text-gray-700 [:h1.text-2xl.font-bold.text-gray-700
"Tasks"] "Tasks"]
[:div (hx/alpine-mount-then-appear {:data-key "show"}) [:div (hx/htmx-transition-appear {:class "space-y-2"})
(let [[unpaid-invoice-count unpaid-invoice-amount] (let [[unpaid-invoice-count unpaid-invoice-amount]
(first (dc/q '[:find (count ?e) (sum ?ab) (first (dc/q '[:find (count ?e) (sum ?ab)
:in $ [?clients ?start-date ?end-date] :in $ [?clients ?start-date ?end-date]
@@ -262,8 +262,7 @@
"?date-range=" "?date-range="
(url/url-encode (pr-str {:start (atime/unparse-local (time/plus (time/now) (time/years -1)) atime/iso-date) :end (atime/unparse-local (time/now) atime/iso-date)}))) } (url/url-encode (pr-str {:start (atime/unparse-local (time/plus (time/now) (time/years -1)) atime/iso-date) :end (atime/unparse-local (time/now) atime/iso-date)}))) }
"Review now") "Review now")])))])))
])))])))
(defn stub-card [params & children] (defn stub-card [params & children]
(com/card (-> params (com/card (-> params
@@ -276,30 +275,35 @@
[:div.htmx-indicator (svg/spinner {:class "inline w-32 h-32 text-green-500"})]])) [:div.htmx-indicator (svg/spinner {:class "inline w-32 h-32 text-green-500"})]]))
(defn- page-contents [request] (defn- page-contents [request]
[:div [:div.mb-8
[:div {:class "grid grid-cols-1 lg:grid-cols-2 2xl:grid-cols-3 gap-4 auto-rows-fr max-h-[970px]"} [:div {:class "grid grid-cols-1 lg:grid-cols-2 2xl:grid-cols-3 gap-4 mb-8"}
[:div (stub-card {:title "Expenses" [:div.h-96 (stub-card {:title "Expenses"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/expense-card) :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/expense-card)
:hx-trigger "load"} )] :hx-trigger "load"} )]
[:div [:div.h-96
(stub-card {:title "Tasks" (stub-card {:title "Tasks"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/tasks-card) :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/tasks-card)
:hx-trigger "load"} )] :hx-trigger "load"} )]
[:div.row-span-2 [:div {:class " row-span-2 h-[49rem]"}
(stub-card {:title "Bank Accounts" (stub-card {:title "Bank Accounts"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/bank-accounts-card) :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/bank-accounts-card)
:hx-trigger "load"} ) :hx-trigger "load"} )
] ]
[:div [:div.h-96
(stub-card {:title "Gross Sales, last 14 days" (stub-card {:title "Gross Sales, last 14 days"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/sales-card) :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/sales-card)
:hx-trigger "load"}) :hx-trigger "load"})
] ]
[:div [:div.h-96
(stub-card {:title "Profit and Loss, last month" (stub-card {:title "Profit and Loss, last month"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/pnl-card) :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/pnl-card)
:hx-trigger "load"}) ] ] ]) :hx-trigger "load"}) ]
[:div.col-span-2.h-96
(stub-card {:title "Expense breakdown"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes :company-expense-report-breakdown-card)
:hx-trigger "load"} )]
[:div]] ])
(defn page [request] (defn page [request]
(base-page (base-page
@@ -331,6 +335,6 @@
::d-routes/pnl-card pnl-card ::d-routes/pnl-card pnl-card
::d-routes/sales-card sales-chart-card ::d-routes/sales-card sales-chart-card
::d-routes/bank-accounts-card bank-accounts-card ::d-routes/bank-accounts-card bank-accounts-card
::d-routes/tasks-card tasks-card} ::d-routes/tasks-card tasks-card }
(fn [h] (fn [h]
(wrap-client-redirect-unauthenticated (wrap-admin h))))) (wrap-client-redirect-unauthenticated (wrap-admin h)))))

View File

@@ -1,6 +1,7 @@
(ns auto-ap.ssr.hx (ns auto-ap.ssr.hx
(:require [cheshire.core :as cheshire] (:require [cheshire.core :as cheshire]
[clojure.string :as str])) [clojure.string :as str]
[auto-ap.ssr.hiccup-helper :as hh]))
(defn vals [m] (defn vals [m]
@@ -53,3 +54,9 @@
(defn trigger-click-or-enter [m] (defn trigger-click-or-enter [m]
(assoc m :hx-trigger "click, keyup[keyCode==13]")) (assoc m :hx-trigger "click, keyup[keyCode==13]"))
(defn htmx-transition-appear [params]
(-> params
(update :class (fn [c]
(-> (or c "")
(hh/add-class "opacity-100 transition htmx-added:opacity-0 duration-300")))))
)