diff --git a/resources/public/output.css b/resources/public/output.css index 4da0b717..ab9396c7 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1404,6 +1404,10 @@ input:checked + .toggle-bg { flex-shrink: 0; } +.shrink { + flex-shrink: 1; +} + .basis-1\/2 { flex-basis: 50%; } @@ -1412,6 +1416,10 @@ input:checked + .toggle-bg { flex-basis: 25%; } +.basis-1\/3 { + flex-basis: 33.333333%; +} + .-translate-x-full { --tw-translate-x: -100%; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -1560,6 +1568,11 @@ input:checked + .toggle-bg { gap: 2rem; } +.gap-x-2 { + -moz-column-gap: 0.5rem; + column-gap: 0.5rem; +} + .-space-x-px > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(-1px * var(--tw-space-x-reverse)); diff --git a/src/clj/auto_ap/jobs/ntg.clj b/src/clj/auto_ap/jobs/ntg.clj index 829a16ee..248e4937 100644 --- a/src/clj/auto_ap/jobs/ntg.clj +++ b/src/clj/auto_ap/jobs/ntg.clj @@ -77,7 +77,8 @@ location (parse/best-location-match matching-client location-hint location-hint ) vendor (d/pull (d/db conn) '[:vendor/default-account] :vendor/general-produce)] (when-not (and matching-client - (not (@missing-client-hints location-hint))) + (not (@missing-client-hints location-hint)) + (not (str/blank? location-hint))) (log/warn ::missing-client :client-hint location-hint) (swap! missing-client-hints conj location-hint)) diff --git a/src/clj/auto_ap/ssr/invoice/glimpse.clj b/src/clj/auto_ap/ssr/invoice/glimpse.clj index 01379a22..e4584ba4 100644 --- a/src/clj/auto_ap/ssr/invoice/glimpse.clj +++ b/src/clj/auto_ap/ssr/invoice/glimpse.clj @@ -38,25 +38,43 @@ [(get-in sf ["Type" "Text"]) (get-in sf ["LabelDetection" "Text"])] )))) -(defn find-best [field-descriptors] - {:raw field-descriptors - :best - (->> field-descriptors - (sort-by #(* (-> % :type :confidence) - (-> % :value-detection :confidence))) - last - :value-detection - :text)}) +(defn stack-rank [valid-values field-descriptors] + (->> field-descriptors + (filter (comp valid-values :text :type)) + (sort-by #(* (-> % :type :confidence) + (-> % :value-detection :confidence))) + (reverse) + (map (comp :text :value-detection)) + (reduce + (fn [[result seen?] new] + (if (seen? new) + [result seen?] + [(conj result new) (conj seen? new)])) + [[] #{}]) + first)) -(defn textract->coalesced [tx] +(defn textract->textract-invoice [tx] (let [lookup (lookup tx) + total-options (stack-rank #{"TOTAL"} lookup) + account-number-options (stack-rank #{"CUSTOMER_NUMBER"} lookup) + customer-identifier-options (stack-rank #{"RECEIVER_NAME"} lookup) + vendor-name-options (stack-rank #{"VENDOR_NAME"} lookup) + date-options (stack-rank #{"ORDER_DATE"} lookup) + invoice-number-options (stack-rank #{"INVOICE_RECEIPT_ID"} lookup) ] - {:total (find-best (filter (fn [node] (= "TOTAL" (:text (:type node)))) lookup)) - :account-number (find-best (filter (fn [node] (= "CUSTOMER_NUMBER" (:text (:type node)))) lookup)) - :customer-identifier (find-best (filter (fn [node] (= "RECEIVER_NAME" (:text (:type node)))) lookup)) - :vendor-name (find-best (filter (fn [node] (= "VENDOR_NAME" (:text (:type node)))) lookup)) - :date (find-best (filter (fn [node] (= "ORDER_DATE" (:text (:type node)))) lookup)) - :invoice-number (find-best (filter (fn [node] (= "INVOICE_RECEIPT_ID" (:text (:type node)))) lookup)) + #:textract-invoice + {:total (first total-options) + :total-options total-options + :account-number (first account-number-options) + :account-number-options account-number-options + :customer-identifier (first customer-identifier-options) + :customer-identifier-options customer-identifier-options + :vendor-name (first vendor-name-options) + :vendor-name-options (rest vendor-name-options) + :date (first date-options) + :date-options date-options + :invoice-number (first invoice-number-options) + :invoice-number-options invoice-number-options })) (defn clean-customer [c] @@ -134,62 +152,73 @@ invoice_dropzone = new Dropzone(\"#invoice\", { @(dc/transact conn [{:db/id id :textract-invoice/textract-status (:job-status result)}]))) (dc/pull (dc/db conn) '[*] [:textract-invoice/job-id job-id]))) +(defn pill-list* [{:keys [selected options class]}] + (let [options (->> options + (filter (complement #{selected})) + (map (fn [x] [:div.shrink (com/pill {:color :secondary} (com/link {:href "#"} x))]) ))] + (when (seq options) + [:div.col-span-6.col-start-1.text-xs + "Alternates: " + [:div.flex.gap-2.flex-wrap {:class class} + options]]))) + (defn textract->invoice-form* [job-id] - (let [coalesced (-> (textract/get-expense-analysis {:job-id job-id}) - (textract->coalesced)) - candidate-invoice (-> coalesced - (coalesced->invoice))] + (let [coalesced (-> (textract/get-expense-analysis {:job-id job-id}) + (textract->textract-invoice)) + #_#_candidate-invoice (-> coalesced + (coalesced->invoice))] [:form [:div.grid.grid-cols-6.gap-4 [:div.col-span-6 (com/field {:label "Client"} (com/text-input {:name (path->name [:invoice/client]) - :value (pull-attr (dc/db conn) :client/name (:invoice/client candidate-invoice)) + :value (:textract-invoice/customer-identifier coalesced) :placeholder "Client" :disabled true :autofocus true}))] + (pill-list* {:selected (:textract-invoice/customer-identifier coalesced) + :options (:textract-invoice/customer-identifier-options coalesced) + :class "flex-col"}) + [:div.col-span-6 (com/field {:label "Vendor"} (com/text-input {:name (path->name [:invoice/vendor]) - :value (pull-attr (dc/db conn) :vendor/name (:invoice/vendor candidate-invoice)) + :value (:textract-invoice/vendor-name coalesced) :placeholder "Vendor" :disabled true :autofocus true}))] + (pill-list* {:selected (:textract-invoice/vendor-name coalesced) + :options (:textract-invoice/vendor-name-options coalesced) + :class "flex-row"}) + [:div.col-span-3 (com/field {:label "Date"} (com/text-input {:name (path->name [:invoice/date]) - :value (atime/unparse-local (:invoice/date candidate-invoice) - atime/normal-date) + :value (:textract-invoice/date coalesced) :placeholder "Date" :disabled true :autofocus true}))] - [:div.col-span-3.col-start-1.text-xs - "Alternates: " - (butlast - (interleave - (map (fn [x] (com/link {:href "#"} (pr-str x))) (set (map (comp :text :value-detection) (:raw (:date coalesced))))) - (repeat ", ")))] + (pill-list* {:selected (:textract-invoice/date coalesced) + :options (:textract-invoice/date-options coalesced)}) [:div.col-span-2.col-start-1 (com/field {:label "Total"} (com/text-input {:name (path->name [:invoice/total]) - :value (:invoice/total candidate-invoice) + :value (:textract-invoice/total coalesced) :placeholder "Total" :disabled true :autofocus true}))] - [:div.col-span-3.col-start-1.text-xs - "Alternates: " - (butlast - (interleave - (map (fn [x] (com/link {:href "#"} (pr-str x))) (set (map (comp :text :value-detection) (:raw (:total coalesced))))) - (repeat ", ")))] + (pill-list* {:selected (:textract-invoice/total coalesced) + :options (:textract-invoice/total-options coalesced)}) [:div.col-span-2.col-start-1 (com/field {:label "Invoice Number"} (com/text-input {:name (path->name [:invoice/invoice-number]) - :value (:invoice/invoice-number candidate-invoice) + :value (:textract-invoice/invoice-number coalesced) :placeholder "Invoice Number" :disabled true - :autofocus true}))]]])) + :autofocus true}))] + (pill-list* {:selected (:textract-invoice/invoice-number coalesced) + :options (:textract-invoice/invoice-number-options coalesced)})]])) (defn job-progress* [job-id] (when (pull-id (dc/db conn) [:textract-invoice/job-id job-id]) @@ -212,7 +241,7 @@ invoice_dropzone = new Dropzone(\"#invoice\", { [:div.flex.flex-row.space-x-4 [:div {:style {:width "805"}} (com/card {} - [:iframe.p-4 {:src (:textract-invoice/pdf-url textract-invoice) :width 791 :height 1024}])] + [:iframe.p-4 {:src (:textract-invoice/pdf-url textract-invoice) :width 791 :height 700}])] [:div {:class "basis-1/4"} (com/card {} [:div.p-4