diff --git a/README.md b/README.md index b9205aff..c9786a5d 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ * NATIVE - Native支付 * APP - app支付 * MWEB - H5支付 -* 查询订单(开发中) +* 查询订单 * 关闭订单(开发中) * 申请退款(开发中) * 查询退款(开发中) @@ -34,62 +34,82 @@ $ go get github.com/iGoogle-ink/gopay 未完成 -## 微信统一下单 example +## 微信 + +注意:具体参数根据请求的不同而不同,请参考微信官方文档的参数说明! + +参考文档:[微信支付文档](https://pay.weixin.qq.com/wiki/doc/api/index.html) -* 初始化客户端 - * 参数:AppId:应用ID - * 参数:mchID:商户ID - * 参数:secretKey:Key值 - * 参数:isProd:是否正式环境 + +### 统一下单 ```go -//正式环境 +//初始化微信客户端 +// appId:应用ID +// mchID:商户ID +// secretKey:Key值 +// isProd:是否是正式环境 client := gopay.NewWeChatClient("wxd678efh567hg6787", "1230000109", "192006250b4c09247ec02edce69f6a2d", true) -//沙箱环境 -client := gopay.NewWeChatClient("wxd678efh567hg6787", "1230000109", "192006250b4c09247ec02edce69f6a2d", false) +//初始化参数Map +body := make(gopay.BodyMap) +body.Set("nonce_str", gopay.GetRandomString(32)) +body.Set("body", "测试支付") +number := gopay.GetRandomString(32) +log.Println("Number:", number) +body.Set("out_trade_no", number) +body.Set("total_fee", 1) +body.Set("spbill_create_ip", "127.0.0.1") //终端IP +body.Set("notify_url", "http://www.igoogle.ink") +body.Set("trade_type", gopay.TradeType_JsApi) +body.Set("device_info", "WEB") +body.Set("sign_type", gopay.SignType_MD5) +//body.Set("scene_info", `{"h5_info": {"type":"Wap","wap_url": "http://www.igoogle.ink","wap_name": "测试支付"}}`) +body.Set("openid", "o0Df70H2Q0fY8JXh1aFPIRyOBgu6") + +//发起下单请求 +wxRsp, err := client.UnifiedOrder(body) +if err != nil { + fmt.Println("Error:", err) + return +} +fmt.Println("ReturnCode:", wxRsp.ReturnCode) +fmt.Println("ReturnMsg:", wxRsp.ReturnMsg) +fmt.Println("Appid:", wxRsp.Appid) +fmt.Println("MchId:", wxRsp.MchId) +fmt.Println("DeviceInfo:", wxRsp.DeviceInfo) +fmt.Println("NonceStr:", wxRsp.NonceStr) +fmt.Println("Sign:", wxRsp.Sign) +fmt.Println("ResultCode:", wxRsp.ResultCode) +fmt.Println("ErrCode:", wxRsp.ErrCode) +fmt.Println("ErrCodeDes:", wxRsp.ErrCodeDes) +fmt.Println("PrepayId:", wxRsp.PrepayId) +fmt.Println("TradeType:", wxRsp.TradeType) +fmt.Println("CodeUrl:", wxRsp.CodeUrl) +fmt.Println("MwebUrl:", wxRsp.MwebUrl) ``` -* 初始化统一下单参数 -> 以下参数设置皆为必选参数,如需其他参数,请参考API文档。 -> -> 参考文档:[微信支付文档](https://pay.weixin.qq.com/wiki/doc/api/index.html) +### 查询订单 ```go -params := new(gopay.WeChatPayParams) -params.NonceStr = "dyUNIkNS29hvDUC1CmoF0alSdfCQGg9I" -params.Body = "支付测试" -params.OutTradeNo = "GYsadfjk4dhg3fkh3ffgnlsdkf" -params.TotalFee = 10 //单位为分,如沙箱环境,则默认为101 -params.SpbillCreateIp = "127.0.0.1" -params.NotifyUrl = "http://www.igoogle.ink" -params.TradeType = gopay.WX_PayType_JsApi -params.DeviceInfo = "WEB" -params.SignType = gopay.WX_SignType_HMAC_SHA256 //如不设置此参数,默认为MD5,如沙箱环境,则默认为MD5 -params.Openid = "o0Df70H2Q0fY8JXh1aFPIRyOBgu8" //JSAPI 方式时,此参数必填 -``` +//初始化微信客户端 +// appId:应用ID +// mchID:商户ID +// secretKey:Key值 +// isProd:是否是正式环境 +client := gopay.NewWeChatClient("wxd678efh567hg6787", "1230000109", "192006250b4c09247ec02edce69f6a2d", true) -* 发起统一下单请求 - * 参数:param:统一下单请求参数 -> 请求成功后,获取下单结果 -```go -wxRsp, err := client.UnifiedOrder(params) +//初始化参数结构体 +body := make(gopay.BodyMap) +body.Set("out_trade_no", "CC68aTofMIwVKkVR5UruoBLFFXTAqBfv") +body.Set("nonce_str", gopay.GetRandomString(32)) +body.Set("sign_type", gopay.SignType_MD5) + +//请求订单查询 +wxRsp, err := client.QueryOrder(body) if err != nil { fmt.Println("Error:", err) -} else { - fmt.Println("ReturnCode:", wxRsp.ReturnCode) - fmt.Println("ReturnMsg:", wxRsp.ReturnMsg) - fmt.Println("Appid:", wxRsp.Appid) - fmt.Println("MchId:", wxRsp.MchId) - fmt.Println("DeviceInfo:", wxRsp.DeviceInfo) - fmt.Println("NonceStr:", wxRsp.NonceStr) - fmt.Println("Sign:", wxRsp.Sign) - fmt.Println("ResultCode:", wxRsp.ResultCode) - fmt.Println("ErrCode:", wxRsp.ErrCode) - fmt.Println("ErrCodeDes:", wxRsp.ErrCodeDes) - fmt.Println("PrepayId:", wxRsp.PrepayId) - fmt.Println("TradeType:", wxRsp.TradeType) - fmt.Println("CodeUrl:", wxRsp.CodeUrl) - fmt.Println("MwebUrl:", wxRsp.MwebUrl) + return } +fmt.Println("Response:", wxRsp) ``` ## 支付宝支付 example diff --git a/ali_pay.go b/alipay_client.go similarity index 100% rename from ali_pay.go rename to alipay_client.go diff --git a/ali_pay_test.go b/alipay_client_test.go similarity index 100% rename from ali_pay_test.go rename to alipay_client_test.go diff --git a/constant.go b/constant.go index 0714cf39..7b9e09b5 100644 --- a/constant.go +++ b/constant.go @@ -5,25 +5,25 @@ const ( wx_base_url = "https://api.mch.weixin.qq.com/" wx_sanbox_base_url = "https://api.mch.weixin.qq.com/sandboxnew/" - wxURL_unifiedOrder = wx_base_url + "pay/unifiedorder" - wxURL_orderquery = wx_base_url + "pay/orderquery" - wxURL_closeorder = wx_base_url + "pay/closeorder" + wxURL_UnifiedOrder = wx_base_url + "pay/unifiedorder" + wxURL_OrderQuery = wx_base_url + "pay/orderquery" + wxURL_CloseOrder = wx_base_url + "pay/closeorder" - wxURL_sanbox_getsignkey = wx_sanbox_base_url + "pay/getsignkey" - wxURL_sanbox_unifiedOrder = wx_sanbox_base_url + "pay/unifiedorder" - wxURL_sanbox_orderquery = wx_sanbox_base_url + "pay/orderquery" - wxURL_sanbox_closeorder = wx_sanbox_base_url + "pay/closeorder" + wxURL_SanBox_GetSignKey = wx_sanbox_base_url + "pay/getsignkey" + wxURL_SanBox_UnifiedOrder = wx_sanbox_base_url + "pay/unifiedorder" + wxURL_SanBox_OrderQuery = wx_sanbox_base_url + "pay/orderquery" + wxURL_SanBox_CloseOrder = wx_sanbox_base_url + "pay/closeorder" //支付类型 - WX_PayType_Mini = "JSAPI" - WX_PayType_JsApi = "JSAPI" - WX_PayType_App = "APP" - WX_PayType_H5 = "MWEB" - WX_PayType_Native = "NATIVE" + TradeType_Mini = "JSAPI" + TradeType_JsApi = "JSAPI" + TradeType_App = "APP" + TradeType_H5 = "MWEB" + TradeType_Native = "NATIVE" //签名方式 - WX_SignType_MD5 = "MD5" - WX_SignType_HMAC_SHA256 = "HMAC-SHA256" + SignType_MD5 = "MD5" + SignType_HMAC_SHA256 = "HMAC-SHA256" //Debug数据 secretKey = "GFDS8j98rewnmgl45wHTt980jg543wmg" diff --git a/util.go b/util.go index c0c6549f..ac47c3fc 100644 --- a/util.go +++ b/util.go @@ -2,29 +2,39 @@ package gopay import ( "bytes" + "encoding/xml" + "errors" + "github.com/parnurzeal/gorequest" "math/rand" + "sort" + "strconv" "time" ) -type requestBody map[string]string +type BodyMap map[string]interface{} //设置参数 -func (w requestBody) Set(key string, value string) { - w[key] = value +func (bm BodyMap) Set(key string, value interface{}) { + bm[key] = value } //获取参数 -func (w requestBody) Get(key string) string { - if w == nil { +func (bm BodyMap) Get(key string) string { + if bm == nil { return "" } - ws := w[key] - return ws + v := bm[key] + value, ok := v.(int) + if ok { + value := strconv.Itoa(value) + return value + } + return v.(string) } //删除参数 -func (w requestBody) Remove(key string) { - delete(w, key) +func (bm BodyMap) Remove(key string) { + delete(bm, key) } //获取随机字符串 @@ -40,20 +50,54 @@ func GetRandomString(length int) string { return string(result) } -func generateXml(w requestBody) (reqXml string) { +//获取根据Key排序后的请求参数字符串 +func sortSignParams(secretKey string, body BodyMap) string { + keyList := make([]string, 0) + for k := range body { + keyList = append(keyList, k) + } + sort.Strings(keyList) buffer := new(bytes.Buffer) - buffer.WriteString("") - - for k, v := range w { - buffer.WriteString("<") + for _, k := range keyList { buffer.WriteString(k) - buffer.WriteString(">") + buffer.WriteString("=") + value, ok := body[k].(int) + if ok { + value := strconv.Itoa(value) + buffer.WriteString(value) + } else { + buffer.WriteString(body[k].(string)) + } + buffer.WriteString("&") + } + buffer.WriteString("key=") + buffer.WriteString(secretKey) + return buffer.String() +} + +//从微信提供的接口获取:SandboxSignkey +func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) { + reqs := make(BodyMap) + reqs.Set("mch_id", mchId) + reqs.Set("nonce_str", nonceStr) + reqs.Set("sign", sign) + + reqXml := generateXml(reqs) + //fmt.Println("req:::", reqXml) + _, byteList, errorList := gorequest.New(). + Post(wxURL_SanBox_GetSignKey). + Type("xml"). + SendString(reqXml).EndBytes() + if len(errorList) > 0 { + return "", errorList[0] + } + keyResponse := new(getSignKeyResponse) + err = xml.Unmarshal(byteList, keyResponse) + if err != nil { + return "", err + } + if keyResponse.ReturnCode == "FAIL" { + return "", errors.New(keyResponse.Retmsg) } - buffer.WriteString("") - reqXml = buffer.String() - return + return keyResponse.SandboxSignkey, nil } diff --git a/wechat_client.go b/wechat_client.go new file mode 100644 index 00000000..6136ac65 --- /dev/null +++ b/wechat_client.go @@ -0,0 +1,154 @@ +package gopay + +import ( + "encoding/xml" + "fmt" + "github.com/parnurzeal/gorequest" +) + +type weChatClient struct { + AppId string + MchId string + secretKey string + isProd bool +} + +//初始化微信客户端 +// appId:应用ID +// mchID:商户ID +// secretKey:Key值 +// isProd:是否是正式环境 +func NewWeChatClient(appId, mchId, secretKey string, isProd bool) *weChatClient { + client := new(weChatClient) + client.AppId = appId + client.MchId = mchId + client.secretKey = secretKey + client.isProd = isProd + return client +} + +//统一下单 +func (this *weChatClient) UnifiedOrder(body BodyMap) (wxRsp *weChatUnifiedOrderResponse, err error) { + var sign string + body.Set("appid", this.AppId) + body.Set("mch_id", this.MchId) + //===============生成参数=================== + if !this.isProd { + //沙箱环境 + body.Set("total_fee", 101) + body.Set("sign_type", SignType_MD5) + //从微信接口获取SanBoxSignKey + key, err := getSanBoxSign(this.MchId, body.Get("nonce_str"), this.secretKey, body.Get("sign_type")) + if err != nil { + return nil, err + } + sign = getLocalSign(key, body.Get("sign_type"), body) + } else { + //正式环境 + //本地计算Sign + sign = getLocalSign(this.secretKey, body.Get("sign_type"), body) + } + + body.Set("sign", sign) + + reqXML := generateXml(body) + fmt.Println("req:::", reqXML) + //===============发起请求=================== + agent := gorequest.New() + if this.isProd { + agent.Post(wxURL_UnifiedOrder) + } else { + agent.Post(wxURL_SanBox_UnifiedOrder) + } + agent.Type("xml") + agent.SendString(reqXML) + response, bytes, errs := agent.EndBytes() + defer response.Body.Close() + if len(errs) > 0 { + return nil, errs[0] + } + //fmt.Println("bytes:", string(bytes)) + wxRsp = new(weChatUnifiedOrderResponse) + err = xml.Unmarshal(bytes, wxRsp) + if err != nil { + return nil, err + } + return wxRsp, nil +} + +//查询订单 +func (this *weChatClient) QueryOrder(body BodyMap) (wxRsp *weChatQueryOrderResponse, err error) { + var sign string + body.Set("appid", this.AppId) + body.Set("mch_id", this.MchId) + //===============生成参数=================== + if !this.isProd { + //沙箱环境 + body.Set("sign_type", SignType_MD5) + //从微信接口获取SanBoxSignKey + key, err := getSanBoxSign(this.MchId, body.Get("nonce_str"), this.secretKey, body.Get("sign_type")) + if err != nil { + return nil, err + } + sign = getLocalSign(key, body.Get("sign_type"), body) + } else { + //正式环境 + //本地计算Sign + sign = getLocalSign(this.secretKey, body.Get("sign_type"), body) + } + body.Set("sign", sign) + + reqXML := generateXml(body) + //fmt.Println("req:::", reqXML) + //===============发起请求=================== + agent := gorequest.New() + if this.isProd { + agent.Post(wxURL_OrderQuery) + } else { + agent.Post(wxURL_SanBox_OrderQuery) + } + agent.Type("xml") + agent.SendString(reqXML) + response, bytes, errs := agent.EndBytes() + defer response.Body.Close() + if len(errs) > 0 { + return nil, errs[0] + } + //fmt.Println("bytes:", string(bytes)) + wxRsp = new(weChatQueryOrderResponse) + err = xml.Unmarshal(bytes, wxRsp) + if err != nil { + return nil, err + } + return wxRsp, nil +} + +//关闭订单 +func (this *weChatClient) CloseOrder() { + +} + +//申请退款 +func (this *weChatClient) Refund() { + +} + +//查询退款 +func (this *weChatClient) QueryRefund() { + +} + +//下载对账单 +func (this *weChatClient) DownloadBill() { + +} + +//下载资金账单 +func (this *weChatClient) DownloadFundFlow() { + +} + +//拉取订单评价数据 +func (this *weChatClient) BatchQueryComment() { + +} diff --git a/wechat_client_test.go b/wechat_client_test.go new file mode 100644 index 00000000..fe70b6ab --- /dev/null +++ b/wechat_client_test.go @@ -0,0 +1,62 @@ +package gopay + +import ( + "fmt" + "log" + "testing" +) + +func TestWeChatClient_UnifiedOrder(t *testing.T) { + + //初始化微信客户端 + // appId:应用ID + // mchID:商户ID + // secretKey:Key值 + // isProd:是否是正式环境 + client := NewWeChatClient(appID, mchID, secretKey, true) + + //初始化参数Map + body := make(BodyMap) + body.Set("nonce_str", GetRandomString(32)) + body.Set("body", "测试支付") + number := GetRandomString(32) + log.Println("Number:", number) + body.Set("out_trade_no", number) + body.Set("total_fee", 10) + body.Set("spbill_create_ip", "180.171.101.212") + body.Set("notify_url", "http://www.igoogle.ink") + body.Set("trade_type", TradeType_JsApi) + //body.Set("device_info", "WEB") + body.Set("sign_type", SignType_MD5) + //body.Set("scene_info", `{"h5_info": {"type":"Wap","wap_url": "http://www.igoogle.ink","wap_name": "测试支付"}}`) + //body.Set("openid", openID) + + //请求支付下单,成功后得到结果 + wxRsp, err := client.UnifiedOrder(body) + if err != nil { + fmt.Println("Error:", err) + } + fmt.Println("Response:", wxRsp) +} + +func TestWeChatClient_QueryOrder(t *testing.T) { + //初始化微信客户端 + // appId:应用ID + // mchID:商户ID + // secretKey:Key值 + // isProd:是否是正式环境 + client := NewWeChatClient(appID, mchID, secretKey, true) + + //初始化参数结构体 + params := make(BodyMap) + params.Set("out_trade_no", "CC68aTofMIwVKkVR5UruoBLFFXTAqBfv") + params.Set("nonce_str", GetRandomString(32)) + params.Set("sign_type", SignType_MD5) + + //请求订单查询,成功后得到结果 + wxRsp, err := client.QueryOrder(params) + if err != nil { + fmt.Println("Error:", err) + } + fmt.Println("Response:", wxRsp) +} diff --git a/wechat_params.go b/wechat_params.go index 4e31e331..1be625c2 100644 --- a/wechat_params.go +++ b/wechat_params.go @@ -6,23 +6,25 @@ import ( "crypto/md5" "crypto/sha256" "encoding/hex" - "encoding/xml" - "errors" - "github.com/parnurzeal/gorequest" - "sort" "strconv" "strings" ) //获取请求支付的参数 -func (w *WeChatPayParams) getRequestBody(appId, mchId string, params *WeChatPayParams) (reqs requestBody) { - reqs = make(requestBody) +func getRequestBody(appId, mchId string, params *WeChatPayParams) (reqs BodyMap) { + reqs = make(BodyMap) reqs.Set("appid", appId) reqs.Set("mch_id", mchId) reqs.Set("nonce_str", params.NonceStr) - reqs.Set("body", params.Body) - reqs.Set("out_trade_no", params.OutTradeNo) - reqs.Set("total_fee", strconv.Itoa(params.TotalFee)) + if params.Body != "" { + reqs.Set("body", params.Body) + } + if params.OutTradeNo != "" { + reqs.Set("out_trade_no", params.OutTradeNo) + } + if params.TotalFee != -1 { + reqs.Set("total_fee", strconv.Itoa(params.TotalFee)) + } reqs.Set("spbill_create_ip", params.SpbillCreateIp) reqs.Set("notify_url", params.NotifyUrl) reqs.Set("trade_type", params.TradeType) @@ -66,37 +68,20 @@ func (w *WeChatPayParams) getRequestBody(appId, mchId string, params *WeChatPayP reqs.Set("receipt", params.Receipt) } if params.SceneInfo != "" { - //marshal, _ := json.Marshal(params.SceneInfo) - //reqs.Set("scene_info", string(marshal)) reqs.Set("scene_info", params.SceneInfo) } - return reqs -} - -//获取SanBox秘钥 -func (w *WeChatPayParams) getSanBoxSignKey(mchId, nonceStr, secretKey, signType string) (key string, err error) { - body := make(requestBody) - body.Set("mch_id", mchId) - body.Set("nonce_str", nonceStr) - - //计算沙箱参数Sign - sanboxSign := getSign(secretKey, signType, body) - //沙箱环境:获取key后,重新计算Sign - key, err = getSanBoxSignKey(mchId, nonceStr, sanboxSign) - if err != nil { - return "", err + if params.TransactionId != "" { + reqs.Set("transaction_id", params.TransactionId) } - return + return reqs } -//获取Sign签名和请求支付的参数 -func getSign(secretKey string, signType string, body requestBody) (sign string) { - - signStr := getSignString(secretKey, body) +//本地通过支付参数计算Sign值 +func getLocalSign(secretKey string, signType string, body BodyMap) (sign string) { + signStr := sortSignParams(secretKey, body) //fmt.Println("signStr:", signStr) var hashSign []byte - if signType == WX_SignType_MD5 { - + if signType == SignType_MD5 { hash := md5.New() hash.Write([]byte(signStr)) hashSign = hash.Sum(nil) @@ -109,48 +94,43 @@ func getSign(secretKey string, signType string, body requestBody) (sign string) return } -//获取根据Key排序后的请求参数字符串 -func getSignString(secretKey string, body requestBody) string { - keyList := make([]string, 0) - for k := range body { - keyList = append(keyList, k) - } - sort.Strings(keyList) - buffer := new(bytes.Buffer) - for _, k := range keyList { - buffer.WriteString(k) - buffer.WriteString("=") - buffer.WriteString(body[k]) - buffer.WriteString("&") - } - buffer.WriteString("key=") - buffer.WriteString(secretKey) - return buffer.String() -} - -//获取SanboxKey -func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) { - reqs := make(requestBody) - reqs.Set("mch_id", mchId) - reqs.Set("nonce_str", nonceStr) - reqs.Set("sign", sign) +//从微信提供的接口获取:SandboxSignKey +func getSanBoxSign(mchId, nonceStr, secretKey, signType string) (key string, err error) { + body := make(BodyMap) + body.Set("mch_id", mchId) + body.Set("nonce_str", nonceStr) - reqXml := generateXml(reqs) - //fmt.Println("req:::", reqXml) - _, byteList, errorList := gorequest.New(). - Post(wxURL_sanbox_getsignkey). - Type("xml"). - SendString(reqXml).EndBytes() - if len(errorList) > 0 { - return "", errorList[0] - } - keyResponse := new(getSignKeyResponse) - err = xml.Unmarshal(byteList, keyResponse) + //计算沙箱参数Sign + sanboxSign := getLocalSign(secretKey, signType, body) + //沙箱环境:获取key后,重新计算Sign + key, err = getSanBoxSignKey(mchId, nonceStr, sanboxSign) if err != nil { return "", err } - if keyResponse.ReturnCode == "FAIL" { - return "", errors.New(keyResponse.Retmsg) + return +} + +//生成请求XML的Body体 +func generateXml(bm BodyMap) (reqXml string) { + buffer := new(bytes.Buffer) + buffer.WriteString("") + + for k, v := range bm { + buffer.WriteString("<") + buffer.WriteString(k) + buffer.WriteString(">") } - return keyResponse.SandboxSignkey, nil + buffer.WriteString("") + reqXml = buffer.String() + return } diff --git a/wechat_pay.go b/wechat_pay.go deleted file mode 100644 index 495f4c6a..00000000 --- a/wechat_pay.go +++ /dev/null @@ -1,109 +0,0 @@ -package gopay - -import ( - "encoding/xml" - "github.com/parnurzeal/gorequest" -) - -type weChatClient struct { - AppId string - MchId string - secretKey string - isProd bool -} - -//初始化微信客户端 -// appId:应用ID -// mchID:商户ID -// secretKey:Key值 -// isProd:是否是正式环境 -func NewWeChatClient(appId, mchId, secretKey string, isProd bool) *weChatClient { - client := new(weChatClient) - client.AppId = appId - client.MchId = mchId - client.secretKey = secretKey - client.isProd = isProd - return client -} - -//统一下单 -func (this *weChatClient) UnifiedOrder(param *WeChatPayParams) (wxRsp *weChatPayResponse, err error) { - var reqs requestBody - var sign string - //生成下单请求参数 - if !this.isProd { - //沙箱环境 - param.TotalFee = 101 - param.SignType = WX_SignType_MD5 - reqs = param.getRequestBody(this.AppId, this.MchId, param) - key, err := param.getSanBoxSignKey(this.MchId, param.NonceStr, this.secretKey, param.SignType) - if err != nil { - return nil, err - } - sign = getSign(key, param.SignType, reqs) - } else { - reqs = param.getRequestBody(this.AppId, this.MchId, param) - //计算Sign - sign = getSign(this.secretKey, param.SignType, reqs) - } - - reqs.Set("sign", sign) - - reqXML := generateXml(reqs) - //fmt.Println("req:::", reqXML) - agent := gorequest.New() - if this.isProd { - agent.Post(wxURL_unifiedOrder) - } else { - agent.Post(wxURL_sanbox_unifiedOrder) - } - agent.Type("xml") - agent.SendString(reqXML) - response, bytes, errs := agent.EndBytes() - defer response.Body.Close() - if len(errs) > 0 { - return nil, errs[0] - } - //fmt.Println("bytes:", string(bytes)) - wxRsp = new(weChatPayResponse) - err = xml.Unmarshal(bytes, wxRsp) - if err != nil { - return nil, err - } - return wxRsp, nil -} - -//查询订单 -func (this *weChatClient) QueryOrder() { - -} - -//关闭订单 -func (this *weChatClient) CloseOrder() { - -} - -//申请退款 -func (this *weChatClient) Refund() { - -} - -//查询退款 -func (this *weChatClient) QueryRefund() { - -} - -//下载对账单 -func (this *weChatClient) DownloadBill() { - -} - -//下载资金账单 -func (this *weChatClient) DownloadFundFlow() { - -} - -//拉取订单评价数据 -func (this *weChatClient) BatchQueryComment() { - -} diff --git a/wechat_pay_test.go b/wechat_pay_test.go deleted file mode 100644 index 2dc93ca5..00000000 --- a/wechat_pay_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package gopay - -import ( - "fmt" - "testing" -) - -func TestWXPay(t *testing.T) { - - //初始化微信客户端 - // appId:应用ID - // mchID:商户ID - // secretKey:Key值 - // isProd:是否是正式环境 - client := NewWeChatClient(appID, mchID, secretKey, true) - - //初始化参数结构体 - params := new(WeChatPayParams) - params.NonceStr = "dyUNIkNS29hvDUC1CmoF0alSdfCQGg9I" - params.Body = "测试充值" - params.OutTradeNo = "GYsadfjk4dhg3fk13ffgnlsdkf" - params.TotalFee = 10 //单位为分 - params.SpbillCreateIp = "127.0.0.1" - params.NotifyUrl = "http://www.igoogle.ink" - params.TradeType = WX_PayType_JsApi //目前只支持JSAPI有效 - params.DeviceInfo = "WEB" - params.SignType = WX_SignType_HMAC_SHA256 //如不设置此参数,默认为 MD5 - params.Openid = openID - - //请求支付下单,成功后得到结果 - wxRsp, err := client.UnifiedOrder(params) - if err != nil { - fmt.Println("Error:", err) - } else { - fmt.Println("ReturnCode:", wxRsp.ReturnCode) - fmt.Println("ReturnMsg:", wxRsp.ReturnMsg) - fmt.Println("Appid:", wxRsp.Appid) - fmt.Println("MchId:", wxRsp.MchId) - fmt.Println("DeviceInfo:", wxRsp.DeviceInfo) - fmt.Println("NonceStr:", wxRsp.NonceStr) - fmt.Println("Sign:", wxRsp.Sign) - fmt.Println("ResultCode:", wxRsp.ResultCode) - fmt.Println("ErrCode:", wxRsp.ErrCode) - fmt.Println("ErrCodeDes:", wxRsp.ErrCodeDes) - fmt.Println("PrepayId:", wxRsp.PrepayId) - fmt.Println("TradeType:", wxRsp.TradeType) - fmt.Println("CodeUrl:", wxRsp.CodeUrl) - fmt.Println("MwebUrl:", wxRsp.MwebUrl) - } -} diff --git a/wechat_request_body.go b/wechat_req.go similarity index 96% rename from wechat_request_body.go rename to wechat_req.go index 485c594c..dd327e9e 100644 --- a/wechat_request_body.go +++ b/wechat_req.go @@ -30,7 +30,10 @@ package gopay // Openid: 用户标识: trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识. // Receipt: Y,传入Y时,支付成功消息和支付详情页将出现开票入口。需要在微信支付商户平台或微信公众平台开通电子发票功能,传此字段才可生效. // SceneInfo: 该字段常用于线下活动时的场景信息上报,支持上报实际门店信息,商户也可以按需求自己上报相关信息。该字段为JSON对象数据,对象格式为{"store_info":{"id": "门店ID","name": "名称","area_code": "编码","address": "地址" }}. +// TransactionId:微信的订单号,建议优先使用,与OutTradeNo二选一 +// type WeChatPayParams struct { + //统一下单 NonceStr string `xml:"nonce_str"` Body string `xml:"body"` OutTradeNo string `xml:"out_trade_no"` @@ -51,6 +54,8 @@ type WeChatPayParams struct { Openid string `xml:"openid"` Receipt string `xml:"receipt"` SceneInfo string `xml:"scene_info"` + //查询订单 + TransactionId string `json:"transaction_id"` } //StoreInfo: SceneInfo 的字段信息 diff --git a/wechat_response.go b/wechat_response.go deleted file mode 100644 index 3d62c2ab..00000000 --- a/wechat_response.go +++ /dev/null @@ -1,32 +0,0 @@ -//================================== -// * Name:Jerry -// * Tel:18017448610 -// * DateTime:2019/1/13 14:03 -//================================== -package gopay - -type weChatPayResponse struct { - ReturnCode string `xml:"return_code"` - ReturnMsg string `xml:"return_msg"` - Appid string `xml:"appid"` - MchId string `xml:"mch_id"` - DeviceInfo string `xml:"device_info"` - NonceStr string `xml:"nonce_str"` - Sign string `xml:"sign"` - ResultCode string `xml:"result_code"` - ErrCode string `xml:"err_code"` - ErrCodeDes string `xml:"err_code_des"` - TradeType string `xml:"trade_type"` - PrepayId string `xml:"prepay_id"` - CodeUrl string `xml:"code_url"` - MwebUrl string `xml:"mweb_url"` -} - -type getSignKeyResponse struct { - ReturnCode string `xml:"return_code"` - ReturnMsg string `xml:"return_msg"` - Retmsg string `xml:"retmsg"` - Retcode string `xml:"retcode"` - MchId string `xml:"mch_id"` - SandboxSignkey string `xml:"sandbox_signkey"` -} diff --git a/wechat_rsp.go b/wechat_rsp.go new file mode 100644 index 00000000..040a34c2 --- /dev/null +++ b/wechat_rsp.go @@ -0,0 +1,65 @@ +//================================== +// * Name:Jerry +// * Tel:18017448610 +// * DateTime:2019/1/13 14:03 +//================================== +package gopay + +type weChatUnifiedOrderResponse struct { + ReturnCode string `xml:"return_code"` + ReturnMsg string `xml:"return_msg"` + Appid string `xml:"appid"` + MchId string `xml:"mch_id"` + DeviceInfo string `xml:"device_info"` + NonceStr string `xml:"nonce_str"` + Sign string `xml:"sign"` + ResultCode string `xml:"result_code"` + ErrCode string `xml:"err_code"` + ErrCodeDes string `xml:"err_code_des"` + TradeType string `xml:"trade_type"` + PrepayId string `xml:"prepay_id"` + CodeUrl string `xml:"code_url"` + MwebUrl string `xml:"mweb_url"` +} + +type weChatQueryOrderResponse struct { + ReturnCode string `xml:"return_code"` + ReturnMsg string `xml:"return_msg"` + Appid string `xml:"appid"` + MchId string `xml:"mch_id"` + NonceStr string `xml:"nonce_str"` + Sign string `xml:"sign"` + ResultCode string `xml:"result_code"` + ErrCode string `xml:"err_code"` + ErrCodeDes string `xml:"err_code_des"` + DeviceInfo string `xml:"device_info"` + Openid string `xml:"openid"` + IsSubscribe string `xml:"is_subscribe"` + TradeType string `xml:"trade_type"` + TradeState string `xml:"trade_state"` + BankType string `xml:"bank_type"` + TotalFee int `xml:"total_fee"` + SettlementTotalFee int `xml:"settlement_total_fee"` + FeeType string `xml:"fee_type"` + CashFee int `xml:"cash_fee"` + CashFeeType string `xml:"cash_fee_type"` + CouponFee int `xml:"coupon_fee"` + CouponCount int `xml:"coupon_count"` + CouponType0 string `xml:"coupon_type_$0"` + CouponId0 string `xml:"coupon_id_$0"` + CouponFee0 int `xml:"coupon_fee_$0"` + TransactionId string `xml:"transaction_id"` + OutTradeNo string `xml:"out_trade_no"` + Attach string `xml:"attach"` + TimeEnd string `xml:"time_end"` + TradeStateDesc string `xml:"trade_state_desc"` +} + +type getSignKeyResponse struct { + ReturnCode string `xml:"return_code"` + ReturnMsg string `xml:"return_msg"` + Retmsg string `xml:"retmsg"` + Retcode string `xml:"retcode"` + MchId string `xml:"mch_id"` + SandboxSignkey string `xml:"sandbox_signkey"` +}