From 04bba7f5b5cfb6616c782b2c530172aefd0ab8b5 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Fri, 24 Sep 2021 11:17:34 -0700 Subject: [PATCH] supports multi customers in square --- config/dev.edn | 81 ++++++ config/prod-background-worker.edn | 81 ++++++ src/clj/auto_ap/square/core.clj | 411 ++++++++++++++---------------- 3 files changed, 358 insertions(+), 215 deletions(-) diff --git a/config/dev.edn b/config/dev.edn index 5a8de086..3a2f4655 100644 --- a/config/dev.edn +++ b/config/dev.edn @@ -27,4 +27,85 @@ :yodlee2-client-secret "wZQHoGEkv5AGG2ZH" :yodlee2-base-url "https://development.api.yodlee.com/ysl" :yodlee2-fastlink "https://fl4.preprod.yodlee.com/authenticate/USDevexPreProd2-195/fastlink/?channelAppName=usdevexpreprod2" + + :square-config {"NGE1" + {:square-location "SCX0Y8CTGM1S0", + :location "UC", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGOP" + {:square-location "L3GMNBFARX9GG", + :location "OP", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGDG" + {:square-location "LQTHXQY69MYB6", + :location "DB", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGPG" + {:square-location "AMQ0NPA8FGDEF", + :location "SZ", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGEZ" + {:square-location "L0Z167T2T7W7F", + :location "JS", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGLK" + {:square-location "LRC7WVD77ZM81", + :location "SM", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGA1" + {:square-location "FZ3ZYC77T3W1T", + :location "KA", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGKG" + {:square-location "8JT71V8XGYAT3", + :location "NB", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGEB" + {:square-location "LEV4GM1JPJS6R", + :location "CV", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGGG" + {:square-location "L7S9MXZBJ00HY", + :location "LM", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGRV" + {:square-location "L0J45VZKHWXVR", + :location "RV", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGSM" + {:square-location "LG5X0MHA4NZDM", + :location "SM", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGZO" + {:square-location "KMVFQ9CRCXJ10", + :location "VT", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGWL" + {:square-location "LSWNP14T0YKD9", + :location "WL", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGMJ" + {:square-location "FNH5VRT890WK8", + :location "SC", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGHG" + {:square-location "LXJCAHYGZVNEJ", + :location "DC", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGVZ" + {:square-location "ACNTYY8WVZ6DV", + :location "NP", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGAK" + {:square-location "2RVBYER6QSV7W", + :location "MH", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGGH" + {:square-location "LT322EK0S2TRD", + :location "FM", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"} + "20TY" + {:square-location "L2579ATQ0X1ET", + :location "WG", + :token "EAAAEEr749Ea6AdPTdngsmUPwIM3ETbPwcx3QQl_NS0KWuIL-JNzAg4f3W9DGQhb"}} } diff --git a/config/prod-background-worker.edn b/config/prod-background-worker.edn index 23bd5390..878dba81 100644 --- a/config/prod-background-worker.edn +++ b/config/prod-background-worker.edn @@ -26,4 +26,85 @@ :yodlee2-fastlink "https://fl4.prod.yodlee.com/authenticate/USDevexProd2-319/fastlink/?channelAppName=usdevexprod2" :yodlee2-proxy-host "172.31.10.83" :yodlee2-proxy-port 8888 + + :square-config {"NGE1" + {:square-location "SCX0Y8CTGM1S0", + :location "UC", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGOP" + {:square-location "L3GMNBFARX9GG", + :location "OP", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGDG" + {:square-location "LQTHXQY69MYB6", + :location "DB", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGPG" + {:square-location "AMQ0NPA8FGDEF", + :location "SZ", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGEZ" + {:square-location "L0Z167T2T7W7F", + :location "JS", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGLK" + {:square-location "LRC7WVD77ZM81", + :location "SM", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGA1" + {:square-location "FZ3ZYC77T3W1T", + :location "KA", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGKG" + {:square-location "8JT71V8XGYAT3", + :location "NB", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGEB" + {:square-location "LEV4GM1JPJS6R", + :location "CV", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGGG" + {:square-location "L7S9MXZBJ00HY", + :location "LM", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGRV" + {:square-location "L0J45VZKHWXVR", + :location "RV", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGSM" + {:square-location "LG5X0MHA4NZDM", + :location "SM", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGZO" + {:square-location "KMVFQ9CRCXJ10", + :location "VT", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGWL" + {:square-location "LSWNP14T0YKD9", + :location "WL", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGMJ" + {:square-location "FNH5VRT890WK8", + :location "SC", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGHG" + {:square-location "LXJCAHYGZVNEJ", + :location "DC", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGVZ" + {:square-location "ACNTYY8WVZ6DV", + :location "NP", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGAK" + {:square-location "2RVBYER6QSV7W", + :location "MH", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"}, + "NGGH" + {:square-location "LT322EK0S2TRD", + :location "FM", + :token "EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7"} + "20TY" + {:square-location "L2579ATQ0X1ET", + :location "WG", + :token "EAAAEEr749Ea6AdPTdngsmUPwIM3ETbPwcx3QQl_NS0KWuIL-JNzAg4f3W9DGQhb"}} } diff --git a/src/clj/auto_ap/square/core.clj b/src/clj/auto_ap/square/core.clj index a03162d0..bc8a187e 100644 --- a/src/clj/auto_ap/square/core.clj +++ b/src/clj/auto_ap/square/core.clj @@ -5,6 +5,7 @@ [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.tools.logging :as log] @@ -14,9 +15,10 @@ [yang.scheduler :as scheduler] [clojure.core.async :as async])) -(def base-headers {"Square-Version" "2021-08-18" - "Authorization" "Bearer EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7" - "Content-Type" "application/json"}) +(defn base-headers [client] + {"Square-Version" "2021-08-18" + "Authorization" (str "Bearer " (get-in env [:square-config client :token])) + "Content-Type" "application/json"}) (defn lookup-dates [] (->> (clj-time.periodic/periodic-seq (time/plus (time/now) (time/days -15)) @@ -27,21 +29,19 @@ (auto-ap.time/unparse (time/plus d (time/days 5)) auto-ap.time/iso-date)])))) -(defn locations [] +(defn locations [client] (->> (client/get "https://connect.squareup.com/v2/locations" - {:headers {"Square-Version" "2020-08-12" - "Authorization" "Bearer EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7" - "Content-Type" "application/json"} + {:headers (base-headers client) :as :json}) :body :locations)) -(defn fetch-catalog [i] +(defn fetch-catalog [client i] (if i (try (log/info "looking up catalog for" (str "https://connect.squareup.com/v2/catalog/object/" i)) (->> (client/get (str "https://connect.squareup.com/v2/catalog/object/" i) - {:headers base-headers + {:headers (base-headers client) :query-params {"include_related_items" "true"} :as :json}) :body @@ -53,13 +53,13 @@ (def fetch-catalog-fast (memoize fetch-catalog)) -(defn item-id->category-name [i] - (let [item (fetch-catalog-fast i)] +(defn item-id->category-name [client i] + (let [item (fetch-catalog-fast client i)] (cond (:item_variation_data item) - (item-id->category-name (:item_id (:item_variation_data item))) + (item-id->category-name client (:item_id (:item_variation_data item))) (:category_id (:item_data item)) - (:name (:category_data (fetch-catalog-fast (:category_id (:item_data item))))) + (:name (:category_data (fetch-catalog-fast client (:category_id (:item_data item))))) (:item_data item) "Uncategorized" @@ -109,14 +109,14 @@ (defn search - ([l] - (search l nil)) - ([l d] + ([client] + (search client (get-in env [:square-config client :square-location]))) + ([client l] + (search client l nil)) + ([client l d] (log/info "Searching for" l) (let [result (->> (client/post "https://connect.squareup.com/v2/orders/search" - {:headers {"Square-Version" "2020-08-12" - "Authorization" "Bearer EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7" - "Content-Type" "application/json"} + {:headers (base-headers client) :body (json/write-str (cond-> {"location_ids" [l] "limit" 10000} d (merge (pc d)))) :as :json}) @@ -128,12 +128,10 @@ (defn order - ([o] + ([client o] (log/info "Searching for" o) (let [result (->> (client/get (str "https://connect.squareup.com/v2/orders/" o) - {:headers {"Square-Version" "2020-08-12" - "Authorization" "Bearer EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7" - "Content-Type" "application/json"} + {:headers (base-headers client) :as :json}) :body)] @@ -144,25 +142,7 @@ (* 0.01 (or (:amount amt) 0.0))) (defn location_id->client-location [location] - ({"2RVBYER6QSV7W" ["NGAK" "MH"] - "8JT71V8XGYAT3" ["NGKG" "NB"] - "SCX0Y8CTGM1S0" ["NGE1" "UC"] - "FNH5VRT890WK8" ["NGMJ" "SC"] - "AMQ0NPA8FGDEF" ["NGPG" "SZ"] - "ACNTYY8WVZ6DV" ["NGVZ" "NP"] - "KMVFQ9CRCXJ10" ["NGZO" "VT"] - "L0J45VZKHWXVR" ["NGRV" "RV"] - "L3GMNBFARX9GG" ["NGOP" "OP"] - "LXJCAHYGZVNEJ" ["NGHG" "DC"] - "LSWNP14T0YKD9" ["NGWL" "WL"] - "LT322EK0S2TRD" ["NGGH" "FM"] - "L0Z167T2T7W7F" ["NGEZ" "JS"] - "LEV4GM1JPJS6R" ["NGEB" "CV"] - "LQTHXQY69MYB6" ["NGDG" "DB"] - "L7S9MXZBJ00HY" ["NGGG" "LM"] - "LRC7WVD77ZM81" ["NGLK" "SM"] - "FZ3ZYC77T3W1T" ["NGA1" "KA"] - "LG5X0MHA4NZDM" ["NGSM" "SM"]} location)) + (get-in env [:square-location location])) ;; to get totals: (comment @@ -178,68 +158,70 @@ ))) 0.0)) -(defn order->sales-order [order] - (let [[client loc] (location_id->client-location (:location_id order))] - (remove-nils - #:sales-order - {:date (coerce/to-date (time/to-time-zone (coerce/to-date-time (:created_at order)) (time/time-zone-for-id "America/Los_Angeles"))) - :client [:client/code client] - :location loc - :external-id (str "square/order/" client "-" loc "-" (:id order)) - :total (-> order :net_amounts :total_money amount->money) - :tax (-> order :net_amounts :tax_money amount->money) - :tip (-> order :net_amounts :tip_money amount->money) - :discount (-> order :net_amounts :discount_money amount->money) - :service-charge (-> order :net_amounts :service_charge_money amount->money) - :returns (+ (- (-> order :return_amounts :total_money amount->money) - (-> order :return_amounts :tax_money amount->money) - (-> order :return_amounts :tip_money amount->money) - (-> order :return_amounts :service_charge_money amount->money)) - (-> order :return_amounts :discount_money amount->money)) - :charges (->> (:tenders order) - (map (fn [t] - (remove-nils - #:charge - {:type-name (:type t) - :processor (condp = (some-> (:note t) str/lower-case) - "doordash" :ccp-processor/doordash - "dd" :ccp-processor/doordash - "ubereats" :ccp-processor/uber-eats - "ue" :ccp-processor/uber-eats - "grubhub" :ccp-processor/grubhub - "grub" :ccp-processor/grubhub - "gh" :ccp-processor/grubhub - (condp = (:name (:source order)) - "GRUBHUB" :ccp-processor/grubhub - "UBEREATS" :ccp-processor/uber-eats - "DOORDASH" :ccp-processor/doordash - :ccp-processor/na)) - :total (amount->money (:amount_money t)) - :tip (amount->money (:tip_money t))})))) - :line-items (->> (:line_items order) - (map (fn [li] - (remove-nils - #:order-line-item - {:item-name (:name li) - :category (if (= "GIFT_CARD" (:item_type li)) - "Gift Card" - (item-id->category-name (:catalog_object_id li))) - :total (amount->money (:total_money li)) - :tax (amount->money (:total_tax_money li)) - :discount (amount->money (:total_discount_money li))}))))}))) +(defn order->sales-order [client location order] + (remove-nils + #:sales-order + {:date (coerce/to-date (time/to-time-zone (coerce/to-date-time (:created_at order)) (time/time-zone-for-id "America/Los_Angeles"))) + :client [:client/code client] + :location location + :external-id (str "square/order/" client "-" location "-" (:id order)) + :total (-> order :net_amounts :total_money amount->money) + :tax (-> order :net_amounts :tax_money amount->money) + :tip (-> order :net_amounts :tip_money amount->money) + :discount (-> order :net_amounts :discount_money amount->money) + :service-charge (-> order :net_amounts :service_charge_money amount->money) + :returns (+ (- (-> order :return_amounts :total_money amount->money) + (-> order :return_amounts :tax_money amount->money) + (-> order :return_amounts :tip_money amount->money) + (-> order :return_amounts :service_charge_money amount->money)) + (-> order :return_amounts :discount_money amount->money)) + :charges (->> (:tenders order) + (map (fn [t] + (remove-nils + #:charge + {:type-name (:type t) + :processor (condp = (some-> (:note t) str/lower-case) + "doordash" :ccp-processor/doordash + "dd" :ccp-processor/doordash + "ubereats" :ccp-processor/uber-eats + "ue" :ccp-processor/uber-eats + "grubhub" :ccp-processor/grubhub + "grub" :ccp-processor/grubhub + "gh" :ccp-processor/grubhub + (condp = (:name (:source order)) + "GRUBHUB" :ccp-processor/grubhub + "UBEREATS" :ccp-processor/uber-eats + "DOORDASH" :ccp-processor/doordash + :ccp-processor/na)) + :total (amount->money (:amount_money t)) + :tip (amount->money (:tip_money t))})))) + :line-items (->> (:line_items order) + (map (fn [li] + (remove-nils + #:order-line-item + {:item-name (:name li) + :category (if (= "GIFT_CARD" (:item_type li)) + "Gift Card" + (item-id->category-name client (:catalog_object_id li))) + :total (amount->money (:total_money li)) + :tax (amount->money (:total_tax_money li)) + :discount (amount->money (:total_discount_money li))}))))})) -(defn daily-results [d] - (->> (locations) - (map :id) - (filter location_id->client-location) - (mapcat #(search % d)) - (filter (fn [order] - ;; sometimes orders stay open in square. At least one payment - ;; is needed to import, in order to avoid importing orders in-progress. - (and (> (count (:tenders order)) 0) - (not= #{"FAILED"} - (set (map #(:status (:card_details %)) (:tenders order))))))) - (map order->sales-order))) +(defn daily-results + ([client] + (daily-results client nil)) + ([client d] + (daily-results client (get-in env [:square-config client :square-location]) d)) + ([client location d] + (->> (search client location d) + (filter (fn [order] + ;; sometimes orders stay open in square. At least one payment + ;; is needed to import, in order to avoid importing orders in-progress. + (and (or (> (count (:tenders order)) 0) + (seq (:returns order))) + (not= #{"FAILED"} + (set (map #(:status (:card_details %)) (:tenders order))))))) + (map #(order->sales-order client (get-in env [:square-config client :location]) %))))) #_(daily-results) @@ -255,15 +237,15 @@ (retry f (inc i)))) (log/error "Too many failures")))) -(defn get-payment [p] +(defn get-payment [client p] (:payment (:body (retry #(client/get (str "https://connect.squareup.com/v2/payments/" p) - {:headers base-headers + {:headers (base-headers client) :as :json :retry-handler (fn [ex try-count http-context] (log/warn "Retrying after failure " ex) (if (> try-count 4) false true))}))))) -(defn get-settlement-sales-date [settlement] +(defn get-settlement-sales-date [client settlement] (let [concurrent 10 output-chan (async/chan)] (async/pipeline-blocking concurrent @@ -271,15 +253,8 @@ (map (fn [p] (lc/with-context {:source "Square settlements loading "} (log/info "looking up payment " p " for settlement " (:id settlement)) - (println (or - (-> p - get-payment - :created_at - coerce/to-date) - (coerce/to-date (time/now)))) (or - (-> p - get-payment + (-> (get-payment client p) :created_at coerce/to-date) (coerce/to-date (time/now)))))) @@ -300,7 +275,7 @@ (drop 2) first))) -(defn get-settlement-details [settlements] ;; pairs of [location settlement] +(defn get-settlement-details [client settlements] ;; pairs of [location settlement] (log/info "getting settlement details for " settlements) (let [concurrent 10 output-chan (async/chan)] @@ -310,14 +285,14 @@ (lc/with-context {:source "Square settlements loading "} (log/info "Looking up settlement " s " for location " location) (let [settlement (:body (retry #(client/get (str "https://connect.squareup.com/v1/" location "/settlements/" s) - {:headers base-headers + {:headers (base-headers client) :as :json :retry-handler (fn [ex try-count http-context] (log/warn "Retrying after failure " ex) (if (> try-count 4) false true))})))] - (log/info "sales date for " s " is " (get-settlement-sales-date settlement)) - (assoc settlement :sales-date (get-settlement-sales-date settlement) ))))) + (log/info "sales date for " s " is " (get-settlement-sales-date client settlement)) + (assoc settlement :sales-date (get-settlement-sales-date client settlement) ))))) (async/to-chan settlements) true (fn [e] @@ -326,14 +301,14 @@ (async/> lookup-dates (mapcat (fn [[start-date end-date]] (log/info "looking up settlements for " l " on dates " start-date " to " end-date) (let [settlements (->> (client/get (str "https://connect.squareup.com/v1/" l "/settlements") - {:headers base-headers + {:headers (base-headers client) :query-params {"begin_time" start-date "end_time" end-date} :as :json}) @@ -344,77 +319,74 @@ seq (map (fn [s] [l s])) - (get-settlement-details ) + (get-settlement-details client) ))) (defn daily-settlements - ([] (daily-settlements (->> (locations) - (map :id) - (filter location_id->client-location)))) - ([location-ids] - (->> location-ids - (mapcat (fn [l] - (for [settlement (settlements l) - :let [[client loc] (location_id->client-location l)]] - #:expected-deposit {:external-id (str "square/settlement/" (:id settlement)) - :total (amount->money (:total_money settlement)) - :client [:client/code client] - :location loc - :fee (- (reduce + 0.0 (map (fn [entry] - (if (= (:type entry) "REFUND") - (- (amount->money (:fee_money entry))) - (amount->money (:fee_money entry)))) - (:entries settlement)))) - :date (-> (:initiated_at settlement) - (coerce/to-date)) - :sales-date (or (:sales-date settlement) - (-> (:initiated_at settlement) - (coerce/to-date)))}))) - (filter :expected-deposit/date))) - ) + ([client] (daily-settlements client + (get-in env [:square-config client :square-location]))) + ([client location-id] + (->> (for [settlement (settlements client location-id)] + #:expected-deposit {:external-id (str "square/settlement/" (:id settlement)) + :total (amount->money (:total_money settlement)) + :client [:client/code client] + :location (get-in env [:square-config client :location]) + :fee (- (reduce + 0.0 (map (fn [entry] + (if (= (:type entry) "REFUND") + (- (amount->money (:fee_money entry))) + (amount->money (:fee_money entry)))) + (:entries settlement)))) + :date (-> (:initiated_at settlement) + (coerce/to-date)) + :sales-date (or (:sales-date settlement) + (-> (:initiated_at settlement) + (coerce/to-date)))}) + + (filter :expected-deposit/date)))) -(defn refunds [l] - (let [refunds (:refunds (:body (client/get (str "https://connect.squareup.com/v2/refunds?location_id=" l) - {:headers {"Square-Version" "2021-05-13" - "Authorization" "Bearer EAAAEO2xSqesDutZz71hz3eulKmrlKTiEqG3uZ4j25x5GYlOluQ2cj2JxNUXqXD7" - "Content-Type" "application/json"} - :as :json - :retry-handler (fn [ex try-count http-context] - (log/warn "Retrying after failure " ex) - (if (> try-count 4) false true))})))] - (->> refunds - (filter (fn [r] (= "COMPLETED" (:status r)))) - (map (fn [r] - (let [[client location] (location_id->client-location l)] - #:sales-refund {:external-id (str "square/refund/" (:id r)) - :total (amount->money (:amount_money r)) - :fee (transduce - (comp (filter #(= "ADJUSTMENT" (:type %))) - (map :amount_money) - (map amount->money)) - + - 0.0 - (:processing_fee r)) - :client [:client/code client] - :location location - :date (coerce/to-date (:created_at r)) - :type (:source_type (get-payment (:payment_id r)))})))))) +(defn refunds + ([client] + (refunds client (get-in env [:square-config client :square-location]))) + ([client l] + (let [refunds (:refunds (:body (client/get (str "https://connect.squareup.com/v2/refunds?location_id=" l) + {:headers (base-headers client) + :as :json + :retry-handler (fn [ex try-count http-context] + (log/warn "Retrying after failure " ex) + (if (> try-count 4) false true))})))] + (->> refunds + (filter (fn [r] (= "COMPLETED" (:status r)))) + (map (fn [r] + #:sales-refund {:external-id (str "square/refund/" (:id r)) + :total (amount->money (:amount_money r)) + :fee (transduce + (comp (filter #(= "ADJUSTMENT" (:type %))) + (map :amount_money) + (map amount->money)) + + + 0.0 + (:processing_fee r)) + :client [:client/code client] + :location (get-in env [:square-config client :location]) + :date (coerce/to-date (:created_at r)) + :type (:source_type (get-payment client (:payment_id r)))})))))) (defn upsert - ([] - (upsert nil)) - ([d] + ([client ] + (upsert client nil)) + ([client d] (lc/with-context {:source "Square loading"} (try (let [existing (->> (d/query {:query {:find ['?external-id] - :in ['$] - :where ['[_ :sales-order/external-id ?external-id]]} - :args [(d/db conn)]}) + :in ['$ '?client] + :where ['[?o :sales-order/client ?client] + '[?o :sales-order/external-id ?external-id]]} + :args [(d/db conn) [:client/code client]]}) (map first) set) _ (log/info (count existing) "Sales orders already exist") to-create (filter #(not (existing (:sales-order/external-id %))) - (daily-results d))] + (daily-results client d))] (doseq [x (partition-all 20 to-create)] (log/info "Loading " (count x)) @(d/transact conn x))) @@ -422,21 +394,20 @@ (log/error e)))))) (defn upsert-settlements - ([] (upsert-settlements nil)) - ([location-ids] - (lc/with-context {:source "Square settlements loading "} + ([client] (upsert-settlements client (get-in env [:square-config client :square-location]))) + ([client location-id] + (lc/with-context {:source "Square settlements loading"} (try (let [existing (->> (d/query {:query {:find ['?external-id] - :in ['$] - :where ['[_ :expected-deposit/external-id ?external-id]]} - :args [(d/db conn)]}) + :in ['$ '?client] + :where ['[?d :expected-deposit/client ?client] + '[?d :expected-deposit/external-id ?external-id]]} + :args [(d/db conn) [:client/code client]]}) (map first) set) _ (log/info (count existing) "settlements already exist") to-create (filter #(not (existing (:expected-deposit/external-id %))) - (if location-ids - (daily-settlements location-ids) - (daily-settlements)))] + (daily-settlements client location-id))] (doseq [x (partition-all 20 to-create)] (log/info "Loading expected deposit" (count x)) @(d/transact conn x))) @@ -444,26 +415,28 @@ (log/error e))) (log/info "Done loading settlements")))) -(defn upsert-refunds [] - (doseq [{location :id} (locations)] - (when (location_id->client-location location) - (lc/with-context {:source (str "Square refunds loading for " location)} - (try - (let [existing (->> (d/query {:query {:find ['?external-id] - :in ['$] - :where ['[_ :sales-refund/external-id ?external-id]]} - :args [(d/db conn)]}) - (map first) - set) - _ (log/info (count existing) "refunds already exist") - to-create (filter #(not (existing (:sales-refund/external-id %))) - (refunds location))] - (doseq [x (partition-all 20 to-create)] - (log/info "Loading refund" (count x)) - @(d/transact conn x))) - (catch Exception e - (log/error e))) - (log/info "Done loading refunds"))))) +(defn upsert-refunds + ([client] (upsert-refunds client (get-in env [:square-config client :square-location]))) + ([client location] + (lc/with-context {:source "Loading Square Settlements" + :client client} + (try + (let [existing (->> (d/query {:query {:find ['?external-id] + :in ['$ '?client] + :where ['[?r :sales-refund/client ?client] + '[?r :sales-refund/external-id ?external-id]]} + :args [(d/db conn) [:client/code client]]}) + (map first) + set) + _ (log/info (count existing) "refunds already exist") + to-create (filter #(not (existing (:sales-refund/external-id %))) + (refunds client location))] + (doseq [x (partition-all 20 to-create)] + (log/info "Loading refund" (count x)) + @(d/transact conn x))) + (catch Exception e + (log/error e))) + (log/info "Done loading refunds")))) (defn reset [] (->> @@ -474,17 +447,25 @@ (map first) (map (fn [x] [:db/retractEntity x])))) +(defn upsert-all [] + (doseq [[client-code] (get-in env [:square-config])] + (lc/with-context {:source (str "Square loading for " client-code) + :client client-code} + (log/info "Loading Orders") + (upsert client-code) + (log/info "Loading Settlements") + (upsert-settlements client-code) + (log/info "Loading refunds") + (upsert-refunds client-code) + ))) + (mount/defstate square-loader - :start (scheduler/every (* 4 59 60 1000) upsert) + :start (scheduler/every (* 4 59 60 1000) upsert-all) :stop (scheduler/stop square-loader)) -(mount/defstate square-settlement-loader - :start (scheduler/every (* 4 60 60 1000) upsert-settlements) - :stop (scheduler/stop square-settlement-loader)) -(mount/defstate square-refund-loader - :start (scheduler/every (* 4 58 60 1000) upsert-refunds) - :stop (scheduler/stop square-refund-loader)) + + (comment (daily-results)