(ns auto-ap.intuit.core (:require [amazonica.aws.s3 :as s3] [clj-http.client :as client] [clj-time.coerce :as c] [clojure.core.memoize :as m] [clojure.java.io :as io] [clojure.string :as str] [config.core :as cfg :refer [env]]) (:import (org.apache.commons.codec.binary Base64))) ;; (def authorization-code "AB11638463964I0tYPR3A1inog2HL407u2bZBXHg6LEqCbILRO") ;; (def realm-id "4620816365202617680") ;; (def company-id "4620816365202617680") ;; (def base-url "https://sandbox-quickbooks.api.intuit.com/v3") (def prod-client-id "ABFRwAiOqQiLN66HKplXfyRE3ipD390DHsrUquflRCiOa81mxa") (def prod-client-secret "xDUj04GeQXpLvrhxep1jjDYwjJWbzzOPrirUQTKF") ;; (def prod-redirect-uri "https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl") ;; (def prod-authorization-code "AB11638464998wYuapsEGtIEnRqphrw0H97XUnvEG2dK4cGUyL") ;; (def prod-realm-id "123146163906404") ;; "refreshToken": "AB11647191065B0olWYQ61wfq8uszBusfe6Jpn7Au7qY5exkLL", ;; "accessToken":, ;; (def prod-company-id "123146163906404") (def prod-base-url "https://quickbooks.api.intuit.com/v3") (defn set-access-token [t] (s3/put-object :bucket-name (:data-bucket env) :key (str "intuit/access-token") :input-stream (io/make-input-stream (.getBytes t) {}) :metadata {:content-type "application/text" :content-length (count (.getBytes t))})) (defn set-refresh-token [t] (s3/put-object :bucket-name (:data-bucket env) :key (str "intuit/refresh-token") :input-stream (io/make-input-stream (.getBytes t) {}) :metadata {:content-type "application/text" :content-length (count (.getBytes t))})) #_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn copy-prod-refresh-token [] (set-refresh-token (slurp (:object-content (s3/get-object :bucket-name "data.prod.app.integreatconsult.com" :key "intuit/refresh-token"))))) #_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn init-tokens [access refresh] (set-access-token access) (set-refresh-token refresh)) #_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn lookup-access-token [] (slurp (:object-content (s3/get-object :bucket-name (:data-bucket env) :key "intuit/access-token")))) #_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn lookup-refresh-token [] (slurp (:object-content (s3/get-object :bucket-name (:data-bucket env) :key "intuit/refresh-token")))) (defn get-basic-auth [] (Base64/encodeBase64String (.getBytes (str prod-client-id ":" prod-client-secret)))) (defn get-fresh-access-token [] (let [refresh-token (lookup-refresh-token) response (:body (client/post (str "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer") {:headers {"Accept" "application/json" "Content-Type" "application/x-www-form-urlencoded" "Authorization" (str "Basic " (get-basic-auth))} :form-params {"grant_type" "refresh_token" "refresh_token" refresh-token} :as :json}))] (set-access-token (:access_token response)) (set-refresh-token (:refresh_token response)) (:access_token response))) (def prod-base-headers {"Accept" "application/json" "Content-Type" "application/json"}) (defn with-auth [t token] (assoc t "Authorization" (str "Bearer " token))) #_(client/get (str base-url "/company/4620816365202617680") {:headers base-headers :as :json}) (defn get-bank-accounts-raw [token] (->> (:body (client/get (str prod-base-url "/company/" prod-company-id "/query") {:headers (with-auth prod-base-headers token) :as :json :query-params {"query" "SELECT * From Account maxresults 1000"}})) :QueryResponse)) (defn get-bank-accounts [token] (->> (:body (client/get (str prod-base-url "/company/" prod-company-id "/query") {:headers (with-auth prod-base-headers token) :as :json :query-params {"query" "SELECT * From Account maxresults 1000"}})) :QueryResponse :Account #_(filter #(#{"Bank" "Credit Card"} (:AccountType %))) (map (juxt :Id :Name :CurrentBalance :MetaData)) (map (fn [[id name current-balance metadata]] {:id id :name name :last-updated (c/to-date-time (-> metadata :LastUpdatedTime)) :current-balance (try (double current-balance) (catch Exception _ nil))})))) (defn get-all-transactions [start end] (let [token (get-fresh-access-token)] (:body (client/get (str prod-base-url "/company/" prod-company-id "/reports/TransactionList" "?minorversion=63&start_date=" start "&end_date=" end) {:headers (with-auth prod-base-headers token) :as :json})))) (def memoize-get-all-transactions (m/ttl get-all-transactions :ttl/threshold 60000)) (defn get-transactions [start end external-id] (let [body (memoize-get-all-transactions start end) headers (map :ColTitle (:Column (:Columns body))) rows (map :ColData (:Row (:Rows body)))] (->> rows (map (fn [row] (into {} (map (fn [h r] [(keyword h) (:value r)]) headers row)))) (filter #(str/includes? (:Account %) external-id)))))