automatically set scheduled payment
This commit is contained in:
@@ -156,12 +156,14 @@
|
|||||||
(dissoc :size))])
|
(dissoc :size))])
|
||||||
|
|
||||||
(defn date-input- [{:keys [size] :as params}]
|
(defn date-input- [{:keys [size] :as params}]
|
||||||
[:div.shrink
|
[:div.shrink {:x-data (hx/json {:value (:value params)})}
|
||||||
[:input
|
[:input
|
||||||
(-> params
|
(-> params
|
||||||
(update :class (fnil hh/add-class "") default-input-classes)
|
(update :class (fnil hh/add-class "") default-input-classes)
|
||||||
|
(assoc :x-modelable "value")
|
||||||
(assoc :type "text")
|
(assoc :type "text")
|
||||||
(assoc "_" (hiccup/raw "init initDatepicker(me)"))
|
(assoc "_" (hiccup/raw "init initDatepicker(me)"))
|
||||||
|
(assoc "@change" "value = $event.target.value; console.log(value)")
|
||||||
(assoc "hx-on" (hiccup/raw "changeDate: htmx.trigger(this, \"change\")
|
(assoc "hx-on" (hiccup/raw "changeDate: htmx.trigger(this, \"change\")
|
||||||
htmx:beforeCleanupElement: this.dp.destroy()"))
|
htmx:beforeCleanupElement: this.dp.destroy()"))
|
||||||
(update :class #(str % (use-size size) " w-full"))
|
(update :class #(str % (use-size size) " w-full"))
|
||||||
|
|||||||
@@ -15,9 +15,8 @@
|
|||||||
[auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]]
|
[auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]]
|
||||||
[auto-ap.ssr.svg :as svg]
|
[auto-ap.ssr.svg :as svg]
|
||||||
[auto-ap.ssr.utils
|
[auto-ap.ssr.utils
|
||||||
:refer [apply-middleware-to-all-handlers clj-date-schema
|
:refer [->db-id apply-middleware-to-all-handlers clj-date-schema
|
||||||
entity-id html-response money wrap-schema-decode
|
entity-id html-response money wrap-schema-enforce]]
|
||||||
wrap-schema-enforce]]
|
|
||||||
[auto-ap.time :as atime]
|
[auto-ap.time :as atime]
|
||||||
[bidi.bidi :as bidi]
|
[bidi.bidi :as bidi]
|
||||||
[clj-time.core :as time]
|
[clj-time.core :as time]
|
||||||
@@ -30,6 +29,7 @@
|
|||||||
[:invoice/client entity-id]
|
[:invoice/client entity-id]
|
||||||
[:invoice/date clj-date-schema]
|
[:invoice/date clj-date-schema]
|
||||||
[:invoice/due {:optional true} [:maybe clj-date-schema]]
|
[:invoice/due {:optional true} [:maybe clj-date-schema]]
|
||||||
|
[:invoice/scheduled-payment {:optional true} [:maybe clj-date-schema]]
|
||||||
[:invoice/vendor entity-id]
|
[:invoice/vendor entity-id]
|
||||||
[:invoice/expense-accounts
|
[:invoice/expense-accounts
|
||||||
[:vector {:coerce? true}
|
[:vector {:coerce? true}
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
[])
|
[])
|
||||||
|
|
||||||
(step-schema [_]
|
(step-schema [_]
|
||||||
(mut/select-keys (mm/form-schema linear-wizard) #{:invoice/client :invoice/vendor :invoice/date :invoice/due}))
|
(mut/select-keys (mm/form-schema linear-wizard) #{:invoice/client :invoice/vendor :invoice/date :invoice/due :invoice/scheduled-payment}))
|
||||||
|
|
||||||
(render-step [this request]
|
(render-step [this request]
|
||||||
(alog/peek ::check (:multi-form-state request))
|
(alog/peek ::check (:multi-form-state request))
|
||||||
@@ -62,7 +62,9 @@
|
|||||||
(fc/field-value (:invoice/client fc/*current*)))
|
(fc/field-value (:invoice/client fc/*current*)))
|
||||||
:vendorId (fc/field-value (:invoice/vendor fc/*current*))
|
:vendorId (fc/field-value (:invoice/vendor fc/*current*))
|
||||||
:date (-> (fc/field-value (:invoice/date fc/*current*))
|
:date (-> (fc/field-value (:invoice/date fc/*current*))
|
||||||
(atime/unparse-local atime/normal-date))})}
|
(atime/unparse-local atime/normal-date))
|
||||||
|
:due (some-> (fc/field-value (:invoice/due fc/*current*))
|
||||||
|
(atime/unparse-local atime/normal-date))})}
|
||||||
(fc/with-field :invoice/client
|
(fc/with-field :invoice/client
|
||||||
(if (:client request)
|
(if (:client request)
|
||||||
(com/hidden {:name (fc/field-name)
|
(com/hidden {:name (fc/field-name)
|
||||||
@@ -103,7 +105,8 @@
|
|||||||
(atime/unparse-local atime/normal-date))
|
(atime/unparse-local atime/normal-date))
|
||||||
:name (fc/field-name)
|
:name (fc/field-name)
|
||||||
:error? (fc/field-errors)
|
:error? (fc/field-errors)
|
||||||
"@change" "date=$event.target.value" ;; TODO x-model does not work
|
:x-model "date"
|
||||||
|
;; "@change" "date=$event.target.value" ;; TODO x-model does not work
|
||||||
:placeholder "1/1/2024"})]))
|
:placeholder "1/1/2024"})]))
|
||||||
(fc/with-field :invoice/due
|
(fc/with-field :invoice/due
|
||||||
(com/validated-field
|
(com/validated-field
|
||||||
@@ -115,13 +118,15 @@
|
|||||||
:x-hx-val:vendor-id "vendorId"
|
:x-hx-val:vendor-id "vendorId"
|
||||||
:x-hx-val:date "date"
|
:x-hx-val:date "date"
|
||||||
:x-dispatch:changed "[clientId, vendorId, date]"
|
:x-dispatch:changed "[clientId, vendorId, date]"
|
||||||
:x-effect "console.log([clientId, vendorId, date])"
|
|
||||||
:hx-trigger "changed"
|
:hx-trigger "changed"
|
||||||
:hx-target "this"
|
:hx-target "this"
|
||||||
:hx-swap "innerHTML"}
|
:hx-swap "innerHTML"}
|
||||||
(com/date-input {:value (some-> (fc/field-value)
|
(com/date-input {:value (some-> (fc/field-value)
|
||||||
(atime/unparse-local atime/normal-date))
|
(atime/unparse-local atime/normal-date))
|
||||||
:name (fc/field-name)
|
:name (fc/field-name)
|
||||||
|
:x-model "due"
|
||||||
|
|
||||||
|
:x-effect "console.log('hello due', [due])"
|
||||||
:error? (fc/field-errors)
|
:error? (fc/field-errors)
|
||||||
:placeholder "1/1/2024"})]))
|
:placeholder "1/1/2024"})]))
|
||||||
(fc/with-field :invoice/scheduled-payment
|
(fc/with-field :invoice/scheduled-payment
|
||||||
@@ -129,11 +134,19 @@
|
|||||||
{:label "Scheduled payment (optional)"
|
{:label "Scheduled payment (optional)"
|
||||||
:errors (fc/field-errors)}
|
:errors (fc/field-errors)}
|
||||||
[:div {:class "w-24"}
|
[:div {:class "w-24"}
|
||||||
(com/date-input {:value (some-> (fc/field-value)
|
[:div {:class "w-24"
|
||||||
(atime/unparse-local atime/normal-date))
|
|
||||||
:name (fc/field-name)
|
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/scheduled-payment-date)
|
||||||
:error? (fc/field-errors)
|
:x-dispatch:changed "[clientId, vendorId, due]"
|
||||||
:placeholder "1/1/2024"})]))]
|
:x-effect "console.log('hello', [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
|
(fc/with-field :invoice/invoice-number
|
||||||
(com/validated-field
|
(com/validated-field
|
||||||
@@ -280,14 +293,14 @@
|
|||||||
:validation-route ::route/new-wizard-navigate))
|
:validation-route ::route/new-wizard-navigate))
|
||||||
mm/Initializable
|
mm/Initializable
|
||||||
(init-step-params
|
(init-step-params
|
||||||
[_ request]
|
[_ request]
|
||||||
(alog/peek ::INIT {:invoice/expense-accounts [{:db/id "123"
|
(alog/peek ::INIT {:invoice/expense-accounts [{:db/id "123"
|
||||||
:invoice-expense-account/amount 100}]})
|
:invoice-expense-account/amount 100}]})
|
||||||
{:invoice/expense-accounts [{:db/id "123"
|
{:invoice/expense-accounts [{:db/id "123"
|
||||||
:invoice-expense-account/location "Shared"
|
:invoice-expense-account/location "Shared"
|
||||||
:invoice-expense-account/account (ffirst (dc/q '[:find ?a :where [?a :account/name]]
|
:invoice-expense-account/account (ffirst (dc/q '[:find ?a :where [?a :account/name]]
|
||||||
(dc/db conn)))
|
(dc/db conn)))
|
||||||
:invoice-expense-account/amount 100}]}))
|
:invoice-expense-account/amount 100}]}))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -340,24 +353,98 @@
|
|||||||
(pull-attr (dc/db conn) :account/location))
|
(pull-attr (dc/db conn) :account/location))
|
||||||
:client-locations (some->> client-id
|
:client-locations (some->> client-id
|
||||||
(pull-attr (dc/db conn) :client/locations))})))
|
(pull-attr (dc/db conn) :client/locations))})))
|
||||||
|
(defn clientize-vendor [{:vendor/keys [terms-overrides automatically-paid-when-due default-account account-overrides] :as vendor} client-id]
|
||||||
|
(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-account-override/client to))
|
||||||
|
client-id)))
|
||||||
|
(map :vendor-account-override/account)
|
||||||
|
first)
|
||||||
|
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))
|
||||||
|
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(clojure.pprint/pprint
|
||||||
|
(clientize-vendor (dc/pull
|
||||||
|
(dc/db conn)
|
||||||
|
[:vendor/terms
|
||||||
|
:vendor/automatically-paid-when-due
|
||||||
|
{:vendor/default-account d-accounts/default-read
|
||||||
|
:vendor/account-overrides
|
||||||
|
[:vendor-account-override/client
|
||||||
|
{:vendor-account-override/account d-accounts/default-read}]}
|
||||||
|
{:vendor/terms-overrides
|
||||||
|
[:vendor-terms-override/client :vendor-terms-override/terms]}]
|
||||||
|
(ffirst (dc/q '[:find ?v :in $ :where [?v :vendor/name "Sysco"]] (dc/db conn))))
|
||||||
|
(pull-attr (dc/db conn) :db/id [:client/code "DEMO"]))))
|
||||||
|
|
||||||
|
(defn get-vendor [vendor-id]
|
||||||
|
(dc/pull
|
||||||
|
(dc/db conn)
|
||||||
|
[:vendor/terms
|
||||||
|
:vendor/automatically-paid-when-due
|
||||||
|
{:vendor/default-account d-accounts/default-read
|
||||||
|
:vendor/account-overrides
|
||||||
|
[:vendor-account-override/client
|
||||||
|
{:vendor-account-override/account d-accounts/default-read}]}
|
||||||
|
{:vendor/terms-overrides
|
||||||
|
[:vendor-terms-override/client :vendor-terms-override/terms]}]
|
||||||
|
vendor-id))
|
||||||
|
|
||||||
(defn due-date [{:keys [multi-form-state]}]
|
(defn due-date [{:keys [multi-form-state]}]
|
||||||
(alog/peek ::date multi-form-state)
|
(alog/peek ::date multi-form-state)
|
||||||
(let [vendor (dc/pull (dc/db conn)
|
(let [vendor (clientize-vendor (get-vendor (:invoice/vendor (:step-params multi-form-state)))
|
||||||
[:vendor/terms {:vendor/terms-overrides
|
(->db-id (:invoice/client (:step-params multi-form-state))))
|
||||||
[:vendor-terms-override/client :vendor-terms-override/terms]}]
|
|
||||||
(:invoice/vendor (:step-params multi-form-state)))
|
|
||||||
good-date
|
good-date
|
||||||
(or (when (and (:invoice/date (:step-params multi-form-state))
|
(or (when (and (:invoice/date (:step-params multi-form-state))
|
||||||
(-> vendor :vendor/terms)) ;; TODO get specific terms
|
(-> vendor :vendor/terms)) ;; TODO get specific terms
|
||||||
(time/plus (:invoice/date (:step-params multi-form-state))
|
(time/plus (:invoice/date (:step-params multi-form-state))
|
||||||
(time/days (-> vendor :vendor/terms))))
|
(time/days (-> vendor :vendor/terms))))
|
||||||
(:invoice/due (:step-params multi-form-state)))]
|
(:invoice/due (:step-params multi-form-state)))]
|
||||||
(alog/peek ::good-date multi-form-state)
|
|
||||||
|
|
||||||
(html-response
|
(html-response
|
||||||
(com/date-input {:value (some-> good-date
|
(com/date-input {:value (some-> good-date
|
||||||
(atime/unparse-local atime/normal-date))
|
(atime/unparse-local atime/normal-date))
|
||||||
:name "step-params[invoice/due]"
|
:name "step-params[invoice/due]"
|
||||||
|
:x-init (format "due='%s'" (some-> good-date
|
||||||
|
(atime/unparse-local atime/normal-date)))
|
||||||
|
:x-model "due"
|
||||||
|
:error? false
|
||||||
|
:placeholder "1/1/2024"}))))
|
||||||
|
|
||||||
|
(defn scheduled-payment-date [{: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))))
|
||||||
|
good-date
|
||||||
|
(when (and (:invoice/due (:step-params multi-form-state))
|
||||||
|
(:vendor/automatically-paid-when-due vendor)) ;; TODO get specific terms
|
||||||
|
|
||||||
|
(:invoice/due (:step-params multi-form-state)))]
|
||||||
|
|
||||||
|
(html-response
|
||||||
|
(com/date-input {:value (some-> good-date
|
||||||
|
(atime/unparse-local atime/normal-date))
|
||||||
|
:name "step-params[invoice/scheduled-payment]"
|
||||||
:error? false
|
:error? false
|
||||||
:placeholder "1/1/2024"}))))
|
:placeholder "1/1/2024"}))))
|
||||||
|
|
||||||
@@ -369,17 +456,30 @@
|
|||||||
(mm/wrap-init-multi-form-state initial-new-wizard-state))
|
(mm/wrap-init-multi-form-state initial-new-wizard-state))
|
||||||
::route/due-date (-> due-date
|
::route/due-date (-> due-date
|
||||||
#_(wrap-schema-decode :form-schema [:map
|
#_(wrap-schema-decode :form-schema [:map
|
||||||
[:step-params {:optional true}
|
[:step-params {:optional true}
|
||||||
[:maybe
|
[:maybe
|
||||||
[:map
|
[:map
|
||||||
[:invoice/due {:optional true} [:maybe clj-date-schema]]]]]
|
[:invoice/due {:optional true} [:maybe clj-date-schema]]]]]
|
||||||
[:date {:optional true} [:maybe clj-date-schema]]
|
[:date {:optional true} [:maybe clj-date-schema]]
|
||||||
[:due-date {:optional true} [:maybe clj-date-schema]]
|
[:due-date {:optional true} [:maybe clj-date-schema]]
|
||||||
[:client-id {:optional true} [:maybe entity-id]]
|
[:client-id {:optional true} [:maybe entity-id]]
|
||||||
[:vendor-id {:optional true} [:maybe entity-id]]])
|
[:vendor-id {:optional true} [:maybe entity-id]]])
|
||||||
(mm/wrap-wizard new-wizard)
|
(mm/wrap-wizard new-wizard)
|
||||||
(mm/wrap-decode-multi-form-state)
|
(mm/wrap-decode-multi-form-state)
|
||||||
(wrap-nested-form-params))
|
(wrap-nested-form-params))
|
||||||
|
::route/scheduled-payment-date (-> scheduled-payment-date
|
||||||
|
#_(wrap-schema-decode :form-schema [:map
|
||||||
|
[:step-params {:optional true}
|
||||||
|
[:maybe
|
||||||
|
[:map
|
||||||
|
[:invoice/due {:optional true} [:maybe clj-date-schema]]]]]
|
||||||
|
[:date {:optional true} [:maybe clj-date-schema]]
|
||||||
|
[:due-date {:optional true} [:maybe clj-date-schema]]
|
||||||
|
[:client-id {:optional true} [:maybe entity-id]]
|
||||||
|
[:vendor-id {:optional true} [:maybe entity-id]]])
|
||||||
|
(mm/wrap-wizard new-wizard)
|
||||||
|
(mm/wrap-decode-multi-form-state)
|
||||||
|
(wrap-nested-form-params))
|
||||||
::route/location-select (-> location-select
|
::route/location-select (-> location-select
|
||||||
(wrap-schema-enforce :query-schema [:map
|
(wrap-schema-enforce :query-schema [:map
|
||||||
[:name :string]
|
[:name :string]
|
||||||
|
|||||||
@@ -185,28 +185,28 @@
|
|||||||
(mt2/transformer
|
(mt2/transformer
|
||||||
{:decoders
|
{:decoders
|
||||||
{'inst? {:compile (fn [schema _]
|
{'inst? {:compile (fn [schema _]
|
||||||
(let [properties (mc/properties schema)
|
(let [properties (mc/properties schema)
|
||||||
format (:format properties atime/normal-date)]
|
format (:format properties atime/normal-date)]
|
||||||
(fn [m]
|
(fn [m]
|
||||||
(if (string? m)
|
(if (string? m)
|
||||||
(coerce/to-date-time (atime/parse m format))
|
(coerce/to-date-time (atime/parse m format))
|
||||||
|
|
||||||
m))))}}
|
m))))}}
|
||||||
:encoders
|
:encoders
|
||||||
{'inst?
|
{'inst?
|
||||||
{:compile (fn [schema _]
|
{:compile (fn [schema _]
|
||||||
(let [properties (mc/properties schema)
|
(let [properties (mc/properties schema)
|
||||||
format (:format properties atime/normal-date)]
|
format (:format properties atime/normal-date)]
|
||||||
(fn [m]
|
(fn [m]
|
||||||
(cond
|
(cond
|
||||||
(inst? m)
|
(inst? m)
|
||||||
(atime/unparse-local (coerce/to-date-time m) format)
|
(atime/unparse-local (coerce/to-date-time m) format)
|
||||||
|
|
||||||
(instance? org.joda.time.DateTime m)
|
(instance? org.joda.time.DateTime m)
|
||||||
(atime/unparse-local m format)
|
(atime/unparse-local m format)
|
||||||
|
|
||||||
:else
|
:else
|
||||||
m))))}}}))
|
m))))}}}))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -244,6 +244,18 @@
|
|||||||
m))
|
m))
|
||||||
m))))}}}))
|
m))))}}}))
|
||||||
|
|
||||||
|
(defn ->db-id [m]
|
||||||
|
(cond
|
||||||
|
(map? m)
|
||||||
|
(:db/id m)
|
||||||
|
(nat-int? m)
|
||||||
|
m
|
||||||
|
(and (string? m) (not-empty m))
|
||||||
|
(Long/parseLong m)
|
||||||
|
|
||||||
|
:else
|
||||||
|
m))
|
||||||
|
|
||||||
(def pull-transformer
|
(def pull-transformer
|
||||||
(mt2/transformer {:decoders
|
(mt2/transformer {:decoders
|
||||||
{:entity-map
|
{:entity-map
|
||||||
@@ -302,7 +314,7 @@
|
|||||||
(get headers "hx-request"))]
|
(get headers "hx-request"))]
|
||||||
(alog/peek ::check {:enabled? is-htmx-that-should-inherit-url-parameters?
|
(alog/peek ::check {:enabled? is-htmx-that-should-inherit-url-parameters?
|
||||||
:params (:query-params request)})
|
:params (:query-params request)})
|
||||||
|
|
||||||
(if is-htmx-that-should-inherit-url-parameters?
|
(if is-htmx-that-should-inherit-url-parameters?
|
||||||
(handler (update request :query-params (fn [qp]
|
(handler (update request :query-params (fn [qp]
|
||||||
(->> (concat (:hx-query-params request) qp)
|
(->> (concat (:hx-query-params request) qp)
|
||||||
@@ -311,7 +323,7 @@
|
|||||||
|
|
||||||
|
|
||||||
(def dissoc-nil-transformer
|
(def dissoc-nil-transformer
|
||||||
(let [e {:map {:compile (fn [schema _]
|
(let [e {:map {:compile (fn [schema _]
|
||||||
(fn [data]
|
(fn [data]
|
||||||
(if (map? data)
|
(if (map? data)
|
||||||
(filter-vals
|
(filter-vals
|
||||||
@@ -580,7 +592,7 @@
|
|||||||
(with-precision 2
|
(with-precision 2
|
||||||
(double (.setScale (bigdec d) 2 java.math.RoundingMode/HALF_UP))))
|
(double (.setScale (bigdec d) 2 java.math.RoundingMode/HALF_UP))))
|
||||||
|
|
||||||
|
|
||||||
(defn wrap-implied-route-param [handler & {:as route-params}]
|
(defn wrap-implied-route-param [handler & {:as route-params}]
|
||||||
(fn [request]
|
(fn [request]
|
||||||
(handler (update-in request [:route-params] merge route-params))))
|
(handler (update-in request [:route-params] merge route-params))))
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
"/new" {:get ::new-wizard
|
"/new" {:get ::new-wizard
|
||||||
:post ::new-invoice-submit
|
:post ::new-invoice-submit
|
||||||
"/due-date" ::due-date
|
"/due-date" ::due-date
|
||||||
|
"/scheduled-payment-date" ::scheduled-payment-date
|
||||||
"/navigate" ::new-wizard-navigate
|
"/navigate" ::new-wizard-navigate
|
||||||
"/account/new" ::new-wizard-new-account
|
"/account/new" ::new-wizard-new-account
|
||||||
"/account/location-select" ::location-select}
|
"/account/location-select" ::location-select}
|
||||||
|
|||||||
Reference in New Issue
Block a user