major switch to support import from excel.

This commit is contained in:
Bryce Covert
2018-05-03 22:43:08 -07:00
parent ea1e43d981
commit a526d2da1b
5 changed files with 206 additions and 51 deletions

View File

@@ -1,5 +1,5 @@
(ns auto-ap.db.invoices
(:require [auto-ap.db.utils :refer [clj->db db->clj get-conn query] :as utils]
(:require [auto-ap.db.utils :refer [clj->db kebab->snake db->clj get-conn query] :as utils]
[auto-ap.parse :as parse]
[auto-ap.db.companies :as companies]
[auto-ap.db.vendors :as vendors]
@@ -17,6 +17,26 @@
:invoices
(map clj->db rows)))
(defn upsert-multi! [rows]
(let [k (vec (map #(keyword (kebab->snake (name %))) [:company-id :vendor-id :invoice-number :total :date :imported]))
column-names (str/join "," (map name k))]
(doseq [rows (partition-all 2000 rows)]
(j/db-do-prepared (get-conn)
(sql/format {:with [[[:v (str "(" column-names ")")]
(helpers/values (->> rows
(map clj->db )
(map (apply juxt k))))]]
:insert-into [[:invoices k]
{:select [:v.company-id :v.vendor-id :v.invoice-number :v.total (sql/raw "cast(v.date as timestamp)") :v.imported ]
:from [:v]
:left-join [[:invoices :exist]
[:and
[:= :exist.invoice-number :v.invoice-number]
[:= :exist.company-id :v.company-id]
[:= :exist.vendor-id :v.vendor-id]]]
:where [:= :exist.id nil] }] })))))
(def base-query (sql/build :select :invoices.*
:from :invoices))
@@ -75,8 +95,7 @@
(defn base-graphql [{:keys [imported company-id]}]
(cond-> base-query
(not (nil? imported)) (helpers/merge-where [:= :imported imported])
(not (nil? company-id)) (helpers/merge-where [:= :company-id company-id])
))
(not (nil? company-id)) (helpers/merge-where [:= :company-id company-id])))
(defn get-graphql [{:keys [start sort-by asc] :as args}]
(query

View File

@@ -98,7 +98,7 @@
(doseq [{:keys [vendor-name id email subject body]} reminders]
(when email
(println "Sending email to" email)
(ses/send-email :destination {:to-addresses [email]}
#_(ses/send-email :destination {:to-addresses [email]}
:source (:invoice-email env)
:message {:subject subject
:body {:html (str "<h1>Hello " vendor-name ",</h1><p>" body "</p> <p> - Integreat. </p>")

View File

@@ -18,21 +18,42 @@
(defn assoc-company-code [i]
(assoc i :company-code (first (str/split (:location i) #"-" ))))
(defn assoc-company [i companies]
(assoc i :company-id (or (-> i
:company-code
companies
:id)
(-> i
:company
companies
:id))))
(defn parse-company [{:keys [company-code company]} companies]
(if-let [id (:id (or (companies company-code)
(companies company)))]
id
(throw (Exception. (str "Company code '" company-code "' and company named '" company "' not found.")))))
(defn assoc-vendor [i vendors]
(assoc i :vendor-id (-> i
:vendor-name
vendors
:id)))
(defn parse-invoice-number [{:keys [invoice-number]}]
(or invoice-number ""))
(defn parse-vendor [{:keys [vendor-name]} vendors]
(if-let [id (:id (vendors vendor-name))]
id
(throw (Exception. (str "Vendor '" vendor-name "' not found.")))))
(defn parse-amount [i]
(try
(Double/parseDouble (str/replace (or (second
(re-matches #"[^0-9\.,]*([0-9\.,]+)[^0-9\.,]*" (:amount i)))
"0")
#"," ""))
(catch Exception e
(throw (Exception. (str "Could not parse total from value '" (:amount i) "'") e)))))
(defn parse-date [{:keys [raw-date]}]
(try
(parse/parse-value :clj-time "MM/dd/yyyy" raw-date)
(catch Exception e
(throw (Exception. (str "Could not parse date from '" raw-date "'") e)))))
(defn parse-or-error [key f]
(fn [x]
(try
(assoc x key (f x))
(catch Exception e
(update x :errors conj {:info (.getMessage e)
:details (str e)})))))
(defroutes routes
(wrap-routes
@@ -78,7 +99,7 @@
(POST "/upload-integreat"
{{:keys [excel-rows]} :edn-params}
(let [columns [:date :vendor-name :check :location :invoice-number :amount :company :bill-entered :bill-rejected :added-on :exported-on]
(let [columns [:raw-date :vendor-name :check :location :invoice-number :amount :company :bill-entered :bill-rejected :added-on :exported-on]
all-vendors (reduce
(fn [x y]
@@ -100,23 +121,27 @@
(map #(into {} (map (fn [c k] [k c] ) % columns)))
(map reset-id)
(map assoc-company-code)
(map #(assoc-company % all-companies))
(map #(assoc-vendor % all-vendors))
(map (fn [{:keys [vendor-id company-id amount date invoice-number]}]
{:vendor-id vendor-id
:company-id company-id
:total (Double/parseDouble (second
(re-matches #"[^0-9\.]*([0-9\.]+)[^0-9\.]*" amount)))
:imported true
:status "unpaid"
:invoice-number invoice-number
:date (parse/parse-value :clj-time "MM/dd/yyyy" date )
}))
)]
(invoices/insert-multi! rows)
(map (parse-or-error :company-id #(parse-company % all-companies)))
(map (parse-or-error :vendor-id #(parse-vendor % all-vendors)))
(map (parse-or-error :invoice-number parse-invoice-number))
(map (parse-or-error :total parse-amount))
(map (parse-or-error :date parse-date)))
error-rows (filter :errors rows)
insert-rows (vec (->> (filter #(not (seq (:errors %))) rows)
(map (fn [{:keys [vendor-id total company-id amount date invoice-number]}]
{:vendor-id vendor-id
:company-id company-id
:total total
:imported true
:status "unpaid"
:invoice-number invoice-number
:date date}))))]
(invoices/upsert-multi! insert-rows)
{:status 200
:body (pr-str rows)
:body (pr-str {:imported (count insert-rows)
:errors (map #(dissoc % :date) error-rows)})
:headers {"Content-Type" "application/edn"}}))
;; Removing the export view for now...

View File

@@ -8,7 +8,8 @@
[auto-ap.views.utils :refer [login-url dispatch-value-change bind-field horizontal-field dispatch-event]]
[cljs.reader :as edn]
[auto-ap.routes :as routes]
[bidi.bidi :as bidi]))
[bidi.bidi :as bidi]
[clojure.string :as str]))
(re-frame/reg-sub
::excel-import
@@ -36,7 +37,8 @@
:headers {"Content-Type" "application/edn"}
:uri (str "/api/invoices/upload-integreat")
:on-success [::save-complete]
:on-error [::save-error]}})))
:on-error [::save-error]}
:db (assoc-in db [::excel-import :rows] nil)})))
(re-frame/reg-event-fx
::save-complete
@@ -62,18 +64,28 @@
:subscription excel-import-data}]]
[:button.button.is-large.is-pulled-right.is-primary {:on-click (dispatch-event [::save])} "Import"]
[:div
[:table.table.is-fullwidth
[:thead
[:td "Date"]
[:td "Invoice #"]
[:td "Vendor"]
[:td "Company"]]
[:tbody
(for [{:keys [invoice-number date vendor-name company]} (:rows excel-import-data)]
[:tr
[:td date]
[:td invoice-number]
[:td vendor-name]
[:td company]])]]]])])
[:div.is-clearfix
(when-let [imported (:imported (:rows excel-import-data))]
(str imported " rows imported."))
]
(when-let [errors (:errors (:rows excel-import-data))]
[:div
[:h3 (str "Import errors (" (min 100 (count errors)) ")")]
[:table.table.is-fullwidth
[:thead
[:th "Date"]
[:th "Invoice #"]
[:th "Company"]
[:th "Vendor"]
[:th "Amount"]
[:th "Errors"]]
(for [{:keys [raw-date invoice-number company vendor-name amount] row-errors :errors} (take 100 errors)]
[:tr
[:td raw-date]
[:td invoice-number]
[:td company]
[:td vendor-name]
[:td amount]
[:td (map #(vector :p (:info %)) row-errors)]])]])])])