-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
206 lines (179 loc) · 5.13 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package main
import (
"context"
"fmt"
"log"
"strconv"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
ordermanagerpb "github.com/cs-lexliu/pickup-helper/gen/pb/ordermanager"
shoppingcheckoutcorepb "github.com/cs-lexliu/pickup-helper/gen/pb/shopping-checkout-core"
)
type Order = ordermanagerpb.FulfillmentOrder
type Address = ordermanagerpb.Address
type Checkout = shoppingcheckoutcorepb.Checkout
type BuyerInfo = shoppingcheckoutcorepb.Order_ReceiverInfo
const (
orderManagerAddress = "localhost:10001"
shoppingCheckoutAddress = "localhost:10002"
)
func main() {
if err := mainWithErr(); err != nil {
log.Fatalf(fmt.Sprintf("main: %v", err))
}
}
func mainWithErr() error {
h, err := newHelper()
if err != nil {
log.Fatalf(fmt.Sprintf("new helper: %v", err))
}
defer h.closeHelper()
nextAvailableTimeSlot := getNextAvailableTimeSlot()
// TODO: find a way to get the orderID
orderID := ""
ctx := context.Background()
if err := h.requestPickup(ctx, orderID, nextAvailableTimeSlot); err != nil {
return fmt.Errorf("request pickup: %w", err)
}
return nil
}
type timeSlot struct {
date string
slot string
}
type helper struct {
omConn *grpc.ClientConn
omClient ordermanagerpb.OrderManagerClient
sccConn *grpc.ClientConn
sccClient shoppingcheckoutcorepb.ShoppingCheckoutCoreServiceClient
}
func newHelper() (*helper, error) {
omConn, err := grpc.Dial(orderManagerAddress, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, fmt.Errorf("dail order manager: %w", err)
}
omClient := ordermanagerpb.NewOrderManagerClient(omConn)
scConn, err := grpc.Dial(shoppingCheckoutAddress, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, fmt.Errorf("dail shopping checkout: %w", err)
}
scClient := shoppingcheckoutcorepb.NewShoppingCheckoutCoreServiceClient(scConn)
return &helper{
omConn: omConn,
omClient: omClient,
sccConn: scConn,
sccClient: scClient,
}, nil
}
func (h *helper) closeHelper() {
if h.omConn != nil {
h.omConn.Close()
}
if h.sccConn != nil {
h.sccConn.Close()
}
}
func (h *helper) requestPickup(ctx context.Context, orderID string, ts *timeSlot) error {
var (
// fill in the Refrash pickup address as const
pickupAddress = &Address{
Country: "",
State: "",
City: "",
PostalCode: "",
UnitNo: "",
Address1: "",
Address2: "",
}
)
order, err := h.getOrder(ctx, orderID)
if err != nil {
return fmt.Errorf("get order: %w", err)
}
checkoutID := order.GetCheckoutId()
checkout, err := h.getCheckout(ctx, checkoutID)
if err != nil {
return fmt.Errorf("get checkout: %w", err)
}
buyerInfo := retrieveBuyerInfo(checkout)
if err := h.startDelivery(ctx, orderID, buyerInfo, pickupAddress, ts); err != nil {
return fmt.Errorf("start delivery: %w", err)
}
return nil
}
func (h *helper) getOrder(ctx context.Context, orderID string) (*Order, error) {
req := &ordermanagerpb.GetOrdersRequest{
Query: &ordermanagerpb.GetOrdersRequest_Query{
ByIds: []string{orderID},
},
}
resp, err := h.omClient.GetOrders(ctx, req)
if err != nil {
return nil, fmt.Errorf("om get order %s: %w", orderID, err)
}
if len(resp.GetOrders()) == 0 {
return nil, fmt.Errorf("no order found '%s'", orderID)
}
// assume the order is always existed
return resp.GetOrders()[0], nil
}
func (h *helper) getCheckout(ctx context.Context, checkoutID string) (*Checkout, error) {
req := &shoppingcheckoutcorepb.GetCheckoutByIDRequest{
CheckoutId: checkoutID,
}
resp, err := h.sccClient.GetCheckoutByID(ctx, req)
if err != nil {
return nil, fmt.Errorf("scc get checkout: %w", err)
}
return resp.GetCheckout(), nil
}
func (h *helper) startDelivery(ctx context.Context, orderID string, buyerInfo *BuyerInfo, pickupAddress *Address, timeslot *timeSlot) error {
req := &ordermanagerpb.StartD2DDeliveryRequest{
OrderId: orderID,
BuyerName: buyerInfo.GetReceiverName(),
BuyerPhone: buyerInfo.GetReceiverPhone(),
BuyerEmail: buyerInfo.GetReceiverEmail(),
Address: pickupAddress,
PickupDate: timeslot.date,
PickupSlot: timeslot.slot,
}
if _, err := h.omClient.StartD2DDelivery(ctx, req); err != nil {
return fmt.Errorf("om start d2d delivery: %w", err)
}
return nil
}
func retrieveBuyerInfo(checkout *shoppingcheckoutcorepb.Checkout) *BuyerInfo {
if checkout == nil {
return nil
}
return checkout.GetOrders()[0].GetDeliveryInfo().GetReceiverInfo()
}
func getNextAvailableTimeSlot() *timeSlot {
now := time.Now()
nextWorkingDay := getNextWorkingDay(now).Truncate(24 * time.Hour)
date := strconv.Itoa(int(nextWorkingDay.Unix()))
slot := getSlot(nextWorkingDay)
return &timeSlot{
date: date,
slot: slot,
}
}
func getNextWorkingDay(currentTime time.Time) time.Time {
// add 1 day until the weekday is not Sunday
for {
currentTime = currentTime.AddDate(0, 0, 1)
if currentTime.Weekday() != time.Sunday {
return currentTime
}
}
}
func getSlot(currentTime time.Time) string {
switch currentTime.Weekday() {
case time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday:
return "9AM-6PM"
case time.Saturday:
return "9AM-12PM"
}
return ""
}