re-enabling the ability to import invoices.
This commit is contained in:
1
resources/sample-excel-small.tsv
Normal file
1
resources/sample-excel-small.tsv
Normal file
@@ -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
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
(:require [auto-ap.datomic.clients :as d-clients]
|
(:require [auto-ap.datomic.clients :as d-clients]
|
||||||
[auto-ap.datomic.vendors :as d-vendors]
|
[auto-ap.datomic.vendors :as d-vendors]
|
||||||
[auto-ap.datomic.invoices :as d-invoices]
|
[auto-ap.datomic.invoices :as d-invoices]
|
||||||
|
[auto-ap.datomic.accounts :as d-accounts]
|
||||||
[auto-ap.yodlee.import :refer [manual-import]]
|
[auto-ap.yodlee.import :refer [manual-import]]
|
||||||
[auto-ap.utils :refer [by]]
|
[auto-ap.utils :refer [by]]
|
||||||
[auto-ap.datomic :refer [remove-nils uri]]
|
[auto-ap.datomic :refer [remove-nils uri]]
|
||||||
@@ -69,12 +70,13 @@
|
|||||||
(catch Exception e
|
(catch Exception e
|
||||||
(throw (Exception. (str "Could not parse total from value '" (:amount i) "'") 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
|
(try
|
||||||
(when-let [default-expense-account (:default-expense-account i)]
|
(when-let [account-numeric-code (:account-numeric-code i)]
|
||||||
(Integer/parseInt default-expense-account))
|
(d-accounts/get-account-by-numeric-code-and-sets (Integer/parseInt account-numeric-code)
|
||||||
|
["default"]))
|
||||||
(catch Exception e
|
(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]
|
(defn parse-account-id [i]
|
||||||
(try
|
(try
|
||||||
@@ -100,7 +102,7 @@
|
|||||||
:details (str e)})))))
|
:details (str e)})))))
|
||||||
|
|
||||||
(defn parse-invoice-rows [excel-rows]
|
(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-vendors (by :vendor/name (d-vendors/get-graphql {}))
|
||||||
all-clients (d-clients/get-all)
|
all-clients (d-clients/get-all)
|
||||||
all-clients (merge (by :client/code all-clients) (by :client/name all-clients))
|
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 :client-id #(parse-client % all-clients)))
|
||||||
(map (parse-or-error :vendor #(parse-vendor % all-vendors)))
|
(map (parse-or-error :vendor #(parse-vendor % all-vendors)))
|
||||||
(map (parse-or-error :vendor-id #(parse-vendor-id %)))
|
(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 :invoice-number parse-invoice-number))
|
||||||
(map (parse-or-error :total parse-amount))
|
(map (parse-or-error :total parse-amount))
|
||||||
(map (parse-or-error :date parse-date)))]
|
(map (parse-or-error :date parse-date)))]
|
||||||
@@ -122,13 +124,13 @@
|
|||||||
|
|
||||||
(defn invoice-rows->transaction [rows]
|
(defn invoice-rows->transaction [rows]
|
||||||
(->> 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))
|
(let [invoice #:invoice {:db/id (.toString (java.util.UUID/randomUUID))
|
||||||
:vendor vendor-id
|
:vendor vendor-id
|
||||||
:client client-id
|
:client client-id
|
||||||
:default-location default-location
|
:default-location default-location
|
||||||
:import-status :import-status/imported
|
:import-status :import-status/imported
|
||||||
:default-expense-account default-expense-account
|
#_#_:default-expense-account default-expense-account
|
||||||
:total total
|
:total total
|
||||||
:outstanding-balance (if (= "Cash" check)
|
:outstanding-balance (if (= "Cash" check)
|
||||||
0.0
|
0.0
|
||||||
@@ -138,7 +140,8 @@
|
|||||||
:invoice-status/unpaid)
|
:invoice-status/unpaid)
|
||||||
:invoice-number invoice-number
|
:invoice-number invoice-number
|
||||||
:date (to-date date)
|
: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
|
:location default-location
|
||||||
:amount total}]}
|
:amount total}]}
|
||||||
payment (if (= :invoice-status/paid (:invoice/status invoice))
|
payment (if (= :invoice-status/paid (:invoice/status invoice))
|
||||||
@@ -160,18 +163,18 @@
|
|||||||
|
|
||||||
(defn import-uploaded-invoice [imports]
|
(defn import-uploaded-invoice [imports]
|
||||||
(let [clients (d-clients/get-all)
|
(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}]
|
transactions (reduce (fn [result {:keys [invoice-number customer-identifier total date vendor-code text] :as info}]
|
||||||
(let [[matching-vendor default-expense-account] (->> (d/query
|
(let [[matching-vendor default-account] (->> (d/query
|
||||||
(cond-> {:query {:find ['?vendor '?default-expense-account]
|
(cond-> {:query {:find ['?vendor '?default-account]
|
||||||
:in ['$ '?vendor-name]
|
:in ['$ '?vendor-name]
|
||||||
:where ['[?vendor :vendor/name ?vendor-name]
|
:where ['[?vendor :vendor/name ?vendor-name]
|
||||||
'[?vendor :vendor/default-expense-account ?default-expense-account]]}
|
'[?vendor :vendor/default-account ?default-account]]}
|
||||||
:args [(d/db (d/connect uri)) vendor-code]}))
|
:args [(d/db (d/connect uri)) vendor-code]}))
|
||||||
first)
|
first)
|
||||||
matching-client (parse/best-match clients customer-identifier)
|
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 )
|
matching-location (parse/best-location-match matching-client text )
|
||||||
[existing-id existing-outstanding-balance existing-status import-status] (->> (d/query
|
[existing-id existing-outstanding-balance existing-status import-status] (->> (d/query
|
||||||
(cond-> {:query {:find ['?e '?outstanding-balance '?status '?import-status2]
|
(cond-> {:query {:find ['?e '?outstanding-balance '?status '?import-status2]
|
||||||
@@ -196,7 +199,7 @@
|
|||||||
:invoice/import-status :import-status/pending
|
:invoice/import-status :import-status/pending
|
||||||
:invoice/outstanding-balance (or existing-outstanding-balance (Double/parseDouble total))
|
:invoice/outstanding-balance (or existing-outstanding-balance (Double/parseDouble total))
|
||||||
:invoice/status (or existing-status :invoice-status/unpaid)
|
: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
|
:location matching-location
|
||||||
:amount (Double/parseDouble total)}])
|
:amount (Double/parseDouble total)}])
|
||||||
:db/id existing-id
|
:db/id existing-id
|
||||||
@@ -205,8 +208,7 @@
|
|||||||
[]
|
[]
|
||||||
imports)]
|
imports)]
|
||||||
|
|
||||||
@(d/transact (d/connect uri) transactions)
|
@(d/transact (d/connect uri) transactions)))
|
||||||
))
|
|
||||||
|
|
||||||
(defroutes routes
|
(defroutes routes
|
||||||
(wrap-routes
|
(wrap-routes
|
||||||
@@ -224,12 +226,10 @@
|
|||||||
(drop 1)
|
(drop 1)
|
||||||
(map #(str/split % #"\t"))
|
(map #(str/split % #"\t"))
|
||||||
(map #(into {} (filter identity (map (fn [c k] [k c] ) % columns))))
|
(map #(into {} (filter identity (map (fn [c k] [k c] ) % columns))))
|
||||||
|
|
||||||
(map (parse-or-error :amount parse-amount))
|
(map (parse-or-error :amount parse-amount))
|
||||||
(map (parse-or-error :date parse-date)))
|
(map (parse-or-error :date parse-date)))
|
||||||
error-rows (filter :errors rows)
|
error-rows (filter :errors rows)
|
||||||
_ (println "importing raw transactions" rows)
|
_ (println "importing raw transactions" rows)
|
||||||
|
|
||||||
raw-transactions (vec (->> rows
|
raw-transactions (vec (->> rows
|
||||||
(filter #(not (seq (:errors %))) )
|
(filter #(not (seq (:errors %))) )
|
||||||
(map (fn [{:keys [description-original client-code status high-level-category amount bank-account-code date]}]
|
(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))}))))]
|
:bank-account-id (:db/id (all-bank-accounts bank-account-code))}))))]
|
||||||
|
|
||||||
(manual-import raw-transactions)
|
(manual-import raw-transactions)
|
||||||
|
|
||||||
|
|
||||||
{:status 200
|
{:status 200
|
||||||
:body (pr-str {:imported (count raw-transactions)
|
:body (pr-str {:imported (count raw-transactions)
|
||||||
:errors (map #(dissoc % :date) error-rows)})
|
:errors (map #(dissoc % :date) error-rows)})
|
||||||
@@ -251,8 +249,9 @@
|
|||||||
|
|
||||||
(context "/invoices" []
|
(context "/invoices" []
|
||||||
(POST "/upload"
|
(POST "/upload"
|
||||||
{{ files "file"} :params :as params}
|
{{ file :file } :params :as params}
|
||||||
(let [{:keys [filename tempfile]} files]
|
#_(clojure.pprint/pprint params)
|
||||||
|
(let [{:keys [filename tempfile]} file]
|
||||||
(import-uploaded-invoice (parse/parse-file (.getPath tempfile) filename))
|
(import-uploaded-invoice (parse/parse-file (.getPath tempfile) filename))
|
||||||
{:status 200
|
{:status 200
|
||||||
:body (pr-str {})
|
:body (pr-str {})
|
||||||
|
|||||||
Reference in New Issue
Block a user