supports yodlee manual import.
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
[auto-ap.db.vendors :as vendors]
|
[auto-ap.db.vendors :as vendors]
|
||||||
[auto-ap.db.invoices :as invoices]
|
[auto-ap.db.invoices :as invoices]
|
||||||
[auto-ap.db.utils :refer [query]]
|
[auto-ap.db.utils :refer [query]]
|
||||||
|
[auto-ap.yodlee.import :refer [manual-import]]
|
||||||
[auto-ap.utils :refer [by]]
|
[auto-ap.utils :refer [by]]
|
||||||
[auto-ap.parse :as parse]
|
[auto-ap.parse :as parse]
|
||||||
[auto-ap.graphql.utils :refer [assert-admin]]
|
[auto-ap.graphql.utils :refer [assert-admin]]
|
||||||
@@ -48,12 +49,19 @@
|
|||||||
(defn parse-amount [i]
|
(defn parse-amount [i]
|
||||||
(try
|
(try
|
||||||
(Double/parseDouble (str/replace (or (second
|
(Double/parseDouble (str/replace (or (second
|
||||||
(re-matches #"[^0-9\.,]*([0-9\.,]+)[^0-9\.,]*" (:amount i)))
|
(re-matches #"[^0-9\.,\\-]*([0-9\.,\\-]+)[^0-9\.,]*" (:amount i)))
|
||||||
"0")
|
"0")
|
||||||
#"," ""))
|
#"," ""))
|
||||||
(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-account-id [i]
|
||||||
|
(try
|
||||||
|
(Integer/parseInt (second
|
||||||
|
(re-matches #"[^0-9,\\-]*([0-9,\\-]+)[^0-9,]*" (:account-id i))))
|
||||||
|
(catch Exception e
|
||||||
|
(throw (Exception. (str "Could not parse account from value '" (:account-id i) "'") e)))))
|
||||||
|
|
||||||
(defn parse-date [{:keys [raw-date]}]
|
(defn parse-date [{:keys [raw-date]}]
|
||||||
(try
|
(try
|
||||||
(parse/parse-value :clj-time "MM/dd/yyyy" raw-date)
|
(parse/parse-value :clj-time "MM/dd/yyyy" raw-date)
|
||||||
@@ -70,6 +78,41 @@
|
|||||||
|
|
||||||
(defroutes routes
|
(defroutes routes
|
||||||
(wrap-routes
|
(wrap-routes
|
||||||
|
(context "/" []
|
||||||
|
(context "/transactions" []
|
||||||
|
(POST "/batch-upload"
|
||||||
|
{{:keys [data company-id]} :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 :account-id]
|
||||||
|
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 :account-id parse-account-id))
|
||||||
|
(map (parse-or-error :date parse-date)))
|
||||||
|
|
||||||
|
raw-transactions (vec (->> rows
|
||||||
|
(filter #(not (seq (:errors %))) )
|
||||||
|
(map (fn [{:keys [description-original status high-level-category amount account-id]}]
|
||||||
|
{:description-original description-original
|
||||||
|
:status status
|
||||||
|
:high-level-category high-level-category
|
||||||
|
:amount amount
|
||||||
|
:account-id account-id}))))]
|
||||||
|
|
||||||
|
(manual-import raw-transactions company-id 1)
|
||||||
|
|
||||||
|
{:status 200
|
||||||
|
:body (pr-str {:status "success"})
|
||||||
|
:headers {"Content-Type" "application/edn"}}))
|
||||||
|
)
|
||||||
(context "/invoices" []
|
(context "/invoices" []
|
||||||
#_(POST "/upload"
|
#_(POST "/upload"
|
||||||
{{ files "file"} :params :as params}
|
{{ files "file"} :params :as params}
|
||||||
@@ -82,8 +125,8 @@
|
|||||||
:headers {"Content-Type" "application/edn"}}))
|
:headers {"Content-Type" "application/edn"}}))
|
||||||
|
|
||||||
(POST "/upload-integreat"
|
(POST "/upload-integreat"
|
||||||
{{:keys [excel-rows]} :edn-params identity :identity}
|
{{:keys [excel-rows]} :edn-params user :identity}
|
||||||
(assert-admin identity)
|
(assert-admin user)
|
||||||
(let [columns [:raw-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 (by :name (vendors/get-all))
|
all-vendors (by :name (vendors/get-all))
|
||||||
@@ -132,5 +175,5 @@
|
|||||||
:already-imported already-imported-count
|
:already-imported already-imported-count
|
||||||
:vendors-not-found vendors-not-found
|
: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"}}))))
|
||||||
wrap-secure))
|
wrap-secure))
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
(let [matching-checks (checks/get-graphql {:company-id company-id
|
(let [matching-checks (checks/get-graphql {:company-id company-id
|
||||||
:bank-account-id bank-account-id
|
:bank-account-id bank-account-id
|
||||||
:amount amount
|
:amount (- amount)
|
||||||
:status "pending"})]
|
:status "pending"})]
|
||||||
(if (= 1 (count matching-checks))
|
(if (= 1 (count matching-checks))
|
||||||
(:id (first matching-checks))
|
(:id (first matching-checks))
|
||||||
@@ -48,14 +48,19 @@
|
|||||||
description-simple :simple} :description
|
description-simple :simple} :description
|
||||||
{merchant-id :i
|
{merchant-id :i
|
||||||
merchant-name :name} :merchant
|
merchant-name :name} :merchant
|
||||||
|
base-type :baseType
|
||||||
type :type
|
type :type
|
||||||
status :status}
|
status :status}
|
||||||
transaction
|
transaction
|
||||||
|
amount (if (= "DEBIT" base-type)
|
||||||
|
(- amount)
|
||||||
|
amount)
|
||||||
check-number (extract-check-number transaction)
|
check-number (extract-check-number transaction)
|
||||||
company-id (yodlee-account-id->company account-id)
|
company-id (yodlee-account-id->company account-id)
|
||||||
bank-account-id (yodlee-account-id->bank-account-id account-id)
|
bank-account-id (yodlee-account-id->bank-account-id account-id)
|
||||||
check-id (transaction->check-id transaction check-number company-id bank-account-id amount)
|
check-id (transaction->check-id transaction check-number company-id bank-account-id amount)
|
||||||
]]
|
]]
|
||||||
|
(println transaction)
|
||||||
|
|
||||||
(try
|
(try
|
||||||
(transactions/upsert!
|
(transactions/upsert!
|
||||||
@@ -88,8 +93,9 @@
|
|||||||
|
|
||||||
(mapcat (fn [transaction-group]
|
(mapcat (fn [transaction-group]
|
||||||
(map
|
(map
|
||||||
(fn [index {:keys [date description-original high-level-category amount] :as transaction}]
|
(fn [index {:keys [date description-original high-level-category amount account-id] :as transaction}]
|
||||||
{:id (str date "-" description-original "-" amount "-" index)
|
{:id (str date "-" description-original "-" amount "-" index)
|
||||||
|
|
||||||
:date (time/unparse date "YYYY-MM-dd")
|
:date (time/unparse date "YYYY-MM-dd")
|
||||||
:amount {:amount amount}
|
:amount {:amount amount}
|
||||||
:description {:original description-original
|
:description {:original description-original
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
[:div {:class "navbar-end"}
|
[:div {:class "navbar-end"}
|
||||||
(if @user
|
(if @user
|
||||||
[:div {:class (str "navbar-item has-dropdown " (when (get-in @menu [:account :active?]) "is-active"))}
|
[:div {:class (str "navbar-item has-dropdown " (when (get-in @menu [:account :active?]) "is-active"))}
|
||||||
|
|
||||||
[:a {:class "navbar-link login" :on-click (fn [e] (re-frame/dispatch [::events/toggle-menu :account]))} (:name @user)]
|
[:a {:class "navbar-link login" :on-click (fn [e] (re-frame/dispatch [::events/toggle-menu :account]))} (:name @user)]
|
||||||
[:div {:class "navbar-dropdown"}
|
[:div {:class "navbar-dropdown"}
|
||||||
[:a {:class "navbar-item"} "My profile"]
|
[:a {:class "navbar-item"} "My profile"]
|
||||||
@@ -206,6 +207,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
||||||
[:div {:class "compose has-text-centered"}
|
[:div {:class "compose has-text-centered"}
|
||||||
[:a {:class "button is-danger is-block is-bold" :href (bidi/path-for routes/routes :index)
|
[:a {:class "button is-danger is-block is-bold" :href (bidi/path-for routes/routes :index)
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[goog.string :as gstring]
|
[goog.string :as gstring]
|
||||||
[auto-ap.views.components.sorter :refer [sorted-column]]
|
[auto-ap.views.components.sorter :refer [sorted-column]]
|
||||||
|
[auto-ap.views.components.modal :refer [action-modal]]
|
||||||
[auto-ap.views.components.paginator :refer [paginator]]
|
[auto-ap.views.components.paginator :refer [paginator]]
|
||||||
[auto-ap.events :as events]
|
[auto-ap.events :as events]
|
||||||
[auto-ap.views.utils :refer [dispatch-event date->str ]]
|
[auto-ap.views.utils :refer [dispatch-event date->str bind-field]]
|
||||||
[auto-ap.utils :refer [by]]
|
[auto-ap.utils :refer [by]]
|
||||||
[auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
|
[auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
|
||||||
[auto-ap.subs :as subs]))
|
[auto-ap.subs :as subs]))
|
||||||
@@ -135,19 +136,73 @@
|
|||||||
[:a.tag {:href (:s3-url check) :target "_new"} [:i.fa.fa-money-check] [:span.icon [:i.fa.fa-money]] (str " " (:check-number check) " (" (gstring/format "$%.2f" amount ) ")")])]
|
[:a.tag {:href (:s3-url check) :target "_new"} [:i.fa.fa-money-check] [:span.icon [:i.fa.fa-money]] (str " " (:check-number check) " (" (gstring/format "$%.2f" amount ) ")")])]
|
||||||
]))]]]))))
|
]))]]]))))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::manual-yodlee-import
|
||||||
|
(fn [{:keys [db]} _]
|
||||||
|
{:dispatch [::events/modal-status ::manual-yodlee-import {:visible? true}]
|
||||||
|
:db (assoc-in db [::manual-yodlee-import] {:company-id (:id @(re-frame/subscribe [::subs/company]))
|
||||||
|
:data ""})}))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
::manual-yodlee-import
|
||||||
|
(fn [db]
|
||||||
|
(-> db ::manual-yodlee-import)))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::manual-yodlee-import-completed
|
||||||
|
(fn [{:keys [db]} _]
|
||||||
|
{:dispatch [::events/modal-completed ::manual-yodlee-import]}))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::manual-yodlee-import-started
|
||||||
|
(fn [{:keys [db]} _]
|
||||||
|
(let [manual-yodlee-import (::manual-yodlee-import db)]
|
||||||
|
{:http {:token (:user db)
|
||||||
|
:method :post
|
||||||
|
:body (pr-str manual-yodlee-import)
|
||||||
|
:headers {"Content-Type" "application/edn"}
|
||||||
|
:uri (str "/api/transactions/batch-upload")
|
||||||
|
:on-success [::manual-yodlee-import-completed]
|
||||||
|
:on-error [::manual-yodlee-import-error]}})))
|
||||||
|
|
||||||
|
|
||||||
|
(defn manual-yodlee-import-modal []
|
||||||
|
(let [data @(re-frame/subscribe [::manual-yodlee-import])
|
||||||
|
change-event [::events/change-form [::manual-yodlee-import]]]
|
||||||
|
[action-modal {:id ::manual-yodlee-import
|
||||||
|
:title "Manual Yodlee Import"
|
||||||
|
:action-text "Import"
|
||||||
|
:save-event [::manual-yodlee-import-started]}
|
||||||
|
[:div.field
|
||||||
|
[:label.label
|
||||||
|
"Yodlee manual import table"]
|
||||||
|
[:div.control
|
||||||
|
[bind-field
|
||||||
|
[:textarea.textarea {:field [:data]
|
||||||
|
:event change-event
|
||||||
|
:subscription data}]]]]]))
|
||||||
|
|
||||||
(def transactions-page
|
(def transactions-page
|
||||||
|
|
||||||
(with-meta
|
(with-meta
|
||||||
(fn []
|
(fn []
|
||||||
(let [current-company @(re-frame/subscribe [::subs/company])]
|
(let [current-company @(re-frame/subscribe [::subs/company])
|
||||||
|
user @(re-frame/subscribe [::subs/user])]
|
||||||
[:div
|
[:div
|
||||||
[:h1.title "Transactions"]
|
[:h1.title "Transactions"]
|
||||||
|
(when (= "admin" (:role user))
|
||||||
|
[:div.is-pulled-right
|
||||||
|
[:button.button.is-danger {:disabled (if current-company
|
||||||
|
""
|
||||||
|
"disabled")
|
||||||
|
:on-click (dispatch-event [::manual-yodlee-import])}
|
||||||
|
"Manual Yodlee Import"]])
|
||||||
[transaction-table {:id :transactions
|
[transaction-table {:id :transactions
|
||||||
:params (re-frame/subscribe [::params])
|
:params (re-frame/subscribe [::params])
|
||||||
:transaction-page (re-frame/subscribe [::transaction-page])
|
:transaction-page (re-frame/subscribe [::transaction-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]))}]
|
||||||
|
[manual-yodlee-import-modal]]))
|
||||||
{: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