plaid
This commit is contained in:
@@ -64,7 +64,11 @@
|
||||
(into (->> (:bank_accounts edit_client)
|
||||
(filter #(nil? (:intuit_bank_account %)))
|
||||
(filter #(:bank-account/intuit-bank-account (d/entity (d/db conn) (:id %))))
|
||||
(map (fn [ba] [:db/retract (:id ba) :bank-account/intuit-bank-account (:db/id (:bank-account/intuit-bank-account (d/entity (d/db conn) (:id ba))))])))))
|
||||
(map (fn [ba] [:db/retract (:id ba) :bank-account/intuit-bank-account (:db/id (:bank-account/intuit-bank-account (d/entity (d/db conn) (:id ba))))]))))
|
||||
(into (->> (:bank_accounts edit_client)
|
||||
(filter #(nil? (:plaid_account %)))
|
||||
(filter #(:bank-account/plaid-account (d/entity (d/db conn) (:id %))))
|
||||
(map (fn [ba] [:db/retract (:id ba) :bank-account/plaid-account (:db/id (:bank-account/plaid-account (d/entity (d/db conn) (:id ba))))])))))
|
||||
|
||||
|
||||
transactions (into [(remove-nils {:db/id id
|
||||
@@ -110,6 +114,7 @@
|
||||
:bank-account/yodlee-account-id (:yodlee_account_id %)
|
||||
:bank-account/type (keyword "bank-account-type" (name (:type %)))}
|
||||
(:yodlee_account %) (assoc :bank-account/yodlee-account [:yodlee-account/id (:yodlee_account %)])
|
||||
(:plaid_account %) (assoc :bank-account/plaid-account (:plaid_account %))
|
||||
(:intuit_bank_account %) (assoc :bank-account/intuit-bank-account (:intuit_bank_account %))))
|
||||
(:bank_accounts edit_client))
|
||||
|
||||
@@ -223,7 +228,9 @@
|
||||
(map (fn [c]
|
||||
(if (is-admin? (:id context))
|
||||
c
|
||||
(dissoc c :client/yodlee-provider-accounts))))
|
||||
(-> c
|
||||
(dissoc :client/yodlee-provider-accounts)
|
||||
(dissoc :client/plaid-items)))))
|
||||
(map (fn [c]
|
||||
(update c :client/bank-accounts
|
||||
(fn [bank-accounts]
|
||||
|
||||
159
src/clj/auto_ap/graphql/plaid.clj
Normal file
159
src/clj/auto_ap/graphql/plaid.clj
Normal file
@@ -0,0 +1,159 @@
|
||||
(ns auto-ap.graphql.plaid
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
:refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query]]
|
||||
[auto-ap.graphql.utils :refer [assert-admin assert-present]]
|
||||
[auto-ap.plaid.core :as p]
|
||||
[clj-time.coerce :as coerce]
|
||||
[clj-time.core :as time]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[datomic.api :as d]))
|
||||
|
||||
(defn plaid-link-token [context value args]
|
||||
(assert-admin (:id context))
|
||||
(let [client-code (:client/code (d/pull (d/db conn) [:client/code] (:client_id value)))]
|
||||
{:token (p/get-link-token client-code)}))
|
||||
|
||||
(defn link-plaid [context value args]
|
||||
(assert-admin (:id context))
|
||||
(when-not (:client_code value)
|
||||
(throw (ex-info "Client not provided" {:validation-error "Client not provided."})))
|
||||
(when-not (:public_token value)
|
||||
(throw (ex-info "Public token not provided" {:validation-error "public token not provided"})))
|
||||
|
||||
(let [access-token (:access_token (p/exchange-public-token (:public_token value) (:client_code value)))
|
||||
account-result (p/get-accounts access-token )
|
||||
item {:plaid-item/client [:client/code (:client_code value)]
|
||||
:plaid-item/external-id (-> account-result :item :item_id )
|
||||
:plaid-item/access-token access-token
|
||||
:plaid-item/status (or (some-> account-result :item :error)
|
||||
"SUCCESS")
|
||||
:plaid-item/last-updated (coerce/to-date (time/now))
|
||||
:db/id "plaid-item"}]
|
||||
|
||||
@(d/transact conn (->> (:accounts account-result)
|
||||
(map (fn [a]
|
||||
(let [balance (some-> a :balances :current (* 0.01))]
|
||||
(cond-> {:plaid-account/external-id (:account_id a)
|
||||
:plaid-account/number (:mask a)
|
||||
:plaid-account/name (str (:name a) " " (:mask a))
|
||||
:plaid-item/_accounts "plaid-item"}
|
||||
balance (assoc :plaid-account/balance balance)))))
|
||||
(into [item])))
|
||||
{:message (str "Plaid linked successfully. Access Token: " access-token)}))
|
||||
|
||||
|
||||
(def default-read '[:db/id
|
||||
:plaid-item/external-id
|
||||
:plaid-item/last-updated
|
||||
:plaid-item/status
|
||||
{:plaid-item/accounts [:db/id
|
||||
:plaid-account/external-id
|
||||
:plaid-account/number
|
||||
:plaid-account/balance
|
||||
:plaid-account/name]}])
|
||||
|
||||
(defn raw-graphql-ids [db args]
|
||||
(println args)
|
||||
(let [query (cond-> {:query {:find []
|
||||
:in ['$]
|
||||
:where []}
|
||||
:args [db]}
|
||||
|
||||
(:sort args) (add-sorter-fields {"external-id" ['[?e :plaid-item/external-id ?sort-external-id]]}
|
||||
args)
|
||||
|
||||
(:client-id args)
|
||||
(merge-query {:query {:in '[?client-id]
|
||||
:where ['[?e :plaid-item/client ?client-id]]}
|
||||
:args [(:client-id args)]})
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?e]
|
||||
:where ['[?e :plaid-item/external-id]]}}))]
|
||||
|
||||
(cond->> query
|
||||
true (d/query)
|
||||
true (apply-sort-3 args)
|
||||
true (apply-pagination args))))
|
||||
|
||||
(defn graphql-results [ids db args]
|
||||
(let [results (->> (d/pull-many db default-read ids)
|
||||
(group-by :db/id))]
|
||||
(->> ids
|
||||
(map results)
|
||||
(map first))))
|
||||
|
||||
(defn get-graphql [args]
|
||||
(let [db (d/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
[(graphql-results ids-to-retrieve db args)
|
||||
matching-count]))
|
||||
|
||||
|
||||
|
||||
(defn get-plaid-item-page [context args value]
|
||||
(assert-admin (:id context))
|
||||
(let [args (assoc args :id (:id context))
|
||||
[plaid-items cnt] (get-graphql (<-graphql (assoc args :id (:id context))))]
|
||||
{:plaid_items (->> plaid-items
|
||||
(map #(update % :plaid-item/last-updated coerce/from-date))
|
||||
(map ->graphql))
|
||||
:total cnt
|
||||
:count (count plaid-items)
|
||||
:start (:start args 0)
|
||||
:end (+ (:start args 0) (count plaid-items))}))
|
||||
|
||||
(defn delete-plaid-item [context args value]
|
||||
(assert-admin (:id context))
|
||||
(assert-present args :id)
|
||||
@(d/transact conn [[:db/retractEntity (:id args)]])
|
||||
{:message "Item deleted."})
|
||||
|
||||
(defn attach [schema]
|
||||
(->
|
||||
(merge-with merge schema
|
||||
{:objects {:plaid_link_result
|
||||
{:fields {:token {:type 'String}} }
|
||||
|
||||
:plaid_item
|
||||
{:fields {:external_id {:type 'String}
|
||||
:id {:type :id}
|
||||
:client {:type :client}
|
||||
:status {:type 'String}
|
||||
:last_updated {:type :iso_date}
|
||||
:accounts {:type '(list :plaid_account)}}}
|
||||
|
||||
:plaid_item_page {:fields {:plaid_items {:type '(list :plaid_item)}
|
||||
:count {:type 'Int}
|
||||
:total {:type 'Int}
|
||||
:start {:type 'Int}
|
||||
:end {:type 'Int}}}
|
||||
|
||||
:plaid_account
|
||||
{:fields {:external_id {:type 'String}
|
||||
:id {:type :id}
|
||||
:balance {:type :money}
|
||||
:name {:type 'String}
|
||||
:number {:type 'String}}}}
|
||||
:queries {:plaid_link_token {:type :plaid_link_result
|
||||
:args {:client_id {:type :id}}
|
||||
:resolve :plaid-link-token}
|
||||
:plaid_item_page {:type :plaid_item_page
|
||||
:args {:client_id {:type :id}
|
||||
:sort {:type '(list :sort_item)}
|
||||
:start {:type 'Int}
|
||||
:per_page {:type 'Int}}
|
||||
:resolve :get-plaid-item-page}}
|
||||
:mutations {:link_plaid {:type :message
|
||||
:args {:client_code {:type 'String}
|
||||
:public_token {:type 'String}}
|
||||
:resolve :mutation/link-plaid}
|
||||
:delete_plaid_item {:type :message
|
||||
:args {:id {:type :id}}
|
||||
:resolve :mutation/delete-plaid-item}}})
|
||||
(attach-resolvers {:plaid-link-token plaid-link-token
|
||||
:get-plaid-item-page get-plaid-item-page
|
||||
:mutation/link-plaid link-plaid
|
||||
:mutation/delete-plaid-item delete-plaid-item})))
|
||||
|
||||
@@ -51,6 +51,14 @@
|
||||
(log/warn "user " id " not an admin!")
|
||||
(throw-unauthorized)))
|
||||
|
||||
(defn assert-present
|
||||
([args key]
|
||||
(assert-present args key (name key)))
|
||||
([args key name]
|
||||
(if (not (get args key))
|
||||
(throw (ex-info (str "Missing field '" name "'.")
|
||||
{:validation-error (str "Missing field '" name "'.")})))))
|
||||
|
||||
(defn assert-power-user [id]
|
||||
(when-not (#{"power-user" "admin"} (:user/role id))
|
||||
(log/warn "user " id " not an power-user!")
|
||||
|
||||
Reference in New Issue
Block a user