/
order.go
125 lines (112 loc) · 4.02 KB
/
order.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
package cart
import (
"context"
"fmt"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/sns"
"github.com/aws/aws-sdk-go-v2/service/sns/types"
"github.com/pkg/errors"
"github.com/samber/lo"
"github.com/shopspring/decimal"
"github.com/asia-loop-gmbh/asia-loop-utils-go/v8/pkg/orderutils"
"github.com/asia-loop-gmbh/asia-loop-utils-go/v8/pkg/shop/coupon"
"github.com/asia-loop-gmbh/asia-loop-utils-go/v8/pkg/shop/db"
mysns "github.com/nam-truong-le/lambda-utils-go/v4/pkg/aws/sns"
"github.com/nam-truong-le/lambda-utils-go/v4/pkg/aws/ssm"
"github.com/nam-truong-le/lambda-utils-go/v4/pkg/logger"
"github.com/nam-truong-le/lambda-utils-go/v4/pkg/random"
)
func CreateOrder(ctx context.Context, shoppingCart *db.Cart, confirmedTotal string) (*db.Order, error) {
log := logger.FromContext(ctx)
log.Infof("Cart was paid, will create final order")
colOrders, err := db.CollectionOrders(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to init db collection")
}
invoiceNumber, err := orderutils.NextShopOrderInvoice(ctx)
if err != nil {
log.Errorf("Failed to generate invoice number: %s", err)
return nil, errors.Wrap(err, "failed to generate invoice number")
}
orderNumber := fmt.Sprintf("S%s", random.String(10, lo.NumbersCharset))
order, err := ToOrder(ctx, shoppingCart)
if err != nil {
log.Errorf("Failed to convert cart to order: %s", err)
return nil, errors.Wrap(err, "failed to convert cart to order")
}
checkTotal := decimal.RequireFromString(confirmedTotal)
orderTotal := decimal.RequireFromString(order.Summary.Total.Value)
if !checkTotal.Equal(orderTotal) {
log.Errorf(
"Fraud detected for cart [%s], total confirmed by payment or manually = [%s], order total = [%s]",
shoppingCart.ID, checkTotal.StringFixed(2), orderTotal.StringFixed(2),
)
return nil, fmt.Errorf("different totals: %s | %s", checkTotal.StringFixed(2), orderTotal.StringFixed(2))
}
order.InvoiceNumber = invoiceNumber
order.OrderNumber = &orderNumber
now := time.Now()
order.CreatedAt = now
order.UpdatedAt = now
for i := 0; i < len(order.Items); i++ {
// check if gift card, then create codes
if order.Items[i].IsGiftCard {
order.Items[i].GiftCardCode = lo.Times(order.Items[i].Amount, func(index int) string {
newCoupon, err := db.NewMehrzweckCoupon(ctx, order.Items[i].UnitPrice)
if err != nil {
log.Errorf("Failed to create coupon [%s]", err)
// TODO: we don't expect this happens, so it's good for now
return ""
}
log.Infof("Gift card code generated: %s = %s€", newCoupon.Code, newCoupon.Total)
return newCoupon.Code
})
}
// check if coupon, then update coupon value
if order.Items[i].SKU == db.CouponSKU {
err := coupon.UpdateCouponByOrderItem(ctx, order.ID.Hex(), order.Items[i])
if err != nil {
log.Errorf("Failed to update coupon %s: %s", order.Items[i].Name, err)
}
}
}
_, err = colOrders.InsertOne(ctx, order)
if err != nil {
log.Errorf("Failed to insert order: %s", err)
return nil, errors.Wrap(err, "failed to insert order")
}
log.Infof("Order was created for cart [%s]", shoppingCart.ID)
sendSNSOrderCreated(ctx, order)
return order, nil
}
func sendSNSOrderCreated(ctx context.Context, order *db.Order) {
log := logger.FromContext(ctx)
log.Infof("Send SNS message")
topic, err := ssm.GetParameter(ctx, "/shop/sns/order/created/arn", false)
if err != nil {
log.Errorf("Failed to get topic arn: %s", err)
return
}
c, err := mysns.NewClient(ctx)
if err != nil {
log.Errorf("Failed to init sns: %s", err)
return
}
params := &sns.PublishInput{
TopicArn: aws.String(topic),
Message: aws.String(fmt.Sprintf("New order [%d]", order.OrderNumber)),
MessageGroupId: aws.String(order.StoreKey),
MessageAttributes: map[string]types.MessageAttributeValue{
"orderId": {
DataType: aws.String("String"),
StringValue: aws.String(order.ID.Hex()),
},
},
}
if _, err := c.Publish(ctx, params); err != nil {
log.Errorf("Failed to publish: %s", err)
return
}
log.Infof("SNS message published")
}