Makes insights actually work
This commit is contained in:
@@ -64,23 +64,27 @@
|
||||
(assoc similar-transaction :score score)))
|
||||
|
||||
(defn similar->recommendation [txs client]
|
||||
(->> txs
|
||||
(reduce (fn [acc t]
|
||||
(-> acc
|
||||
(update-in [[(:db/id (:transaction/vendor t))
|
||||
(:db/id (:transaction-account/account (first (:transaction/accounts t))))]
|
||||
:count]
|
||||
(fnil inc 0))
|
||||
(update-in [[(:db/id (:transaction/vendor t))
|
||||
(:db/id (:transaction-account/account (first (:transaction/accounts t))))]
|
||||
:seen-by-client?]
|
||||
(fn [seen-by-client?] (or seen-by-client? (= (:db/id (:transaction/client t))
|
||||
client))))))
|
||||
{})
|
||||
(map (fn [[k v]]
|
||||
(-> k
|
||||
(conj (:count v))
|
||||
(conj (:seen-by-client? v)))))))
|
||||
(try
|
||||
(->> txs
|
||||
(reduce (fn [acc t]
|
||||
(-> acc
|
||||
(update-in [[(:db/id (:transaction/vendor t))
|
||||
(:db/id (:transaction-account/account (first (:transaction/accounts t))))]
|
||||
:count]
|
||||
(fnil inc 0))
|
||||
(update-in [[(:db/id (:transaction/vendor t))
|
||||
(:db/id (:transaction-account/account (first (:transaction/accounts t))))]
|
||||
:seen-by-client?]
|
||||
(fn [seen-by-client?] (or seen-by-client? (= (:db/id (:transaction/client t))
|
||||
client))))))
|
||||
{})
|
||||
(map (fn [[k v]]
|
||||
(-> k
|
||||
(conj (:count v))
|
||||
(conj (:seen-by-client? v))))))
|
||||
(catch Exception e
|
||||
(println e)
|
||||
[])))
|
||||
|
||||
(defn get-outcome-recommendations []
|
||||
(for [[transaction client] (get-recent-transactions)
|
||||
|
||||
@@ -7,13 +7,15 @@
|
||||
(defn button- [params & children]
|
||||
[:button (update params
|
||||
:class #(cond-> %
|
||||
true (str " text-white focus:ring-4 font-bold rounded-lg text-xs p-3 text-center mr-2 inline-flex items-center hover:scale-105 transition duration-100 justify-center")
|
||||
(= :secondary (:color params)) (str " bg-blue-500 hover:bg-blue-600 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700")
|
||||
(= :primary (:color params)) (str " bg-green-500 hover:bg-green-600 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 ")))
|
||||
true (str " focus:ring-4 font-bold rounded-lg text-xs p-3 text-center mr-2 inline-flex items-center hover:scale-105 transition duration-100 justify-center")
|
||||
(= :secondary (:color params)) (str " text-white bg-blue-500 hover:bg-blue-600 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700")
|
||||
(= :primary (:color params)) (str " text-white bg-green-500 hover:bg-green-600 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 ")
|
||||
(nil? (:color params))
|
||||
(str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700")))
|
||||
[:div.htmx-indicator.flex.items-center
|
||||
(svg/spinner {:class "inline w-4 h-4 text-white"})
|
||||
[:div.ml-3 "Loading..."]]
|
||||
(into [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center ] children)])
|
||||
(into [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center] children)])
|
||||
|
||||
(defn icon-button- [params & children]
|
||||
(into
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
children))
|
||||
|
||||
(defn badge- [params & children]
|
||||
[:div {:class "absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white bg-red-500 border-2 border-white rounded-full -top-2 -right-2 dark:border-gray-900"} children])
|
||||
[:div {:class "absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white bg-red-300 border-3 border-white rounded-full -top-2 -right-2 dark:border-gray-900"} children])
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
[datomic.api :as dc]
|
||||
[hiccup2.core :as hiccup]
|
||||
[iol-ion.tx :refer [random-tempid]]
|
||||
[auto-ap.client-routes :as client-routes])
|
||||
[auto-ap.client-routes :as client-routes]
|
||||
[auto-ap.datomic.vendors :as d-vendors]
|
||||
[clj-time.core :as time])
|
||||
(:import
|
||||
(java.util UUID)))
|
||||
|
||||
@@ -328,10 +330,16 @@ invoice_dropzone = new Dropzone(\"#invoice\", {
|
||||
[_ total] (:textract-invoice/total textract-invoice)
|
||||
[_ date] (:textract-invoice/date textract-invoice)
|
||||
[_ invoice-number] (:textract-invoice/invoice-number textract-invoice)
|
||||
vendor (dc/pull (dc/db conn) d-vendors/default-read vendor-id)
|
||||
location (when client-id
|
||||
(->> (dc/pull (dc/db conn) '[:client/locations] client-id)
|
||||
:client/locations
|
||||
first))]
|
||||
first))
|
||||
due (and (:vendor/terms vendor)
|
||||
(coerce/to-date
|
||||
(time/plus date (time/days (d-vendors/terms-for-client-id vendor client-id)))))
|
||||
scheduled-payment (and (d-vendors/automatically-paid-for-client-id? vendor client-id)
|
||||
due)]
|
||||
(when (and client-id date invoice-number vendor-id total)
|
||||
{:db/id (random-tempid)
|
||||
:invoice/client client-id
|
||||
@@ -340,6 +348,8 @@ invoice_dropzone = new Dropzone(\"#invoice\", {
|
||||
:invoice/invoice-number invoice-number
|
||||
:invoice/total total
|
||||
:invoice/date date
|
||||
:invoice/due (coerce/to-date due)
|
||||
:invoice/scheduled-payment (coerce/to-date scheduled-payment)
|
||||
:invoice/location location
|
||||
:invoice/import-status :import-status/imported
|
||||
:invoice/outstanding-balance total
|
||||
|
||||
@@ -26,6 +26,20 @@
|
||||
:transaction/bank-account [:bank-account/code]}
|
||||
:transaction/account-confidence
|
||||
:transaction/date])
|
||||
(defn parse-outcome [tx]
|
||||
(update tx :transaction/outcome-recommendation
|
||||
(fn [ors]
|
||||
(map
|
||||
(fn [[v a c s]]
|
||||
{:vendor (dc/pull (dc/db conn)
|
||||
[:vendor/name :db/id]
|
||||
v)
|
||||
:account (dc/pull (dc/db conn)
|
||||
[:account/name :db/id]
|
||||
a)
|
||||
:count c
|
||||
:seen-by-client? s})
|
||||
ors))))
|
||||
|
||||
(defn transaction-recommendations [identity selected-client & {:keys [after]}]
|
||||
(let [visible-clients (visible-clients identity)]
|
||||
@@ -54,20 +68,7 @@
|
||||
(#(if after
|
||||
(drop 1 %)
|
||||
%))
|
||||
(map (fn [tx]
|
||||
(update tx :transaction/outcome-recommendation
|
||||
(fn [ors]
|
||||
(map
|
||||
(fn [[v a c s]]
|
||||
{:vendor (dc/pull (dc/db conn)
|
||||
[:vendor/name :db/id]
|
||||
v)
|
||||
:account (dc/pull (dc/db conn)
|
||||
[:account/name :db/id]
|
||||
a)
|
||||
:count c
|
||||
:seen-by-client? s})
|
||||
ors)))))
|
||||
(map parse-outcome)
|
||||
(take 50)
|
||||
(into []))))
|
||||
|
||||
@@ -144,39 +145,52 @@
|
||||
[:div.tag.is-danger.is-light (str "$" (Math/round (:transaction/amount r)))]))
|
||||
|
||||
(com/data-grid-right-stack-cell {}
|
||||
(when-not hide-actions?
|
||||
[:div.flex.gap-2.flex-col {:style {:width "25em"}}
|
||||
(for [or (sort-by (comp - :count)
|
||||
(:transaction/outcome-recommendation r))]
|
||||
[:form {:hx-post (bidi/path-for ssr-routes/only-routes
|
||||
:transaction-insight-code
|
||||
:transaction-id (:db/id r))
|
||||
:hx-target "closest tr"}
|
||||
(when-let [vendor-id (:db/id (:vendor or))]
|
||||
[:input {:type :hidden :value vendor-id :name "vendor"}])
|
||||
(when-let [account-id (:db/id (:account or))]
|
||||
[:input {:type :hidden :value account-id :name "account"}])
|
||||
|
||||
(com/button {:color (if (:seen-by-client? or)
|
||||
:primary
|
||||
:secondary)
|
||||
:style {:position "relative"}}
|
||||
(:vendor/name (:vendor or))
|
||||
(when (:vendor/name (:vendor or))
|
||||
" | ")
|
||||
(:account/name (:account or))
|
||||
(com/badge {:color :secondary}
|
||||
(:count or)))])
|
||||
(com/icon-button {:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
:transaction-insight-explain
|
||||
:transaction-id (:db/id r))
|
||||
:hx-target "#modal-holder"
|
||||
:hx-swap "outerHTML"}
|
||||
svg/question)]))))
|
||||
[:div.flex.gap-2.flex-col {:style {:width "25em"}}
|
||||
(for [or (take 3 (sort-by (comp - :count)
|
||||
(:transaction/outcome-recommendation r)))]
|
||||
[:form {:hx-post (bidi/path-for ssr-routes/only-routes
|
||||
:transaction-insight-code
|
||||
:transaction-id (:db/id r))
|
||||
:hx-target "closest tr"
|
||||
:hx-swap "outerHTML"
|
||||
:disabled hide-actions?}
|
||||
(when-let [vendor-id (:db/id (:vendor or))]
|
||||
[:input {:type :hidden :value vendor-id :name "vendor"}])
|
||||
(when-let [account-id (:db/id (:account or))]
|
||||
[:input {:type :hidden :value account-id :name "account"}])
|
||||
|
||||
(com/button {:color (if (:seen-by-client? or)
|
||||
:primary
|
||||
:secondary)
|
||||
:style {:position "relative"
|
||||
:display "block"
|
||||
:width "100%"}}
|
||||
(:vendor/name (:vendor or))
|
||||
(when (:vendor/name (:vendor or))
|
||||
" | ")
|
||||
(:account/name (:account or))
|
||||
(com/badge {:color :secondary}
|
||||
(:count or)))])
|
||||
[:div.flex.flex-row.gap-2
|
||||
(com/button {:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
:transaction-insight-explain
|
||||
:transaction-id (:db/id r))
|
||||
:hx-target "#modal-holder"
|
||||
:hx-swap "outerHTML"}
|
||||
[:div.flex
|
||||
svg/question
|
||||
"Explain"])
|
||||
(com/button {:hx-delete (bidi/path-for ssr-routes/only-routes
|
||||
:transaction-insight-disapprove
|
||||
:transaction-id (:db/id r))
|
||||
:hx-target "closest tr"
|
||||
:hx-swap "outerHTML"}
|
||||
[:div.flex
|
||||
svg/question
|
||||
"Reject"])]])))
|
||||
|
||||
(defn code [{:keys [identity session] {:keys [transaction-id]} :route-params {:strs [vendor account]} :form-params}]
|
||||
(let [approval-details (dc/pull (dc/db conn) [{:transaction/recommended-account [:account/location :db/id]}
|
||||
:transaction/recommended-vendor
|
||||
(let [approval-details (dc/pull (dc/db conn) [:transaction/recommended-vendor
|
||||
:transaction/amount
|
||||
:db/id
|
||||
{:transaction/client [:client/locations]}]
|
||||
@@ -201,25 +215,25 @@
|
||||
:transaction-account/account (-> account :db/id)
|
||||
:transaction-account/amount (* 0.01 cents)
|
||||
:transaction-account/location location})
|
||||
(spread-cents cents-to-distribute (count valid-locations))))}]]
|
||||
(spread-cents cents-to-distribute (count valid-locations))))}]
|
||||
db-before (dc/db conn)]
|
||||
@(dc/transact conn [updated-transaction])
|
||||
(html-response (transaction-row
|
||||
(dc/pull (dc/db conn)
|
||||
pull-expr
|
||||
(Long/parseLong transaction-id))
|
||||
:auto-remove? true
|
||||
(parse-outcome (dc/pull db-before
|
||||
pull-expr
|
||||
(Long/parseLong transaction-id)))
|
||||
:hide-actions? true
|
||||
:class "live-added"))))
|
||||
:class "live-added"
|
||||
"_" (hiccup/raw "init transition opacity to 0 then remove me")))))
|
||||
|
||||
(defn disapprove [{:keys [identity session] {:keys [transaction-id]} :route-params}]
|
||||
(let [transaction-id (cond-> transaction-id string? (Long/parseLong))]
|
||||
@(dc/transact conn [[:upsert-transaction {:db/id transaction-id :transaction/recommended-account nil :transaction/recommended-vendor nil}]])
|
||||
(let [transaction-id (cond-> transaction-id string? (Long/parseLong))
|
||||
db-before (dc/db conn)]
|
||||
@(dc/transact conn [[:upsert-transaction {:db/id transaction-id :transaction/outcome-recommendation nil}]])
|
||||
(html-response (transaction-row
|
||||
(dc/pull (dc/db conn) pull-expr transaction-id)
|
||||
:auto-remove? true
|
||||
:hide-actions? true
|
||||
:class "live-removed"
|
||||
"_" (hiccup/raw "init transition opacity to 0 then remove me")))))
|
||||
(parse-outcome (dc/pull db-before pull-expr transaction-id))
|
||||
:hide-actions? true
|
||||
"_" (hiccup/raw "init transition opacity to 0 over 500ms then remove me")))))
|
||||
(defn explain [{:keys [identity session] {:keys [transaction-id]} :route-params}]
|
||||
(let [r (dc/pull (dc/db conn)
|
||||
pull-expr
|
||||
@@ -288,7 +302,8 @@
|
||||
(com/data-grid-header {:style {:width "15em"}} "Account")
|
||||
(com/data-grid-header {:style {:width "8em"}} "Date")
|
||||
(com/data-grid-header {} "Description")
|
||||
(com/data-grid-header {:style {:width "8em"}} "Amount")]})))
|
||||
(com/data-grid-header {:style {:width "8em"}} "Amount")
|
||||
(com/data-grid-header {})]})))
|
||||
|
||||
(defn insight-table [{:keys [session identity]}]
|
||||
(html-response (insight-table* {:selected-client
|
||||
|
||||
Reference in New Issue
Block a user