Addes expense report card
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -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"}
|
||||||
|
|||||||
@@ -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)))))
|
||||||
@@ -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")))))
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user