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(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(">")
+ 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"`
+}