Editing works.
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user