tries sales changes
This commit is contained in:
@@ -133,6 +133,47 @@
|
||||
(str (subs s 0 (- max-len 3)) "...")
|
||||
s))
|
||||
|
||||
(defn account-display-cell [{:keys [item field-name-prefix client-id]}]
|
||||
(let [account-id (:ledger-mapped/account item)
|
||||
account-name (when account-id
|
||||
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read account-id)
|
||||
client-id)))]
|
||||
[:div.account-cell.flex.items-center.gap-2
|
||||
(com/hidden {:name (str field-name-prefix "[ledger-mapped/account]")
|
||||
:value (or account-id "")})
|
||||
(if account-id
|
||||
[:span.text-sm account-name]
|
||||
(com/pill {:color :red} "Missing acct"))
|
||||
(com/a-icon-button {:hx-get (bidi/path-for ssr-routes/only-routes ::route/edit-item-account)
|
||||
:hx-target "closest .account-cell"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-vals (hx/json {:item-index (or (:item-index item) 0)
|
||||
:client-id client-id
|
||||
:current-account-id (or account-id "")})}
|
||||
svg/pencil)]))
|
||||
|
||||
(defn account-edit-cell [{:keys [field-name-prefix client-id current-account-id]}]
|
||||
(let [account-input-name (str field-name-prefix "[ledger-mapped/account]")]
|
||||
[:div.account-cell.flex.flex-col.gap-2
|
||||
(account-typeahead* {:name account-input-name
|
||||
:value current-account-id
|
||||
:client-id client-id})
|
||||
[:div.flex.gap-1
|
||||
(com/a-icon-button {:hx-put (bidi/path-for ssr-routes/only-routes ::route/save-item-account)
|
||||
:hx-target "closest .account-cell"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-include "closest .account-cell"
|
||||
:hx-vals (hx/json {:field-name-prefix field-name-prefix
|
||||
:client-id client-id})}
|
||||
svg/check)
|
||||
(com/a-icon-button {:hx-get (bidi/path-for ssr-routes/only-routes ::route/cancel-item-account)
|
||||
:hx-target "closest .account-cell"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-vals (hx/json {:field-name-prefix field-name-prefix
|
||||
:client-id client-id
|
||||
:current-account-id (or current-account-id "")})}
|
||||
svg/x)]]))
|
||||
|
||||
(def grid-page
|
||||
(helper/build {:id "entity-table"
|
||||
:id-fn :db/id
|
||||
@@ -304,11 +345,7 @@
|
||||
(total-debits))]
|
||||
|
||||
(com/data-grid-row {:id "total-row"
|
||||
:class "bg-slate-50 border-t-2 border-slate-300"
|
||||
:hx-trigger "change from:closest form target:.amount-field"
|
||||
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/expense-account-total)
|
||||
:hx-target "this"
|
||||
:hx-swap "innerHTML"}
|
||||
:class "bg-slate-50 border-t-2 border-slate-300"}
|
||||
(com/data-grid-cell {})
|
||||
(com/data-grid-cell {:class "text-right"}
|
||||
[:span.text-xs.uppercase.tracking-wider.font-semibold.text-slate-600
|
||||
@@ -337,11 +374,7 @@
|
||||
credit-over? (and unbalanced? (> total-credits total-debits))]
|
||||
|
||||
(com/data-grid-row {:id "unbalanced-row"
|
||||
:class (when unbalanced? "bg-red-50 border-t border-red-200")
|
||||
:hx-trigger "change from:closest form target:.amount-field"
|
||||
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/expense-account-total)
|
||||
:hx-target "this"
|
||||
:hx-swap "innerHTML"}
|
||||
:class (when unbalanced? "bg-red-50 border-t border-red-200")}
|
||||
(com/data-grid-cell {})
|
||||
(com/data-grid-cell {:class "text-right"}
|
||||
(when unbalanced?
|
||||
@@ -357,7 +390,45 @@
|
||||
(format "$%,.2f" (- total-credits total-debits))]))
|
||||
(com/data-grid-cell {}))))
|
||||
|
||||
(defn- account-typeahead*
|
||||
(defn summary-total-display [request]
|
||||
(let [total-credits (-> request
|
||||
:multi-form-state
|
||||
:step-params
|
||||
:sales-summary/items
|
||||
(total-credits))
|
||||
total-debits (-> request
|
||||
:multi-form-state
|
||||
:step-params
|
||||
:sales-summary/items
|
||||
(total-debits))]
|
||||
[:div.flex.justify-between.text-sm.py-1.border-t.mt-1
|
||||
{:id "total-display"}
|
||||
[:span.font-semibold "Total"]
|
||||
[:div.flex.gap-8
|
||||
[:span.font-mono (format "$%,.2f" total-debits)]
|
||||
[:span.font-mono (format "$%,.2f" total-credits)]]]))
|
||||
|
||||
(defn unbalanced-display [request]
|
||||
(let [total-credits (-> request
|
||||
:multi-form-state
|
||||
:step-params
|
||||
:sales-summary/items
|
||||
(total-credits))
|
||||
total-debits (-> request
|
||||
:multi-form-state
|
||||
:step-params
|
||||
:sales-summary/items
|
||||
(total-debits))
|
||||
delta (- total-debits total-credits)]
|
||||
(when-not (dollars-0? delta)
|
||||
[:div.flex.justify-between.text-sm.py-1
|
||||
{:id "unbalanced-display"}
|
||||
[:span.font-semibold.text-red-600 "Unbalanced"]
|
||||
[:div.flex.gap-8
|
||||
[:span.font-mono (when (pos? delta) (format "$%,.2f" 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
|
||||
@@ -446,38 +517,124 @@
|
||||
|
||||
(render-step
|
||||
[this {:keys [multi-form-state] :as request}]
|
||||
(mm/default-render-step
|
||||
linear-wizard this
|
||||
:head [:div.p-2 "New invoice"]
|
||||
:body (mm/default-step-body
|
||||
{}
|
||||
[:div
|
||||
(fc/with-field :db/id
|
||||
(com/hidden {:name (fc/field-name)
|
||||
:value (fc/field-value)}))
|
||||
(com/data-grid {:headers
|
||||
[(com/data-grid-header {} "Category")
|
||||
(com/data-grid-header {} "Account")
|
||||
(com/data-grid-header {} "Debits")
|
||||
(com/data-grid-header {} "Credits")
|
||||
(com/data-grid-header {} "")]}
|
||||
(fc/with-field :sales-summary/items
|
||||
(list
|
||||
(fc/cursor-map #(sales-summary-item-row* {:value %
|
||||
:client-id (:db/id (:sales-summary/client (:snapshot multi-form-state)))}))
|
||||
(com/data-grid-new-row {:colspan 5
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes ::route/new-summary-item)
|
||||
:row-offset 0
|
||||
:index (count (fc/field-value))
|
||||
:tr-params {:hx-vals (hx/json {:client-id (:db/id (:sales-summary/client (:snapshot multi-form-state)))})}}
|
||||
"New Summary Item")))
|
||||
(summary-total-row* request)
|
||||
(unbalanced-row* request))])
|
||||
(let [client-id (:db/id (:sales-summary/client (:snapshot multi-form-state)))
|
||||
items (:sales-summary/items (:step-params multi-form-state))
|
||||
sorted-items (sort-items items)
|
||||
indexed-items (map-indexed vector sorted-items)
|
||||
debit-items (filter #(= :ledger-side/debit (:ledger-mapped/ledger-side (second %))) indexed-items)
|
||||
credit-items (filter #(= :ledger-side/credit (:ledger-mapped/ledger-side (second %))) indexed-items)
|
||||
max-rows (max (count debit-items) (count credit-items))
|
||||
padded-debits (concat debit-items (repeat (- max-rows (count debit-items)) nil))
|
||||
padded-credits (concat credit-items (repeat (- max-rows (count credit-items)) nil))]
|
||||
(mm/default-render-step
|
||||
linear-wizard this
|
||||
:head [:div.p-2 "Edit Summary"]
|
||||
:body (mm/default-step-body
|
||||
{}
|
||||
[:div
|
||||
(fc/with-field :db/id
|
||||
(com/hidden {:name (fc/field-name)
|
||||
:value (fc/field-value)}))
|
||||
[:div.grid.grid-cols-2.gap-6
|
||||
[:div
|
||||
[:div.font-semibold.text-sm.mb-2 "Debits"]
|
||||
[:div.space-y-1
|
||||
(for [[actual-idx item] padded-debits]
|
||||
(if item
|
||||
(let [manual? (:sales-summary-item/manual? item)]
|
||||
(if manual?
|
||||
[: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]")
|
||||
:value (:db/id item)})
|
||||
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][sales-summary-item/manual?]")
|
||||
:value "true"})
|
||||
(fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")]
|
||||
item []
|
||||
(fc/with-field :sales-summary-item/category
|
||||
(com/text-input {:placeholder "Category"
|
||||
:name (fc/field-name)
|
||||
:value (fc/field-value)
|
||||
:class "w-32 text-sm"})))
|
||||
(account-typeahead* {:name (str "step-params[sales-summary/items][" actual-idx "][ledger-mapped/account]")
|
||||
:value (:ledger-mapped/account item)
|
||||
:client-id client-id})
|
||||
(fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")]
|
||||
item []
|
||||
(fc/with-field :debit
|
||||
(com/money-input {:class "w-24 text-right font-mono tabular-nums"
|
||||
:name (fc/field-name)
|
||||
:value (fc/field-value)})))
|
||||
(com/a-icon-button {"@click.prevent.stop" "$refs.p.remove()"} svg/x)]
|
||||
[:div.flex.items-center.gap-2.text-sm
|
||||
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]")
|
||||
:value (:db/id item)})
|
||||
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][sales-summary-item/category]")
|
||||
:value (:sales-summary-item/category item)})
|
||||
[:span.text-gray-500 (truncate (:sales-summary-item/category item) 30)]
|
||||
(account-display-cell {:item (assoc item :item-index actual-idx)
|
||||
:field-name-prefix (str "step-params[sales-summary/items][" actual-idx "]")
|
||||
:client-id client-id})
|
||||
[:span.font-mono.tabular-nums.text-gray-900 (format "$%,.2f" (:ledger-mapped/amount item))]]))
|
||||
[:div.h-6]))]
|
||||
[:div.mt-2.border-t.pt-1
|
||||
(summary-total-display request)
|
||||
(unbalanced-display request)]]
|
||||
[:div
|
||||
[:div.font-semibold.text-sm.mb-2 "Credits"]
|
||||
[:div.space-y-1
|
||||
(for [[actual-idx item] padded-credits]
|
||||
(if item
|
||||
(let [manual? (:sales-summary-item/manual? item)]
|
||||
(if manual?
|
||||
[: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]")
|
||||
:value (:db/id item)})
|
||||
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][sales-summary-item/manual?]")
|
||||
:value "true"})
|
||||
(fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")]
|
||||
item []
|
||||
(fc/with-field :sales-summary-item/category
|
||||
(com/text-input {:placeholder "Category"
|
||||
:name (fc/field-name)
|
||||
:value (fc/field-value)
|
||||
:class "w-32 text-sm"})))
|
||||
(account-typeahead* {:name (str "step-params[sales-summary/items][" actual-idx "][ledger-mapped/account]")
|
||||
:value (:ledger-mapped/account item)
|
||||
:client-id client-id})
|
||||
(fc/start-form-with-prefix [(str "step-params[sales-summary/items][" actual-idx "]")]
|
||||
item []
|
||||
(fc/with-field :credit
|
||||
(com/money-input {:class "w-24 text-right font-mono tabular-nums"
|
||||
:name (fc/field-name)
|
||||
:value (fc/field-value)})))
|
||||
(com/a-icon-button {"@click.prevent.stop" "$refs.p.remove()"} svg/x)]
|
||||
[:div.flex.items-center.gap-2.text-sm
|
||||
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][db/id]")
|
||||
:value (:db/id item)})
|
||||
(com/hidden {:name (str "step-params[sales-summary/items][" actual-idx "][sales-summary-item/category]")
|
||||
:value (:sales-summary-item/category item)})
|
||||
[:span.text-gray-500 (truncate (:sales-summary-item/category item) 30)]
|
||||
(account-display-cell {:item (assoc item :item-index actual-idx)
|
||||
:field-name-prefix (str "step-params[sales-summary/items][" actual-idx "]")
|
||||
:client-id client-id})
|
||||
[:span.font-mono.tabular-nums.text-gray-900 (format "$%,.2f" (:ledger-mapped/amount item))]]))
|
||||
[:div.h-6]))]
|
||||
[:div.mt-2.border-t.pt-1
|
||||
(summary-total-display request)
|
||||
(unbalanced-display request)]]]
|
||||
[:div.mt-4.border-t.pt-2
|
||||
(fc/with-field :sales-summary/items
|
||||
(com/data-grid-new-row {:colspan 2
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes ::route/new-summary-item)
|
||||
:row-offset 0
|
||||
:index (count (fc/field-value))
|
||||
:tr-params {:hx-vals (hx/json {:client-id client-id})}}
|
||||
"New Summary Item"))]])
|
||||
|
||||
:footer
|
||||
(mm/default-step-footer linear-wizard this :validation-route ::route/edit-wizard-navigate)
|
||||
:validation-route ::route/edit-wizard-navigate
|
||||
:width-height-class "lg:w-[920px] lg:h-[640px]")))
|
||||
:footer
|
||||
(mm/default-step-footer linear-wizard this :validation-route ::route/edit-wizard-navigate)
|
||||
:validation-route ::route/edit-wizard-navigate
|
||||
:width-height-class "lg:w-[900px] lg:h-[600px]")))
|
||||
|
||||
(defn attach-ledger [i]
|
||||
(cond-> i
|
||||
@@ -524,7 +681,6 @@
|
||||
{:db/id (:db/id i)
|
||||
:ledger-mapped/account (:ledger-mapped/account i)}))
|
||||
(:sales-summary/items result))}]]
|
||||
(clojure.pprint/pprint (:sales-summary/items result))
|
||||
@(dc/transact conn [transaction])
|
||||
(html-response
|
||||
(row* identity (dc/pull (dc/db conn) default-read (:db/id result))
|
||||
@@ -547,6 +703,48 @@
|
||||
|
||||
(mm/->MultiStepFormState entity [] entity)))
|
||||
|
||||
(defn edit-item-account [request]
|
||||
(let [{:keys [item-index client-id current-account-id]} (:query-params request)
|
||||
item-index (if (string? item-index) (Integer/parseInt item-index) item-index)
|
||||
field-name-prefix (str "step-params[sales-summary/items][" item-index "]")
|
||||
current-account-id (when (and current-account-id (not= current-account-id ""))
|
||||
(if (string? current-account-id)
|
||||
(Long/parseLong current-account-id)
|
||||
current-account-id))
|
||||
client-id (if (string? client-id) (Long/parseLong client-id) client-id)]
|
||||
(html-response
|
||||
(account-edit-cell {:field-name-prefix field-name-prefix
|
||||
:client-id client-id
|
||||
:current-account-id current-account-id}))))
|
||||
|
||||
(defn save-item-account [request]
|
||||
(let [{:keys [field-name-prefix client-id]} (:query-params request)
|
||||
account-input-name (str field-name-prefix "[ledger-mapped/account]")
|
||||
account-id-str (get-in request [:form-params account-input-name])
|
||||
account-id (when (and account-id-str (not= account-id-str ""))
|
||||
(Long/parseLong account-id-str))
|
||||
item {:ledger-mapped/account account-id
|
||||
:item-index (second (re-find #"\[(\d+)\]" (or field-name-prefix "")))}
|
||||
client-id (if (string? client-id) (Long/parseLong client-id) client-id)]
|
||||
(html-response
|
||||
(account-display-cell {:item item
|
||||
:field-name-prefix field-name-prefix
|
||||
:client-id client-id}))))
|
||||
|
||||
(defn cancel-item-account [request]
|
||||
(let [{:keys [field-name-prefix client-id current-account-id]} (:query-params request)
|
||||
account-id (when (and current-account-id (not= current-account-id ""))
|
||||
(if (string? current-account-id)
|
||||
(Long/parseLong current-account-id)
|
||||
current-account-id))
|
||||
item {:ledger-mapped/account account-id
|
||||
:item-index (second (re-find #"\[(\d+)\]" (or field-name-prefix "")))}
|
||||
client-id (if (string? client-id) (Long/parseLong client-id) client-id)]
|
||||
(html-response
|
||||
(account-display-cell {:item item
|
||||
:field-name-prefix field-name-prefix
|
||||
:client-id client-id}))))
|
||||
|
||||
(def key->handler
|
||||
(apply-middleware-to-all-handlers
|
||||
(->>
|
||||
@@ -566,10 +764,17 @@
|
||||
:client-id (:client-id (:query-params request))}))
|
||||
(fn build-new-row [base _]
|
||||
(assoc base :sales-summary-item/manual? true)))
|
||||
(wrap-schema-enforce :query-schema [:map
|
||||
[:client-id {:optional true}
|
||||
[:maybe entity-id]]]))
|
||||
::route/edit-wizard-submit (-> mm/submit-handler
|
||||
(wrap-schema-enforce :query-schema [:map
|
||||
[:client-id {:optional true}
|
||||
[:maybe entity-id]]]))
|
||||
::route/edit-item-account (-> edit-item-account
|
||||
(wrap-schema-enforce :query-schema [:map
|
||||
[:item-index nat-int?]
|
||||
[:client-id {:optional true} [:maybe entity-id]]
|
||||
[:current-account-id {:optional true} [:maybe :string]]]))
|
||||
::route/save-item-account save-item-account
|
||||
::route/cancel-item-account cancel-item-account
|
||||
::route/edit-wizard-submit (-> mm/submit-handler
|
||||
(mm/wrap-wizard edit-wizard)
|
||||
(mm/wrap-decode-multi-form-state))})
|
||||
(fn [h]
|
||||
|
||||
@@ -3,5 +3,8 @@
|
||||
:put ::edit-wizard-submit}
|
||||
"/table" ::table
|
||||
["/" [#"\d+" :db/id]] {:get ::edit-wizard }
|
||||
"/edit/navigate" ::edit-wizard-navigate
|
||||
"/edit/sales-summary-item" ::new-summary-item})
|
||||
"/edit/navigate" ::edit-wizard-navigate
|
||||
"/edit/sales-summary-item" ::new-summary-item
|
||||
"/edit/item-account" ::edit-item-account
|
||||
"/edit/save-item-account" ::save-item-account
|
||||
"/edit/cancel-item-account" ::cancel-item-account})
|
||||
|
||||
Reference in New Issue
Block a user