7 Commits

Author SHA1 Message Date
55650c2dab Merge pull request 'refactor(charts): unify on Chart.js, remove Chartist' (#11) from integreat-unify-charts into staging
Reviewed-on: #11
2026-06-02 09:23:29 -07:00
19186097d5 fix(ssr): stop content-card forcing always-on scrollbars; add tmp/ scratch dir
content-card used `overflow-scroll`, which renders scrollbar tracks even
when the content fits — visible as superfluous bars around the admin chart
cards. Switch to `overflow-auto` so scrollbars only appear when content
genuinely overflows (e.g. wide data tables still scroll).

Also add a gitignored ./tmp/ scratch directory (tracked via .gitkeep) and
document in AGENTS.md that temp files belong there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:16:16 -07:00
1f6395382d refactor(charts): unify on Chart.js, remove Chartist
The admin page was the only consumer of Chartist while the dashboard and
expense report already use Chart.js. Convert the admin "Growth in clients"
(bar) and "Changes by hour" (line) charts to Chart.js using the same
Alpine x-data/x-init canvas pattern as the dashboard, and drop the global
Chartist CSS/JS includes from the base page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 07:55:47 -07:00
d52159637e fixes 2026-06-02 07:15:42 -07:00
3648597031 update 2026-06-02 07:14:37 -07:00
901d9eb508 date-choosing 2026-06-02 07:13:29 -07:00
569e52d1c1 Merge pull request 'feat(transactions): port manual bank-transaction import to SSR' (#9) from integreat-add-transaction-manual into staging
Reviewed-on: #9
2026-06-01 21:06:52 -07:00
9 changed files with 287 additions and 238 deletions

3
.gitignore vendored
View File

@@ -51,3 +51,6 @@ sysco-poller/**/*.csv
.tmp/**
playwright-report/**
test-results/**
# Scratch dir for temp files (screenshots, logs, etc.); keep the dir, ignore contents
/tmp/*
!/tmp/.gitkeep

View File

@@ -1,5 +1,9 @@
# Integreat Development Guide
## Temporary Files
Write any temporary files (screenshots, scratch logs, generated artifacts, etc.) to the `./tmp/` directory at the repo root. Its contents are gitignored (only `.gitkeep` is tracked), so nothing there will be accidentally committed. Do not scatter temp files elsewhere in the repo or in the system `/tmp`.
## Build & Run Commands
### Build

File diff suppressed because one or more lines are too long

View File

@@ -333,7 +333,8 @@
(iol-ion.tx.upsert-sales-summary-ledger/upsert-sales-summary (dc/db conn) {:db/id 17592314241429})
(mark-all-dirty 5)
(mark-all-dirty 14)
(delete-all)
(sales-summaries-v2)

View File

@@ -10,8 +10,7 @@
[bidi.bidi :as bidi]
[clj-time.coerce :as coerce]
[clj-time.core :as time]
[datomic.api :as dc]
[hiccup2.core :as hiccup]))
[datomic.api :as dc]))
(defn hourly-changes []
(let [tx-instant-attr (:db/id (dc/pull (dc/db conn) '[:db/id] :db/txInstant))
@@ -56,34 +55,68 @@
[:div
[:h1.text-2xl.mb-3.font-bold "Growth in clients"]
[:div
[:div {:class "w-full h-64"
:id "client-chart"
:data-chart (hx/json {:labels ["2 years ago" "1 year ago" "today"],
:series [(for [n [2 1 0]
:let [start (time/plus (time/now) (time/years (- n)))]]
(->> (dc/q '[:find (count ?c)
:in $
:where [?c :client/code]]
(dc/as-of (dc/db conn) (coerce/to-date start)))
first
first))]})}]
[:script {:lang "javascript"}
(hiccup/raw
"new Chartist.Bar('#client-chart', JSON.parse(document.getElementById('client-chart').getAttribute('data-chart')))")]]]])
[:div.w-full.h-64
[:canvas.w-full.h-full {:x-data (hx/json {:chart nil
:labels ["2 years ago" "1 year ago" "today"]
:data (for [n [2 1 0]
:let [start (time/plus (time/now) (time/years (- n)))]]
(->> (dc/q '[:find (count ?c)
:in $
:where [?c :client/code]]
(dc/as-of (dc/db conn) (coerce/to-date start)))
first
first))})
:x-init "new Chart($el, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Clients',
data: data,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});"}]]]]])
(com/content-card {:class "w-1/2"}
[:div {:class "flex flex-col px-4 py-3 space-y-3"}
[:div
[:h1.text-2xl.mb-3.font-bold "Changes by hour"]
[:div
[:div {:class "w-full h-64"
:id "changes"
:data-chart (hx/json {:labels (for [n (range -24 0)]
(format "%d" n)),
:series [(hourly-changes)]})}]
[:script {:lang "javascript"}
(hiccup/raw
"new Chartist.Line('#changes', JSON.parse(document.getElementById('changes').getAttribute('data-chart')))")]]]])])
[:div.w-full.h-64
[:canvas.w-full.h-full {:x-data (hx/json {:chart nil
:labels (for [n (range -24 0)]
(format "%d" n))
:data (hourly-changes)})
:x-init "new Chart($el, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Changes',
data: data,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});"}]]]]])])
"Admin"))
(def key->handler

View File

@@ -14,5 +14,5 @@
[:section (merge params {:class (hh/add-class " py-3 sm:py-5" (:class params))})
[:div {:class (:max-w params "max-w-screen-2xl")}
(into
[:div {:class "relative overflow-scroll shadow-md dark:bg-gray-800 sm:rounded-lg border-2 border-gray-200 dark:border-gray-900 bg-white"}]
[:div {:class "relative overflow-auto shadow-md dark:bg-gray-800 sm:rounded-lg border-2 border-gray-200 dark:border-gray-900 bg-white"}]
children)]])

View File

@@ -11,10 +11,10 @@
[auto-ap.routes.transactions :as transaction-routes]
[auto-ap.ssr-routes :as ssr-routes]
[auto-ap.ssr.components :as com]
[auto-ap.ssr.components.date-range :as dr]
[auto-ap.ssr.components.link-dropdown :refer [link-dropdown]]
[auto-ap.ssr.grid-page-helper :as helper]
[auto-ap.ssr.hx :as hx]
[auto-ap.ssr.pos.common :refer [date-range-field*]]
[auto-ap.ssr.svg :as svg]
[auto-ap.ssr.utils
:refer [clj-date-schema entity-id html-response ref->enum-schema
@@ -31,7 +31,7 @@
(defn exact-match-id* [request]
(if (nat-int? (:exact-match-id (:query-params request)))
[:div {:x-data (hx/json {:exact_match (:exact-match-id (:query-params request))}) :id "exact-match-id-tag"}
[:div {:x-data (hx/json {:exact_match (:exact-match-id (:query-params request))}) :id "exact-match-id-tag" :class "filter-trigger"}
(com/hidden {:name "exact-match-id"
"x-model" "exact_match"})
(com/pill {:color :primary}
@@ -46,13 +46,14 @@
[:div {:hx-trigger "clientSelected from:body"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::route/bank-account-filter)
:hx-target "this"
:hx-swap "outerHTML"}
:hx-swap "outerHTML"
:class "filter-trigger"}
(when (:client request)
(let [bank-account-belongs-to-client? (get (set (map :db/id (:client/bank-accounts (:client request))))
(:db/id (:bank-account (:query-params request))))]
(com/field {:label "Bank Account"}
(com/radio-card {:size :small
:name "bank-account"
(com/radio-card {:size :small
:name "bank-account"
:value (or (when bank-account-belongs-to-client?
(:db/id (:bank-account (:query-params request))))
"")
@@ -60,90 +61,96 @@
(into [{:value ""
:content "All"}]
(for [ba (:client/bank-accounts (:client request))]
{:value (:db/id ba)
{:value (:db/id ba)
:content (:bank-account/name ba)}))}))))])
(defn bank-account-filter [request]
(html-response (bank-account-filter* request)))
(defn filters [request]
[:form#ledger-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
::route/table)
"hx-target" "#entity-table"
[:form#ledger-filters {"hx-trigger" "datesApplied, change delay:500ms from:.filter-trigger, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
::route/table)
"hx-target" "#entity-table"
"hx-indicator" "#entity-table"}
(com/hidden {:name "status"
:value (some-> (:status (:query-params request)) name)})
[:fieldset.space-y-6
(com/field {:label "Vendor"}
(com/typeahead {:name "vendor"
:id "vendor"
(com/typeahead {:name "vendor"
:id "vendor"
:url (bidi/path-for ssr-routes/only-routes :vendor-search)
:value (:vendor (:query-params request))
:value (:vendor (:query-params request))
:value-fn :db/id
:content-fn :vendor/name}))
:content-fn :vendor/name
:class "filter-trigger"}))
(com/field {:label "Account"}
(com/typeahead {:name "account"
:id "account"
(com/typeahead {:name "account"
:id "account"
:url (bidi/path-for ssr-routes/only-routes :account-search)
:value (:account (:query-params request))
:value (:account (:query-params request))
:value-fn :db/id
:content-fn #(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read (:db/id %))
(:db/id (:client request))))}))
(:db/id (:client request))))
:class "filter-trigger"}))
(bank-account-filter* request)
(date-range-field* request)
(dr/date-range-field {:value {:start (:start-date (:query-params request))
:end (:end-date (:query-params request))}
:id "date-range"
:apply-button? true})
(com/field {:label "Invoice #"}
(com/text-input {:name "invoice-number"
:id "invoice-number"
:class "hot-filter"
:value (:invoice-number (:query-params request))
(com/text-input {:name "invoice-number"
:id "invoice-number"
:class "hot-filter"
:value (:invoice-number (:query-params request))
:placeholder "e.g., ABC-456"
:size :small}))
:size :small}))
(com/field {:label "Account Code"}
[:div.flex.space-x-4.items-baseline
(com/int-input {:name "numeric-code-gte"
:id "numeric-code-gte"
(com/int-input {:name "numeric-code-gte"
:id "numeric-code-gte"
:hx-preserve "true"
:class "hot-filter w-20"
:value (:numeric-code-gte (:query-params request))
:class "hot-filter w-20"
:value (:numeric-code-gte (:query-params request))
:placeholder "40000"
:size :small})
:size :small})
[:div.align-baseline
"to"]
(com/int-input {:name "numeric-code-lte"
(com/int-input {:name "numeric-code-lte"
:hx-preserve "true"
:id "numeric-code-lte"
:class "hot-filter w-20"
:value (:numeric-code-lte (:query-params request))
:id "numeric-code-lte"
:class "hot-filter w-20"
:value (:numeric-code-lte (:query-params request))
:placeholder "50000"
:size :small})])
:size :small})])
(com/field {:label "Amount"}
[:div.flex.space-x-4.items-baseline
(com/money-input {:name "amount-gte"
:id "amount-gte"
(com/money-input {:name "amount-gte"
:id "amount-gte"
:hx-preserve "true"
:class "hot-filter w-20"
:value (:amount-gte (:query-params request))
:class "hot-filter w-20"
:value (:amount-gte (:query-params request))
:placeholder "0.01"
:size :small})
:size :small})
[:div.align-baseline
"to"]
(com/money-input {:name "amount-lte"
(com/money-input {:name "amount-lte"
:hx-preserve "true"
:id "amount-lte"
:class "hot-filter w-20"
:value (:amount-lte (:query-params request))
:id "amount-lte"
:class "hot-filter w-20"
:value (:amount-lte (:query-params request))
:placeholder "9999.34"
:size :small})])
[:div.mt-4 {:x-data (hx/json {:onlyUnbalanced (:only-unbalanced (:query-params request))})}
:size :small})])
[:div.mt-4 {:x-data (hx/json {:onlyUnbalanced (:only-unbalanced (:query-params request))})}
(com/hidden {:name "only-unbalanced"
":value" "onlyUnbalanced ? 'on' : ''"})
(com/checkbox {:value (:only-unbalanced (:query-params request))
:class "filter-trigger"
:x-model "onlyUnbalanced"}
"Show unbalanced")]
(exact-match-id* request)]])
@@ -184,12 +191,12 @@
args query-params
query
(if (:exact-match-id args)
{:query {:find '[?e]
:in '[$ ?e [?c ...]]
{:query {:find '[?e]
:in '[$ ?e [?c ...]]
:where '[[?e :journal-entry/client ?c]]}
:args [db
(:exact-match-id args)
valid-clients]}
:args [db
(:exact-match-id args)
valid-clients]}
(cond-> {:query {:find []
:in ['$ '[?clients ?start ?end]]
:where '[[(iol-ion.query/scan-ledger $ ?clients ?start ?end) [[?e _ ?sort-default] ...]]]}
@@ -202,28 +209,28 @@
(merge-query {:query {:where ['(not [?e :journal-entry/original-entity])]}})
(seq (:external-id-like args))
(merge-query {:query {:in ['?external-id-like]
(merge-query {:query {:in ['?external-id-like]
:where ['[?e :journal-entry/external-id ?external-id]
'[(.contains ^String ?external-id ?external-id-like)]]}
:args [(:external-id-like args)]})
:args [(:external-id-like args)]})
(seq (:source args))
(merge-query {:query {:in ['?source]
(merge-query {:query {:in ['?source]
:where ['[?e :journal-entry/source ?source]]}
:args [(:source args)]})
:args [(:source args)]})
(:external? route-params)
(merge-query {:query {:where ['[?e :journal-entry/external-id]]}})
(:vendor args)
(merge-query {:query {:in ['?vendor-id]
(merge-query {:query {:in ['?vendor-id]
:where ['[?e :journal-entry/vendor ?vendor-id]]}
:args [(:db/id (:vendor args))]})
:args [(:db/id (:vendor args))]})
(:invoice-number args)
(merge-query {:query {:in ['?invoice-number]
(merge-query {:query {:in ['?invoice-number]
:where ['[?e :journal-entry/original-entity ?oe]
'[?oe :invoice/invoice-number ?invoice-number]]}
:args [(:invoice-number args)]})
:args [(:invoice-number args)]})
(or (:numeric-code-lte args)
(:numeric-code-gte args)
@@ -235,77 +242,77 @@
(or (:numeric-code-gte args)
(:numeric-code-lte args))
(merge-query {:query {:in '[?from-numeric-code ?to-numeric-code]
(merge-query {:query {:in '[?from-numeric-code ?to-numeric-code]
:where ['[?li :journal-entry-line/account ?a]
'(or-join [?a ?c]
[?a :account/numeric-code ?c]
[?a :bank-account/numeric-code ?c])
'[(>= ?c ?from-numeric-code)]
'[(<= ?c ?to-numeric-code)]]}
:args [(or (:numeric-code-gte args) 0) (or (:numeric-code-lte args) 99999)]})
:args [(or (:numeric-code-gte args) 0) (or (:numeric-code-lte args) 99999)]})
(seq (:numeric-code args))
(merge-query {:query {:in '[[[?from-numeric-code ?to-numeric-code] ...]]
(merge-query {:query {:in '[[[?from-numeric-code ?to-numeric-code] ...]]
:where ['[?li :journal-entry-line/account ?a]
'(or-join [?a ?c]
[?a :account/numeric-code ?c]
[?a :bank-account/numeric-code ?c])
'[(>= ?c ?from-numeric-code)]
'[(<= ?c ?to-numeric-code)]]}
:args [(map (juxt :from :to) (:numeric-code args))]})
:args [(map (juxt :from :to) (:numeric-code args))]})
(seq (:account args))
(merge-query {:query {:in ['?a3]
(merge-query {:query {:in ['?a3]
:where ['[?li :journal-entry-line/account ?a3]]}
:args [(:db/id (:account args))]})
:args [(:db/id (:account args))]})
(:amount-gte args)
(merge-query {:query {:in ['?amount-gte]
(merge-query {:query {:in ['?amount-gte]
:where ['[?e :journal-entry/amount ?a]
'[(>= ?a ?amount-gte)]]}
:args [(:amount-gte args)]})
:args [(:amount-gte args)]})
(:amount-lte args)
(merge-query {:query {:in ['?amount-lte]
(merge-query {:query {:in ['?amount-lte]
:where ['[?e :journal-entry/amount ?a]
'[(<= ?a ?amount-lte)]]}
:args [(:amount-lte args)]})
:args [(:amount-lte args)]})
(:db/id (:bank-account args))
(merge-query {:query {:in ['?a]
(merge-query {:query {:in ['?a]
:where ['[?li :journal-entry-line/account ?a]]}
:args [(:db/id (:bank-account args))]})
:args [(:db/id (:bank-account args))]})
(:account-id args)
(merge-query {:query {:in ['?a2]
(merge-query {:query {:in ['?a2]
:where ['[?e :journal-entry/line-items ?li2]
'[?li2 :journal-entry-line/account ?a2]]}
:args [(:account-id args)]})
:args [(:account-id args)]})
(not-empty (:location args))
(merge-query {:query {:in ['?location]
(merge-query {:query {:in ['?location]
:where ['[?li :journal-entry-line/location ?location]]}
:args [(:location args)]})
:args [(:location args)]})
(not-empty (:locations args))
(merge-query {:query {:in ['[?location ...]]
(merge-query {:query {:in ['[?location ...]]
:where ['[?li :journal-entry-line/location ?location]]}
:args [(:locations args)]})
:args [(:locations args)]})
(:sort args) (add-sorter-fields {"client" ['[?e :journal-entry/client ?c]
'[?c :client/name ?sort-client]]
"date" ['[?e :journal-entry/date ?sort-date]]
"vendor" '[(or-join [?e ?sort-vendor]
(and
[?e :journal-entry/vendor ?v]
[?v :vendor/name ?sort-vendor])
(and [(missing? $ ?e :journal-entry/vendor)]
[(ground "") ?sort-vendor]))]
"amount" ['[?e :journal-entry/amount ?sort-amount]]
(:sort args) (add-sorter-fields {"client" ['[?e :journal-entry/client ?c]
'[?c :client/name ?sort-client]]
"date" ['[?e :journal-entry/date ?sort-date]]
"vendor" '[(or-join [?e ?sort-vendor]
(and
[?e :journal-entry/vendor ?v]
[?v :vendor/name ?sort-vendor])
(and [(missing? $ ?e :journal-entry/vendor)]
[(ground "") ?sort-vendor]))]
"amount" ['[?e :journal-entry/amount ?sort-amount]]
"external-id" ['[?e :journal-entry/external-id ?sort-external-id]]
"source" '[(or-join [?e ?sort-source]
[?e :journal-entry/source ?sort-source]
(and [(missing? $ ?e :journal-entry/source)]
[(ground "") ?sort-source]))]}
"source" '[(or-join [?e ?sort-source]
[?e :journal-entry/source ?sort-source]
(and [(missing? $ ?e :journal-entry/source)]
[(ground "") ?sort-source]))]}
args)
true
@@ -334,11 +341,11 @@
:journal-entry/external-id
:db/id
[:journal-entry/date :xform clj-time.coerce/from-date]
{:journal-entry/vendor [:vendor/name :db/id]
{:journal-entry/vendor [:vendor/name :db/id]
:journal-entry/original-entity [:invoice/invoice-number
:invoice/source-url
:transaction/description-original :db/id]
:journal-entry/client [:client/name :client/code :db/id]
:journal-entry/client [:client/name :client/code :db/id]
:journal-entry/line-items [:journal-entry-line/debit
:journal-entry-line/location
:journal-entry-line/running-balance
@@ -362,8 +369,8 @@
(defn sum-outstanding [ids]
(->>
(dc/q {:find ['?id '?o]
:in ['$ '[?id ...]]
(dc/q {:find ['?id '?o]
:in ['$ '[?id ...]]
:where ['[?id :invoice/outstanding-balance ?o]]}
(dc/db conn)
ids)
@@ -375,8 +382,8 @@
(defn sum-total-amount [ids]
(->>
(dc/q {:find ['?id '?o]
:in ['$ '[?id ...]]
(dc/q {:find ['?id '?o]
:in ['$ '[?id ...]]
:where ['[?id :invoice/total ?o]]}
(dc/db conn)
ids)
@@ -386,7 +393,7 @@
0.0)))
(defn fetch-page [request]
(let [db (dc/db conn)
(let [db (dc/db conn)
{ids-to-retrieve :ids matching-count :count
all-ids :all-ids} (fetch-ids db request)]
@@ -410,12 +417,12 @@
(if account-name
[:div {:x-tooltip (hx/json (str "Running Balance: " (some->> (:journal-entry-line/running-balance jel)
(format "$%,.2f"))))}
[:div.text-left.underline.cursor-pointer {:x-ref "source"}
[:div.text-left.underline.cursor-pointer {:x-ref "source"}
(:journal-entry-line/location jel) ": "
(or (:account/numeric-code account) (:bank-account/numeric-code account))
" - " account-name]]
[:div.text-left (com/pill {:color :yellow} "Unassigned")])
[:div.text-right.text-underline (format "$%,.2f" (key jel))]))
[:div.text-right.text-underline (format "$%,.2f" (key jel))]))
(when-not (= 1 (count lines))
[:div.col-span-2 (com/pill {:color :primary} "Total: " (->> lines
@@ -443,9 +450,9 @@
[:to nat-int?]]]]]
[:numeric-code-gte {:optional true} [:maybe nat-int?]]
[:numeric-code-lte {:optional true} [:maybe nat-int?]]
[:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]]
[:bank-account {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :bank-account/name]}]]]
[:account {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :account/name]}]]]
[:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]]
[:bank-account {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :bank-account/name]}]]]
[:account {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :account/name]}]]]
[:check-number {:optional true} [:maybe [:string {:decode/string strip}]]]
[:invoice-number {:optional true} [:maybe [:string {:decode/string strip}]]]
[:status {:optional true} [:maybe (ref->enum-schema "invoice-status")]]
@@ -459,17 +466,20 @@
[:maybe clj-date-schema]]]]))
(def grid-page
(helper/build {:id "entity-table"
:nav com/main-aside-nav
(helper/build {:id "entity-table"
:nav com/main-aside-nav
:check-boxes? true
:check-box-warning? (fn [e]
(some? (:invoice/scheduled-payment e)))
:page-specific-nav filters
:fetch-page fetch-page
:page-specific-nav filters
:fetch-page fetch-page
:oob-render
(fn [request]
[(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)
(assoc-in (exact-match-id* request) [1 :hx-swap-oob] true)])
[(assoc-in (dr/date-range-field {:value {:start (:start-date (:query-params request))
:end (:end-date (:query-params request))}
:id "date-range"
:apply-button? true}) [1 :hx-swap-oob] true)
(assoc-in (exact-match-id* request) [1 :hx-swap-oob] true)])
:query-schema query-schema
:action-buttons (fn [request]
[(when-not (:external? (:route-params request)) (com/button {:color :primary
@@ -485,7 +495,7 @@
:hx-confirm "Are you sure you want to void this invoice?"}
svg/trash))
(when (and (can? (:identity request) {:subject :invoice :activity :edit})
(#{:invoice-status/unpaid :invoice-status/paid} (:invoice/status entity)))
(#{:invoice-status/unpaid :invoice-status/paid} (:invoice/status entity)))
(com/icon-button {:hx-put (bidi/path-for ssr-routes/only-routes
::route/edit-wizard
:db/id (:db/id entity))}
@@ -497,14 +507,14 @@
:db/id (:db/id entity))}
svg/undo))])
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes ::route/page)}
"Ledger"]]
:title (fn [r]
(str
(some-> r :route-params :status name str/capitalize (str " "))
"Register"))
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes ::route/page)}
"Ledger"]]
:title (fn [r]
(str
(some-> r :route-params :status name str/capitalize (str " "))
"Register"))
:entity-name "register"
:route ::route/table
:route ::route/table
:csv-route ::route/csv
:break-table (fn [request entity]
(cond
@@ -521,102 +531,102 @@
(for [je journal-entries
jel (:journal-entry/line-items je)]
(merge jel je)))
:headers [{:key "id"
:name "Id"
:render-csv :db/id
:render-for #{:csv}}
{:key "client"
:name "Client"
:sort-key "client"
:hide? (fn [args]
(and (= (count (:clients args)) 1)
(= 1 (count (:client/locations (:client args))))))
:render (fn [x] [:div.flex.items-center.gap-2 (-> x :journal-entry/client :client/name)])
:render-csv (fn [x] (-> x :journal-entry/client :client/name))}
:headers [{:key "id"
:name "Id"
:render-csv :db/id
:render-for #{:csv}}
{:key "client"
:name "Client"
:sort-key "client"
:hide? (fn [args]
(and (= (count (:clients args)) 1)
(= 1 (count (:client/locations (:client args))))))
:render (fn [x] [:div.flex.items-center.gap-2 (-> x :journal-entry/client :client/name)])
:render-csv (fn [x] (-> x :journal-entry/client :client/name))}
{:key "vendor"
:name "Vendor"
:sort-key "vendor"
:render (fn [e] (or (-> e :journal-entry/vendor :vendor/name)
[:span.italic.text-gray-400 (-> e :journal-entry/alternate-description)]))
:render-csv (fn [e] (or (-> e :journal-entry/vendor :vendor/name)
(-> e :journal-entry/alternate-description)))}
{:key "source"
:name "Source"
:sort-key "source"
:hide? (fn [args]
(not (:external? (:route-params args))))
:render :journal-entry/source
:render-csv :journal-entry/source}
{:key "external-id"
:name "External Id"
:sort-key "external-id"
:class "max-w-[12rem]"
:hide? (fn [args]
(not (:external? (:route-params args))))
:render (fn [x] [:p.truncate (:journal-entry/external-id x)])
:render-csv :journal-entry/external-id}
{:key "date"
:sort-key "date"
:name "Date"
:show-starting "lg"
:render (fn [{:journal-entry/keys [date]}]
(some-> date (atime/unparse-local atime/normal-date)))}
{:key "amount"
:sort-key "amount"
:name "Amount"
:show-starting "lg"
:render (fn [{:journal-entry/keys [amount]}]
(some->> amount
(format "$%,.2f")))}
{:key "account"
:name "Account"
:sort-key "account"
:class "text-right"
:render-csv #(or (-> % :journal-entry-line/account :account/name)
(-> % :journal-entry-line/account :bank-account/name))
:render-for #{:csv}}
{:key "debit"
:name "Debit"
:class "text-right"
:render (partial render-lines :journal-entry-line/debit)
:render-csv :journal-entry-line/debit}
{:key "vendor"
:name "Vendor"
:sort-key "vendor"
:render (fn [e] (or (-> e :journal-entry/vendor :vendor/name)
[:span.italic.text-gray-400 (-> e :journal-entry/alternate-description)]))
:render-csv (fn [e] (or (-> e :journal-entry/vendor :vendor/name)
(-> e :journal-entry/alternate-description)))}
{:key "source"
:name "Source"
:sort-key "source"
:hide? (fn [args]
(not (:external? (:route-params args))))
:render :journal-entry/source
:render-csv :journal-entry/source}
{:key "external-id"
:name "External Id"
:sort-key "external-id"
:class "max-w-[12rem]"
:hide? (fn [args]
(not (:external? (:route-params args))))
:render (fn [x] [:p.truncate (:journal-entry/external-id x)])
:render-csv :journal-entry/external-id}
{:key "date"
:sort-key "date"
:name "Date"
:show-starting "lg"
:render (fn [{:journal-entry/keys [date]}]
(some-> date (atime/unparse-local atime/normal-date)))}
{:key "amount"
:sort-key "amount"
:name "Amount"
:show-starting "lg"
:render (fn [{:journal-entry/keys [amount]}]
(some->> amount
(format "$%,.2f")))}
{:key "account"
:name "Account"
:sort-key "account"
:class "text-right"
:render-csv #(or (-> % :journal-entry-line/account :account/name)
(-> % :journal-entry-line/account :bank-account/name))
:render-for #{:csv}}
{:key "debit"
:name "Debit"
:class "text-right"
:render (partial render-lines :journal-entry-line/debit)
:render-csv :journal-entry-line/debit}
{:key "credit"
:name "Credit"
:class "text-right"
:render (partial render-lines :journal-entry-line/credit)
:render-csv :journal-entry-line/credit}
{:key "credit"
:name "Credit"
:class "text-right"
:render (partial render-lines :journal-entry-line/credit)
:render-csv :journal-entry-line/credit}
{:key "links"
:name "Links"
:show-starting "lg"
:class "w-8"
:render (fn [i]
(link-dropdown
(cond-> []
(-> i :journal-entry/original-entity :invoice/invoice-number)
(conj
{:link (hu/url (bidi/path-for ssr-routes/only-routes
::invoice-route/all-page)
{:exact-match-id (:db/id (:journal-entry/original-entity i))})
:color :primary
:content (format "Invoice '%s'" (-> i :journal-entry/original-entity :invoice/invoice-number))})
(-> i :journal-entry/original-entity :invoice/source-url)
{:link (-> i :journal-entry/original-entity :invoice/source-url)
:color :secondary
:content (str "File")}
{:key "links"
:name "Links"
:show-starting "lg"
:class "w-8"
:render (fn [i]
(link-dropdown
(cond-> []
(-> i :journal-entry/original-entity :invoice/invoice-number)
(conj
{:link (hu/url (bidi/path-for ssr-routes/only-routes
::invoice-route/all-page)
{:exact-match-id (:db/id (:journal-entry/original-entity i))})
:color :primary
:content (format "Invoice '%s'" (-> i :journal-entry/original-entity :invoice/invoice-number))})
(-> i :journal-entry/original-entity :invoice/source-url)
{:link (-> i :journal-entry/original-entity :invoice/source-url)
:color :secondary
:content (str "File")}
(-> i :journal-entry/original-entity :transaction/description-original)
(conj
{:link (hu/url (bidi/path-for ssr-routes/only-routes
::transaction-routes/all-page)
{:exact-match-id (:db/id (:journal-entry/original-entity i))})
:color :primary
:content (format "Transaction '%s'" (-> i :journal-entry/original-entity :transaction/description-original))})
(-> i :journal-entry/memo)
(conj {:color :secondary
:content (str "Memo: " (:journal-entry/memo i))}))))
:render-for #{:html}}]}))
(-> i :journal-entry/original-entity :transaction/description-original)
(conj
{:link (hu/url (bidi/path-for ssr-routes/only-routes
::transaction-routes/all-page)
{:exact-match-id (:db/id (:journal-entry/original-entity i))})
:color :primary
:content (format "Transaction '%s'" (-> i :journal-entry/original-entity :transaction/description-original))})
(-> i :journal-entry/memo)
(conj {:color :secondary
:content (str "Memo: " (:journal-entry/memo i))}))))
:render-for #{:html}}]}))
(def row* (partial helper/row* grid-page))

View File

@@ -23,8 +23,6 @@
[: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 "//cdn.jsdelivr.net/chartist.js/latest/chartist.min.css"}]
[:script {:src "//cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"}]
[:link {:rel "stylesheet", :href "/output.css"}]
[:script {:src "https://cdn.plaid.com/link/v2/stable/link-initialize.js"}]
[:script {:src "https://cdn.jsdelivr.net/npm/@ryangjchandler/alpine-tooltip@1.x.x/dist/cdn.min.js" :defer true}]

0
tmp/.gitkeep Normal file
View File