diff --git a/src/clj/auto_ap/parse/templates.clj b/src/clj/auto_ap/parse/templates.clj index bf93296e..17ea6309 100644 --- a/src/clj/auto_ap/parse/templates.clj +++ b/src/clj/auto_ap/parse/templates.clj @@ -55,14 +55,29 @@ :total #"Total:\s+\$ ([0-9.]+)"} :parser {:date [:clj-time "MM/dd/yy"]}} + ;; DAYLIGHT FOOD STATEMENT + {:vendor "Daylight Foods" + :keywords [#"DAYLIGHT FOODS" #"Customer Statement"] + :extract {:date #"^.*?([0-9]+/[0-9]+/[0-9]+)" + :customer-identifier #"Phone:.*\n+\s+(.*)" + :invoice-number #"\s+(\w+)" + :total #"([\-]?[0-9]+\.[0-9]+)"} + :parser {:date [:clj-time "MM/dd/yy"] + :total [:trim-commas-and-negate nil]} + :multi #"\n" + :multi-match? #"^\s*[A-Z]\d+\s+([0-9]+/[0-9]+/[0-9]+)"} + ;; DAYLIGHT FOOD {:vendor "Daylight Foods" :keywords [#"DAYLIGHT FOODS"] :extract {:date #"\n\s*Date[^\n]+\n\s*([0-9]+/[0-9]+/[0-9]+)" - :customer-identifier #"Bill To:[^\n]+\n\s*([\w ]+)" + :customer-identifier #"Bill To:.*\n\s*(.*?)\s{2,}" :invoice-number #"Invoice\s([\w\./]+)*" - :total #"Total Invoice\s+([0-9.]+)"} - :parser {:date [:clj-time "MM/dd/yy"]}} + :total #"Total Invoice\s+([\-]?[0-9.]+)"} + :parser {:date [:clj-time "MM/dd/yy"] + :total [:trim-commas-and-negate nil]}} + + ;; SOUTHBAY FRESH {:vendor "Southbay Fresh Produce" @@ -105,6 +120,16 @@ :parser {:date [:clj-time "EEE MMM dd, yyyy HH:mm aa"] :total [:trim-commas nil]}} + ;; GOLDEN BRANDS + {:vendor "Bigoli Fresh Pasta" + :keywords [#"bigolifreshpasta.com"] + :extract {:date #"INVOICE #.*?\n.*?([0-9]+/[0-9]+/[0-9]+)" ;; HOW TO GO TO SPCIFIC LINE + :customer-identifier #"BILL TO.*\n\s+(.*?)\s{2,}" + :invoice-number #"INVOICE #.*?\n(\d+)" + :total #" TOTAL\s+([0-9,]+\.[0-9]{2})"} + :parser {:date [:clj-time "MM/dd/yyyy"] + :total [:trim-commas nil]}} + ;; Del Monte Meats {:vendor "Del Monte Meat Co" :keywords [#"Del Monte"] @@ -226,11 +251,13 @@ :keywords [#"Suncrest.*Invoice"] :extract {:date #"Date.*\n\s*\n(?:.*?)([0-9]+/[0-9]+/[0-9]+)" :customer-identifier #"Bill To(?:.*?)\n\n(.*?)\s{2,}" - :invoice-number #"Invoice #.*\n\s*\n(?:.*?)\s{2,}(\d{5,})" + :invoice-number #"Invoice #.*\n\s*\n.*? (\d{3,})" :total #"Balance Due\s+\$([0-9,]+\.[0-9]{2})"} :parser {:date [:clj-time "MM/dd/yyyy"] :total [:trim-commas nil]}} + + ;; PACIFIC SEAFOOD {:vendor "Pacific Seafood" :keywords [#"pacseafood"] @@ -266,12 +293,12 @@ ;; US FOODS {:vendor "US Foods" :keywords [#"US Foods"] - :extract {:date #"INVOICE NUMBER[^\n]+\n\n\d+\s+\d+\s+([0-9]+/[0-9]+/[0-9]+)" + :extract {:date #"INVOICE DATE.*\n+.*?(?=([0-9]+/[0-9]+/[0-9]+))([0-9]+/[0-9]+/[0-9]+)" :customer-identifier #"BILL TO[^\n]+\n([\S ]+?)(?=\s{2,})" ;; ([\S ]+)\s{2,} :invoice-number #"INVOICE NUMBER[^\n]+\n\n\d+\s+(\d+)" - :total #"(?:DELIVERED AMOUNT|PLEASE REMIT).*(?=\$)\$([0-9.,]+)\s*\n"} - :parser {:date [:clj-time "MM/dd/yyyy"] - :total [:trim-commas nil]}} + :total #"(?:DELIVERED AMOUNT|PLEASE REMIT|AMOUNT).*?\$([0-9.,]+( CR)?)\n"} + :parser {:date [:clj-time ["MM/dd/yyyy" "yyyy/MM/dd"]] + :total [:trim-commas-and-negate nil]}} ;; SYSCO {:vendor "Sysco" @@ -387,7 +414,7 @@ :extract {:date #"([0-9]+/[0-9]+/[0-9]+)" :customer-identifier #"SOLD\s+([\S ]+?)(?=(\s{2,}|\n))" :invoice-number #"(\S+)\s+(?=[0-9]+/[0-9]+/[0-9]+)" - :total #"(?:INVOICE|TOTAL)\s+([\d\.,\-]+\.[\d\-]+( CR)?)"} + :total #"(?:INVOICE|TOTAL|CREDIT)\s+([\d\.,\-]+\.[\d\-]+( CR)?)"} :parser {:date [:clj-time "MM/dd/yyyy"] :total [:trim-commas-and-negate nil]}}]) diff --git a/src/clj/auto_ap/parse/util.clj b/src/clj/auto_ap/parse/util.clj index b07f3e2a..c7e6b713 100644 --- a/src/clj/auto_ap/parse/util.clj +++ b/src/clj/auto_ap/parse/util.clj @@ -27,8 +27,20 @@ (defmethod parse-value :clj-time [_ format value] - (time/from-time-zone (f/parse (f/formatter format) value) - (time/time-zone-for-id "America/Los_Angeles"))) + (let [format (if (sequential? format) + format + [format])] + (reduce + (fn [_ format] + (try + (reduced (time/from-time-zone (f/parse (f/formatter format) value) + (time/time-zone-for-id "America/Los_Angeles"))) + (catch Exception e + (println e) + nil))) + nil + format) + )) (defmethod parse-value nil [_ _ value] diff --git a/src/clj/auto_ap/routes/invoices.clj b/src/clj/auto_ap/routes/invoices.clj index c89c5487..45cee686 100644 --- a/src/clj/auto_ap/routes/invoices.clj +++ b/src/clj/auto_ap/routes/invoices.clj @@ -207,7 +207,7 @@ (= (:db/id c) (Long/parseLong client))) clients)))) _ (when-not matching-client - (throw (ex-info (str "No client found in file. Select a client first.") + (throw (ex-info (str "Searched clients for '" customer-identifier "'. No client found in file. Select a client first.") {:invoice-number invoice-number :customer-identifier customer-identifier :vendor-code vendor-code}))) @@ -237,7 +237,9 @@ (throw (ex-info (str "Failed to find potential matching invoice with" " invoice " invoice-number " vendor " matching-vendor - " client " (:client/name matching-client)) + " client " (:client/name matching-client) + ". " + (.toString e)) {:args [ invoice-number matching-vendor (:db/id matching-client)]}))) ))] @@ -270,7 +272,7 @@ imports)] (when-not (seq transactions) (throw (ex-info "No invoices found." - {:imports imports}))) + {:imports (str imports)}))) @(d/transact (d/connect uri) (vec (set transactions))))) diff --git a/src/cljs/auto_ap/views/pages/import_invoices.cljs b/src/cljs/auto_ap/views/pages/import_invoices.cljs index 6520f667..8372563e 100644 --- a/src/cljs/auto_ap/views/pages/import_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/import_invoices.cljs @@ -15,50 +15,52 @@ [cljsjs.dropzone :as dropzone] [cljs.reader :as edn] [clojure.string :as str])) -(def dropzone +(defn dropzone [] (let [client (re-frame/subscribe [::subs/client]) token (re-frame/subscribe [::subs/token]) vendor (reagent/atom nil)] - (with-meta - (fn [] - [:form.dz {:action "/api/invoices/upload"} - [:div.field.has-addons - [:p.control - [:a.button.is-static "Force Location"]] - [:p.control - [:input.input {:name "location" :placeholder "SG" :size "4" :maxlength "2" :style {:display "inline"}}]]] - [:div.field.has-addons - [:p.control - [:a.button.is-static "Force vendor"]] - [typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors]) - :match->text :name - :name "vendor" - :type "typeahead" - :on-change (fn [v] - (reset! vendor v)) - :value @vendor}] - ] - [:div.tile.notification - - [:div.has-text-centered {:style {:padding "80px 0px" :width "100%"}} - [:span - [:span {:class "icon"} - [:i {:class "fa fa-cloud-download"}]] - "Drop any invoices you want to process here"]]]]) - {:component-did-mount (fn [this] - (js/Dropzone. (rdom/dom-node this) - (clj->js {:init (fn [] - (.on (js-this) "success" (fn [_ files] - (re-frame/dispatch [::invalidated]))) - (.on (js-this) "error" (fn [_ error] - (re-frame/dispatch [::errored error])))) - :paramName "file" - :headers {"Authorization" (str "Token " @token)} - :url (str "/api/invoices/upload" - (when-let [client-name (-> @client :id)] - (str "?client=" client-name))) - :previewsContainer "#dz-hidden" - :previewTemplate "
"})))}))) + (reagent/create-class + {:display-name "dropzone" + :component-did-mount (fn [this] + (js/Dropzone. (rdom/dom-node this) + (clj->js {:init (fn [] + (.on (js-this) "success" (fn [_ files] + (re-frame/dispatch [::invalidated]))) + (.on (js-this) "error" (fn [_ error] + (re-frame/dispatch [::errored error])))) + :paramName "file" + :headers {"Authorization" (str "Token " @token)} + :url (str "/api/invoices/upload" + (when-let [client-name (-> @client :id)] + (str "?client=" client-name))) + :previewsContainer "#dz-hidden" + :previewTemplate ""}))) + :reagent-render (fn [] + [:form.dz {:action "/api/invoices/upload"} + [:div.field.has-addons + [:p.control + [:a.button.is-static "Force Location"]] + [:p.control + [:input.input {:name "location" :placeholder "SG" :size "4" :maxlength "2" :style {:display "inline"}}]]] + [:div.field.has-addons + [:p.control + [:a.button.is-static "Force vendor"]] + [typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors]) + :match->text :name + :name "vendor" + :type "typeahead" + :on-change (fn [v] + (reset! vendor v)) + :value @vendor}] + ] + [:div.tile.notification + + [:div.has-text-centered {:style {:padding "80px 0px" :width "100%"}} + [:span + [:span {:class "icon"} + [:i {:class "fa fa-cloud-download"}]] + "Drop any invoices you want to process here"]]]])}) + )) (re-frame/reg-sub @@ -191,12 +193,13 @@ (fn [] (let [invoice-page (re-frame/subscribe [::invoice-page]) status (re-frame/subscribe [::subs/status]) - error (re-frame/subscribe [::error])] + error (re-frame/subscribe [::error]) + client (:id @(re-frame/subscribe [::subs/client]))] + ^{:key client} [:div [:h1.title "Upload invoices"] [dropzone] - [:div {:class "section"} (when @error