-
Notifications
You must be signed in to change notification settings - Fork 20
/
wxpay.go
186 lines (172 loc) · 5.23 KB
/
wxpay.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
package ppp
import (
proto "github.com/panjjo/ppp/proto"
)
var wxpay *WXPay
// WXPay 微信支付服务商模式主体
// 微信支付服务商模式
// 服务商模式与单商户模式区别只是多了一个 子商户权限,其余接口结构返回完全一致
type WXPay struct {
ws WXPaySingle
}
// NewWXPay 获取微信实例
func NewWXPay(config Config) *WXPay {
ws := NewWXPaySingle(config)
wx := &WXPay{ws: *ws}
wxpay = wx
return wx
}
// BarPay 商户主动扫码支付
// 服务商模式调用
// 真实处理为 WXPaySingle.BarPay
func (W *WXPay) BarPay(ctx *Context, req *proto.Barpay) (trade *proto.Trade, e Error) {
auth := ctx.getAuth(req.UserID, req.MchID)
if auth.Status != proto.Accountstatus_ok {
// 授权错误
e.Code = AuthErr
return
}
return W.ws.BarPay(ctx, req)
}
// Refund 订单退款
// 服务商模式调用
// 真实处理为 WXPaySingle.Refund
func (W *WXPay) Refund(ctx *Context, req *proto.Refund) (refund *proto.Refund, e Error) {
auth := ctx.getAuth(req.UserID, req.MchID)
if auth.Status != proto.Accountstatus_ok {
// 授权错误
e.Code = AuthErr
return
}
return W.ws.Refund(ctx, req)
}
// Cancel 撤销订单
// 服务商模式调用
// 真实处理为 WXPaySingle.Cancel
func (W *WXPay) Cancel(ctx *Context, req *proto.Trade) (trade *proto.Trade, e Error) {
auth := ctx.getAuth(req.UserID, req.MchID)
if auth.Status != proto.Accountstatus_ok {
// 授权错误
e.Code = AuthErr
return
}
return W.ws.Cancel(ctx, req)
}
// TradeInfo 获取订单详情
// 服务商模式调用
// 真实处理为 WXPaySingle.TradeInfo
func (W *WXPay) TradeInfo(ctx *Context, req *proto.Trade) (trade *proto.Trade, e Error) {
auth := ctx.getAuth(req.UserID, req.MchID)
if auth.Status != proto.Accountstatus_ok {
// 授权错误
e.Code = AuthErr
return
}
return W.ws.TradeInfo(ctx, req)
}
// PayParams 获取支付参数
// 用于前段请求,不想暴露证书的私密信息的可用此方法组装请求参数,前端只负责请求
// 支持的有 JS支付,手机app支付,公众号支付
// APP支付紧支持单商户模式,公众号支付,扫码支付等支持服务商和单商户模式
func (W *WXPay) PayParams(ctx *Context, req *proto.Params) (data *proto.ParamsData, e Error) {
auth := ctx.getAuth(req.UserID, req.MchID)
if auth.Status != proto.Accountstatus_ok {
// 授权错误
e.Code = AuthErr
return
}
return W.ws.PayParams(ctx, req)
}
// BindUser 用户绑定
// 将Auth授权绑定到User上去
// 多个用户可使用同一个Auth,可有效防止重复授权导致多个Auth争取token问题
// 绑定了之后 调用其他接口可传UserID查找对应Auth
// 如果业务逻辑不需要绑定,就不要绑定,调用其他接口传MchID即可
func (W *WXPay) BindUser(ctx *Context, req *proto.User) (user *proto.User, e Error) {
if req.UserID == "" || req.MchID == "" {
e.Code = SysErrParams
e.Msg = "userid mchid 必传"
return
}
auth := getToken(req.MchID, ctx.appid())
if auth.ID == "" {
// 授权不存在
e.Code = AuthErr
return
}
user = getUser(req.UserID, proto.WXPAY)
if user.ID != "" {
// 存在更新授权
user.MchID = auth.MchID
user.Status = auth.Status
updateUser(map[string]interface{}{"userid": user.UserID}, user)
} else {
// 保存授权
user = &proto.User{
UserID: req.UserID,
MchID: req.MchID,
Status: auth.Status,
ID: randomTimeString(),
From: proto.WXPAY,
}
saveUser(user)
}
return
}
// UnBindUser 用户解除绑定
// 将Auth授权和User进行解绑
// 多个用户可使用同一个Auth,可有效防止重复授权导致多个Auth争取token问题
// 解绑之后auth授权依然有效
func (W *WXPay) UnBindUser(ctx *Context, req *proto.User) (user *proto.User, e Error) {
if req.UserID == "" {
e.Code = SysErrParams
e.Msg = "userid 必传"
return
}
user = getUser(req.UserID, proto.WXPAY)
if user.ID != "" {
// 存在更新授权
user.MchID = ""
user.Status = proto.Accountstatus_unauth
updateUser(map[string]interface{}{"userid": user.UserID}, user)
} else {
// 用户不存在
e.Code = UserErrNotFount
}
return
}
// AuthSigned 增加授权
// 刷新/获取授权
// 传入参数为Token格式,微信传入MchId:子商户ID
// req mchid account appid
func (W *WXPay) AuthSigned(ctx *Context, req *proto.Account) (auth *proto.Account, e Error) {
auth = ctx.getAuth("wxAuthsigned", req.MchID)
if auth.ID != "" {
// 授权已存在直接返回
return
}
auth.MchID = ""
auth = &proto.Account{
ID: randomTimeString(),
Status: proto.Accountstatus_ok,
MchID: req.MchID,
From: proto.WXPAY,
Account: req.Account,
SubAppID: req.SubAppID,
}
ctx.auth = auth
// 检测权限是否真实开通
// 临时指定auth状态为&proto.Tradestatus_succ 为了后面通过权限验证
if _, err := W.TradeInfo(ctx, &proto.Trade{MchID: auth.MchID, OutTradeID: "tradeforAuthSignedCheck"}); err.Code != TradeErrNotFound {
// 查询订单返回权限错误,说明授权存在问题
e.Code = AuthErr
e.Msg = err.Msg
return
}
auth.AppID = ctx.appid()
// 保存authinfo
saveToken(auth)
// 更新所有绑定过此auth的用户数据
updateUserMulti(map[string]interface{}{"mchid": auth.MchID, "type": proto.WXPAY}, map[string]interface{}{"status": proto.Accountstatus_ok})
return
}