Editing works.

This commit is contained in:
2024-04-03 12:55:37 -07:00
parent 179e3b219b
commit d2ed08f6f9
4 changed files with 255 additions and 205 deletions

View File

@@ -33,6 +33,9 @@
(defprotocol Initializable
(init-step-params [this multi-form-state request]))
(defprotocol CustomNext
(custom-next-handler [this request]))
(defprotocol Discardable
(can-discard? [this step-params])
(discard-changes [this request]))
@@ -70,6 +73,11 @@
:edit-path []
:step-params @cursor)))
(defn get-mfs-field [mfs k]
(or (get (:step-params mfs) k)
(get-in (:snapshot mfs) (conj (or (:edit-path mfs) [])
k))))
(def step-key-schema (mc/schema [:orn {:decode/arbitrary clojure.edn/read-string
:encode/arbitrary pr-str}
[:sub-step [:cat :keyword [:or :int :string]]]
@@ -228,7 +236,7 @@
:else
"forward")))
(defn render-navigate [{ {:keys [wizard] :as request } :request to-step :to-step oob :oob}]
(defn navigate-handler [{{:keys [wizard] :as request} :request to-step :to-step oob :oob}]
(let [current-step (get-current-step wizard)
wizard (navigate wizard to-step)
new-step (get-current-step wizard)
@@ -249,12 +257,15 @@
(def next-handler
(-> (fn [{:keys [wizard] :as request}]
(render-navigate {:request request
:to-step (:to (:query-params request))}))
(let [current-step (get-current-step wizard)]
(if (satisfies? CustomNext current-step)
(custom-next-handler current-step request)
(navigate-handler {:request request
:to-step (:to (:query-params request))}))))
(wrap-ensure-step)
(wrap-schema-enforce :query-schema
[:map
[:to step-key-schema]])))
[:to {:optional true} [:maybe step-key-schema]]])))
(def discard-handler
(->
@@ -326,7 +337,7 @@
(assoc request :wizard (hydrate-from-request linear-wizard request))))))
(defn open-wizard-handler [{:keys [wizard current-step query-params] :as request}]
(cond->
(cond->
(modal-response
[:div#transitioner.flex-1 {:x-data (hx/json {"transitionType" "none"})
:x-ref "transitioner"

View File

@@ -8,6 +8,8 @@
[:invoice/date :xform clj-time.coerce/from-date]
[:invoice/due :xform clj-time.coerce/from-date]
[:invoice/scheduled-payment :xform clj-time.coerce/from-date]
{:invoice/client [:client/code :db/id :client/name]
:invoice/expense-accounts [* {:invoice-expense-account/account [:account/name :db/id
:account/location

View File

@@ -2,7 +2,6 @@
(:require [auto-ap.datomic
:refer [audit-transact conn pull-attr]]
[auto-ap.datomic.accounts :as d-accounts]
[auto-ap.ssr.invoice.common :refer [default-read]]
[auto-ap.datomic.invoices :as d-invoices]
[auto-ap.graphql.utils :refer [assert-can-see-client
assert-not-locked exception->4xx]]
@@ -17,6 +16,7 @@
[auto-ap.ssr.components.multi-modal :as mm]
[auto-ap.ssr.form-cursor :as fc]
[auto-ap.ssr.hx :as hx]
[auto-ap.ssr.invoice.common :refer [default-read]]
[auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]]
[auto-ap.ssr.svg :as svg]
[auto-ap.ssr.utils
@@ -70,10 +70,6 @@
(some? (:vendor/default-account (get-vendor vendor-id))))
;; TODO negative expense accounts for negative invoices?
;; TODO make changing expense accounts work for editing invoices
;; TODO make a change of total automatically change the expense accounts when editing
;; TODO just close when editing, don't go to print screen
(def new-form-schema
[:map
@@ -81,7 +77,9 @@
[:customize-due-and-scheduled? {:optional true :default false :decode/arbitrary (fn [x] (if (= "" x)
false
x))} [:maybe :boolean]]
[:invoice/client entity-id]
[:customize-accounts {:optional true :default :default} [:enum :default :customize]]
[:invoice/client {:optional true} [:maybe entity-id]]
[:invoice/date clj-date-schema]
[:invoice/due {:optional true} [:maybe clj-date-schema]]
[:invoice/scheduled-payment {:optional true} [:maybe clj-date-schema]]
@@ -105,41 +103,57 @@
(defn wrap-schema [s]
[:and s
[:fn (fn [{:keys [:db/id :invoice/invoice-number :invoice/vendor] :as z}]
(println "HERE" id invoice-number vendor z)
[:fn (fn [{:keys [:db/id :invoice/invoice-number :invoice/vendor :invoice/client] :as z}]
(if id
true
(and invoice-number vendor)))]])
(and invoice-number vendor client)))]])
(defn clientize-vendor [{:vendor/keys [terms-overrides automatically-paid-when-due default-account account-overrides] :as vendor} client-id]
(let [terms-override (->> terms-overrides
(if (nil? vendor)
nil
(let [terms-override (->> terms-overrides
(filter (fn [to]
(= (->db-id (:vendor-terms-override/client to))
client-id)))
(map :vendor-terms-override/terms)
first)
account (or (->> account-overrides
(filter (fn [to]
(= (->db-id (:vendor-terms-override/client to))
(= (->db-id (:vendor-account-override/client to))
client-id)))
(map :vendor-terms-override/terms)
(map :vendor-account-override/account)
first)
account (or (->> account-overrides
(filter (fn [to]
(= (->db-id (:vendor-account-override/client to))
client-id)))
(map :vendor-account-override/account)
first)
default-account)
account (d-accounts/clientize account client-id)
default-account)
account (d-accounts/clientize account client-id)
automatically-paid-when-due (->> automatically-paid-when-due
(filter (fn [to]
(= (->db-id to)
client-id)))
seq
boolean)
vendor (cond-> vendor
terms-override (assoc :vendor/terms terms-override)
true (assoc :vendor/automatically-paid-when-due automatically-paid-when-due
:vendor/default-account account)
true (dissoc :vendor/account-overrides :vendor/terms-overrides))]
vendor))
automatically-paid-when-due (->> automatically-paid-when-due
(filter (fn [to]
(= (->db-id to)
client-id)))
seq
boolean)
vendor (cond-> vendor
terms-override (assoc :vendor/terms terms-override)
true (assoc :vendor/automatically-paid-when-due automatically-paid-when-due
:vendor/default-account account)
true (dissoc :vendor/account-overrides :vendor/terms-overrides))]
vendor)))
(defn account-prediction* [{:keys [multi-form-state]}]
(let [vendor (clientize-vendor (get-vendor (:invoice/vendor (:step-params multi-form-state)))
(->db-id (:invoice/client (:step-params multi-form-state))))
account-name (:account/name (:vendor/default-account vendor))
value (mm/get-mfs-field multi-form-state :customize-accounts)]
(when vendor
(com/radio-list {:name "step-params[customize-accounts]"
:value (name value)
:options (filter identity
[(when account-name {:value (name :default)
:content (com/pill {:color :primary} account-name)})
{:value (name :customize)
:content [:div "Customize accounts"]}])}))))
(defrecord BasicDetailsStep [linear-wizard]
@@ -153,155 +167,178 @@
[])
(step-schema [_]
(wrap-schema (mut/select-keys (mm/form-schema linear-wizard) #{:invoice/client :invoice/vendor :invoice/date :invoice/due :invoice/scheduled-payment :invoice/total :invoice/invoice-number :db/id :customize-due-and-scheduled?})))
(wrap-schema (mut/select-keys (mm/form-schema linear-wizard) #{:invoice/client :invoice/vendor :invoice/date :invoice/due :invoice/scheduled-payment :invoice/total :invoice/invoice-number :db/id :customize-due-and-scheduled? :customize-accounts})))
(render-step [this request]
(mm/default-render-step
linear-wizard this
:head [:div.p-2 "New invoice"]
:body (mm/default-step-body
{}
[:div {:x-data (hx/json {:clientId (or (:db/id (:client request))
(fc/field-value (:invoice/client fc/*current*)))
:vendorId (fc/field-value (:invoice/vendor fc/*current*))
:date (-> (fc/field-value (:invoice/date fc/*current*))
(atime/unparse-local atime/normal-date))
:due (some-> (fc/field-value (:invoice/due fc/*current*))
(atime/unparse-local atime/normal-date))
:scheduledPayment (some-> (fc/field-value (:invoice/scheduled-payment fc/*current*))
(atime/unparse-local atime/normal-date))
:customizeDueAndScheduled (fc/field-value (:customize-due-and-scheduled? fc/*current*))})}
(fc/with-field :db/id
(when (fc/field-value)
(render-step
[this {:keys [multi-form-state] :as request}]
(let [extant? (mm/get-mfs-field multi-form-state :db/id)]
(mm/default-render-step
linear-wizard this
:head [:div.p-2 (if extant?
"Edit invoice"
"New invoice")]
:body (mm/default-step-body
{}
[:div {:x-data (hx/json {:clientId (or (fc/field-value (:invoice/client fc/*current*))
(:db/id (:client request)))
:vendorId (fc/field-value (:invoice/vendor fc/*current*))
:date (-> (fc/field-value (:invoice/date fc/*current*))
(atime/unparse-local atime/normal-date))
:due (some-> (fc/field-value (:invoice/due fc/*current*))
(atime/unparse-local atime/normal-date))
:scheduledPayment (some-> (fc/field-value (:invoice/scheduled-payment fc/*current*))
(atime/unparse-local atime/normal-date))
:customizeDueAndScheduled (fc/field-value (:customize-due-and-scheduled? fc/*current*))})}
(fc/with-field :db/id
(when extant?
(com/hidden {:name (fc/field-name)
:value (fc/field-value)})))
(fc/with-field :customize-due-and-scheduled?
(com/hidden {:name (fc/field-name)
:value (fc/field-value)})))
(fc/with-field :customize-due-and-scheduled?
(com/hidden {:name (fc/field-name)
:value (fc/field-value)
:x-model "customizeDueAndScheduled"}))
(fc/with-field :invoice/client
(if (:client request)
(com/hidden {:name (fc/field-name)
:value (:db/id (:client request))})
:value (fc/field-value)
:x-model "customizeDueAndScheduled"}))
(fc/with-field :invoice/client
(if (or (:client request) extant?)
(com/hidden {:name (fc/field-name)
:value (or (mm/get-mfs-field multi-form-state :invoice/client)
(:db/id (:client request)))})
(com/validated-field
{:label "Client"
: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 :company-search)
:value (fc/field-value)
:content-fn (fn [c] (pull-attr (dc/db conn) :client/name c))
:x-model "clientId"})])))
(fc/with-field :invoice/vendor
(com/validated-field
{:label "Client"
{:label "Vendor"
:errors (fc/field-errors)}
[:div.w-96
(com/typeahead {:name (fc/field-name)
:error? (fc/error?)
:disabled (boolean (-> request :multi-form-state :snapshot :db/id))
:class "w-96"
:placeholder "Search..."
:url (bidi/path-for ssr-routes/only-routes :company-search)
:url (bidi/path-for ssr-routes/only-routes :vendor-search)
:value (fc/field-value)
:content-fn (fn [c] (pull-attr (dc/db conn) :client/name c))
:x-model "clientId"})])))
(fc/with-field :invoice/vendor
(com/validated-field
{:label "Vendor"
:errors (fc/field-errors)}
[:div.w-96
(com/typeahead {:name (fc/field-name)
:error? (fc/error?)
:disabled (boolean (-> request :multi-form-state :snapshot :db/id))
: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"})]))
:content-fn (fn [c] (pull-attr (dc/db conn) :vendor/name c))
:x-model "vendorId"})]))
[:div.flex.items-center.gap-2
(fc/with-field :invoice/date
(com/validated-field
{:label "Date"
:errors (fc/field-errors)}
[:div {:class "w-24"}
(com/date-input {:value (some-> (fc/field-value)
(atime/unparse-local atime/normal-date))
:name (fc/field-name)
:error? (fc/field-errors)
:x-model "date"
:placeholder "1/1/2024"})]))
[:div {:x-show "!customizeDueAndScheduled"}
(com/link {"@click" "customizeDueAndScheduled=true"
:x-show "!due && !scheduledPayment"}
"Add due / scheduled payment date")
(com/link {"@click" "customizeDueAndScheduled=true"
:x-show "due || scheduledPayment"}
"Change due / scheduled payment date")]]
(fc/with-field :invoice/due
(com/validated-field
(hx/alpine-appear {:label "Due (optional)"
:errors (fc/field-errors)
:x-show "customizeDueAndScheduled"})
[:div {:class "w-24"
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/due-date)
:x-dispatch:changed "[clientId, vendorId, date]"
:hx-trigger "changed"
:hx-target "this"
:hx-swap "innerHTML"}
(com/date-input {:value (some-> (fc/field-value)
(atime/unparse-local atime/normal-date))
:name (fc/field-name)
:x-model "due"
[:div.flex.items-center.gap-2
(fc/with-field :invoice/date
(com/validated-field
{:label "Date"
:errors (fc/field-errors)}
[:div {:class "w-24"}
(com/date-input {:value (some-> (fc/field-value)
(atime/unparse-local atime/normal-date))
:name (fc/field-name)
:error? (fc/field-errors)
:x-model "date"
:placeholder "1/1/2024"})]))
[:div {:x-show "!customizeDueAndScheduled"}
(com/link {"@click" "customizeDueAndScheduled=true"
:x-show "!due && !scheduledPayment"}
"Add due / scheduled payment date")
(com/link {"@click" "customizeDueAndScheduled=true"
:x-show "due || scheduledPayment"}
"Change due / scheduled payment date")]]
(fc/with-field :invoice/due
(com/validated-field
(hx/alpine-appear {:label "Due (optional)"
:errors (fc/field-errors)
:x-show "customizeDueAndScheduled"})
[:div {:class "w-24"
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/due-date)
:x-dispatch:changed "[clientId, vendorId, date]"
:hx-trigger "changed"
:hx-target "this"
:hx-swap "innerHTML"}
(com/date-input {:value (some-> (fc/field-value)
(atime/unparse-local atime/normal-date))
:name (fc/field-name)
:x-model "due"
:error? (fc/field-errors)
:placeholder "1/1/2024"})]))
(fc/with-field :invoice/scheduled-payment
(com/validated-field
(hx/alpine-appear {:label "Scheduled payment (optional)"
:errors (fc/field-errors)
:x-show "customizeDueAndScheduled"})
[:div {:class "w-24"}
[:div {:class "w-24"
:error? (fc/field-errors)
:placeholder "1/1/2024"})]))
(fc/with-field :invoice/scheduled-payment
(com/validated-field
(hx/alpine-appear {:label "Scheduled payment (optional)"
:errors (fc/field-errors)
:x-show "customizeDueAndScheduled"})
[:div {:class "w-24"}
[:div {:class "w-24"
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/scheduled-payment-date)
:x-dispatch:changed "[clientId, vendorId, due]"
:hx-trigger "changed"
:hx-target "this"
:hx-swap "innerHTML"}
(com/date-input {:value (some-> (fc/field-value)
(atime/unparse-local atime/normal-date))
:name (fc/field-name)
:error? (fc/field-errors)
:placeholder "1/1/2024"})]]))
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/scheduled-payment-date)
:x-dispatch:changed "[clientId, vendorId, due]"
:hx-trigger "changed"
:hx-target "this"
:hx-swap "innerHTML"}
(com/date-input {:value (some-> (fc/field-value)
(atime/unparse-local atime/normal-date))
:name (fc/field-name)
:error? (fc/field-errors)
:placeholder "1/1/2024"})]]))
(fc/with-field :invoice/invoice-number
(com/validated-field
{:label "Invoice Number"
:errors (fc/field-errors)}
[:div {:class "w-24"}
(com/text-input {:value (-> (fc/field-value))
:disabled (boolean (-> request :multi-form-state :snapshot :db/id))
:name (fc/field-name)
:error? (fc/field-errors)
:placeholder "HA-123"})]))
(fc/with-field :invoice/total
(com/validated-field
{:label "Total"
:errors (fc/field-errors)}
[:div {:class "w-16"}
(com/money-input {:value (-> (fc/field-value))
:name (fc/field-name)
:class "w-24"
:error? (fc/field-errors)
:placeholder "212.44"})]))
(fc/with-field :invoice/invoice-number
(com/validated-field
{:label "Invoice Number"
:errors (fc/field-errors)}
[:div {:class "w-24"}
(com/text-input {:value (-> (fc/field-value))
:disabled (boolean (-> request :multi-form-state :snapshot :db/id))
:name (fc/field-name)
:error? (fc/field-errors)
:placeholder "HA-123"})]))
(fc/with-field :invoice/total
(com/validated-field
{:label "Total"
:errors (fc/field-errors)}
[:div {:class "w-16"}
(com/money-input {:value (-> (fc/field-value))
:name (fc/field-name)
:class "w-24"
:error? (fc/field-errors)
:placeholder "212.44"})]))
[:div#expense-account-prediction
(hx/alpine-appear
{:x-dispatch:bryce "[vendorId]"
:hx-trigger "load, bryce"
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/account-prediction)
:hx-target "this"
:hx-swap "innerHTML"})]])
[:div#expense-account-prediction
(hx/alpine-appear
{:x-dispatch:bryce "[vendorId]"
:hx-trigger "bryce"
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/account-prediction)
:hx-target "this"
:hx-swap "innerHTML"})
(account-prediction* request)]])
:footer
(mm/default-step-footer linear-wizard this :validation-route ::route/new-wizard-navigate
:next-button (com/button {:color :primary :x-ref "next" :class "w-32"
:hx-put (bidi.bidi/path-for ssr-routes/only-routes
::route/new-wizard-navigate)} "Save"))
:validation-route ::route/new-wizard-navigate)))
mm/CustomNext
(custom-next-handler
[_ request]
(if (= (get-in request [:multi-form-state :step-params :customize-accounts])
:customize)
(mm/navigate-handler {:request request
:to-step :accounts})
(html-response [:div]
:headers {"location" (bidi.bidi/path-for ssr-routes/only-routes ::route/new-invoice-submit)}
:status 308)
#_(mm/navigate-handler {:request request
:to-step :next-steps}))))
:footer
(mm/default-step-footer linear-wizard this :validation-route ::route/new-wizard-navigate
:next-button (com/button {:color :primary :x-ref "next" :class "w-32"} "Save"))
:validation-route ::route/new-wizard-navigate)))
(defn- location-select*
[{:keys [name account-location client-locations value]}]
@@ -467,8 +504,6 @@
:invoice-expense-account/amount (:invoice/total (:step-params current))}])
(:step-params current))))
;; TODO closing should render the final row
(defrecord NextSteps [linear-wizard]
mm/ModalWizardStep
(step-name [_]
@@ -587,45 +622,61 @@
new-form-schema)
(submit [this {:keys [multi-form-state request-method identity] :as request}]
(let [invoice (:snapshot multi-form-state)
extant? (:db/id invoice)
client-id (->db-id (:invoice/client invoice))
vendor-id (->db-id (:invoice/vendor invoice))
transaction [:upsert-invoice (-> multi-form-state
:snapshot
(assoc :db/id (or (:db/id invoice) "invoice"))
(dissoc :customize-due-and-scheduled? :invoice/journal-entry :invoice/payments)
(assoc :invoice/expense-accounts (if-let [ieas (seq (-> multi-form-state :snapshot :invoice/expense-accounts))]
ieas
(dissoc :customize-due-and-scheduled? :invoice/journal-entry :invoice/payments :customize-accounts)
(assoc :invoice/expense-accounts (if (= :customize (:customize-accounts invoice))
(-> multi-form-state :step-params :invoice/expense-accounts)
[{:db/id "123"
:invoice-expense-account/location "Shared"
:invoice-expense-account/account (:db/id (:vendor/default-account (clientize-vendor (get-vendor vendor-id)
client-id)))
:invoice-expense-account/amount (:invoice/total (:snapshot multi-form-state))}]))
:invoice-expense-account/amount (or (:invoice/total (:step-params multi-form-state))
(:invoice/total (:snapshot multi-form-state)))}]))
(assoc
:invoice/outstanding-balance (:invoice/total (:snapshot multi-form-state))
:invoice/outstanding-balance (or
(:invoice/total (:step-params multi-form-state))
(:invoice/total (:snapshot multi-form-state)))
:invoice/import-status :import-status/imported
:invoice/status :invoice-status/unpaid)
(maybe-spread-locations)
(update :invoice/date coerce/to-date)
(update :invoice/due coerce/to-date))]]
(update :invoice/due coerce/to-date)
(update :invoice/scheduled-payment coerce/to-date))]]
(assert-invoice-amounts-add-up (second transaction))
(when-not (:db/id invoice)
(when-not extant?
(assert-no-conflicting invoice))
(exception->4xx #(assert-can-see-client (:identity request) client-id))
(exception->4xx #(assert-not-locked client-id (:invoice/date invoice)))
(let [transaction-result (audit-transact [transaction] (:identity request))]
(solr/touch-with-ledger (get-in transaction-result [:tempids "invoice"]))
(assoc-in (mm/render-navigate {:request (assoc-in request [:multi-form-state :snapshot :db/id] (get-in transaction-result [:tempids "invoice"]))
:to-step :next-steps})
[:headers "hx-trigger"] "invalidated")))))
(if extant?
(html-response
(@(resolve 'auto-ap.ssr.invoices/row*) identity (dc/pull (dc/db conn) default-read (:db/id invoice)) {:flash? true
:request request})
:headers (cond-> {"hx-trigger" "modalclose"
"hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id invoice))
"hx-reswap" "outerHTML"}))
(assoc-in (mm/navigate-handler {:request (assoc-in request [:multi-form-state :snapshot :db/id] (get-in transaction-result [:tempids "invoice"]))
:to-step :next-steps})
[:headers "hx-trigger"] "invalidated"))))))
(def new-wizard (->NewWizard2 nil nil))
(defn initial-new-wizard-state [request]
(mm/->MultiStepFormState {:invoice/date (time/now)}
(mm/->MultiStepFormState {:invoice/date (time/now)
:customize-accounts :default}
[]
{:invoice/date (time/now)}))
{:invoice/date (time/now)
:customize-accounts :default}))
@@ -634,9 +685,11 @@
(let [entity (dc/pull (dc/db conn) default-read (:db/id (:route-params request)))
entity (select-keys entity (mut/keys new-form-schema))]
(mm/->MultiStepFormState entity
(mm/->MultiStepFormState (assoc entity
:customize-accounts :customize)
[]
entity)))
(assoc entity
:customize-accounts :customize))))
(defn location-select [{{:keys [name account-id client-id value] :as qp} :query-params}]
(html-response (location-select* {:name name
@@ -683,27 +736,10 @@
:error? false
:placeholder "1/1/2024"}))))
(defn account-prediction [{:keys [multi-form-state form-errors]}]
(let [vendor (clientize-vendor (get-vendor (:invoice/vendor (:step-params multi-form-state)))
(->db-id (:invoice/client (:step-params multi-form-state))))]
(html-response
(if-let [account-name (:account/name (:vendor/default-account vendor))]
[:div {:class "transition duration-300 ease-in-out htmx-added:opacity-0 opacity-100"}
[:label {:class "block mb-2 text-sm font-medium text-gray-900 dark:text-white"} "Default expense account"]
[:div.flex.gap-2.items-center (com/pill {:color :primary} account-name)
(com/validated-save-button (cond-> {:errors form-errors
:color :secondary
;;:x-data (hx/json {})
:class "w-24"
:hx-put (hu/url (bidi/path-for ssr-routes/only-routes ::route/new-wizard-navigate)
{:from (mm/encode-step-key :basic-details)
:to (mm/encode-step-key :accounts)})
:hx-target "closest form"})
"Change"
[:div.w-5.h-5 svg/arrow-right])]]
[:div]))))
(defn account-prediction [{:keys [multi-form-state form-errors] :as request}]
(html-response
(account-prediction* request)))
(def key->handler
(apply-middleware-to-all-handlers

View File

@@ -5,6 +5,7 @@
"/voided" ::voided-page}
"/new" {:get ::new-wizard
:post ::new-invoice-submit
:put ::new-invoice-submit
"/due-date" ::due-date
"/scheduled-payment-date" ::scheduled-payment-date
"/navigate" ::new-wizard-navigate