Makes insights actually work

This commit is contained in:
Bryce
2023-08-19 21:13:49 -07:00
parent 8a31112c5b
commit ecc31f3680
7 changed files with 128 additions and 87 deletions

View File

@@ -1859,6 +1859,11 @@ input:checked + .toggle-bg {
background-color: rgb(253 246 178 / var(--tw-bg-opacity)); background-color: rgb(253 246 178 / var(--tw-bg-opacity));
} }
.bg-red-300 {
--tw-bg-opacity: 1;
background-color: rgb(255 104 104 / var(--tw-bg-opacity));
}
.bg-opacity-50 { .bg-opacity-50 {
--tw-bg-opacity: 0.5; --tw-bg-opacity: 0.5;
} }

View File

@@ -64,23 +64,27 @@
(assoc similar-transaction :score score))) (assoc similar-transaction :score score)))
(defn similar->recommendation [txs client] (defn similar->recommendation [txs client]
(->> txs (try
(reduce (fn [acc t] (->> txs
(-> acc (reduce (fn [acc t]
(update-in [[(:db/id (:transaction/vendor t)) (-> acc
(:db/id (:transaction-account/account (first (:transaction/accounts t))))] (update-in [[(:db/id (:transaction/vendor t))
:count] (:db/id (:transaction-account/account (first (:transaction/accounts t))))]
(fnil inc 0)) :count]
(update-in [[(:db/id (:transaction/vendor t)) (fnil inc 0))
(:db/id (:transaction-account/account (first (:transaction/accounts t))))] (update-in [[(:db/id (:transaction/vendor t))
:seen-by-client?] (:db/id (:transaction-account/account (first (:transaction/accounts t))))]
(fn [seen-by-client?] (or seen-by-client? (= (:db/id (:transaction/client t)) :seen-by-client?]
client)))))) (fn [seen-by-client?] (or seen-by-client? (= (:db/id (:transaction/client t))
{}) client))))))
(map (fn [[k v]] {})
(-> k (map (fn [[k v]]
(conj (:count v)) (-> k
(conj (:seen-by-client? v))))))) (conj (:count v))
(conj (:seen-by-client? v))))))
(catch Exception e
(println e)
[])))
(defn get-outcome-recommendations [] (defn get-outcome-recommendations []
(for [[transaction client] (get-recent-transactions) (for [[transaction client] (get-recent-transactions)

View File

@@ -7,13 +7,15 @@
(defn button- [params & children] (defn button- [params & children]
[:button (update params [:button (update params
:class #(cond-> % :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") 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 " bg-blue-500 hover:bg-blue-600 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700") (= :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 " bg-green-500 hover:bg-green-600 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-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 [:div.htmx-indicator.flex.items-center
(svg/spinner {:class "inline w-4 h-4 text-white"}) (svg/spinner {:class "inline w-4 h-4 text-white"})
[:div.ml-3 "Loading..."]] [: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] (defn icon-button- [params & children]
(into (into

View File

@@ -20,4 +20,4 @@
children)) children))
(defn badge- [params & 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])

View File

@@ -23,7 +23,9 @@
[datomic.api :as dc] [datomic.api :as dc]
[hiccup2.core :as hiccup] [hiccup2.core :as hiccup]
[iol-ion.tx :refer [random-tempid]] [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 (:import
(java.util UUID))) (java.util UUID)))
@@ -328,10 +330,16 @@ invoice_dropzone = new Dropzone(\"#invoice\", {
[_ total] (:textract-invoice/total textract-invoice) [_ total] (:textract-invoice/total textract-invoice)
[_ date] (:textract-invoice/date textract-invoice) [_ date] (:textract-invoice/date textract-invoice)
[_ invoice-number] (:textract-invoice/invoice-number 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 location (when client-id
(->> (dc/pull (dc/db conn) '[:client/locations] client-id) (->> (dc/pull (dc/db conn) '[:client/locations] client-id)
:client/locations :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) (when (and client-id date invoice-number vendor-id total)
{:db/id (random-tempid) {:db/id (random-tempid)
:invoice/client client-id :invoice/client client-id
@@ -340,6 +348,8 @@ invoice_dropzone = new Dropzone(\"#invoice\", {
:invoice/invoice-number invoice-number :invoice/invoice-number invoice-number
:invoice/total total :invoice/total total
:invoice/date date :invoice/date date
:invoice/due (coerce/to-date due)
:invoice/scheduled-payment (coerce/to-date scheduled-payment)
:invoice/location location :invoice/location location
:invoice/import-status :import-status/imported :invoice/import-status :import-status/imported
:invoice/outstanding-balance total :invoice/outstanding-balance total

View File

@@ -26,6 +26,20 @@
:transaction/bank-account [:bank-account/code]} :transaction/bank-account [:bank-account/code]}
:transaction/account-confidence :transaction/account-confidence
:transaction/date]) :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]}] (defn transaction-recommendations [identity selected-client & {:keys [after]}]
(let [visible-clients (visible-clients identity)] (let [visible-clients (visible-clients identity)]
@@ -54,20 +68,7 @@
(#(if after (#(if after
(drop 1 %) (drop 1 %)
%)) %))
(map (fn [tx] (map parse-outcome)
(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)))))
(take 50) (take 50)
(into [])))) (into []))))
@@ -144,39 +145,52 @@
[:div.tag.is-danger.is-light (str "$" (Math/round (:transaction/amount r)))])) [:div.tag.is-danger.is-light (str "$" (Math/round (:transaction/amount r)))]))
(com/data-grid-right-stack-cell {} (com/data-grid-right-stack-cell {}
(when-not hide-actions? [:div.flex.gap-2.flex-col {:style {:width "25em"}}
[:div.flex.gap-2.flex-col {:style {:width "25em"}} (for [or (take 3 (sort-by (comp - :count)
(for [or (sort-by (comp - :count) (:transaction/outcome-recommendation r)))]
(:transaction/outcome-recommendation r))] [:form {:hx-post (bidi/path-for ssr-routes/only-routes
[:form {:hx-post (bidi/path-for ssr-routes/only-routes :transaction-insight-code
:transaction-insight-code :transaction-id (:db/id r))
:transaction-id (:db/id r)) :hx-target "closest tr"
:hx-target "closest tr"} :hx-swap "outerHTML"
(when-let [vendor-id (:db/id (:vendor or))] :disabled hide-actions?}
[:input {:type :hidden :value vendor-id :name "vendor"}]) (when-let [vendor-id (:db/id (:vendor or))]
(when-let [account-id (:db/id (:account or))] [:input {:type :hidden :value vendor-id :name "vendor"}])
[:input {:type :hidden :value account-id :name "account"}]) (when-let [account-id (:db/id (:account or))]
[:input {:type :hidden :value account-id :name "account"}])
(com/button {:color (if (:seen-by-client? or) (com/button {:color (if (:seen-by-client? or)
:primary :primary
:secondary) :secondary)
:style {:position "relative"}} :style {:position "relative"
(:vendor/name (:vendor or)) :display "block"
(when (:vendor/name (:vendor or)) :width "100%"}}
" | ") (:vendor/name (:vendor or))
(:account/name (:account or)) (when (:vendor/name (:vendor or))
(com/badge {:color :secondary} " | ")
(:count or)))]) (:account/name (:account or))
(com/icon-button {:hx-get (bidi/path-for ssr-routes/only-routes (com/badge {:color :secondary}
:transaction-insight-explain (:count or)))])
:transaction-id (:db/id r)) [:div.flex.flex-row.gap-2
:hx-target "#modal-holder" (com/button {:hx-get (bidi/path-for ssr-routes/only-routes
:hx-swap "outerHTML"} :transaction-insight-explain
svg/question)])))) :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}] (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]} (let [approval-details (dc/pull (dc/db conn) [:transaction/recommended-vendor
:transaction/recommended-vendor
:transaction/amount :transaction/amount
:db/id :db/id
{:transaction/client [:client/locations]}] {:transaction/client [:client/locations]}]
@@ -201,25 +215,25 @@
:transaction-account/account (-> account :db/id) :transaction-account/account (-> account :db/id)
:transaction-account/amount (* 0.01 cents) :transaction-account/amount (* 0.01 cents)
:transaction-account/location location}) :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]) @(dc/transact conn [updated-transaction])
(html-response (transaction-row (html-response (transaction-row
(dc/pull (dc/db conn) (parse-outcome (dc/pull db-before
pull-expr pull-expr
(Long/parseLong transaction-id)) (Long/parseLong transaction-id)))
:auto-remove? true
:hide-actions? true :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}] (defn disapprove [{:keys [identity session] {:keys [transaction-id]} :route-params}]
(let [transaction-id (cond-> transaction-id string? (Long/parseLong))] (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}]]) db-before (dc/db conn)]
@(dc/transact conn [[:upsert-transaction {:db/id transaction-id :transaction/outcome-recommendation nil}]])
(html-response (transaction-row (html-response (transaction-row
(dc/pull (dc/db conn) pull-expr transaction-id) (parse-outcome (dc/pull db-before pull-expr transaction-id))
:auto-remove? true :hide-actions? true
:hide-actions? true "_" (hiccup/raw "init transition opacity to 0 over 500ms then remove me")))))
:class "live-removed"
"_" (hiccup/raw "init transition opacity to 0 then remove me")))))
(defn explain [{:keys [identity session] {:keys [transaction-id]} :route-params}] (defn explain [{:keys [identity session] {:keys [transaction-id]} :route-params}]
(let [r (dc/pull (dc/db conn) (let [r (dc/pull (dc/db conn)
pull-expr pull-expr
@@ -288,7 +302,8 @@
(com/data-grid-header {:style {:width "15em"}} "Account") (com/data-grid-header {:style {:width "15em"}} "Account")
(com/data-grid-header {:style {:width "8em"}} "Date") (com/data-grid-header {:style {:width "8em"}} "Date")
(com/data-grid-header {} "Description") (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]}] (defn insight-table [{:keys [session identity]}]
(html-response (insight-table* {:selected-client (html-response (insight-table* {:selected-client

View File

@@ -35,7 +35,6 @@
:active-route active-route :active-route active-route
:route :admin}) :route :admin})
[:p.menu-label "Setup"] [:p.menu-label "Setup"]
(menu-item {:label "Clients" (menu-item {:label "Clients"
:icon-class "fa fa-star-o" :icon-class "fa fa-star-o"
@@ -96,8 +95,14 @@
:active-route active-route :active-route active-route
:route :admin-ezcater-xls :route :admin-ezcater-xls
:icon-style {:font-size "25px"}}) :icon-style {:font-size "25px"}})
(menu-item {:label "Invoice glimpse"
:icon-class "icon icon-cog-play-1"
:test-route #{:invoice-glimpse}
:active-route active-route
:route :invoice-glimpse
:icon-style {:font-size "25px"}})
(into [:div ] children)]) (into [:div] children)])
#?(:clj #?(:clj
(defn admin-side-bar [active-page] (defn admin-side-bar [active-page]