improvements.

This commit is contained in:
Bryce
2024-03-21 22:24:28 -07:00
parent 87952b79d1
commit 9cf81f6d15
4 changed files with 78 additions and 418 deletions

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,6 @@
(:require [auto-ap.datomic
:refer [conn pull-attr]]
[auto-ap.datomic.accounts :as d-accounts]
[auto-ap.logging :as alog]
[auto-ap.routes.invoice :as route]
[auto-ap.routes.utils
:refer [wrap-client-redirect-unauthenticated]]
@@ -15,7 +14,7 @@
[auto-ap.ssr.svg :as svg]
[auto-ap.ssr.utils
:refer [apply-middleware-to-all-handlers entity-id html-response
wrap-schema-enforce]]
money wrap-schema-enforce]]
[auto-ap.time :as atime]
[bidi.bidi :as bidi]
[datomic.api :as dc]
@@ -24,8 +23,14 @@
(def new-form-schema
[:map
[:invoice/client [:entity-map {:pull [:db/id :client/name :client/accounts]}]]
[:invoice/vendor [:entity-map {:pull [:db/id :vendor/name]}]]])
[:invoice/client entity-id]
[:invoice/vendor entity-id]
[:invoice/expense-accounts
[:vector {:coerce? true}
[:map
[:invoice-expense-account/account entity-id]
[:invoice-expense-account/location :string]
[:invoice-expense-account/amount money]]]]])
(defrecord BasicDetailsStep [linear-wizard]
mm/ModalWizardStep
@@ -160,58 +165,53 @@
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
client-id)))})])
(defn- transaction-rule-account-row*
[account client-id client-locations]
(defn- invoice-expense-account-row*
[{:keys [value client-id]}]
(com/data-grid-row
(-> {:x-data (hx/json {:show (boolean (not (fc/field-value (:new? account))))
:accountId (:db/id (fc/field-value (:invoice/account account)))})
(-> {:x-data (hx/json {:show (boolean (not (fc/field-value (:new? value))))
:accountId (:db/id (fc/field-value (:invoice-expense-account/account value)))})
:data-key "show"
:x-ref "p"}
hx/alpine-mount-then-appear)
(let [account-name (fc/field-name (:transaction-rule-account/account account))]
(list
(fc/with-field :db/id
(com/hidden {:name (fc/field-name)
:value (fc/field-value)}))
(fc/with-field :transaction-rule-account/account
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)}
(account-typeahead* {:value (fc/field-value)
:client-id client-id
:name (fc/field-name)
:x-model "accountId"}))))
(fc/with-field :transaction-rule-account/location
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)
:x-hx-val:account-id "accountId"
:hx-vals (hx/json {:name (fc/field-name)
:clientId client-id})
:x-dispatch:changed "accountId"
:hx-trigger "changed"
:hx-get (bidi/path-for ssr-routes/only-routes ::route/location-select)
:hx-target "find *"
:hx-swap "outerHTML"}
(location-select* {:name (fc/field-name)
:account-location (:account/location (cond->> (:transaction-rule-account/account @account)
(nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn)
'[:account/location])))
:client-locations client-locations
:value (fc/field-value)}))))
(fc/with-field :transaction-rule-account/percentage
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)}
(com/money-input {:name (fc/field-name)
:class "w-16"
:value (some-> (fc/field-value)
(* 100)
(long))}))))))
(fc/with-field :db/id
(com/hidden {:name (fc/field-name)
:value (fc/field-value)}))
(fc/with-field :invoice-expense-account/account
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)}
(account-typeahead* {:value (fc/field-value)
:client-id client-id
:name (fc/field-name)
:x-model "accountId"}))))
(fc/with-field :invoice-expense-account/location
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)
:x-hx-val:account-id "accountId"
:hx-vals (hx/json {:name (fc/field-name)
:clientId client-id})
:x-dispatch:changed "accountId"
:hx-trigger "changed"
:hx-get (bidi/path-for ssr-routes/only-routes ::route/location-select)
:hx-target "find *"
:hx-swap "outerHTML"}
(location-select* {:name (fc/field-name)
:account-location (:account/location (cond->> (:invoice-expense-account/account @value)
(nat-int? (:invoice-expense-account/account @value)) (dc/pull (dc/db conn)
'[:account/location])))
:client-locations (pull-attr (dc/db conn) :client/locations client-id)
:value (fc/field-value)}))))
(fc/with-field :invoice-expense-account/amount
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)}
(com/money-input {:name (fc/field-name)
:class "w-16"
:value (fc/field-value)}))))
(com/data-grid-cell {:class "align-top"}
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
@@ -226,7 +226,7 @@
[])
(step-schema [_]
(mut/select-keys (mm/form-schema linear-wizard) #{}))
(mut/select-keys (mm/form-schema linear-wizard) #{:invoice/expense-accounts}))
(render-step [this {{:keys [snapshot]} :multi-form-state :as request}]
(mm/default-render-step
@@ -235,7 +235,7 @@
:body (mm/default-step-body
{}
[:div {}
(:client/name (:invoice/client snapshot))
(pull-attr (dc/db conn) :client/name (:invoice/client snapshot))
(fc/with-field :invoice/expense-accounts
(com/validated-field
{:errors (fc/field-errors)}
@@ -243,14 +243,13 @@
(com/data-grid-header {:class "w-32"} "Location")
(com/data-grid-header {:class "w-16"} "%")
(com/data-grid-header {:class "w-16"})]}
(fc/cursor-map #(transaction-rule-account-row* %
(some->> snapshot :invoice/client :db/id)
(some->> snapshot :invoice/client :client/locations)))
(fc/cursor-map #(invoice-expense-account-row* {:value %
:client-id (:invoice/client snapshot)}))
(com/data-grid-new-row {:colspan 4
:hx-get (bidi/path-for ssr-routes/only-routes
::route/new-wizard-new-account)
:index (count (fc/field-value))
:tr-params {:hx-vals (hx/json {:client-id (:db/id (:invoice/client snapshot))})}}
:tr-params {:hx-vals (hx/json {:client-id (:invoice/client snapshot)})}}
"New account"))))])
:footer
(mm/default-step-footer linear-wizard this :validation-route ::route/new-wizard-navigate)
@@ -270,13 +269,12 @@
(mm/get-step this current-step)
(mm/get-step this :basic-details)))
(render-wizard [this {:keys [multi-form-state] :as request}]
(alog/peek ::MFS multi-form-state)
(mm/default-render-wizard
this request
:form-params
(-> mm/default-form-props
(assoc :hx-post
(str (bidi/path-for ssr-routes/only-routes ::route/pay-submit))))))
(str (bidi/path-for ssr-routes/only-routes ::route/new-invoice-submit))))))
(steps [_]
[:basic-details
:accounts])
@@ -288,7 +286,9 @@
:accounts (->AccountsStep this)}
step-key)))
(form-schema [_] new-form-schema)
(submit [this {:keys [multi-form-state request-method identity] :as request}]))
(submit [this {:keys [multi-form-state request-method identity] :as request}]
(html-response [:div]
:headers {"hx-trigger" "modalclose"})))
(def new-wizard (->NewWizard2 nil nil))
@@ -312,24 +312,27 @@
(mm/wrap-wizard new-wizard)
(mm/wrap-init-multi-form-state initial-new-wizard-state))
::route/location-select (-> location-select
(wrap-schema-enforce :query-schema [:map
[:name :string]
[:client-id {:optional true}
[:maybe entity-id]]
[:account-id {:optional true}
[:maybe entity-id]]]))
(wrap-schema-enforce :query-schema [:map
[:name :string]
[:client-id {:optional true}
[:maybe entity-id]]
[:account-id {:optional true}
[:maybe entity-id]]]))
::route/new-invoice-submit (-> mm/submit-handler
(mm/wrap-wizard new-wizard)
(mm/wrap-decode-multi-form-state))
::route/new-wizard-navigate (-> mm/next-handler
(mm/wrap-wizard new-wizard)
(mm/wrap-decode-multi-form-state))
::route/new-wizard-new-account (->
(add-new-entity-handler [:step-params :invoice/expense-accounts]
(fn render [cursor request]
(transaction-rule-account-row*
cursor
(:client-id (:query-params request))
(some->> (:client-id (:query-params request)) (pull-attr (dc/db conn) :client/locations))))
(invoice-expense-account-row*
{:value cursor
:client-id (:client-id (:query-params request))}))
(fn build-new-row [base _]
(assoc base :transaction-rule-account/location "Shared")))
(assoc base :invoice-expense-account/location "Shared")))
(wrap-schema-enforce :query-schema [:map
[:client-id {:optional true}
[:maybe entity-id]]]))}

View File

@@ -1087,327 +1087,6 @@
(def pay-wizard
(->PayWizard nil nil nil))
(def new-form-schema
[:map
[:invoice/client [:entity-map {:pull [:db/id :client/name :client/accounts]}]]
[:invoice/vendor [:entity-map {:pull [:db/id :vendor/name]}]]])
(defrecord BasicDetailsStep [linear-wizard]
mm/ModalWizardStep
(step-name [_]
"Basic Details")
(step-key [_]
:basic-details)
(edit-path [_ _]
[])
(step-schema [_]
(mut/select-keys (mm/form-schema linear-wizard) #{:invoice/client :invoice/vendor}))
(render-step [this request]
(mm/default-render-step
linear-wizard this
:head [:div.p-2 "New invoice"]
:body (mm/default-step-body
{}
[:div {}
(fc/with-field :invoice/client
(if (:client request)
(com/hidden {:name (fc/field-name)
:value (: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))})])))
(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?)
: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))})]))
(fc/with-field :invoice/date
(com/validated-field
{:label "Date"
:errors (fc/field-errors)}
[:div {:class "w-24"}
(com/date-input {:value (-> (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/due
(com/validated-field
{:label "Due (optional)"
:errors (fc/field-errors)}
[:div {:class "w-24"}
(com/date-input {:value (-> (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/scheduled-payment
(com/validated-field
{:label "Scheduled payment (optional)"
:errors (fc/field-errors)}
[:div {:class "w-24"}
(com/date-input {:value (-> (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))
: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"})]))])
:footer
(mm/default-step-footer linear-wizard this :validation-route ::route/new-wizard-navigate)
:validation-route ::route/new-wizard-navigate)))
(defn- location-select*
[{:keys [name account-location client-locations value]}]
(com/select {:options (into [["" ""]]
(cond account-location
[[account-location account-location]]
(seq client-locations)
(into [["Shared" "Shared"]]
(for [cl client-locations]
[cl cl]))
:else
[["Shared" "Shared"]]))
:name name
:value value
:class "w-full"}))
(defn- account-typeahead*
[{:keys [name value client-id x-model]}]
[:div.flex.flex-col
(com/typeahead {:name name
:placeholder "Search..."
:url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id)
:id name
:x-model x-model
:value value
:content-fn (fn [value]
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
client-id)))})])
(defn- transaction-rule-account-row*
[account client-id client-locations]
(com/data-grid-row
(-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account)))
(fc/field-value (:transaction-rule-account/account account)))
:location (fc/field-value (:transaction-rule-account/location account))
:show (boolean (not (fc/field-value (:new? account))))})
:data-key "show"
:x-ref "p"}
hx/alpine-mount-then-appear)
(let [account-name (fc/field-name (:transaction-rule-account/account account))]
(list
(fc/with-field :db/id
(com/hidden {:name (fc/field-name)
:value (fc/field-value)}))
(fc/with-field :transaction-rule-account/account
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)}
[:div {:hx-trigger "changed"
:hx-target "next div"
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', value: event.detail.accountId || ''}" account-name)
:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/account-typeahead))
:x-init "$watch('clientId', cid => $dispatch('changed', $data));"}]
(account-typeahead* {:value (fc/field-value)
:client-id client-id
:name (fc/field-name)
:x-model "accountId"}))))
(fc/with-field :transaction-rule-account/location
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)
:x-data (hx/json {:location (fc/field-value)})}
[:div {:hx-trigger "changed"
:hx-target "next *"
:hx-swap "outerHTML"
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || '', value: event.detail.location || ''}" (fc/field-name))
:hx-get (bidi/path-for ssr-routes/only-routes ::route/location-select)
:x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data) )"}]
(location-select* {:name (fc/field-name)
:account-location (:account/location (cond->> (:transaction-rule-account/account @account)
(nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn)
'[:account/location])))
:client-locations client-locations
:x-model "location"
:value (fc/field-value)}))))
(fc/with-field :transaction-rule-account/percentage
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)}
(com/money-input {:name (fc/field-name)
:class "w-16"
:value (some-> (fc/field-value)
(* 100)
(long))}))))))
(com/data-grid-cell {:class "align-top"}
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
(defrecord AccountsStep [linear-wizard]
mm/ModalWizardStep
(step-name [_]
"Details")
(step-key [_]
:accounts)
(edit-path [_ _]
[])
(step-schema [_]
(mut/select-keys (mm/form-schema linear-wizard) #{}))
(render-step [this {{:keys [snapshot]} :multi-form-state :as request}]
(mm/default-render-step
linear-wizard this
:head [:div.p-2 "Invoice accounts "]
:body (mm/default-step-body
{}
[:div {}
(:client/name (:invoice/client snapshot))
(fc/with-field :invoice/expense-accounts
(com/validated-field
{:errors (fc/field-errors)}
(com/data-grid {:headers [(com/data-grid-header {} "Account")
(com/data-grid-header {:class "w-32"} "Location")
(com/data-grid-header {:class "w-16"} "%")
(com/data-grid-header {:class "w-16"})]}
(fc/cursor-map #(transaction-rule-account-row* %
(some->> snapshot :invoice/client :db/id)
(some->> snapshot :invoice/client :client/locations)))
(com/data-grid-new-row {:colspan 4
:hx-get (bidi/path-for ssr-routes/only-routes
::route/new-wizard-new-account)
:index (count (fc/field-value))
:tr-params (hx/bind-alpine-vals {} {"client-id" "clientId"})}
"New account")))) ])
:footer
(mm/default-step-footer linear-wizard this :validation-route ::route/new-wizard-navigate)
:validation-route ::route/new-wizard-navigate)))
(defrecord NewWizard2 [_ current-step]
mm/LinearModalWizard
(hydrate-from-request
[this request]
this)
(navigate [this step-key]
(assoc this :current-step step-key))
(get-current-step [this]
(if current-step
(mm/get-step this current-step)
(mm/get-step this :basic-details)))
(render-wizard [this {:keys [multi-form-state] :as request}]
(alog/peek ::MFS multi-form-state)
(mm/default-render-wizard
this request
:form-params
(-> mm/default-form-props
(assoc :hx-post
(str (bidi/path-for ssr-routes/only-routes ::route/pay-submit))))))
(steps [_]
[:basic-details
:accounts])
(get-step [this step-key]
(let [step-key-result (mc/parse mm/step-key-schema step-key)
[step-key-type step-key] step-key-result]
(get {:basic-details (->BasicDetailsStep this)
:accounts (->AccountsStep this)}
step-key)))
(form-schema [_] new-form-schema)
(submit [this {:keys [multi-form-state request-method identity] :as request}]
#_(let [snapshot (mc/decode
payment-form-schema
(:snapshot multi-form-state)
mt/strip-extra-keys-transformer)
_ (exception->4xx
#(if (= :handwrite-check (:method snapshot))
(when (or (not (some? (:check-number snapshot)))
(= "" (:check-number snapshot)))
(throw (Exception. "Check number is required")))
true))
result (exception->4xx
#(if (= :handwrite-check (:method snapshot))
(add-handwritten-check request this snapshot)
(print-checks-internal (map (fn [i] {:invoice-id (:invoice-id i)
:amount (:amount i)})
(:invoices snapshot))
(:client snapshot)
(:bank-account snapshot)
(cond (= :print-check (:method snapshot))
:payment-type/check
(= :debit (:method snapshot))
:payment-type/debit
(= :cash (:method snapshot))
:payment-type/cash
(= :credit (:method snapshot))
:payment-type/credit
:else :payment-type/debit)
identity)))]
(modal-response
(com/modal {}
(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"}
(com/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]
(when-not (:pdf-url result)
[:div "That's a wrap. Your payment is complete."])
(when (:pdf-url result)
[:div "Your checks are ready. Click "
(com/link {:href (:pdf-url result) :target "_new"} "here")
" to download and print."])
(when (:pdf-url result)
[:div.text-xs.italic [:em "Remember to turn off all scaling and margins."]])])))
:headers {"hx-trigger" "invalidated"}))))
(def new-wizard (->NewWizard2 nil nil))
(defn wrap-status-from-source [handler]
(fn [{:keys [matched-current-page-route] :as request}]
(let [request (cond-> request
@@ -1461,11 +1140,6 @@
{:mode :simple
:has-warning? (boolean has-warning?)}))))
(defn initial-new-wizard-state [request]
(mm/->MultiStepFormState {:TODO nil}
[]
{}))
(def key->handler
(apply-middleware-to-all-handlers
(->
@@ -1491,25 +1165,7 @@
(mm/wrap-wizard pay-wizard)
(mm/wrap-init-multi-form-state initial-pay-wizard-state))
::route/new-wizard (-> mm/open-wizard-handler
(mm/wrap-wizard new-wizard)
(mm/wrap-init-multi-form-state initial-new-wizard-state))
::route/new-wizard-navigate (-> mm/next-handler
(mm/wrap-wizard new-wizard)
(mm/wrap-decode-multi-form-state))
::route/new-wizard-new-account (->
(add-new-entity-handler [:step-params :invoice/expense-accounts]
(fn render [cursor request]
(transaction-rule-account-row*
cursor
(:client-id (:query-params request))
(some->> (:client-id (:query-params request)) (pull-attr (dc/db conn) :client/locations))))
(fn build-new-row [base _]
(assoc base :transaction-rule-account/location "Shared")))
(wrap-schema-enforce :query-schema [:map
[:client-id {:optional true}
[:maybe entity-id]]]))
::route/pay-submit (-> mm/submit-handler
(mm/wrap-wizard pay-wizard)

View File

@@ -4,6 +4,7 @@
"/paid" ::paid-page
"/voided" ::voided-page}
"/new" {:get ::new-wizard
:post ::new-invoice-submit
"/navigate" ::new-wizard-navigate
"/account/new" ::new-wizard-new-account
"/account/location-select" ::location-select}