Every action kind of works.
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -27,6 +27,7 @@
|
|||||||
(def navigation-button-list buttons/navigation-button-list-)
|
(def navigation-button-list buttons/navigation-button-list-)
|
||||||
(def navigation-button buttons/navigation-button-)
|
(def navigation-button buttons/navigation-button-)
|
||||||
(def modal dialog/modal-)
|
(def modal dialog/modal-)
|
||||||
|
(def success-modal dialog/success-modal-)
|
||||||
(def modal-card dialog/modal-card-)
|
(def modal-card dialog/modal-card-)
|
||||||
(def modal-card-advanced dialog/modal-card-advanced-)
|
(def modal-card-advanced dialog/modal-card-advanced-)
|
||||||
(def modal-header dialog/modal-header-)
|
(def modal-header dialog/modal-header-)
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
(ns auto-ap.ssr.components.dialog
|
(ns auto-ap.ssr.components.dialog
|
||||||
(:require
|
(:require
|
||||||
[auto-ap.ssr.hiccup-helper :as hh]
|
[auto-ap.ssr.hiccup-helper :as hh]
|
||||||
[auto-ap.ssr.hx :as hx]))
|
[auto-ap.ssr.components.buttons :as b]
|
||||||
|
[auto-ap.ssr.hx :as hx]
|
||||||
|
[auto-ap.ssr.svg :as svg]))
|
||||||
|
|
||||||
|
|
||||||
(defn modal-
|
(defn modal-
|
||||||
@@ -31,8 +33,7 @@
|
|||||||
content]
|
content]
|
||||||
(when footer [:div {:class "p-4"}
|
(when footer [:div {:class "p-4"}
|
||||||
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex (hx/alpine-appear {:x-show "unexpectedError" :class "dark:bg-red-900 dark:text-red-300"})
|
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex (hx/alpine-appear {:x-show "unexpectedError" :class "dark:bg-red-900 dark:text-red-300"})
|
||||||
[:span {:class "w-2 h-2 mr-1 bg-red-500 rounded-full"}]
|
[:span {:class "w-2 h-2 mr-1 bg-red-500 rounded-full"}] [:span.px-2.py-0.5 "An unexpected error has occured. Integreat staff have been notified."]]
|
||||||
[:span.px-2.py-0.5 "An unexpected error has occured. Integreat staff have been notified."]]
|
|
||||||
(when (:error params )
|
(when (:error params )
|
||||||
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex { :class "dark:bg-red-900 dark:text-red-300"}
|
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex { :class "dark:bg-red-900 dark:text-red-300"}
|
||||||
[:span {:class "w-2 h-2 mr-1 bg-red-500 rounded-full"}]
|
[:span {:class "w-2 h-2 mr-1 bg-red-500 rounded-full"}]
|
||||||
@@ -67,3 +68,18 @@
|
|||||||
[:div (merge params
|
[:div (merge params
|
||||||
{:class (hh/add-class "modal-card bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content flex flex-col max-h-screen max-w-screen" (:class params "")) })
|
{:class (hh/add-class "modal-card bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content flex flex-col max-h-screen max-w-screen" (:class params "")) })
|
||||||
children])
|
children])
|
||||||
|
|
||||||
|
(defn success-modal- [{:keys [title]} & children]
|
||||||
|
(modal- {}
|
||||||
|
(modal-card-advanced-
|
||||||
|
{:class "transition duration-300 ease-in-out htmx-swapping:-translate-x-2/3 htmx-swapping:opacity-0 htmx-swapping:scale-0 htmx-added:translate-x-2/3 htmx-added:opacity-0 htmx-added:scale-0 scale-100 translate-x-0 opacity-100"}
|
||||||
|
(modal-body- {}
|
||||||
|
[:div.flex.flex-col.mt-4.space-y-4.items-center
|
||||||
|
[:div.w-24.h-24.bg-green-50.rounded-full.p-4.text-green-300.animate-gg
|
||||||
|
svg/thumbs-up]
|
||||||
|
[:div.text-center.mt-4
|
||||||
|
[:h3.text-xl.font-bold title]
|
||||||
|
children
|
||||||
|
[:div.mt-6
|
||||||
|
(b/button- {:color :primary
|
||||||
|
"@click" "$dispatch('modalclose');"} "Close")]]]))))
|
||||||
|
|||||||
@@ -305,6 +305,53 @@
|
|||||||
[: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))
|
||||||
|
|
||||||
|
;; 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 ]
|
||||||
|
|
||||||
|
[: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
|
||||||
|
])]]
|
||||||
|
|
||||||
;; Hidden ID field
|
;; Hidden ID field
|
||||||
(fc/with-field :db/id
|
(fc/with-field :db/id
|
||||||
@@ -363,7 +410,7 @@
|
|||||||
(com/radio-card {:options (mapv (fn [[k v]] {:value (name k) :content v})
|
(com/radio-card {:options (mapv (fn [[k v]] {:value (name k) :content v})
|
||||||
transaction-approval-status)
|
transaction-approval-status)
|
||||||
:value (name (or (fc/field-value) :transaction-approval-status/unapproved))
|
:value (name (or (fc/field-value) :transaction-approval-status/unapproved))
|
||||||
:name (fc/field-name)})))])
|
:name (fc/field-name)}))))
|
||||||
: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)))
|
||||||
@@ -502,23 +549,30 @@
|
|||||||
[:h3.text-lg.font-bold.mb-4 "Available Payments"]
|
[:h3.text-lg.font-bold.mb-4 "Available Payments"]
|
||||||
[:div.space-y-2
|
[:div.space-y-2
|
||||||
(for [payment payments]
|
(for [payment payments]
|
||||||
[:form.py-2.border-b.border-gray-200 {:hx-post (bidi/path-for ssr-routes/only-routes
|
[:div.py-2.border-b.border-gray-200 {:hx-post (bidi/path-for ssr-routes/only-routes
|
||||||
::route/match-payment)
|
::route/match-payment)
|
||||||
|
:hx-include "this"
|
||||||
|
:hx-trigger "matchPayment"
|
||||||
|
:hx-params "transaction-id, match-payment-id"
|
||||||
:hx-target "#modal-holder"
|
:hx-target "#modal-holder"
|
||||||
:hx-swap "outerHTML"}
|
: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 "payment-id"
|
:value (-> request :multi-form-state :snapshot :db/id)})
|
||||||
:value (:db/id payment)})
|
|
||||||
|
|
||||||
|
(com/hidden {:name "match-payment-id"
|
||||||
|
:value (:db/id payment)
|
||||||
|
:form ""})
|
||||||
[:div.flex.justify-between.items-center
|
[:div.flex.justify-between.items-center
|
||||||
[:div.space-y-1
|
[:div.space-y-1
|
||||||
[:div.font-medium
|
[:div.font-medium
|
||||||
(str (:payment/invoice-number payment) " - " (-> payment :payment/vendor :vendor/name))]
|
(str (:payment/invoice-number payment) " - " (-> payment :payment/vendor :vendor/name))]
|
||||||
[:div.text-sm.text-gray-600
|
[:div.text-sm.text-gray-600
|
||||||
(str "Amount: $" (format "%.2f" (:payment/amount payment)))
|
(str "Amount: $" (format "%.2f" (:payment/amount payment)))
|
||||||
" • "
|
" • "
|
||||||
(str "Date: " (some-> payment :payment/date coerce/to-date-time (atime/unparse-local atime/normal-date)))]]
|
(str "Date: " (some-> payment :payment/date coerce/to-date-time (atime/unparse-local atime/normal-date)))]]
|
||||||
(com/button {:color :primary :size :small} "Match")]])]]
|
(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.text-center.py-4.text-gray-500 "No matching payments available for this transaction."])]))
|
||||||
|
|
||||||
(defn get-available-autopay-invoices [request]
|
(defn get-available-autopay-invoices [request]
|
||||||
@@ -544,14 +598,18 @@
|
|||||||
[:h3.text-lg.font-bold.mb-4 "Available Autopay Invoices"]
|
[:h3.text-lg.font-bold.mb-4 "Available Autopay Invoices"]
|
||||||
[:div.space-y-4
|
[:div.space-y-4
|
||||||
(for [match-group invoice-matches]
|
(for [match-group invoice-matches]
|
||||||
[:form.border.border-gray-200.rounded.p-4 {:hx-post (bidi/path-for ssr-routes/only-routes
|
[:div.border.border-gray-200.rounded.p-4 {:hx-post (bidi/path-for ssr-routes/only-routes
|
||||||
::route/match-autopay-invoices)
|
::route/match-autopay-invoices)
|
||||||
|
:hx-trigger "matchAutopay"
|
||||||
|
:hx-include "this"
|
||||||
|
:hx-params "transaction-id, autopay-invoice-ids"
|
||||||
:hx-target "#modal-holder"
|
:hx-target "#modal-holder"
|
||||||
:hx-swap "outerHTML"}
|
:hx-swap "outerHTML"}
|
||||||
(com/hidden {:name "transaction-id"
|
|
||||||
:value (get-in request [:multi-form-state :snapshot :db/id])})
|
|
||||||
[:div.space-y-3
|
[:div.space-y-3
|
||||||
[:div.text-sm.font-medium "Match with these invoices:"]
|
[: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]
|
(for [invoice match-group]
|
||||||
[:div.flex.justify-between.items-center.py-2.border-b.border-gray-100
|
[:div.flex.justify-between.items-center.py-2.border-b.border-gray-100
|
||||||
[:div
|
[:div
|
||||||
@@ -559,9 +617,9 @@
|
|||||||
[:div.text-sm.text-gray-600 (-> invoice :invoice/vendor :vendor/name)]]
|
[:div.text-sm.text-gray-600 (-> invoice :invoice/vendor :vendor/name)]]
|
||||||
[:div.text-right
|
[:div.text-right
|
||||||
[:div.font-medium (format "$%.2f" (:invoice/total invoice))]
|
[:div.font-medium (format "$%.2f" (:invoice/total invoice))]
|
||||||
(com/hidden {:name "autopay-invoice-ids[]" :value (:db/id invoice)})]])
|
(com/hidden {:name "autopay-invoice-ids" :value (:db/id invoice) :form ""})]])
|
||||||
[:div.flex.justify-end.mt-4
|
[:div.flex.justify-end.mt-4
|
||||||
(com/button {:color :primary :size :small} "Match")]]])]]
|
(com/a-button {:color :primary :size :small "@click" "$dispatch('matchAutopay')"} "Match")]]])]]
|
||||||
[:div.text-center.py-4.text-gray-500 "No matching autopay invoices available for this transaction."])]))
|
[:div.text-center.py-4.text-gray-500 "No matching autopay invoices available for this transaction."])]))
|
||||||
|
|
||||||
(defn get-available-unpaid-invoices [request]
|
(defn get-available-unpaid-invoices [request]
|
||||||
@@ -587,14 +645,20 @@
|
|||||||
[:h3.text-lg.font-bold.mb-4 "Available Unpaid Invoices"]
|
[:h3.text-lg.font-bold.mb-4 "Available Unpaid Invoices"]
|
||||||
[:div.space-y-4
|
[:div.space-y-4
|
||||||
(for [match-group invoice-matches]
|
(for [match-group invoice-matches]
|
||||||
[:form.border.border-gray-200.rounded.p-4 {:hx-post (bidi/path-for ssr-routes/only-routes
|
[:div.border.border-gray-200.rounded.p-4 {:hx-post (bidi/path-for ssr-routes/only-routes
|
||||||
::route/match-unpaid-invoices)
|
::route/match-unpaid-invoices)
|
||||||
|
:hx-trigger "matchUnpaidInvoices"
|
||||||
|
:hx-include "this"
|
||||||
|
:hx-params "transaction-id, unpaid-invoice-ids"
|
||||||
:hx-target "#modal-holder"
|
:hx-target "#modal-holder"
|
||||||
:hx-swap "outerHTML"}
|
:hx-swap "outerHTML"}
|
||||||
(com/hidden {:name "transaction-id"
|
|
||||||
:value (get-in request [:multi-form-state :snapshot :db/id])})
|
|
||||||
[:div.space-y-3
|
[:div.space-y-3
|
||||||
[:div.text-sm.font-medium "Match with these invoices:"]
|
[: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]
|
(for [invoice match-group]
|
||||||
[:div.flex.justify-between.items-center.py-2.border-b.border-gray-100
|
[:div.flex.justify-between.items-center.py-2.border-b.border-gray-100
|
||||||
[:div
|
[:div
|
||||||
@@ -602,9 +666,9 @@
|
|||||||
[:div.text-sm.text-gray-600 (-> invoice :invoice/vendor :vendor/name)]]
|
[:div.text-sm.text-gray-600 (-> invoice :invoice/vendor :vendor/name)]]
|
||||||
[:div.text-right
|
[:div.text-right
|
||||||
[:div.font-medium (format "$%.2f" (:invoice/outstanding-balance invoice))]
|
[:div.font-medium (format "$%.2f" (:invoice/outstanding-balance invoice))]
|
||||||
(com/hidden {:name "unpaid-invoice-ids" :value (:db/id invoice)})]])
|
(com/hidden {:name "unpaid-invoice-ids" :value (:db/id invoice) :form ""})]])
|
||||||
[:div.flex.justify-end.mt-4
|
[:div.flex.justify-end.mt-4
|
||||||
(com/button {:color :primary :size :small} "Match")]]])]]
|
(com/a-button {:color :primary :size :small "@click" "$dispatch('matchUnpaidInvoices')"} "Match")]]])]]
|
||||||
[:div.text-center.py-4.text-gray-500 "No matching unpaid invoices available for this transaction."])]))
|
[:div.text-center.py-4.text-gray-500 "No matching unpaid invoices available for this transaction."])]))
|
||||||
|
|
||||||
(defn get-available-rules [request]
|
(defn get-available-rules [request]
|
||||||
@@ -636,7 +700,6 @@
|
|||||||
|
|
||||||
(defn transaction-rules-view [request]
|
(defn transaction-rules-view [request]
|
||||||
(let [matching-rules (get-available-rules request)]
|
(let [matching-rules (get-available-rules request)]
|
||||||
(alog/peek ::MATCHING matching-rules)
|
|
||||||
[:div
|
[:div
|
||||||
(if (seq matching-rules)
|
(if (seq matching-rules)
|
||||||
[:div
|
[:div
|
||||||
@@ -645,13 +708,17 @@
|
|||||||
(for [{:keys [:db/id :transaction-rule/note :transaction-rule/description]} matching-rules]
|
(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
|
[:div.py-2.border-b.border-gray-200 {:hx-post (bidi/path-for ssr-routes/only-routes
|
||||||
::route/apply-rule)
|
::route/apply-rule)
|
||||||
|
:hx-params "transaction-id, rule-id"
|
||||||
|
:hx-include "this"
|
||||||
:hx-trigger "applyRule"
|
:hx-trigger "applyRule"
|
||||||
:hx-target "#modal-holder"
|
:hx-target "#modal-holder"
|
||||||
:hx-swap "outerHTML"}
|
:hx-swap "outerHTML"}
|
||||||
(com/hidden {:name "transaction-id"
|
(com/hidden {:name "transaction-id"
|
||||||
:value (get-in request [:multi-form-state :snapshot :db/id])})
|
:value (get-in request [:multi-form-state :snapshot :db/id])
|
||||||
|
:form ""})
|
||||||
(com/hidden {:name "rule-id"
|
(com/hidden {:name "rule-id"
|
||||||
:value id})
|
:value id
|
||||||
|
:form ""})
|
||||||
[:div.flex.justify-between.items-center
|
[:div.flex.justify-between.items-center
|
||||||
[:div.space-y-1
|
[:div.space-y-1
|
||||||
[:div.font-medium note]
|
[:div.font-medium note]
|
||||||
@@ -673,7 +740,6 @@
|
|||||||
:payment/vendor [:vendor/name]}
|
:payment/vendor [:vendor/name]}
|
||||||
]
|
]
|
||||||
(-> tx :transaction/payment :db/id))]
|
(-> tx :transaction/payment :db/id))]
|
||||||
(println "PAYMENT IS" payment)
|
|
||||||
(when payment
|
(when payment
|
||||||
[:div.my-4.p-4.bg-blue-50.rounded
|
[:div.my-4.p-4.bg-blue-50.rounded
|
||||||
[:h3.text-lg.font-bold.mb-2 "Linked Payment"]
|
[:h3.text-lg.font-bold.mb-2 "Linked Payment"]
|
||||||
@@ -694,13 +760,14 @@
|
|||||||
[:div.font-medium "Date"]
|
[:div.font-medium "Date"]
|
||||||
[:div (some-> payment :payment/date (atime/unparse-local atime/normal-date))]]
|
[:div (some-> payment :payment/date (atime/unparse-local atime/normal-date))]]
|
||||||
[:div.mt-4 {:hx-post (bidi/path-for ssr-routes/only-routes ::route/unlink-payment)
|
[:div.mt-4 {:hx-post (bidi/path-for ssr-routes/only-routes ::route/unlink-payment)
|
||||||
:hx-params "unlink-transaction-id"
|
:hx-params "transaction-id"
|
||||||
:hx-trigger "unlinkPayment"
|
:hx-trigger "unlinkPayment"
|
||||||
|
:hx-include "this"
|
||||||
:hx-target "#modal-holder"
|
:hx-target "#modal-holder"
|
||||||
:hx-swap "outerHTML"
|
:hx-swap "outerHTML"
|
||||||
:hx-confirm "Are you sure you want to unlink this payment?"}
|
:hx-confirm "Are you sure you want to unlink this payment?"}
|
||||||
|
|
||||||
(com/hidden {:name "unlink-transaction-id" :value tx-id})
|
(com/hidden {:name "transaction-id" :value tx-id :form ""})
|
||||||
(com/a-button {:color :red :size :small
|
(com/a-button {:color :red :size :small
|
||||||
"@click" "$dispatch('unlinkPayment')"} "Unlink Payment")]]])))
|
"@click" "$dispatch('unlinkPayment')"} "Unlink Payment")]]])))
|
||||||
|
|
||||||
@@ -924,11 +991,9 @@
|
|||||||
[]
|
[]
|
||||||
entity)))
|
entity)))
|
||||||
|
|
||||||
(defn match-payment [{{:strs [transaction-id payment-id]} :form-params :as request}]
|
(defn match-payment [{{:keys [transaction-id match-payment-id]} :form-params :as request}]
|
||||||
(let [transaction-id (Long/parseLong transaction-id)
|
(let [transaction (d-transactions/get-by-id transaction-id)
|
||||||
payment-id (Long/parseLong payment-id)
|
payment (d-checks/get-by-id match-payment-id)]
|
||||||
transaction (d-transactions/get-by-id transaction-id)
|
|
||||||
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) (-> transaction :transaction/client :db/id)))
|
||||||
(exception->4xx #(assert-can-see-client (:identity request) (-> payment :payment/client :db/id)))
|
(exception->4xx #(assert-can-see-client (:identity request) (-> payment :payment/client :db/id)))
|
||||||
@@ -960,21 +1025,20 @@
|
|||||||
(:identity request))
|
(:identity request))
|
||||||
(solr/touch-with-ledger transaction-id)
|
(solr/touch-with-ledger transaction-id)
|
||||||
|
|
||||||
(html-response [:div.p-4
|
(modal-response
|
||||||
[:div.text-2xl.text-center.text-green-600 svg/check]
|
(com/success-modal {:title "Transaction linked successfully"}
|
||||||
[:div.text-center.mt-4
|
|
||||||
[:h3.text-xl.font-bold "Transaction linked successfully"]
|
[:p.text-gray-600.mt-2 "The transaction has been linked to the autopay invoices."]
|
||||||
[:p.text-gray-600.mt-2 "The transaction has been linked to the selected payment."]
|
[:p.text-gray-600.mt-2 "To view the new payment, click "
|
||||||
[:div.mt-6
|
(com/link {:href (hu/url (bidi/path-for ssr-routes/only-routes ::payment-route/all-page)
|
||||||
(com/button {:color :primary
|
{:exact-match-id match-payment-id})
|
||||||
"@click" "$dispatch('modalclose'); $dispatch('refreshTable')"} "Close")]]])))
|
:hx-boost true}
|
||||||
|
"here")
|
||||||
|
" to view it."])
|
||||||
|
:headers {"hx-trigger" "invalidated"})))
|
||||||
|
|
||||||
(defn match-autopay-invoices [{{:strs [transaction-id autopay-invoice-ids]} :form-params :as request}]
|
(defn match-autopay-invoices [{{:keys [transaction-id autopay-invoice-ids]} :form-params :as request}]
|
||||||
(let [transaction-id (Long/parseLong transaction-id)
|
(let [ transaction (d-transactions/get-by-id transaction-id)
|
||||||
autopay-invoice-ids (if (string? autopay-invoice-ids)
|
|
||||||
[(Long/parseLong autopay-invoice-ids)]
|
|
||||||
(mapv #(Long/parseLong %) autopay-invoice-ids))
|
|
||||||
transaction (d-transactions/get-by-id transaction-id)
|
|
||||||
db (dc/db conn)
|
db (dc/db conn)
|
||||||
invoice-clients (set (map #(pull-ref db :invoice/client %) autopay-invoice-ids))
|
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))]
|
invoice-amount (reduce + 0.0 (map #(pull-attr db :invoice/total %) autopay-invoice-ids))]
|
||||||
@@ -1009,18 +1073,14 @@
|
|||||||
|
|
||||||
(solr/touch-with-ledger transaction-id)
|
(solr/touch-with-ledger transaction-id)
|
||||||
|
|
||||||
(html-response [:div.p-4
|
(modal-response
|
||||||
[:div.text-2xl.text-center.text-green-600 svg/check]
|
(com/success-modal {:title "Transaction linked successfully"}
|
||||||
[:div.text-center.mt-4
|
|
||||||
[:h3.text-xl.font-bold "Transaction linked successfully"]
|
[:p.text-gray-600.mt-2 "The transaction has been linked to the autopay invoices."])
|
||||||
[:p.text-gray-600.mt-2 "The transaction has been linked to the selected autopay invoices."]
|
:headers {"hx-trigger" "invalidated"})))
|
||||||
[:div.mt-6
|
|
||||||
(com/button {:color :primary
|
|
||||||
"@click" "$dispatch('modalclose'); $dispatch('refreshTable')"} "Close")]]])))
|
|
||||||
|
|
||||||
(defn match-unpaid-invoices [{{:keys [transaction-id unpaid-invoice-ids]} :form-params :as request}]
|
(defn match-unpaid-invoices [{{:keys [transaction-id unpaid-invoice-ids]} :form-params :as request}]
|
||||||
(let [ _ (println "UNPAID INVOOICES " unpaid-invoice-ids)
|
(let [ transaction (d-transactions/get-by-id transaction-id)
|
||||||
transaction (d-transactions/get-by-id transaction-id)
|
|
||||||
db (dc/db conn)
|
db (dc/db conn)
|
||||||
invoice-clients (set (map #(pull-ref db :invoice/client %) unpaid-invoice-ids))
|
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))]
|
invoice-amount (reduce + 0.0 (map #(pull-attr db :invoice/outstanding-balance %) unpaid-invoice-ids))]
|
||||||
@@ -1057,19 +1117,22 @@
|
|||||||
|
|
||||||
(solr/touch-with-ledger transaction-id)
|
(solr/touch-with-ledger transaction-id)
|
||||||
|
|
||||||
(html-response [:div.p-4
|
(modal-response
|
||||||
[:div.text-2xl.text-center.text-green-600 svg/check]
|
(com/success-modal {:title "Transaction linked successfully"}
|
||||||
[:div.text-center.mt-4
|
|
||||||
[:h3.text-xl.font-bold "Transaction linked successfully"]
|
[:p.text-gray-600.mt-2 "The transaction has been linked to the autopay invoices."]
|
||||||
[:p.text-gray-600.mt-2 "The transaction has been linked to the selected unpaid invoices."]
|
[:p.text-gray-600.mt-2 "To view the new payment, click "
|
||||||
[:div.mt-6
|
(com/link {:href (hu/url (bidi/path-for ssr-routes/only-routes ::payment-route/all-page)
|
||||||
(com/button {:color :primary
|
{:exact-match-id (:db/id (pull-attr (dc/db conn)
|
||||||
"@click" "$dispatch('modalclose'); $dispatch('refreshTable')"} "Close")]]])))
|
:transaction/payment
|
||||||
|
(:db/id transaction)))})
|
||||||
|
:hx-boost true}
|
||||||
|
"here")
|
||||||
|
" to view it."])
|
||||||
|
:headers {"hx-trigger" "invalidated"})))
|
||||||
|
|
||||||
(defn apply-rule [{{:strs [transaction-id rule-id]} :form-params :as request}]
|
(defn apply-rule [{{:keys [transaction-id rule-id]} :form-params :as request}]
|
||||||
(let [transaction-id (Long/parseLong transaction-id)
|
(let [ transaction (-> (d-transactions/get-by-id transaction-id)
|
||||||
rule-id (Long/parseLong rule-id)
|
|
||||||
transaction (-> (d-transactions/get-by-id transaction-id)
|
|
||||||
(update :transaction/date coerce/to-date)) ;; TODO make rule application flexible for date-time and dates
|
(update :transaction/date coerce/to-date)) ;; TODO make rule application flexible for date-time and dates
|
||||||
transaction-rule (dc/pull (dc/db conn)
|
transaction-rule (dc/pull (dc/db conn)
|
||||||
[:transaction-rule/description
|
[:transaction-rule/description
|
||||||
@@ -1095,108 +1158,94 @@
|
|||||||
:transaction/amount (:transaction/amount transaction)}
|
:transaction/amount (:transaction/amount transaction)}
|
||||||
transaction-rule
|
transaction-rule
|
||||||
locations)]
|
locations)]
|
||||||
(alog/peek ::APPLY-RULE updated-tx)
|
|
||||||
(audit-transact [[:upsert-transaction updated-tx]] (:identity request)))
|
(audit-transact [[:upsert-transaction updated-tx]] (:identity request)))
|
||||||
|
|
||||||
(solr/touch-with-ledger transaction-id)
|
(solr/touch-with-ledger transaction-id)
|
||||||
|
|
||||||
(html-response [:div.p-4
|
(modal-response
|
||||||
[:div.text-2xl.text-center.text-green-600 svg/check]
|
(com/success-modal {:title "Rule applied successfully"
|
||||||
[:div.text-center.mt-4
|
}
|
||||||
[:h3.text-xl.font-bold "Rule applied successfully"]
|
[:p.text-gray-600.mt-2 "The selected rule has been applied to this transaction."])
|
||||||
[:p.text-gray-600.mt-2 "The selected rule has been applied to this transaction."]
|
:headers {"hx-trigger" "invalidated"})))
|
||||||
[:div.mt-6
|
|
||||||
(com/button {:color :primary
|
|
||||||
"@click" "$dispatch('modalclose'); $dispatch('refreshTable')"} "Close")]]])))
|
|
||||||
|
|
||||||
(defn unlink-payment [{{:keys [unlink-transaction-id]} :form-params :as request}]
|
(defn unlink-payment [{{:keys [transaction-id]} :form-params :as request}]
|
||||||
(let [ transaction (dc/pull (dc/db conn)
|
(let [transaction (dc/pull (dc/db conn)
|
||||||
'[:transaction/approval-status
|
'[:transaction/approval-status
|
||||||
|
|
||||||
:transaction/date
|
:transaction/date
|
||||||
:transaction/location
|
:transaction/location
|
||||||
:transaction/vendor
|
:transaction/vendor
|
||||||
:transaction/accounts
|
:transaction/accounts
|
||||||
:transaction/status
|
:transaction/status
|
||||||
:transaction/client [:db/id]
|
:transaction/client [:db/id]
|
||||||
{:transaction/payment [:payment/date
|
{:transaction/payment [:payment/date
|
||||||
{[ :payment/status :xform iol-ion.query/ident] [:db/ident]} :db/id]}]
|
{[:payment/status :xform iol-ion.query/ident] [:db/ident]} :db/id]}]
|
||||||
unlink-transaction-id)
|
transaction-id)
|
||||||
payment (-> transaction :transaction/payment)]
|
payment (-> transaction :transaction/payment)]
|
||||||
|
|
||||||
(exception->4xx #(assert-can-see-client (:identity request) (-> transaction :transaction/client :db/id)))
|
(exception->4xx #(assert-can-see-client (:identity request) (-> transaction :transaction/client :db/id)))
|
||||||
(exception->4xx #(assert-not-locked (-> transaction :transaction/client :db/id) (:transaction/date transaction)))
|
(exception->4xx #(assert-not-locked (-> transaction :transaction/client :db/id) (:transaction/date transaction)))
|
||||||
|
|
||||||
(when (not= :payment-status/cleared (-> payment :payment/status))
|
(when (not= :payment-status/cleared (-> payment :payment/status))
|
||||||
(throw (ex-info "Payment can't be undone because it isn't cleared."
|
(throw (ex-info "Payment can't be undone because it isn't cleared."
|
||||||
{:validation-error "Payment can't be undone because it isn't cleared."})))
|
{:validation-error "Payment can't be undone because it isn't cleared."})))
|
||||||
|
|
||||||
(let [is-autopay-payment? (some->> (dc/q {:find ['?sp]
|
(let [is-autopay-payment? (some->> (dc/q {:find ['?sp]
|
||||||
:in ['$ '?payment]
|
:in ['$ '?payment]
|
||||||
:where ['[?ip :invoice-payment/payment ?payment]
|
:where ['[?ip :invoice-payment/payment ?payment]
|
||||||
'[?ip :invoice-payment/invoice ?i]
|
'[?ip :invoice-payment/invoice ?i]
|
||||||
'[(get-else $ ?i :invoice/scheduled-payment "N/A") ?sp]]}
|
'[(get-else $ ?i :invoice/scheduled-payment "N/A") ?sp]]}
|
||||||
(dc/db conn) (:db/id payment))
|
(dc/db conn) (:db/id payment))
|
||||||
seq
|
seq
|
||||||
(map first)
|
(map first)
|
||||||
(every? #(instance? java.util.Date %)))]
|
(every? #(instance? java.util.Date %)))]
|
||||||
(if is-autopay-payment?
|
(if is-autopay-payment?
|
||||||
(audit-transact
|
(audit-transact
|
||||||
(-> [{:db/id (:db/id payment)
|
(-> [{:db/id (:db/id payment)
|
||||||
:payment/status :payment-status/pending}
|
:payment/status :payment-status/pending}
|
||||||
[:upsert-transaction
|
[:upsert-transaction
|
||||||
{:db/id (:db/id transaction)
|
{:db/id (:db/id transaction)
|
||||||
:transaction/approval-status :transaction-approval-status/unapproved
|
:transaction/approval-status :transaction-approval-status/unapproved
|
||||||
:transaction/payment nil
|
:transaction/payment nil
|
||||||
:transaction/vendor nil
|
:transaction/vendor nil
|
||||||
:transaction/location nil
|
:transaction/location nil
|
||||||
:transaction/accounts nil}]
|
:transaction/accounts nil}]
|
||||||
[:db/retractEntity (:db/id payment)]]
|
[:db/retractEntity (:db/id payment)]]
|
||||||
(into (map (fn [[invoice-payment]]
|
(into (map (fn [[invoice-payment]]
|
||||||
[:db/retractEntity invoice-payment])
|
[:db/retractEntity invoice-payment])
|
||||||
(dc/q {:find ['?ip]
|
(dc/q {:find ['?ip]
|
||||||
:in ['$ '?p]
|
:in ['$ '?p]
|
||||||
:where ['[?ip :invoice-payment/payment ?p]]}
|
:where ['[?ip :invoice-payment/payment ?p]]}
|
||||||
(dc/db conn)
|
(dc/db conn)
|
||||||
(:db/id payment)))))
|
(:db/id payment)))))
|
||||||
(:identity request))
|
(:identity request))
|
||||||
(audit-transact
|
(audit-transact
|
||||||
[{:db/id (:db/id payment)
|
[{:db/id (:db/id payment)
|
||||||
:payment/status :payment-status/pending}
|
:payment/status :payment-status/pending}
|
||||||
[:upsert-transaction
|
[:upsert-transaction
|
||||||
{:db/id (:db/id transaction)
|
{:db/id (:db/id transaction)
|
||||||
:transaction/approval-status :transaction-approval-status/unapproved
|
:transaction/approval-status :transaction-approval-status/unapproved
|
||||||
:transaction/payment nil
|
:transaction/payment nil
|
||||||
:transaction/vendor nil
|
:transaction/vendor nil
|
||||||
:transaction/location nil
|
:transaction/location nil
|
||||||
:transaction/accounts nil}]]
|
:transaction/accounts nil}]]
|
||||||
(:identity request))))
|
(:identity request))))
|
||||||
|
|
||||||
(solr/touch-with-ledger unlink-transaction-id)
|
(solr/touch-with-ledger transaction-id)
|
||||||
|
|
||||||
(modal-response
|
(modal-response
|
||||||
(com/modal {}
|
(com/success-modal {:title "Transaction unlinked successfully"}
|
||||||
(com/modal-card-advanced
|
|
||||||
{:class "transition duration-300 ease-in-out htmx-swapping:-translate-x-2/3 htmx-swapping:opacity-0 htmx-swapping:scale-0 htmx-added:translate-x-2/3 htmx-added:opacity-0 htmx-added:scale-0 scale-100 translate-x-0 opacity-100"}
|
[:p.text-gray-600.mt-2 "The transaction has been unlinked from its payment."]
|
||||||
(com/modal-body {}
|
[:p "If you'd like to also void the payment, click "
|
||||||
[:div.flex.flex-col.mt-4.space-y-4.items-center
|
(com/link
|
||||||
[:div.w-24.h-24.bg-green-50.rounded-full.p-4.text-green-300.animate-gg
|
{:hx-boost true
|
||||||
svg/thumbs-up]
|
:href (hu/url (bidi/path-for ssr-routes/only-routes ::payment-route/all-page)
|
||||||
[:div.text-center.mt-4
|
{:exact-match-id (:db/id payment)})}
|
||||||
[:h3.text-xl.font-bold "Transaction unlinked successfully"]
|
"here")
|
||||||
[:p.text-gray-600.mt-2 "The transaction has been unlinked from its payment."]
|
" to view the payment"])
|
||||||
[:p "If you'd like to also void the payment, click "
|
|
||||||
(com/link
|
:headers {"hx-trigger" "invalidated"})))
|
||||||
{:hx-boost true
|
|
||||||
:href (hu/url (bidi/path-for ssr-routes/only-routes ::payment-route/all-page)
|
|
||||||
{:exact-match-id (:db/id payment)})}
|
|
||||||
"here")
|
|
||||||
" to view the payment"]
|
|
||||||
[:div.mt-6
|
|
||||||
(com/button {:color :primary
|
|
||||||
"@click" "$dispatch('modalclose'); $dispatch('refreshTable')"} "Close")]]])))
|
|
||||||
:headers {"hx-trigger" "invalidated"})
|
|
||||||
))
|
|
||||||
|
|
||||||
(defn edit-transaction [{:keys [route-params] :as request}]
|
(defn edit-transaction [{:keys [route-params] :as request}]
|
||||||
(mm/open-wizard-handler (-> request
|
(mm/open-wizard-handler (-> request
|
||||||
@@ -1239,16 +1288,25 @@
|
|||||||
(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/match-payment match-payment
|
::route/match-payment (-> match-payment
|
||||||
::route/match-autopay-invoices match-autopay-invoices
|
(wrap-schema-enforce :form-schema
|
||||||
|
[:map [:transaction-id entity-id]
|
||||||
|
[:match-payment-id entity-id]]))
|
||||||
|
::route/match-autopay-invoices (-> match-autopay-invoices
|
||||||
|
(wrap-schema-enforce :form-schema
|
||||||
|
[:map [:transaction-id entity-id]
|
||||||
|
[:autopay-invoice-ids [:vector {:coerce? true} entity-id]]]))
|
||||||
::route/match-unpaid-invoices (-> match-unpaid-invoices
|
::route/match-unpaid-invoices (-> match-unpaid-invoices
|
||||||
(wrap-schema-enforce :form-schema
|
(wrap-schema-enforce :form-schema
|
||||||
[:map [:transaction-id entity-id]
|
[:map [:transaction-id entity-id]
|
||||||
[:unpaid-invoice-ids [:vector {:coerce? true} entity-id]]]))
|
[:unpaid-invoice-ids [:vector {:coerce? true} entity-id]]]))
|
||||||
::route/apply-rule apply-rule
|
::route/apply-rule (-> apply-rule
|
||||||
|
(wrap-schema-enforce :form-schema
|
||||||
|
[:map [:transaction-id entity-id]
|
||||||
|
[:rule-id entity-id]]))
|
||||||
::route/unlink-payment (-> unlink-payment
|
::route/unlink-payment (-> unlink-payment
|
||||||
(wrap-schema-enforce :form-schema
|
(wrap-schema-enforce :form-schema
|
||||||
[:map [:unlink-transaction-id entity-id]]))}
|
[:map [:transaction-id entity-id]]))}
|
||||||
(fn [h]
|
(fn [h]
|
||||||
(-> h
|
(-> h
|
||||||
(wrap-client-redirect-unauthenticated)))))
|
(wrap-client-redirect-unauthenticated)))))
|
||||||
@@ -210,11 +210,11 @@
|
|||||||
(coerce/to-date-time #inst "2000-01-01"))
|
(coerce/to-date-time #inst "2000-01-01"))
|
||||||
true))]
|
true))]
|
||||||
[:fn
|
[:fn
|
||||||
{:error/message "Invalid date"}
|
{:error/message "Can not look more than four years into the future."}
|
||||||
(fn [d]
|
(fn [d]
|
||||||
(if d
|
(if d
|
||||||
(time/before? (coerce/to-date-time d)
|
(time/before? (coerce/to-date-time d)
|
||||||
(time/plus (time/now) (time/years 2)))
|
(time/plus (time/now) (time/years 4)))
|
||||||
true))]]))
|
true))]]))
|
||||||
|
|
||||||
(def date-transformer
|
(def date-transformer
|
||||||
|
|||||||
Reference in New Issue
Block a user