Add $/% toggle for transaction account amounts in manual edit
When editing a transaction manually, users can now toggle between viewing
account amounts as dollar values or percentages. The toggle appears in the
table header as a radio button group ($ / %).
Key features:
- Global toggle switches all accounts simultaneously
- $→%: amounts are converted to percentages of the transaction total
- %→$: uses percentages->dollars with spread-cents for accurate cent distribution
- Form state preserves vendor, memo, approval status when toggling
- Save handler converts % back to $ before persisting to Datomic
- Uses HTMX to re-render only the account grid body on toggle
New route: /toggle-amount-mode
New functions: ->percentage, percentages->dollars, convert-accounts-mode,
account-grid-body*, toggle-amount-mode
This commit is contained in:
@@ -80,6 +80,7 @@
|
||||
[:transaction/memo {:optional true} [:maybe [:string {:decode/string strip}]]]
|
||||
[:transaction/vendor {:optional true} [:maybe entity-id]]
|
||||
[:transaction/approval-status {:optional true} [:maybe (ref->enum-schema "transaction-approval-status")]]
|
||||
[:amount-mode {:optional true} [:maybe [:enum "$" "%"]]]
|
||||
[:transaction/accounts {:optional true}
|
||||
[:maybe
|
||||
[:vector {:coerce? true}
|
||||
@@ -102,17 +103,14 @@
|
||||
[:unlink-payment [:map
|
||||
[:transaction-id entity-id]]]
|
||||
[:link-unpaid-invoices [:map
|
||||
|
||||
[:unpaid-invoice-ids {:decode/string (fn [x] (edn/read-string x))}
|
||||
[:vector {:coerce? true} entity-id]]]]
|
||||
[:link-autopay-invoices [:map
|
||||
|
||||
[:autopay-invoice-ids {:decode/string (fn [x] (edn/read-string x))} [:vector {:coerce? true} entity-id]]]]
|
||||
[:link-payment [:map
|
||||
[:payment-id entity-id]]]
|
||||
[:manual (require-approval [:map])]]]))
|
||||
|
||||
|
||||
(defn clientize-vendor [{:vendor/keys [terms-overrides automatically-paid-when-due default-account account-overrides] :as vendor} client-id]
|
||||
(if (nil? vendor)
|
||||
nil
|
||||
@@ -166,7 +164,7 @@
|
||||
(com/typeahead {:name name
|
||||
:placeholder "Search..."
|
||||
:url (hu/url (bidi/path-for ssr-routes/only-routes :account-search)
|
||||
(cond-> { :purpose "transaction"}
|
||||
(cond-> {:purpose "transaction"}
|
||||
client-id (assoc :client-id client-id)))
|
||||
:id name
|
||||
:x-model x-model
|
||||
@@ -175,7 +173,7 @@
|
||||
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
|
||||
client-id)))})])
|
||||
|
||||
(defn transaction-account-row* [{:keys [value client-id]}]
|
||||
(defn transaction-account-row* [{:keys [value client-id amount-mode total]}]
|
||||
(com/data-grid-row
|
||||
(-> {:x-data (hx/json {:show (boolean (not (fc/field-value (:new? value))))
|
||||
:accountId (fc/field-value (:transaction-account/account value))})
|
||||
@@ -200,7 +198,7 @@
|
||||
(com/validated-field
|
||||
{:errors (fc/field-errors)
|
||||
:x-hx-val:account-id "accountId"
|
||||
:hx-vals (hx/json (cond-> {:name (fc/field-name) }
|
||||
:hx-vals (hx/json (cond-> {:name (fc/field-name)}
|
||||
client-id (assoc :client-id client-id)))
|
||||
:x-dispatch:changed "accountId"
|
||||
:hx-trigger "changed"
|
||||
@@ -218,9 +216,15 @@
|
||||
{}
|
||||
(com/validated-field
|
||||
{:errors (fc/field-errors)}
|
||||
(if (= "%" amount-mode)
|
||||
(com/text-input {:name (fc/field-name)
|
||||
:class "w-16"
|
||||
:value (fc/field-value)
|
||||
:type "number"
|
||||
:step "0.01"})
|
||||
(com/money-input {:name (fc/field-name)
|
||||
:class "w-16"
|
||||
:value (fc/field-value)}))))
|
||||
:value (fc/field-value)})))))
|
||||
(com/data-grid-cell {:class "align-top"}
|
||||
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
|
||||
|
||||
@@ -263,6 +267,103 @@
|
||||
(defn account-balance [request]
|
||||
(html-response (account-balance* request)))
|
||||
|
||||
(defn ->percentage [amount total]
|
||||
(when (and amount total (not= total 0))
|
||||
(* 100.0 (/ amount total))))
|
||||
|
||||
(defn percentages->dollars [percentages total]
|
||||
(let [total-cents (int (* 100 (Math/abs total)))
|
||||
pct-sum (reduce + 0 percentages)
|
||||
normalized-pcts (if (zero? pct-sum)
|
||||
(repeat (count percentages) 0)
|
||||
(map #(* (/ % pct-sum) 100) percentages))
|
||||
individual-cents (map #(int (* total-cents (/ % 100))) normalized-pcts)
|
||||
short-by (- total-cents (reduce + 0 individual-cents))
|
||||
adjustments (concat (take short-by (repeat 1)) (repeat 0))
|
||||
final-cents (map + individual-cents adjustments)]
|
||||
(map #(* 0.01 %) final-cents)))
|
||||
|
||||
(defn convert-accounts-mode [accounts old-mode new-mode total]
|
||||
(if (= old-mode new-mode)
|
||||
accounts
|
||||
(let [amounts (map :transaction-account/amount accounts)]
|
||||
(map #(assoc %1 :transaction-account/amount %2)
|
||||
accounts
|
||||
(case [old-mode new-mode]
|
||||
["$" "%"] (map #(->percentage % total) amounts)
|
||||
["%" "$"] (percentages->dollars amounts total)
|
||||
amounts)))))
|
||||
|
||||
(defn account-grid-body* [request]
|
||||
(let [snapshot (-> request :multi-form-state :snapshot)
|
||||
amount-mode (or (:amount-mode snapshot) "$")
|
||||
total (Math/abs (:transaction/amount snapshot))]
|
||||
(com/data-grid {:headers [(com/data-grid-header {} "Account")
|
||||
(com/data-grid-header {:class "w-32"} "Location")
|
||||
(com/data-grid-header {:class "w-16"}
|
||||
(com/radio-card {:options [{:value "$" :content "$"}
|
||||
{:value "%" :content "%"}]
|
||||
:value amount-mode
|
||||
:name "step-params[amount-mode]"
|
||||
:hx-post (bidi/path-for ssr-routes/only-routes ::route/toggle-amount-mode)
|
||||
:hx-target "#account-grid-body"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-include "closest form"}))
|
||||
(com/data-grid-header {:class "w-16"})]}
|
||||
(fc/cursor-map #(transaction-account-row* {:value %
|
||||
:client-id (-> request :entity :transaction/client :db/id)
|
||||
:amount-mode amount-mode
|
||||
:total total}))
|
||||
|
||||
(com/data-grid-new-row {:colspan 4
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
::route/edit-wizard-new-account)
|
||||
:row-offset 0
|
||||
:index (count (:transaction/accounts snapshot))
|
||||
:tr-params {:hx-vals (hx/json {:client-id (:transaction/client snapshot)})}}
|
||||
"New account")
|
||||
(com/data-grid-row {}
|
||||
(com/data-grid-cell {})
|
||||
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TOTAL"])
|
||||
(com/data-grid-cell {:id "total"
|
||||
:class "text-right"
|
||||
:hx-trigger "change from:closest form target:.amount-field"
|
||||
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/account-total)
|
||||
:hx-target "this"
|
||||
:hx-swap "innerHTML"}
|
||||
(account-total* request))
|
||||
(com/data-grid-cell {}))
|
||||
|
||||
(com/data-grid-row {}
|
||||
(com/data-grid-cell {})
|
||||
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "BALANCE"])
|
||||
(com/data-grid-cell {:id "total"
|
||||
:class "text-right"
|
||||
:hx-trigger "change from:closest form target:.amount-field"
|
||||
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/account-balance)
|
||||
:hx-target "this"
|
||||
:hx-swap "innerHTML"}
|
||||
(account-balance* request))
|
||||
(com/data-grid-cell {}))
|
||||
|
||||
(com/data-grid-row {}
|
||||
(com/data-grid-cell {})
|
||||
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TRANSACTION TOTAL"])
|
||||
(com/data-grid-cell {:class "text-right"}
|
||||
(format "$%,.2f" total))
|
||||
(com/data-grid-cell {})))))
|
||||
|
||||
(defn toggle-amount-mode [request]
|
||||
(let [snapshot (-> request :multi-form-state :snapshot)
|
||||
old-mode (or (:amount-mode snapshot) "$")
|
||||
new-mode (or (get-in request [:form-params :amount-mode]) "$")
|
||||
total (Math/abs (:transaction/amount snapshot))
|
||||
accounts (convert-accounts-mode (:transaction/accounts snapshot) old-mode new-mode total)]
|
||||
(html-response
|
||||
[:div#account-grid-body
|
||||
(account-grid-body* (assoc-in request [:multi-form-state :snapshot :transaction/accounts] accounts
|
||||
[:multi-form-state :snapshot :amount-mode] new-mode))])))
|
||||
|
||||
(defrecord BasicDetailsStep [linear-wizard]
|
||||
mm/ModalWizardStep
|
||||
(step-name [_]
|
||||
@@ -288,7 +389,7 @@
|
||||
:body (mm/default-step-body
|
||||
{}
|
||||
[:div {:x-data (hx/json {:clientId (or (fc/field-value (:transaction/client fc/*current*))
|
||||
(:db/id (:client request))) })}
|
||||
(:db/id (:client request)))})}
|
||||
|
||||
;; Read-only transaction details
|
||||
[:div.mb-6.border.rounded-lg.p-4.bg-gray-50
|
||||
@@ -330,9 +431,7 @@
|
||||
[:div.text-sm.font-medium.text-gray-500 "Transaction Type"]
|
||||
[:div.text-base (or (some-> tx :transaction/type) "-")]]]]
|
||||
|
||||
|
||||
|
||||
;; Transaction Links Section
|
||||
;; Transaction Links Section
|
||||
#_[:div.mb-6.border.rounded-lg.p-4.bg-gray-50
|
||||
[:h3.text-lg.font-semibold.mb-2 "Transaction Links"]
|
||||
(let [tx-id (mm/get-mfs-field multi-form-state :db/id)
|
||||
@@ -367,7 +466,7 @@
|
||||
(for [{:keys [entity-id date op]} all-payments
|
||||
:let [payment (dc/pull (dc/db conn)
|
||||
'[:db/id :payment/invoice-number
|
||||
[ :payment/date :xform clj-time.coerce/from-date]
|
||||
[:payment/date :xform clj-time.coerce/from-date]
|
||||
{:payment/vendor [:vendor/name]}]
|
||||
entity-id)]]
|
||||
[:li.text-sm.text-gray-600 {:class (when-not op "line-through")}
|
||||
@@ -378,14 +477,12 @@
|
||||
|
||||
;; Invoices section
|
||||
|
||||
|
||||
;; Hidden ID field
|
||||
;; Hidden ID field
|
||||
(fc/with-field :db/id
|
||||
(com/hidden {:name (fc/field-name)
|
||||
:value (fc/field-value)}))
|
||||
|
||||
|
||||
;; Editable fields section
|
||||
;; Editable fields section
|
||||
;; Vendor field
|
||||
)
|
||||
:footer
|
||||
@@ -414,8 +511,6 @@
|
||||
client-id))]
|
||||
(filter #(dollars= (Math/abs (:transaction/amount tx)) (:payment/amount %)) payments)))
|
||||
|
||||
|
||||
|
||||
(defn get-available-autopay-invoices [request]
|
||||
(let [tx-id (or (-> request :multi-form-state :snapshot :db/id)
|
||||
(get-in request [:route-params :db/id]))
|
||||
@@ -447,9 +542,8 @@
|
||||
[:span.block.text-sm.font-medium (:invoice/invoice-number invoice)]
|
||||
[:span.block.text-sm.text-gray-500 (-> invoice :invoice/vendor :vendor/name)]
|
||||
[:span.block.text-sm.font-medium (format "$%.2f" (:invoice/outstanding-balance invoice))]]))})
|
||||
:name (fc/with-field :autopay-invoice-ids (fc/field-name ))
|
||||
:width "w-full"})]
|
||||
]
|
||||
:name (fc/with-field :autopay-invoice-ids (fc/field-name))
|
||||
:width "w-full"})]]
|
||||
[:div.text-center.py-4.text-gray-500 "No matching autopay invoices available for this transaction."])]))
|
||||
|
||||
(defn get-available-unpaid-invoices [request]
|
||||
@@ -487,16 +581,15 @@
|
||||
:form ""})
|
||||
[:div.space-y-2
|
||||
[:label.block.text-sm.font-medium.mb-1 "Select an unpaid invoice to apply:"]
|
||||
(com/radio-card {:options (for [match-group invoice-matches]
|
||||
(com/radio-card {:options (for [match-group invoice-matches]
|
||||
{:value (pr-str (map :db/id match-group))
|
||||
:content (doall (for [invoice match-group]
|
||||
[:div.ml-3
|
||||
[:span.block.text-sm.font-medium (:invoice/invoice-number invoice)]
|
||||
[:span.block.text-sm.text-gray-500 (-> invoice :invoice/vendor :vendor/name)]
|
||||
[:span.block.text-sm.font-medium (format "$%.2f" (:invoice/outstanding-balance invoice))]]))})
|
||||
:name (fc/with-field :unpaid-invoice-ids (fc/field-name ))
|
||||
:width "w-full"})
|
||||
]
|
||||
:name (fc/with-field :unpaid-invoice-ids (fc/field-name))
|
||||
:width "w-full"})]
|
||||
#_(com/a-button {:color :primary "@click" "$dispatch('linkUnpaidInvoices')"} "Link")]]
|
||||
[:div.text-center.py-4.text-gray-500 "No matching unpaid invoices available for this transaction."])]))
|
||||
|
||||
@@ -526,7 +619,6 @@
|
||||
(-> rule
|
||||
(update :transaction-rule/description #(some-> % iol-ion.query/->pattern))))))))))
|
||||
|
||||
|
||||
(defn transaction-rules-view [request]
|
||||
(let [matching-rules (get-available-rules request)]
|
||||
[:div
|
||||
@@ -544,8 +636,8 @@
|
||||
:content [:div.ml-3
|
||||
[:span.block.text-sm.font-medium note]
|
||||
[:span.block.text-sm.text-gray-500 description]]})
|
||||
:name (fc/with-field :rule-id (fc/field-name ))
|
||||
:width "w-full"}) ]
|
||||
:name (fc/with-field :rule-id (fc/field-name))
|
||||
:width "w-full"})]
|
||||
#_(com/a-button {"@click" "$dispatch('applyRule')"} "Apply")]
|
||||
[:div.text-center.py-4.text-gray-500 "No matching rules found for this transaction."])]))
|
||||
|
||||
@@ -559,7 +651,7 @@
|
||||
'[:payment/amount
|
||||
:db/id
|
||||
[:payment/date :xform clj-time.coerce/from-date]
|
||||
{ [ :payment/status :xform iol-ion.query/ident] [:db/ident]
|
||||
{[:payment/status :xform iol-ion.query/ident] [:db/ident]
|
||||
|
||||
:payment/vendor [:vendor/name]}]
|
||||
|
||||
@@ -604,7 +696,7 @@
|
||||
[:div.space-y-2
|
||||
[:label.block.text-sm.font-medium.mb-1 "Select a payment to match:"]
|
||||
(when payments
|
||||
(let [payment-id-field (fc/with-field :payment-id (fc/field-name ))]
|
||||
(let [payment-id-field (fc/with-field :payment-id (fc/field-name))]
|
||||
(com/radio-card {:options (for [payment payments]
|
||||
{:value (:db/id payment)
|
||||
:content (str (:payment/invoice-number payment) " - "
|
||||
@@ -612,7 +704,7 @@
|
||||
" - Amount: $" (format "%.2f" (:payment/amount payment))
|
||||
" • Date: " (some-> payment :payment/date coerce/to-date-time (atime/unparse-local atime/normal-date)))})
|
||||
:name payment-id-field
|
||||
:width "w-full"}))) ]]
|
||||
:width "w-full"})))]]
|
||||
[:div.text-center.py-4.text-gray-500 "No matching payments available for this transaction."]))]))
|
||||
|
||||
(defn count-payment-matches [request]
|
||||
@@ -638,7 +730,7 @@
|
||||
[])
|
||||
|
||||
(step-schema [_]
|
||||
#_(require-approval (mut/select-keys (mm/form-schema linear-wizard) #{:transaction/client :transaction/vendor :transaction/memo :transaction/approval-status :db/id}))
|
||||
#_(require-approval (mut/select-keys (mm/form-schema linear-wizard) #{:transaction/client :transaction/vendor :transaction/memo :transaction/approval-status :db/id}))
|
||||
(mm/form-schema linear-wizard))
|
||||
|
||||
(render-step [this {{:keys [snapshot] :as multi-form-state} :multi-form-state :as request}]
|
||||
@@ -721,8 +813,7 @@
|
||||
|
||||
;; Memo field
|
||||
|
||||
|
||||
;; Approval status field
|
||||
;; Approval status field
|
||||
(fc/with-field :transaction/approval-status
|
||||
(com/validated-field
|
||||
{:label "Status"
|
||||
@@ -734,64 +825,21 @@
|
||||
(fc/with-field :transaction/accounts
|
||||
(com/validated-field
|
||||
{:errors (fc/field-errors)}
|
||||
(com/data-grid {:headers [(com/data-grid-header {} "Account")
|
||||
(com/data-grid-header {:class "w-32"} "Location")
|
||||
(com/data-grid-header {:class "w-16"} "$")
|
||||
(com/data-grid-header {:class "w-16"})]}
|
||||
(fc/cursor-map #(transaction-account-row* {:value %
|
||||
:client-id (-> request :entity :transaction/client :db/id)}))
|
||||
|
||||
(com/data-grid-new-row {:colspan 4
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
::route/edit-wizard-new-account)
|
||||
:row-offset 0
|
||||
:index (count (fc/field-value))
|
||||
:tr-params {:hx-vals (hx/json {:client-id (:transaction/client snapshot)})}}
|
||||
"New account")
|
||||
(com/data-grid-row {}
|
||||
(com/data-grid-cell {})
|
||||
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TOTAL"])
|
||||
(com/data-grid-cell {:id "total"
|
||||
:class "text-right"
|
||||
:hx-trigger "change from:closest form target:.amount-field"
|
||||
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/account-total)
|
||||
:hx-target "this"
|
||||
:hx-swap "innerHTML"}
|
||||
(account-total* request))
|
||||
(com/data-grid-cell {}))
|
||||
|
||||
(com/data-grid-row {}
|
||||
(com/data-grid-cell {})
|
||||
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "BALANCE"])
|
||||
(com/data-grid-cell {:id "total"
|
||||
:class "text-right"
|
||||
:hx-trigger "change from:closest form target:.amount-field"
|
||||
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/account-balance)
|
||||
:hx-target "this"
|
||||
:hx-swap "innerHTML"}
|
||||
(account-balance* request))
|
||||
(com/data-grid-cell {}))
|
||||
|
||||
(com/data-grid-row {}
|
||||
|
||||
(com/data-grid-cell {})
|
||||
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TRANSACTION TOTAL"])
|
||||
(com/data-grid-cell {:class "text-right"}
|
||||
(format "$%,.2f" (Math/abs (:transaction/amount snapshot))))
|
||||
(com/data-grid-cell {})))))]]]])
|
||||
[:div#account-grid-body
|
||||
(account-grid-body* request)]))]]]])
|
||||
:footer
|
||||
(mm/default-step-footer linear-wizard this :validation-route ::route/edit-wizard-navigate
|
||||
:next-button (com/button {:color :primary :x-ref "next" :class "w-32"} "Done"))
|
||||
:validation-route ::route/edit-wizard-navigate)) )
|
||||
:validation-route ::route/edit-wizard-navigate)))
|
||||
|
||||
(defmulti save-handler (fn [request]
|
||||
(-> request :multi-form-state :snapshot :action)))
|
||||
|
||||
(defn- default-update-tx [snapshot transaction]
|
||||
(merge {:transaction/memo (:transaction/memo snapshot) }
|
||||
(merge {:transaction/memo (:transaction/memo snapshot)}
|
||||
transaction))
|
||||
|
||||
(defn- save-linked-transaction [{{ snapshot :snapshot} :multi-form-state :as request transaction :entity} payment]
|
||||
(defn- save-linked-transaction [{{snapshot :snapshot} :multi-form-state :as request transaction :entity} payment]
|
||||
(exception->4xx #(assert-not-locked (-> transaction :transaction/client :db/id) (:transaction/date transaction)))
|
||||
(audit-transact (into
|
||||
[{:db/id (:db/id payment)
|
||||
@@ -811,7 +859,7 @@
|
||||
:transaction-account/amount (Math/abs (:transaction/amount transaction))}]})]])
|
||||
(:identity request)))
|
||||
|
||||
(defn- save-memo-only [{{ snapshot :snapshot} :multi-form-state :as request}]
|
||||
(defn- save-memo-only [{{snapshot :snapshot} :multi-form-state :as request}]
|
||||
(audit-transact [[:upsert-transaction (default-update-tx snapshot {})]]
|
||||
(:identity request)))
|
||||
|
||||
@@ -822,8 +870,8 @@
|
||||
payment-id))
|
||||
|
||||
(defmethod save-handler
|
||||
:link-payment [{{ {:keys [transaction-id payment-id] :as snapshot} :snapshot} :multi-form-state :as request transaction :entity}]
|
||||
(let [ payment (d-checks/get-by-id payment-id)]
|
||||
:link-payment [{{{:keys [transaction-id payment-id] :as snapshot} :snapshot} :multi-form-state :as request transaction :entity}]
|
||||
(let [payment (d-checks/get-by-id payment-id)]
|
||||
|
||||
(exception->4xx #(assert-can-see-client (:identity request) (-> transaction :transaction/client :db/id)))
|
||||
(exception->4xx #(assert-can-see-client (:identity request) (-> payment :payment/client :db/id)))
|
||||
@@ -855,7 +903,7 @@
|
||||
:headers {"hx-trigger" "invalidated"})))
|
||||
|
||||
(defmethod save-handler :link-autopay-invoices
|
||||
[{{ {:keys [autopay-invoice-ids] :as snapshot} :snapshot} :multi-form-state :as request transaction :entity} ]
|
||||
[{{{:keys [autopay-invoice-ids] :as snapshot} :snapshot} :multi-form-state :as request transaction :entity}]
|
||||
(let [db (dc/db conn)
|
||||
invoice-clients (set (map #(pull-ref db :invoice/client %) autopay-invoice-ids))
|
||||
invoice-amount (reduce + 0.0 (map #(pull-attr db :invoice/total %) autopay-invoice-ids))]
|
||||
@@ -898,8 +946,8 @@
|
||||
:headers {"hx-trigger" "invalidated"})))
|
||||
|
||||
(defmethod save-handler :link-unpaid-invoices
|
||||
[{{ {:keys [unpaid-invoice-ids] :as snapshot} :snapshot} :multi-form-state :as request transaction :entity} ]
|
||||
(let [ db (dc/db conn)
|
||||
[{{{:keys [unpaid-invoice-ids] :as snapshot} :snapshot} :multi-form-state :as request transaction :entity}]
|
||||
(let [db (dc/db conn)
|
||||
invoice-clients (set (map #(pull-ref db :invoice/client %) unpaid-invoice-ids))
|
||||
invoice-amount (reduce + 0.0 (map #(pull-attr db :invoice/outstanding-balance %) unpaid-invoice-ids))]
|
||||
|
||||
@@ -1060,6 +1108,16 @@
|
||||
tx-id (:db/id tx-data)
|
||||
client-id (->db-id (:transaction/client tx-data))
|
||||
existing-tx (d-transactions/get-by-id tx-id)
|
||||
amount-mode (or (:amount-mode tx-data) "$")
|
||||
total (Math/abs (:transaction/amount existing-tx))
|
||||
tx-data (if (= "%" amount-mode)
|
||||
(update tx-data :transaction/accounts
|
||||
#(map (fn [account dollar-amount]
|
||||
(assoc account :transaction-account/amount dollar-amount))
|
||||
%
|
||||
(percentages->dollars (map :transaction-account/amount %) total)))
|
||||
tx-data)
|
||||
tx-data (dissoc tx-data :amount-mode)
|
||||
transaction [:upsert-transaction (maybe-spread-locations (assoc tx-data :db/id tx-id))]]
|
||||
|
||||
(alog/info ::transaction transaction :entity transaction)
|
||||
@@ -1159,7 +1217,6 @@
|
||||
(html-response (fc/with-field :step-params (payment-matches-view request))
|
||||
:headers {"hx-trigger" "unlinked"}))))
|
||||
|
||||
|
||||
(defrecord EditWizard [_ current-step]
|
||||
mm/LinearModalWizard
|
||||
(hydrate-from-request
|
||||
@@ -1173,7 +1230,7 @@
|
||||
(mm/get-step this :basic-details)))
|
||||
(render-wizard [this {:keys [multi-form-state] :as request}]
|
||||
(println "HERE XYZ" (:form-errors request))
|
||||
(clojure.pprint/pprint (:snapshot multi-form-state) )
|
||||
(clojure.pprint/pprint (:snapshot multi-form-state))
|
||||
(mm/default-render-wizard
|
||||
this request
|
||||
:form-params
|
||||
@@ -1183,7 +1240,7 @@
|
||||
:render-timeline? false))
|
||||
(steps [_]
|
||||
[:basic-details
|
||||
:links ])
|
||||
:links])
|
||||
(get-step [this step-key]
|
||||
(let [step-key-result (mc/parse mm/step-key-schema step-key)
|
||||
[step-key-type step-key] step-key-result]
|
||||
@@ -1193,8 +1250,7 @@
|
||||
(form-schema [_]
|
||||
edit-form-schema)
|
||||
(submit [this {:keys [multi-form-state request-method identity] :as request}]
|
||||
(save-handler request)
|
||||
))
|
||||
(save-handler request)))
|
||||
|
||||
(def edit-wizard (->EditWizard nil nil))
|
||||
|
||||
@@ -1208,7 +1264,7 @@
|
||||
:transaction/status
|
||||
:transaction/type
|
||||
:transaction/memo
|
||||
{ [ :transaction/approval-status :xform iol-ion.query/ident] [:db/ident]}
|
||||
{[:transaction/approval-status :xform iol-ion.query/ident] [:db/ident]}
|
||||
:transaction/amount
|
||||
:transaction/accounts]
|
||||
tx-id)
|
||||
@@ -1250,12 +1306,20 @@
|
||||
::route/account-balance (-> account-balance
|
||||
(mm/wrap-wizard edit-wizard)
|
||||
(mm/wrap-decode-multi-form-state))
|
||||
::route/toggle-amount-mode (-> toggle-amount-mode
|
||||
(mm/wrap-wizard edit-wizard)
|
||||
(mm/wrap-decode-multi-form-state))
|
||||
::route/edit-wizard-new-account (->
|
||||
(add-new-entity-handler [:step-params :transaction/accounts]
|
||||
(fn render [cursor request]
|
||||
(let [snapshot (-> request :multi-form-state :snapshot)
|
||||
amount-mode (or (:amount-mode snapshot) "$")
|
||||
total (Math/abs (:transaction/amount snapshot))]
|
||||
(transaction-account-row*
|
||||
{:value cursor
|
||||
:client-id (:client-id (:query-params request))}))
|
||||
:client-id (:client-id (:query-params request))
|
||||
:amount-mode amount-mode
|
||||
:total total})))
|
||||
(fn build-new-row [base _]
|
||||
(assoc base :transaction-account/location "Shared")))
|
||||
(wrap-schema-enforce :query-schema [:map
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
"/location-select" ::location-select
|
||||
"/account-total" ::account-total
|
||||
"/account-balance" ::account-balance
|
||||
"/toggle-amount-mode" ::toggle-amount-mode
|
||||
"/edit-wizard-new-account" ::edit-wizard-new-account
|
||||
"/match-payment" ::link-payment
|
||||
"/match-autopay-invoices" ::link-autopay-invoices
|
||||
|
||||
Reference in New Issue
Block a user