From 8429d8516cdf0b1908e8ed115d0e61eeed6b4df2 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 10 Mar 2025 09:26:29 -0700 Subject: [PATCH] Switching to radio. --- src/clj/auto_ap/ssr/components/radio.clj | 7 +- src/clj/auto_ap/ssr/transaction/edit.clj | 507 ++++++++++++----------- 2 files changed, 258 insertions(+), 256 deletions(-) diff --git a/src/clj/auto_ap/ssr/components/radio.clj b/src/clj/auto_ap/ssr/components/radio.clj index 379d776e..aa9fc81e 100644 --- a/src/clj/auto_ap/ssr/components/radio.clj +++ b/src/clj/auto_ap/ssr/components/radio.clj @@ -2,11 +2,12 @@ (:require [auto-ap.ssr.hiccup-helper :as hh] [auto-ap.ssr.hx :as hx])) -(defn radio-card- [{:keys [options name title size orientation] :or {size :medium} selected-value :value}] +(defn radio-card- [{:keys [options name title size orientation width] :or {size :medium width "w-48"} selected-value :value}] [:h3 {:class "mb-4 font-semibold text-gray-900 dark:text-white"} title] - [:ul {:class (cond-> "w-48 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white" + [:ul {:class (cond-> " text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white" (= orientation :horizontal) (-> (hh/add-class "flex gap-2 flex-wrap") - (hh/remove-wildcard ["w-" "rounded-lg" "border" "bg-"])))} + (hh/remove-wildcard ["w-" "rounded-lg" "border" "bg-"])) + true (str " " width " "))} (for [{:keys [value content]} options] [:li {:class (cond-> "w-full border-b border-gray-200 rounded-t-lg dark:border-gray-600" (= orientation :horizontal) (-> (hh/remove-wildcard ["w-full" "rounded-"]) diff --git a/src/clj/auto_ap/ssr/transaction/edit.clj b/src/clj/auto_ap/ssr/transaction/edit.clj index 795912be..9d2f0ca2 100644 --- a/src/clj/auto_ap/ssr/transaction/edit.clj +++ b/src/clj/auto_ap/ssr/transaction/edit.clj @@ -79,8 +79,8 @@ :error/path [:transaction-account/location]} (fn [iea] (check-location-belongs (:transaction-account/location iea) - (:transaction-account/account iea)))]]]] - ]) + (:transaction-account/account iea)))]]]]]) + (defn clientize-vendor [{:vendor/keys [terms-overrides automatically-paid-when-due default-account account-overrides] :as vendor} client-id] (if (nil? vendor) @@ -262,7 +262,7 @@ {} [:div {:x-data (hx/json {:clientId (or (fc/field-value (:transaction/client fc/*current*)) (:db/id (:client request))) - :vendorId (fc/field-value (:transaction/vendor fc/*current*))})} + :vendorId (fc/field-value (:transaction/vendor fc/*current*))})} ;; Read-only transaction details [:div.mb-6.border.rounded-lg.p-4.bg-gray-50 @@ -270,147 +270,147 @@ [:div.grid.grid-cols-2.gap-4 [:div [:div.text-sm.font-medium.text-gray-500 "Amount"] - [:div.text-base (format "$%,.2f" (Math/abs (:transaction/amount tx)))] - ] + [:div.text-base (format "$%,.2f" (Math/abs (:transaction/amount tx)))]] + [:div [:div.text-sm.font-medium.text-gray-500 "Date"] - [:div.text-base (some-> tx :transaction/date coerce/to-date-time (atime/unparse-local atime/normal-date))] - ] + [:div.text-base (some-> tx :transaction/date coerce/to-date-time (atime/unparse-local atime/normal-date))]] + [:div [:div.text-sm.font-medium.text-gray-500 "Bank Account"] - [:div.text-base (or (-> tx :transaction/bank-account :bank-account/name) "-")] - ] + [:div.text-base (or (-> tx :transaction/bank-account :bank-account/name) "-")]] + [:div [:div.text-sm.font-medium.text-gray-500 "Post Date"] - [:div.text-base (some-> tx :transaction/post-date coerce/to-date-time (atime/unparse-local atime/normal-date))] - ] + [:div.text-base (some-> tx :transaction/post-date coerce/to-date-time (atime/unparse-local atime/normal-date))]] + [:div [:div.text-sm.font-medium.text-gray-500 "Original Description"] - [:div.text-base (or (:transaction/description-original tx) "-")] - ] + [:div.text-base (or (:transaction/description-original tx) "-")]] + [:div [:div.text-sm.font-medium.text-gray-500 "Simplified Description"] - [:div.text-base (or (:transaction/description-simple tx) "-")] - ] + [:div.text-base (or (:transaction/description-simple tx) "-")]] + [:div [:div.text-sm.font-medium.text-gray-500 "Check Number"] - [:div.text-base (or (:transaction/check-number tx) "-")] - ] + [:div.text-base (or (:transaction/check-number tx) "-")]] + [:div [:div.text-sm.font-medium.text-gray-500 "Status"] - [:div.text-base (or (some-> tx :transaction/status) "-")] - ] + [:div.text-base (or (some-> tx :transaction/status) "-")]] + [:div [:div.text-sm.font-medium.text-gray-500 "Transaction Type"] - [:div.text-base (or (some-> tx :transaction/type) "-")] - ] - ]] + [:div.text-base (or (some-> tx :transaction/type) "-")]]]] + + ;; 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) - db-history (dc/history (dc/db conn)) + [:h3.text-lg.font-semibold.mb-2 "Transaction Links"] + (let [tx-id (mm/get-mfs-field multi-form-state :db/id) + db-history (dc/history (dc/db conn)) - ;; Get current and historical payments linked to this transaction - current-payment (when-let [payment-id (-> (dc/pull (dc/db conn) - '[:transaction/payment] - tx-id) - :transaction/payment - :db/id)] - {:entity-id payment-id :active true}) - historical-payments (when tx-id - (->> (dc/q '[:find ?payment ?inst ?added - :in $ ?e - :where - [?e :transaction/payment ?payment ?tx ?added] - [?tx :db/txInstant ?inst]] - db-history tx-id) - (map (fn [[id date op]] {:entity-id id - :date date - :op op})))) + ;; Get current and historical payments linked to this transaction + current-payment (when-let [payment-id (-> (dc/pull (dc/db conn) + '[:transaction/payment] + tx-id) + :transaction/payment + :db/id)] + {:entity-id payment-id :active true}) + historical-payments (when tx-id + (->> (dc/q '[:find ?payment ?inst ?added + :in $ ?e + :where + [?e :transaction/payment ?payment ?tx ?added] + [?tx :db/txInstant ?inst]] + db-history tx-id) + (map (fn [[id date op]] {:entity-id id + :date date + :op op})))) - all-payments historical-payments ] + all-payments historical-payments] - [:div - ;; Payments section - [:div.mb-3 - [:h4.font-medium.text-gray-700 "Linked Payments:"] - (if (seq all-payments) - [:ul.list-disc.pl-6.mt-1 - (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/vendor [:vendor/name]}] - entity-id)]] - [:li.text-sm.text-gray-600 {:class (when-not op "line-through")} - (if op [:span.text-green-600 "✓ "] "") - (str "Payment #" (:payment/invoice-number payment) " - " - (-> payment :payment/vendor :vendor/name))])] - [:p.text-sm.text-gray-500.italic "No payments linked to this transaction"])] + [:div + ;; Payments section + [:div.mb-3 + [:h4.font-medium.text-gray-700 "Linked Payments:"] + (if (seq all-payments) + [:ul.list-disc.pl-6.mt-1 + (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/vendor [:vendor/name]}] + entity-id)]] + [:li.text-sm.text-gray-600 {:class (when-not op "line-through")} + (if op [:span.text-green-600 "✓ "] "") + (str "Payment #" (:payment/invoice-number payment) " - " + (-> payment :payment/vendor :vendor/name))])] + [:p.text-sm.text-gray-500.italic "No payments linked to this transaction"])]])]] + + ;; Invoices section - ;; Invoices section - ])]] ;; Hidden ID field - (fc/with-field :db/id - (com/hidden {:name (fc/field-name) - :value (fc/field-value)})) + (fc/with-field :db/id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) ;; Hidden client field - (fc/with-field :transaction/client - (com/hidden {:name (fc/field-name) - :value (or (mm/get-mfs-field multi-form-state :transaction/client) - (:db/id (:client request)))})) + (fc/with-field :transaction/client + (com/hidden {:name (fc/field-name) + :value (or (mm/get-mfs-field multi-form-state :transaction/client) + (:db/id (:client request)))})) ;; Editable fields section - [:div.mt-6 - [:h3.text-lg.font-semibold.mb-4 "Editable Fields"]] + [:div.mt-6 + [:h3.text-lg.font-semibold.mb-4 "Editable Fields"]] ;; Vendor field - (fc/with-field :transaction/vendor - (com/validated-field - {:label "Vendor" - :errors (fc/field-errors)} - [:div.w-96 - (com/typeahead {:name (fc/field-name) - :error? (fc/error?) - :class "w-96" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :vendor-search) - :value (fc/field-value) - :content-fn (fn [c] (pull-attr (dc/db conn) :vendor/name c)) - :x-model "vendorId"})])) - [:div.mb-4 - [:span.text-sm.text-gray-500 "Can't find the vendor? " - (com/link {:href (bidi.bidi/path-for - client-routes/routes - :new-vendor) - :target "new"} - "Add new vendor") - " in a new window, then return here."]] + (fc/with-field :transaction/vendor + (com/validated-field + {:label "Vendor" + :errors (fc/field-errors)} + [:div.w-96 + (com/typeahead {:name (fc/field-name) + :error? (fc/error?) + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :vendor-search) + :value (fc/field-value) + :content-fn (fn [c] (pull-attr (dc/db conn) :vendor/name c)) + :x-model "vendorId"})])) + [:div.mb-4 + [:span.text-sm.text-gray-500 "Can't find the vendor? " + (com/link {:href (bidi.bidi/path-for + client-routes/routes + :new-vendor) + :target "new"} + "Add new vendor") + " in a new window, then return here."]] ;; Memo field - (fc/with-field :transaction/memo - (com/validated-field - {:label "Memo" - :errors (fc/field-errors)} - [:div.w-96 - (com/text-input {:value (-> (fc/field-value)) - :name (fc/field-name) - :error? (fc/field-errors) - :placeholder "Optional note"})])) + (fc/with-field :transaction/memo + (com/validated-field + {:label "Memo" + :errors (fc/field-errors)} + [:div.w-96 + (com/text-input {:value (-> (fc/field-value)) + :name (fc/field-name) + :error? (fc/field-errors) + :placeholder "Optional note"})])) ;; Approval status field - (fc/with-field :transaction/approval-status - (com/validated-field - {:label "Status" - :errors (fc/field-errors)} - (com/radio-card {:options (mapv (fn [[k v]] {:value (name k) :content v}) - transaction-approval-status) - :value (name (or (fc/field-value) :transaction-approval-status/unapproved)) - :name (fc/field-name)})))) + (fc/with-field :transaction/approval-status + (com/validated-field + {:label "Status" + :errors (fc/field-errors)} + (com/radio-card {:options (mapv (fn [[k v]] {:value (name k) :content v}) + transaction-approval-status) + :value (name (or (fc/field-value) :transaction-approval-status/unapproved)) + :name (fc/field-name)})))) :footer (mm/default-step-footer linear-wizard this :validation-route ::route/edit-wizard-navigate) :validation-route ::route/edit-wizard-navigate))) @@ -533,47 +533,44 @@ payments (when client-id (dc/q '[:find [(pull ?p [:db/id :payment/invoice-number :payment/amount :payment/date {:payment/vendor [:db/id :vendor/name]}]) ...] - :in $ ?client - :where - [?p :payment/client ?client] - [?p :payment/status :payment-status/pending]] + :in $ ?client + :where + [?p :payment/client ?client] + [?p :payment/status :payment-status/pending]] (dc/db conn) client-id))] (filter #(dollars= (Math/abs (:transaction/amount tx)) (:payment/amount %)) payments))) (defn payment-matches-view [request] (let [payments (get-available-payments request)] - [:div + [:div (if (seq payments) [:div [:h3.text-lg.font-bold.mb-4 "Available Payments"] - [:div.space-y-2 - (for [payment payments] - [:div.py-2.border-b.border-gray-200 {:hx-post (bidi/path-for ssr-routes/only-routes - ::route/match-payment) - :hx-include "this" - :hx-trigger "matchPayment" - :hx-params "transaction-id, match-payment-id" - :hx-target "#modal-holder" - :hx-swap "outerHTML"} - (com/hidden {:name "transaction-id" - :form "" - :value (-> request :multi-form-state :snapshot :db/id)}) - - - (com/hidden {:name "match-payment-id" - :value (:db/id payment) - :form ""}) - [:div.flex.justify-between.items-center - [:div.space-y-1 - [:div.font-medium - (str (:payment/invoice-number payment) " - " (-> payment :payment/vendor :vendor/name))] - [:div.text-sm.text-gray-600 - (str "Amount: $" (format "%.2f" (:payment/amount payment))) - " • " - (str "Date: " (some-> payment :payment/date coerce/to-date-time (atime/unparse-local atime/normal-date)))]] - (com/a-button {:color :primary :size :small "@click" "$dispatch('matchPayment')"} "Match")]])]] - [:div.text-center.py-4.text-gray-500 "No matching payments available for this transaction."])])) + [:div {:hx-post (bidi/path-for ssr-routes/only-routes ::route/match-payment) + :hx-trigger "matchPayment" + :hx-target "#modal-holder" + :hx-include "this" + :hx-swap "outerHTML"} + (com/hidden {:name "action" + :value "link-payment" + :form ""}) + (com/hidden {:name "transaction-id" + :value (-> request :multi-form-state :snapshot :db/id) + :form ""}) + [:div.space-y-2 + [:label.block.text-sm.font-medium.mb-1 "Select a payment to match:"] + (when payments + (com/radio-card {:options (for [payment payments] + {:value (:db/id payment) + :content (str (:payment/invoice-number payment) " - " + (-> payment :payment/vendor :vendor/name) + " - Amount: $" (format "%.2f" (:payment/amount payment)) + " • Date: " (some-> payment :payment/date coerce/to-date-time (atime/unparse-local atime/normal-date)))}) + :name "payment-id" + :width "w-full"})) + (com/a-button {"@click" "$dispatch('matchPayment')"} "Match" #_[:button.mt-4.w-full.py-2.bg-blue-500.text-white.rounded.hover:bg-blue-600 "Match"])]] ] + [:div.text-center.py-4.text-gray-500 "No matching payments available for this transaction."]) ])) (defn get-available-autopay-invoices [request] (let [tx-id (or (-> request :multi-form-state :snapshot :db/id) @@ -596,30 +593,24 @@ (if (seq invoice-matches) [:div [:h3.text-lg.font-bold.mb-4 "Available Autopay Invoices"] - [:div.space-y-4 - (for [match-group invoice-matches] - [:div.border.border-gray-200.rounded.p-4 {:hx-post (bidi/path-for ssr-routes/only-routes - ::route/match-autopay-invoices) - :hx-trigger "matchAutopay" - :hx-include "this" - :hx-params "transaction-id, autopay-invoice-ids" + [:form {:hx-post (bidi/path-for ssr-routes/only-routes ::route/match-autopay) + :hx-trigger "submit" :hx-target "#modal-holder" :hx-swap "outerHTML"} - [:div.space-y-3 - [:div.text-sm.font-medium "Match with these invoices:"] (com/hidden {:name "transaction-id" - :form "" - :value (-> request :multi-form-state :snapshot :db/id)}) + :value (get-in request [:multi-form-state :snapshot :db/id]) + :form ""}) + [:div.space-y-2 + [:label.block.text-sm.font-medium.mb-1 "Select an autopay invoice to apply:"] + (for [match-group invoice-matches] (for [invoice match-group] - [:div.flex.justify-between.items-center.py-2.border-b.border-gray-100 - [:div - [:div.font-medium (:invoice/invoice-number invoice)] - [:div.text-sm.text-gray-600 (-> invoice :invoice/vendor :vendor/name)]] - [:div.text-right - [:div.font-medium (format "$%.2f" (:invoice/total invoice))] - (com/hidden {:name "autopay-invoice-ids" :value (:db/id invoice) :form ""})]]) - [:div.flex.justify-end.mt-4 - (com/a-button {:color :primary :size :small "@click" "$dispatch('matchAutopay')"} "Match")]]])]] + [:div.flex.items-center + [:input {:type :radio :value (:db/id invoice) :name "autopay-invoice-id"}] + [: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/total invoice))]]]))] + [:button.mt-4.w-full.py-2.bg-blue-500.text-white.rounded.hover:bg-blue-600 "Match"]]] [:div.text-center.py-4.text-gray-500 "No matching autopay invoices available for this transaction."])])) (defn get-available-unpaid-invoices [request] @@ -629,7 +620,7 @@ client-id (or (get-in request [:multi-form-state :snapshot :transaction/client]) (get-in request [:client :db/id])) matches-set (when (and tx client-id) - (i-transactions/match-transaction-to-unpaid-invoices + (i-transactions/match-transaction-to-unpaid-invoices (:transaction/amount tx) client-id))] (when matches-set @@ -643,32 +634,24 @@ (if (seq invoice-matches) [:div [:h3.text-lg.font-bold.mb-4 "Available Unpaid Invoices"] - [:div.space-y-4 - (for [match-group invoice-matches] - [:div.border.border-gray-200.rounded.p-4 {:hx-post (bidi/path-for ssr-routes/only-routes - ::route/match-unpaid-invoices) - :hx-trigger "matchUnpaidInvoices" - :hx-include "this" - :hx-params "transaction-id, unpaid-invoice-ids" - :hx-target "#modal-holder" - :hx-swap "outerHTML"} - - [:div.space-y-3 - [:div.text-sm.font-medium "Match with these invoices:"] - (com/hidden {:name "transaction-id" - :form "" - :value (-> request :multi-form-state :snapshot :db/id)}) - - (for [invoice match-group] - [:div.flex.justify-between.items-center.py-2.border-b.border-gray-100 - [:div - [:div.font-medium (:invoice/invoice-number invoice)] - [:div.text-sm.text-gray-600 (-> invoice :invoice/vendor :vendor/name)]] - [:div.text-right - [:div.font-medium (format "$%.2f" (:invoice/outstanding-balance invoice))] - (com/hidden {:name "unpaid-invoice-ids" :value (:db/id invoice) :form ""})]]) - [:div.flex.justify-end.mt-4 - (com/a-button {:color :primary :size :small "@click" "$dispatch('matchUnpaidInvoices')"} "Match")]]])]] + [:form {:hx-post (bidi/path-for ssr-routes/only-routes ::route/match-unpaid-invoices) + :hx-trigger "submit" + :hx-target "#modal-holder" + :hx-swap "outerHTML"} + (com/hidden {:name "transaction-id" + :value (get-in request [:multi-form-state :snapshot :db/id]) + :form ""}) + [:div.space-y-2 + [:label.block.text-sm.font-medium.mb-1 "Select an unpaid invoice to apply:"] + (for [match-group invoice-matches] + (for [invoice match-group] + [:div.flex.items-center + [:input {:type :radio :value (:db/id invoice) :name "unpaid-invoice-id"}] + [: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))]]]))] + [:button.mt-4.w-full.py-2.bg-blue-500.text-white.rounded.hover:bg-blue-600 "Match"]]] [:div.text-center.py-4.text-gray-500 "No matching unpaid invoices available for this transaction."])])) (defn get-available-rules [request] @@ -685,18 +668,18 @@ :transaction-rule/client :transaction-rule/bank-account :transaction-rule/yodlee-merchant]) :where - [?r :transaction-rule/description] - ] + [?r :transaction-rule/description]] + (dc/db conn))] (when tx (->> patterns (map first) (filter (fn [rule] - (rm/rule-applies? (-> tx - (update :transaction/date coerce/to-date) - ) (-> rule - (update :transaction-rule/description #(some-> % iol-ion.query/->pattern)))))) - )))) + (rm/rule-applies? (-> tx + (update :transaction/date coerce/to-date)) + (-> rule + (update :transaction-rule/description #(some-> % iol-ion.query/->pattern)))))))))) + (defn transaction-rules-view [request] (let [matching-rules (get-available-rules request)] @@ -704,27 +687,22 @@ (if (seq matching-rules) [:div [:h3.text-lg.font-bold.mb-4 "Matching Transaction Rules"] - [:div.space-y-2 - (for [{:keys [:db/id :transaction-rule/note :transaction-rule/description]} matching-rules] - [:div.py-2.border-b.border-gray-200 {:hx-post (bidi/path-for ssr-routes/only-routes - ::route/apply-rule) - :hx-params "transaction-id, rule-id" - :hx-include "this" - :hx-trigger "applyRule" + [:form {:hx-post (bidi/path-for ssr-routes/only-routes ::route/apply-rule) + :hx-trigger "submit" :hx-target "#modal-holder" :hx-swap "outerHTML"} - (com/hidden {:name "transaction-id" + (com/hidden {:name "transaction-id" :value (get-in request [:multi-form-state :snapshot :db/id]) :form ""}) - (com/hidden {:name "rule-id" - :value id - :form ""}) - [:div.flex.justify-between.items-center - [:div.space-y-1 - [:div.font-medium note] - [:div.text-sm.text-gray-600 - (str "Pattern: " description)]] - (com/a-button {:color :primary :size :small "@click" "$dispatch('applyRule')"} "Apply")]])]] + [:div.space-y-2 + [:label.block.text-sm.font-medium.mb-1 "Select a rule to apply:"] + (for [{:keys [:db/id :transaction-rule/note :transaction-rule/description]} matching-rules] + [:div.flex.items-center + [:input {:type :radio :value id :name "rule-id"}] + [:div.ml-3 + [:span.block.text-sm.font-medium note] + [:span.block.text-sm.text-gray-500 description]]])] + [:button.mt-4.w-full.py-2.bg-blue-500.text-white.rounded.hover:bg-blue-600 "Apply"]]] [:div.text-center.py-4.text-gray-500 "No matching rules found for this transaction."])])) (defn payment-info-view [request] @@ -734,11 +712,11 @@ payment (dc/pull (dc/db conn) '[:payment/amount - [:payment/date :xform clj-time.coerce/from-date] - { [ :payment/status :xform iol-ion.query/ident] [:db/ident] + [:payment/date :xform clj-time.coerce/from-date] + { [ :payment/status :xform iol-ion.query/ident] [:db/ident] - :payment/vendor [:vendor/name]} - ] + :payment/vendor [:vendor/name]}] + (-> tx :transaction/payment :db/id))] (when payment [:div.my-4.p-4.bg-blue-50.rounded @@ -752,7 +730,7 @@ [:div (-> payment :payment/vendor :vendor/name)]] [:div.flex.justify-between [:div.font-medium "Amount"] - [:div (some->> (:payment/amount payment) (format "$%.2f" ))]] + [:div (some->> (:payment/amount payment) (format "$%.2f"))]] [:div.flex.justify-between [:div.font-medium "Status"] [:div (some-> payment :payment/status name)]] @@ -839,7 +817,7 @@ (transaction-rules-view request)] [:div {:x-show "activeForm === 'manual'", :x-transition:enter "transition ease-out duration-500", :x-transition:enter-start "opacity-0 transform scale-95", :x-transition:enter-end "opacity-100 transform scale-100"} [:div {} - + (fc/with-field :transaction/accounts (com/validated-field {:errors (fc/field-errors)} @@ -849,7 +827,7 @@ (com/data-grid-header {:class "w-16"})]} (fc/cursor-map #(transaction-account-row* {:value % :client-id (:transaction/client snapshot)})) - + (com/data-grid-new-row {:colspan 4 :hx-get (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-new-account) @@ -868,7 +846,7 @@ :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"]) @@ -880,18 +858,20 @@ :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 {})))))]]] ]) + (com/data-grid-cell {})))))]]]]) :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)) ) + + (defrecord EditWizard [_ current-step] mm/LinearModalWizard (hydrate-from-request @@ -1106,19 +1086,19 @@ (solr/touch-with-ledger transaction-id) -(modal-response - (com/success-modal {:title "Transaction linked successfully"} + (modal-response + (com/success-modal {:title "Transaction linked successfully"} - [:p.text-gray-600.mt-2 "The transaction has been linked to the autopay invoices."] - [:p.text-gray-600.mt-2 "To view the new payment, click " - (com/link {:href (hu/url (bidi/path-for ssr-routes/only-routes ::payment-route/all-page) - {:exact-match-id (:db/id (pull-attr (dc/db conn) - :transaction/payment - (:db/id transaction)))}) - :hx-boost true} - "here") - " to view it."]) - :headers {"hx-trigger" "invalidated"}))) + [:p.text-gray-600.mt-2 "The transaction has been linked to the autopay invoices."] + [:p.text-gray-600.mt-2 "To view the new payment, click " + (com/link {:href (hu/url (bidi/path-for ssr-routes/only-routes ::payment-route/all-page) + {:exact-match-id (:db/id (pull-attr (dc/db conn) + :transaction/payment + (:db/id transaction)))}) + :hx-boost true} + "here") + " to view it."]) + :headers {"hx-trigger" "invalidated"}))) (defn apply-rule [{{:keys [transaction-id rule-id]} :form-params :as request}] (let [ transaction (-> (d-transactions/get-by-id transaction-id) @@ -1152,12 +1132,12 @@ (solr/touch-with-ledger transaction-id) (modal-response - (com/success-modal {:title "Rule applied successfully" - } + (com/success-modal {:title "Rule applied successfully"} + [:p.text-gray-600.mt-2 "The selected rule has been applied to this transaction."]) :headers {"hx-trigger" "invalidated"}))) -(defn unlink-payment [{{:keys [transaction-id]} :form-params :as request}] +(defn unlink-payment [{{:keys [transaction-id] :as fp} :form-params :as request}] (let [transaction (dc/pull (dc/db conn) '[:transaction/approval-status @@ -1241,6 +1221,25 @@ (mm/wrap-wizard edit-wizard) (mm/wrap-init-multi-form-state initial-edit-wizard-state)))) +(def save-schema + (mc/schema + [:and [:map [:action [:enum :apply-rule :unlink-payment :link-unpaid-invoices :link-autopay-invoices :link-payment]]] + [:multi {:dispatch :action} + [:apply-rule [:map + [:transaction-id entity-id] + [:rule-id entity-id]]] + [:unlink-payment [:map + [:transaction-id entity-id]]] + [:link-unpaid-invoices [:map + [:transaction-id entity-id] + [:unpaid-invoice-ids [:vector {:coerce? true} entity-id]]]] + [:link-autopay-invoices [:map + [:transaction-id entity-id] + [:autopay-invoice-ids [:vector {:coerce? true} entity-id]]]] + [:link-payment [:map + [:transaction-id entity-id] + [:payment-id entity-id]]]]])) + (def key->handler (apply-middleware-to-all-handlers {::route/edit-wizard (-> mm/open-wizard-handler @@ -1267,20 +1266,19 @@ (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] - (transaction-account-row* - {:value cursor - :client-id (:client-id (:query-params request))})) - (fn build-new-row [base _] - (assoc base :transaction-account/location "Shared"))) - (wrap-schema-enforce :query-schema [:map - [:client-id {:optional true} - [:maybe entity-id]]])) + (add-new-entity-handler [:step-params :transaction/accounts] + (fn render [cursor request] + (transaction-account-row* + {:value cursor + :client-id (:client-id (:query-params request))})) + (fn build-new-row [base _] + (assoc base :transaction-account/location "Shared"))) + (wrap-schema-enforce :query-schema [:map + [:client-id {:optional true} + [:maybe entity-id]]])) ::route/match-payment (-> match-payment (wrap-schema-enforce :form-schema - [:map [:transaction-id entity-id] - [:match-payment-id entity-id]])) + save-schema)) ::route/match-autopay-invoices (-> match-autopay-invoices (wrap-schema-enforce :form-schema [:map [:transaction-id entity-id] @@ -1295,7 +1293,10 @@ [:rule-id entity-id]])) ::route/unlink-payment (-> unlink-payment (wrap-schema-enforce :form-schema - [:map [:transaction-id entity-id]]))} + save-schema))} (fn [h] (-> h - (wrap-client-redirect-unauthenticated))))) \ No newline at end of file + (wrap-client-redirect-unauthenticated))))) + + +