working on ezcater
ezcater other. dajusments. migration for square2
This commit is contained in:
4
.projectile
Normal file
4
.projectile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
-/target
|
||||||
|
-/node_modules
|
||||||
|
-/data
|
||||||
|
-/datomic-init
|
||||||
BIN
resources/public/img/ezcater.png
Normal file
BIN
resources/public/img/ezcater.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
resources/public/img/koala.png
Normal file
BIN
resources/public/img/koala.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
resources/public/img/square.png
Normal file
BIN
resources/public/img/square.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
63
scratch-sessions/dynamo-replica.clj
Normal file
63
scratch-sessions/dynamo-replica.clj
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
;; This buffer is for Clojure experiments and evaluation.
|
||||||
|
|
||||||
|
;; Press C-j to evaluate the last expression.
|
||||||
|
|
||||||
|
;; You can also press C-u C-j to evaluate the expression and pretty-print its result.
|
||||||
|
|
||||||
|
(ns dynamo-replica
|
||||||
|
(:require [amazonica.aws.dynamodbv2 :as ddb]
|
||||||
|
[datomic.api :as d]
|
||||||
|
[auto-ap.datomic :refer [conn]]))
|
||||||
|
|
||||||
|
(ddb/delete-table :table-name "sales-replica")
|
||||||
|
|
||||||
|
(ddb/create-table
|
||||||
|
:table-name "sales-replica"
|
||||||
|
:key-schema [{:attribute-name "id" :key-type "HASH"}
|
||||||
|
{:attribute-name "date" :key-type "RANGE"}]
|
||||||
|
:attribute-definitions
|
||||||
|
[{:attribute-name "id" :attribute-type "S"}
|
||||||
|
{:attribute-name "date" :attribute-type "S"}
|
||||||
|
{:attribute-name "client" :attribute-type "N"}]
|
||||||
|
:global-secondary-indexes
|
||||||
|
[{:index-name "client_date"
|
||||||
|
:key-schema [{:attribute-name "client" :key-type "HASH"}
|
||||||
|
{:attribute-name "date" :key-type "RANGE"}]
|
||||||
|
:projection {:projection-type "ALL"}
|
||||||
|
:provisioned-throughput
|
||||||
|
{:read-capacity-units 500
|
||||||
|
:write-capacity-units 500}}]
|
||||||
|
:provisioned-throughput
|
||||||
|
{:read-capacity-units 500
|
||||||
|
:write-capacity-units 500})
|
||||||
|
|
||||||
|
(user/init-repl)
|
||||||
|
|
||||||
|
(doseq [client ["NGAK"]
|
||||||
|
batch (->> (d/q '[:find [?s ...]
|
||||||
|
:in $ ?c
|
||||||
|
:where
|
||||||
|
[?s :sales-order/client ?c]]
|
||||||
|
(d/db conn)
|
||||||
|
[:client/code client])
|
||||||
|
|
||||||
|
(partition-all 25)
|
||||||
|
(map (fn [batch]
|
||||||
|
(for [o (d/pull-many (d/db conn) '[* {:sales-order/charges [*] :sales-order/line-items [*]}] batch)]
|
||||||
|
{:id (str (:db/id o))
|
||||||
|
:client (:db/id (:sales-order/client o))
|
||||||
|
:date (str (:sales-order/date o))
|
||||||
|
:total (:sales-order/total o)
|
||||||
|
#_#_:line-items (into-array (for [i (:sales-order/line-items o)]
|
||||||
|
(java.util.HashMap. {:total (:order-line-item/total i)})))}))))]
|
||||||
|
(println "Adding 25 ... " (first batch))
|
||||||
|
(ddb/batch-write-item :request-items
|
||||||
|
{"sales-replica"
|
||||||
|
(for [item batch]
|
||||||
|
{:put-request {:item item}})})
|
||||||
|
(Thread/sleep 50)
|
||||||
|
#_(ddb/put-item :table-name "sales-replica"
|
||||||
|
:item item))
|
||||||
|
|
||||||
|
(doc d/pull-many)
|
||||||
|
|
||||||
235
scratch-sessions/working-on-ezcater-square-v2.clj
Normal file
235
scratch-sessions/working-on-ezcater-square-v2.clj
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
;; This buffer is for Clojure experiments and evaluation.
|
||||||
|
|
||||||
|
;; Press C-j to evaluate the last expression.
|
||||||
|
|
||||||
|
;; You can also press C-u C-j to evaluate the expression and pretty-print its result.
|
||||||
|
(ns working-on-ezcater-square-v2
|
||||||
|
(:require [auto-ap.square.core :as sc]
|
||||||
|
[clj-time.core :as time]
|
||||||
|
[auto-ap.ezcater.core :as ez])
|
||||||
|
)
|
||||||
|
|
||||||
|
(auto-ap.routes.queries/put-query
|
||||||
|
"ec3bae96-95cd-40aa-b0b1-342ab58efed2"
|
||||||
|
" [:find ?d4 ?type ?p2 (sum ?total) (sum ?tip)
|
||||||
|
:with ?charge
|
||||||
|
:in $
|
||||||
|
:where
|
||||||
|
[?charge :charge/date ?date]
|
||||||
|
[(ground (clj-time.coerce/to-date (clj-time.core/minus (auto-ap.time/local-now) (clj-time.core/days 50)))) ?min-d]
|
||||||
|
[(>= ?date ?min-d)]
|
||||||
|
[?charge :charge/client ?c]
|
||||||
|
[?c :client/code \"NGOP2\"]
|
||||||
|
[?charge :charge/type-name ?type]
|
||||||
|
[?charge :charge/total ?total]
|
||||||
|
[?charge :charge/tip ?tip]
|
||||||
|
(or
|
||||||
|
|
||||||
|
(and [_ :expected-deposit/charges ?charge ]
|
||||||
|
[(ground :settlement) ?ccp]
|
||||||
|
[(ground :settlement) ?p])
|
||||||
|
(and
|
||||||
|
(not [_ :expected-deposit/charges ?charge])
|
||||||
|
[(get-else $ ?charge :charge/processor :na) ?ccp]
|
||||||
|
[(get-else $ ?ccp :db/ident :na) ?p]
|
||||||
|
))
|
||||||
|
[(name ?p) ?p2]
|
||||||
|
[(clj-time.coerce/to-date-time ?date) ?d2]
|
||||||
|
[(auto-ap.time/localize ?d2) ?d3]
|
||||||
|
[(auto-ap.time/unparse-local ?d3 auto-ap.time/normal-date) ?d4]]
|
||||||
|
", "")
|
||||||
|
|
||||||
|
(user/init-repl)
|
||||||
|
|
||||||
|
(in-ns 'auto-ap.square.core)
|
||||||
|
(require '[auto-ap.square.core :as sc])
|
||||||
|
|
||||||
|
(require '[auto-ap.ezcater.core :as ez])
|
||||||
|
|
||||||
|
(def square-client (first (sc/get-square-clients "NGOP2")))
|
||||||
|
|
||||||
|
|
||||||
|
(def square-location (first (for [client (sc/get-square-clients "NGOP2")
|
||||||
|
square-location (:client/square-locations client)
|
||||||
|
:when (:square-location/client-location square-location)]
|
||||||
|
square-location)))
|
||||||
|
|
||||||
|
|
||||||
|
(sc/upsert square-client square-location (time/plus (time/now) (time/days -45)) (time/now))
|
||||||
|
|
||||||
|
(sc/upsert-settlements square-client square-location)
|
||||||
|
|
||||||
|
(sc/get-order square-client square-location "EYIVOtQj8FgdpgNlpUQP9S51uNbZY" )
|
||||||
|
(sc/get-payment square-client "vhnZ67vi7BIO6mZ6R609Vsih7nDZY")
|
||||||
|
k
|
||||||
|
(sc/get-order square-client square-location "ggjaHEikb81AKjrJC7H4RRqjDXZZY")
|
||||||
|
|
||||||
|
(sc/get-payment square-client "zhEgwmQL4cI0P00NGBAzqX5gnX6YY")
|
||||||
|
|
||||||
|
(sc/get-order square-client square-location "CdzNsHRryhGNQ9fh4tdYcEBwA4PZY")
|
||||||
|
|
||||||
|
(sc/get-order square-client square-location "hipr01buRJcFg2NFeFTjuJ4eV")
|
||||||
|
|
||||||
|
|
||||||
|
(user/start-db)
|
||||||
|
|
||||||
|
(def my-search (doall (search (first (get-square-clients "NGOP2"))
|
||||||
|
{:db/id 17592186106155,
|
||||||
|
:square-location/name "Oyster Point",
|
||||||
|
:square-location/square-id "L3GMNBFARX9GG",
|
||||||
|
:square-location/client-location "OP"}
|
||||||
|
#clj-time/date-time "2022-06-30T00:00:00-08:00"
|
||||||
|
#clj-time/date-time "2022-07-01T00:00:00-08:00"
|
||||||
|
|
||||||
|
)))
|
||||||
|
|
||||||
|
(def my-search (doall (search (first (get-square-clients "NGOP2"))
|
||||||
|
{:db/id 17592186106155,
|
||||||
|
:square-location/name "Oyster Point",
|
||||||
|
:square-location/square-id "L3GMNBFARX9GG",
|
||||||
|
:square-location/client-location "OP"}
|
||||||
|
#clj-time/date-time "2022-07-13T00:00:00-08:00"
|
||||||
|
#clj-time/date-time "2022-07-14T00:00:00-08:00"
|
||||||
|
|
||||||
|
)))
|
||||||
|
|
||||||
|
(set/difference
|
||||||
|
|
||||||
|
|
||||||
|
(filter
|
||||||
|
|
||||||
|
(comp (set/difference
|
||||||
|
(set (map :id
|
||||||
|
(let [search-results my-search
|
||||||
|
koala-production-ids (->> search-results
|
||||||
|
(filter #(= "koala-production" (:name (:source %))))
|
||||||
|
(map :id)
|
||||||
|
(into #{}))]
|
||||||
|
(let [search-results my-search]
|
||||||
|
(->> search-results
|
||||||
|
(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)))
|
||||||
|
(or (= #{} (set (map #(:status (:card_details %)) (:tenders order))))
|
||||||
|
(not= #{} (set/difference
|
||||||
|
(set (map #(:status (:card_details %)) (:tenders order)))
|
||||||
|
#{"FAILED" "VOIDED"}))))))
|
||||||
|
(filter (fn [order]
|
||||||
|
(not= "Koala" (:name (:source order)))))
|
||||||
|
(filter (fn has-linked-koala-production? [order]
|
||||||
|
;; if a POS order is linked (via note) to a koala-production order, we want
|
||||||
|
;; to keep the koala-production order, because it has taxes correct
|
||||||
|
(not (and (:line_items order) ;; returns do not have line items, so they should be allowed
|
||||||
|
(->> (:line_items order)
|
||||||
|
(map :note)
|
||||||
|
(every? koala-production-ids))))))))))
|
||||||
|
)
|
||||||
|
(set (map :id (->> my-search
|
||||||
|
(filter (fn [order]
|
||||||
|
(and (or (> (count (:tenders order)) 0)
|
||||||
|
(seq (:returns order)))
|
||||||
|
(or (= #{} (set (map #(:status (:card_details %)) (:tenders order))))
|
||||||
|
(not= #{} (set/difference
|
||||||
|
(set (map #(:status (:card_details %)) (:tenders order)))
|
||||||
|
#{"FAILED" "VOIDED"})))
|
||||||
|
(not= ["CUSTOM_AMOUNT"]
|
||||||
|
(mapv :item_type (:line_items order )))
|
||||||
|
))))
|
||||||
|
)))
|
||||||
|
:id
|
||||||
|
)
|
||||||
|
my-search))
|
||||||
|
|
||||||
|
|
||||||
|
(doseq [p (->>
|
||||||
|
(d/query {:query {:find ['?e]
|
||||||
|
:in ['$]
|
||||||
|
:where ['(or [?e :sales-order/client [:client/code "NGOP2"]]
|
||||||
|
[?e :sales-refund/client [:client/code "NGOP2"]]
|
||||||
|
[?e :expected-deposit/client [:client/code "NGOP2"]])]}
|
||||||
|
:args [(d/db conn)]})
|
||||||
|
(map first)
|
||||||
|
(map (fn [x] [:db/retractEntity x]))
|
||||||
|
(partition-all 100))]
|
||||||
|
@(d/transact conn p))
|
||||||
|
|
||||||
|
|
||||||
|
(def weird-order
|
||||||
|
{:total_service_charge_money {:amount 0, :currency "USD"},
|
||||||
|
:closed_at "2022-07-14T02:50:43Z",
|
||||||
|
:total_discount_money {:amount 0, :currency "USD"},
|
||||||
|
:total_money {:amount 120533, :currency "USD"},
|
||||||
|
:total_tip_money {:amount 0, :currency "USD"},
|
||||||
|
:taxes
|
||||||
|
[{:uid "64a788f3-13c6-45a8-9333-c7e4ed4b45f2",
|
||||||
|
:catalog_object_id "4XTWECYYOZWTGRJ475C3QOQL",
|
||||||
|
:catalog_version 1655153159309,
|
||||||
|
:name "9.875%",
|
||||||
|
:percentage "9.875",
|
||||||
|
:type "ADDITIVE",
|
||||||
|
:applied_money {:amount 10833, :currency "USD"},
|
||||||
|
:scope "LINE_ITEM"}],
|
||||||
|
:net_amounts
|
||||||
|
{:total_money {:amount 120533, :currency "USD"},
|
||||||
|
:tax_money {:amount 10833, :currency "USD"},
|
||||||
|
:discount_money {:amount 0, :currency "USD"},
|
||||||
|
:tip_money {:amount 0, :currency "USD"},
|
||||||
|
:service_charge_money {:amount 0, :currency "USD"}},
|
||||||
|
:total_tax_money {:amount 10833, :currency "USD"},
|
||||||
|
:location_id "L3GMNBFARX9GG",
|
||||||
|
:tenders
|
||||||
|
[{:id "pQgHRVNc3WzBDZVGpORONh5YvaB",
|
||||||
|
:location_id "L3GMNBFARX9GG",
|
||||||
|
:transaction_id "XBo0x9zb7rkpWLAJ79cgihweV",
|
||||||
|
:created_at "2022-07-14T02:50:42Z",
|
||||||
|
:note "ezcater 7\\13",
|
||||||
|
:amount_money {:amount 120533, :currency "USD"},
|
||||||
|
:processing_fee_money {:amount 0, :currency "USD"},
|
||||||
|
:type "OTHER"}],
|
||||||
|
:state "COMPLETED",
|
||||||
|
:ticket_name "Ezcater 7-13",
|
||||||
|
:updated_at "2022-07-14T02:50:43Z",
|
||||||
|
:net_amount_due_money {:amount 0, :currency "USD"},
|
||||||
|
:return_amounts
|
||||||
|
{:total_money {:amount 0, :currency "USD"},
|
||||||
|
:tax_money {:amount 0, :currency "USD"},
|
||||||
|
:discount_money {:amount 0, :currency "USD"},
|
||||||
|
:tip_money {:amount 0, :currency "USD"},
|
||||||
|
:service_charge_money {:amount 0, :currency "USD"}},
|
||||||
|
:line_items
|
||||||
|
[{:total_discount_money {:amount 0, :currency "USD"},
|
||||||
|
:total_money {:amount 120533, :currency "USD"},
|
||||||
|
:total_tax_money {:amount 10833, :currency "USD"},
|
||||||
|
:uid "6a293751-027e-45a0-9f5d-e9f4e7cb62fd",
|
||||||
|
:variation_total_price_money {:amount 109700, :currency "USD"},
|
||||||
|
:item_type "CUSTOM_AMOUNT",
|
||||||
|
:gross_sales_money {:amount 109700, :currency "USD"},
|
||||||
|
:applied_taxes
|
||||||
|
[{:uid "64a788f3-13c6-45a8-9333-c7e4ed4b45f2",
|
||||||
|
:tax_uid "64a788f3-13c6-45a8-9333-c7e4ed4b45f2",
|
||||||
|
:applied_money {:amount 10833, :currency "USD"}}],
|
||||||
|
:base_price_money {:amount 109700, :currency "USD"},
|
||||||
|
:quantity "1"}],
|
||||||
|
:id "XBo0x9zb7rkpWLAJ79cgihweV",
|
||||||
|
:created_at "2022-07-14T02:50:43Z"})
|
||||||
|
|
||||||
|
(order->sales-order "a" "b" weird-order)
|
||||||
|
|
||||||
|
|
||||||
|
(doseq [n ["185431988" "186982950" "186344682" "185281242" "184313395" "185477889" "185043055" "184552573" "185042091" "182674641" "184083782" "184200746" "181197904"]]
|
||||||
|
(clojure.pprint/pprint
|
||||||
|
@(d/transact auto-ap.datomic/conn [(-> {"id" "bf3dcf5c-a68f-42d9-9084-049133e03d3d", "parent_type" "Caterer", "parent_id" "ef505599-947f-42da-a36c-4b569e33a747", "entity_type" "Order", "entity_id" "178289110", "key" "accepted", "occurred_at" "2022-07-21T19:21:07.549Z"}
|
||||||
|
(assoc "entity_id" n)
|
||||||
|
(ez/lookup-order)
|
||||||
|
(ez/order->sales-order)
|
||||||
|
(update :sales-order/date coerce/to-date)
|
||||||
|
(update-in [:sales-order/charges 0 :charge/date] coerce/to-date))])))
|
||||||
|
|
||||||
|
;;
|
||||||
|
(clojure.pprint/pprint [(-> {"id" "bf3dcf5c-a68f-42d9-9084-049133e03d3d", "parent_type" "Caterer", "parent_id" "91541331-d7ae-4634-9e8b-ccbbcfb2ce70", "entity_type" "Order", "entity_id" "178289110", "key" "accepted", "occurred_at" "2022-07-21T19:21:07.549Z"}
|
||||||
|
(lookup-order)
|
||||||
|
#_(order->sales-order)
|
||||||
|
#_(update :sales-order/date coerce/to-date)
|
||||||
|
#_(update-in [:sales-order/charges 0 :charge/date] coerce/to-date))])
|
||||||
@@ -292,5 +292,43 @@
|
|||||||
:db/index true}]]
|
:db/index true}]]
|
||||||
:requires [:add-orders]}
|
:requires [:add-orders]}
|
||||||
:add-ezcater-vendor {:txes [[{:db/ident :vendor/ccp-ezcater
|
:add-ezcater-vendor {:txes [[{:db/ident :vendor/ccp-ezcater
|
||||||
:vendor/name "EZCater CCP"}]]}})
|
:vendor/name "EZCater CCP"}]]}
|
||||||
|
:add-charge-client {:txes [[{:db/ident :charge/client
|
||||||
|
:db/doc "The client for the sale"
|
||||||
|
:db/valueType :db.type/ref
|
||||||
|
:db/cardinality :db.cardinality/one}
|
||||||
|
|
||||||
|
{:db/ident :charge/location
|
||||||
|
:db/doc "The location of the sale"
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/cardinality :db.cardinality/one}]]}
|
||||||
|
:add-charge-date {:txes [[{:db/ident :charge/date
|
||||||
|
:db/doc "The date for the payment"
|
||||||
|
:db/valueType :db.type/instant
|
||||||
|
:db/cardinality :db.cardinality/one}]]}
|
||||||
|
:add-ezcater-processor {:txes [[{:db/ident :ccp-processor/ezcater
|
||||||
|
:db/doc "ezcater processor"}]]}
|
||||||
|
:add-koala-processor {:txes [[{:db/ident :ccp-processor/koala
|
||||||
|
:db/doc "koala processor"}]]}
|
||||||
|
:add-square-processor {:txes [[{:db/ident :ccp-processor/square
|
||||||
|
:db/doc "square processor"}]]}
|
||||||
|
:add-reference-link3 {:txes [[{:db/ident :sales-order/reference-link
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/doc "A link someone can go to to look at the order"}
|
||||||
|
{:db/ident :charge/reference-link
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/doc "A link someone can go to to look at the charge"}]]}
|
||||||
|
:add-source-field2 {:txes [[{:db/ident :sales-order/source
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/doc "Where the POS says the order is from"}
|
||||||
|
{:db/ident :charge/note
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/doc "A custom note"}]]}
|
||||||
|
:add-feature-flags {:txes [[{:db/ident :client/feature-flags
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/cardinality :db.cardinality/many}]]}})
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
(:sort args) (add-sorter-fields {"client" ['[?e :sales-order/client ?c]
|
(:sort args) (add-sorter-fields {"client" ['[?e :sales-order/client ?c]
|
||||||
'[?c :client/name ?sort-client]]
|
'[?c :client/name ?sort-client]]
|
||||||
"location" ['[?e :sales-order/location ?sort-location]]
|
"location" ['[?e :sales-order/location ?sort-location]]
|
||||||
|
"source" ['[?e :sales-order/source ?sort-source]]
|
||||||
"date" ['[?e :sales-order/date ?sort-date]]
|
"date" ['[?e :sales-order/date ?sort-date]]
|
||||||
"total" ['[?e :sales-order/total ?sort-total]]
|
"total" ['[?e :sales-order/total ?sort-total]]
|
||||||
"tax" ['[?e :sales-order/tax ?sort-tax]]
|
"tax" ['[?e :sales-order/tax ?sort-tax]]
|
||||||
@@ -68,6 +69,11 @@
|
|||||||
'[?chg :charge/processor ?processor]]}
|
'[?chg :charge/processor ?processor]]}
|
||||||
:args [(keyword "ccp-processor"
|
:args [(keyword "ccp-processor"
|
||||||
(name (:processor args)))]})
|
(name (:processor args)))]})
|
||||||
|
(:type-name args)
|
||||||
|
(merge-query {:query {:in ['?type-name]
|
||||||
|
:where ['[?e :sales-order/charges ?chg]
|
||||||
|
'[?chg :charge/type-name ?type-name]]}
|
||||||
|
:args [(:type-name args)]})
|
||||||
|
|
||||||
(:total-gte args)
|
(:total-gte args)
|
||||||
(merge-query {:query {:in ['?total-gte]
|
(merge-query {:query {:in ['?total-gte]
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
[clojure.tools.logging :as log]
|
[clojure.tools.logging :as log]
|
||||||
[clj-time.core :as time]
|
[clj-time.core :as time]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[auto-ap.time :as atime]))
|
[auto-ap.time :as atime]
|
||||||
|
[cemerick.url :as url]))
|
||||||
|
|
||||||
(defn query [{:ezcater-integration/keys [api-key]} q]
|
(defn query [{:ezcater-integration/keys [api-key]} q]
|
||||||
(-> (client/post "https://api.ezcater.com/graphql/"
|
(-> (client/post "https://api.ezcater.com/graphql/"
|
||||||
@@ -118,58 +119,90 @@
|
|||||||
[:ezcater-caterer/uuid caterer-uuid]))
|
[:ezcater-caterer/uuid caterer-uuid]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn round-carry-cents [f]
|
||||||
|
(with-precision 2 (double (.setScale (bigdec f) 2 java.math.RoundingMode/HALF_UP))))
|
||||||
|
|
||||||
(defn commision [order]
|
(defn commision [order]
|
||||||
(let [commision% (if (= "MARKETPLACE" (:orderSourceType order))
|
|
||||||
0.15
|
(let [commision% (cond
|
||||||
0.07)]
|
(= "CLUB_SODA" (:orderSourceType order))
|
||||||
|
0.25M
|
||||||
|
|
||||||
|
(= "MARKETPLACE" (:orderSourceType order))
|
||||||
|
0.15M
|
||||||
|
:else
|
||||||
|
0.07M)]
|
||||||
|
(round-carry-cents
|
||||||
(* commision%
|
(* commision%
|
||||||
0.01
|
0.01M
|
||||||
(+
|
(+
|
||||||
(-> order :totals :subTotal :subunits )
|
(-> order :totals :subTotal :subunits )
|
||||||
(reduce +
|
(reduce +
|
||||||
0
|
0
|
||||||
(map :subunits (:feesAndDiscounts (:catererCart order))))))))
|
(map (comp :subunits :cost) (:feesAndDiscounts (:catererCart order)))))))))
|
||||||
|
|
||||||
(defn ccp-fee [order]
|
(defn ccp-fee [order]
|
||||||
(* 0.000275
|
(round-carry-cents
|
||||||
|
(* 0.000275M
|
||||||
(+
|
(+
|
||||||
(-> order :totals :subTotal :subunits )
|
(-> order :totals :subTotal :subunits )
|
||||||
(-> order :totals :salesTax :subunits )
|
(-> order :totals :salesTax :subunits )
|
||||||
(reduce +
|
(reduce +
|
||||||
0
|
0
|
||||||
(map :subunits (:feesAndDiscounts (:catererCart order)))))))
|
(map (comp :subunits :cost) (:feesAndDiscounts (:catererCart order))))))))
|
||||||
|
|
||||||
(defn order->sales-order [{{:keys [timestamp]} :event {:keys [orderItems]} :catererCart :keys [client-code client-location uuid] :as order}]
|
(defn order->sales-order [{{:keys [timestamp]} :event {:keys [orderItems]} :catererCart :keys [client-code client-location uuid] :as order}]
|
||||||
|
(let [adjustment (round-carry-cents (- (+ (-> order :totals :subTotal :subunits (* 0.01))
|
||||||
|
(-> order :totals :salesTax :subunits (* 0.01)))
|
||||||
|
(-> order :catererCart :totals :catererTotalDue )
|
||||||
|
(commision order)
|
||||||
|
(ccp-fee order)))
|
||||||
|
service-charge (+ (commision order) (ccp-fee order))
|
||||||
|
tax (-> order :totals :salesTax :subunits (* 0.01))
|
||||||
|
tip (-> order :totals :tip :subunits (* 0.01))]
|
||||||
#:sales-order
|
#:sales-order
|
||||||
{:date (atime/localize (coerce/to-date-time timestamp))
|
{:date (atime/localize (coerce/to-date-time timestamp))
|
||||||
:external-id (str "ezcater/order/" client-code "-" client-location "-" uuid)
|
:external-id (str "ezcater/order/" client-code "-" client-location "-" uuid)
|
||||||
:client [:client/code client-code]
|
:client [:client/code client-code]
|
||||||
:location client-location
|
:location client-location
|
||||||
:line-items (->> orderItems
|
:reference-link (str (url/url "https://ezmanage.ezcater.com/orders/" uuid ))
|
||||||
(map-indexed (fn [i li]
|
:line-items [#:order-line-item
|
||||||
#:order-line-item
|
{:external-id (str "ezcater/order/" client-code "-" client-location "-" uuid "-" 0)
|
||||||
{:external-id (str "ezcater/order/" client-code "-" client-location "-" uuid "-" i)
|
:item-name "EZCater Catering"
|
||||||
:item-name (:name li)
|
:category "EZCater Catering"
|
||||||
:category "External Catering"
|
:discount adjustment
|
||||||
:total (* 0.01 (:subunits (:totalInSubunits li)))})))
|
:tax tax
|
||||||
|
:total (+ (-> order :totals :subTotal :subunits (* 0.01))
|
||||||
|
tax
|
||||||
|
tip)}]
|
||||||
|
:charges [#:charge
|
||||||
|
{:type-name "CARD"
|
||||||
|
:date (atime/localize (coerce/to-date-time timestamp))
|
||||||
|
:client [:client/code client-code]
|
||||||
|
:location client-location
|
||||||
|
:external-id (str "ezcater/charge/" uuid)
|
||||||
|
:processor :ccp-processor/ezcater
|
||||||
|
:total (+ (-> order :totals :subTotal :subunits (* 0.01))
|
||||||
|
tax
|
||||||
|
tip)
|
||||||
|
:tip tip}]
|
||||||
|
|
||||||
:total (-> order :catererCart :totals :catererTotalDue )
|
:total (+ (-> order :totals :subTotal :subunits (* 0.01))
|
||||||
:discount (- (+ (-> order :totals :subTotal :subunits (* 0.01))
|
tax
|
||||||
(-> order :totals :salesTax :subunits (* 0.01)))
|
tip)
|
||||||
(-> order :catererCart :totals :catererTotalDue )
|
:discount adjustment
|
||||||
(commision order)
|
:service-charge service-charge
|
||||||
(ccp-fee order))
|
:tax tax
|
||||||
:service-charge (+ (commision order) (ccp-fee order))
|
:tip tip
|
||||||
:tax (-> order :totals :salesTax :subunits (* 0.01))
|
:returns 0.0
|
||||||
:tip (-> order :totals :tip :subunits (* 0.01))
|
:vendor :vendor/ccp-ezcater}))
|
||||||
:vendor :vendor/ccp-ezcater})
|
|
||||||
|
|
||||||
(defn lookup-order [json]
|
(defn lookup-order [json]
|
||||||
(let [caterer (get-caterer (get json "parent_id"))
|
(let [caterer (get-caterer (get json "parent_id"))
|
||||||
integration (:ezcater-integration/_caterers caterer)
|
integration (:ezcater-integration/_caterers caterer)
|
||||||
client (-> caterer :ezcater-location/_caterer first :client/_ezcater-locations :client/code)
|
client (-> caterer :ezcater-location/_caterer first :client/_ezcater-locations :client/code)
|
||||||
location (-> caterer :ezcater-location/_caterer first :ezcater-location/location)]
|
location (-> caterer :ezcater-location/_caterer first :ezcater-location/location)]
|
||||||
|
(doto
|
||||||
(-> (query
|
(-> (query
|
||||||
integration
|
integration
|
||||||
{:venia/queries [[:order {:id (get json "entity_id")}
|
{:venia/queries [[:order {:id (get json "entity_id")}
|
||||||
@@ -224,12 +257,18 @@
|
|||||||
:subunits]]]]]]]})
|
:subunits]]]]]]]})
|
||||||
(:order)
|
(:order)
|
||||||
(assoc :client-code client
|
(assoc :client-code client
|
||||||
:client-location location))))
|
:client-location location))
|
||||||
|
log/info)))
|
||||||
|
|
||||||
(defn import-order [json]
|
(defn import-order [json]
|
||||||
;; {"id" "bf3dcf5c-a68f-42d9-9084-049133e03d3d", "parent_type" "Caterer", "parent_id" "91541331-d7ae-4634-9e8b-ccbbcfb2ce70", "entity_type" "Order", "entity_id" "9ab05fee-a9c5-483b-a7f2-14debde4b7a8", "key" "accepted", "occurred_at" "2022-07-21T19:21:07.549Z"}
|
;; {"id" "bf3dcf5c-a68f-42d9-9084-049133e03d3d", "parent_type" "Caterer", "parent_id" "91541331-d7ae-4634-9e8b-ccbbcfb2ce70", "entity_type" "Order", "entity_id" "9ab05fee-a9c5-483b-a7f2-14debde4b7a8", "key" "accepted", "occurred_at" "2022-07-21T19:21:07.549Z"}
|
||||||
|
(clojure.pprint/pprint [(-> json
|
||||||
|
(lookup-order)
|
||||||
|
(order->sales-order)
|
||||||
|
(update :sales-order/date coerce/to-date)
|
||||||
|
(update-in [:sales-order/charges 0 :charge/date] coerce/to-date))])
|
||||||
@(d/transact conn [(-> json
|
@(d/transact conn [(-> json
|
||||||
(lookup-order)
|
(lookup-order)
|
||||||
(order->sales-order)
|
(order->sales-order)
|
||||||
(update :sales-order/date coerce/to-date))])
|
(update :sales-order/date coerce/to-date)
|
||||||
)
|
(update-in [:sales-order/charges 0 :charge/date] coerce/to-date))]))
|
||||||
|
|||||||
@@ -506,6 +506,9 @@
|
|||||||
:enums {
|
:enums {
|
||||||
:processor {:values [{:enum-value :na}
|
:processor {:values [{:enum-value :na}
|
||||||
{:enum-value :doordash}
|
{:enum-value :doordash}
|
||||||
|
{:enum-value :koala}
|
||||||
|
{:enum-value :ezcater}
|
||||||
|
{:enum-value :square}
|
||||||
{:enum-value :uber_eats}
|
{:enum-value :uber_eats}
|
||||||
{:enum-value :grubhub}]}
|
{:enum-value :grubhub}]}
|
||||||
:integration_state {:values [{:enum-value :failed}
|
:integration_state {:values [{:enum-value :failed}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
{:fields {:id {:type :id}
|
{:fields {:id {:type :id}
|
||||||
:location {:type 'String}
|
:location {:type 'String}
|
||||||
:external_id {:type 'String}
|
:external_id {:type 'String}
|
||||||
|
:reference_link {:type 'String}
|
||||||
|
:source {:type 'String}
|
||||||
:total {:type :money}
|
:total {:type :money}
|
||||||
:tip {:type :money}
|
:tip {:type :money}
|
||||||
:tax {:type :money}
|
:tax {:type :money}
|
||||||
@@ -52,6 +54,8 @@
|
|||||||
:charge
|
:charge
|
||||||
{:fields {:id {:type :id}
|
{:fields {:id {:type :id}
|
||||||
:processor {:type :processor}
|
:processor {:type :processor}
|
||||||
|
:reference_link {:type 'String}
|
||||||
|
:note {:type 'String}
|
||||||
:type_name {:type 'String}
|
:type_name {:type 'String}
|
||||||
:total {:type :money}
|
:total {:type :money}
|
||||||
:tip {:type :money}
|
:tip {:type :money}
|
||||||
@@ -69,6 +73,7 @@
|
|||||||
:date_range {:type :date_range}
|
:date_range {:type :date_range}
|
||||||
:total_lte {:type :money}
|
:total_lte {:type :money}
|
||||||
:total_gte {:type :money}
|
:total_gte {:type :money}
|
||||||
|
:type_name {:type 'String}
|
||||||
:processor {:type :processor}
|
:processor {:type :processor}
|
||||||
:start {:type 'Int}
|
:start {:type 'Int}
|
||||||
:per_page {:type 'Int}
|
:per_page {:type 'Int}
|
||||||
|
|||||||
9
src/clj/auto_ap/jobs/square2.clj
Normal file
9
src/clj/auto_ap/jobs/square2.clj
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
(ns auto-ap.jobs.square2
|
||||||
|
(:gen-class)
|
||||||
|
(:require
|
||||||
|
[auto-ap.jobs.core :refer [execute]]
|
||||||
|
[auto-ap.square.core2 :as square2]))
|
||||||
|
|
||||||
|
(defn -main [& _]
|
||||||
|
(execute "square2-loading" square2/upsert-all))
|
||||||
|
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
(POST "/event" request
|
(POST "/event" request
|
||||||
(log/info (str "POST EVENT " (body-string request) request))
|
(log/info (str "POST EVENT " (body-string request) request))
|
||||||
(e/import-order (:json-params request))
|
(e/import-order (:json-params request))
|
||||||
|
|
||||||
{:status 200
|
{:status 200
|
||||||
:headers {"Content-Type" "application/json"}
|
:headers {"Content-Type" "application/json"}
|
||||||
:body "{}"}))
|
:body "{}"}))
|
||||||
|
|||||||
@@ -449,7 +449,8 @@
|
|||||||
:client/square-auth-token
|
:client/square-auth-token
|
||||||
{:client/square-locations [:db/id :square-location/name :square-location/square-id :square-location/client-location]}]) ...]
|
{:client/square-locations [:db/id :square-location/name :square-location/square-id :square-location/client-location]}]) ...]
|
||||||
:in $
|
:in $
|
||||||
:where [?c :client/square-auth-token]]
|
:where [?c :client/square-auth-token]
|
||||||
|
(not [?c :client/feature-flags "new-square"])]
|
||||||
(d/db conn)))
|
(d/db conn)))
|
||||||
([ & codes]
|
([ & codes]
|
||||||
(d/q '[:find [(pull ?c [:db/id
|
(d/q '[:find [(pull ?c [:db/id
|
||||||
@@ -458,6 +459,7 @@
|
|||||||
{:client/square-locations [:db/id :square-location/name :square-location/square-id :square-location/client-location]}]) ...]
|
{:client/square-locations [:db/id :square-location/name :square-location/square-id :square-location/client-location]}]) ...]
|
||||||
:in $ [?code ...]
|
:in $ [?code ...]
|
||||||
:where [?c :client/square-auth-token]
|
:where [?c :client/square-auth-token]
|
||||||
|
(not [?c :client/feature-flags "new-square"])
|
||||||
[?c :client/code ?code]]
|
[?c :client/code ?code]]
|
||||||
(d/db conn)
|
(d/db conn)
|
||||||
codes)))
|
codes)))
|
||||||
|
|||||||
541
src/clj/auto_ap/square/core2.clj
Normal file
541
src/clj/auto_ap/square/core2.clj
Normal file
@@ -0,0 +1,541 @@
|
|||||||
|
(ns auto-ap.square.core2
|
||||||
|
(:require
|
||||||
|
[auto-ap.datomic :refer [conn remove-nils]]
|
||||||
|
[auto-ap.time :as atime]
|
||||||
|
[clj-http.client :as client]
|
||||||
|
[clj-time.coerce :as coerce]
|
||||||
|
[clj-time.core :as time]
|
||||||
|
[clj-time.format :as f]
|
||||||
|
[clj-time.periodic :as periodic]
|
||||||
|
[clojure.core.async :as async]
|
||||||
|
[clojure.data.json :as json]
|
||||||
|
[clojure.set :as set]
|
||||||
|
[clojure.string :as str]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[cemerick.url :as url]
|
||||||
|
[datomic.api :as d]
|
||||||
|
[slingshot.slingshot :refer [try+]]
|
||||||
|
[unilog.context :as lc]))
|
||||||
|
|
||||||
|
(defn client-base-headers [client]
|
||||||
|
{"Square-Version" "2021-08-18"
|
||||||
|
"Authorization" (str "Bearer " (:client/square-auth-token client))
|
||||||
|
"Content-Type" "application/json"})
|
||||||
|
|
||||||
|
(defn retry-4 [ex try-count _]
|
||||||
|
(log/warn "Retrying after failure " ex)
|
||||||
|
(if (> try-count 4) false true))
|
||||||
|
|
||||||
|
(defn lookup-dates []
|
||||||
|
(->> (periodic/periodic-seq (time/plus (time/now) (time/days -50))
|
||||||
|
(time/now)
|
||||||
|
(time/days 5))
|
||||||
|
(map (fn [d]
|
||||||
|
[(atime/unparse (time/plus d (time/days 1)) atime/iso-date)
|
||||||
|
|
||||||
|
(atime/unparse (time/plus d (time/days 5)) atime/iso-date)]))))
|
||||||
|
|
||||||
|
(defn client-locations [client]
|
||||||
|
(try
|
||||||
|
(->> (client/get "https://connect.squareup.com/v2/locations"
|
||||||
|
{:headers (client-base-headers client)
|
||||||
|
:as :json})
|
||||||
|
:body
|
||||||
|
:locations)
|
||||||
|
(catch Exception e
|
||||||
|
(log/warn e)
|
||||||
|
[])))
|
||||||
|
|
||||||
|
(defn fetch-catalog [client i]
|
||||||
|
(if i
|
||||||
|
(try
|
||||||
|
(log/trace "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 (client-base-headers client)
|
||||||
|
:query-params {"include_related_items" "true"}
|
||||||
|
:as :json})
|
||||||
|
:body
|
||||||
|
:object)
|
||||||
|
(catch Exception e
|
||||||
|
(log/error e)
|
||||||
|
nil))
|
||||||
|
(log/warn "Trying to look up non existant ")))
|
||||||
|
|
||||||
|
(def fetch-catalog-fast (memoize fetch-catalog))
|
||||||
|
|
||||||
|
(defn item-id->category-name [client i]
|
||||||
|
(let [item (fetch-catalog-fast client i)]
|
||||||
|
(cond (: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 client (:category_id (:item_data item)))))
|
||||||
|
|
||||||
|
(:item_data item)
|
||||||
|
"Uncategorized"
|
||||||
|
|
||||||
|
:else
|
||||||
|
(do
|
||||||
|
(log/warn "couldn't look up" i)
|
||||||
|
"Uncategorized"))))
|
||||||
|
|
||||||
|
(defn pc [start end]
|
||||||
|
{"query" {"filter" {"date_time_filter"
|
||||||
|
{
|
||||||
|
"created_at" {
|
||||||
|
"start_at" (f/unparse (f/formatter "YYYY-MM-dd'T'HH:mm:ssZZ") start)
|
||||||
|
"end_at" (f/unparse (f/formatter "YYYY-MM-dd'T'HH:mm:ssZZ") end)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
"sort" {
|
||||||
|
"sort_field" "CREATED_AT"
|
||||||
|
"sort_order" "DESC"
|
||||||
|
}}})
|
||||||
|
|
||||||
|
#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
|
||||||
|
(defn get-order
|
||||||
|
([client location order-id]
|
||||||
|
(log/info "Searching for" (:square-location/client-location location))
|
||||||
|
(let [result (->> (client/get (str "https://connect.squareup.com/v2/orders/" order-id)
|
||||||
|
{:headers (client-base-headers client)
|
||||||
|
:as :json})
|
||||||
|
:body
|
||||||
|
)]
|
||||||
|
result)))
|
||||||
|
|
||||||
|
(defn continue-search [client location start end cursor]
|
||||||
|
(log/info "Continuing search for" cursor)
|
||||||
|
(let [result (->> (client/post "https://connect.squareup.com/v2/orders/search"
|
||||||
|
{:headers (client-base-headers client)
|
||||||
|
:body (json/write-str (cond-> {"location_ids" [(:square-location/square-id location)]
|
||||||
|
"limit" 10000
|
||||||
|
"cursor" cursor}
|
||||||
|
start (merge (pc start end))))
|
||||||
|
:as :json})
|
||||||
|
:body)]
|
||||||
|
(log/info "found " (count (:orders result)))
|
||||||
|
(if (not-empty (:cursor result))
|
||||||
|
(concat (:orders result) (continue-search client location start end (:cursor result)))
|
||||||
|
(:orders result))))
|
||||||
|
|
||||||
|
(defn search
|
||||||
|
([client location start end]
|
||||||
|
(log/info "Searching for" (:square-location/client-location location))
|
||||||
|
(let [result (->> (client/post "https://connect.squareup.com/v2/orders/search"
|
||||||
|
{:headers (client-base-headers client)
|
||||||
|
:body (json/write-str (cond-> {"location_ids" [(:square-location/square-id location)] "limit" 10000}
|
||||||
|
start (merge (pc start end))))
|
||||||
|
:as :json})
|
||||||
|
:body)]
|
||||||
|
(log/info "found " (count (:orders result)))
|
||||||
|
(if (not-empty (:cursor result))
|
||||||
|
(concat (:orders result) (continue-search client location start end (:cursor result)))
|
||||||
|
(:orders result)))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn amount->money [amt]
|
||||||
|
(* 0.01 (or (:amount amt) 0.0)))
|
||||||
|
|
||||||
|
|
||||||
|
;; to get totals:
|
||||||
|
(comment
|
||||||
|
(reduce
|
||||||
|
(fn [total i]
|
||||||
|
(+ total (+ (- (:sales-order/total i)
|
||||||
|
(:sales-order/tax i)
|
||||||
|
(:sales-order/tip i)
|
||||||
|
(:sales-order/service-charge i))
|
||||||
|
(:sales-order/returns i)
|
||||||
|
|
||||||
|
(:sales-order/discount i)
|
||||||
|
)))
|
||||||
|
0.0
|
||||||
|
[]))
|
||||||
|
|
||||||
|
(defn tender->charge [order client location t]
|
||||||
|
(remove-nils
|
||||||
|
#:charge
|
||||||
|
{:type-name (:type t)
|
||||||
|
:date (coerce/to-date (time/to-time-zone (coerce/to-date-time (:created_at order)) (time/time-zone-for-id "America/Los_Angeles")))
|
||||||
|
:client (:db/id client)
|
||||||
|
:note (:note t)
|
||||||
|
:location (:square-location/client-location location)
|
||||||
|
:reference-link (str (url/url "https://squareup.com/receipt/preview" (:id t) ))
|
||||||
|
:external-id (when (:id t)
|
||||||
|
(str "square/charge/" (:id t)))
|
||||||
|
:processor (condp = (:type t)
|
||||||
|
"OTHER"
|
||||||
|
(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
|
||||||
|
"Koala" :ccp-processor/koala
|
||||||
|
"koala-production" :ccp-processor/koala
|
||||||
|
:ccp-processor/na))
|
||||||
|
"CARD"
|
||||||
|
:ccp-processor/square
|
||||||
|
|
||||||
|
"SQUARE_GIFT_CARD"
|
||||||
|
:ccp-processor/square
|
||||||
|
|
||||||
|
"CASH"
|
||||||
|
:ccp-processor/na
|
||||||
|
|
||||||
|
:ccp-processor/na)
|
||||||
|
:total (amount->money (:amount_money t))
|
||||||
|
:tip (amount->money (:tip_money t))}))
|
||||||
|
|
||||||
|
(defn order->sales-order [client location order]
|
||||||
|
(let [is-order-only-for-charge?
|
||||||
|
(= ["CUSTOM_AMOUNT"]
|
||||||
|
(mapv :item_type (:line_items order )))]
|
||||||
|
(if is-order-only-for-charge?
|
||||||
|
(->> (:tenders order)
|
||||||
|
(map #(tender->charge order client location %)))
|
||||||
|
[(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 (:db/id client)
|
||||||
|
:location (:square-location/client-location location)
|
||||||
|
:external-id (str "square/order/" (:client/code client) "-" (:square-location/client-location location) "-" (:id order))
|
||||||
|
:source (or (:name (:source order))
|
||||||
|
"Square")
|
||||||
|
:vendor :vendor/ccp-square
|
||||||
|
|
||||||
|
:reference-link (str (url/url "https://squareup.com/dashboard/sales/transactions" (:id order) "by-unit" (:square-location/square-id location)))
|
||||||
|
: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 #(tender->charge order client location %)))
|
||||||
|
:line-items (->> (:line_items order)
|
||||||
|
(map-indexed (fn [i li]
|
||||||
|
(remove-nils
|
||||||
|
#:order-line-item
|
||||||
|
{:external-id (str "square/order/" (:client/code client) "-" (:square-location/client-location location) "-" (:id order) "-" i)
|
||||||
|
: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
|
||||||
|
([client location]
|
||||||
|
(daily-results client location (time/plus (time/now) (time/days -45)) (time/now)))
|
||||||
|
([client location start end]
|
||||||
|
(let [search-results (search client location start end)]
|
||||||
|
(->> search-results
|
||||||
|
(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)))
|
||||||
|
(or (= #{} (set (map #(:status (:card_details %)) (:tenders order))))
|
||||||
|
(not= #{} (set/difference
|
||||||
|
(set (map #(:status (:card_details %)) (:tenders order)))
|
||||||
|
#{"FAILED" "VOIDED"}))))))
|
||||||
|
(mapcat #(order->sales-order client location %))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn retry
|
||||||
|
([f] (retry f 0))
|
||||||
|
([f i]
|
||||||
|
(if (< i 5)
|
||||||
|
(try
|
||||||
|
(f)
|
||||||
|
(catch Exception e
|
||||||
|
(log/warn "error pulling http " e)
|
||||||
|
(retry f (inc i))))
|
||||||
|
(log/warn "Too many failures"))))
|
||||||
|
|
||||||
|
(defn get-payment [client p]
|
||||||
|
(:payment (:body (retry #(client/get (str "https://connect.squareup.com/v2/payments/" p)
|
||||||
|
{:headers (client-base-headers client)
|
||||||
|
:as :json
|
||||||
|
:retry-handler retry-4})))))
|
||||||
|
(defn halt-if-error [x]
|
||||||
|
(if (instance? Throwable x)
|
||||||
|
(throw x)
|
||||||
|
x))
|
||||||
|
|
||||||
|
(defn get-settlement-sales-date [client settlement]
|
||||||
|
(let [concurrent 4
|
||||||
|
output-chan (async/chan)]
|
||||||
|
(async/pipeline-blocking concurrent
|
||||||
|
output-chan
|
||||||
|
(map (fn [p]
|
||||||
|
(lc/with-context {:source "Square settlements loading "}
|
||||||
|
(log/trace "looking up payment " p " for settlement " (:id settlement))
|
||||||
|
(or
|
||||||
|
(-> (get-payment client p)
|
||||||
|
:created_at
|
||||||
|
coerce/to-date)
|
||||||
|
(coerce/to-date (time/now))))))
|
||||||
|
(async/to-chan! (->> settlement
|
||||||
|
:entries
|
||||||
|
(filter #(= "CHARGE" (:type %)))
|
||||||
|
(map :payment_id)
|
||||||
|
(filter identity)
|
||||||
|
(set)
|
||||||
|
(take 20)
|
||||||
|
))
|
||||||
|
true
|
||||||
|
(fn [e]
|
||||||
|
(lc/with-context {:source "Square settlements loading "}
|
||||||
|
(log/warn "Error loading sales date details" e)
|
||||||
|
e)))
|
||||||
|
(->> (async/<!! (async/into [] output-chan))
|
||||||
|
(map halt-if-error)
|
||||||
|
sort
|
||||||
|
(drop 2)
|
||||||
|
first)))
|
||||||
|
|
||||||
|
(defn get-settlement-details [client location settlements] ;; pairs of [location settlement]
|
||||||
|
(log/info "getting settlement details for " settlements)
|
||||||
|
(let [concurrent 4
|
||||||
|
output-chan (async/chan)]
|
||||||
|
(async/pipeline-blocking concurrent
|
||||||
|
output-chan
|
||||||
|
(map (fn [s]
|
||||||
|
(lc/with-context {:source "Square settlements loading "}
|
||||||
|
(log/info "Looking up settlement " s " for location " (:square-location/client-location location))
|
||||||
|
(let [settlement (:body (retry #(client/get (str "https://connect.squareup.com/v1/" (:square-location/square-id location) "/settlements/" s)
|
||||||
|
{:headers (client-base-headers client)
|
||||||
|
:as :json
|
||||||
|
:retry-handler retry-4})))
|
||||||
|
sales-date (get-settlement-sales-date client settlement)]
|
||||||
|
|
||||||
|
(log/info "sales date for " s " is " sales-date)
|
||||||
|
(assoc settlement :sales-date sales-date)))))
|
||||||
|
(async/to-chan! settlements)
|
||||||
|
true
|
||||||
|
(fn [e]
|
||||||
|
(lc/with-context {:source "Square settlements loading "}
|
||||||
|
(log/warn "Error loading settlements details" e)
|
||||||
|
e)))
|
||||||
|
(->> (async/<!! (async/into [] output-chan))
|
||||||
|
(map halt-if-error))))
|
||||||
|
|
||||||
|
(defn settlements
|
||||||
|
([client location] (settlements client location (lookup-dates)))
|
||||||
|
([client location lookup-dates]
|
||||||
|
(log/info "Searching for" (:square-location/client-location location))
|
||||||
|
(->> lookup-dates
|
||||||
|
(mapcat (fn [[start-date end-date]]
|
||||||
|
(log/info "looking up settlements for " (:square-location/client-location location) " on dates " start-date " to " end-date)
|
||||||
|
(let [settlements (->> (retry #(client/get (str "https://connect.squareup.com/v1/" (:square-location/square-id location) "/settlements")
|
||||||
|
{:headers (client-base-headers client)
|
||||||
|
:query-params {"begin_time" start-date
|
||||||
|
"end_time" end-date}
|
||||||
|
:as :json
|
||||||
|
:retry-handler retry-4}))
|
||||||
|
:body
|
||||||
|
(map :id))]
|
||||||
|
settlements)))
|
||||||
|
set
|
||||||
|
seq
|
||||||
|
(get-settlement-details client location))))
|
||||||
|
|
||||||
|
(defn daily-settlements
|
||||||
|
([client location]
|
||||||
|
(->> (for [settlement (settlements client location)]
|
||||||
|
#:expected-deposit {:external-id (str "square/settlement/" (:id settlement))
|
||||||
|
:vendor :vendor/ccp-square
|
||||||
|
:status :expected-deposit-status/pending
|
||||||
|
:total (amount->money (:total_money settlement))
|
||||||
|
:client (:db/id client)
|
||||||
|
:location (:square-location/client-location 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)))
|
||||||
|
:charges (->> (:entries settlement)
|
||||||
|
(filter :payment_id)
|
||||||
|
(map (fn [p] {:charge/external-id (str "square/charge/" (:payment_id p))})))})
|
||||||
|
|
||||||
|
(filter :expected-deposit/date))))
|
||||||
|
|
||||||
|
(defn refunds
|
||||||
|
([client l]
|
||||||
|
(let [refunds (:refunds (:body (client/get (str "https://connect.squareup.com/v2/refunds?location_id=" (:square-location/square-id l))
|
||||||
|
{:headers (client-base-headers client)
|
||||||
|
:as :json
|
||||||
|
:retry-handler retry-4})))]
|
||||||
|
(->> refunds
|
||||||
|
(filter (fn [r] (= "COMPLETED" (:status r))))
|
||||||
|
(map (fn [r]
|
||||||
|
#:sales-refund {:external-id (str "square/refund/" (:id r))
|
||||||
|
:vendor :vendor/ccp-square
|
||||||
|
:total (amount->money (:amount_money r))
|
||||||
|
:fee (transduce
|
||||||
|
(comp (filter #(= "ADJUSTMENT" (:type %)))
|
||||||
|
(map :amount_money)
|
||||||
|
(map amount->money))
|
||||||
|
+
|
||||||
|
0.0
|
||||||
|
(:processing_fee r))
|
||||||
|
:client (:db/id client)
|
||||||
|
:location (:square-location/client-location l)
|
||||||
|
:date (coerce/to-date (:created_at r))
|
||||||
|
:type (:source_type (get-payment client (:payment_id r)))}))))))
|
||||||
|
|
||||||
|
(defn upsert
|
||||||
|
([client ]
|
||||||
|
(doseq [square-location (:client/square-locations client)
|
||||||
|
:when (:square-location/client-location square-location)]
|
||||||
|
(upsert client square-location (time/plus (time/now) (time/days -45)) (time/now))))
|
||||||
|
([client location start end]
|
||||||
|
(lc/with-context {:source "Square loading"}
|
||||||
|
(doseq [x (partition-all 20 (daily-results client location start end))]
|
||||||
|
(log/info "Loading " (count x))
|
||||||
|
@(d/transact conn x)))))
|
||||||
|
|
||||||
|
(defn upsert-settlements
|
||||||
|
([client]
|
||||||
|
(doseq [square-location (:client/square-locations client)
|
||||||
|
:when (:square-location/client-location square-location)]
|
||||||
|
(upsert-settlements client square-location)))
|
||||||
|
([client location]
|
||||||
|
(lc/with-context {:source "Square settlements loading"
|
||||||
|
:client (:client/code client)}
|
||||||
|
(doseq [x (partition-all 20 (daily-settlements client location))]
|
||||||
|
(log/info "Loading expected deposit" (count x))
|
||||||
|
@(d/transact conn x))
|
||||||
|
(log/info "Done loading settlements"))))
|
||||||
|
|
||||||
|
(defn upsert-refunds
|
||||||
|
([client]
|
||||||
|
(doseq [square-location (:client/square-locations client)
|
||||||
|
:when (:square-location/client-location square-location)]
|
||||||
|
(upsert-refunds client square-location)))
|
||||||
|
([client location]
|
||||||
|
(lc/with-context {:source "Loading Square Settlements"
|
||||||
|
:client (:client/code client)
|
||||||
|
:location (:square-location/client-location client)}
|
||||||
|
(doseq [x (partition-all 20 (refunds client location))]
|
||||||
|
(log/info "Loading refund" (count x))
|
||||||
|
@(d/transact conn x))
|
||||||
|
(log/info "Done loading refunds"))))
|
||||||
|
|
||||||
|
(def square-read [:db/id
|
||||||
|
:client/code
|
||||||
|
:client/square-auth-token
|
||||||
|
{:client/square-locations [:db/id :square-location/name :square-location/square-id :square-location/client-location]}])
|
||||||
|
|
||||||
|
(defn get-square-clients
|
||||||
|
([]
|
||||||
|
(d/q '[:find [(pull ?c [:db/id
|
||||||
|
:client/square-integration-status
|
||||||
|
:client/code
|
||||||
|
:client/square-auth-token
|
||||||
|
{:client/square-locations [:db/id :square-location/name :square-location/square-id :square-location/client-location]}]) ...]
|
||||||
|
:in $
|
||||||
|
:where [?c :client/square-auth-token]
|
||||||
|
[?c :client/feature-flags "new-square"]]
|
||||||
|
(d/db conn)))
|
||||||
|
([ & codes]
|
||||||
|
(d/q '[:find [(pull ?c [:db/id
|
||||||
|
:client/code
|
||||||
|
:client/square-auth-token
|
||||||
|
{:client/square-locations [:db/id :square-location/name :square-location/square-id :square-location/client-location]}]) ...]
|
||||||
|
:in $ [?code ...]
|
||||||
|
:where [?c :client/square-auth-token]
|
||||||
|
[?c :client/feature-flags "new-square"]
|
||||||
|
[?c :client/code ?code]]
|
||||||
|
(d/db conn)
|
||||||
|
codes)))
|
||||||
|
|
||||||
|
(defn upsert-locations
|
||||||
|
([] (doseq [client (get-square-clients)]
|
||||||
|
(upsert-locations client)))
|
||||||
|
([client]
|
||||||
|
(let [square-id->id (into {}
|
||||||
|
(map
|
||||||
|
(fn [sl]
|
||||||
|
[(:square-location/square-id sl)
|
||||||
|
(:db/id sl)])
|
||||||
|
(:client/square-locations client)))]
|
||||||
|
(->> (for [square-location (client-locations client)]
|
||||||
|
{:db/id (or (square-id->id (:id square-location)) (d/tempid :db.part/user))
|
||||||
|
:client/_square-locations (:db/id client)
|
||||||
|
:square-location/name (:name square-location)
|
||||||
|
:square-location/square-id (:id square-location)})
|
||||||
|
(d/transact conn)
|
||||||
|
deref))))
|
||||||
|
|
||||||
|
#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
|
||||||
|
(defn reset []
|
||||||
|
(->>
|
||||||
|
(d/query {:query {:find ['?e]
|
||||||
|
:in ['$]
|
||||||
|
:where ['(or [?e :sales-order/date]
|
||||||
|
[?e :expected-deposit/date])]}
|
||||||
|
:args [(d/db conn)]})
|
||||||
|
(map first)
|
||||||
|
(map (fn [x] [:db/retractEntity x]))))
|
||||||
|
|
||||||
|
(defn mark-integration-status [client integration-status]
|
||||||
|
@(d/transact conn
|
||||||
|
[{:db/id (:db/id client)
|
||||||
|
:client/square-integration-status (assoc integration-status
|
||||||
|
:db/id (or (-> client :client/square-integration-status :db/id)
|
||||||
|
#db/id [:db.part/user]))}]))
|
||||||
|
|
||||||
|
(defn upsert-all [ & clients]
|
||||||
|
(doseq [client (apply get-square-clients clients)
|
||||||
|
:when (seq (filter :square-location/client-location (:client/square-locations client)))]
|
||||||
|
(lc/with-context {:client (:client/code client)}
|
||||||
|
(mark-integration-status client {:integration-status/last-attempt (coerce/to-date (time/now))})
|
||||||
|
|
||||||
|
(try+
|
||||||
|
(upsert-locations client)
|
||||||
|
(upsert client)
|
||||||
|
(upsert-settlements client)
|
||||||
|
(upsert-refunds client)
|
||||||
|
(mark-integration-status client {:integration-status/state :integration-state/success
|
||||||
|
:integration-status/last-updated (coerce/to-date (time/now))})
|
||||||
|
|
||||||
|
(catch [:status 401] data
|
||||||
|
(mark-integration-status client {:integration-status/state :integration-state/unauthorized
|
||||||
|
:integration-status/message (-> data :body str)}))
|
||||||
|
|
||||||
|
(catch [:status 503] data
|
||||||
|
(mark-integration-status client {:integration-status/state :integration-state/failed
|
||||||
|
:integration-status/message (-> data :body str)}))
|
||||||
|
|
||||||
|
(catch Object _
|
||||||
|
(log/warn &throw-context)
|
||||||
|
(mark-integration-status client {:integration-status/state :integration-state/failed
|
||||||
|
:integration-status/message (or (some-> (:wrapper &throw-context) (.getMessage ))
|
||||||
|
(some-> (:object &throw-context) str)
|
||||||
|
"Unknown error")}))))))
|
||||||
|
|
||||||
@@ -24,6 +24,14 @@
|
|||||||
[form-builder/builder {:submit-event [::saving ]
|
[form-builder/builder {:submit-event [::saving ]
|
||||||
:id ::form}
|
:id ::form}
|
||||||
[form-builder/section {:title "Sales Order"}
|
[form-builder/section {:title "Sales Order"}
|
||||||
|
[:div
|
||||||
|
"Order " (:id data)
|
||||||
|
(when (:reference-link data)
|
||||||
|
[:a {:href (:reference-link data)
|
||||||
|
:target "_new"}
|
||||||
|
[:span.icon
|
||||||
|
[:i.fa.fa-external-link
|
||||||
|
]]])]
|
||||||
(when-not @(re-frame/subscribe [::subs/client])
|
(when-not @(re-frame/subscribe [::subs/client])
|
||||||
[form-builder/field-v2 {:field :client}
|
[form-builder/field-v2 {:field :client}
|
||||||
"Client"
|
"Client"
|
||||||
@@ -62,7 +70,12 @@
|
|||||||
[:ul
|
[:ul
|
||||||
(for [charge (:charges data)]
|
(for [charge (:charges data)]
|
||||||
^{:key (:id charge)}
|
^{:key (:id charge)}
|
||||||
[:li (:type-name charge) ": " (:total charge)])]]
|
[:li [:span (:type-name charge) ": " (:total charge)
|
||||||
|
(when (:reference-link charge)
|
||||||
|
[:a {:href (:reference-link charge) :target "_new"}
|
||||||
|
[:span.icon
|
||||||
|
[:i.fa.fa-external-link
|
||||||
|
]]])]])]]
|
||||||
|
|
||||||
[form-builder/section {:title "Line Items"}
|
[form-builder/section {:title "Line Items"}
|
||||||
[:ul
|
[:ul
|
||||||
|
|||||||
@@ -25,13 +25,14 @@
|
|||||||
{:start (:start params 0)
|
{:start (:start params 0)
|
||||||
:sort (:sort params)
|
:sort (:sort params)
|
||||||
:per-page (:per-page params)
|
:per-page (:per-page params)
|
||||||
|
:type-name (:type-name params)
|
||||||
:total-gte (:amount-gte (:total-range params))
|
:total-gte (:amount-gte (:total-range params))
|
||||||
:total-lte (:amount-lte (:total-range params))
|
:total-lte (:amount-lte (:total-range params))
|
||||||
:date-range (:date-range params)
|
:date-range (:date-range params)
|
||||||
:processor (some-> (:processor params) keyword)
|
:processor (some-> (:processor params) keyword)
|
||||||
:client-id (:id @(re-frame/subscribe [::subs/client]))}
|
:client-id (:id @(re-frame/subscribe [::subs/client]))}
|
||||||
[[:sales-orders [:id :total :tax :tip :discount :service-charge :returns :date
|
[[:sales-orders [:id :source :total :tax :tip :reference-link :discount :service-charge :returns :date
|
||||||
[:charges [:type-name :total :processor :id [:expected-deposit [:id]] ]]
|
[:charges [:type-name :note :reference-link :total :processor :id [:expected-deposit [:id]] ]]
|
||||||
[:line-items [:item-name :total :category]]
|
[:line-items [:item-name :total :category]]
|
||||||
[:client [:name :id]]]]
|
[:client [:name :id]]]]
|
||||||
:total
|
:total
|
||||||
|
|||||||
@@ -39,9 +39,40 @@
|
|||||||
|
|
||||||
(when (= :sales-orders ap)
|
(when (= :sales-orders ap)
|
||||||
[:<>
|
[:<>
|
||||||
|
[:p.menu-label "Payment Method"]
|
||||||
|
[:div
|
||||||
|
[:nav.panel
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :type-name nil])}
|
||||||
|
[:span.panel-icon]
|
||||||
|
"All"]
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :type-name "CASH"])}
|
||||||
|
[:span.panel-icon
|
||||||
|
[:span {:class "icon-accounting-bill" :style {:font-weight "400"}}]]
|
||||||
|
"Cash"]
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :type-name "CARD"])}
|
||||||
|
[:span.panel-icon
|
||||||
|
[:span {:class "icon-credit-card-1" :style {:font-weight "400"}}]]
|
||||||
|
"Card"]
|
||||||
|
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :type-name "SQUARE_GIFT_CARD"])}
|
||||||
|
[:span.panel-icon
|
||||||
|
[:span {:class "icon-gift-box" :style {:font-weight "400"}}]]
|
||||||
|
"Gift Card"]
|
||||||
|
|
||||||
|
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :type-name "OTHER"])}
|
||||||
|
[:span.panel-icon ]
|
||||||
|
"Other"]]]
|
||||||
|
|
||||||
[:p.menu-label "Processor"]
|
[:p.menu-label "Processor"]
|
||||||
[:div
|
[:div
|
||||||
[:nav.panel
|
[:nav.panel
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :processor nil])}
|
||||||
|
[:span.panel-icon]
|
||||||
|
"All"]
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :processor "square"])}
|
||||||
|
[:span.panel-icon [:img.level-item {:src "/img/square.png"}]]
|
||||||
|
"Square"]
|
||||||
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :processor "doordash"])}
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :processor "doordash"])}
|
||||||
[:span.panel-icon [:img.level-item {:src "/img/doordash.png"}]]
|
[:span.panel-icon [:img.level-item {:src "/img/doordash.png"}]]
|
||||||
"Doordash"]
|
"Doordash"]
|
||||||
@@ -51,7 +82,17 @@
|
|||||||
"Uber Eats"]
|
"Uber Eats"]
|
||||||
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :processor "grubhub"])}
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :processor "grubhub"])}
|
||||||
[:span.panel-icon [:img.level-item {:src "/img/grubhub.png"}]]
|
[:span.panel-icon [:img.level-item {:src "/img/grubhub.png"}]]
|
||||||
"Grubhub"]]]])
|
"Grubhub"]
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :processor "koala"])}
|
||||||
|
[:span.panel-icon [:img.level-item {:src "/img/koala.png"}]]
|
||||||
|
"Koala"]
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :processor "ezcater"])}
|
||||||
|
[:span.panel-icon [:img.level-item {:src "/img/ezcater.png"}]]
|
||||||
|
"EZCater"]
|
||||||
|
[:a.panel-block {:on-click (dispatch-event [::data-page/filter-changed data-page :processor "na"])}
|
||||||
|
[:span.panel-icon #_[:img.level-item {:src "/img/grubhub.png"}]]
|
||||||
|
"No Processor"]
|
||||||
|
]]])
|
||||||
|
|
||||||
(when-let [exact-match-id @(re-frame/subscribe [::data-page/filter data-page :exact-match-id])]
|
(when-let [exact-match-id @(re-frame/subscribe [::data-page/filter data-page :exact-match-id])]
|
||||||
[:div
|
[:div
|
||||||
|
|||||||
@@ -17,15 +17,36 @@
|
|||||||
|
|
||||||
(defn row [{sales-order :sales-order
|
(defn row [{sales-order :sales-order
|
||||||
selected-client :selected-client}]
|
selected-client :selected-client}]
|
||||||
(let [{:keys [client date total tax tip charges line-items id]} sales-order
|
(let [{:keys [client date total tax tip charges source line-items id]} sales-order
|
||||||
expected-deposits (->> charges (filter :expected-deposit) (map :expected-deposit))]
|
expected-deposits (->> charges (filter :expected-deposit) (map :expected-deposit))]
|
||||||
[grid/row {:class (:class sales-order) :id id}
|
[grid/row {:class (:class sales-order) :id id}
|
||||||
(when-not selected-client
|
(when-not selected-client
|
||||||
[grid/cell {} (:name client)])
|
[grid/cell {} (:name client)])
|
||||||
[grid/cell {} (date->str date)]
|
[grid/cell {} (date->str date)]
|
||||||
|
[grid/cell {} source]
|
||||||
[grid/cell {:class "has-text-right"} (nf total)]
|
[grid/cell {:class "has-text-right"} (nf total)]
|
||||||
[grid/cell {:class "has-text-right"} (nf tax)]
|
[grid/cell {:class "has-text-right"} (nf tax)]
|
||||||
[grid/cell {:class "has-text-right"} (nf tip)]
|
[grid/cell {:class "has-text-right"} (nf tip)]
|
||||||
|
[grid/cell {}
|
||||||
|
[:div.level-left
|
||||||
|
(for [charge charges]
|
||||||
|
|
||||||
|
(with-meta
|
||||||
|
(condp = (:type-name charge)
|
||||||
|
"CASH"
|
||||||
|
[:span.icon.level-item {:style {:font-size "24px"}} [:span {:class "icon-accounting-bill" :style {:font-weight "400"}}]]
|
||||||
|
|
||||||
|
"CARD"
|
||||||
|
[:span.icon.level-item {:style {:font-size "24px"}} [:span {:class "icon-credit-card-1" :style {:font-weight "400"}}]]
|
||||||
|
|
||||||
|
"SQUARE_GIFT_CARD"
|
||||||
|
[:span.icon.level-item {:style {:font-size "24px"}} [:span {:class "icon-gift-box" :style {:font-weight "400"}}]]
|
||||||
|
|
||||||
|
[:span.level-item [:span (:type-name charge) (when-let [note (:note charge)]
|
||||||
|
[:span
|
||||||
|
[:i.has-text-grey " (" note ")"]])] ])
|
||||||
|
|
||||||
|
{:key (:id charge)}))]]
|
||||||
[grid/cell {}
|
[grid/cell {}
|
||||||
[:div.level
|
[:div.level
|
||||||
[:div.level-left
|
[:div.level-left
|
||||||
@@ -42,17 +63,15 @@
|
|||||||
:uber-eats
|
:uber-eats
|
||||||
[:img.level-item {:src "/img/ubereats.png" :style {:width "24px" :height "24px"}}]
|
[:img.level-item {:src "/img/ubereats.png" :style {:width "24px" :height "24px"}}]
|
||||||
|
|
||||||
(condp = (:type-name charge)
|
:square
|
||||||
"CASH"
|
[:img.level-item {:src "/img/square.png" :style {:width "24px" :height "24px"}}]
|
||||||
[:span.icon.level-item {:style {:font-size "24px"}} [:span {:class "icon-accounting-bill" :style {:font-weight "400"}}]]
|
|
||||||
|
|
||||||
"CARD"
|
:koala
|
||||||
[:span.icon.level-item {:style {:font-size "24px"}} [:span {:class "icon-credit-card-1" :style {:font-weight "400"}}]]
|
[:img.level-item {:src "/img/koala.png" :style {:width "24px" :height "24px"}}]
|
||||||
|
|
||||||
"SQUARE_GIFT_CARD"
|
:ezcater
|
||||||
[:span.icon.level-item {:style {:font-size "24px"}} [:span {:class "icon-gift-box" :style {:font-weight "400"}}]]
|
[:img.level-item {:src "/img/ezcater.png" :style {:width "24px" :height "24px"}}]
|
||||||
|
nil)
|
||||||
[:span.level-item "Other (" (:type-name charge) ")"]))
|
|
||||||
|
|
||||||
{:key (:id charge)}))]]]
|
{:key (:id charge)}))]]]
|
||||||
|
|
||||||
@@ -105,10 +124,12 @@
|
|||||||
(when-not selected-client
|
(when-not selected-client
|
||||||
[grid/sortable-header-cell {:sort-key "client" :sort-name "Client"} "Client"])
|
[grid/sortable-header-cell {:sort-key "client" :sort-name "Client"} "Client"])
|
||||||
[grid/sortable-header-cell {:sort-key "date" :sort-name "Date" :style {:width "8em"}} "Date"]
|
[grid/sortable-header-cell {:sort-key "date" :sort-name "Date" :style {:width "8em"}} "Date"]
|
||||||
|
[grid/sortable-header-cell {:sort-key "source" :sort-name "Source"} "Source"]
|
||||||
[grid/sortable-header-cell {:sort-key "total" :sort-name "Total" :class "has-text-right" :style {:width "8em"}} "Total"]
|
[grid/sortable-header-cell {:sort-key "total" :sort-name "Total" :class "has-text-right" :style {:width "8em"}} "Total"]
|
||||||
[grid/sortable-header-cell {:sort-key "tax" :sort-name "Tax" :class "has-text-right" :style {:width "7em"}} "Tax"]
|
[grid/sortable-header-cell {:sort-key "tax" :sort-name "Tax" :class "has-text-right" :style {:width "7em"}} "Tax"]
|
||||||
[grid/sortable-header-cell {:sort-key "tip" :sort-name "Tip" :class "has-text-right" :style {:width "7em"}} "Tip"]
|
[grid/sortable-header-cell {:sort-key "tip" :sort-name "Tip" :class "has-text-right" :style {:width "7em"}} "Tip"]
|
||||||
[grid/header-cell {} "Payment Methods"]
|
[grid/header-cell {} "Payment Methods"]
|
||||||
|
[grid/header-cell {} "Processor"]
|
||||||
[grid/header-cell {} "Line Items"]
|
[grid/header-cell {} "Line Items"]
|
||||||
[grid/header-cell {:style {:width "8em"}}]]]
|
[grid/header-cell {:style {:width "8em"}}]]]
|
||||||
[grid/body
|
[grid/body
|
||||||
|
|||||||
@@ -86,48 +86,23 @@
|
|||||||
"2022-06-01T07:00:00Z")
|
"2022-06-01T07:00:00Z")
|
||||||
(sut/order->sales-order)
|
(sut/order->sales-order)
|
||||||
(:sales-order/date )))))
|
(:sales-order/date )))))
|
||||||
(t/testing "It should categorize every item as 'External Catering'"
|
(t/testing "It should simulate a single line item for everything"
|
||||||
(t/is (= 2
|
(t/is (= 1
|
||||||
(-> known-order
|
(-> known-order
|
||||||
sut/order->sales-order
|
sut/order->sales-order
|
||||||
:sales-order/line-items
|
:sales-order/line-items
|
||||||
count)))
|
count)))
|
||||||
(t/is (= #{"External Catering"}
|
(t/is (= #{"EZCater Catering"}
|
||||||
(->> known-order
|
(->> known-order
|
||||||
sut/order->sales-order
|
sut/order->sales-order
|
||||||
:sales-order/line-items
|
:sales-order/line-items
|
||||||
(map :order-line-item/category)
|
(map :order-line-item/category)
|
||||||
set))))
|
set))))
|
||||||
|
|
||||||
|
|
||||||
(t/testing "It should generate an id for every line item"
|
|
||||||
(t/is (= ["ezcater/order/ABC-DT-9ab05fee-a9c5-483b-a7f2-14debde4b7a8-0"
|
|
||||||
"ezcater/order/ABC-DT-9ab05fee-a9c5-483b-a7f2-14debde4b7a8-1"]
|
|
||||||
(->> known-order
|
|
||||||
sut/order->sales-order
|
|
||||||
:sales-order/line-items
|
|
||||||
(map :order-line-item/external-id)))))
|
|
||||||
|
|
||||||
(t/testing "It should generate an external-id"
|
(t/testing "It should generate an external-id"
|
||||||
(t/is (= "ezcater/order/ABC-DT-9ab05fee-a9c5-483b-a7f2-14debde4b7a8"
|
(t/is (= "ezcater/order/ABC-DT-9ab05fee-a9c5-483b-a7f2-14debde4b7a8"
|
||||||
(:sales-order/external-id (sut/order->sales-order known-order)))))
|
(:sales-order/external-id (sut/order->sales-order known-order)))))
|
||||||
|
|
||||||
(t/testing "Should include package name"
|
|
||||||
(t/is (= #{"Spartan Package"}
|
|
||||||
(->> known-order
|
|
||||||
sut/order->sales-order
|
|
||||||
:sales-order/line-items
|
|
||||||
(map :order-line-item/item-name)
|
|
||||||
set))))
|
|
||||||
|
|
||||||
(t/testing "Should use the total amount"
|
|
||||||
(t/is (= [34.29 206.75]
|
|
||||||
(->> (-> known-order
|
|
||||||
(assoc-in [:catererCart :orderItems 0 :totalInSubunits :subunits] 3429)
|
|
||||||
(assoc-in [:catererCart :orderItems 1 :totalInSubunits :subunits] 20675))
|
|
||||||
sut/order->sales-order
|
|
||||||
:sales-order/line-items
|
|
||||||
(map :order-line-item/total)))))
|
|
||||||
|
|
||||||
(t/testing "Should capture amounts"
|
(t/testing "Should capture amounts"
|
||||||
(t/is (= 35.09 (-> known-order
|
(t/is (= 35.09 (-> known-order
|
||||||
@@ -147,7 +122,7 @@
|
|||||||
(-> known-order
|
(-> known-order
|
||||||
(assoc :orderSourceType "EZCATER")
|
(assoc :orderSourceType "EZCATER")
|
||||||
(assoc-in [:totals :subTotal :subunits] 10000)
|
(assoc-in [:totals :subTotal :subunits] 10000)
|
||||||
(assoc-in [:catererCart :feesAndDiscounts 0 :subunits] 10000)
|
(assoc-in [:catererCart :feesAndDiscounts 0 :cost :subunits] 10000)
|
||||||
sut/commision)))))
|
sut/commision)))))
|
||||||
(t/testing "Should calculate 15% commision on marketplace orders"
|
(t/testing "Should calculate 15% commision on marketplace orders"
|
||||||
(t/is (dollars= 15.0
|
(t/is (dollars= 15.0
|
||||||
@@ -160,7 +135,7 @@
|
|||||||
(-> known-order
|
(-> known-order
|
||||||
(assoc :orderSourceType "MARKETPLACE")
|
(assoc :orderSourceType "MARKETPLACE")
|
||||||
(assoc-in [:totals :subTotal :subunits] 10000)
|
(assoc-in [:totals :subTotal :subunits] 10000)
|
||||||
(assoc-in [:catererCart :feesAndDiscounts 0 :subunits] 10000)
|
(assoc-in [:catererCart :feesAndDiscounts 0 :cost :subunits] 10000)
|
||||||
sut/commision)))))
|
sut/commision)))))
|
||||||
(t/testing "Should calculate 2.75% ccp fee"
|
(t/testing "Should calculate 2.75% ccp fee"
|
||||||
(t/is (dollars= 8.25
|
(t/is (dollars= 8.25
|
||||||
@@ -168,10 +143,10 @@
|
|||||||
(assoc :orderSourceType "MARKETPLACE")
|
(assoc :orderSourceType "MARKETPLACE")
|
||||||
(assoc-in [:totals :subTotal :subunits] 10000)
|
(assoc-in [:totals :subTotal :subunits] 10000)
|
||||||
(assoc-in [:totals :salesTax :subunits] 10000)
|
(assoc-in [:totals :salesTax :subunits] 10000)
|
||||||
(assoc-in [:catererCart :feesAndDiscounts 0 :subunits] 10000)
|
(assoc-in [:catererCart :feesAndDiscounts 0 :cost :subunits] 10000)
|
||||||
sut/ccp-fee))))
|
sut/ccp-fee))))
|
||||||
(t/testing "Should use ezcater total paid to the customer"
|
(t/testing "Should use ezcater total paid to the customer"
|
||||||
(t/is (dollars= 420.65
|
(t/is (dollars= 454.09
|
||||||
(-> known-order
|
(-> known-order
|
||||||
sut/order->sales-order
|
sut/order->sales-order
|
||||||
:sales-order/total))))
|
:sales-order/total))))
|
||||||
@@ -179,6 +154,14 @@
|
|||||||
(t/is (dollars= -41.8975
|
(t/is (dollars= -41.8975
|
||||||
(-> known-order
|
(-> known-order
|
||||||
sut/order->sales-order
|
sut/order->sales-order
|
||||||
:sales-order/discount)))))
|
:sales-order/discount))))
|
||||||
|
|
||||||
|
(t/testing "Should create a charge for the order"
|
||||||
|
(t/is (dollars= 454.09
|
||||||
|
(-> known-order
|
||||||
|
sut/order->sales-order
|
||||||
|
:sales-order/charges
|
||||||
|
first
|
||||||
|
:charge/total)))))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user