EZ cater is available now.
This commit is contained in:
@@ -290,5 +290,7 @@
|
||||
:db/index true}
|
||||
{:db/ident :sales-order/client
|
||||
:db/index true}]]
|
||||
:requires [:add-orders]}})
|
||||
:requires [:add-orders]}
|
||||
:add-ezcater-vendor {:txes [[{:db/ident :vendor/ccp-ezcater
|
||||
:vendor/name "EZCater CCP"}]]}})
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
[clj-time.coerce :as coerce]
|
||||
[clojure.tools.logging :as log]
|
||||
[clj-time.core :as time]
|
||||
[clojure.set :as set]))
|
||||
[clojure.set :as set]
|
||||
[auto-ap.time :as atime]))
|
||||
|
||||
(defn query [{:ezcater-integration/keys [api-key]} q]
|
||||
(-> (client/post "https://api.ezcater.com/graphql/"
|
||||
@@ -89,8 +90,7 @@
|
||||
:parentId parentId
|
||||
:eventEntity 'Order
|
||||
:eventKey 'cancelled}}
|
||||
[[:subscription [:parentId :parentEntity :eventEntity :eventKey]]]]]}))
|
||||
)))
|
||||
[[:subscription [:parentId :parentEntity :eventEntity :eventKey]]]]]})))))
|
||||
|
||||
#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
|
||||
(defn upsert-ezcater
|
||||
@@ -109,5 +109,127 @@
|
||||
(mark-integration-status integration {:integration-status/state :integration-state/failed
|
||||
:integration-status/message (.getMessage e)}))))))
|
||||
|
||||
(defn get-caterer [caterer-uuid]
|
||||
(d/pull (d/db conn)
|
||||
'[:ezcater-caterer/name
|
||||
{:ezcater-integration/_caterers [:ezcater-integration/api-key]}
|
||||
{:ezcater-location/_caterer [:ezcater-location/location
|
||||
{:client/_ezcater-locations [:client/code]}]}]
|
||||
[:ezcater-caterer/uuid caterer-uuid]))
|
||||
|
||||
|
||||
|
||||
(defn commision [order]
|
||||
(let [commision% (if (= "MARKETPLACE" (:orderSourceType order))
|
||||
0.15
|
||||
0.07)]
|
||||
(* commision%
|
||||
0.01
|
||||
(+
|
||||
(-> order :totals :subTotal :subunits )
|
||||
(reduce +
|
||||
0
|
||||
(map :subunits (:feesAndDiscounts (:catererCart order))))))))
|
||||
|
||||
(defn ccp-fee [order]
|
||||
(* 0.000275
|
||||
(+
|
||||
(-> order :totals :subTotal :subunits )
|
||||
(-> order :totals :salesTax :subunits )
|
||||
(reduce +
|
||||
0
|
||||
(map :subunits (:feesAndDiscounts (:catererCart order)))))))
|
||||
|
||||
(defn order->sales-order [{{:keys [timestamp]} :event {:keys [orderItems]} :catererCart :keys [client-code client-location uuid] :as order}]
|
||||
#:sales-order
|
||||
{:date (atime/localize (coerce/to-date-time timestamp))
|
||||
:external-id (str "ezcater/order/" client-code "-" client-location "-" uuid)
|
||||
:client [:client/code client-code]
|
||||
:location client-location
|
||||
:line-items (->> orderItems
|
||||
(map-indexed (fn [i li]
|
||||
#:order-line-item
|
||||
{:external-id (str "ezcater/order/" client-code "-" client-location "-" uuid "-" i)
|
||||
:item-name (:name li)
|
||||
:category "External Catering"
|
||||
:total (* 0.01 (:subunits (:totalInSubunits li)))})))
|
||||
|
||||
:total (-> order :catererCart :totals :catererTotalDue )
|
||||
:discount (- (+ (-> 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))
|
||||
:vendor :vendor/ccp-ezcater})
|
||||
|
||||
(defn lookup-order [json]
|
||||
(let [caterer (get-caterer (get json "parent_id"))
|
||||
integration (:ezcater-integration/_caterers caterer)
|
||||
client (-> caterer :ezcater-location/_caterer first :client/_ezcater-locations :client/code)
|
||||
location (-> caterer :ezcater-location/_caterer first :ezcater-location/location)]
|
||||
(-> (query
|
||||
integration
|
||||
{:venia/queries [[:order {:id (get json "entity_id")}
|
||||
[:uuid
|
||||
:orderSourceType
|
||||
[:caterer
|
||||
[:name
|
||||
:uuid
|
||||
[:address [:street]]]]
|
||||
[:event
|
||||
[:timestamp
|
||||
:catererHandoffFoodTime
|
||||
:orderType]]
|
||||
[:catererCart [[:orderItems
|
||||
[:name
|
||||
:quantity
|
||||
:posItemId
|
||||
[:totalInSubunits
|
||||
[:currency
|
||||
:subunits]]]]
|
||||
[:totals
|
||||
[:catererTotalDue]]
|
||||
[:feesAndDiscounts
|
||||
{:type 'DELIVERY_FEE}
|
||||
[[:cost
|
||||
[:currency
|
||||
:subunits]]]]]]
|
||||
[:totals [[:customerTotalDue
|
||||
[
|
||||
:currency
|
||||
:subunits
|
||||
]]
|
||||
[:pointOfSaleIntegrationFee
|
||||
[
|
||||
:currency
|
||||
:subunits
|
||||
]]
|
||||
[:tip
|
||||
[:currency
|
||||
:subunits]]
|
||||
[:salesTax
|
||||
[
|
||||
:currency
|
||||
:subunits
|
||||
]]
|
||||
[:salesTaxRemittance
|
||||
[:currency
|
||||
:subunits
|
||||
]]
|
||||
[:subTotal
|
||||
[:currency
|
||||
:subunits]]]]]]]})
|
||||
(:order)
|
||||
(assoc :client-code client
|
||||
:client-location location))))
|
||||
|
||||
(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"}
|
||||
@(d/transact conn [(-> json
|
||||
(lookup-order)
|
||||
(order->sales-order)
|
||||
(update :sales-order/date coerce/to-date))])
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[clojure.tools.logging :as log]
|
||||
[compojure.core :refer [context defroutes GET POST wrap-routes]]
|
||||
[ring.middleware.json :refer [wrap-json-params]]
|
||||
[auto-ap.ezcater.core :as e]
|
||||
[ring.util.request :refer [body-string]]))
|
||||
|
||||
(defroutes routes
|
||||
@@ -14,8 +15,9 @@
|
||||
:headers {"Content-Type" "application/json"}
|
||||
:body "{}"})
|
||||
(POST "/event" request
|
||||
;; {"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"}
|
||||
(log/info (str "POST EVENT " (body-string request) request))
|
||||
(e/import-order (:json-params request))
|
||||
|
||||
{:status 200
|
||||
:headers {"Content-Type" "application/json"}
|
||||
:body "{}"}))
|
||||
|
||||
184
test/clj/auto_ap/ezcater_test.clj
Normal file
184
test/clj/auto_ap/ezcater_test.clj
Normal file
@@ -0,0 +1,184 @@
|
||||
(ns auto-ap.ezcater-test
|
||||
(:require [auto-ap.ezcater.core :as sut]
|
||||
[clojure.test :as t]
|
||||
[datomic.api :as d ]
|
||||
[auto-ap.utils :refer [dollars=]]
|
||||
[auto-ap.datomic :refer [uri]]
|
||||
[auto-ap.datomic.migrate :as m]
|
||||
[auto-ap.time-reader]))
|
||||
|
||||
|
||||
(defn wrap-setup
|
||||
[f]
|
||||
(with-redefs [auto-ap.datomic/uri "datomic:mem://datomic-transactor:4334/invoice"]
|
||||
(d/create-database uri)
|
||||
(with-redefs [auto-ap.datomic/conn (d/connect uri)]
|
||||
(m/migrate auto-ap.datomic/conn)
|
||||
(f)
|
||||
(d/release auto-ap.datomic/conn)
|
||||
(d/delete-database uri))))
|
||||
|
||||
(t/use-fixtures :each wrap-setup)
|
||||
|
||||
(def sample-event {"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"})
|
||||
|
||||
(def known-order
|
||||
{:uuid "9ab05fee-a9c5-483b-a7f2-14debde4b7a8",
|
||||
:client-code "ABC", :client-location "DT"
|
||||
:orderSourceType "MARKETPLACE",
|
||||
:caterer
|
||||
{:name "Nick The Greek",
|
||||
:uuid "91541331-d7ae-4634-9e8b-ccbbcfb2ce70",
|
||||
:address {:street "165 Plaza Dr"}},
|
||||
:event
|
||||
{:timestamp "2022-07-21T19:15:00Z",
|
||||
:catererHandoffFoodTime "2022-07-21T19:15:00Z",
|
||||
:orderType "TAKEOUT"},
|
||||
:catererCart
|
||||
{:orderItems
|
||||
[{:name "Spartan Package",
|
||||
:quantity 10,
|
||||
:posItemId nil,
|
||||
:totalInSubunits {:currency "USD", :subunits 20950}}
|
||||
{:name "Spartan Package",
|
||||
:quantity 10,
|
||||
:posItemId nil,
|
||||
:totalInSubunits {:currency "USD", :subunits 20950}}],
|
||||
:totals {:catererTotalDue 420.65},
|
||||
:feesAndDiscounts []},
|
||||
:totals
|
||||
{:customerTotalDue {:currency "USD", :subunits 45409},
|
||||
:pointOfSaleIntegrationFee {:currency "USD", :subunits 0},
|
||||
:tip {:currency "USD", :subunits 0},
|
||||
:salesTax {:currency "USD", :subunits 3509},
|
||||
:salesTaxRemittance {:currency "USD", :subunits 0},
|
||||
:subTotal {:currency "USD", :subunits 41900}}})
|
||||
|
||||
(t/deftest lookup-order
|
||||
(t/testing "It should find the order from ezcater"
|
||||
(with-redefs [sut/get-caterer (fn [k]
|
||||
(t/is (= k "91541331-d7ae-4634-9e8b-ccbbcfb2ce70"))
|
||||
{
|
||||
:ezcater-integration/_caterers {:ezcater-integration/api-key "bmlrdHNpZ2FyaXNAZ21haWwuY29tOmQwMzQwMjYzOWI2ODQxNmVkMjdmZWYxMWFhZTk3YzU1MDlmNTcyNjYwMDAzOTA5MDE2OGMzODllNDBjNTVkZGE"}
|
||||
:ezcater-location/_caterer [{:ezcater-location/location "DT"
|
||||
:client/_ezcater-locations {:client/code "ABC"}}]
|
||||
})]
|
||||
(t/is (= known-order
|
||||
(sut/lookup-order sample-event))))))
|
||||
|
||||
(t/deftest order->sales-order
|
||||
(t/testing "It should use the date"
|
||||
(t/is (= #clj-time/date-time "2022-01-01T00:00:00-08:00"
|
||||
(-> known-order
|
||||
(assoc-in [:event :timestamp]
|
||||
"2022-01-01T08:00:00Z")
|
||||
(sut/order->sales-order)
|
||||
(:sales-order/date ))))
|
||||
(t/is (= #clj-time/date-time "2022-06-01T00:00:00-07:00"
|
||||
(-> known-order
|
||||
(assoc-in [:event :timestamp]
|
||||
"2022-06-01T07:00:00Z")
|
||||
(sut/order->sales-order)
|
||||
(:sales-order/date )))))
|
||||
(t/testing "It should categorize every item as 'External Catering'"
|
||||
(t/is (= 2
|
||||
(-> known-order
|
||||
sut/order->sales-order
|
||||
:sales-order/line-items
|
||||
count)))
|
||||
(t/is (= #{"External Catering"}
|
||||
(->> known-order
|
||||
sut/order->sales-order
|
||||
:sales-order/line-items
|
||||
(map :order-line-item/category)
|
||||
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/is (= "ezcater/order/ABC-DT-9ab05fee-a9c5-483b-a7f2-14debde4b7a8"
|
||||
(: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/is (= 35.09 (-> known-order
|
||||
sut/order->sales-order
|
||||
:sales-order/tax)))
|
||||
(t/is (= 0.0 (-> known-order
|
||||
sut/order->sales-order
|
||||
:sales-order/tip))))
|
||||
(t/testing "Should calculate 7% commision on ezcater orders"
|
||||
(t/is (dollars= 7.0
|
||||
(-> known-order
|
||||
(assoc :orderSourceType "EZCATER")
|
||||
(assoc-in [:totals :subTotal :subunits] 10000)
|
||||
sut/commision)))
|
||||
(t/testing "Should inlclude delivery fee in commision"
|
||||
(t/is (dollars= 14.0
|
||||
(-> known-order
|
||||
(assoc :orderSourceType "EZCATER")
|
||||
(assoc-in [:totals :subTotal :subunits] 10000)
|
||||
(assoc-in [:catererCart :feesAndDiscounts 0 :subunits] 10000)
|
||||
sut/commision)))))
|
||||
(t/testing "Should calculate 15% commision on marketplace orders"
|
||||
(t/is (dollars= 15.0
|
||||
(-> known-order
|
||||
(assoc :orderSourceType "MARKETPLACE")
|
||||
(assoc-in [:totals :subTotal :subunits] 10000)
|
||||
sut/commision)))
|
||||
(t/testing "Should inlclude delivery fee in commision"
|
||||
(t/is (dollars= 30.0
|
||||
(-> known-order
|
||||
(assoc :orderSourceType "MARKETPLACE")
|
||||
(assoc-in [:totals :subTotal :subunits] 10000)
|
||||
(assoc-in [:catererCart :feesAndDiscounts 0 :subunits] 10000)
|
||||
sut/commision)))))
|
||||
(t/testing "Should calculate 2.75% ccp fee"
|
||||
(t/is (dollars= 8.25
|
||||
(-> known-order
|
||||
(assoc :orderSourceType "MARKETPLACE")
|
||||
(assoc-in [:totals :subTotal :subunits] 10000)
|
||||
(assoc-in [:totals :salesTax :subunits] 10000)
|
||||
(assoc-in [:catererCart :feesAndDiscounts 0 :subunits] 10000)
|
||||
sut/ccp-fee))))
|
||||
(t/testing "Should use ezcater total paid to the customer"
|
||||
(t/is (dollars= 420.65
|
||||
(-> known-order
|
||||
sut/order->sales-order
|
||||
:sales-order/total))))
|
||||
(t/testing "Should derive adjustments food-total + sales-tax - caterer-total - service fee - ccp fee"
|
||||
(t/is (dollars= -41.8975
|
||||
(-> known-order
|
||||
sut/order->sales-order
|
||||
:sales-order/discount)))))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user