(ns auto-ap.intuit.core (:require [auto-ap.datomic :refer [conn remove-nils]] [amazonica.aws.s3 :as s3] [auto-ap.utils :refer [by]] [clj-http.client :as client] [clj-time.coerce :as coerce] [clj-time.core :as time] [clj-time.format :as f] [config.core :refer [env] :as cfg ] [clojure.string :as str] [clojure.data.json :as json] [clojure.java.io :as io] [clojure.tools.logging :as log] [datomic.api :as d] [mount.core :as mount] [unilog.context :as lc] [yang.scheduler :as scheduler] [clojure.core.async :as async] [clojure.core.memoize :as m]) (: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"})) (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"})) (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"))))) (defn init-tokens [access refresh] (set-access-token access) (set-refresh-token refresh)) (defn lookup-access-token [] (slurp (:object-content (s3/get-object :bucket-name (:data-bucket env) :key "intuit/access-token")))) (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 (doto (:refresh_token response) log/info)) (: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 [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)) (map (fn [[id name]] {:id id :name name})))) (defn get-all-transactions [start end] (let [token (get-fresh-access-token)] (let [body (: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}))] body))) (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)))))