Proper validations and total row.
This commit is contained in:
@@ -123,10 +123,11 @@
|
|||||||
[:div {:class "flex items-center justify-center w-full h-full border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700 bg-opacity-50" }
|
[:div {:class "flex items-center justify-center w-full h-full border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700 bg-opacity-50" }
|
||||||
[:div {:class "px-3 py-1 text-xs font-medium leading-none text-center text-blue-800 bg-blue-200 rounded-full animate-pulse dark:bg-blue-900 dark:text-blue-200"} "loading..."]]])])
|
[:div {:class "px-3 py-1 text-xs font-medium leading-none text-center text-blue-800 bg-blue-200 rounded-full animate-pulse dark:bg-blue-900 dark:text-blue-200"} "loading..."]]])])
|
||||||
|
|
||||||
(defn new-row- [{:keys [index colspan tr-params] :as params} & content]
|
(defn new-row- [{:keys [index colspan tr-params row-offset] :as params} & content]
|
||||||
(row-
|
(row-
|
||||||
(merge {:class "new-row"
|
(merge {:class "new-row"
|
||||||
:x-data (hx/json {:newRowIndex index})
|
:x-data (hx/json {:newRowIndex index
|
||||||
|
:offset (or row-offset 0)})
|
||||||
}
|
}
|
||||||
tr-params)
|
tr-params)
|
||||||
(cell- {:colspan colspan
|
(cell- {:colspan colspan
|
||||||
@@ -135,10 +136,10 @@
|
|||||||
(a-button- (merge
|
(a-button- (merge
|
||||||
(dissoc params :index :colspan)
|
(dissoc params :index :colspan)
|
||||||
{
|
{
|
||||||
"@click" "$dispatch('newRow', {index: newRowIndex++})"
|
"@click" "$dispatch('newRow', {index: (newRowIndex++)})"
|
||||||
:color :secondary
|
:color :secondary
|
||||||
:hx-trigger "newRow"
|
:hx-trigger "newRow"
|
||||||
:hx-vals (hiccup/raw "js:{index: event.detail.index}")
|
:hx-vals (hiccup/raw "js:{index: event.detail.index }")
|
||||||
:hx-target "closest .new-row"
|
:hx-target "closest .new-row"
|
||||||
:hx-swap "beforebegin"})
|
:hx-swap "beforebegin"})
|
||||||
content)])))
|
content)])))
|
||||||
|
|||||||
21
src/clj/auto_ap/ssr/invoice/common.clj
Normal file
21
src/clj/auto_ap/ssr/invoice/common.clj
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
(ns auto-ap.ssr.invoice.common)
|
||||||
|
|
||||||
|
(def default-read '[:db/id
|
||||||
|
:invoice/invoice-number
|
||||||
|
:invoice/total
|
||||||
|
:invoice/outstanding-balance
|
||||||
|
:invoice/source-url
|
||||||
|
|
||||||
|
[:invoice/date :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
|
||||||
|
{:account/client-overrides [:account-client-override/name
|
||||||
|
{:account-client-override/client [:db/id]}]}]}]
|
||||||
|
[:transaction/_invoices :as :invoice/transaction] [:db/id]
|
||||||
|
[:payment/_invoices :as :invoice/payments] [:db/id :payment/date :payment/amount
|
||||||
|
|
||||||
|
{[:transaction/_payment :as :payment/transaction] [:db/id]
|
||||||
|
[:payment/status :xform iol-ion.query/ident] [:db/ident]}]
|
||||||
|
[:invoice/status :xform iol-ion.query/ident] [:db/ident]
|
||||||
|
:invoice/vendor [:vendor/name :db/id]}])
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
(ns auto-ap.ssr.invoice.new-invoice-wizard
|
(ns auto-ap.ssr.invoice.new-invoice-wizard
|
||||||
(:require [auto-ap.datomic
|
(:require [auto-ap.datomic
|
||||||
:refer [audit-transact conn pull-attr pull-ref]]
|
:refer [audit-transact conn pull-attr]]
|
||||||
[auto-ap.datomic.accounts :as d-accounts]
|
[auto-ap.datomic.accounts :as d-accounts]
|
||||||
[auto-ap.datomic.invoices :as d-invoices]
|
[auto-ap.datomic.invoices :as d-invoices]
|
||||||
|
[auto-ap.ssr.invoice.common :refer [default-read]]
|
||||||
[auto-ap.graphql.utils :refer [assert-can-see-client
|
[auto-ap.graphql.utils :refer [assert-can-see-client
|
||||||
assert-not-locked exception->4xx]]
|
assert-not-locked exception->4xx]]
|
||||||
[auto-ap.logging :as alog]
|
[auto-ap.logging :as alog]
|
||||||
@@ -29,8 +30,7 @@
|
|||||||
[datomic.api :as dc]
|
[datomic.api :as dc]
|
||||||
[iol-ion.query :refer [dollars=]]
|
[iol-ion.query :refer [dollars=]]
|
||||||
[malli.core :as mc]
|
[malli.core :as mc]
|
||||||
[malli.util :as mut]
|
[malli.util :as mut]))
|
||||||
[manifold.deferred :as d]))
|
|
||||||
|
|
||||||
(defn get-vendor [vendor-id]
|
(defn get-vendor [vendor-id]
|
||||||
(dc/pull
|
(dc/pull
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
[:fn {:error/message "Not an allowed account."}
|
[:fn {:error/message "Not an allowed account."}
|
||||||
check-allowance]]]
|
check-allowance]]]
|
||||||
[:invoice-expense-account/location :string]
|
[:invoice-expense-account/location :string]
|
||||||
[:invoice-expense-account/amount money]]
|
[:invoice-expense-account/amount [:double {:min 0}]]]
|
||||||
[:fn {:error/fn (fn [r x] (:type r))
|
[:fn {:error/fn (fn [r x] (:type r))
|
||||||
:error/path [:invoice-expense-account/location]} check-invoice-expense-account-location]]]]])
|
:error/path [:invoice-expense-account/location]} check-invoice-expense-account-location]]]]])
|
||||||
|
|
||||||
@@ -122,6 +122,7 @@
|
|||||||
vendor))
|
vendor))
|
||||||
|
|
||||||
|
|
||||||
|
;; TODO account / vendor search should use allowances
|
||||||
|
|
||||||
|
|
||||||
(defrecord BasicDetailsStep [linear-wizard]
|
(defrecord BasicDetailsStep [linear-wizard]
|
||||||
@@ -330,11 +331,22 @@
|
|||||||
(com/validated-field
|
(com/validated-field
|
||||||
{:errors (fc/field-errors)}
|
{:errors (fc/field-errors)}
|
||||||
(com/money-input {:name (fc/field-name)
|
(com/money-input {:name (fc/field-name)
|
||||||
:class "w-16"
|
:class "w-16 amount-field"
|
||||||
:value (fc/field-value)}))))
|
:value (fc/field-value)}))))
|
||||||
(com/data-grid-cell {:class "align-top"}
|
(com/data-grid-cell {:class "align-top"}
|
||||||
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
|
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
|
||||||
|
|
||||||
|
(defn invoice-expense-account-total* [request]
|
||||||
|
(format "$%,.2f" (->> (-> request
|
||||||
|
:multi-form-state
|
||||||
|
:step-params
|
||||||
|
:invoice/expense-accounts)
|
||||||
|
(map (fnil :invoice-expense-account/amount 0.0))
|
||||||
|
(filter number?)
|
||||||
|
(reduce + 0.0))))
|
||||||
|
|
||||||
|
(defn invoice-expense-account-total [request]
|
||||||
|
(html-response (invoice-expense-account-total* request)))
|
||||||
|
|
||||||
(defrecord AccountsStep [linear-wizard]
|
(defrecord AccountsStep [linear-wizard]
|
||||||
mm/ModalWizardStep
|
mm/ModalWizardStep
|
||||||
@@ -349,7 +361,7 @@
|
|||||||
(step-schema [_]
|
(step-schema [_]
|
||||||
(mut/select-keys (mm/form-schema linear-wizard) #{:invoice/expense-accounts}))
|
(mut/select-keys (mm/form-schema linear-wizard) #{:invoice/expense-accounts}))
|
||||||
|
|
||||||
(render-step [this {{:keys [snapshot]} :multi-form-state :as request}]
|
(render-step [this {{:keys [snapshot] :as multi-form-state} :multi-form-state :as request}]
|
||||||
(alog/peek ::mfs (:step-params (:multi-form-state request)))
|
(alog/peek ::mfs (:step-params (:multi-form-state request)))
|
||||||
(mm/default-render-step
|
(mm/default-render-step
|
||||||
linear-wizard this
|
linear-wizard this
|
||||||
@@ -363,27 +375,50 @@
|
|||||||
{:errors (fc/field-errors)}
|
{:errors (fc/field-errors)}
|
||||||
(com/data-grid {:headers [(com/data-grid-header {} "Account")
|
(com/data-grid {:headers [(com/data-grid-header {} "Account")
|
||||||
(com/data-grid-header {:class "w-32"} "Location")
|
(com/data-grid-header {:class "w-32"} "Location")
|
||||||
(com/data-grid-header {:class "w-16"} "%")
|
(com/data-grid-header {:class "w-16"} "$")
|
||||||
(com/data-grid-header {:class "w-16"})]}
|
(com/data-grid-header {:class "w-16"})]}
|
||||||
(fc/cursor-map #(invoice-expense-account-row* {:value %
|
(fc/cursor-map #(invoice-expense-account-row* {:value %
|
||||||
:client-id (:invoice/client snapshot)}))
|
:client-id (:invoice/client snapshot)}))
|
||||||
|
|
||||||
(com/data-grid-new-row {:colspan 4
|
(com/data-grid-new-row {:colspan 4
|
||||||
:hx-get (bidi/path-for ssr-routes/only-routes
|
:hx-get (bidi/path-for ssr-routes/only-routes
|
||||||
::route/new-wizard-new-account)
|
::route/new-wizard-new-account)
|
||||||
|
:row-offset 0
|
||||||
:index (count (fc/field-value))
|
:index (count (fc/field-value))
|
||||||
:tr-params {:hx-vals (hx/json {:client-id (:invoice/client snapshot)})}}
|
:tr-params {:hx-vals (hx/json {:client-id (:invoice/client snapshot)})}}
|
||||||
"New account"))))])
|
"New account")
|
||||||
|
(com/data-grid-row {}
|
||||||
|
(com/data-grid-cell {})
|
||||||
|
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TOTAL"])
|
||||||
|
(com/data-grid-cell {:id "total"
|
||||||
|
:class "text-right"
|
||||||
|
:hx-trigger "change from:closest form target:.amount-field"
|
||||||
|
:hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/expense-account-total)
|
||||||
|
:hx-target "this"
|
||||||
|
:hx-swap "innerHTML"}
|
||||||
|
(invoice-expense-account-total* request))
|
||||||
|
(com/data-grid-cell {}))
|
||||||
|
(com/data-grid-row {}
|
||||||
|
|
||||||
|
(com/data-grid-cell {})
|
||||||
|
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "INVOICE TOTAL"])
|
||||||
|
(com/data-grid-cell {:class "text-right"}
|
||||||
|
(format "$%,.2f" (:invoice/total snapshot)))
|
||||||
|
(com/data-grid-cell {})))))])
|
||||||
:footer
|
:footer
|
||||||
(mm/default-step-footer linear-wizard this :validation-route ::route/new-wizard-navigate)
|
(mm/default-step-footer linear-wizard this :validation-route ::route/new-wizard-navigate)
|
||||||
:validation-route ::route/new-wizard-navigate))
|
:validation-route ::route/new-wizard-navigate))
|
||||||
mm/Initializable
|
mm/Initializable
|
||||||
(init-step-params
|
(init-step-params
|
||||||
[_ current request]
|
[_ current request]
|
||||||
{:invoice/expense-accounts [{:db/id "123"
|
(alog/peek ::step (:step-params current))
|
||||||
:invoice-expense-account/location "Shared"
|
(if (not (seq (:invoice/expense-accounts (:step-params current))))
|
||||||
:invoice-expense-account/account (:db/id (:vendor/default-account (clientize-vendor (get-vendor (->db-id (:invoice/vendor (:snapshot current))))
|
(assoc (:step-params current) :invoice/expense-accounts [{:db/id "123"
|
||||||
(->db-id (:invoice/client (:snapshot current))))))
|
:invoice-expense-account/location "Shared"
|
||||||
:invoice-expense-account/amount 100}]}))
|
:invoice-expense-account/account (:db/id (:vendor/default-account (clientize-vendor (get-vendor (->db-id (:invoice/vendor (:snapshot current))))
|
||||||
|
(->db-id (:invoice/client (:snapshot current))))))
|
||||||
|
:invoice-expense-account/amount (:invoice/total (:step-params current))}])
|
||||||
|
(:step-params current))))
|
||||||
|
|
||||||
|
|
||||||
(defn assert-no-conflicting [{:invoice/keys [invoice-number client vendor]}]
|
(defn assert-no-conflicting [{:invoice/keys [invoice-number client vendor]}]
|
||||||
@@ -431,36 +466,50 @@
|
|||||||
(form-schema [_] new-form-schema)
|
(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}]
|
||||||
|
|
||||||
(let [invoice (:snapshot multi-form-state)
|
(let [invoice (:snapshot multi-form-state)
|
||||||
client-id (->db-id (:invoice/client invoice))
|
client-id (->db-id (:invoice/client invoice))
|
||||||
vendor-id (->db-id (:invoice/vendor invoice))
|
vendor-id (->db-id (:invoice/vendor invoice))
|
||||||
transaction [:upsert-invoice (-> multi-form-state
|
transaction [:upsert-invoice (-> multi-form-state
|
||||||
:snapshot
|
:snapshot
|
||||||
(assoc :db/id "invoice")
|
(assoc :db/id "invoice")
|
||||||
(assoc
|
(assoc
|
||||||
:invoice/outstanding-balance (:invoice/total (:snapshot multi-form-state))
|
:invoice/outstanding-balance (:invoice/total (:snapshot multi-form-state))
|
||||||
:invoice/import-status :import-status/imported
|
:invoice/import-status :import-status/imported
|
||||||
:invoice/status :invoice-status/unpaid)
|
:invoice/status :invoice-status/unpaid)
|
||||||
|
|
||||||
(update :invoice/expense-accounts
|
(update :invoice/expense-accounts
|
||||||
(fn [eas]
|
(fn [eas]
|
||||||
(mapv (fn [ea]
|
(mapv (fn [ea]
|
||||||
(-> ea
|
(-> ea
|
||||||
(assoc :invoice-expense-account/amount
|
(assoc :invoice-expense-account/amount
|
||||||
(:invoice/total (:snapshot multi-form-state)))))
|
(:invoice/total (:snapshot multi-form-state)))))
|
||||||
eas)))
|
eas)))
|
||||||
(update :invoice/date coerce/to-date)
|
(update :invoice/date coerce/to-date)
|
||||||
(update :invoice/due coerce/to-date))]]
|
(update :invoice/due coerce/to-date))]]
|
||||||
|
|
||||||
(assert-invoice-amounts-add-up invoice)
|
(assert-invoice-amounts-add-up invoice)
|
||||||
(assert-no-conflicting invoice)
|
(assert-no-conflicting invoice)
|
||||||
(exception->4xx #(assert-can-see-client (:identity request) client-id))
|
(exception->4xx #(assert-can-see-client (:identity request) client-id))
|
||||||
|
|
||||||
(exception->4xx #(assert-not-locked client-id (:invoice/date invoice)))
|
(exception->4xx #(assert-not-locked client-id (:invoice/date invoice)))
|
||||||
(let [transaction-result (audit-transact [transaction] (:identity request))]
|
(let [transaction-result (audit-transact [transaction] (:identity request))]
|
||||||
(solr/touch-with-ledger (get-in transaction-result [:tempids "invoice"]))))
|
(solr/touch-with-ledger (get-in transaction-result [:tempids "invoice"]))
|
||||||
(html-response [:div]
|
(html-response
|
||||||
:headers {"hx-trigger" "modalclose,invalidated"})))
|
(@(resolve 'auto-ap.ssr.invoices/row*)
|
||||||
|
|
||||||
|
identity
|
||||||
|
(dc/pull (dc/db conn) default-read (get-in transaction-result [:tempids "invoice"]))
|
||||||
|
{:flash? true
|
||||||
|
:request request})
|
||||||
|
:headers {"hx-trigger" "modalclose"
|
||||||
|
"hx-retarget" "#entity-table tbody"
|
||||||
|
"hx-reswap" "afterbegin"
|
||||||
|
|
||||||
|
#_(format "#entity-table tr[data-id=\"%d\"]" (get-in transaction-result [:tempids "invoice"]))})))
|
||||||
|
|
||||||
|
|
||||||
|
#_(html-response [:div]
|
||||||
|
:headers {"hx-trigger" "modalclose,invalidated"})))
|
||||||
|
|
||||||
(def new-wizard (->NewWizard2 nil nil))
|
(def new-wizard (->NewWizard2 nil nil))
|
||||||
|
|
||||||
@@ -548,6 +597,9 @@
|
|||||||
(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/expense-account-total (-> invoice-expense-account-total
|
||||||
|
(mm/wrap-wizard new-wizard)
|
||||||
|
(mm/wrap-decode-multi-form-state))
|
||||||
::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]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[auto-ap.datomic
|
[auto-ap.datomic
|
||||||
:refer [add-sorter-fields apply-pagination apply-sort-3
|
:refer [add-sorter-fields apply-pagination apply-sort-3
|
||||||
audit-transact conn merge-query observable-query
|
audit-transact conn merge-query observable-query
|
||||||
pull-attr pull-many]]
|
pull-many]]
|
||||||
[auto-ap.datomic.accounts :as d-accounts]
|
[auto-ap.datomic.accounts :as d-accounts]
|
||||||
[auto-ap.datomic.bank-accounts :as d-bank-accounts]
|
[auto-ap.datomic.bank-accounts :as d-bank-accounts]
|
||||||
[auto-ap.datomic.invoices :as d-invoices]
|
[auto-ap.datomic.invoices :as d-invoices]
|
||||||
@@ -23,7 +23,6 @@
|
|||||||
:refer [wrap-admin wrap-client-redirect-unauthenticated]]
|
:refer [wrap-admin wrap-client-redirect-unauthenticated]]
|
||||||
[auto-ap.solr :as solr]
|
[auto-ap.solr :as solr]
|
||||||
[auto-ap.ssr-routes :as ssr-routes]
|
[auto-ap.ssr-routes :as ssr-routes]
|
||||||
[auto-ap.ssr.common-handlers :refer [add-new-entity-handler]]
|
|
||||||
[auto-ap.ssr.components :as com]
|
[auto-ap.ssr.components :as com]
|
||||||
[auto-ap.ssr.components.link-dropdown :refer [link-dropdown]]
|
[auto-ap.ssr.components.link-dropdown :refer [link-dropdown]]
|
||||||
[auto-ap.ssr.components.multi-modal :as mm]
|
[auto-ap.ssr.components.multi-modal :as mm]
|
||||||
@@ -31,6 +30,7 @@
|
|||||||
[auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]]
|
[auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]]
|
||||||
[auto-ap.ssr.hiccup-helper :as hh]
|
[auto-ap.ssr.hiccup-helper :as hh]
|
||||||
[auto-ap.ssr.hx :as hx]
|
[auto-ap.ssr.hx :as hx]
|
||||||
|
[auto-ap.ssr.invoice.common :refer [default-read]]
|
||||||
[auto-ap.ssr.invoice.new-invoice-wizard :as new-invoice-wizard]
|
[auto-ap.ssr.invoice.new-invoice-wizard :as new-invoice-wizard]
|
||||||
[auto-ap.ssr.pos.common :refer [date-range-field*]]
|
[auto-ap.ssr.pos.common :refer [date-range-field*]]
|
||||||
[auto-ap.ssr.svg :as svg]
|
[auto-ap.ssr.svg :as svg]
|
||||||
@@ -120,25 +120,7 @@
|
|||||||
(exact-match-id* request)]])
|
(exact-match-id* request)]])
|
||||||
|
|
||||||
|
|
||||||
(def default-read '[:db/id
|
|
||||||
:invoice/invoice-number
|
|
||||||
:invoice/total
|
|
||||||
:invoice/outstanding-balance
|
|
||||||
:invoice/source-url
|
|
||||||
|
|
||||||
[:invoice/date :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
|
|
||||||
{:account/client-overrides [:account-client-override/name
|
|
||||||
{:account-client-override/client [:db/id]}]}]}]
|
|
||||||
[:transaction/_invoices :as :invoice/transaction] [:db/id]
|
|
||||||
[:payment/_invoices :as :invoice/payments] [:db/id :payment/date :payment/amount
|
|
||||||
|
|
||||||
{[:transaction/_payment :as :payment/transaction] [:db/id]
|
|
||||||
[:payment/status :xform iol-ion.query/ident] [:db/ident]}]
|
|
||||||
[:invoice/status :xform iol-ion.query/ident] [:db/ident]
|
|
||||||
:invoice/vendor [:vendor/name :db/id]}])
|
|
||||||
|
|
||||||
(defn fetch-ids [db {:keys [query-params route-params] :as request}]
|
(defn fetch-ids [db {:keys [query-params route-params] :as request}]
|
||||||
(let [valid-clients (extract-client-ids (:clients request)
|
(let [valid-clients (extract-client-ids (:clients request)
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
"/scheduled-payment-date" ::scheduled-payment-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
|
||||||
|
"/total" ::expense-account-total}
|
||||||
"/pay-button" ::pay-button
|
"/pay-button" ::pay-button
|
||||||
"/pay" {:get ::pay-wizard
|
"/pay" {:get ::pay-wizard
|
||||||
"/navigate" ::pay-wizard-navigate
|
"/navigate" ::pay-wizard-navigate
|
||||||
|
|||||||
Reference in New Issue
Block a user