This commit is contained in:
2024-05-26 20:22:13 -07:00
111 changed files with 10708 additions and 5015 deletions

View File

@@ -1,25 +1,37 @@
(ns auto-ap.import.intuit
(:require
[auto-ap.datomic :refer [conn]]
[auto-ap.import.common :refer [wrap-integration]]
[auto-ap.import.transactions :as t]
[auto-ap.intuit.core :as i]
[auto-ap.logging :as alog]
[auto-ap.time :as atime]
[clj-time.coerce :as coerce]
[clj-time.core :as time]
[clojure.string :as str]
[com.unbounce.dogstatsd.core :as statsd]
[datomic.api :as dc]))
(:require [auto-ap.datomic :refer [conn]]
[auto-ap.import.common :refer [wrap-integration]]
[auto-ap.import.transactions :as t]
[auto-ap.intuit.core :as i]
[auto-ap.logging :as alog]
[auto-ap.time :as atime]
[clj-time.coerce :as coerce]
[clj-time.core :as time]
[clojure.string :as str]
[com.unbounce.dogstatsd.core :as statsd]
[datomic.api :as dc]
[iol-ion.utils :refer [remove-nils]]))
(defn get-intuit-bank-accounts
( [db]
(dc/q '[:find ?external-id ?ba ?c
:in $
:where
[?c :client/bank-accounts ?ba]
[?ba :bank-account/intuit-bank-account ?iab]
[?iab :intuit-bank-account/external-id ?external-id]]
db))
([db & client-codes]
(dc/q '[:find ?external-id ?ba ?c
:in $ [?cc ...]
:where
[?c :client/code ?cc]
[?c :client/bank-accounts ?ba]
[?ba :bank-account/intuit-bank-account ?iab]
[?iab :intuit-bank-account/external-id ?external-id]]
db
client-codes)))
(defn get-intuit-bank-accounts [db]
(dc/q '[:find ?external-id ?ba ?c
:in $
:where
[?c :client/bank-accounts ?ba]
[?ba :bank-account/intuit-bank-account ?iab]
[?iab :intuit-bank-account/external-id ?external-id]]
db))
(defn intuit->transaction [transaction]
(let [check-number (when (not (str/blank? (:Num transaction)))
@@ -78,6 +90,9 @@
bank-accounts (i/get-bank-accounts token)]
@(dc/transact conn (mapv
(fn [ba]
{:intuit-bank-account/external-id (:name ba)
:intuit-bank-account/name (:name ba)})
(remove-nils
{:intuit-bank-account/external-id (:name ba)
:intuit-bank-account/name (:name ba)
:intuit-bank-account/last-synced (coerce/to-date (:last-updated ba))
:intuit-bank-account/current-balance (:current-balance ba)}))
bank-accounts))))

View File

@@ -10,10 +10,64 @@
[clj-time.core :as time]
[clojure.string :as str]
[com.unbounce.dogstatsd.core :as statsd]
[datomic.api :as dc]))
[datomic.api :as dc]
[clj-http.client :as client]))
(for [[e] (take 5 (get-intuit-bank-accounts (dc/db conn)))]
(i/get-transactions "2023-02-01"
"2023-02-05"
e))
(defn get-bank-accounts [token]
(defn get-bank-accounts [token]
(->> (:body (client/get (str i/prod-base-url "/company/" i/prod-company-id "/query")
{:headers
(i/with-auth i/prod-base-headers token)
:as :json
:query-params {"query" "SELECT * From Account maxresults 1000"}}))
:QueryResponse
:Account
#_(filter
#(#{"Bank" "Credit Card"} (:AccountType %))))))
(require 'auto-ap.time_reader)
(let [start #clj-time/date-time "2024-02-01"
end #clj-time/date-time "2024-04-01"]
(for [[ib ba c] (seq (get-intuit-bank-accounts (dc/db conn) "BCFM"))
:let [raw-transactions (i/get-transactions (atime/unparse-local start atime/iso-date)
(atime/unparse-local end atime/iso-date)
ib)
ideal-transactions (intuits->transactions raw-transactions ba c)
found-transactions (when (seq ideal-transactions)
(into {} (dc/q '[:find ?si (count ?t)
:in $ [?eid ...]
:where
[?t :transaction/id ?eid]
[?t :transaction/approval-status ?s]
[?s :db/ident ?si]]
(dc/db conn)
(map :transaction/id ideal-transactions))))
missing-transaction-ids (when (seq ideal-transactions)
(->>
(dc/q '[:find ?eid
:in $ [?eid ...]
:where (not [_ :transaction/id ?eid])]
(dc/db conn)
(map :transaction/id ideal-transactions))
(map first)
(into #{})))
missing-transactions (filter (comp missing-transaction-ids :transaction/id) ideal-transactions)]]
{:bank-account/name (pull-attr (dc/db conn) :bank-account/name ba)
:external-transaction-count (count raw-transactions)
:integreat-transaction-count (reduce + 0 (vals found-transactions))
:approved-count (:transaction-approval-status/approved found-transactions 0)
:unapproved-count (:transaction-approval-status/unapproved found-transactions 0)
:requires-feedback-count (:transaction-approval-status/requires-feedback found-transactions 0)
:missing-transactions missing-transactions}))

View File

@@ -1,31 +1,44 @@
(ns auto-ap.import.plaid
(:require
[auto-ap.datomic :refer [conn random-tempid]]
[auto-ap.import.common :refer [wrap-integration]]
[auto-ap.import.transactions :as t]
[auto-ap.logging :as alog]
[auto-ap.plaid.core :as p]
[auto-ap.solr]
[auto-ap.time :as atime]
[auto-ap.utils :refer [allow-once by]]
[clj-time.coerce :as coerce]
[clj-time.core :as time]
[datomic.api :as dc]
[digest :as di]
[manifold.deferred :as de]
[manifold.executor :as ex]
[clojure.string :as str]))
(:require [auto-ap.datomic :refer [conn random-tempid]]
[auto-ap.import.common :refer [wrap-integration]]
[auto-ap.import.transactions :as t]
[auto-ap.logging :as alog]
[auto-ap.plaid.core :as p]
[auto-ap.solr]
[auto-ap.time :as atime]
[auto-ap.utils :refer [allow-once by]]
[clj-time.coerce :as coerce]
[clj-time.core :as time]
[clojure.string :as str]
[datomic.api :as dc]
[digest :as di]
[iol-ion.utils :refer [remove-nils]]
[manifold.deferred :as de]
[manifold.executor :as ex]))
(defn get-plaid-accounts [db]
(-> (dc/q '[:find ?ba ?c ?external-id ?t
:in $
:where
[?c :client/bank-accounts ?ba]
[?ba :bank-account/plaid-account ?pa]
[?pa :plaid-account/external-id ?external-id]
[?pi :plaid-item/accounts ?pa]
[?pi :plaid-item/access-token ?t]]
db )))
(defn get-plaid-accounts
([db]
(-> (dc/q '[:find ?ba ?c ?external-id ?t
:in $
:where
[?c :client/bank-accounts ?ba]
[?ba :bank-account/plaid-account ?pa]
[?pa :plaid-account/external-id ?external-id]
[?pi :plaid-item/accounts ?pa]
[?pi :plaid-item/access-token ?t]]
db)))
([db & client-codes]
(-> (dc/q '[:find ?ba ?c ?external-id ?t
:in $ [?cc ...]
:where
[?c :client/code ?cc]
[?c :client/bank-accounts ?ba]
[?ba :bank-account/plaid-account ?pa]
[?pa :plaid-account/external-id ?external-id]
[?pi :plaid-item/accounts ?pa]
[?pi :plaid-item/access-token ?t]]
db
client-codes))))
(defn plaid->transaction [t plaid-merchant->vendor-id]
@@ -71,8 +84,36 @@
{"id" (:db/id result)
"name" (:plaid-merchant/name result)}))))
(defn upsert-accounts []
(try
(doseq [[bank-account-id client-id external-id access-token] (get-plaid-accounts (dc/db conn))]
(try
(let [accounts (p/get-accounts access-token)
item (p/get-item access-token)]
@(dc/transact
conn
(for [a (:accounts accounts)]
(remove-nils
{:plaid-account/external-id (:account_id a)
:plaid-account/last-synced (coerce/to-date (coerce/to-date-time (-> item :status :transactions :last_successful_update)))
:plaid-account/balance (or (some-> a
:balances
:current
double)
0.0)}))))
(catch Exception e
(alog/warn ::couldnt-upsert-account :error e))))
(catch Exception e
(alog/warn ::couldnt-upsert-accounts :error e))))
(defn import-plaid-int []
(let [import-batch (t/start-import-batch :import-source/plaid "Automated plaid user")
(let [_ (upsert-accounts)
import-batch (t/start-import-batch :import-source/plaid "Automated plaid user")
end (atime/local-now)
start (time/plus end (time/days -30))
plaid-merchant->vendor-id (build-plaid-merchant->vendor-id)]

View File

@@ -0,0 +1,80 @@
(ns auto-ap.import.plaid)
(let [end (atime/local-now)
start (time/plus end (time/days -30))
[_ _ external-id access-token] (first (get-plaid-accounts (dc/db conn) "BCFM"))]
(p/get-balance access-token))
(def g *1)
(take 5 (:transactions g))
;; => ({:account_id "Dpj0d9yKmXsOxBd0eaL4UONyEJYomNIX7kba3",
;; :balances
;; {:available nil,
;; :current 17764.42,
;; :iso_currency_code "USD",
;; :limit nil,
;; :unofficial_currency_code nil},
;; :mask "1006",
;; :name "NICHOLAS TAPTELIS -91006",
;; :official_name "Business Gold Rewards Card",
;; :subtype "credit card",
;; :type "credit"})
(dc/q '[:find (pull ?pa [{ :plaid-item/_accounts [*]}])
:in $ ?ba
:where [?ba :bank-account/plaid-account ?pa]]
(dc/db conn)
[:bank-account/code "VS-BA6149"])
(auto-ap.datomic/pull-attr (dc/db conn) :db/id [:bank-account/code "VS-BA6149"])
(p/get-transactions "access-production-1aee2c7d-0a57-403d-83dc-28a252fb92b4" "jZrAPpjMoLU55oZdpPVVuk8D7XVjXnuv1EJy6" (clj-time.coerce/to-date-time #inst "2024-05-01") (clj-time.coerce/to-date-time #inst "2024-05-15"))
(user/init-repl)
(defn import-plaid-int-2 []
(let [
import-batch (t/start-import-batch :import-source/plaid "Automated plaid user")
end (atime/local-now)
start (time/plus end (time/days -30))
plaid-merchant->vendor-id (build-plaid-merchant->vendor-id)]
(try
(doseq [[bank-account-id client-id external-id access-token] (get-plaid-accounts (dc/db conn))
:when (= bank-account-id 17592234448533)
:let [_ (println "TRYING INTEGRATION")
transaction-result (wrap-integration #(p/get-transactions access-token external-id start end)
bank-account-id)
_ (println "FOUND" (count (:transactions transaction-result)))
accounts-by-id (by :account_id (:accounts transaction-result))]
transaction (:transactions transaction-result)]
(when (not (:pending transaction))
(t/import-transaction! import-batch (doto (assoc (plaid->transaction (assoc transaction
:account
(accounts-by-id (:account_id transaction)))
plaid-merchant->vendor-id)
:transaction/bank-account bank-account-id
:transaction/client client-id)
(#(println (:transaction/date %)))))))
(try
(rebuild-search-index)
(catch Exception e
(alog/error ::cant-index-plaid
:error e)
(println "CANT INDEX")))
(t/finish! import-batch)
(println "DONE")
(catch Exception e
(println "FAIL")
(t/fail! import-batch e)))))
(import-plaid-int-2)
{:transaction/bank-account 17592234448533, :transaction/date #inst "2024-05-14T07:00:00.000-00:00", :transaction/client 17592234448526, :transaction/status "POSTED", :transaction/plaid-merchant {:plaid-merchant/name "Integreat Restau", :db/id "99cb3ac3-1326-4090-8e36-721a0db3a7cf"}, :db/id "89d4fb46-bb17-436f-b1f9-505bfd67e3ec", :transaction/id "0c56701d74584f800b19b1ce6c7b15212b420626a0d0d28761bab4fec4e10ee8", :transaction/description-original "INTEGREAT RESTAU DES:ACH ID:408-340-3111 INDN:PALA UMBERTO CO ID:XXXXX03620 CCD", :transaction/amount -275.0, :transaction/raw-id "drKydaj39qUPPaR0DQyyHVrD4zb8XBIyxe9QJ"}
(auto-ap.datomic/pull-attr (dc/db conn) :db/id [:bank-account/code "NGGG-CB"])

View File

@@ -85,30 +85,35 @@
(alog/info ::searching-unpaid-invoice
:client-id client-id
:amount amount)
(let [candidate-invoices-vendor-groups (->> (dc/q {:find ['?vendor-id '?e '?outstanding-balance '?d]
:in ['$ '?client-id]
:where ['[?e :invoice/client ?client-id]
'[?e :invoice/status :invoice-status/unpaid]
'(not [_ :invoice-payment/invoice ?e])
'[?e :invoice/vendor ?vendor-id]
'[?e :invoice/outstanding-balance ?outstanding-balance]
'[?e :invoice/date ?d]]}
(dc/db conn) client-id)
(sort-by last) ;; sort by scheduled payment date
(group-by first) ;; group by vendors
vals)
considerations (for [candidate-invoices candidate-invoices-vendor-groups
invoice-count (range 1 32)
consideration (partition invoice-count 1 candidate-invoices)
:when (dollars= (reduce (fn [acc [_ _ amount]]
(+ acc amount)) 0.0 consideration)
(- amount))]
consideration)]
(alog/info ::unpaid-invoice-considerations-found
:client-id client-id
:amount amount
:count (count considerations))
considerations))
(try
(let [candidate-invoices-vendor-groups (->> (dc/q {:find ['?vendor-id '?e '?outstanding-balance '?d]
:in ['$ '?client-id]
:where ['[?e :invoice/client ?client-id]
'[?e :invoice/status :invoice-status/unpaid]
'(not [_ :invoice-payment/invoice ?e])
'[?e :invoice/vendor ?vendor-id]
'[?e :invoice/outstanding-balance ?outstanding-balance]
'[?e :invoice/date ?d]]}
(dc/db conn) client-id)
(sort-by last) ;; sort by scheduled payment date
(group-by first) ;; group by vendors
vals)
considerations (for [candidate-invoices candidate-invoices-vendor-groups
invoice-count (range 1 32)
consideration (partition invoice-count 1 candidate-invoices)
:when (dollars= (reduce (fn [acc [_ _ amount]]
(+ acc amount)) 0.0 consideration)
(- amount))]
consideration)]
(alog/info ::unpaid-invoice-considerations-found
:client-id client-id
:amount amount
:count (count considerations))
considerations)
(catch Exception e
(alog/error ::cant-get-considerations
:error e)
[])))
(defn match-transaction-to-single-unfulfilled-autopayments [amount client-id]
(let [considerations (match-transaction-to-unfulfilled-autopayments amount client-id)]