Adding vendor import stuff.
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
-- 1525464770 DOWN change-amount-to-number
|
||||||
|
alter table invoices drop column total;
|
||||||
|
alter table invoices add column total varchar(255);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- 1525464770 UP change-amount-to-number
|
||||||
|
alter table invoices drop column total;
|
||||||
|
alter table invoices add column total decimal;
|
||||||
@@ -36,7 +36,10 @@
|
|||||||
[:and
|
[:and
|
||||||
[:= :exist.invoice-number :v.invoice-number]
|
[:= :exist.invoice-number :v.invoice-number]
|
||||||
[:= :exist.company-id :v.company-id]
|
[:= :exist.company-id :v.company-id]
|
||||||
[:= :exist.vendor-id :v.vendor-id]]]
|
[:or [:= :exist.vendor-id :v.vendor-id]
|
||||||
|
[:and
|
||||||
|
[:= :exist.vendor-id nil]
|
||||||
|
[:= :v.vendor-id nil]]]]]
|
||||||
:where [:= :exist.id nil] }] })))))
|
:where [:= :exist.id nil] }] })))))
|
||||||
0
|
0
|
||||||
(partition-all 2000 rows))))
|
(partition-all 2000 rows))))
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
(let [[id] (-> (sql/build :insert-into :vendors
|
(let [[id] (-> (sql/build :insert-into :vendors
|
||||||
:values [(unparse data)])
|
:values [(unparse data)])
|
||||||
execute!)]
|
execute!)]
|
||||||
|
(println "inserted vendor: " data ", id " id)
|
||||||
(get-by-id id)))
|
(get-by-id id)))
|
||||||
|
|
||||||
(defn find-with-reminders []
|
(defn find-with-reminders []
|
||||||
|
|||||||
@@ -27,10 +27,16 @@
|
|||||||
(defn parse-invoice-number [{:keys [invoice-number]}]
|
(defn parse-invoice-number [{:keys [invoice-number]}]
|
||||||
(or invoice-number ""))
|
(or invoice-number ""))
|
||||||
|
|
||||||
(defn parse-vendor [{:keys [vendor-name]} vendors]
|
(defn parse-vendor [{:keys [vendor-name check]} vendors]
|
||||||
(if-let [id (:id (vendors vendor-name))]
|
(let [id (:id (vendors vendor-name))]
|
||||||
|
(cond id
|
||||||
id
|
id
|
||||||
(throw (Exception. (str "Vendor '" vendor-name "' not found.")))))
|
|
||||||
|
(= "Cash" check)
|
||||||
|
nil
|
||||||
|
|
||||||
|
:else
|
||||||
|
(throw (Exception. (str "Vendor '" vendor-name "' not found."))))))
|
||||||
|
|
||||||
(defn parse-amount [i]
|
(defn parse-amount [i]
|
||||||
(try
|
(try
|
||||||
@@ -127,6 +133,11 @@
|
|||||||
(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)))
|
||||||
error-rows (filter :errors rows)
|
error-rows (filter :errors rows)
|
||||||
|
vendors-not-found (->> rows
|
||||||
|
(filter #(and (nil? (:vendor-id %))
|
||||||
|
(not= "Cash" (:check %))))
|
||||||
|
(map :vendor-name)
|
||||||
|
set)
|
||||||
insert-rows (vec (->> (filter #(not (seq (:errors %))) rows)
|
insert-rows (vec (->> (filter #(not (seq (:errors %))) rows)
|
||||||
(map (fn [{:keys [vendor-id total company-id amount date invoice-number]}]
|
(map (fn [{:keys [vendor-id total company-id amount date invoice-number]}]
|
||||||
{:vendor-id vendor-id
|
{:vendor-id vendor-id
|
||||||
@@ -138,13 +149,15 @@
|
|||||||
:date date}))))
|
:date date}))))
|
||||||
|
|
||||||
inserted-row-count (invoices/upsert-multi! insert-rows)
|
inserted-row-count (invoices/upsert-multi! insert-rows)
|
||||||
already-imported-count (- (count insert-rows) inserted-row-count)]
|
already-imported-count (- (count insert-rows) inserted-row-count)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{:status 200
|
{:status 200
|
||||||
:body (pr-str {:imported inserted-row-count
|
:body (pr-str {:imported inserted-row-count
|
||||||
:already-imported already-imported-count
|
:already-imported already-imported-count
|
||||||
|
:vendors-not-found vendors-not-found
|
||||||
:errors (map #(dissoc % :date) error-rows)})
|
:errors (map #(dissoc % :date) error-rows)})
|
||||||
:headers {"Content-Type" "application/edn"}}))
|
:headers {"Content-Type" "application/edn"}}))
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
[cljs-time.coerce :as c]
|
[cljs-time.coerce :as c]
|
||||||
[cljs-time.core :as time]
|
[cljs-time.core :as time]
|
||||||
[cljs-time.format :as format]
|
[cljs-time.format :as format]
|
||||||
[cljs.core.async :refer [<!]]
|
[cljs.core.async :refer [<! ] :as async]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[clojure.walk :as walk]
|
[clojure.walk :as walk]
|
||||||
[venia.core :as v]
|
[venia.core :as v]
|
||||||
@@ -68,6 +68,31 @@
|
|||||||
(conj on-success)
|
(conj on-success)
|
||||||
(re-frame/dispatch)))))))
|
(re-frame/dispatch)))))))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:https
|
||||||
|
(fn [{:keys [requests on-success on-failure]}]
|
||||||
|
(go
|
||||||
|
|
||||||
|
(let [results (->>
|
||||||
|
(for [{:keys [method body headers uri token]} requests]
|
||||||
|
(go
|
||||||
|
(let [headers (if token
|
||||||
|
(assoc headers "Authorization" (str "Token " token))
|
||||||
|
headers)
|
||||||
|
response (<! (http/request {:method method
|
||||||
|
:body body
|
||||||
|
:headers headers
|
||||||
|
:url uri}))]
|
||||||
|
(if (>= (:status response) 400)
|
||||||
|
:error
|
||||||
|
:success))))
|
||||||
|
(async/merge)
|
||||||
|
(async/reduce conj [])
|
||||||
|
(async/<!))]
|
||||||
|
(if (some #{:error} results)
|
||||||
|
(re-frame/dispatch on-failure)
|
||||||
|
(re-frame/dispatch on-success))))))
|
||||||
|
|
||||||
(defn kebab->snake [s]
|
(defn kebab->snake [s]
|
||||||
(str/replace s #"-" "_"))
|
(str/replace s #"-" "_"))
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
[auto-ap.views.components.sorter :refer [sorted-column]]
|
[auto-ap.views.components.sorter :refer [sorted-column]]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[cljs-time.format :as format]))
|
[cljs-time.format :as format]
|
||||||
|
[goog.string :as gstring]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn invoice-table [{:keys [id invoice-page status on-params-change vendors params]}]
|
(defn invoice-table [{:keys [id invoice-page status on-params-change vendors params check-boxes on-check-changed]}]
|
||||||
(let [state (reagent/atom (or @params {}))
|
(let [state (reagent/atom (or @params {}))
|
||||||
opc (fn [p]
|
opc (fn [p]
|
||||||
(swap! state merge p)
|
(swap! state merge p)
|
||||||
@@ -40,6 +41,8 @@
|
|||||||
[:table.table.is-fullwidth
|
[:table.table.is-fullwidth
|
||||||
[:thead
|
[:thead
|
||||||
[:tr
|
[:tr
|
||||||
|
(when check-boxes
|
||||||
|
[:th])
|
||||||
[sorted-column {:on-sort opc
|
[sorted-column {:on-sort opc
|
||||||
:style {:width "25%" :cursor "pointer"}
|
:style {:width "25%" :cursor "pointer"}
|
||||||
:sort-key "vendor"
|
:sort-key "vendor"
|
||||||
@@ -78,8 +81,12 @@
|
|||||||
(for [{:keys [company invoice-number date total id vendor] :as i} (:invoices @invoice-page)]
|
(for [{:keys [company invoice-number date total id vendor] :as i} (:invoices @invoice-page)]
|
||||||
^{:key id}
|
^{:key id}
|
||||||
[:tr
|
[:tr
|
||||||
|
(when check-boxes
|
||||||
|
[:td [:input.checkbox {:type "checkbox" :on-change (fn [x e] (when on-check-changed
|
||||||
|
(on-check-changed id)))} ]])
|
||||||
[:td (:name vendor)]
|
[:td (:name vendor)]
|
||||||
[:td (:name company)]
|
[:td (:name company)]
|
||||||
[:td invoice-number]
|
[:td invoice-number]
|
||||||
[:td (date->str date) ]
|
[:td (date->str date) ]
|
||||||
[:td total]]))]]]))))
|
|
||||||
|
[:td (gstring/format "$%.2f" total )]]))]]]))))
|
||||||
|
|||||||
@@ -59,11 +59,79 @@
|
|||||||
(assoc-in [::excel-import :rows] nil)
|
(assoc-in [::excel-import :rows] nil)
|
||||||
(assoc-in [::excel-import :saving?] false))}))
|
(assoc-in [::excel-import :saving?] false))}))
|
||||||
|
|
||||||
|
(re-frame/reg-event-db
|
||||||
|
::toggle-vendor
|
||||||
|
(fn [db [_ data]]
|
||||||
|
(update-in db [::excel-import :create-vendors] (fn [x]
|
||||||
|
(let [x (or x #{})]
|
||||||
|
(if (x data)
|
||||||
|
(disj x data)
|
||||||
|
(conj x data)))))))
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::create-vendors
|
||||||
|
(fn [{:keys [db]}]
|
||||||
|
(let [excel-import (::excel-import db)]
|
||||||
|
{:https {:requests (map (fn [v]
|
||||||
|
{:token (:user db)
|
||||||
|
:method :post
|
||||||
|
:body (pr-str {:name v})
|
||||||
|
:headers {"Content-Type" "application/edn"}
|
||||||
|
:uri (str "/api/vendors/")})
|
||||||
|
(get-in db [::excel-import :create-vendors]))
|
||||||
|
:on-success [::create-vendor-complete]
|
||||||
|
:on-error [::create-vendor-error]}
|
||||||
|
:db (-> db
|
||||||
|
(assoc-in [::excel-import :saving-vendors?] true))})))
|
||||||
|
|
||||||
|
|
||||||
|
(re-frame/reg-event-db
|
||||||
|
::create-vendor-complete
|
||||||
|
(fn [db [_ data]]
|
||||||
|
(-> db
|
||||||
|
(update-in [::excel-import :rows :vendors-not-found]
|
||||||
|
(fn [v]
|
||||||
|
(reduce disj v (get-in db [::excel-import :create-vendors]))))
|
||||||
|
(update-in [::excel-import] dissoc :create-vendors))))
|
||||||
|
|
||||||
(defn admin-excel-import-page []
|
(defn admin-excel-import-page []
|
||||||
[:div
|
[:div
|
||||||
(let [excel-import-data @(re-frame/subscribe [::excel-import])]
|
(let [{{:keys [vendors-not-found already-imported imported]} :rows
|
||||||
|
:keys [create-vendors]
|
||||||
|
:or {create-vendors #{}}
|
||||||
|
:as excel-import-data} @(re-frame/subscribe [::excel-import])]
|
||||||
[:div
|
[:div
|
||||||
[:h1.title "Import Invoices from Integreat Excel"]
|
[:h1.title "Import Invoices from Integreat Excel"]
|
||||||
|
(when (seq vendors-not-found)
|
||||||
|
[:article.message.is-warning.is-paddingless
|
||||||
|
[:div.message-header
|
||||||
|
"Some vendors could not be found"]
|
||||||
|
|
||||||
|
[:div.message-body
|
||||||
|
[:h2 "Check the vendors you want to create"]
|
||||||
|
[:div.columns
|
||||||
|
(for [[i vendor-group] (map vector (range) (partition-all (max 1 (/ (count vendors-not-found) 3)) vendors-not-found))]
|
||||||
|
^{:key i}
|
||||||
|
[:div.column
|
||||||
|
(for [v vendor-group]
|
||||||
|
^{:key v} [:div.control
|
||||||
|
[:label.checkbox
|
||||||
|
[:input {:value v
|
||||||
|
:checked (if (create-vendors v)
|
||||||
|
"checked"
|
||||||
|
"")
|
||||||
|
|
||||||
|
:type "checkbox"
|
||||||
|
:on-change (fn []
|
||||||
|
(re-frame/dispatch [::toggle-vendor v]))}]
|
||||||
|
(str " " v)]])])]
|
||||||
|
[:div
|
||||||
|
[:button.button.is-pulled-right
|
||||||
|
{:on-click (dispatch-event [::create-vendors])
|
||||||
|
:disabled (when-not (seq create-vendors)
|
||||||
|
"disabled")
|
||||||
|
}
|
||||||
|
(str "Create " (count create-vendors) " vendors")]]
|
||||||
|
[:div.is-clearfix]]])
|
||||||
[bind-field
|
[bind-field
|
||||||
[:textarea.textarea {:rows "20"
|
[:textarea.textarea {:rows "20"
|
||||||
:field :excel-rows
|
:field :excel-rows
|
||||||
@@ -76,17 +144,17 @@
|
|||||||
"is-loading")
|
"is-loading")
|
||||||
:disabled (when (:saving? excel-import-data) "disabled")} "Import"]
|
:disabled (when (:saving? excel-import-data) "disabled")} "Import"]
|
||||||
|
|
||||||
|
[:div.is-clearfix]
|
||||||
[:div.is-clearfix
|
[:div.is-clearfix
|
||||||
[:p
|
[:p
|
||||||
(when-let [imported (:imported (:rows excel-import-data))]
|
(when imported
|
||||||
(str imported " rows imported."))]
|
(str imported " rows imported."))]
|
||||||
[:p
|
[:p
|
||||||
(when-let [already-imported (:already-imported (:rows excel-import-data))]
|
(when already-imported
|
||||||
(str already-imported " rows already imported."))]]
|
(str already-imported " rows already imported."))]]
|
||||||
(when-let [errors (:errors (:rows excel-import-data))]
|
(when-let [errors (:errors (:rows excel-import-data))]
|
||||||
|
|
||||||
[:div
|
[:div
|
||||||
[:h3 (str "Import errors (" (min 100 (count errors)) ")")]
|
[:h3 (str "Import errors (" (min 100 (count errors)) " / " (count errors) " )")]
|
||||||
[:table.table.is-fullwidth
|
[:table.table.is-fullwidth
|
||||||
[:thead
|
[:thead
|
||||||
[:th "Date"]
|
[:th "Date"]
|
||||||
@@ -95,11 +163,13 @@
|
|||||||
[:th "Vendor"]
|
[:th "Vendor"]
|
||||||
[:th "Amount"]
|
[:th "Amount"]
|
||||||
[:th "Errors"]]
|
[:th "Errors"]]
|
||||||
|
|
||||||
(for [{:keys [raw-date invoice-number company vendor-name amount] row-errors :errors} (take 100 errors)]
|
(for [{:keys [raw-date invoice-number company vendor-name amount] row-errors :errors} (take 100 errors)]
|
||||||
|
^{:key (str raw-date invoice-number company vendor-name amount)}
|
||||||
[:tr
|
[:tr
|
||||||
[:td raw-date]
|
[:td raw-date]
|
||||||
[:td invoice-number]
|
[:td invoice-number]
|
||||||
[:td company]
|
[:td company]
|
||||||
[:td vendor-name]
|
[:td vendor-name]
|
||||||
[:td amount]
|
[:td amount]
|
||||||
[:td (map #(vector :p (:info %)) row-errors)]])]])])])
|
[:td (map (fn [{:keys [info]}] ^{:key info} [:p info]) row-errors)]])]])])])
|
||||||
|
|||||||
@@ -34,6 +34,16 @@
|
|||||||
(assoc ::invoice-page (first (:invoice-page data)))
|
(assoc ::invoice-page (first (:invoice-page data)))
|
||||||
(assoc-in [:status :loading] false))))
|
(assoc-in [:status :loading] false))))
|
||||||
|
|
||||||
|
(re-frame/reg-event-db
|
||||||
|
::toggle-check
|
||||||
|
(fn [db [_ data]]
|
||||||
|
(update-in db [::invoice-page :checked] (fn [x]
|
||||||
|
|
||||||
|
(let [x (or x #{})]
|
||||||
|
(if (x data)
|
||||||
|
(disj x data)
|
||||||
|
(conj x data)))))))
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::invalidated
|
::invalidated
|
||||||
(fn [cofx [_ params]]
|
(fn [cofx [_ params]]
|
||||||
@@ -44,10 +54,16 @@
|
|||||||
(fn []
|
(fn []
|
||||||
[:div
|
[:div
|
||||||
[:h1.title "Unpaid invoices"]
|
[:h1.title "Unpaid invoices"]
|
||||||
|
[:div.is-pulled-right
|
||||||
|
[:button.button.is-primary "Print check(s)"]]
|
||||||
|
|
||||||
[invoice-table {:id :unpaid
|
[invoice-table {:id :unpaid
|
||||||
:params (re-frame/subscribe [::params])
|
:params (re-frame/subscribe [::params])
|
||||||
:invoice-page (re-frame/subscribe [::invoice-page])
|
:invoice-page (re-frame/subscribe [::invoice-page])
|
||||||
:status (re-frame/subscribe [::subs/status])
|
:status (re-frame/subscribe [::subs/status])
|
||||||
:on-params-change (fn [params]
|
:on-params-change (fn [params]
|
||||||
(re-frame/dispatch [::params-change params])) }]])
|
(re-frame/dispatch [::params-change params]))
|
||||||
|
:check-boxes true
|
||||||
|
:on-check-changed (fn [which]
|
||||||
|
(re-frame/dispatch [::toggle-check which]))}]])
|
||||||
{:component-will-mount #(re-frame/dispatch-sync [::params-change {}]) }))
|
{:component-will-mount #(re-frame/dispatch-sync [::params-change {}]) }))
|
||||||
|
|||||||
Reference in New Issue
Block a user