From d10b97e68e2e151fa7f8a5be5620af484d5d00ec Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Mon, 28 Jan 2019 17:40:22 -0800 Subject: [PATCH] reimplemented import --- src/clj/auto_ap/datomic.clj | 6 +--- src/clj/auto_ap/datomic/checks.clj | 3 ++ src/clj/auto_ap/datomic/invoices.clj | 5 +++ src/clj/auto_ap/datomic/migrate.clj | 3 ++ .../migrate/add_bank_account_codes.clj | 28 ++++++++++++++++ src/clj/auto_ap/datomic/transactions.clj | 5 +++ src/clj/auto_ap/graphql.clj | 4 +++ src/clj/auto_ap/graphql/clients.clj | 1 + src/clj/auto_ap/routes/exports.clj | 11 ++++--- src/clj/auto_ap/routes/invoices.clj | 23 ++++++------- src/cljc/auto_ap/entities/clients.cljc | 14 +++++++- src/cljs/auto_ap/events.cljs | 4 +-- .../auto_ap/views/pages/admin/clients.cljs | 32 +++++++++++++++---- 13 files changed, 107 insertions(+), 32 deletions(-) create mode 100644 src/clj/auto_ap/datomic/migrate/add_bank_account_codes.clj diff --git a/src/clj/auto_ap/datomic.clj b/src/clj/auto_ap/datomic.clj index 2822fdc8..cfea0651 100644 --- a/src/clj/auto_ap/datomic.clj +++ b/src/clj/auto_ap/datomic.clj @@ -214,8 +214,7 @@ :db/doc "Current check number"} {:db/ident :bank-account-type/check} - {:db/ident :bank-account-type/cash} - ]) + {:db/ident :bank-account-type/cash}]) (def invoice-schema [{:db/ident :invoice/original-id @@ -750,6 +749,3 @@ (defn migrate-users [conn] [(load-users (users/get-all))]) - - - diff --git a/src/clj/auto_ap/datomic/checks.clj b/src/clj/auto_ap/datomic/checks.clj index 2b2562ca..f1e5a7b1 100644 --- a/src/clj/auto_ap/datomic/checks.clj +++ b/src/clj/auto_ap/datomic/checks.clj @@ -38,6 +38,9 @@ (:client-id args) (add-arg '?client-id (:client-id args) '[?e :payment/client ?client-id]) + (:client-code args) (add-arg '?client-code (:client-code args) + '[?e :payment/client ?client-id] + '[?client-id :client/code ?client-code] ) (:vendor-id args) (add-arg '?vendor-id (:vendor-id args) '[?e :payment/vendor ?vendor-id]) (:original-id args) (add-arg '?original-id (cond-> (:original-id args) (string? (:original-id args)) Long/parseLong ) diff --git a/src/clj/auto_ap/datomic/invoices.clj b/src/clj/auto_ap/datomic/invoices.clj index 4bea7685..58932a42 100644 --- a/src/clj/auto_ap/datomic/invoices.clj +++ b/src/clj/auto_ap/datomic/invoices.clj @@ -19,6 +19,7 @@ {:invoice/vendor [:vendor/name :db/id]} {:invoice/status [:db/ident]} {:invoice-payment/_invoice [* {:invoice-payment/payment [* {:payment/status [*]} + {:payment/bank-account [*]} {:transaction/_payment [*]}]}]}])) (defn <-datomic [x] @@ -41,6 +42,10 @@ (:client-id args) (add-arg '?client-id (:client-id args) '[?e :invoice/client ?client-id]) + (:client-code args) (add-arg '?client-code (:client-code args) + '[?e :invoice/client ?client-id] + '[?client-id :client/code ?client-code]) + (:original-id args) (add-arg '?original-id (cond-> (:original-id args) (string? (:original-id args)) Long/parseLong ) '[?e :invoice/client ?c] '[?c :client/original-id ?original-id]) diff --git a/src/clj/auto_ap/datomic/migrate.clj b/src/clj/auto_ap/datomic/migrate.clj index fc730938..7f0441bc 100644 --- a/src/clj/auto_ap/datomic/migrate.clj +++ b/src/clj/auto_ap/datomic/migrate.clj @@ -2,6 +2,7 @@ (:require [auto-ap.datomic :refer [uri]] [datomic.api :as d] [auto-ap.datomic.migrate.add-client-codes :refer [add-client-codes]] + [auto-ap.datomic.migrate.add-bank-account-codes :refer [add-bank-account-codes]] [clojure.java.io :as io] [io.rkn.conformity :as c]) (:import [datomic Util]) @@ -50,6 +51,8 @@ :auto-ap/migrate-invoices-expense-accounts {:txes-fn 'auto-ap.datomic/migrate-invoices-expense-accounts :requires [:auto-ap/migrate-invoices-payments]} :auto-ap/migrate-transactions {:txes-fn 'auto-ap.datomic/migrate-transactions :requires [:auto-ap/migrate-invoices-expense-accounts]} :auto-ap/add-client-codes {:txes-fn 'auto-ap.datomic.migrate.add-client-codes/add-client-codes :requires [:auto-ap/migrate-transactions]} + :auto-ap/add-bank-account-codes-schema {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes-schema :requires [:auto-ap/add-client-codes]} + :auto-ap/add-bank-account-codes {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes :requires [:auto-ap/add-bank-account-codes-schema]} }] (println "Conforming database...") (println (c/ensure-conforms conn norms-map)) diff --git a/src/clj/auto_ap/datomic/migrate/add_bank_account_codes.clj b/src/clj/auto_ap/datomic/migrate/add_bank_account_codes.clj new file mode 100644 index 00000000..06e17c4e --- /dev/null +++ b/src/clj/auto_ap/datomic/migrate/add_bank_account_codes.clj @@ -0,0 +1,28 @@ +(ns auto-ap.datomic.migrate.add-bank-account-codes + (:require [datomic.api :as d] + [auto-ap.datomic :refer [uri]] + [clojure.string :as str])) + +(defn add-bank-account-codes-schema [conn] + [[{:db/ident :bank-account/code + :db/valueType :db.type/string + :db/unique :db.unique/identity + :db/cardinality :db.cardinality/one + :db/doc "A bank account's computer-friendly name"}]]) + + +(defn add-bank-account-codes [conn] + (let [db (d/db conn) + all-bank-accounts (d/query {:query {:find ['?b '?original-id '?client-code] + :in ['$] + :where ['[?c :client/code ?client-code] + '[?c :client/bank-accounts ?b] + '[?b :bank-account/original-id ?original-id]]} + :args [db]})] + [(mapv (fn [[bank-account-id bank-account-code client-code ]] + (let [[_ bank-account-code] (str/split bank-account-code #"-" )] + {:db/id bank-account-id + :bank-account/code (str client-code "-" bank-account-code)})) + all-bank-accounts)])) + +#_(add-bank-account-codes (d/connect uri)) diff --git a/src/clj/auto_ap/datomic/transactions.clj b/src/clj/auto_ap/datomic/transactions.clj index 16b29d4a..213a4ac0 100644 --- a/src/clj/auto_ap/datomic/transactions.clj +++ b/src/clj/auto_ap/datomic/transactions.clj @@ -84,6 +84,11 @@ :where ['[?e :transaction/client ?client-id]]} :args [(:client-id args)]}) + (:client-code args) + (merge-query {:query {:in ['?client-code] + :where ['[?e :transaction/client ?client-id] + '[?client-id :client/code ?client-code]]} + :args [(:client-code args)]}) (:original-id args) (merge-query {:query {:in ['?original-id] diff --git a/src/clj/auto_ap/graphql.clj b/src/clj/auto_ap/graphql.clj index b5d6b032..4eaedb63 100644 --- a/src/clj/auto_ap/graphql.clj +++ b/src/clj/auto_ap/graphql.clj @@ -53,6 +53,7 @@ {:fields {:id {:type :id } :type {:type :bank_account_type} :number {:type 'String} + :code {:type 'String} :check_number {:type 'Int} :name {:type 'String} :bank_code {:type 'String} @@ -214,12 +215,14 @@ :all_invoices {:type '(list :invoice) :args {:client_id {:type :id} + :client_code {:type 'String} :original_id {:type 'Int} :statuses {:type '(list String)}} :resolve :get-all-invoices} :all_payments {:type '(list :payment) :args {:client_id {:type :id} + :client_code {:type 'String} :original_id {:type 'Int} :statuses {:type '(list String)}} :resolve :get-all-payments} @@ -263,6 +266,7 @@ :bank_accounts {:type '(list :edit_bank_account)}}} :edit_bank_account {:fields {:id {:type :id } + :code {:type 'String} :type {:type :bank_account_type} :number {:type 'String} :check_number {:type 'Int} diff --git a/src/clj/auto_ap/graphql/clients.clj b/src/clj/auto_ap/graphql/clients.clj index 1b44ec34..7562d527 100644 --- a/src/clj/auto_ap/graphql/clients.clj +++ b/src/clj/auto_ap/graphql/clients.clj @@ -36,6 +36,7 @@ :client/bank-accounts (map #(remove-nils {:db/id (:id %) + :bank-account/code (:code %) :bank-account/bank-name (:bank_name %) :bank-account/bank-code (:bank_code %) :bank-account/routing (:routing %) diff --git a/src/clj/auto_ap/routes/exports.clj b/src/clj/auto_ap/routes/exports.clj index fba3bce1..8c3571f8 100644 --- a/src/clj/auto_ap/routes/exports.clj +++ b/src/clj/auto_ap/routes/exports.clj @@ -21,20 +21,21 @@ (GET "/invoices/export" {:keys [query-params identity] :as request} (assert-admin identity) (let [query [[:all_invoices - {:client-id (query-params "client") + {:client-code (query-params "client-code") :original-id (query-params "original")} [:id :total :outstanding-balance :invoice-number :date :status - [:payments [:amount [:payment [:check-number :memo [:bank_account [:id :number :bank-name :bank-code]]]]]] + [:payments [:amount [:payment [:check-number :memo [:bank_account [:id :name :number :bank-name :bank-code]]]]]] [:vendor [:name :id [:primary_contact [:name]] [:address [:street1 :city :state :zip]]]] [:expense_accounts [:amount :id :expense_account_id :location [:expense_account [:id :name [:parent [:id :name]]]]]] [:client [:name :id :locations]]]]] invoices (graphql/query identity (venia/graphql-query {:venia/queries (->graphql query)}))] - (list (:all-invoices (:data invoices))))) + + (doto (list (:all-invoices (:data invoices))) clojure.pprint/pprint))) (GET "/payments/export" {:keys [query-params identity]} (assert-admin identity) (let [query [[:all_payments - {:client-id (query-params "client") + {:client-code (query-params "client-code") :original-id (query-params "original")} [:id :check-number :amount :memo :date :status :type [:invoices [[:invoice [:id]] :amount]] @@ -54,7 +55,7 @@ (map <-graphql (d-vendors/get-graphql {}))) (GET "/transactions/export" {:keys [query-params identity]} (assert-admin identity) - (let [[transactions] (d-transactions/get-graphql {:client-id (Long/parseLong (query-params "client")) + (let [[transactions] (d-transactions/get-graphql {:client-code (query-params "client-code") #_#_:original-id (Integer/parseInt (query-params "original")) :limit Integer/MAX_VALUE}) transactions (map <-graphql transactions)] diff --git a/src/clj/auto_ap/routes/invoices.clj b/src/clj/auto_ap/routes/invoices.clj index 9d673d42..8d501ba2 100644 --- a/src/clj/auto_ap/routes/invoices.clj +++ b/src/clj/auto_ap/routes/invoices.clj @@ -72,12 +72,7 @@ (catch Exception e (throw (Exception. (str "Could not parse account from value '" (:bank-account-id i) "'") e))))) -(defn parse-client-id [i] - (try - (Long/parseLong (second - (re-matches #"[^0-9,\\-]*([0-9,\\-]+)[^0-9,]*" (:client-id i)))) - (catch Exception e - (throw (Exception. (str "Could not parse client from value '" (:client-id i) "'") e))))) + (defn parse-date [{:keys [raw-date]}] (try @@ -94,7 +89,7 @@ :details (str e)}))))) (defn parse-invoice-rows [excel-rows] - (let [columns [:raw-date :vendor-name :check :location :invoice-number :amount :client :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 :default-expense-account] 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)) @@ -154,29 +149,31 @@ (POST "/batch-upload" {{:keys [data]} :edn-params user :identity} (assert-admin user) - (let [columns [:status :raw-date :description-original :high-level-category nil nil :amount nil nil nil nil nil :bank-account-id :client-id] + (let [columns [:status :raw-date :description-original :high-level-category nil nil :amount nil nil nil nil nil :bank-account-code :client-code] + all-clients (d-clients/get-all) + all-bank-accounts (mapcat :client/bank-accounts all-clients) + all-clients (merge (by :client/code all-clients) (by :client/name all-clients)) + all-bank-accounts (merge (by :bank-account/code all-bank-accounts)) rows (->> (str/split data #"\n" ) (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 :bank-account-id parse-account-id)) - (map (parse-or-error :client-id parse-client-id)) (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-id status high-level-category amount bank-account-id date]}] + (map (fn [{:keys [description-original client-code status high-level-category amount bank-account-code date]}] {:description-original description-original :date date :status status :high-level-category high-level-category :amount amount - :client-id client-id - :bank-account-id bank-account-id}))))] + :client-id (:db/id (all-clients client-code)) + :bank-account-id (:db/id (all-bank-accounts bank-account-code))}))))] (manual-import raw-transactions) diff --git a/src/cljc/auto_ap/entities/clients.cljc b/src/cljc/auto_ap/entities/clients.cljc index 1b9e3022..f179ac0a 100644 --- a/src/cljc/auto_ap/entities/clients.cljc +++ b/src/cljc/auto_ap/entities/clients.cljc @@ -9,9 +9,20 @@ (s/def ::name ::shared/required-identifier) (s/def ::code (s/and ::shared/required-identifier - #(re-matches #"[A-Z0-9]+" %))) + #(re-matches #"[A-Z0-9\-]+" %))) (s/def ::address (s/nilable ::address/address)) +(s/def ::bank-name ::shared/required-identifier) +(s/def ::bank-code ::shared/required-identifier) +(s/def ::routing ::shared/required-identifier) +(s/def ::number ::shared/required-identifier) +(s/def ::type keyword?) +(s/def ::number string?) +(s/def ::yodlee-account-id string?) + +(s/def ::bank-account (s/keys :req-un [::code ::name ::bank-name ::bank-code ::routing ::number])) +(s/def ::bank-accounts (s/coll-of ::bank-account)) + (s/def ::location string?) (s/def ::locations (s/coll-of ::location)) @@ -23,6 +34,7 @@ :opt-un [::email ::address ::locations + ::bank-accounts ::id])) diff --git a/src/cljs/auto_ap/events.cljs b/src/cljs/auto_ap/events.cljs index 17449177..06c37f57 100644 --- a/src/cljs/auto_ap/events.cljs +++ b/src/cljs/auto_ap/events.cljs @@ -41,7 +41,7 @@ :graphql {:token token :query-obj {:venia/queries [[:client - [:id :name :code :email :locations [:bank-accounts [:id :number :check-number :name :type] ] + [:id :name :code :email :locations [:bank-accounts [:id :code :number :check-number :name :type] ] [:address [:street1 :street2 :city :state :zip]]]] [:vendor [:id :name :default-expense-account [:primary-contact [:name :phone :email :id]] [:secondary-contact [:id :name :phone :email]] :print-as :invoice-reminder-schedule :code]]]} @@ -64,7 +64,7 @@ (fn [{:keys [db]} [_ token user]] {:graphql {:token token :query-obj {:venia/queries [[:client - [:id :name :code [:address [:street1 :street2 :city :state :zip]] [:bank-accounts [:id :number :check-number :name :type]]]] + [:id :name :code [:address [:street1 :street2 :city :state :zip]] [:bank-accounts [:id :code :number :check-number :name :type]]]] [:vendor [:id :name :default-expense-account [:primary-contact [:name :phone :email :id]] [:secondary-contact [:id :name :phone :email]] :print-as :invoice-reminder-schedule :code]]]} diff --git a/src/cljs/auto_ap/views/pages/admin/clients.cljs b/src/cljs/auto_ap/views/pages/admin/clients.cljs index 2be74ac8..cd9e5bdf 100644 --- a/src/cljs/auto_ap/views/pages/admin/clients.cljs +++ b/src/cljs/auto_ap/views/pages/admin/clients.cljs @@ -3,6 +3,7 @@ [clojure.string :as str]) (:require [re-frame.core :as re-frame] [reagent.core :as reagent] + [clojure.spec.alpha :as s] [clojure.string :as str] [auto-ap.subs :as subs] [auto-ap.events :as events] @@ -40,7 +41,7 @@ (update :bank-accounts #(into % (map (fn [ba] (dissoc ba :is-new?)) (:new-bank-accounts edited-client)))) (dissoc :new-bank-accounts)) } - [:id :name :code [:address [:street1 :street2 :city :state :zip]] [:bank-accounts [:id :number :check-number :name]]] + [:id :name :code :email [:address [:street1 :street2 :city :state :zip]] [:bank-accounts [:id :number :check-number :name :code :bank-code :bank-name :routing]]] ]}]} :on-success [::save-complete] :on-error [::save-error]}}))) @@ -81,8 +82,10 @@ ::add-new-bank-account (fn [{:keys [db]} _] (let [client (:client @(re-frame/subscribe [::subs/admin])) + _ (println (s/explain-data ::entity/bank-account (:new-account client))) new-bank-account (:new-account client) new-bank-account (-> new-bank-account + (update :code #(str (:code client) "-" %)) (update :check-number #(if (seq %) (js/parseInt %) nil)) (update :yodlee-account-id #(if (seq %) (js/parseInt %) nil)) (assoc :is-new? true))] @@ -180,6 +183,18 @@ :event ::change :subscription editing-client}] [:h2.subtitle "Add account"] + [horizontal-field + [:label.label "Acct code"] + [:div.control + [:div.field.has-addons.is-extended + [:p.control [:a.button.is-static (:code editing-client) "-" ]] + [:p.control + [bind-field + [:input.input {:type "code" + :field [:new-account :code] + :spec ::entity/code + :event ::change + :subscription editing-client}]]]]]] [horizontal-field [:label.label "Bank"] @@ -240,7 +255,12 @@ :event ::change :subscription editing-client}]]] [:div.control - [:button.button.is-primary.is-pulled-right {:on-click (dispatch-event [::add-new-bank-account])} "Add"]]] + [:button.button.is-primary.is-pulled-right {:on-click (dispatch-event [::add-new-bank-account]) + :disabled (if (and (s/valid? ::entity/bank-account (:new-account editing-client)) + (not ((set (map :code (:bank-accounts editing-client))) + (str (:code editing-client) "-" (-> editing-client :new-account :code))))) + "" + "disabled")} "Add"]]] @@ -250,10 +270,10 @@ [:div.control [:ul - (for [{:keys [name number check-number id]} (:bank-accounts editing-client)] - ^{:key id} [:li name]) - (for [[index {:keys [name number check-number]}] (map vector (range) (:new-bank-accounts editing-client))] - ^{:key index} [:li [:strong "* " name] [:button.button {:on-click (dispatch-event [::remove-new-bank-account index])} [:span.icon [:i.fa.fa-times]]]])]]] + (for [{:keys [code name number check-number id]} (:bank-accounts editing-client)] + ^{:key id} [:li code ": " name]) + (for [[index {:keys [name code number check-number]}] (map vector (range) (:new-bank-accounts editing-client))] + ^{:key index} [:li [:strong "* " code ": " name] [:button.button {:on-click (dispatch-event [::remove-new-bank-account index])} [:span.icon [:i.fa.fa-times]]]])]]] (when (:saving? editing-client) [:div.is-overlay {:style {"backgroundColor" "rgba(150,150,150, 0.5)"}}])]))) )