This commit is contained in:
2026-05-18 16:21:07 -07:00
parent a156ac99fe
commit baef2afc63

View File

@@ -133,6 +133,19 @@
(str (subs s 0 (- max-len 3)) "...") (str (subs s 0 (- max-len 3)) "...")
s)) s))
(defn account-typeahead*
[{:keys [name value client-id]}]
[:div.flex.flex-col
(com/typeahead {:name name
:placeholder "Search..."
:url (hu/url (bidi/path-for ssr-routes/only-routes :account-search)
{:client-id client-id
:purpose "invoice"})
:value value
:content-fn (fn [value]
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
client-id)))})])
(defn account-display-cell [{:keys [item field-name-prefix client-id]}] (defn account-display-cell [{:keys [item field-name-prefix client-id]}]
(let [account-id (:ledger-mapped/account item) (let [account-id (:ledger-mapped/account item)
account-name (when account-id account-name (when account-id
@@ -140,7 +153,7 @@
client-id)))] client-id)))]
[:div.account-cell.flex.items-center.gap-2 [:div.account-cell.flex.items-center.gap-2
(com/hidden {:name (str field-name-prefix "[ledger-mapped/account]") (com/hidden {:name (str field-name-prefix "[ledger-mapped/account]")
:value (or account-id "")}) :value (or account-id "")})
(if account-id (if account-id
[:span.text-sm account-name] [:span.text-sm account-name]
(com/pill {:color :red} "Missing acct")) (com/pill {:color :red} "Missing acct"))
@@ -157,22 +170,22 @@
[:div.account-cell.flex.flex-col.gap-2 [:div.account-cell.flex.flex-col.gap-2
(account-typeahead* {:name account-input-name (account-typeahead* {:name account-input-name
:value current-account-id :value current-account-id
:client-id client-id}) :client-id client-id}
[:div.flex.gap-1 [:div.flex.gap-1
(com/a-icon-button {:hx-put (bidi/path-for ssr-routes/only-routes ::route/save-item-account) (com/a-icon-button {:hx-put (bidi/path-for ssr-routes/only-routes ::route/save-item-account)
:hx-target "closest .account-cell" :hx-target "closest .account-cell"
:hx-swap "outerHTML" :hx-swap "outerHTML"
:hx-include "closest .account-cell" :hx-include "closest .account-cell"}
:hx-vals (hx/json {:field-name-prefix field-name-prefix :hx-vals (hx/json {:field-name-prefix field-name-prefix
:client-id client-id})} :client-id client-id})
svg/check) svg/check)
(com/a-icon-button {:hx-get (bidi/path-for ssr-routes/only-routes ::route/cancel-item-account) (com/a-icon-button {:hx-get (bidi/path-for ssr-routes/only-routes ::route/cancel-item-account)
:hx-target "closest .account-cell" :hx-target "closest .account-cell"
:hx-swap "outerHTML" :hx-swap "outerHTML"
:hx-vals (hx/json {:field-name-prefix field-name-prefix :hx-vals (hx/json {:field-name-prefix field-name-prefix}
:client-id client-id :client-id client-id
:current-account-id (or current-account-id "")})} :current-account-id (or current-account-id ""))}
svg/x)]])) svg/x)])]))
(def grid-page (def grid-page
(helper/build {:id "entity-table" (helper/build {:id "entity-table"
@@ -401,19 +414,19 @@
:step-params :step-params
:sales-summary/items :sales-summary/items
(total-debits))] (total-debits))]
[:div.flex.justify-between.text-sm.py-1.border-t.mt-1 [:div.flex.justify-between.text-sm.py-1.border-t.mt-1
{:id "total-display"} {:id "total-display"}]
[:span.font-semibold "Total"] [:span.font-semibold "Total"]
[:div.flex.gap-8 [:div.flex.gap-8
[:span.font-mono (format "$%,.2f" total-debits)] [:span.font-mono (format "$%,.2f" total-debits)]
[:span.font-mono (format "$%,.2f" total-credits)]]])) [:span.font-mono (format "$%,.2f" total-credits)]]))
(defn unbalanced-display [request] (defn unbalanced-display [request]
(let [total-credits (-> request (let [total-credits (-> request
:multi-form-state :multi-form-state
:step-params :step-params
:sales-summary/items :sales-summary/items
(total-credits)) (total-credits))
total-debits (-> request total-debits (-> request
:multi-form-state :multi-form-state
:step-params :step-params
@@ -422,24 +435,11 @@
delta (- total-debits total-credits)] delta (- total-debits total-credits)]
(when-not (dollars-0? delta) (when-not (dollars-0? delta)
[:div.flex.justify-between.text-sm.py-1 [:div.flex.justify-between.text-sm.py-1
{:id "unbalanced-display"} {:id "unbalanced-display"}
[:span.font-semibold.text-red-600 "Unbalanced"] [:span.font-semibold.text-red-600 "Unbalanced"]
[:div.flex.gap-8 [:div.flex.gap-8
[:span.font-mono (when (pos? delta) (format "$%,.2f" delta))] [:span.font-mono (when (pos? delta) (format "$%,.2f" delta))
[:span.font-mono (when (neg? delta) (format "$%,.2f" (Math/abs delta)))]]]))) [:span.font-mono (when (neg? delta) (format "$%,.2f" (Math/abs delta)))]]]])))
(defn account-typeahead*
[{:keys [name value client-id]}]
[:div.flex.flex-col
(com/typeahead {:name name
:placeholder "Search..."
:url (hu/url (bidi/path-for ssr-routes/only-routes :account-search)
{:client-id client-id
:purpose "invoice"})
:value value
:content-fn (fn [value]
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
client-id)))})])
(defn sales-summary-item-row* [{:keys [value client-id]}] (defn sales-summary-item-row* [{:keys [value client-id]}]
(let [manual? (fc/field-value (:sales-summary-item/manual? value))] (let [manual? (fc/field-value (:sales-summary-item/manual? value))]
@@ -543,28 +543,28 @@
(if item (if item
(let [manual? (:sales-summary-item/manual? item)] (let [manual? (:sales-summary-item/manual? item)]
(if manual? (if manual?
[:div.flex.items-center.gap-2.text-sm {:x-ref "p" :x-data (hx/json {})} [:div.flex.items-center.gap-2.text-sm {:x-ref "p" :x-data (hx/json {})}
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]") (com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]")
:value (:db/id item)}) :value (:db/id item)})
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][sales-summary-item/manual?]") (com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][sales-summary-item/manual?]")
:value "true"}) :value "true"})
(fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")] (fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")]
item [] item []
(fc/with-field :sales-summary-item/category (fc/with-field :sales-summary-item/category
(com/text-input {:placeholder "Category" (com/text-input {:placeholder "Category"
:name (fc/field-name) :name (fc/field-name)
:value (fc/field-value) :value (fc/field-value)
:class "w-32 text-sm"}))) :class "w-32 text-sm"})))
(account-typeahead* {:name (str "step-params[sales-summary/items][" actual-idx "][ledger-mapped/account]") (account-typeahead* {:name (str "step-params[sales-summary/items][" actual-idx "][ledger-mapped/account]")
:value (:ledger-mapped/account item) :value (:ledger-mapped/account item)
:client-id client-id}) :client-id client-id})
(fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")] (fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")]
item [] item []
(fc/with-field :debit (fc/with-field :debit
(com/money-input {:class "w-24 text-right font-mono tabular-nums" (com/money-input {:class "w-24 text-right font-mono tabular-nums"
:name (fc/field-name) :name (fc/field-name)
:value (fc/field-value)}))) :value (fc/field-value)})))
(com/a-icon-button {"@click.prevent.stop" "$refs.p.remove()"} svg/x)] (com/a-icon-button {"@click.prevent.stop" "$refs.p.remove()"} svg/x)]
[:div.flex.items-center.gap-2.text-sm [:div.flex.items-center.gap-2.text-sm
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]") (com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]")
:value (:db/id item)}) :value (:db/id item)})
@@ -572,8 +572,8 @@
:value (:sales-summary-item/category item)}) :value (:sales-summary-item/category item)})
[:span.text-gray-500 (truncate (:sales-summary-item/category item) 30)] [:span.text-gray-500 (truncate (:sales-summary-item/category item) 30)]
(account-display-cell {:item (assoc item :item-index actual-idx) (account-display-cell {:item (assoc item :item-index actual-idx)
:field-name-prefix (str "step-params[sales-summary/items][" actual-idx "]") :field-name-prefix (str "step-params[sales-summary/items][" actual-idx "]")
:client-id client-id}) :client-id client-id})
[:span.font-mono.tabular-nums.text-gray-900 (format "$%,.2f" (:ledger-mapped/amount item))]])) [:span.font-mono.tabular-nums.text-gray-900 (format "$%,.2f" (:ledger-mapped/amount item))]]))
[:div.h-6]))] [:div.h-6]))]
[:div.mt-2.border-t.pt-1 [:div.mt-2.border-t.pt-1
@@ -586,28 +586,28 @@
(if item (if item
(let [manual? (:sales-summary-item/manual? item)] (let [manual? (:sales-summary-item/manual? item)]
(if manual? (if manual?
[:div.flex.items-center.gap-2.text-sm {:x-ref "p" :x-data (hx/json {})} [:div.flex.items-center.gap-2.text-sm {:x-ref "p" :x-data (hx/json {})}
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]") (com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]")
:value (:db/id item)}) :value (:db/id item)})
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][sales-summary-item/manual?]") (com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][sales-summary-item/manual?]")
:value "true"}) :value "true"})
(fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")] (fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")]
item [] item []
(fc/with-field :sales-summary-item/category (fc/with-field :sales-summary-item/category
(com/text-input {:placeholder "Category" (com/text-input {:placeholder "Category"
:name (fc/field-name) :name (fc/field-name)
:value (fc/field-value) :value (fc/field-value)
:class "w-32 text-sm"}))) :class "w-32 text-sm"})))
(account-typeahead* {:name (str "step-params[sales-summary/items][" actual-idx "][ledger-mapped/account]") (account-typeahead* {:name (str "step-params[sales-summary/items][" actual-idx "][ledger-mapped/account]")
:value (:ledger-mapped/account item) :value (:ledger-mapped/account item)
:client-id client-id}) :client-id client-id})
(fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")] (fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")]
item [] item []
(fc/with-field :credit (fc/with-field :credit
(com/money-input {:class "w-24 text-right font-mono tabular-nums" (com/money-input {:class "w-24 text-right font-mono tabular-nums"
:name (fc/field-name) :name (fc/field-name)
:value (fc/field-value)}))) :value (fc/field-value)})))
(com/a-icon-button {"@click.prevent.stop" "$refs.p.remove()"} svg/x)] (com/a-icon-button {"@click.prevent.stop" "$refs.p.remove()"} svg/x)]
[:div.flex.items-center.gap-2.text-sm [:div.flex.items-center.gap-2.text-sm
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]") (com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]")
:value (:db/id item)}) :value (:db/id item)})
@@ -615,8 +615,8 @@
:value (:sales-summary-item/category item)}) :value (:sales-summary-item/category item)})
[:span.text-gray-500 (truncate (:sales-summary-item/category item) 30)] [:span.text-gray-500 (truncate (:sales-summary-item/category item) 30)]
(account-display-cell {:item (assoc item :item-index actual-idx) (account-display-cell {:item (assoc item :item-index actual-idx)
:field-name-prefix (str "step-params[sales-summary/items][" actual-idx "]") :field-name-prefix (str "step-params[sales-summary/items][" actual-idx "]")
:client-id client-id}) :client-id client-id})
[:span.font-mono.tabular-nums.text-gray-900 (format "$%,.2f" (:ledger-mapped/amount item))]])) [:span.font-mono.tabular-nums.text-gray-900 (format "$%,.2f" (:ledger-mapped/amount item))]]))
[:div.h-6]))] [:div.h-6]))]
[:div.mt-2.border-t.pt-1 [:div.mt-2.border-t.pt-1
@@ -634,7 +634,7 @@
:footer :footer
(mm/default-step-footer linear-wizard this :validation-route ::route/edit-wizard-navigate) (mm/default-step-footer linear-wizard this :validation-route ::route/edit-wizard-navigate)
:validation-route ::route/edit-wizard-navigate :validation-route ::route/edit-wizard-navigate
:width-height-class "lg:w-[900px] lg:h-[600px]"))) :width-height-class "lg:w-[900px] lg:h-[600px]"))))
(defn attach-ledger [i] (defn attach-ledger [i]
(cond-> i (cond-> i
@@ -757,24 +757,24 @@
::route/edit-wizard-navigate (-> mm/next-handler ::route/edit-wizard-navigate (-> mm/next-handler
(mm/wrap-wizard edit-wizard) (mm/wrap-wizard edit-wizard)
(mm/wrap-decode-multi-form-state)) (mm/wrap-decode-multi-form-state))
::route/new-summary-item (-> (add-new-entity-handler [:step-params :sales-summary/items] ::route/new-summary-item (-> (add-new-entity-handler [:step-params :sales-summary/items]
(fn render [cursor request] (fn render [cursor request]
(sales-summary-item-row* (sales-summary-item-row*
{:value cursor {:value cursor
:client-id (:client-id (:query-params request))})) :client-id (:client-id (:query-params request))}))
(fn build-new-row [base _] (fn build-new-row [base _]
(assoc base :sales-summary-item/manual? true))) (assoc base :sales-summary-item/manual? true)))
(wrap-schema-enforce :query-schema [:map (wrap-schema-enforce :query-schema [:map
[:client-id {:optional true} [:client-id {:optional true}
[:maybe entity-id]]])) [:maybe entity-id]]]))
::route/edit-item-account (-> edit-item-account ::route/edit-item-account (-> edit-item-account
(wrap-schema-enforce :query-schema [:map (wrap-schema-enforce :query-schema [:map
[:item-index nat-int?] [:item-index nat-int?]
[:client-id {:optional true} [:maybe entity-id]] [:client-id {:optional true} [:maybe entity-id]]
[:current-account-id {:optional true} [:maybe :string]]])) [:current-account-id {:optional true} [:maybe :string]]]))
::route/save-item-account save-item-account ::route/save-item-account save-item-account
::route/cancel-item-account cancel-item-account ::route/cancel-item-account cancel-item-account
::route/edit-wizard-submit (-> mm/submit-handler ::route/edit-wizard-submit (-> mm/submit-handler
(mm/wrap-wizard edit-wizard) (mm/wrap-wizard edit-wizard)
(mm/wrap-decode-multi-form-state))}) (mm/wrap-decode-multi-form-state))})
(fn [h] (fn [h]