From ea1e43d981cd447e0443572fbb91642885168ae3 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Thu, 3 May 2018 15:23:10 -0700 Subject: [PATCH] can import from excel now. --- .../1525382176-DOWN-more-customer-fields.sql | 4 + .../1525382176-UP-more-customer-fields.sql | 20 +++++ src/clj/auto_ap/routes/invoices.clj | 73 ++++++++++++++++- src/cljs/auto_ap/history.cljs | 1 + src/cljs/auto_ap/routes.cljs | 3 +- src/cljs/auto_ap/views/main.cljs | 11 ++- src/cljs/auto_ap/views/pages.cljs | 4 + .../views/pages/admin/excel-import.cljs | 79 +++++++++++++++++++ src/cljs/auto_ap/views/utils.cljs | 2 +- 9 files changed, 192 insertions(+), 5 deletions(-) create mode 100644 migrator/migrations/1525382176-DOWN-more-customer-fields.sql create mode 100644 migrator/migrations/1525382176-UP-more-customer-fields.sql create mode 100644 src/cljs/auto_ap/views/pages/admin/excel-import.cljs diff --git a/migrator/migrations/1525382176-DOWN-more-customer-fields.sql b/migrator/migrations/1525382176-DOWN-more-customer-fields.sql new file mode 100644 index 00000000..dc053f00 --- /dev/null +++ b/migrator/migrations/1525382176-DOWN-more-customer-fields.sql @@ -0,0 +1,4 @@ +-- 1525382176 DOWN more-customer-fields +ALTER TABLE companies drop column code; +delete from invoices; +delete from companies; diff --git a/migrator/migrations/1525382176-UP-more-customer-fields.sql b/migrator/migrations/1525382176-UP-more-customer-fields.sql new file mode 100644 index 00000000..428ca84a --- /dev/null +++ b/migrator/migrations/1525382176-UP-more-customer-fields.sql @@ -0,0 +1,20 @@ +-- 1525382176 UP more-customer-fields +ALTER TABLE companies ADD code varchar(255); + +INSERT INTO companies (code, name, data) +VALUES +('BCBC', 'Brown Chicken Brown Cow', '{}'), +('BSG', 'Bella Saratoga', '{}'), +('CBC', 'Campbell Brewing Co', '{}'), +('IBC', 'Iguanas Burritozilla', '{}'), +('IBCBC', 'Shared CBC-IBC Expenses', '{}'), +('KOG', 'Knock Out Grill & Bar', '{}'), +('LFT', 'Lefty''s East Coast Pizzeria', '{}'), +('MAM', 'Mama Mia''s', '{}'), +('MLF', 'Mama Lu''s Foods', '{}'), +('MPI', 'Moscini Pizza Inc', '{}'), +('NBST', 'Nasch Bistro', '{}'), +('NMKT', 'Naschmarkt', '{}'), +('RCI', 'Roberto''s Cantina Inc', '{}'), +('SIB', 'Sorelle Italian Bistro', '{}'), +('TSL', 'The Socialight', '{}'); diff --git a/src/clj/auto_ap/routes/invoices.clj b/src/clj/auto_ap/routes/invoices.clj index b45e55ac..a0209bf8 100644 --- a/src/clj/auto_ap/routes/invoices.clj +++ b/src/clj/auto_ap/routes/invoices.clj @@ -6,7 +6,33 @@ [auto-ap.parse :as parse] [auto-ap.routes.utils :refer [wrap-secure]] [compojure.core :refer [GET POST context defroutes - wrap-routes]])) + wrap-routes]] + [clojure.string :as str])) + +(defn reset-id [i] + (update i :invoice-number + (fn [n] (if (re-matches #"#+" n) + nil + n)))) + +(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 assoc-vendor [i vendors] + (assoc i :vendor-id (-> i + :vendor-name + vendors + :id))) (defroutes routes (wrap-routes @@ -48,7 +74,50 @@ (invoices/import (parse/parse-file (.getPath tempfile) filename) companies vendors) {:status 200 :body (pr-str (invoices/get-pending ((:query-params params ) "company"))) - :headers {"Content-Type" "application/edn"}})) + :headers {"Content-Type" "application/edn"}})) + + (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] + + all-vendors (reduce + (fn [x y] + (assoc x (:name y) y)) + {} + (vendors/get-all)) + + all-companies (reduce + (fn [x y] + (-> x + (assoc (:code y) y) + (assoc (:name y) y))) + {} + (companies/get-all)) + + + rows (->> (str/split excel-rows #"\n" ) + (map #(str/split % #"\t")) + (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) + + {:status 200 + :body (pr-str rows) + :headers {"Content-Type" "application/edn"}})) ;; Removing the export view for now... #_(wrap-json-response (GET "/export" {:keys [query-params]} diff --git a/src/cljs/auto_ap/history.cljs b/src/cljs/auto_ap/history.cljs index 7701be01..cc1a5315 100644 --- a/src/cljs/auto_ap/history.cljs +++ b/src/cljs/auto_ap/history.cljs @@ -8,6 +8,7 @@ (bidi/match-route routes/routes url)) (defn- dispatch-route [matched-route] + (println matched-route) (re-frame/dispatch [:auto-ap.events/set-active-page (:handler matched-route)])) diff --git a/src/cljs/auto_ap/routes.cljs b/src/cljs/auto_ap/routes.cljs index 5d5962d7..d94c8135 100644 --- a/src/cljs/auto_ap/routes.cljs +++ b/src/cljs/auto_ap/routes.cljs @@ -6,7 +6,8 @@ "admin/" {"" :admin "companies" :admin-companies "reminders" :admin-reminders - "vendors" :admin-vendors} + "vendors" :admin-vendors + "excel-import" :admin-excel-import} "invoices/" {"" :invoices "import" :import-invoices "unpaid" :unpaid-invoices diff --git a/src/cljs/auto_ap/views/main.cljs b/src/cljs/auto_ap/views/main.cljs index c92f38f9..065ef025 100644 --- a/src/cljs/auto_ap/views/main.cljs +++ b/src/cljs/auto_ap/views/main.cljs @@ -18,6 +18,7 @@ :paid-invoices :left-panel :admin :admin-left-panel :admin-companies :admin-left-panel + :admin-excel-import :admin-left-panel :admin-vendors :admin-left-panel :admin-reminders :admin-left-panel :new-invoice :blank} page)) @@ -94,7 +95,15 @@ [:span {:class "icon"} [:i {:class "fa fa-star-o"}]] - [:span {:class "name"} "Reminders"]]]]] + [:span {:class "name"} "Reminders"]]]] + [:p.menu-label "Import"] + [:ul.menu-list + [:li.menu-item + [:a {:href (bidi/path-for routes/routes :admin-excel-import) , :class (str "item" (active-when= ap :admin-excel-import))} + [:span {:class "icon"} + [:i {:class "fa fa-download"}]] + + [:span {:class "name"} "Excel Invoices"]]]]] [:div.left-nav [:div {:class "compose has-text-centered"} diff --git a/src/cljs/auto_ap/views/pages.cljs b/src/cljs/auto_ap/views/pages.cljs index 9d7153af..73c26761 100644 --- a/src/cljs/auto_ap/views/pages.cljs +++ b/src/cljs/auto_ap/views/pages.cljs @@ -13,6 +13,7 @@ [auto-ap.views.pages.unpaid-invoices :refer [unpaid-invoices-page]] [auto-ap.views.pages.new-invoice :refer [new-invoice-page]] [auto-ap.views.pages.import-invoices :refer [import-invoices-page]] + [auto-ap.views.pages.admin.excel-import :refer [admin-excel-import-page]] [auto-ap.views.pages.paid-invoices :refer [paid-invoices-page]] [cljs.reader :as edn] [cljsjs.dropzone :as dz] @@ -42,6 +43,9 @@ (defmethod active-page :admin-reminders [] [admin-reminders-page]) +(defmethod active-page :admin-excel-import [] + [admin-excel-import-page]) + (defmethod active-page :unpaid-invoices [] [unpaid-invoices-page]) diff --git a/src/cljs/auto_ap/views/pages/admin/excel-import.cljs b/src/cljs/auto_ap/views/pages/admin/excel-import.cljs new file mode 100644 index 00000000..07ddfc22 --- /dev/null +++ b/src/cljs/auto_ap/views/pages/admin/excel-import.cljs @@ -0,0 +1,79 @@ +(ns auto-ap.views.pages.admin.excel-import + (:require-macros [cljs.core.async.macros :refer [go]]) + (:require [re-frame.core :as re-frame] + [reagent.core :as reagent] + [auto-ap.subs :as subs] + [auto-ap.events.admin.companies :as events] + [auto-ap.entities.companies :as entity] + [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])) + +(re-frame/reg-sub + ::excel-import + (fn [db] + (::excel-import db))) + +(re-frame/reg-event-db + ::change + (fn [db [_ field v]] + (assoc-in db (into [::excel-import] field) v))) + +(re-frame/reg-event-db + ::edit + (fn [db [_ field v]] + (assoc db ::excel-import nil ) + db)) + +(re-frame/reg-event-fx + ::save + (fn [{:keys [db]}] + (let [excel-import (::excel-import db)] + {:http {:token (:user db) + :method :post + :body (pr-str excel-import) + :headers {"Content-Type" "application/edn"} + :uri (str "/api/invoices/upload-integreat") + :on-success [::save-complete] + :on-error [::save-error]}}))) + +(re-frame/reg-event-fx + ::save-complete + (fn [{:keys [db]} [_ rows]] + {:dispatch [::edit nil] + :db (assoc-in db [::excel-import :rows] rows)})) + +(re-frame/reg-event-fx + ::save-error + (fn [{:keys [db]}] + {:dispatch [::change [:error] true]})) + +(defn admin-excel-import-page [] + [:div + (let [excel-import-data @(re-frame/subscribe [::excel-import])] + [:div + [:h1.title "Import Invoices from Integreat Excel"] + [bind-field + [:textarea.textarea {:rows "20" + :field :excel-rows + :type "text" + :event ::change + :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]])]]]])]) diff --git a/src/cljs/auto_ap/views/utils.cljs b/src/cljs/auto_ap/views/utils.cljs index 8eb5f40c..369142bb 100644 --- a/src/cljs/auto_ap/views/utils.cljs +++ b/src/cljs/auto_ap/views/utils.cljs @@ -34,7 +34,7 @@ (when d (format/unparse pretty-long d))) -(defmulti do-bind (fn [_ {:keys [type]}] +(defmulti do-bind (fn [a {:keys [type] :as x}] type)) (defmethod do-bind "select" [dom {:keys [field subscription event class value spec] :as keys} & rest]