tons of bug fixes

This commit is contained in:
Bryce Covert
2020-07-08 21:44:11 -07:00
parent 86f51f93e4
commit d120b7e810
18 changed files with 442 additions and 156 deletions

View File

@@ -44,9 +44,6 @@ proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
# Mitigate httpoxy attack (see README for details) # Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy ""; proxy_set_header Proxy "";
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
server { server {
server_name _; # This is just an invalid value which will never trigger on a real hostname. server_name _; # This is just an invalid value which will never trigger on a real hostname.
listen 80; listen 80;

View File

@@ -1,3 +1,7 @@
gzip on; gzip on;
gzip_types application/edn; gzip_types application/edn;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;

View File

@@ -1,4 +1,4 @@
(ns fixing-transactions-manually-imported-incorrectl) (ns auto-ap.yodlee.import)
;; This buffer is for Clojure experiments and evaluation. ;; This buffer is for Clojure experiments and evaluation.
@@ -14,15 +14,31 @@
(first all-ts) (first all-ts)
(def g (auto-ap.yodlee.import/get-existing)) (def g (auto-ap.yodlee.import/get-existing))
(map (first
:transaction/yodlee-merchant (let [all-bank-accounts (auto-ap.yodlee.import/get-all-bank-accounts)
(let [all-bank-accounts (get-all-bank-accounts)
transaction->bank-account (comp (by :bank-account/yodlee-account-id all-bank-accounts) :accountId) transaction->bank-account (comp (by :bank-account/yodlee-account-id all-bank-accounts) :accountId)
all-rules (tr/get-all)] all-rules (tr/get-all)]
(transactions->txs all-ts transaction->bank-account (rm/rule-applying-fn all-rules) (get-existing)))) (transactions->txs all-ts transaction->bank-account (rm/rule-applying-fn all-rules) (get-existing))))
(count g) (count g)
(with-open [writer (java.io.StringWriter.)]
(clojure.data.csv/write-csv writer
(->>
(let [all-bank-accounts (auto-ap.yodlee.import/get-all-bank-accounts)
all-clients (by :db/id (d-clients/get-all))
transaction->bank-account (comp (by :bank-account/yodlee-account-id all-bank-accounts) :accountId)
all-bank-accounts (by :db/id all-bank-accounts)
all-rules (tr/get-all)]
(->> (transactions->txs all-ts transaction->bank-account (rm/rule-applying-fn all-rules) (get-existing))
(map (fn [r]
[(:transaction/id r) (:transaction/amount r)
(coerce/to-date-time (:transaction/date r))
(:transaction/description-original r)
(:bank-account/code (all-bank-accounts (:transaction/bank-account r)))
(:client/code (all-clients (:transaction/client r)))]))))))
(println (.toString writer)))
(g (digest/sha-256 (str 2553824503))) (g (digest/sha-256 (str 2553824503)))
@@ -32,20 +48,117 @@
(with-open [writer (java.io.StringWriter.)] (with-open [writer (java.io.StringWriter.)]
(clojure.data.csv/write-csv writer (clojure.data.csv/write-csv writer
(->> (->>
(d/query {:query {:find ['?e] (d/query {:query {:find ['?e '?e2]
:in ['$] :in ['$]
:where ['[?e :transaction/id ?tid] :where ['[?e :transaction/id ?tid]
'[?e :transaction/date ?d] '[?e :transaction/date ?d]
'(not [?e :transaction/type])]} '[?e :transaction/type]
:args [(d/since (d/db (d/connect uri)) #inst "2020-06-01")]}) '[?e :transaction/bank-account ?ba]
(map first) '[?e2 :transaction/date ?d]
'[(not= ?e2 ?e)]
'[?e :transaction/amount ?a1]
'[?e2 :transaction/amount ?a2]
'[?e2 :transaction/bank-account ?ba]
'[(auto-ap.utils/dollars= ?a1 ?a2)]
'(not [?e2 :transaction/type])]}
:args [(d/since (d/db (d/connect uri)) #inst "2020-04-01")]})
vec vec
(d/pull-many (d/db (d/connect uri)) (map (fn [[e1 e2]]
[:db/id [
:transaction/date :transaction/id :transaction/amount (d/pull (d/db (d/connect uri))
:transaction/description-original [:db/id
{:transaction/client [:client/code]} :transaction/date :transaction/id :transaction/amount
{:transaction/bank-account [:bank-account/code]}]) :transaction/description-original
(map (fn [r] {:transaction/client [:client/code]}
[(:transaction/id r) (:db/id r) (:transaction/amount r) (coerce/to-date-time (:transaction/date r)) (:transaction/description-original r) (:bank-account/code (:transaction/bank-account r)) (:client/code (:transaction/client r))])))) {:transaction/bank-account [:bank-account/code]}]
e1)
(d/pull (d/db (d/connect uri))
[:db/id
:transaction/date :transaction/id :transaction/amount
:transaction/description-original
{:transaction/client [:client/code]}
{:transaction/bank-account [:bank-account/code]}]
e2)
]))
(map (fn [[r1 r2]]
[(:transaction/id r1)
(:db/id r1 )
(:transaction/amount r1)
(coerce/to-date-time (:transaction/date r1))
(:transaction/description-original r1)
(:bank-account/code (:transaction/bank-account r1))
(:client/code (:transaction/client r1))
(:transaction/id r2)
(:db/id r2)
(:transaction/amount r2)
(coerce/to-date-time (:transaction/date r2))
(:transaction/description-original r2)
(:bank-account/code (:transaction/bank-account r2))
(:client/code (:transaction/client r2))])))
)
(println (.toString writer))) (println (.toString writer)))
(def matches-to-repair2
(->>
(d/query {:query {:find ['?e '?e2]
:in ['$]
:where ['[?e :transaction/id ?tid]
'[?e :transaction/date ?d]
'[?e :transaction/type]
'[?e :transaction/bank-account ?ba]
'[?e2 :transaction/date ?d]
'[(not= ?e2 ?e)]
'[?e :transaction/amount ?a1]
'[?e2 :transaction/amount ?a2]
'[?e2 :transaction/bank-account ?ba]
'[(auto-ap.utils/dollars= ?a1 ?a2)]
'(not [?e2 :transaction/type])]}
:args [(d/since (d/db (d/connect uri)) #inst "2020-04-01")]})
vec
(map (fn [[e1 e2]]
[
(d/pull (d/db (d/connect uri))
[:db/id
:transaction/date :transaction/id :transaction/amount
:transaction/description-original
:transaction/approval-status
{:transaction/client [:client/code]}
{:transaction/bank-account [:bank-account/code]}
{:journal-entry/_original-entity ['*]}]
e1)
(d/pull (d/db (d/connect uri))
[:db/id
:transaction/date :transaction/id :transaction/amount
:transaction/description-original
:transaction/approval-status
{:transaction/client [:client/code]}
{:transaction/bank-account [:bank-account/code]}
{:journal-entry/_original-entity ['*]}]
e2)
]))
))
(count matches-to-repair2)
(defn repair-transaction [[t-auto t-manual]]
(into
[{:db/id "datomic.tx"
:db/doc "Deletes a transaction that was added manually and automatically"}
[:db/retractEntity (:db/id t-auto)]]
(mapv
(fn [j]
[:db/retractEntity (:db/id j)])
(:journal-entry/_original-entity t-auto))))
(defn map-new-transaction-id [[t-auto t-manual]]
[[:db/add (:db/id t-manual) :transaction/id (:transaction/id t-auto)]])
(map-new-transaction-id (first matches-to-repair))
(doseq [t matches-to-repair]
@(d/transact (d/connect uri) (map-new-transaction-id t)))

View File

@@ -33,8 +33,13 @@
(defmethod entity-change->ledger :invoice (defmethod entity-change->ledger :invoice
[db [type id]] [db [type id]]
(let [entity (d/pull db ['* {:invoice/vendor '[*] :invoice/payment '[*]}] id)] (let [entity (d/pull db ['* {:invoice/vendor '[*]
(when-not (= true (:invoice/exclude-from-ledger entity)) :invoice/payment '[*]
:invoice/status '[:db/ident]
:invoice/import-status '[:db/ident]}] id)]
(when-not (or (= true (:invoice/exclude-from-ledger entity))
(= :import-status/pending (:db/ident (:invoice/import-status entity)))
(= :invoice-status/voided (:db/ident (:invoice/status entity))))
(remove-nils (remove-nils
{:journal-entry/source "invoice" {:journal-entry/source "invoice"
:journal-entry/client (:db/id (:invoice/client entity)) :journal-entry/client (:db/id (:invoice/client entity))
@@ -157,3 +162,5 @@
#_(process-one (d/tx-report-queue (d/connect uri) )) #_(process-one (d/tx-report-queue (d/connect uri) ))
#_(process-all) #_(process-all)
#_(reset! break true)

View File

@@ -1,5 +1,6 @@
(ns auto-ap.parse.excel (ns auto-ap.parse.excel
(:require [auto-ap.parse.templates :as t] (:require [auto-ap.parse.templates :as t]
[auto-ap.parse.util :as u]
[clojure.string :as str] [clojure.string :as str]
[dk.ative.docjure.spreadsheet :as d]) [dk.ative.docjure.spreadsheet :as d])
(:import (org.apache.poi.ss.util CellAddress))) (:import (org.apache.poi.ss.util CellAddress)))
@@ -9,7 +10,7 @@
(defn template-applies? [text {:keys [keywords]}] (defn template-applies? [text {:keys [keywords]}]
(every? #(re-find % text) keywords)) (every? #(re-find % text) keywords))
(defn extract [wb {:keys [extract vendor]}] (defn extract [wb {:keys [extract vendor parser]}]
(if (fn? extract) (if (fn? extract)
(extract wb vendor) (extract wb vendor)
[(reduce-kv [(reduce-kv
@@ -24,11 +25,15 @@
(map (fn [cell] (map (fn [cell]
(let [address (.getAddress cell) (let [address (.getAddress cell)
cell-value (str (d/read-cell (d/select-cell (.toString (CellAddress. (+ offset-row (.getRow address)) (+ offset-column (.getColumn address)) )) cell-value (str (d/read-cell (d/select-cell (.toString (CellAddress. (+ offset-row (.getRow address)) (+ offset-column (.getColumn address)) ))
(first (d/sheet-seq wb)))))] (first (d/sheet-seq wb)))))
(if extract-regex raw-result (if extract-regex
(second (re-find extract-regex cell-value)) (second (re-find extract-regex cell-value))
cell-value)))) cell-value)]
(if (get parser k)
(u/parse-value (first (get parser k) ) (second (get parser k) ) raw-result)
raw-result
))))
first))) first)))
{:vendor-code vendor} {:vendor-code vendor}
extract)])) extract)]))

View File

@@ -271,7 +271,7 @@
;; PACIFIC SEAFOOD ;; PACIFIC SEAFOOD
{:vendor "Pacific Seafood" {:vendor "Pacific Seafood"
:keywords [#"pacseafood"] :keywords [#"(pacseafood|PACIFIC FRESH)"]
:extract {:date #"DATE(?:.*\n.*(?=([0-9]+/[0-9]+/[0-9]+)))([0-9]+/[0-9]+/[0-9]+)" :extract {:date #"DATE(?:.*\n.*(?=([0-9]+/[0-9]+/[0-9]+)))([0-9]+/[0-9]+/[0-9]+)"
:customer-identifier #"DELIVER TO:(?:.*\n)(.*?)(?=\s{2})" :customer-identifier #"DELIVER TO:(?:.*\n)(.*?)(?=\s{2})"
:invoice-number #"INVOICE NO\.\n(?:.*?(?= [0-9]+\n)) ([0-9]+)" :invoice-number #"INVOICE NO\.\n(?:.*?(?= [0-9]+\n)) ([0-9]+)"
@@ -439,12 +439,15 @@
:total [#"PAY THIS" -1 0] :total [#"PAY THIS" -1 0]
:date [#"INVOICE DATE" 0 1] :date [#"INVOICE DATE" 0 1]
:invoice-number [#"INVOICE NUMBER" 0 1]}} :invoice-number [#"INVOICE NUMBER" 0 1]}}
{:vendor "SWO" {:vendor "Southern Glazers"
:keywords [#"Please note that the total invoice amount may"] :keywords [#"Please note that the total invoice amount may"]
:extract {:customer-identifier [#"Customer #" 1 0] :extract {:customer-identifier [#"Customer #" 1 0]
:total [#"Total Invoice" 0 5] :total [#"Subtotal" 0 16 ]
:date [#"Date" 0 0 #"Date: (.*)"] :date [#"Date" 0 0 #"Date: (.*)"]
:invoice-number [#"Invoice #" 0 0 #"Invoice #: (.*)"]}} :invoice-number [#"Invoice #" 0 0 #"Invoice #: (.*)"]
:account-number [#"Customer #" 0 0 #"Customer #: (.*)"]}
:parser { :total [:trim-commas-and-remove-dollars nil]
:date [:clj-time "MM/dd/yyyy"]}}
{:vendor "Mama Lu's Foods" {:vendor "Mama Lu's Foods"
:keywords [#"Mama Lu's Foods"] :keywords [#"Mama Lu's Foods"]
:extract (fn [wb vendor] :extract (fn [wb vendor]

View File

@@ -13,6 +13,9 @@
[_ _ value] [_ _ value]
(str/replace value #"," "") (str/replace value #"," "")
) )
(defmethod parse-value :trim-commas-and-remove-dollars
[_ _ value]
(str/replace (str/replace value #"," "") #"\$" ""))
(defmethod parse-value :trim-commas-and-negate (defmethod parse-value :trim-commas-and-negate
[_ _ value] [_ _ value]

View File

@@ -42,7 +42,7 @@
(let [[session token] (yodlee/get-access-token)] (let [[session token] (yodlee/get-access-token)]
{:status 200 {:status 200
:headers {"Content-Type" "application/edn"} :headers {"Content-Type" "application/edn"}
:body (pr-str (yodlee/get-provider-accounts-with-accounts)) })) :body (pr-str @yodlee/in-memory-cache) }))
(POST "/reauthenticate/:id" {:keys [query-params identity] {:keys [id]} :route-params (POST "/reauthenticate/:id" {:keys [query-params identity] {:keys [id]} :route-params
data :edn-params data :edn-params
:as request} :as request}
@@ -53,6 +53,7 @@
:headers {"Content-Type" "application/edn"} :headers {"Content-Type" "application/edn"}
:body (pr-str (yodlee/reauthenticate (Long/parseLong id) data)) }) :body (pr-str (yodlee/reauthenticate (Long/parseLong id) data)) })
(catch Exception e (catch Exception e
(println e)
{:status 500 {:status 500
:headers {"Content-Type" "application/edn"} :headers {"Content-Type" "application/edn"}
:body (pr-str {:message (.getMessage e) :body (pr-str {:message (.getMessage e)

View File

@@ -2,6 +2,7 @@
(:require #_[auto-ap.background.mail :refer [always-process-sqs]] (:require #_[auto-ap.background.mail :refer [always-process-sqs]]
[auto-ap.handler :refer [app]] [auto-ap.handler :refer [app]]
[auto-ap.ledger :refer [process-all]] [auto-ap.ledger :refer [process-all]]
[auto-ap.yodlee.core :refer [load-in-memory-cache]]
[nrepl.server :refer [start-server stop-server]] [nrepl.server :refer [start-server stop-server]]
[config.core :refer [env]] [config.core :refer [env]]
[ring.adapter.jetty :refer [run-jetty]]) [ring.adapter.jetty :refer [run-jetty]])
@@ -15,5 +16,6 @@
(start-server :port 9000 :bind "0.0.0.0" #_#_:handler (cider-nrepl-handler)) (start-server :port 9000 :bind "0.0.0.0" #_#_:handler (cider-nrepl-handler))
(let [port (Integer/parseInt (or (env :port) "3000"))] (let [port (Integer/parseInt (or (env :port) "3000"))]
(future (process-all)) (future (process-all))
(future (load-in-memory-cache))
#_(future (always-process-sqs)) #_(future (always-process-sqs))
(run-jetty app {:port port :join? false}))) (run-jetty app {:port port :join? false})))

View File

@@ -157,20 +157,9 @@
:as :json})))) :as :json}))))
(defn reauthenticate [pa data]
(let [cob-session (login-cobrand)
user-session (login-user cob-session)
batch-size 100]
(-> (str (:yodlee-base-url env) "/providerAccounts?providerAccountIds=" pa)
(client/put {:headers (merge base-headers {"Authorization" (auth-header cob-session user-session)})
:body (json/write-str data)
:as :json}))))
(defn update-yodlee [id]
(update-provider-account id)
(get-provider-account id))
(defn get-specific-transactions [account] (defn get-specific-transactions [account]
(let [cob-session (login-cobrand) (let [cob-session (login-cobrand)
@@ -255,6 +244,41 @@
(update-in provider-accounts [(:providerAccountId a) :accounts] conj a)) provider-accounts) (update-in provider-accounts [(:providerAccountId a) :accounts] conj a)) provider-accounts)
vals))) vals)))
(defonce in-memory-cache (atom []))
(defn load-in-memory-cache []
(future
(loop []
(try
(reset! in-memory-cache (get-provider-accounts-with-accounts))
(catch Exception e
(println e)))
(Thread/sleep (* 60 * 1000 * 5))
(recur))))
(defn refresh-provider-account [id]
(swap! in-memory-cache
(fn [i]
(-> (by :id i)
(update id merge (get-provider-account-detail id))
vals))))
(defn update-yodlee [id]
(update-provider-account id)
(refresh-provider-account id)
)
(defn reauthenticate [pa data]
(let [cob-session (login-cobrand)
user-session (login-user cob-session)
batch-size 100]
(-> (str (:yodlee-base-url env) "/providerAccounts?providerAccountIds=" pa)
(client/put {:headers (merge base-headers {"Authorization" (auth-header cob-session user-session)})
:body (json/write-str data)
:as :json}))
(refresh-provider-account pa)))
#_(defn get-users [] #_(defn get-users []
(let [cob-session (login-cobrand)] (let [cob-session (login-cobrand)]
(-> "https://developer.api.yodlee.com/ysl/user" (-> "https://developer.api.yodlee.com/ysl/user"

View File

@@ -224,8 +224,6 @@
txes (transduce txes (transduce
(comp (comp
(mapcat (fn parse-map [[account account-name override-name _ type]] (mapcat (fn parse-map [[account account-name override-name _ type]]
(let [code (some-> account (let [code (some-> account
not-empty not-empty
@@ -277,3 +275,28 @@
[{:db/id [:client/code client-code] [{:db/id [:client/code client-code]
:client/signature-file (str "https://s3.amazonaws.com/integreat-signature-images/" filename)}])) :client/signature-file (str "https://s3.amazonaws.com/integreat-signature-images/" filename)}]))
(defn fix-transactions-without-locations [client-code location]
(->>
(d/query {:query {:find ['(pull ?e [*])]
:in ['$ '?client-code]
:where ['[?e :transaction/accounts ?ta]
'[?e :transaction/matched-rule]
'[?e :transaction/approval-status :transaction-approval-status/approved]
'(not [?ta :transaction-account/location])
'[?e :transaction/client ?c]
'[?c :client/code ?client-code]
]}
:args [(d/db (d/connect uri)) client-code]})
(mapcat
(fn [[{:transaction/keys [accounts]}]]
(mapv
(fn [a]
{:db/id (:db/id a)
:transaction-account/location location}
)
accounts)
)
)
vec))

View File

@@ -5,6 +5,9 @@
(s/def ::account map?) (s/def ::account map?)
(s/def ::location (s/and string?
not-empty))
(s/def ::transaction-rule-account (s/keys :req-un [::account] (s/def ::transaction-rule-account (s/keys :req-un [::account
::location]
:opt-un [])) :opt-un []))

View File

@@ -143,7 +143,7 @@
(defn vertical-form [{:keys [can-submit id change-event submit-event ]}] (defn vertical-form [{:keys [can-submit id change-event submit-event ]}]
{:form ^{:key "form"} {:form
(fn [{:keys [title] :as params} & children] (fn [{:keys [title] :as params} & children]
(let [{:keys [data active? error]} @(re-frame/subscribe [::form id]) (let [{:keys [data active? error]} @(re-frame/subscribe [::form id])
can-submit @(re-frame/subscribe can-submit)] can-submit @(re-frame/subscribe can-submit)]
@@ -157,6 +157,20 @@
[:h1.title.is-2 title] [:h1.title.is-2 title]
[:<> [:<>
children]])) children]]))
:form-inline
(fn [{:keys [title] :as params} children]
(let [{:keys [data active? error]} @(re-frame/subscribe [::form id])
can-submit @(re-frame/subscribe can-submit)]
[:form { :on-submit (fn [e]
(when (.-stopPropagation e)
(.stopPropagation e)
(.preventDefault e))
(when can-submit
(re-frame/dispatch-sync (vec (conj submit-event params)))))}
[:h1.title.is-2 title]
children]))
:raw-field (fn [control] :raw-field (fn [control]
(let [{:keys [data]} @(re-frame/subscribe [::form id])] (let [{:keys [data]} @(re-frame/subscribe [::form id])]
[bind-field (-> control [bind-field (-> control

View File

@@ -4,7 +4,7 @@
[clojure.string :as str])) [clojure.string :as str]))
(defn get-valid-matches [matches not-found-description not-found-value text] (defn get-valid-matches [matches not-found-description not-found-value text]
(let [valid-matches (take 5 (for [[[id t :as match] i] (map vector matches (range)) (let [valid-matches (take 15 (for [[[id t :as match] i] (map vector matches (range))
:when (str/includes? (or (some-> t .toLowerCase) "") (or (some-> text .toLowerCase) ""))] :when (str/includes? (or (some-> t .toLowerCase) "") (or (some-> text .toLowerCase) ""))]
match)) match))
valid-matches (if (and not-found-description text) valid-matches (if (and not-found-description text)
@@ -111,10 +111,14 @@
nil)]))}))) nil)]))})))
(defn get-valid-entity-matches [matches not-found-description not-found-value text match->text] (defn get-valid-entity-matches [matches not-found-description not-found-value text match->text]
(let [valid-matches (take 5 (for [[match i] (map vector matches (range)) (let [valid-matches (->> (for [[match i] (map vector matches (range))
:let [t (match->text match)] :let [t (match->text match)
:when (str/includes? (or (some-> t .toLowerCase) "") (or (some-> text .toLowerCase) ""))] match-index (str/index-of (or (some-> t .toLowerCase) "") (or (some-> text .toLowerCase) ""))]
match)) :when match-index]
[match match-index ])
(sort-by second)
(map first)
(take 10))
valid-matches (if (and not-found-description text) valid-matches (if (and not-found-description text)
(concat valid-matches [[:not-found (not-found-description text) (not-found-value text)]]) (concat valid-matches [[:not-found (not-found-description text) (not-found-value text)]])
valid-matches)] valid-matches)]

View File

@@ -5,6 +5,7 @@
[reagent.core :as reagent] [reagent.core :as reagent]
[clojure.string :as str] [clojure.string :as str]
[cljs-time.format :as f] [cljs-time.format :as f]
[cljs-time.core :as time]
[auto-ap.subs :as subs] [auto-ap.subs :as subs]
[auto-ap.events.admin.clients :as events] [auto-ap.events.admin.clients :as events]
[auto-ap.entities.clients :as entity] [auto-ap.entities.clients :as entity]
@@ -70,8 +71,9 @@
(fn [{:keys [db]} _] (fn [{:keys [db]} _]
{:db (-> db {:db (-> db
(assoc ::yodlee {:provider-accounts-loading? true}) (assoc ::yodlee {:provider-accounts-loading? true})
#_(assoc ::provider-accounts []) (assoc ::save-error nil)
#_(assoc ::provider-accounts-loading? true)) (assoc ::provider-accounts [])
(assoc ::provider-accounts-loading? true))
:http {:token (:user db) :http {:token (:user db)
:method :get :method :get
:headers {"Content-Type" "application/edn"} :headers {"Content-Type" "application/edn"}
@@ -121,7 +123,7 @@
(re-frame/reg-event-fx (re-frame/reg-event-fx
::save-error ::save-error
(fn [{:keys [db]} [_ authentication]] (fn [{:keys [db]} [_ authentication]]
{:dispatch [::mounted]})) {:db (assoc :db ::load-error "error")}))
(defn yodlee-link-button [] (defn yodlee-link-button []
[:div [:div
@@ -149,6 +151,14 @@
[:button.button.is-primary {:class (if loading? "is-loading" "") :on-click (dispatch-event [::authenticate-with-yodlee])} "Authenticate with Yodlee"]))]) [:button.button.is-primary {:class (if loading? "is-loading" "") :on-click (dispatch-event [::authenticate-with-yodlee])} "Authenticate with Yodlee"]))])
(defn yodlee-date->date [d]
(try
(some-> d
(str->date (:date-time-no-ms f/formatters))
)
(catch js/Error e
nil)))
(defn yodlee-date->str [d] (defn yodlee-date->str [d]
(try (try
(or (some-> d (or (some-> d
@@ -209,11 +219,16 @@
:uri (str "/api/yodlee/reauthenticate/" provider-account-id ) :uri (str "/api/yodlee/reauthenticate/" provider-account-id )
:body {"loginForm" :body {"loginForm"
{"row" {"row"
[{"field" (->> (get-in db [::forms/forms [::login-form provider-account-id]])
(mapv (fn [[k v]] :data
{"id" k (sort-by (fn [[k v]] k))
"value" v}) (map second)
(:data (get-in db [::forms/forms [::login-form provider-account-id]])))}]}} (map (fn [row]
{"field"
(mapv (fn [[k v]]
{"id" k
"value" v})
row)})))}}
:on-success [::authenticated] :on-success [::authenticated]
:on-error [::forms/save-error [::login-form provider-account-id]]}})) :on-error [::forms/save-error [::login-form provider-account-id]]}}))
@@ -233,57 +248,73 @@
[:div.card-header-title "Provider account " (:id account) [:div.card-header-title "Provider account " (:id account)
]] ]]
[:div.card-content [:div.card-content
[:div.notification.is-info.is-light
[:div.level
[:div.level-left
[:div.level-item
[:p
"This account was last updated on "
(yodlee-date->str (-> account :dataset first :lastUpdated))
", and last attempted "
(yodlee-date->str (-> account :dataset first :lastUpdateAttempt))
"."]]]
[:div.level-right [:button.button.is-success {:on-click (dispatch-event [::kick (:id account)] )} "Force refresh" ]]]
] (if (> (some-> (-> account :dataset first :lastUpdated)
[:div.notification.is-info.is-warning (yodlee-date->date )
[:div.level (time/interval (time/now))
[:div.level-left (time/in-days ))
[:div.level-item 1)
"This provider account's status is '" [:div.notification.is-info.is-light
(-> account :dataset first :additionalStatus) [:div.level
"'. If this is in error, it might help to try reauthenticating by filling out the form below."]]]] [:div.level-left
[:div.level-item
[:p
"This account was last updated on "
(yodlee-date->str (-> account :dataset first :lastUpdated))
", and last attempted "
(yodlee-date->str (-> account :dataset first :lastUpdateAttempt))
"."]]]
[:div.level-right [:button.button.is-success {:on-click (dispatch-event [::kick (:id account)] )} "Force refresh" ]]]
])
[yodlee-accounts-table (:accounts account)] [yodlee-accounts-table (:accounts account)]
[:div (if (not= (-> account :dataset first :additionalStatus)
(if (:field account) "AVAILABLE_DATA_RETRIEVED")
(for [f (:field account)] [:div
(let [{error :error account-data :data } @(re-frame/subscribe [::forms/form [::mfa-form (:id account)]]) [:div.notification.is-info.is-warning
change-event [::forms/change [::mfa-form (:id account)]] [:div.level
{:keys [form field field-holder raw-field error-notification submit-button]} (forms/vertical-form {:can-submit [::can-submit] [:div.level-left
:change-event change-event [:div.level-item
:submit-event [::reauthenticate-mfa (:id account)] "This provider account's status is '"
:id [::mfa-form (:id account)]} )] (-> account :dataset first :additionalStatus)
(form {:title "Reauthenticate (login)"} "'. If this is in error, it might help to try reauthenticating by filling out the form below."]]]]
(if (:field account)
(for [f (:field account)]
(let [{error :error account-data :data } @(re-frame/subscribe [::forms/form [::mfa-form (:id account)]])
change-event [::forms/change [::mfa-form (:id account)]]
{:keys [form-inline field field-holder raw-field error-notification submit-button]} (forms/vertical-form {:can-submit [::can-submit]
:change-event change-event
:submit-event [::reauthenticate-mfa (:id account)]
:id [::mfa-form (:id account)]} )]
(form-inline {:title "Reauthenticate (mfa)"}
[:<>
(error-notification)
(doall
(for [f (-> account :field)]
^{:key (:id f)}
(field (:label f)
[:input.input {:type "text" :field [(:id f)] :value (-> f :field first :value)}])))
(submit-button "Reauthenticate")])))
(let [{error :error account-data :data } @(re-frame/subscribe [::forms/form [::login-form (:id account)]])
change-event [::forms/change [::login-form (:id account)]]
{:keys [form-inline field field-holder raw-field error-notification submit-button]} (forms/vertical-form {:can-submit [::can-submit]
:change-event change-event
:submit-event [::reauthenticate (:id account)]
:id [::login-form (:id account)]} )]
(form-inline {:title "Reauthenticate (login)"}
[:<>
(error-notification) (error-notification)
(for [f (-> account :field)] (doall
^{:key (:id f)} (for [[row i] (map vector (-> account :loginForm last :row) (range))
(field (:label f) f (:field row)]
[:input.input {:type "text" :field [(:id f)] :value (-> f :field first :value)}])) ^{:key (:id f)}
(submit-button "Reauthenticate")))) [:div
(let [{error :error account-data :data } @(re-frame/subscribe [::forms/form [::login-form (:id account)]]) (field (:label row)
change-event [::forms/change [::login-form (:id account)]] [:input.input {:type "text" :field [i (:id f)]}])]))
{:keys [form field field-holder raw-field error-notification submit-button]} (forms/vertical-form {:can-submit [::can-submit] (submit-button "Reauthenticate")])))])]]))]]))
:change-event change-event
:submit-event [::reauthenticate (:id account)]
:id [::login-form (:id account)]} )]
(form {:title "Reauthenticate (MFA)"}
(error-notification)
(for [f (-> account :loginForm first :row)]
^{:key (:id f)}
(field (:label f)
[:input.input {:type "text" :field [(:id f)] :value (-> f :field first :value)}]))
(submit-button "Reauthenticate"))))]]]))]]))
(defn admin-yodlee-content [] (defn admin-yodlee-content []

View File

@@ -184,7 +184,6 @@
(re-frame/reg-event-fx (re-frame/reg-event-fx
::succeeded ::succeeded
[(forms/triggers-stop ::form)]
(fn [{:keys [db]} [_ {:keys [invoice-created invoice-printed]} command result]] (fn [{:keys [db]} [_ {:keys [invoice-created invoice-printed]} command result]]
(let [invoice (condp = command (let [invoice (condp = command
:edit (:edit-invoice result) :edit (:edit-invoice result)
@@ -192,11 +191,13 @@
:create (:add-invoice result) :create (:add-invoice result)
:add-and-print (first (:invoices (:add-and-print-invoice result))))] :add-and-print (first (:invoices (:add-and-print-invoice result))))]
{:db (cond-> db {:db (cond-> db
(#{:create :add-and-print} command) (forms/start-form ::form {:client @(re-frame/subscribe [::subs/client]) (#{:create :add-and-print} command) (forms/start-form ::form {:client @(re-frame/subscribe [::subs/client])
:status :unpaid :status :unpaid
:date (date->str (c/now) standard)})) :date (date->str (c/now) standard)})
(= :edit command) (forms/stop-form ::form))
:dispatch-n (cond-> [(conj invoice-created invoice)] :dispatch-n (cond-> [(conj invoice-created invoice)]
(= :add-and-print command) (conj (conj invoice-printed (:pdf-url (:add-and-print-invoice result)))))}))) (= :add-and-print command) (conj (conj invoice-printed (:pdf-url (:add-and-print-invoice result)))))})))

View File

@@ -1,11 +1,12 @@
(ns auto-ap.views.pages.ledger.profit-and-loss (ns auto-ap.views.pages.ledger.profit-and-loss
(:require [auto-ap.subs :as subs] (:require [auto-ap.subs :as subs]
[auto-ap.views.components.layouts :refer [side-bar-layout appearing-side-bar]] [auto-ap.views.components.layouts :refer [side-bar-layout appearing-side-bar]]
[auto-ap.views.pages.ledger.table :refer [table]] [auto-ap.views.pages.ledger.table :as ledger-table ]
[vimsical.re-frame.cofx.inject :as inject]
[goog.string :as gstring] [goog.string :as gstring]
[auto-ap.utils :refer [dollars-0? by ]] [auto-ap.utils :refer [dollars-0? by ]]
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]] [auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
[auto-ap.views.utils :refer [date->str date-picker bind-field standard dispatch-event local-now ->% ->$ str->date]] [auto-ap.views.utils :refer [date->str date-picker bind-field standard dispatch-event local-now ->% ->$ str->date with-user]]
[cljs-time.core :as t] [cljs-time.core :as t]
[re-frame.core :as re-frame])) [re-frame.core :as re-frame]))
(def ranges (def ranges
@@ -67,9 +68,29 @@
(-> db ::ledger-list :ledger-page))) (-> db ::ledger-list :ledger-page)))
(re-frame/reg-sub (re-frame/reg-sub
::ledger-params ::last-ledger-params
(fn [db] (fn [db]
(-> db (::ledger-params {}) ))) (-> db ::last-ledger-params )))
(re-frame/reg-sub
::investigate-ledger-params
(fn [db]
(-> db ::investigate-ledger-params )))
(re-frame/reg-sub
::ledger-params
:<- [::last-ledger-params]
:<- [::subs/client]
:<- [::ledger-table/table-params]
:<- [::investigate-ledger-params]
(fn [[last-params client table-params investigate-ledger-params]]
(let [params (cond-> {}
client (assoc :client-id (:id client))
(seq table-params) (merge table-params)
(seq investigate-ledger-params) (merge investigate-ledger-params))]
(when (not= params last-params)
(re-frame/dispatch [::ledger-params-changed]))
params)))
(re-frame/reg-sub (re-frame/reg-sub
::accounts ::accounts
@@ -200,6 +221,8 @@
(re-frame/reg-event-fx (re-frame/reg-event-fx
::date-picked ::date-picked
(fn [cofx [_ f date]] (fn [cofx [_ f date]]
@@ -218,14 +241,15 @@
(re-frame/reg-event-fx (re-frame/reg-event-fx
::ledger-params-changed ::ledger-params-changed
(fn [{:keys [db]} [_ params]] [with-user (re-frame/inject-cofx ::inject/sub [::ledger-params])]
(fn [{:keys [user ::ledger-params db]} [_ ]]
{:db (assoc db {:db (assoc db
::ledger-list-loading true ::ledger-list-loading true
::ledger-params params) ::last-ledger-params ledger-params)
:graphql {:token (-> db :user) :graphql {:token user
:query-obj {:venia/queries [[:ledger-page :query-obj {:venia/queries [[:ledger-page
params ledger-params
[[:journal-entries [:id [[:journal-entries [:id
:source :source
:amount :amount
@@ -242,26 +266,25 @@
:end]]]} :end]]]}
:on-success [::ledger-list-received]}})) :on-success [::ledger-list-received]}}))
(re-frame/reg-event-fx (re-frame/reg-event-db
::investigate-clicked ::investigate-clicked
(fn [{:keys [db] } [_ location from-numeric-code to-numeric-code which]] (fn [db [_ location from-numeric-code to-numeric-code which]]
{:db (assoc db (-> db
::ledger-list-active? true (assoc
::ledger-list-loading true) ::ledger-list-active? true
::ledger-list-loading true
:dispatch [::ledger-params-changed (assoc (::ledger-params db) ::investigate-ledger-params {:client-id (:id @(re-frame/subscribe [::subs/client]))
:client-id (:id @(re-frame/subscribe [::subs/client])) :from-numeric-code from-numeric-code
:from-numeric-code from-numeric-code :to-numeric-code to-numeric-code
:to-numeric-code to-numeric-code :location location
:location location :date-range {:start (if (= :current which)
:date-range {:start (if (= :current which) (:from-date (::params db))
(:from-date (::params db)) (date->str (t/minus (str->date (:from-date (::params db)) standard) (t/years 1))
(date->str (t/minus (str->date (:from-date (::params db)) standard) (t/years 1)) standard))
standard)) :end (if (= :current which)
:end (if (= :current which) (:to-date (::params db))
(:to-date (::params db)) (date->str (t/minus (str->date (:to-date (::params db)) standard) (t/years 1))
(date->str (t/minus (str->date (:to-date (::params db)) standard) (t/years 1)) standard))}}))))
standard))})]}))
(def groupings (def groupings
{:sales [["40000-43999 Food Sales " 40000 43999] {:sales [["40000-43999 Food Sales " 40000 43999]
@@ -625,17 +648,18 @@
[:div [:a.delete.is-pulled-right {:on-click (dispatch-event [::ledger-list-closing])}] [:div [:a.delete.is-pulled-right {:on-click (dispatch-event [::ledger-list-closing])}]
[:div [:div
[:h1.title "Ledger entries"] [:h1.title "Ledger entries"]
[table {:id :ledger [ledger-table/table {:id :ledger
:ledger-page ledger-page :ledger-page ledger-page
:status? false :status? false
:status (re-frame/subscribe [::ledger-list-loading]) :status (re-frame/subscribe [::ledger-list-loading])
:params (re-frame/subscribe [::ledger-params]) :params (re-frame/subscribe [::ledger-params])
:on-params-change (fn [params] :on-params-change (fn [params]
(re-frame/dispatch [::ledger-params-changed params]))}]]])) (re-frame/dispatch [::ledger-params-changed params]))}]]]))
(defn profit-and-loss-page [] (defn profit-and-loss-page []
(let [ledger-list-active? @(re-frame/subscribe [::ledger-list-active?]) (let [ledger-list-active? @(re-frame/subscribe [::ledger-list-active?])
user (re-frame/subscribe [::subs/user])] user (re-frame/subscribe [::subs/user])
ledger-params @(re-frame/subscribe [::ledger-params])]
(if (not= "manager" (:user/role @user)) (if (not= "manager" (:user/role @user))
[side-bar-layout [side-bar-layout
{:side-bar [ledger-side-bar] {:side-bar [ledger-side-bar]

View File

@@ -216,22 +216,23 @@
:field [:description-original] :field [:description-original]
:disabled "disabled"}]] :disabled "disabled"}]]
(when (and (seq (:potential-transaction-rule-matches data)) (cond
(not (:matched-rule data)) (and (seq (:potential-transaction-rule-matches data))
(not (:payment data)) (not (:matched-rule data))
is-admin?) (not (:payment data))
is-admin?)
[potential-transaction-rule-matches-box {:potential-transaction-rule-matches (:potential-transaction-rule-matches data) [potential-transaction-rule-matches-box {:potential-transaction-rule-matches (:potential-transaction-rule-matches data)
:edit-completed edit-completed}]) :edit-completed edit-completed}]
(when (and (seq (:potential-payment-matches data)) (and (seq (:potential-payment-matches data))
(not (:payment data)) (not (:payment data))
is-admin?) is-admin?)
[potential-payment-matches-box {:potential-payment-matches (:potential-payment-matches data) [potential-payment-matches-box {:potential-payment-matches (:potential-payment-matches data)
:edit-completed edit-completed}]) :edit-completed edit-completed}]
(when (and (not (seq (:potential-payment-matches data))) (and (not (seq (:potential-payment-matches data)))
(not (seq (:potential-transaction-rule-matches data)))) (not (seq (:potential-transaction-rule-matches data))))
[:div [:div
[field "Vendor" [field "Vendor"
[typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors]) [typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors])
@@ -274,4 +275,30 @@
[error-notification] [error-notification]
(when-not should-disable-for-client? (when-not should-disable-for-client?
[submit-button "Save"])])])]) [submit-button "Save"])]
:else
[:div
[field "Approval Status"
[button-radio
{:type "button-radio"
:field [:approval-status]
:options [[:unapproved "Unapproved"]
[:requires-feedback "Client Review"]
[:approved "Approved"]
[:excluded "Excluded from Ledger"]]
:disabled should-disable-for-client?}]]
[field "Forecasted-transaction"
[typeahead-entity {:matches (doto @(re-frame/subscribe [::subs/forecasted-transactions-for-client (:id (:client data))]) println)
:match->text :identifier
:type "typeahead-entity"
:field [:forecast-match]}]]
[:hr]
[error-notification]
(when-not should-disable-for-client?
[submit-button "Save"])]
)])])