Skip to content

Commit 6c322c7

Browse files
committed
Add webhook for orders create events to notify customer.io of placed orders
1 parent d0d7ec6 commit 6c322c7

File tree

8 files changed

+255
-30
lines changed

8 files changed

+255
-30
lines changed

auth/service/service/service.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,12 @@ func (s *Service) initializeRouter() error {
333333
return errors.Wrap(err, "unable to create fulfillment event processor")
334334
}
335335

336-
shopifyRouter, err := shopifyAPI.NewRouter(fulfillmentEventProcessor)
336+
ordersCreateEventProcessor, err := shopify.NewOrdersCreateEventProcessor(s.Logger(), customerIOClient, shopifyClnt)
337+
if err != nil {
338+
return errors.Wrap(err, "unable to create orders create event processor")
339+
}
340+
341+
shopifyRouter, err := shopifyAPI.NewRouter(fulfillmentEventProcessor, ordersCreateEventProcessor)
337342
if err != nil {
338343
return errors.Wrap(err, "unable to create shopify router")
339344
}

oura/customerio/events.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package customerio
22

33
const (
44
OuraEligibilitySurveyCompletedEventType = "oura_eligibility_survey_completed"
5+
OuraSizingKitOrderedEventType = "oura_sizing_kit_ordered"
56
OuraSizingKitDeliveredEventType = "oura_sizing_kit_delivered"
7+
OuraRingOrderedEventType = "oura_ring_ordered"
68
OuraRingDeliveredEventType = "oura_ring_delivered"
79
)
810

@@ -12,8 +14,18 @@ type OuraEligibilitySurveyCompletedData struct {
1214
OuraSizingKitDiscountCode string `json:"oura_sizing_kit_discount_code,omitempty"`
1315
}
1416

17+
type OuraSizingKitOrderedData struct {
18+
OuraSizingKitDiscountCode string `json:"oura_sizing_kit_discount_code"`
19+
}
20+
1521
type OuraSizingKitDeliveredData struct {
16-
OuraRingDiscountCode string `json:"oura_ring_discount_code"`
22+
OuraSizingKitDiscountCode string `json:"oura_sizing_kit_discount_code"`
23+
OuraRingDiscountCode string `json:"oura_ring_discount_code"`
1724
}
1825

19-
type OuraRingDeliveredData struct{}
26+
type OuraRingOrderedData struct {
27+
OuraRingDiscountCode string `json:"oura_ring_discount_code"`
28+
}
29+
type OuraRingDeliveredData struct {
30+
OuraRingDiscountCode string `json:"oura_ring_discount_code"`
31+
}

oura/shopify/api/router.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,21 @@ import (
1010
)
1111

1212
type Router struct {
13-
fulfillmentEventProcessor *shopify.FulfillmentEventProcessor
13+
fulfillmentEventProcessor *shopify.FulfillmentEventProcessor
14+
ordersCreateEventProcessor *shopify.OrdersCreateEventProcessor
1415
}
1516

16-
func NewRouter(fulfillmentEventProcessor *shopify.FulfillmentEventProcessor) (*Router, error) {
17+
func NewRouter(fulfillmentEventProcessor *shopify.FulfillmentEventProcessor, ordersCreateEventProcessor *shopify.OrdersCreateEventProcessor) (*Router, error) {
1718
return &Router{
18-
fulfillmentEventProcessor: fulfillmentEventProcessor,
19+
fulfillmentEventProcessor: fulfillmentEventProcessor,
20+
ordersCreateEventProcessor: ordersCreateEventProcessor,
1921
}, nil
2022
}
2123

2224
func (r *Router) Routes() []*rest.Route {
2325
return []*rest.Route{
2426
rest.Post("/v1/partners/shopify/fulfillment", r.HandleFulfillmentEvent),
27+
rest.Post("/v1/partners/shopify/orders/create", r.HandleOrdersCreateEvent),
2528
}
2629
}
2730

@@ -30,7 +33,7 @@ func (r *Router) HandleFulfillmentEvent(res rest.ResponseWriter, req *rest.Reque
3033
responder := request.MustNewResponder(res, req)
3134

3235
event := shopify.FulfillmentEvent{}
33-
if err := request.DecodeRequestBody(req.Request, event); err != nil {
36+
if err := request.DecodeRequestBody(req.Request, &event); err != nil {
3437
responder.Error(http.StatusBadRequest, err)
3538
return
3639
}
@@ -43,3 +46,22 @@ func (r *Router) HandleFulfillmentEvent(res rest.ResponseWriter, req *rest.Reque
4346
responder.Empty(http.StatusOK)
4447
return
4548
}
49+
50+
func (r *Router) HandleOrdersCreateEvent(res rest.ResponseWriter, req *rest.Request) {
51+
ctx := req.Context()
52+
responder := request.MustNewResponder(res, req)
53+
54+
event := shopify.OrdersCreateEvent{}
55+
if err := request.DecodeRequestBody(req.Request, &event); err != nil {
56+
responder.Error(http.StatusBadRequest, err)
57+
return
58+
}
59+
60+
if err := r.ordersCreateEventProcessor.Process(ctx, event); err != nil {
61+
responder.Error(http.StatusInternalServerError, err)
62+
return
63+
}
64+
65+
responder.Empty(http.StatusOK)
66+
return
67+
}

oura/shopify/client.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ type DiscountCodeInput struct {
2121
}
2222

2323
type DeliveredProducts struct {
24-
OrderID string `json:"order_id"`
2524
IDs []string `json:"products"`
2625
DiscountCode string `json:"discount_code"`
2726
}

oura/shopify/client/order.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,12 @@ func (c *defaultClient) GetDeliveredProducts(ctx context.Context, orderID string
5959
}
6060
}
6161

62-
return &shopify.DeliveredProducts{IDs: ids}, nil
62+
var discountCode string
63+
if resp.GetOrderByIdentifier().GetDiscountCode() != nil {
64+
discountCode = *resp.GetOrderByIdentifier().GetDiscountCode()
65+
}
66+
return &shopify.DeliveredProducts{
67+
IDs: ids,
68+
DiscountCode: discountCode,
69+
}, nil
6370
}

oura/shopify/fulfillment.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
)
1313

1414
var (
15-
deliveredProductIDToOuraDiscountAttribute = map[string]string{
15+
productIDToOuraDiscountAttribute = map[string]string{
1616
OuraSizingKitProductID: "oura_sizing_kit_discount_code",
1717
OuraRingProductID: "oura_ring_discount_code",
1818
}
@@ -75,7 +75,7 @@ func (f *FulfillmentEventProcessor) Process(ctx context.Context, event Fulfillme
7575
deliveredProductID := deliveredProducts.IDs[0]
7676
logger = logger.WithField("orderId", orderId).WithField("productId", deliveredProductID)
7777

78-
attribute, ok := deliveredProductIDToOuraDiscountAttribute[deliveredProductID]
78+
attribute, ok := productIDToOuraDiscountAttribute[deliveredProductID]
7979
if !ok {
8080
logger.Warn("unable to find discount attribute for delivered product")
8181
return nil
@@ -85,9 +85,11 @@ func (f *FulfillmentEventProcessor) Process(ctx context.Context, event Fulfillme
8585
"filter": map[string]any{
8686
"and": []any{
8787
map[string]any{
88-
"field": attribute,
89-
"operator": "eq",
90-
"value": deliveredProducts.DiscountCode,
88+
"attribute": map[string]any{
89+
"field": attribute,
90+
"operator": "eq",
91+
"value": deliveredProducts.DiscountCode,
92+
},
9193
},
9294
},
9395
},
@@ -111,12 +113,12 @@ func (f *FulfillmentEventProcessor) Process(ctx context.Context, event Fulfillme
111113

112114
switch deliveredProductID {
113115
case OuraSizingKitProductID:
114-
if err := f.onSizingKitDelivered(ctx, customers.Identifiers[0], event); err != nil {
116+
if err := f.onSizingKitDelivered(ctx, customers.Identifiers[0], event, deliveredProducts.DiscountCode); err != nil {
115117
logger.WithError(err).Warn("unable to send sizing kit delivered event")
116118
return err
117119
}
118120
case OuraRingProductID:
119-
if err := f.onRingDelivered(ctx, customers.Identifiers[0], event); err != nil {
121+
if err := f.onRingDelivered(ctx, customers.Identifiers[0], event, deliveredProducts.DiscountCode); err != nil {
120122
logger.WithError(err).Warn("unable to send ring delivered event")
121123
return err
122124
}
@@ -127,7 +129,7 @@ func (f *FulfillmentEventProcessor) Process(ctx context.Context, event Fulfillme
127129
return nil
128130
}
129131

130-
func (f *FulfillmentEventProcessor) onSizingKitDelivered(ctx context.Context, identifiers customerio.Identifiers, event FulfillmentEvent) error {
132+
func (f *FulfillmentEventProcessor) onSizingKitDelivered(ctx context.Context, identifiers customerio.Identifiers, event FulfillmentEvent, sizingKitDiscountCode string) error {
131133
discountCode := RandomDiscountCode()
132134
err := f.shopifyClient.CreateDiscountCode(ctx, DiscountCodeInput{
133135
Title: OuraRingDiscountCodeTitle,
@@ -142,18 +144,21 @@ func (f *FulfillmentEventProcessor) onSizingKitDelivered(ctx context.Context, id
142144
Name: customerio.OuraSizingKitDeliveredEventType,
143145
ID: fmt.Sprintf("%d", event.ID),
144146
Data: customerio.OuraSizingKitDeliveredData{
145-
OuraRingDiscountCode: discountCode,
147+
OuraRingDiscountCode: discountCode,
148+
OuraSizingKitDiscountCode: sizingKitDiscountCode,
146149
},
147150
}
148151

149152
return f.customerIOClient.SendEvent(ctx, identifiers.ID, sizingKitDelivered)
150153
}
151154

152-
func (f *FulfillmentEventProcessor) onRingDelivered(ctx context.Context, identifiers customerio.Identifiers, event FulfillmentEvent) error {
155+
func (f *FulfillmentEventProcessor) onRingDelivered(ctx context.Context, identifiers customerio.Identifiers, event FulfillmentEvent, ringDiscountCode string) error {
153156
ringDelivered := customerio.Event{
154157
Name: customerio.OuraRingDeliveredEventType,
155158
ID: fmt.Sprintf("%d", event.ID),
156-
Data: customerio.OuraRingDeliveredData{},
159+
Data: customerio.OuraRingDeliveredData{
160+
OuraRingDiscountCode: ringDiscountCode,
161+
},
157162
}
158163

159164
return f.customerIOClient.SendEvent(ctx, identifiers.ID, ringDelivered)

oura/shopify/fulfillment_test.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ var _ = Describe("FulfillmentEventProcessor", func() {
8686
shopifyClnt.EXPECT().
8787
GetDeliveredProducts(gomock.Any(), fmt.Sprintf("gid://shopify/Order/%d", event.OrderID)).
8888
Return(&shopify.DeliveredProducts{
89-
OrderID: fmt.Sprintf("%d", event.OrderID),
9089
IDs: []string{shopify.OuraSizingKitProductID},
9190
DiscountCode: sizingKitDiscountCode,
9291
}, nil)
@@ -100,9 +99,11 @@ var _ = Describe("FulfillmentEventProcessor", func() {
10099
"filter": {
101100
"and": [
102101
{
103-
"field": "oura_sizing_kit_discount_code",
104-
"operator": "eq",
105-
"value": "` + sizingKitDiscountCode + `"
102+
"attribute": {
103+
"field": "oura_sizing_kit_discount_code",
104+
"operator": "eq",
105+
"value": "` + sizingKitDiscountCode + `"
106+
}
106107
}
107108
]
108109
}
@@ -125,7 +126,8 @@ var _ = Describe("FulfillmentEventProcessor", func() {
125126
"name": "oura_sizing_kit_delivered",
126127
"id": "` + fmt.Sprintf("%d", event.ID) + `",
127128
"data": {
128-
"oura_ring_discount_code": "` + input.Code + `"
129+
"oura_ring_discount_code": "` + input.Code + `",
130+
"oura_sizing_kit_discount_code": "` + sizingKitDiscountCode + `"
129131
}
130132
}`),
131133
},
@@ -153,7 +155,6 @@ var _ = Describe("FulfillmentEventProcessor", func() {
153155
shopifyClnt.EXPECT().
154156
GetDeliveredProducts(gomock.Any(), fmt.Sprintf("gid://shopify/Order/%d", event.OrderID)).
155157
Return(&shopify.DeliveredProducts{
156-
OrderID: fmt.Sprintf("%d", event.OrderID),
157158
IDs: []string{shopify.OuraRingProductID},
158159
DiscountCode: discountCode,
159160
}, nil)
@@ -167,9 +168,11 @@ var _ = Describe("FulfillmentEventProcessor", func() {
167168
"filter": {
168169
"and": [
169170
{
170-
"field": "oura_ring_discount_code",
171-
"operator": "eq",
172-
"value": "` + discountCode + `"
171+
"attribute": {
172+
"field": "oura_ring_discount_code",
173+
"operator": "eq",
174+
"value": "` + discountCode + `"
175+
}
173176
}
174177
]
175178
}
@@ -184,7 +187,9 @@ var _ = Describe("FulfillmentEventProcessor", func() {
184187
ouraTest.NewRequestJSONBodyMatcher(`{
185188
"name": "oura_ring_delivered",
186189
"id": "` + fmt.Sprintf("%d", event.ID) + `",
187-
"data": {}
190+
"data": {
191+
"oura_ring_discount_code": "` + discountCode + `"
192+
}
188193
}`),
189194
},
190195
ouraTest.Response{StatusCode: http.StatusOK, Body: "{}"},

0 commit comments

Comments
 (0)