-
Notifications
You must be signed in to change notification settings - Fork 2
/
payment.go
263 lines (239 loc) · 10.4 KB
/
payment.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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
package unionpay
import (
"bytes"
"net/url"
"time"
)
const (
kFrontTrans = "/gateway/api/frontTransReq.do"
kBackTrans = "/gateway/api/backTransReq.do"
kQueryTrans = "/gateway/api/queryTrans.do"
kAppTrans = "/gateway/api/appTransReq.do"
)
// CreateWebPayment 消费接口-创建网页支付。
//
// 文档地址:https://open.unionpay.com/tjweb/acproduct/APIList?acpAPIId=754&apiservId=448&version=V2.2&bussType=0
//
// orderId:商户消费订单号。
//
// amount:交易金额,单位分,不要带小数点。
//
// frontURL:前台通知地址。
//
// backURL:后台通知地址。
func (c *Client) CreateWebPayment(orderId, amount, frontURL, backURL string, opts ...CallOption) (*WebPayment, error) {
var values = url.Values{}
// 此处的参数可被 WithPayload() 替换
values.Set("accessType", "0")
values.Set("currencyCode", "156") // 交易币种 156 - 人民币
values.Set("channelType", "07") // 渠道类型,这个字段区分B2C网关支付和手机wap支付;07 - PC,平板 08 - 手机
values.Set("bizType", "000201") // 业务类型,000201 - B2C网关支付和手机wap支付
values.Set("txnType", "01")
values.Set("txnSubType", "01") // 01:自助消费,通过地址的方式区分前台消费和后台消费(含无跳转支付) 03:分期付款
values.Set("txnTime", time.Now().Format("20060102150405"))
for _, opt := range opts {
if opt != nil {
opt(values)
}
}
values.Set("orderId", orderId)
values.Set("txnAmt", amount)
values.Set("frontUrl", frontURL)
values.Set("backUrl", backURL)
values, err := c.URLValues(values)
if err != nil {
return nil, err
}
var buff = bytes.NewBufferString("")
if err = c.webPaymentTpl.Execute(buff, map[string]interface{}{"Values": values, "Action": c.host + kFrontTrans}); err != nil {
return nil, err
}
var payment = &WebPayment{}
payment.Code = CodeSuccess
payment.HTML = buff.String()
payment.Version = values.Get("version")
payment.BizType = values.Get("bizType")
payment.TxnTime = values.Get("txnTime")
payment.TxnType = values.Get("txnType")
payment.TxnSubType = values.Get("txnSubType")
payment.AccessType = values.Get("accessType")
payment.MerId = values.Get("merId")
payment.OrderId = values.Get("orderId")
return payment, nil
}
// CreateAppPayment 消费接口-创建 App 支付。
//
// 文档地址:https://open.unionpay.com/tjweb/acproduct/APIList?apiservId=3021&acpAPIId=961&bussType=0
//
// orderId:商户消费订单号。
//
// amount:交易金额,单位分,不要带小数点。
//
// backURL:后台通知地址。
func (c *Client) CreateAppPayment(orderId, amount, backURL string, opts ...CallOption) (*AppPayment, error) {
var values = url.Values{}
// 此处的参数可被 WithPayload() 替换
values.Set("accessType", "0")
values.Set("currencyCode", "156") // 交易币种 156 - 人民币
values.Set("channelType", "08") // 渠道类型,这个字段区分B2C网关支付和手机wap支付;07 - PC,平板 08 - 手机
values.Set("bizType", "000201") // 业务类型,000201 - B2C网关支付和手机wap支付
values.Set("txnType", "01")
values.Set("txnSubType", "01") // 01:自助消费,通过地址的方式区分前台消费和后台消费(含无跳转支付) 03:分期付款
values.Set("txnTime", time.Now().Format("20060102150405"))
for _, opt := range opts {
if opt != nil {
opt(values)
}
}
values.Set("orderId", orderId)
values.Set("txnAmt", amount)
values.Set("backUrl", backURL)
var rValues, err = c.Request(kAppTrans, values)
if err != nil {
return nil, err
}
var payment *AppPayment
if err = DecodeValues(rValues, &payment); err != nil {
return nil, err
}
return payment, nil
}
// GetTransaction 交易状态查询接口
//
// 文档地址:https://open.unionpay.com/tjweb/acproduct/APIList?acpAPIId=757&apiservId=448&version=V2.2&bussType=0
//
// orderId:商户订单号。
//
// txnTime:订单发送时间,格式为 YYYYMMDDhhmmss,orderId 和 txnTime 组成唯一订单信息。
//
// 注:
// 应答报文中,“应答码”即respCode字段,表示的是查询交易本身的应答,即查询这个动作是否成功,不代表被查询交易的状态;
// 若查询动作成功,即应答码为“00“,则根据“原交易应答码”即origRespCode来判断被查询交易是否成功。此时若origRespCode为00,则表示被查询交易成功。
func (c *Client) GetTransaction(orderId, txnTime string, opts ...CallOption) (*Transaction, error) {
var values = url.Values{}
// 此处的参数可被 WithPayload() 替换
values.Set("accessType", "0")
values.Set("bizType", "000000")
values.Set("txnType", "00")
values.Set("txnSubType", "00")
for _, opt := range opts {
if opt != nil {
opt(values)
}
}
values.Set("orderId", orderId)
values.Set("txnTime", txnTime)
var rValues, err = c.Request(kQueryTrans, values)
if err != nil {
return nil, err
}
var transaction *Transaction
if err = DecodeValues(rValues, &transaction); err != nil {
return nil, err
}
return transaction, nil
}
// Revoke 消费撤销接口。
//
// 文档地址:https://open.unionpay.com/tjweb/acproduct/APIList?acpAPIId=755&apiservId=448&version=V2.2&bussType=0
//
// queryId:原消费交易返回的的queryId,可以从消费交易后台通知接口中或者交易状态查询接口(GetTransaction)中获取。
//
// orderId:商户撤销订单号,和要消费撤销的订单号没有关系。后续可用本 orderId 和返回结构体中的 TxnTime 通过交易状态查询接口(GetTransaction) 查询消费撤销信息。
//
// amount:退货金额,单位分,不要带小数点。
//
// backURL:后台通知地址。
//
// 消费撤销和退货的区别:
//
// 消费撤销仅能对当天的消费做,必须为全额,一般当日或第二日到账,可能存在极少数银行不支持。
//
// 退货(除二维码产品外)能对90天内(见注1、2)的消费做(包括当天),支持部分退货或全额退货,到账时间较长,一般1-10天(多数发卡行5天内,但工行可能会10天),所有银行都支持。
//
// 二维码产品退货支持30天,30天以上的退货可能可以发成功(失败应该会同步报错“原交易不存在或状态不正确[2011000]”之类的信息),但不保证一定可以成功。
//
// 注1:以上的天均指清算日,一般前一日23点至当天23点为一个清算日。
//
// 注2:系统实际支持330天的退货,但银联对发卡行的退货支持要求仅为90天,超过90天的退货发卡行虽然也会承兑,但可能为人工处理,到账速度较慢。330天以上的退货也可能成功,但不保证一定可以成功(失败应该会同步报错4040007之类的应答码),建议直接给用户转账来退款。
func (c *Client) Revoke(queryId, orderId, amount, backURL string, opts ...CallOption) (*Revoke, error) {
var values = url.Values{}
// 此处的参数可被 WithPayload() 替换
values.Set("accessType", "0")
values.Set("currencyCode", "156") // 交易币种 156 - 人民币
values.Set("channelType", "07") // 渠道类型,这个字段区分B2C网关支付和手机wap支付;07 - PC,平板 08 - 手机
values.Set("bizType", "000201") // 业务类型,000201 - B2C网关支付和手机wap支付
values.Set("txnType", "31")
values.Set("txnSubType", "00")
values.Set("txnTime", time.Now().Format("20060102150405"))
for _, opt := range opts {
if opt != nil {
opt(values)
}
}
values.Set("origQryId", queryId)
values.Set("orderId", orderId)
values.Set("txnAmt", amount)
values.Set("backUrl", backURL)
var rValues, err = c.Request(kBackTrans, values)
if err != nil {
return nil, err
}
var revoke *Revoke
if err = DecodeValues(rValues, &revoke); err != nil {
return nil, err
}
return revoke, nil
}
// Refund 退货接口。
//
// 文档地址:https://open.unionpay.com/tjweb/acproduct/APIList?acpAPIId=756&apiservId=448&version=V2.2&bussType=0
//
// queryId:原消费交易返回的的queryId,可以从消费交易后台通知接口中或者交易状态查询接口(GetTransaction)中获取。
//
// orderId:商户退货订单号,和要退款的订单号没有关系。后续可用本 orderId 和返回结构体中的 TxnTime 通过交易状态查询接口(GetTransaction) 查询退货信息。
//
// amount:退货金额,单位分,不要带小数点。
//
// backURL:后台通知地址。
//
// 消费撤销和退货的区别:
//
// 消费撤销仅能对当天的消费做,必须为全额,一般当日或第二日到账,可能存在极少数银行不支持。
//
// 退货(除二维码产品外)能对90天内(见注1、2)的消费做(包括当天),支持部分退货或全额退货,到账时间较长,一般1-10天(多数发卡行5天内,但工行可能会10天),所有银行都支持。
//
// 二维码产品退货支持30天,30天以上的退货可能可以发成功(失败应该会同步报错“原交易不存在或状态不正确[2011000]”之类的信息),但不保证一定可以成功。
//
// 注1:以上的天均指清算日,一般前一日23点至当天23点为一个清算日。
//
// 注2:系统实际支持330天的退货,但银联对发卡行的退货支持要求仅为90天,超过90天的退货发卡行虽然也会承兑,但可能为人工处理,到账速度较慢。330天以上的退货也可能成功,但不保证一定可以成功(失败应该会同步报错4040007之类的应答码),建议直接给用户转账来退款。
func (c *Client) Refund(queryId, orderId, amount, backURL string, opts ...CallOption) (*Refund, error) {
var values = url.Values{}
// 此处的参数可被 WithPayload() 替换
values.Set("accessType", "0")
values.Set("currencyCode", "156") // 交易币种 156 - 人民币
values.Set("channelType", "07") // 渠道类型,这个字段区分B2C网关支付和手机wap支付;07 - PC,平板 08 - 手机
values.Set("bizType", "000201") // 业务类型,000201 - B2C网关支付和手机wap支付
values.Set("txnType", "04")
values.Set("txnSubType", "00")
values.Set("txnTime", time.Now().Format("20060102150405"))
for _, opt := range opts {
if opt != nil {
opt(values)
}
}
values.Set("origQryId", queryId)
values.Set("orderId", orderId)
values.Set("txnAmt", amount)
values.Set("backUrl", backURL)
var rValues, err = c.Request(kBackTrans, values)
if err != nil {
return nil, err
}
var refund *Refund
if err = DecodeValues(rValues, &refund); err != nil {
return nil, err
}
return refund, nil
}