diff --git a/resources/sample-excel-small.tsv b/resources/sample-excel-small.tsv new file mode 100644 index 00000000..0d9370af --- /dev/null +++ b/resources/sample-excel-small.tsv @@ -0,0 +1 @@ +6/16/17 Acme Bread DEMO-CB 3/26/56 12:00 AM $54.00 Naschmarkt X 7/31/17 8:26 AM 8/1/17 3:57 PM 116 \ No newline at end of file diff --git a/src/clj/auto_ap/routes/invoices.clj b/src/clj/auto_ap/routes/invoices.clj index ac54ac60..7f5d9d92 100644 --- a/src/clj/auto_ap/routes/invoices.clj +++ b/src/clj/auto_ap/routes/invoices.clj @@ -2,6 +2,7 @@ (:require [auto-ap.datomic.clients :as d-clients] [auto-ap.datomic.vendors :as d-vendors] [auto-ap.datomic.invoices :as d-invoices] + [auto-ap.datomic.accounts :as d-accounts] [auto-ap.yodlee.import :refer [manual-import]] [auto-ap.utils :refer [by]] [auto-ap.datomic :refer [remove-nils uri]] @@ -69,12 +70,13 @@ (catch Exception e (throw (Exception. (str "Could not parse total from value '" (:amount i) "'") e))))) -(defn parse-default-expense-account [i] +(defn parse-account-numeric-code [i] (try - (when-let [default-expense-account (:default-expense-account i)] - (Integer/parseInt default-expense-account)) + (when-let [account-numeric-code (:account-numeric-code i)] + (d-accounts/get-account-by-numeric-code-and-sets (Integer/parseInt account-numeric-code) + ["default"])) (catch Exception e - (throw (Exception. (str "Could not parse expense account from value '" (:default-expense-account i) "'") e))))) + (throw (Exception. (str "Could not parse expense account from value '" (:account-numeric-code i) "'") e))))) (defn parse-account-id [i] (try @@ -100,7 +102,7 @@ :details (str e)}))))) (defn parse-invoice-rows [excel-rows] - (let [columns [:raw-date :vendor-name :check :location :invoice-number :amount :client-name :bill-entered :bill-rejected :added-on :exported-on :default-expense-account] + (let [columns [:raw-date :vendor-name :check :location :invoice-number :amount :client-name :bill-entered :bill-rejected :added-on :exported-on :account-numeric-code] all-vendors (by :vendor/name (d-vendors/get-graphql {})) all-clients (d-clients/get-all) all-clients (merge (by :client/code all-clients) (by :client/name all-clients)) @@ -112,7 +114,7 @@ (map (parse-or-error :client-id #(parse-client % all-clients))) (map (parse-or-error :vendor #(parse-vendor % all-vendors))) (map (parse-or-error :vendor-id #(parse-vendor-id %))) - (map (parse-or-error :default-expense-account parse-default-expense-account)) + (map (parse-or-error :account-id parse-account-numeric-code)) (map (parse-or-error :invoice-number parse-invoice-number)) (map (parse-or-error :total parse-amount)) (map (parse-or-error :date parse-date)))] @@ -122,13 +124,13 @@ (defn invoice-rows->transaction [rows] (->> rows - (mapcat (fn [{:keys [vendor-id total client-id amount date invoice-number default-location default-expense-account check vendor]}] + (mapcat (fn [{:keys [vendor-id total client-id amount date invoice-number default-location account-id check vendor]}] (let [invoice #:invoice {:db/id (.toString (java.util.UUID/randomUUID)) :vendor vendor-id :client client-id :default-location default-location :import-status :import-status/imported - :default-expense-account default-expense-account + #_#_:default-expense-account default-expense-account :total total :outstanding-balance (if (= "Cash" check) 0.0 @@ -138,7 +140,8 @@ :invoice-status/unpaid) :invoice-number invoice-number :date (to-date date) - :expense-accounts [#:invoice-expense-account {:expense-account-id (or default-expense-account (:vendor/default-expense-account vendor)) + :expense-accounts [#:invoice-expense-account {:account (or account-id + (-> vendor :vendor/account :db/id)) :location default-location :amount total}]} payment (if (= :invoice-status/paid (:invoice/status invoice)) @@ -160,18 +163,18 @@ (defn import-uploaded-invoice [imports] (let [clients (d-clients/get-all) - _ (println imports) + _ (clojure.pprint/pprint imports) transactions (reduce (fn [result {:keys [invoice-number customer-identifier total date vendor-code text] :as info}] - (let [[matching-vendor default-expense-account] (->> (d/query - (cond-> {:query {:find ['?vendor '?default-expense-account] - :in ['$ '?vendor-name] - :where ['[?vendor :vendor/name ?vendor-name] - '[?vendor :vendor/default-expense-account ?default-expense-account]]} - :args [(d/db (d/connect uri)) vendor-code]})) - first) + (let [[matching-vendor default-account] (->> (d/query + (cond-> {:query {:find ['?vendor '?default-account] + :in ['$ '?vendor-name] + :where ['[?vendor :vendor/name ?vendor-name] + '[?vendor :vendor/default-account ?default-account]]} + :args [(d/db (d/connect uri)) vendor-code]})) + first) matching-client (parse/best-match clients customer-identifier) - _ (println "New invoice matches client" matching-client) + _ (println "New invoice matches client '" matching-client "', vendor '" matching-vendor "', account '" default-account "'") matching-location (parse/best-location-match matching-client text ) [existing-id existing-outstanding-balance existing-status import-status] (->> (d/query (cond-> {:query {:find ['?e '?outstanding-balance '?status '?import-status2] @@ -196,7 +199,7 @@ :invoice/import-status :import-status/pending :invoice/outstanding-balance (or existing-outstanding-balance (Double/parseDouble total)) :invoice/status (or existing-status :invoice-status/unpaid) - :invoice/expense-accounts (when-not existing-id [#:invoice-expense-account {:expense-account-id default-expense-account + :invoice/expense-accounts (when-not existing-id [#:invoice-expense-account {:account default-account :location matching-location :amount (Double/parseDouble total)}]) :db/id existing-id @@ -205,8 +208,7 @@ [] imports)] - @(d/transact (d/connect uri) transactions) - )) + @(d/transact (d/connect uri) transactions))) (defroutes routes (wrap-routes @@ -224,12 +226,10 @@ (drop 1) (map #(str/split % #"\t")) (map #(into {} (filter identity (map (fn [c k] [k c] ) % columns)))) - (map (parse-or-error :amount parse-amount)) (map (parse-or-error :date parse-date))) error-rows (filter :errors rows) _ (println "importing raw transactions" rows) - raw-transactions (vec (->> rows (filter #(not (seq (:errors %))) ) (map (fn [{:keys [description-original client-code status high-level-category amount bank-account-code date]}] @@ -242,8 +242,6 @@ :bank-account-id (:db/id (all-bank-accounts bank-account-code))}))))] (manual-import raw-transactions) - - {:status 200 :body (pr-str {:imported (count raw-transactions) :errors (map #(dissoc % :date) error-rows)}) @@ -251,8 +249,9 @@ (context "/invoices" [] (POST "/upload" - {{ files "file"} :params :as params} - (let [{:keys [filename tempfile]} files] + {{ file :file } :params :as params} + #_(clojure.pprint/pprint params) + (let [{:keys [filename tempfile]} file] (import-uploaded-invoice (parse/parse-file (.getPath tempfile) filename)) {:status 200 :body (pr-str {})