-
Notifications
You must be signed in to change notification settings - Fork 0
/
order.go
145 lines (125 loc) · 3.05 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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package models
import (
"time"
"gorm.io/gorm"
)
type OrderType uint
const (
OrderTypeUnknown OrderType = iota
// 购买会员
OrderTypeSubscription
// 会员自动续费
OrderTypeSubscriptionAutoRenew
// 购买小时数
OrderTypeBuyCredits
// 购买商品
OrderTypeBuyProduct
)
func (t *OrderType) MarshalJSON() ([]byte, error) {
str := ""
switch *t {
case OrderTypeSubscription:
str = "subscription"
case OrderTypeSubscriptionAutoRenew:
str = "subscription_auto_renew"
case OrderTypeBuyCredits:
str = "buy_credits"
case OrderTypeBuyProduct:
str = "buy_product"
}
return []byte(`"` + str + `"`), nil
}
type OrderStatus uint
const (
OrderStatusPending OrderStatus = iota
OrderStatusPaid
OrderStatusCancelled
)
func (status *OrderStatus) MarshalJSON() ([]byte, error) {
str := ""
switch *status {
case OrderStatusPending:
str = "pending"
case OrderStatusPaid:
str = "paid"
}
return []byte(`"` + str + `"`), nil
}
type Order struct {
gorm.Model
TimestamppedID string `gorm:"index" json:"oid"`
Date time.Time `json:"date"`
Price Price `json:"price"`
DiscountedPrice Price `json:"discounted_price"`
Amount uint `json:"amount"`
Type OrderType `json:"type"`
GoodID uint `json:"-"`
Good Good `json:"good"`
CouponID *uint `json:"-"`
Coupon *Coupon `json:"-"`
Affiliate User `json:"-"`
AffiliateID uint `json:"-"`
Data string `json:"-"`
Status OrderStatus `gorm:"notNull;type:int;default:0" json:"status"`
}
func CreateOrder(o *Order) error {
tx := db.Create(o)
return tx.Error
}
func GetOrderByID(id string) (Order, error) {
var o Order
tx := db.Preload("Affiliate").Where("timestampped_id = ?", id).First(&o)
return o, tx.Error
}
// mark paid only marks current order to paid status,
// to keep atomic operation, use CommitPaid instead.
func (o *Order) MarkPaid() error {
tx := db.Model(o).Update("status", OrderStatusPaid)
return tx.Error
}
// CommitPaid commits the order to paid status,
// and increase user's credits in one transaction.
func (o *Order) CommitPaid() error {
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
err := tx.
Model(o).
Update("status", OrderStatusPaid).
Error
if err != nil {
tx.Rollback()
return err
}
err = tx.
Model(User{}).
Where("id = ?", o.AffiliateID).
Update("remaining_credit", gorm.Expr("remaining_credit + ? * 100", o.Amount)).
Error
if err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
func (u *User) ListOrders() ([]Order, error) {
orders := []Order{}
tx := db.Preload("Good").Where("affiliate_id = ?", u.ID).Order("id desc").Find(&orders)
return orders, tx.Error
}
func GetNetRevenu() Price {
var result = struct {
Revenu Price `gorm:"column:revenu" json:"revenu"`
}{}
tx := db.
Where("status = ? AND created_at > ?", OrderStatusPaid, time.Now().AddDate(0, -1, 0)).
Select("SUM(price) revenu").
Scan(&result)
if tx.Error != nil {
return 0
}
return result.Revenu
}