Add vendor pre-population for bulk code and individual edit forms
- Add vendor-changed HTMX handlers for both bulk code and individual edit - Pre-populate default account at 100% when vendor is selected and no accounts exist - Fix render-accounts-section to render from step-params correctly - Change bulk code vendor-changed from hx-get to hx-post to include form data - Add routes for vendor-changed endpoints - Update e2e tests to cover vendor pre-population - Run lein cljfmt fix across codebase
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
(:require
|
||||
[amazonica.aws.s3 :as s3]
|
||||
[auto-ap.datomic
|
||||
:refer [add-sorter-fields apply-pagination apply-sort-3
|
||||
audit-transact conn merge-query observable-query
|
||||
pull-attr pull-many random-tempid]]
|
||||
:refer [add-sorter-fields apply-pagination apply-sort-3
|
||||
audit-transact conn merge-query observable-query
|
||||
pull-attr pull-many random-tempid]]
|
||||
[auto-ap.datomic.clients :as d-clients]
|
||||
[auto-ap.datomic.invoices :as d-invoices]
|
||||
[auto-ap.datomic.vendors :as d-vendors]
|
||||
@@ -24,24 +24,23 @@
|
||||
[auto-ap.ssr.pos.common :refer [date-range-field*]]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[auto-ap.ssr.utils
|
||||
:refer [apply-middleware-to-all-handlers clj-date-schema
|
||||
entity-id html-response main-transformer ref->enum-schema
|
||||
strip wrap-entity wrap-implied-route-param
|
||||
wrap-schema-enforce]]
|
||||
[auto-ap.time :as atime]
|
||||
[auto-ap.utils :refer [dollars=]]
|
||||
[bidi.bidi :as bidi]
|
||||
[clj-time.coerce :as coerce :refer [to-date]]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[com.brunobonacci.mulog :as mu]
|
||||
[config.core :refer [env]]
|
||||
[datomic.api :as dc]
|
||||
[hiccup2.core :as hiccup]
|
||||
[malli.core :as mc])
|
||||
:refer [apply-middleware-to-all-handlers clj-date-schema
|
||||
entity-id html-response main-transformer ref->enum-schema
|
||||
strip wrap-entity wrap-implied-route-param
|
||||
wrap-schema-enforce]]
|
||||
[auto-ap.time :as atime]
|
||||
[auto-ap.utils :refer [dollars=]]
|
||||
[bidi.bidi :as bidi]
|
||||
[clj-time.coerce :as coerce :refer [to-date]]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[com.brunobonacci.mulog :as mu]
|
||||
[config.core :refer [env]]
|
||||
[datomic.api :as dc]
|
||||
[hiccup2.core :as hiccup]
|
||||
[malli.core :as mc])
|
||||
(:import [java.util UUID]))
|
||||
|
||||
|
||||
(defn exact-match-id* [request]
|
||||
(if (nat-int? (:exact-match-id (:query-params request)))
|
||||
[:div {:x-data (hx/json {:exact_match (:exact-match-id (:query-params request))}) :id "exact-match-id-tag"}
|
||||
@@ -108,7 +107,6 @@
|
||||
:size :small})])
|
||||
(exact-match-id* request)]])
|
||||
|
||||
|
||||
(defn fetch-ids [db {:keys [query-params route-params] :as request}]
|
||||
(let [valid-clients (extract-client-ids (:clients request)
|
||||
(:client-id request)
|
||||
@@ -131,8 +129,6 @@
|
||||
(some-> (:start-date query-params) coerce/to-date)
|
||||
(some-> (:end-date query-params) coerce/to-date)]]}
|
||||
|
||||
|
||||
|
||||
(:client-id query-params)
|
||||
(merge-query {:query {:in ['?client-id]
|
||||
:where ['[?e :invoice/client ?client-id]]}
|
||||
@@ -144,7 +140,6 @@
|
||||
'[?client-id :client/code ?client-code]]}
|
||||
:args [(:client-code query-params)]})
|
||||
|
||||
|
||||
(:start (:due-range query-params)) (merge-query {:query {:in '[?start-due]
|
||||
:where ['[?e :invoice/due ?due]
|
||||
'[(>= ?due ?start-due)]]}
|
||||
@@ -155,7 +150,6 @@
|
||||
'[(<= ?due ?end-due)]]}
|
||||
:args [(coerce/to-date (:end (:due-range query-params)))]})
|
||||
|
||||
|
||||
(:import-status query-params)
|
||||
(merge-query {:query {:in ['?import-status]
|
||||
:where ['[?e :invoice/import-status ?import-status]]}
|
||||
@@ -232,7 +226,6 @@
|
||||
(apply-sort-3 (assoc query-params :default-asc? false))
|
||||
(apply-pagination query-params))))
|
||||
|
||||
|
||||
(defn hydrate-results [ids db _]
|
||||
(let [results (->> (pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
@@ -307,7 +300,6 @@
|
||||
(assoc-in [:query-params :start] 0)
|
||||
(assoc-in [:query-params :per-page] 250))))
|
||||
|
||||
|
||||
:else
|
||||
selected)
|
||||
ids (->> (dc/q '[:find ?i
|
||||
@@ -318,29 +310,27 @@
|
||||
(map first))]
|
||||
ids))
|
||||
|
||||
(def upload-schema
|
||||
[:map
|
||||
(def upload-schema
|
||||
[:map
|
||||
[:force-client {:optional true}
|
||||
[:maybe entity-id]]
|
||||
[:force-vendor {:optional true}
|
||||
[:maybe entity-id]]
|
||||
[:force-chatgpt {:optional true :default false}
|
||||
[:maybe [ :boolean {:decode/string {:enter #(if (= % "on") true
|
||||
[:force-chatgpt {:optional true :default false}
|
||||
[:maybe [:boolean {:decode/string {:enter #(if (= % "on") true
|
||||
|
||||
(boolean %))}}]]]
|
||||
(boolean %))}}]]]
|
||||
[:force-location {:optional true}
|
||||
[:maybe [:string {:decode/string strip :min 2 :max 2}]]]])
|
||||
|
||||
(defn upload-form [{:keys [form-params form-errors] :as request}]
|
||||
(com/content-card {}
|
||||
|
||||
|
||||
[:div.px-4.py-3.space-y-4
|
||||
|
||||
[:div.flex.justify-between.items-center [:h1.text-2xl.mb-3.font-bold "Import new invoices"]
|
||||
]
|
||||
|
||||
[:div.flex.justify-between.items-center [:h1.text-2xl.mb-3.font-bold "Import new invoices"]]
|
||||
[:div#page-notification.notification.block {:style {:display "none"}}]
|
||||
|
||||
|
||||
|
||||
[:form
|
||||
{:hx-post (bidi/path-for ssr-routes/only-routes
|
||||
::route/import-file)
|
||||
@@ -351,7 +341,7 @@
|
||||
(fc/start-form
|
||||
form-params form-errors
|
||||
[:div.flex.gap-4.items-center
|
||||
|
||||
|
||||
(fc/with-field :force-client
|
||||
(com/validated-field {:label "Force client"
|
||||
:errors (fc/field-errors)}
|
||||
@@ -366,7 +356,7 @@
|
||||
(fc/with-field :force-location
|
||||
(com/validated-field {:label "Force location"
|
||||
:errors (fc/field-errors)}
|
||||
|
||||
|
||||
(com/text-input {:name (fc/field-name)
|
||||
:value (fc/field-value)
|
||||
:size 2})))
|
||||
@@ -382,15 +372,15 @@
|
||||
:value (fc/field-value)
|
||||
:content-fn (fn [c] (pull-attr (dc/db conn) :vendor/name c))})]))
|
||||
(fc/with-field :force-chatgpt
|
||||
(com/validated-field { :errors (fc/field-errors)
|
||||
(com/validated-field {:errors (fc/field-errors)
|
||||
:label " "}
|
||||
(com/checkbox {:name (fc/field-name)
|
||||
:error? (fc/error?) }
|
||||
:error? (fc/error?)}
|
||||
"Only use ChatGPT")))])
|
||||
|
||||
|
||||
[:div.border-2.border-dashed.rounded-lg.p-4.w-full.text-center.cursor-pointer.h-64.flex.items-center.justify-center.text-lg.relative
|
||||
{ :x-data (hx/json {"files" nil
|
||||
"hovering" false})
|
||||
{:x-data (hx/json {"files" nil
|
||||
"hovering" false})
|
||||
":class" "{'bg-blue-100': !hovering,
|
||||
'border-blue-300': !hovering,
|
||||
'text-blue-700': !hovering,
|
||||
@@ -399,8 +389,6 @@
|
||||
'text-green-700': hovering
|
||||
}"
|
||||
:x-ref "box"}
|
||||
|
||||
|
||||
|
||||
[:input {:type "file"
|
||||
:name "file"
|
||||
@@ -410,13 +398,12 @@
|
||||
:x-on:dragover "hovering = true",
|
||||
:x-on:dragleave "hovering = false",
|
||||
:x-on:drop "hovering = false"}]
|
||||
[:div.flex.flex-col.space-2
|
||||
[:div
|
||||
[:div.flex.flex-col.space-2
|
||||
[:div
|
||||
[:ul {:x-show "files != null"}
|
||||
[:template {:x-for "f in files" }
|
||||
[:li (com/pill {:color :primary :x-text "f.name"}) ]
|
||||
]]]
|
||||
|
||||
[:template {:x-for "f in files"}
|
||||
[:li (com/pill {:color :primary :x-text "f.name"})]]]]
|
||||
|
||||
[:div.htmx-indicator-hidden "Drop files to upload here"]]]
|
||||
(com/button {:color :primary :class "w-32 mt-3"} "Upload")]]))
|
||||
|
||||
@@ -435,14 +422,12 @@
|
||||
:query-schema query-schema
|
||||
:action-buttons (fn [request]
|
||||
(let [[_ _ outstanding total] (:page-results request)]
|
||||
[
|
||||
(when (can? (:identity request) {:subject :invoice :activity :import})
|
||||
[(when (can? (:identity request) {:subject :invoice :activity :import})
|
||||
(com/button {:hx-put (str (bidi/path-for ssr-routes/only-routes ::route/bulk-approve))
|
||||
"x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})"
|
||||
"hx-include" "#invoice-filters"
|
||||
:color :primary
|
||||
":disabled" "$data.all_selected || ($data.selected && $data.selected.length > 0) ? false: true "
|
||||
}
|
||||
":disabled" "$data.all_selected || ($data.selected && $data.selected.length > 0) ? false: true "}
|
||||
"Approve selected"))
|
||||
(when (can? (:identity request) {:subject :invoice :activity :import})
|
||||
(com/button {:hx-delete (str (bidi/path-for ssr-routes/only-routes ::route/bulk-disapprove))
|
||||
@@ -463,8 +448,8 @@
|
||||
(when (and (= :import-status/pending (:invoice/import-status entity))
|
||||
(can? (:identity request) {:subject :invoice :activity :import}))
|
||||
(com/icon-button {:hx-put (bidi/path-for ssr-routes/only-routes
|
||||
::route/approve
|
||||
:db/id (:db/id entity))}
|
||||
::route/approve
|
||||
:db/id (:db/id entity))}
|
||||
svg/thumbs-up))])
|
||||
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes ::route/page)}
|
||||
@@ -515,11 +500,11 @@
|
||||
|
||||
(defn disapprove [{invoice :entity :as request identity :identity}]
|
||||
(when-not (= :import-status/pending (:invoice/import-status invoice))
|
||||
(throw (ex-info (str "Cannot disapprove an invoice if it is not pending." (:invoice/import-status invoice))
|
||||
(throw (ex-info (str "Cannot disapprove an invoice if it is not pending." (:invoice/import-status invoice))
|
||||
{:type :notification})))
|
||||
(exception->notification
|
||||
#(assert-can-see-client identity (:db/id (:invoice/client invoice))))
|
||||
|
||||
|
||||
(audit-transact [[:db/retractEntity (:db/id invoice)]] identity)
|
||||
|
||||
(html-response (row* (:identity request) invoice
|
||||
@@ -528,13 +513,13 @@
|
||||
|
||||
(defn approve [{invoice :entity :as request identity :identity}]
|
||||
(when-not (= :import-status/pending (:invoice/import-status invoice))
|
||||
(throw (ex-info (str "Cannot approve an invoice if it is not pending." (:invoice/import-status invoice))
|
||||
(throw (ex-info (str "Cannot approve an invoice if it is not pending." (:invoice/import-status invoice))
|
||||
{:type :notification})))
|
||||
(exception->notification
|
||||
#(do (assert-can-see-client identity (:db/id (:invoice/client invoice)))
|
||||
(assert-not-locked (-> invoice :invoice/client :db/id) (-> invoice :invoice/date))))
|
||||
|
||||
(audit-transact [ [:upsert-invoice {:db/id (:db/id invoice) :invoice/import-status :import-status/imported}]] identity)
|
||||
|
||||
(audit-transact [[:upsert-invoice {:db/id (:db/id invoice) :invoice/import-status :import-status/imported}]] identity)
|
||||
|
||||
(html-response (row* (:identity request) invoice
|
||||
{:class "live-added"})
|
||||
@@ -542,51 +527,49 @@
|
||||
|
||||
(defn bulk-disapprove [request]
|
||||
(let [ids (selected->ids request (:form-params request))
|
||||
updates (map
|
||||
(fn [i] [:db/retractEntity i])
|
||||
ids) ]
|
||||
(audit-transact updates (:identity request) )
|
||||
updates (map
|
||||
(fn [i] [:db/retractEntity i])
|
||||
ids)]
|
||||
(audit-transact updates (:identity request))
|
||||
|
||||
(html-response [:div]
|
||||
:headers {"hx-trigger" (hx/json { :notification (format "Successfully disapproved %d invoices."
|
||||
:headers {"hx-trigger" (hx/json {:notification (format "Successfully disapproved %d invoices."
|
||||
(count ids))
|
||||
:invalidated "invalidated"})})))
|
||||
|
||||
(defn bulk-approve [request]
|
||||
(let [ids (selected->ids request (:form-params request))]
|
||||
(exception->notification
|
||||
(exception->notification
|
||||
#(doseq [i ids
|
||||
:let [invoice (dc/pull (dc/db conn) '[{:invoice/client [:db/id]}
|
||||
:invoice/date] i)]]
|
||||
(assert-can-see-client (:identity request) (-> invoice :invoice/client :db/id))
|
||||
(assert-not-locked (-> invoice :invoice/client :db/id) (-> invoice :invoice/date))))
|
||||
:let [invoice (dc/pull (dc/db conn) '[{:invoice/client [:db/id]}
|
||||
:invoice/date] i)]]
|
||||
(assert-can-see-client (:identity request) (-> invoice :invoice/client :db/id))
|
||||
(assert-not-locked (-> invoice :invoice/client :db/id) (-> invoice :invoice/date))))
|
||||
(let [transactions (map (fn [i] [:upsert-invoice {:db/id i :invoice/import-status :import-status/imported}]) ids)]
|
||||
(audit-transact transactions (:identity request)))
|
||||
(html-response [:div]
|
||||
:headers {"hx-trigger" (hx/json { :notification (format "Successfully approved %d invoices."
|
||||
:headers {"hx-trigger" (hx/json {:notification (format "Successfully approved %d invoices."
|
||||
(count ids))
|
||||
:invalidated "invalidated"})})))
|
||||
|
||||
#_(defn upload-invoices [{{files :file
|
||||
files-2 "file"
|
||||
client :client
|
||||
client-2 "client"
|
||||
location :location
|
||||
location-2 "location"
|
||||
vendor :vendor
|
||||
vendor-2 "vendor"} :params
|
||||
user :identity}]
|
||||
(let [files (or files files-2)
|
||||
client (or client client-2)
|
||||
location (or location location-2)
|
||||
vendor (some-> (or vendor vendor-2)
|
||||
(Long/parseLong))
|
||||
]
|
||||
))
|
||||
files-2 "file"
|
||||
client :client
|
||||
client-2 "client"
|
||||
location :location
|
||||
location-2 "location"
|
||||
vendor :vendor
|
||||
vendor-2 "vendor"} :params
|
||||
user :identity}]
|
||||
(let [files (or files files-2)
|
||||
client (or client client-2)
|
||||
location (or location location-2)
|
||||
vendor (some-> (or vendor vendor-2)
|
||||
(Long/parseLong))]))
|
||||
|
||||
(defn match-vendor [vendor-code forced-vendor vendor-search]
|
||||
(when (and (not forced-vendor) (str/blank? vendor-code))
|
||||
(if vendor-search
|
||||
(if vendor-search
|
||||
(throw (ex-info (format "No vendor found. Searched for '%s'. Please supply an forced vendor."
|
||||
vendor-search)
|
||||
{:vendor-code vendor-code}))
|
||||
@@ -594,10 +577,10 @@
|
||||
{:vendor-code vendor-code}))))
|
||||
(let [vendor-id (or forced-vendor
|
||||
(->> (dc/q
|
||||
{:find ['?vendor]
|
||||
:in ['$ '?vendor-name]
|
||||
:where ['[?vendor :vendor/name ?vendor-name]]}
|
||||
(dc/db conn) vendor-code)
|
||||
{:find ['?vendor]
|
||||
:in ['$ '?vendor-name]
|
||||
:where ['[?vendor :vendor/name ?vendor-name]]}
|
||||
(dc/db conn) vendor-code)
|
||||
first
|
||||
first))]
|
||||
(when-not vendor-id
|
||||
@@ -605,9 +588,9 @@
|
||||
{:vendor-code vendor-code})))
|
||||
|
||||
(if-let [matching-vendor (->> (dc/q
|
||||
{:find [(list 'pull '?vendor-id d-vendors/default-read)]
|
||||
:in ['$ '?vendor-id]}
|
||||
(dc/db conn) vendor-id)
|
||||
{:find [(list 'pull '?vendor-id d-vendors/default-read)]
|
||||
:in ['$ '?vendor-id]}
|
||||
(dc/db conn) vendor-id)
|
||||
first
|
||||
first)]
|
||||
matching-vendor
|
||||
@@ -617,7 +600,7 @@
|
||||
(defn import->invoice [{:keys [invoice-number source-url customer-identifier account-number total date vendor-code text full-text client-override vendor-search vendor-override location-override import-status]} user]
|
||||
(when-not total
|
||||
(throw (Exception. "Couldn't parse total from file.")))
|
||||
(when-not date
|
||||
(when-not date
|
||||
(throw (Exception. "Couldn't parse date from file.")))
|
||||
(let [matching-client (cond
|
||||
client-override client-override
|
||||
@@ -629,9 +612,9 @@
|
||||
:client-override client-override
|
||||
:matching (when matching-client
|
||||
(dc/pull (dc/db conn) [:client/name :client/code] matching-client)))
|
||||
|
||||
|
||||
matching-vendor (match-vendor vendor-code vendor-override vendor-search)
|
||||
|
||||
|
||||
matching-location (or (when-not (str/blank? location-override)
|
||||
location-override)
|
||||
(parse/best-location-match (dc/pull (dc/db conn)
|
||||
@@ -658,22 +641,20 @@
|
||||
(defn validate-invoice [invoice user]
|
||||
(let [missing-keys (for [k [:invoice/invoice-number :invoice/client :invoice/vendor :invoice/total :invoice/outstanding-balance :invoice/date]
|
||||
:when (not (get invoice k))]
|
||||
k
|
||||
)]
|
||||
(cond
|
||||
(not (:invoice/client invoice))
|
||||
(do
|
||||
k)]
|
||||
(cond
|
||||
(not (:invoice/client invoice))
|
||||
(do
|
||||
(alog/warn ::no-client :invoice invoice)
|
||||
(assoc invoice :error-message (str "Searched clients for '" (:invoice/client-identifier invoice) "'. No client found in file. Select a client first.")))
|
||||
|
||||
(not (can-see-client? user (:invoice/client invoice)))
|
||||
(do
|
||||
(alog/warn ::cant-see-client :invoice invoice )
|
||||
(assoc invoice :error-message "No access for the client in this file.")
|
||||
)
|
||||
|
||||
(do
|
||||
(alog/warn ::cant-see-client :invoice invoice)
|
||||
(assoc invoice :error-message "No access for the client in this file."))
|
||||
|
||||
(seq missing-keys)
|
||||
(do
|
||||
(do
|
||||
(alog/warn ::mising-keys :keys missing-keys)
|
||||
(assoc invoice :error-message (str "Missing the key " missing-keys)))
|
||||
:else
|
||||
@@ -686,33 +667,31 @@
|
||||
count)]
|
||||
(map #(assoc % :invoice/source-url-admin-only (boolean (> client-count 1))) is)))
|
||||
|
||||
|
||||
(defn import-uploaded-invoice [user imports]
|
||||
(alog/info ::importing-uploaded :count (count imports)
|
||||
:bc (or user "NOO"))
|
||||
(let [potential-invoices (->> imports
|
||||
(map #(import->invoice % user))
|
||||
(map #(validate-invoice % user))
|
||||
admin-only-if-multiple-clients
|
||||
)
|
||||
errored-invoices (->> potential-invoices
|
||||
admin-only-if-multiple-clients)
|
||||
errored-invoices (->> potential-invoices
|
||||
(filter #(:error-message %)))
|
||||
successful-invoices (->> potential-invoices
|
||||
(filter #(not (:error-message %))))
|
||||
proposed-invoices (->> potential-invoices
|
||||
(filter #(not (:error-message %)))
|
||||
(mapv d-invoices/code-invoice)
|
||||
(mapv (fn [i] [:propose-invoice i])))]
|
||||
|
||||
(mapv (fn [i] [:propose-invoice i])))]
|
||||
|
||||
(alog/info ::creating-invoice :invoices proposed-invoices)
|
||||
(let [tx (audit-transact proposed-invoices user)]
|
||||
#_(when-not (seq (dc/q '[:find ?i
|
||||
:in $ [?i ...]
|
||||
:where [?i :invoice/invoice-number]]
|
||||
(:db-after tx)
|
||||
(map :e (:tx-data tx))))
|
||||
(throw (ex-info "No new invoices found."
|
||||
{:template (:template (first imports))})))
|
||||
:in $ [?i ...]
|
||||
:where [?i :invoice/invoice-number]]
|
||||
(:db-after tx)
|
||||
(map :e (:tx-data tx))))
|
||||
(throw (ex-info "No new invoices found."
|
||||
{:template (:template (first imports))})))
|
||||
{:tx tx
|
||||
:errored-invoices errored-invoices
|
||||
:successful-invoices successful-invoices
|
||||
@@ -730,7 +709,7 @@
|
||||
"text/csv"
|
||||
"application/pdf")
|
||||
:content-length (.length tempfile)})
|
||||
imports (->> (if force-chatgpt
|
||||
imports (->> (if force-chatgpt
|
||||
(parse/glimpse2 (.getPath tempfile))
|
||||
(parse/parse-file (.getPath tempfile) filename :allow-glimpse? true))
|
||||
(map #(assoc %
|
||||
@@ -740,16 +719,16 @@
|
||||
:source-url (str "https://" (:data-bucket env)
|
||||
"/"
|
||||
s3-location))))]
|
||||
(try
|
||||
|
||||
(try
|
||||
|
||||
(import-uploaded-invoice identity imports)
|
||||
|
||||
(catch Exception e
|
||||
(alog/warn ::couldnt-import-upload
|
||||
:error e
|
||||
:template (:template ( first imports)))
|
||||
:template (:template (first imports)))
|
||||
(throw (ex-info (ex-message e)
|
||||
{:template (:template ( first imports))
|
||||
{:template (:template (first imports))
|
||||
:sample (first imports)}
|
||||
e)))))
|
||||
(catch Exception e
|
||||
@@ -767,23 +746,21 @@
|
||||
(fn [result {:keys [filename tempfile]}]
|
||||
(try
|
||||
(let [i (import-internal tempfile filename force-client force-location force-vendor force-chatgpt (:identity request))]
|
||||
(alog/info ::failure-error-count :count (count (:errored-invoices i)) )
|
||||
|
||||
(-> result
|
||||
(update :error? #(or %
|
||||
(alog/info ::failure-error-count :count (count (:errored-invoices i)))
|
||||
|
||||
(-> result
|
||||
(update :error? #(or %
|
||||
(boolean (seq (:errored-invoices i)))))
|
||||
|
||||
|
||||
(update :files conj {:filename filename
|
||||
:error? (boolean (seq (:errored-invoices i)))
|
||||
:successful-invoices (count (:successful-invoices i))
|
||||
:errors [:div
|
||||
[:p.text-green-500 [:b (count (:successful-invoices i)) " succeeded in total."]
|
||||
]
|
||||
[:p [:b (count (:errored-invoices i)) " failed in total."]
|
||||
]
|
||||
[:ul
|
||||
:errors [:div
|
||||
[:p.text-green-500 [:b (count (:successful-invoices i)) " succeeded in total."]]
|
||||
[:p [:b (count (:errored-invoices i)) " failed in total."]]
|
||||
[:ul
|
||||
(for [e (take 5 (:errored-invoices i))]
|
||||
[:li (:error-message e)]) ]]
|
||||
[:li (:error-message e)])]]
|
||||
:template (:template (first (:imports i)))})))
|
||||
(catch Exception e
|
||||
(-> result
|
||||
@@ -793,11 +770,10 @@
|
||||
:response (.getMessage e)
|
||||
:sample (:sample (ex-data e))
|
||||
:template (:template (ex-data e))})))))
|
||||
{:error? false
|
||||
:files []
|
||||
}
|
||||
{:error? false
|
||||
:files []}
|
||||
file)]
|
||||
|
||||
|
||||
(html-response [:div#page-notification.p-4.rounded-lg
|
||||
[:table
|
||||
[:thead
|
||||
@@ -835,34 +811,34 @@
|
||||
{"hx-trigger" "invalidated"})))
|
||||
|
||||
#_(defn wrap-test [handler]
|
||||
(fn [request]
|
||||
(clojure.pprint/pprint (:multipart-params request))
|
||||
(handler request )))
|
||||
(fn [request]
|
||||
(clojure.pprint/pprint (:multipart-params request))
|
||||
(handler request)))
|
||||
|
||||
(def key->handler
|
||||
(apply-middleware-to-all-handlers
|
||||
(apply-middleware-to-all-handlers
|
||||
{::route/import-page
|
||||
(->
|
||||
(helper/page-route grid-page)
|
||||
(wrap-implied-route-param :status nil))
|
||||
::route/import-table
|
||||
::route/import-table
|
||||
(-> (helper/table-route grid-page)
|
||||
(wrap-implied-route-param :status nil))
|
||||
|
||||
|
||||
::route/disapprove (-> disapprove
|
||||
(wrap-entity [:route-params :db/id] default-read)
|
||||
(wrap-schema-enforce :route-params [:map [:db/id entity-id]]))
|
||||
::route/approve (-> approve
|
||||
(wrap-entity [:route-params :db/id] default-read)
|
||||
(wrap-schema-enforce :route-params [:map [:db/id entity-id]]))
|
||||
(wrap-entity [:route-params :db/id] default-read)
|
||||
(wrap-schema-enforce :route-params [:map [:db/id entity-id]]))
|
||||
::route/bulk-disapprove (-> bulk-disapprove
|
||||
(wrap-schema-enforce :form-schema query-schema))
|
||||
::route/bulk-approve (-> bulk-approve
|
||||
(wrap-schema-enforce :form-schema query-schema))
|
||||
(wrap-schema-enforce :form-schema query-schema))
|
||||
::route/import-file (-> import-file
|
||||
(wrap-schema-enforce :multipart-schema upload-schema))}
|
||||
(fn [a]
|
||||
(-> a
|
||||
(-> a
|
||||
(wrap-must {:subject :invoice :activity :import})))))
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user