微信支付支持退款
This commit is contained in:
@@ -1,17 +1,16 @@
|
|||||||
package wxpay
|
package wxpay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/md5"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
"github.com/clbanning/mxj"
|
"github.com/clbanning/mxj"
|
||||||
|
"github.com/nanjishidu/gomini/gocrypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CData string
|
type CData string
|
||||||
@@ -69,7 +68,7 @@ type RefundReqInfo struct {
|
|||||||
OutRefundNo string `json:"out_refund_no"`
|
OutRefundNo string `json:"out_refund_no"`
|
||||||
OutTradeNo string `json:"out_trade_no"`
|
OutTradeNo string `json:"out_trade_no"`
|
||||||
RefundAccount string `json:"refund_account"`
|
RefundAccount string `json:"refund_account"`
|
||||||
RefundFee string `json:"refund_fee"`
|
RefundFee string `json:"refund_fee" xml:"refund_fee"`
|
||||||
RefundID string `json:"refund_id"`
|
RefundID string `json:"refund_id"`
|
||||||
RefundRecvAccout string `json:"refund_recv_accout"`
|
RefundRecvAccout string `json:"refund_recv_accout"`
|
||||||
RefundRequestSource string `json:"refund_request_source"`
|
RefundRequestSource string `json:"refund_request_source"`
|
||||||
@@ -94,7 +93,8 @@ type RefundResultMsg struct {
|
|||||||
ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"`
|
ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"`
|
||||||
ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"`
|
ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"`
|
||||||
|
|
||||||
ReqInfo *RefundReqInfo `json:"req_info,omitempty" xml:"req_info,omitempty"`
|
ReqInfoStr string `json:"req_info,omitempty"`
|
||||||
|
ReqInfoObj *RefundReqInfo `json:"req_info_obj,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CallbackMsg struct {
|
type CallbackMsg struct {
|
||||||
@@ -127,13 +127,12 @@ func Err2CallbackResponse(err error, data string) *CallbackResponse {
|
|||||||
func (a *API) decodeReqInfo(msg string) (decryptedMsg string, err error) {
|
func (a *API) decodeReqInfo(msg string) (decryptedMsg string, err error) {
|
||||||
binMsg, err := base64.StdEncoding.DecodeString(msg)
|
binMsg, err := base64.StdEncoding.DecodeString(msg)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
aesKey := []byte(fmt.Sprintf("%x", md5.Sum([]byte(a.appKey))))
|
// aesKey := []byte(fmt.Sprintf("%x", md5.Sum([]byte(a.appKey))))
|
||||||
binResult, err2 := utils.AESCBCDecpryt(binMsg, aesKey, aesKey[:16])
|
// binResult, err2 := utils.AESCBCDecpryt(binMsg, aesKey, aesKey[:16])
|
||||||
|
gocrypto.SetAesKey(strings.ToLower(gocrypto.Md5(a.appKey)))
|
||||||
|
binResult, err2 := gocrypto.AesECBDecrypt(binMsg)
|
||||||
if err = err2; err == nil {
|
if err = err2; err == nil {
|
||||||
var msgLen int32
|
decryptedMsg = string(binResult)
|
||||||
if err = binary.Read(bytes.NewBuffer(binResult[16:]), binary.BigEndian, &msgLen); err == nil {
|
|
||||||
decryptedMsg = string(binResult[16+4 : 16+4+msgLen])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return decryptedMsg, err
|
return decryptedMsg, err
|
||||||
@@ -144,15 +143,15 @@ func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackR
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Err2CallbackResponse(err, "")
|
return nil, Err2CallbackResponse(err, "")
|
||||||
}
|
}
|
||||||
mapData, _, err := a.checkResultAsMap(string(data))
|
return a.getCallbackMsg(string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) getCallbackMsg(msgBody string) (msg *CallbackMsg, callbackResponse *CallbackResponse) {
|
||||||
|
mapData, _, err := a.checkResultAsMap(msgBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Err2CallbackResponse(err, "")
|
return nil, Err2CallbackResponse(err, "")
|
||||||
}
|
}
|
||||||
sign := utils.Interface2String(mapData[sigKey])
|
|
||||||
desiredSign := a.signParam(mapData)
|
|
||||||
if desiredSign != sign {
|
|
||||||
return nil, Err2CallbackResponse(fmt.Errorf("desiredSign:%s <> sign:%s", desiredSign, sign), "")
|
|
||||||
}
|
|
||||||
msg = &CallbackMsg{
|
msg = &CallbackMsg{
|
||||||
MapData: mapData,
|
MapData: mapData,
|
||||||
}
|
}
|
||||||
@@ -163,13 +162,15 @@ func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackR
|
|||||||
ReturnMsg: utils.Interface2String(mapData["return_msg"]),
|
ReturnMsg: utils.Interface2String(mapData["return_msg"]),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if transactionID := utils.Interface2String(mapData["transaction_id"]); transactionID != "" {
|
reqInfo := utils.Interface2String(mapData["req_info"])
|
||||||
msg.MsgType = MsgTypePay
|
if reqInfo == "" {
|
||||||
var payResult *PayResultMsg
|
sign := utils.Interface2String(mapData[sigKey])
|
||||||
if err = utils.Map2StructByJson(mapData, &payResult, false); err == nil {
|
desiredSign := a.signParam(mapData)
|
||||||
msg.Data = payResult
|
if desiredSign != sign {
|
||||||
|
return nil, Err2CallbackResponse(fmt.Errorf("desiredSign:%s <> sign:%s", desiredSign, sign), "")
|
||||||
}
|
}
|
||||||
} else if reqInfo := utils.Interface2String(mapData["req_info"]); reqInfo != "" {
|
}
|
||||||
|
if reqInfo != "" {
|
||||||
msg.MsgType = MsgTypeRefund
|
msg.MsgType = MsgTypeRefund
|
||||||
var refundResult *RefundResultMsg
|
var refundResult *RefundResultMsg
|
||||||
if err = utils.Map2StructByJson(mapData, &refundResult, false); err == nil {
|
if err = utils.Map2StructByJson(mapData, &refundResult, false); err == nil {
|
||||||
@@ -177,12 +178,18 @@ func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackR
|
|||||||
mv, err2 := mxj.NewMapXml([]byte(reqInfo))
|
mv, err2 := mxj.NewMapXml([]byte(reqInfo))
|
||||||
if err = err2; err == nil {
|
if err = err2; err == nil {
|
||||||
reqInfoMap := mv["root"].(map[string]interface{})
|
reqInfoMap := mv["root"].(map[string]interface{})
|
||||||
if err = utils.Map2StructByJson(reqInfoMap, &refundResult.ReqInfo, false); err == nil {
|
if err = utils.Map2StructByJson(reqInfoMap, &refundResult.ReqInfoObj, false); err == nil {
|
||||||
msg.Data = refundResult
|
msg.Data = refundResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if transactionID := utils.Interface2String(mapData["transaction_id"]); transactionID != "" {
|
||||||
|
msg.MsgType = MsgTypePay
|
||||||
|
var payResult *PayResultMsg
|
||||||
|
if err = utils.Map2StructByJson(mapData, &payResult, false); err == nil {
|
||||||
|
msg.Data = payResult
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
35
platformapi/wxpay/callback_test.go
Normal file
35
platformapi/wxpay/callback_test.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package wxpay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPayCallback(t *testing.T) {
|
||||||
|
bodyMsg := strings.Replace(`
|
||||||
|
<xml><appid><![CDATA[wx4b5930c13f8b1170]]></appid>\n<bank_type><![CDATA[CMB_CREDIT]]></bank_type>\n<cash_fee><![CDATA[1]]></cash_fee>\n<fee_type><![CDATA[CNY]]></fee_type>\n<is_subscribe><![CDATA[N]]></is_subscribe>\n<mch_id><![CDATA[1390686702]]></mch_id>\n<nonce_str><![CDATA[8E0DDB300B7511EA908C186590E02977]]></nonce_str>\n<openid><![CDATA[ojWb10N52xdnLuInkn06bkn9pUhk]]></openid>\n<out_trade_no><![CDATA[8E0DD6260B7511EA908C186590E02977]]></out_trade_no>\n<result_code><![CDATA[SUCCESS]]></result_code>\n<return_code><![CDATA[SUCCESS]]></return_code>\n<sign><![CDATA[5281BDD91AF551FF7CDF1A0F6D702A30]]></sign>\n<time_end><![CDATA[20191120171206]]></time_end>\n<total_fee>1</total_fee>\n<trade_type><![CDATA[NATIVE]]></trade_type>\n<transaction_id><![CDATA[4200000455201911201954456843]]></transaction_id>\n</xml>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
`, "\\n", "\n", -1)
|
||||||
|
result, err := api.getCallbackMsg(bodyMsg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(utils.Format4Output(result, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPayRefundCallback(t *testing.T) {
|
||||||
|
bodyMsg := strings.Replace(`
|
||||||
|
<xml><return_code>SUCCESS</return_code><appid><![CDATA[wx4b5930c13f8b1170]]></appid><mch_id><![CDATA[1390686702]]></mch_id><nonce_str><![CDATA[092e154ce3baac44dd1c9091b50639ec]]></nonce_str><req_info><![CDATA[5bRx2mV2fwR09J0CxiLBfJkeIFYRgW6m8qKkz853XZEf5nxXLzevP7j2eF+Gno1v/800tU4ZRAW1RsJjNUckKdtHBxvaVMxD+oMzDRf1YqRSfiLS9s6km1aMAXwqlJbX3leMWw9QNmngeNBA2cSiZe02pY8Gbj+R8b2YEU2QStq+1+iZya14fvvc9wxTtXBO3KeZ9beJ0jf/mI7IEBXC1KG5QX42Yuyo8gXFQwF/64wr/2gsg+A8KVwEJF07lVEMPYhRdXz8C5Qr40nVM1Pd8ulHEoO+kCELW5GWjT2hs8Io4e6OLtZ5kG8Zp7E5u7iY5XmpTIsgtypn9AuW2voCBZ0VAeYVmcsR6qVBJFKVVkcDA0Kmb0II3cp9otOztGgfATuqDAfncYEoC8NqUdopwBVesC7fEbOEdfPfi6GvJdXTN4mAjDVtRudvttLn3+wTt5X7BqgeuZrAfcbT/gr3pbUFi2Cgv7ubHWtcOGFyhIw/qnA7burUMZ06WdT6Q0CZKeWPJTgT0UbB47T15Zbu9VFeMS0cZlOxn2L1cU/XgY/XDRmjB7gDayasrHQUaotj7F77KSX5Ijf+YbTmVyiGDwb1vocLlQMZax6GD9ECcytFty1jdW9GYJVz56Xnbmq9K7LUgzNZURlWZPY+aoPv8rG+3LaRAKDLBzQYKN2+lyNziXBP60xRicdMHmdTnYHPb8Bcj5c0Byy9ufw9+hMjAXzC9D9qMeDxvt1qHjGd3b8bA6cgpbQtDg6vI3arruiR+WVfn9/ZN26WrG/iLxST927wXmHRwJSitCBty0X/x+/lealMiyC3Kmf0C5ba+gIFxOe1Wx7OP0RQmkL5WPvttMf7ogU9RZamVfjgs6aPw3l4bxTmMHJkSvePUpdWpOU4ZXVH+aVgcX3KZWrn7ltf2Tvdbfi8IVFjzbvwn+4smC6u4cMQpMMpRLeuIqwwwg4J+rqOkyV3JdiTGInu2NErhFshQl868hoaSe4lJ2aaU/z9miDtBQkS0K3bQIWIUv4+kLyEgzQ6ld3qjEXEVme/DiLygEJLstIXvNMY43MdUYRF1BpOzpVB/ed28bQrshx++ROPrjthlX4bwksi5Qtpvg==]]></req_info></xml>
|
||||||
|
|
||||||
|
|
||||||
|
`, "\\n", "\n", -1)
|
||||||
|
result, err := api.getCallbackMsg(bodyMsg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(utils.Format4Output(result, false))
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package wxpay
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -16,8 +17,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
prodURL = "https://api.mch.weixin.qq.com/pay"
|
prodURL = "https://api.mch.weixin.qq.com"
|
||||||
sandboxURL = "https://api.mch.weixin.qq.com/sandboxnew/pay"
|
sandboxURL = "https://api.mch.weixin.qq.com/sandboxnew"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -169,6 +170,46 @@ type CreateOrderResult struct {
|
|||||||
CodeURL string `json:"code_url"`
|
CodeURL string `json:"code_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PayRefundParam struct {
|
||||||
|
RequestBase
|
||||||
|
|
||||||
|
TransactionID string `json:"transaction_id,omitempty" xml:"transaction_id,omitempty"`
|
||||||
|
OutTradeNo string `json:"out_trade_no,omitempty" xml:"out_trade_no,omitempty"`
|
||||||
|
OutRefundNo string `json:"out_refund_no" xml:"out_refund_no"`
|
||||||
|
TotalFee int `json:"total_fee" xml:"total_fee"`
|
||||||
|
RefundFee int `json:"refund_fee" xml:"refund_fee"`
|
||||||
|
|
||||||
|
RefundFeeType string `json:"refund_fee_type,omitempty" xml:"refund_fee_type,omitempty"`
|
||||||
|
RefundDesc CData `json:"refund_desc,omitempty" xml:"refund_desc,omitempty"`
|
||||||
|
NotifyURL string `json:"notify_url,omitempty" xml:"notify_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PayRefundResult struct {
|
||||||
|
ReturnCode string `json:"return_code" xml:"return_code"`
|
||||||
|
ReturnMsg string `json:"return_msg" xml:"return_msg"`
|
||||||
|
|
||||||
|
AppID string `json:"appid" xml:"appid"`
|
||||||
|
DeviceInfo string `json:"device_info,omitempty" xml:"device_info,omitempty"`
|
||||||
|
MchID string `json:"mch_id" xml:"mch_id"`
|
||||||
|
NonceStr string `json:"nonce_str" xml:"nonce_str"`
|
||||||
|
Sign string `json:"sign" xml:"sign"`
|
||||||
|
ResultCode string `json:"result_code" xml:"result_code"`
|
||||||
|
ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"`
|
||||||
|
ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"`
|
||||||
|
|
||||||
|
CashFee string `json:"cash_fee"`
|
||||||
|
CashRefundFee string `json:"cash_refund_fee"`
|
||||||
|
CouponRefundCount string `json:"coupon_refund_count"`
|
||||||
|
CouponRefundFee string `json:"coupon_refund_fee"`
|
||||||
|
OutRefundNo string `json:"out_refund_no"`
|
||||||
|
OutTradeNo string `json:"out_trade_no"`
|
||||||
|
RefundChannel string `json:"refund_channel"`
|
||||||
|
RefundFee string `json:"refund_fee"`
|
||||||
|
RefundID string `json:"refund_id"`
|
||||||
|
TotalFee string `json:"total_fee"`
|
||||||
|
TransactionID string `json:"transaction_id"`
|
||||||
|
}
|
||||||
|
|
||||||
func New(appID, appKey, mchID string, config ...*platformapi.APIConfig) *API {
|
func New(appID, appKey, mchID string, config ...*platformapi.APIConfig) *API {
|
||||||
curConfig := platformapi.DefAPIConfig
|
curConfig := platformapi.DefAPIConfig
|
||||||
if len(config) > 0 {
|
if len(config) > 0 {
|
||||||
@@ -183,6 +224,19 @@ func New(appID, appKey, mchID string, config ...*platformapi.APIConfig) *API {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewWithCertificate(appID, appKey, mchID string, certPEMBlock, keyPEMBlock []byte, config ...*platformapi.APIConfig) (a *API) {
|
||||||
|
certs, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
|
||||||
|
if err == nil {
|
||||||
|
a = New(appID, appKey, mchID, config...)
|
||||||
|
a.client.Transport = &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{certs},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
func (a *API) GetAppID() string {
|
func (a *API) GetAppID() string {
|
||||||
return a.appID
|
return a.appID
|
||||||
}
|
}
|
||||||
@@ -237,6 +291,12 @@ func (a *API) AccessAPI(action string, requestParam IRequestBase) (retVal map[st
|
|||||||
retVal, errLevel, err = a.checkResultAsMap(jsonResult1[platformapi.KeyData].(string))
|
retVal, errLevel, err = a.checkResultAsMap(jsonResult1[platformapi.KeyData].(string))
|
||||||
return errLevel, err
|
return errLevel, err
|
||||||
})
|
})
|
||||||
|
if err == nil {
|
||||||
|
if utils.Interface2String(retVal["result_code"]) != ResponseCodeSuccess {
|
||||||
|
err = utils.NewErrorCode(utils.Interface2String(retVal["err_code_des"]), utils.Interface2String(retVal["err_code"]))
|
||||||
|
retVal = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return retVal, err
|
return retVal, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,13 +311,6 @@ func (a *API) checkResultAsMap(xmlStr string) (result map[string]interface{}, er
|
|||||||
errLevel = platformapi.ErrLevelGeneralFail
|
errLevel = platformapi.ErrLevelGeneralFail
|
||||||
err = utils.NewErrorCode(utils.Interface2String(result["return_msg"]), returnCode)
|
err = utils.NewErrorCode(utils.Interface2String(result["return_msg"]), returnCode)
|
||||||
result = nil
|
result = nil
|
||||||
} else {
|
|
||||||
// if utils.Interface2String(result["result_code"]) != ResponseCodeSuccess {
|
|
||||||
// errLevel = platformapi.ErrLevelGeneralFail
|
|
||||||
// err = utils.NewErrorCode(utils.Interface2String(result["err_code_desc"]), utils.Interface2String(result["err_code"]))
|
|
||||||
// result = nil
|
|
||||||
// } else {
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result, errLevel, err
|
return result, errLevel, err
|
||||||
@@ -281,7 +334,7 @@ func (a *API) OrderQuery(transactionID, outTradeNo string) (orderInfo *OrderInfo
|
|||||||
TransactionID: transactionID,
|
TransactionID: transactionID,
|
||||||
OutTradeNo: outTradeNo,
|
OutTradeNo: outTradeNo,
|
||||||
}
|
}
|
||||||
retVal, err := a.AccessAPI("orderquery", param)
|
retVal, err := a.AccessAPI("pay/orderquery", param)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = utils.Map2StructByJson(retVal, &orderInfo, false)
|
err = utils.Map2StructByJson(retVal, &orderInfo, false)
|
||||||
}
|
}
|
||||||
@@ -289,9 +342,20 @@ func (a *API) OrderQuery(transactionID, outTradeNo string) (orderInfo *OrderInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) CreateUnifiedOrder(param *CreateOrderParam) (createOrderResult *CreateOrderResult, err error) {
|
func (a *API) CreateUnifiedOrder(param *CreateOrderParam) (createOrderResult *CreateOrderResult, err error) {
|
||||||
retVal, err := a.AccessAPI("unifiedorder", param)
|
retVal, err := a.AccessAPI("pay/unifiedorder", param)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = utils.Map2StructByJson(retVal, &createOrderResult, false)
|
err = utils.Map2StructByJson(retVal, &createOrderResult, false)
|
||||||
}
|
}
|
||||||
return createOrderResult, err
|
return createOrderResult, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *API) PayRefund(param *PayRefundParam) (refundResult *PayRefundResult, err error) {
|
||||||
|
if a.client.Transport == nil {
|
||||||
|
return nil, fmt.Errorf("没有配置证书,不能退款")
|
||||||
|
}
|
||||||
|
retVal, err := a.AccessAPI("secapi/pay/refund", param)
|
||||||
|
if err == nil {
|
||||||
|
err = utils.Map2StructByJson(retVal, &refundResult, false)
|
||||||
|
}
|
||||||
|
return refundResult, err
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package wxpay
|
package wxpay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -20,8 +21,10 @@ func init() {
|
|||||||
logger, _ := zap.NewDevelopment()
|
logger, _ := zap.NewDevelopment()
|
||||||
sugarLogger = logger.Sugar()
|
sugarLogger = logger.Sugar()
|
||||||
baseapi.Init(sugarLogger)
|
baseapi.Init(sugarLogger)
|
||||||
|
certPEMBlock, _ := ioutil.ReadFile("1390686702_20190115_cert/apiclient_cert.pem")
|
||||||
api = New("wx4b5930c13f8b1170", "XKJPOIHJ233adf01KJIXlIeQDSDKFJAD", "1390686702")
|
keyPEMBlock, _ := ioutil.ReadFile("1390686702_20190115_cert/apiclient_key.pem")
|
||||||
|
api = NewWithCertificate("wx4b5930c13f8b1170", "XKJPOIHJ233adf01KJIXlIeQDSDKFJAD", "1390686702", certPEMBlock, keyPEMBlock)
|
||||||
|
// api = New("wx4b5930c13f8b1170", "XKJPOIHJ233adf01KJIXlIeQDSDKFJAD", "1390686702")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOrderQuery(t *testing.T) {
|
func TestOrderQuery(t *testing.T) {
|
||||||
@@ -33,10 +36,12 @@ func TestOrderQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateUnifiedOrder(t *testing.T) {
|
func TestCreateUnifiedOrder(t *testing.T) {
|
||||||
|
orderNo := "367609100BA711EAAA20186590E02977" // utils.GetUUID()
|
||||||
|
// t.Log(orderNo)
|
||||||
result, err := api.CreateUnifiedOrder(&CreateOrderParam{
|
result, err := api.CreateUnifiedOrder(&CreateOrderParam{
|
||||||
Body: "这里一个测试商品",
|
Body: "这里一个测试商品",
|
||||||
NotifyURL: "http://callback.test.jxc4.com/wxpay/msg/",
|
NotifyURL: "http://callback.test.jxc4.com/wxpay/msg/",
|
||||||
OutTradeNo: utils.GetUUID(),
|
OutTradeNo: orderNo,
|
||||||
SpbillCreateIP: "114.114.114.114",
|
SpbillCreateIP: "114.114.114.114",
|
||||||
TradeType: TradeTypeNative,
|
TradeType: TradeTypeNative,
|
||||||
TotalFee: 1,
|
TotalFee: 1,
|
||||||
@@ -47,6 +52,21 @@ func TestCreateUnifiedOrder(t *testing.T) {
|
|||||||
t.Log(utils.Format4Output(result, false))
|
t.Log(utils.Format4Output(result, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPayRefund(t *testing.T) {
|
||||||
|
result, err := api.PayRefund(&PayRefundParam{
|
||||||
|
TransactionID: "",
|
||||||
|
OutTradeNo: "8E0DD6260B7511EA908C186590E02977",
|
||||||
|
NotifyURL: "http://callback.test.jxc4.com/wxpay/msg/",
|
||||||
|
OutRefundNo: utils.GetUUID(),
|
||||||
|
TotalFee: 1,
|
||||||
|
RefundFee: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(utils.Format4Output(result, false))
|
||||||
|
}
|
||||||
|
|
||||||
func TestXml2Json(t *testing.T) {
|
func TestXml2Json(t *testing.T) {
|
||||||
xmlStr := strings.Replace(`
|
xmlStr := strings.Replace(`
|
||||||
<root>
|
<root>
|
||||||
|
|||||||
Reference in New Issue
Block a user