Procházet zdrojové kódy

Merge pull request #18 from iGoogle-ink/gopay/wechat

Gopay/wechat
Jerry před 6 roky
rodič
revize
7c4d6b8be1
8 změnil soubory, kde provedl 483 přidání a 120 odebrání
  1. 9 3
      README.md
  2. 15 0
      body_map.go
  3. 1 0
      http_client.go
  4. 10 0
      release_note.txt
  5. 232 80
      wechat/client.go
  6. 107 2
      wechat/client_test.go
  7. 105 33
      wechat/model.go
  8. 4 2
      wechat/service_api.go

+ 9 - 3
README.md

@@ -48,9 +48,15 @@ func main() {
 * 申请退款:client.Refund()
 * 申请退款:client.Refund()
 * 查询退款:client.QueryRefund()
 * 查询退款:client.QueryRefund()
 * 下载对账单:client.DownloadBill()
 * 下载对账单:client.DownloadBill()
-* 下载资金账单:client.DownloadFundFlow()
-* 拉取订单评价数据:client.BatchQueryComment()
-* 企业向微信用户个人付款:client.Transfer()
+* 下载资金账单(正式):client.DownloadFundFlow()
+* 交易保障:client.Report()
+* 拉取订单评价数据(正式):client.BatchQueryComment()
+* 企业向微信用户个人付款(正式):client.Transfer()
+* 授权码查询OpenId(正式):client.AuthCodeToOpenId()
+* 公众号纯签约(正式):client.EntrustPublic()
+* APP纯签约-预签约接口-获取预签约ID(正式):client.EntrustAppPre()
+* H5纯签约(正式):client.EntrustH5()
+* 支付中签约(正式):client.EntrustPaying()
 
 
 ### 微信公共API
 ### 微信公共API
 
 

+ 15 - 0
body_map.go

@@ -150,6 +150,21 @@ func (bm BodyMap) EncodeAliPaySignParams() string {
 	return buf.String()[:buf.Len()-1]
 	return buf.String()[:buf.Len()-1]
 }
 }
 
 
+func (bm BodyMap) EncodeGetParams() string {
+	var (
+		buf strings.Builder
+	)
+	for k, _ := range bm {
+		if v := bm.Get(k); v != NULL {
+			buf.WriteString(k)
+			buf.WriteByte('=')
+			buf.WriteString(v)
+			buf.WriteByte('&')
+		}
+	}
+	return buf.String()[:buf.Len()-1]
+}
+
 func (bm BodyMap) CheckEmptyError(keys ...string) error {
 func (bm BodyMap) CheckEmptyError(keys ...string) error {
 	var emptyKeys []string
 	var emptyKeys []string
 	for _, k := range keys {
 	for _, k := range keys {

+ 1 - 0
http_client.go

@@ -141,6 +141,7 @@ func (c *Client) EndStruct(v interface{}) (res *http.Response, errs []error) {
 		return nil, c.Errors
 		return nil, c.Errors
 	}
 	}
 }
 }
+
 func (c *Client) EndBytes() (res *http.Response, bs []byte, errs []error) {
 func (c *Client) EndBytes() (res *http.Response, bs []byte, errs []error) {
 	if len(c.Errors) > 0 {
 	if len(c.Errors) > 0 {
 		return nil, nil, c.Errors
 		return nil, nil, c.Errors

+ 10 - 0
release_note.txt

@@ -1,3 +1,13 @@
+版本号:Release 2.0.3
+发布时间:2019/12/18 19:25
+修改记录:
+   (1) 微信:新增Client方法:client.AuthCodeToOpenId(),授权码查询OpenId(正式)
+   (2) 微信:新增Client方法:client.Report(),交易保障
+   (3) 微信:新增Client方法:client.EntrustPublic(),公众号纯签约(正式)
+   (4) 微信:新增Client方法:client.EntrustAppPre(),APP纯签约-预签约接口-获取预签约ID(正式)
+   (5) 微信:新增Client方法:client.EntrustH5(),H5纯签约(正式)
+   (5) 微信:新增Client方法:client.EntrustPaying(),支付中签约(正式)
+
 版本号:Release 2.0.2
 版本号:Release 2.0.2
 发布时间:2019/12/13 23:25
 发布时间:2019/12/13 23:25
 修改记录:
 修改记录:

+ 232 - 80
wechat/client.go

@@ -45,18 +45,38 @@ func (w *Client) Micropay(bm gopay.BodyMap) (wxRsp *MicropayResponse, err error)
 	}
 	}
 	var bs []byte
 	var bs []byte
 	if w.IsProd {
 	if w.IsProd {
-		bs, err = w.doWeChat(bm, microPay, nil)
+		bs, err = w.doWeChatPostProd(bm, microPay, nil)
 	} else {
 	} else {
-		bs, err = w.doWeChat(bm, sandboxMicroPay, nil)
+		bm.Set("total_fee", 1)
+		bs, err = w.doWeChatPostSanBox(bm, sandboxMicroPay)
 	}
 	}
 	if err != nil {
 	if err != nil {
-		return
+		return nil, err
 	}
 	}
 	wxRsp = new(MicropayResponse)
 	wxRsp = new(MicropayResponse)
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 	}
 	}
-	return
+	return wxRsp, nil
+}
+
+// 授权码查询openid(正式)
+//    文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_13&index=9
+func (w *Client) AuthCodeToOpenId(bm gopay.BodyMap) (wxRsp *AuthCodeToOpenIdResponse, err error) {
+	err = bm.CheckEmptyError("nonce_str", "auth_code")
+	if err != nil {
+		return nil, err
+	}
+
+	bs, err := w.doWeChatPostProd(bm, authCodeToOpenid, nil)
+	if err != nil {
+		return nil, err
+	}
+	wxRsp = new(AuthCodeToOpenIdResponse)
+	if err = xml.Unmarshal(bs, wxRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
+	}
+	return wxRsp, nil
 }
 }
 
 
 // 统一下单
 // 统一下单
@@ -68,19 +88,19 @@ func (w *Client) UnifiedOrder(bm gopay.BodyMap) (wxRsp *UnifiedOrderResponse, er
 	}
 	}
 	var bs []byte
 	var bs []byte
 	if w.IsProd {
 	if w.IsProd {
-		bs, err = w.doWeChat(bm, unifiedOrder, nil)
+		bs, err = w.doWeChatPostProd(bm, unifiedOrder, nil)
 	} else {
 	} else {
 		bm.Set("total_fee", 101)
 		bm.Set("total_fee", 101)
-		bs, err = w.doWeChat(bm, sandboxUnifiedOrder, nil)
+		bs, err = w.doWeChatPostSanBox(bm, sandboxUnifiedOrder)
 	}
 	}
 	if err != nil {
 	if err != nil {
-		return
+		return nil, err
 	}
 	}
 	wxRsp = new(UnifiedOrderResponse)
 	wxRsp = new(UnifiedOrderResponse)
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 	}
 	}
-	return
+	return wxRsp, nil
 }
 }
 
 
 // 查询订单
 // 查询订单
@@ -95,18 +115,18 @@ func (w *Client) QueryOrder(bm gopay.BodyMap) (wxRsp *QueryOrderResponse, err er
 	}
 	}
 	var bs []byte
 	var bs []byte
 	if w.IsProd {
 	if w.IsProd {
-		bs, err = w.doWeChat(bm, orderQuery, nil)
+		bs, err = w.doWeChatPostProd(bm, orderQuery, nil)
 	} else {
 	} else {
-		bs, err = w.doWeChat(bm, sandboxOrderQuery, nil)
+		bs, err = w.doWeChatPostSanBox(bm, sandboxOrderQuery)
 	}
 	}
 	if err != nil {
 	if err != nil {
-		return
+		return nil, err
 	}
 	}
 	wxRsp = new(QueryOrderResponse)
 	wxRsp = new(QueryOrderResponse)
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 	}
 	}
-	return
+	return wxRsp, nil
 }
 }
 
 
 // 关闭订单
 // 关闭订单
@@ -118,18 +138,18 @@ func (w *Client) CloseOrder(bm gopay.BodyMap) (wxRsp *CloseOrderResponse, err er
 	}
 	}
 	var bs []byte
 	var bs []byte
 	if w.IsProd {
 	if w.IsProd {
-		bs, err = w.doWeChat(bm, closeOrder, nil)
+		bs, err = w.doWeChatPostProd(bm, closeOrder, nil)
 	} else {
 	} else {
-		bs, err = w.doWeChat(bm, sandboxCloseOrder, nil)
+		bs, err = w.doWeChatPostSanBox(bm, sandboxCloseOrder)
 	}
 	}
 	if err != nil {
 	if err != nil {
-		return
+		return nil, err
 	}
 	}
 	wxRsp = new(CloseOrderResponse)
 	wxRsp = new(CloseOrderResponse)
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 	}
 	}
-	return
+	return wxRsp, nil
 }
 }
 
 
 // 撤销订单
 // 撤销订单
@@ -148,18 +168,18 @@ func (w *Client) Reverse(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12File
 		if tlsConfig, err = w.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath); err != nil {
 		if tlsConfig, err = w.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		bs, err = w.doWeChat(bm, reverse, tlsConfig)
+		bs, err = w.doWeChatPostProd(bm, reverse, tlsConfig)
 	} else {
 	} else {
-		bs, err = w.doWeChat(bm, sandboxReverse, nil)
+		bs, err = w.doWeChatPostSanBox(bm, sandboxReverse)
 	}
 	}
 	if err != nil {
 	if err != nil {
-		return
+		return nil, err
 	}
 	}
 	wxRsp = new(ReverseResponse)
 	wxRsp = new(ReverseResponse)
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 	}
 	}
-	return
+	return wxRsp, nil
 }
 }
 
 
 // 申请退款
 // 申请退款
@@ -181,18 +201,18 @@ func (w *Client) Refund(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12FileP
 		if tlsConfig, err = w.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath); err != nil {
 		if tlsConfig, err = w.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		bs, err = w.doWeChat(bm, refund, tlsConfig)
+		bs, err = w.doWeChatPostProd(bm, refund, tlsConfig)
 	} else {
 	} else {
-		bs, err = w.doWeChat(bm, sandboxRefund, nil)
+		bs, err = w.doWeChatPostSanBox(bm, sandboxRefund)
 	}
 	}
 	if err != nil {
 	if err != nil {
-		return
+		return nil, err
 	}
 	}
 	wxRsp = new(RefundResponse)
 	wxRsp = new(RefundResponse)
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 	}
 	}
-	return
+	return wxRsp, nil
 }
 }
 
 
 // 查询退款
 // 查询退款
@@ -207,18 +227,18 @@ func (w *Client) QueryRefund(bm gopay.BodyMap) (wxRsp *QueryRefundResponse, err
 	}
 	}
 	var bs []byte
 	var bs []byte
 	if w.IsProd {
 	if w.IsProd {
-		bs, err = w.doWeChat(bm, refundQuery, nil)
+		bs, err = w.doWeChatPostProd(bm, refundQuery, nil)
 	} else {
 	} else {
-		bs, err = w.doWeChat(bm, sandboxRefundQuery, nil)
+		bs, err = w.doWeChatPostSanBox(bm, sandboxRefundQuery)
 	}
 	}
 	if err != nil {
 	if err != nil {
-		return
+		return nil, err
 	}
 	}
 	wxRsp = new(QueryRefundResponse)
 	wxRsp = new(QueryRefundResponse)
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 	if err = xml.Unmarshal(bs, wxRsp); err != nil {
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
 	}
 	}
-	return
+	return wxRsp, nil
 }
 }
 
 
 // 下载对账单
 // 下载对账单
@@ -234,18 +254,17 @@ func (w *Client) DownloadBill(bm gopay.BodyMap) (wxRsp string, err error) {
 	}
 	}
 	var bs []byte
 	var bs []byte
 	if w.IsProd {
 	if w.IsProd {
-		bs, err = w.doWeChat(bm, downloadBill, nil)
+		bs, err = w.doWeChatPostProd(bm, downloadBill, nil)
 	} else {
 	} else {
-		bs, err = w.doWeChat(bm, sandboxDownloadBill, nil)
+		bs, err = w.doWeChatPostSanBox(bm, sandboxDownloadBill)
 	}
 	}
 	if err != nil {
 	if err != nil {
-		return
+		return gopay.NULL, err
 	}
 	}
-	wxRsp = string(bs)
-	return
+	return string(bs), nil
 }
 }
 
 
-// 下载资金账单
+// 下载资金账单(正式)
 //    注意:如已使用client.AddCertFilePath()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    注意:如已使用client.AddCertFilePath()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    貌似不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
 //    貌似不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7
@@ -258,27 +277,48 @@ func (w *Client) DownloadFundFlow(bm gopay.BodyMap, certFilePath, keyFilePath, p
 	if accountType != "Basic" && accountType != "Operation" && accountType != "Fees" {
 	if accountType != "Basic" && accountType != "Operation" && accountType != "Fees" {
 		return gopay.NULL, errors.New("account_type error, please reference: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7")
 		return gopay.NULL, errors.New("account_type error, please reference: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7")
 	}
 	}
-	var (
-		bs        []byte
-		tlsConfig *tls.Config
-	)
 	bm.Set("sign_type", SignType_HMAC_SHA256)
 	bm.Set("sign_type", SignType_HMAC_SHA256)
-	if w.IsProd {
-		if tlsConfig, err = w.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath); err != nil {
-			return gopay.NULL, err
-		}
-		bs, err = w.doWeChat(bm, downloadFundFlow, tlsConfig)
-	} else {
-		bs, err = w.doWeChat(bm, sandboxDownloadFundFlow, nil)
+	tlsConfig, err := w.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath)
+	if err != nil {
+		return gopay.NULL, err
 	}
 	}
+	bs, err := w.doWeChatPostProd(bm, downloadFundFlow, tlsConfig)
 	if err != nil {
 	if err != nil {
-		return
+		return gopay.NULL, err
 	}
 	}
 	wxRsp = string(bs)
 	wxRsp = string(bs)
 	return
 	return
 }
 }
 
 
-// 拉取订单评价数据
+// 交易保障
+//    文档地址:(JSAPI)https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_8&index=9
+//    文档地址:(付款码)https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_14&index=8
+//    文档地址:(Native)https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_8&index=9
+//    文档地址:(APP)https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_8&index=10
+//    文档地址:(H5)https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_8&index=9
+//    文档地址:(微信小程序)https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_8&index=9
+func (w *Client) Report(bm gopay.BodyMap) (wxRsp *ReportResponse, err error) {
+	err = bm.CheckEmptyError("nonce_str", "interface_url", "execute_time", "return_code", "return_msg", "result_code", "user_ip")
+	if err != nil {
+		return nil, err
+	}
+	var bs []byte
+	if w.IsProd {
+		bs, err = w.doWeChatPostProd(bm, report, nil)
+	} else {
+		bs, err = w.doWeChatPostSanBox(bm, sandboxReport)
+	}
+	if err != nil {
+		return nil, err
+	}
+	wxRsp = new(ReportResponse)
+	if err = xml.Unmarshal(bs, wxRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
+	}
+	return wxRsp, nil
+}
+
+// 拉取订单评价数据(正式)
 //    注意:如已使用client.AddCertFilePath()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    注意:如已使用client.AddCertFilePath()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    貌似不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
 //    貌似不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_17&index=11
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_17&index=11
@@ -287,27 +327,19 @@ func (w *Client) BatchQueryComment(bm gopay.BodyMap, certFilePath, keyFilePath,
 	if err != nil {
 	if err != nil {
 		return gopay.NULL, err
 		return gopay.NULL, err
 	}
 	}
-	var (
-		bs        []byte
-		tlsConfig *tls.Config
-	)
 	bm.Set("sign_type", SignType_HMAC_SHA256)
 	bm.Set("sign_type", SignType_HMAC_SHA256)
-	if w.IsProd {
-		if tlsConfig, err = w.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath); err != nil {
-			return gopay.NULL, err
-		}
-		bs, err = w.doWeChat(bm, batchQueryComment, tlsConfig)
-	} else {
-		bs, err = w.doWeChat(bm, sandboxBatchQueryComment, nil)
+	tlsConfig, err := w.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath)
+	if err != nil {
+		return gopay.NULL, err
 	}
 	}
+	bs, err := w.doWeChatPostProd(bm, batchQueryComment, tlsConfig)
 	if err != nil {
 	if err != nil {
-		return
+		return gopay.NULL, err
 	}
 	}
-	wxRsp = string(bs)
-	return
+	return string(bs), nil
 }
 }
 
 
-// 企业向微信用户个人付款
+// 企业向微信用户个人付款(正式)
 //    注意:如已使用client.AddCertFilePath()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    注意:如已使用client.AddCertFilePath()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    注意:此方法未支持沙箱环境,默认正式环境,转账请慎重
 //    注意:此方法未支持沙箱环境,默认正式环境,转账请慎重
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
@@ -344,53 +376,173 @@ func (w *Client) Transfer(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12Fil
 	return wxRsp, nil
 	return wxRsp, nil
 }
 }
 
 
-// 公众号纯签约(未完成
+// 公众号纯签约(正式
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_1&index=1
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_1&index=1
-func (w *Client) EntrustPublic(bm gopay.BodyMap) (bs []byte, err error) {
-	bs, err = w.doWeChat(bm, entrustPublic, nil)
+func (w *Client) EntrustPublic(bm gopay.BodyMap) (wxRsp *EntrustPublicResponse, err error) {
+	err = bm.CheckEmptyError("plan_id", "contract_code", "request_serial", "contract_display_account", "notify_url", "version", "timestamp")
+	if err != nil {
+		return nil, err
+	}
+	bs, err := w.doWeChatGetProd(bm, entrustPublic, SignType_MD5)
+	if err != nil {
+		return nil, err
+	}
+	wxRsp = new(EntrustPublicResponse)
+	if err = xml.Unmarshal(bs, wxRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
+	}
+	return wxRsp, nil
+}
 
 
-	return nil, nil
+// APP纯签约-预签约接口-获取预签约ID(正式)
+//    文档地址:https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_5&index=2
+func (w *Client) EntrustAppPre(bm gopay.BodyMap) (wxRsp *EntrustAppPreResponse, err error) {
+	err = bm.CheckEmptyError("plan_id", "contract_code", "request_serial", "contract_display_account", "notify_url", "version", "timestamp")
+	if err != nil {
+		return nil, err
+	}
+	bs, err := w.doWeChatPostProd(bm, entrustApp, nil)
+	if err != nil {
+		return nil, err
+	}
+	wxRsp = new(EntrustAppPreResponse)
+	if err = xml.Unmarshal(bs, wxRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
+	}
+	return wxRsp, nil
 }
 }
 
 
-// 向微信发送请求
-func (w *Client) doWeChat(bm gopay.BodyMap, path string, tlsConfig *tls.Config) (bs []byte, err error) {
+// H5纯签约(正式)
+//    文档地址:https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_16&index=4
+func (w *Client) EntrustH5(bm gopay.BodyMap) (wxRsp *EntrustH5Response, err error) {
+	err = bm.CheckEmptyError("plan_id", "contract_code", "request_serial", "contract_display_account", "notify_url", "version", "timestamp", "clientip")
+	if err != nil {
+		return nil, err
+	}
+	bs, err := w.doWeChatGetProd(bm, entrustH5, SignType_HMAC_SHA256)
+	if err != nil {
+		return nil, err
+	}
+	wxRsp = new(EntrustH5Response)
+	if err = xml.Unmarshal(bs, wxRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
+	}
+	return wxRsp, nil
+}
+
+// 支付中签约(正式)
+//    文档地址:https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_13&index=5
+func (w *Client) EntrustPaying(bm gopay.BodyMap) (wxRsp *EntrustPayingResponse, err error) {
+	err = bm.CheckEmptyError("contract_mchid", "contract_appid",
+		"out_trade_no", "nonce_str", "body", "notify_url", "total_fee",
+		"spbill_create_ip", "trade_type", "plan_id", "contract_code",
+		"request_serial", "contract_display_account", "contract_notify_url")
+	if err != nil {
+		return nil, err
+	}
+	bs, err := w.doWeChatPostProd(bm, entrustPaying, nil)
+	if err != nil {
+		return nil, err
+	}
+	wxRsp = new(EntrustPayingResponse)
+	if err = xml.Unmarshal(bs, wxRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
+	}
+	return wxRsp, nil
+}
+
+// Post请求
+func (w *Client) doWeChatPostSanBox(bm gopay.BodyMap, path string) (bs []byte, err error) {
 	var url = baseUrlCh + path
 	var url = baseUrlCh + path
+	w.mu.RLock()
+	defer w.mu.RUnlock()
 	bm.Set("appid", w.AppId)
 	bm.Set("appid", w.AppId)
 	bm.Set("mch_id", w.MchId)
 	bm.Set("mch_id", w.MchId)
 
 
 	if bm.Get("sign") == gopay.NULL {
 	if bm.Get("sign") == gopay.NULL {
-		var sign string
-		if !w.IsProd {
-			bm.Set("sign_type", SignType_MD5)
-			sign, err = getSignBoxSign(w.MchId, w.ApiKey, bm)
-			if err != nil {
-				return nil, err
-			}
-		} else {
-			sign = getReleaseSign(w.ApiKey, bm.Get("sign_type"), bm)
+		bm.Set("sign_type", SignType_MD5)
+		sign, err := getSignBoxSign(w.MchId, w.ApiKey, bm)
+		if err != nil {
+			return nil, err
 		}
 		}
 		bm.Set("sign", sign)
 		bm.Set("sign", sign)
 	}
 	}
 
 
+	if w.BaseURL != gopay.NULL {
+		url = w.BaseURL + path
+	}
+	res, bs, errs := gopay.NewHttpClient().Type(gopay.TypeXML).Post(url).SendString(generateXml(bm)).EndBytes()
+	if len(errs) > 0 {
+		return nil, errs[0]
+	}
+	if res.StatusCode != 200 {
+		return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
+	}
+	if strings.Contains(string(bs), "HTML") || strings.Contains(string(bs), "html") {
+		return nil, errors.New(string(bs))
+	}
+	return bs, nil
+}
+
+// Post请求、正式
+func (w *Client) doWeChatPostProd(bm gopay.BodyMap, path string, tlsConfig *tls.Config) (bs []byte, err error) {
+	var url = baseUrlCh + path
+	w.mu.RLock()
+	defer w.mu.RUnlock()
+	bm.Set("appid", w.AppId)
+	bm.Set("mch_id", w.MchId)
+
+	if bm.Get("sign") == gopay.NULL {
+		sign := getReleaseSign(w.ApiKey, bm.Get("sign_type"), bm)
+		bm.Set("sign", sign)
+	}
+
 	httpClient := gopay.NewHttpClient()
 	httpClient := gopay.NewHttpClient()
 	if w.IsProd && tlsConfig != nil {
 	if w.IsProd && tlsConfig != nil {
 		httpClient.SetTLSConfig(tlsConfig)
 		httpClient.SetTLSConfig(tlsConfig)
 	}
 	}
+	if w.BaseURL != gopay.NULL {
+		url = w.BaseURL + path
+	}
+	res, bs, errs := httpClient.Type(gopay.TypeXML).Post(url).SendString(generateXml(bm)).EndBytes()
+	if len(errs) > 0 {
+		return nil, errs[0]
+	}
+	if res.StatusCode != 200 {
+		return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
+	}
+	if strings.Contains(string(bs), "HTML") || strings.Contains(string(bs), "html") {
+		return nil, errors.New(string(bs))
+	}
+	return bs, nil
+}
+
+// Get请求、正式
+func (w *Client) doWeChatGetProd(bm gopay.BodyMap, path, signType string) (bs []byte, err error) {
+	var url = baseUrlCh + path
+	w.mu.RLock()
+	defer w.mu.RUnlock()
+	bm.Set("appid", w.AppId)
+	bm.Set("mch_id", w.MchId)
+	bm.Remove("sign")
+	sign := getReleaseSign(w.ApiKey, signType, bm)
+	bm.Set("sign", sign)
 
 
 	if w.BaseURL != gopay.NULL {
 	if w.BaseURL != gopay.NULL {
 		w.mu.RLock()
 		w.mu.RLock()
 		url = w.BaseURL + path
 		url = w.BaseURL + path
 		w.mu.RUnlock()
 		w.mu.RUnlock()
 	}
 	}
-
-	res, bs, errs := httpClient.Type(gopay.TypeXML).Post(url).SendString(generateXml(bm)).EndBytes()
+	param := bm.EncodeGetParams()
+	url = url + "?" + param
+	res, bs, errs := gopay.NewHttpClient().Get(url).EndBytes()
 	if len(errs) > 0 {
 	if len(errs) > 0 {
 		return nil, errs[0]
 		return nil, errs[0]
 	}
 	}
 	if res.StatusCode != 200 {
 	if res.StatusCode != 200 {
 		return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
 		return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
 	}
 	}
-	if strings.Contains(string(bs), "HTML") {
+	if strings.Contains(string(bs), "HTML") || strings.Contains(string(bs), "html") {
 		return nil, errors.New(string(bs))
 		return nil, errors.New(string(bs))
 	}
 	}
 	return bs, nil
 	return bs, nil

+ 107 - 2
wechat/client_test.go

@@ -146,12 +146,25 @@ func TestClient_Micropay(t *testing.T) {
 		return
 		return
 	}
 	}
 	fmt.Println("Response:", *wxRsp)
 	fmt.Println("Response:", *wxRsp)
-
 	ok, err := VerifySign(apiKey, SignType_MD5, wxRsp)
 	ok, err := VerifySign(apiKey, SignType_MD5, wxRsp)
 	if err != nil {
 	if err != nil {
 		fmt.Println("err:", err)
 		fmt.Println("err:", err)
 	}
 	}
-	fmt.Println("同步验签结果:", ok)
+	fmt.Println("同步验签结果:", ok) // 沙箱环境验签失败请用正式环境测
+}
+
+func TestClient_AuthCodeToOpenId(t *testing.T) {
+	// 初始化参数Map
+	bm := make(gopay.BodyMap)
+	bm.Set("nonce_str", gopay.GetRandomString(32))
+	bm.Set("auth_code", "134753997737645794")
+
+	wxRsp, err := client.AuthCodeToOpenId(bm)
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+	fmt.Println("Response:", *wxRsp)
 }
 }
 
 
 func TestClient_Refund(t *testing.T) {
 func TestClient_Refund(t *testing.T) {
@@ -292,6 +305,98 @@ func TestClient_BatchQueryComment(t *testing.T) {
 	fmt.Println("wxRsp:", wxRsp)
 	fmt.Println("wxRsp:", wxRsp)
 }
 }
 
 
+func TestClient_EntrustPublic(t *testing.T) {
+	// 初始化参数结构体
+	bm := make(gopay.BodyMap)
+	bm.Set("plan_id", "12535")
+	bm.Set("contract_code", "100000")
+	bm.Set("request_serial", "1000")
+	bm.Set("contract_display_account", "微信代扣")
+	bm.Set("notify_url", "https://www.igoogle.ink")
+	bm.Set("version", "1.0")
+	bm.Set("timestamp", time.Now().Unix())
+
+	// 公众号纯签约
+	wxRsp, err := client.EntrustPublic(bm)
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+	fmt.Println("wxRsp:", wxRsp)
+}
+
+func TestClient_EntrustAppPre(t *testing.T) {
+	// 初始化参数结构体
+	bm := make(gopay.BodyMap)
+	bm.Set("plan_id", "12535")
+	bm.Set("contract_code", "100000")
+	bm.Set("request_serial", "1000")
+	bm.Set("contract_display_account", "微信代扣")
+	bm.Set("notify_url", "https://www.igoogle.ink")
+	bm.Set("version", "1.0")
+	bm.Set("timestamp", time.Now().Unix())
+
+	// APP纯签约
+	wxRsp, err := client.EntrustAppPre(bm)
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+	fmt.Println("wxRsp:", wxRsp)
+}
+
+func TestClient_EntrustH5(t *testing.T) {
+	// 初始化参数结构体
+	bm := make(gopay.BodyMap)
+	bm.Set("plan_id", "12535")
+	bm.Set("contract_code", "100000")
+	bm.Set("request_serial", "1000")
+	bm.Set("contract_display_account", "微信代扣")
+	bm.Set("notify_url", "https://www.igoogle.ink")
+	bm.Set("version", "1.0")
+	bm.Set("timestamp", time.Now().Unix())
+	bm.Set("clientip", "127.0.0.1")
+
+	// H5纯签约
+	wxRsp, err := client.EntrustH5(bm)
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+	fmt.Println("wxRsp:", wxRsp)
+}
+
+func TestClient_EntrustPaying(t *testing.T) {
+	number := gopay.GetRandomString(32)
+	fmt.Println("out_trade_no:", number)
+	// 初始化参数结构体
+	bm := make(gopay.BodyMap)
+	bm.Set("contract_mchid", mchId)
+	bm.Set("contract_appid", appId)
+	bm.Set("out_trade_no", number)
+	bm.Set("nonce_str", gopay.GetRandomString(32))
+	bm.Set("body", "测试签约")
+	bm.Set("total_fee", 1)
+	bm.Set("spbill_create_ip", "127.0.0.1")
+	bm.Set("trade_type", TradeType_App)
+	bm.Set("plan_id", "12535")
+	bm.Set("contract_code", "100000")
+	bm.Set("request_serial", "1000")
+	bm.Set("contract_display_account", "微信代扣")
+	bm.Set("notify_url", "https://www.igoogle.ink")
+	bm.Set("contract_notify_url", "https://www.igoogle.ink")
+
+	//bm.Set("openid", "o0Df70H2Q0fY8JXh1aFPIRyOBgu8")
+
+	// 支付中签约
+	wxRsp, err := client.EntrustPaying(bm)
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+	fmt.Println("wxRsp:", wxRsp)
+}
+
 // =======================
 // =======================
 
 
 func TestDecryptOpenDataToStruct(t *testing.T) {
 func TestDecryptOpenDataToStruct(t *testing.T) {

+ 105 - 33
wechat/model.go

@@ -8,43 +8,45 @@ const (
 	Other         Country = 4 // 其他国家
 	Other         Country = 4 // 其他国家
 
 
 	// URL
 	// URL
-	baseUrlCh  = "https://api.mch.weixin.qq.com/"   //中国国内
-	baseUrlCh2 = "https://api2.mch.weixin.qq.com/"  //中国国内
-	baseUrlHk  = "https://apihk.mch.weixin.qq.com/" //东南亚
-	baseUrlUs  = "https://apius.mch.weixin.qq.com/" //其他
+	baseUrlCh  = "https://api.mch.weixin.qq.com/"   // 中国国内
+	baseUrlCh2 = "https://api2.mch.weixin.qq.com/"  // 中国国内
+	baseUrlHk  = "https://apihk.mch.weixin.qq.com/" // 东南亚
+	baseUrlUs  = "https://apius.mch.weixin.qq.com/" // 其他
 
 
 	// 正式
 	// 正式
-	microPay          = "pay/micropay"                          //提交付款码支付
-	unifiedOrder      = "pay/unifiedorder"                      //统一下单
-	orderQuery        = "pay/orderquery"                        //查询订单
-	closeOrder        = "pay/closeorder"                        //关闭订单
-	refund            = "secapi/pay/refund"                     //申请退款
-	reverse           = "secapi/pay/reverse"                    //撤销订单
-	refundQuery       = "pay/refundquery"                       //查询退款
-	downloadBill      = "pay/downloadbill"                      //下载对账单
-	downloadFundFlow  = "pay/downloadfundflow"                  //下载资金账单
-	batchQueryComment = "billcommentsp/batchquerycomment"       //拉取订单评价数据
-	transfers         = "mmpaymkttransfers/promotion/transfers" //企业向微信用户个人付款
-	entrustPublic     = "papay/entrustweb"                      //公众号纯签约
-	entrustApp        = "papay/preentrustweb"                   //APP纯签约
-	entrustH5         = "papay/h5entrustweb"                    //H5纯签约
-	entrustQuery      = "papay/querycontract"                   //查询签约关系
-	entrustDelete     = "papay/deletecontract"                  //申请解约
-	entrustApplyPay   = "pay/pappayapply"                       //申请扣款
-	entrustQueryOrder = "pay/paporderquery"                     //查询扣款订单
+	microPay          = "pay/micropay"                          // 提交付款码支付
+	unifiedOrder      = "pay/unifiedorder"                      // 统一下单
+	orderQuery        = "pay/orderquery"                        // 查询订单
+	closeOrder        = "pay/closeorder"                        // 关闭订单
+	refund            = "secapi/pay/refund"                     // 申请退款
+	reverse           = "secapi/pay/reverse"                    // 撤销订单
+	refundQuery       = "pay/refundquery"                       // 查询退款
+	downloadBill      = "pay/downloadbill"                      // 下载对账单
+	downloadFundFlow  = "pay/downloadfundflow"                  // 下载资金账单
+	report            = "payitil/report"                        // 交易保障
+	batchQueryComment = "billcommentsp/batchquerycomment"       // 拉取订单评价数据
+	transfers         = "mmpaymkttransfers/promotion/transfers" // 企业向微信用户个人付款
+	authCodeToOpenid  = "tools/authcodetoopenid"                // 授权码查询openid
+	entrustPublic     = "papay/entrustweb"                      // 公众号纯签约
+	entrustApp        = "papay/preentrustweb"                   // APP纯签约
+	entrustH5         = "papay/h5entrustweb"                    // H5纯签约
+	entrustPaying     = "pay/contractorder"                     // 支付中签约
+	entrustQuery      = "papay/querycontract"                   // 查询签约关系
+	entrustApplyPay   = "pay/pappayapply"                       // 申请扣款
+	entrustDelete     = "papay/deletecontract"                  // 申请解约
+	entrustQueryOrder = "pay/paporderquery"                     // 查询扣款订单
 
 
 	// SanBox
 	// SanBox
-	sandboxGetSignKey        = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey"
-	sandboxMicroPay          = "sandboxnew/pay/micropay"
-	sandboxUnifiedOrder      = "sandboxnew/pay/unifiedorder"
-	sandboxOrderQuery        = "sandboxnew/pay/orderquery"
-	sandboxCloseOrder        = "sandboxnew/pay/closeorder"
-	sandboxRefund            = "sandboxnew/pay/refund"
-	sandboxReverse           = "sandboxnew/pay/reverse"
-	sandboxRefundQuery       = "sandboxnew/pay/refundquery"
-	sandboxDownloadBill      = "sandboxnew/pay/downloadbill"
-	sandboxDownloadFundFlow  = "sandboxnew/pay/downloadfundflow"
-	sandboxBatchQueryComment = "sandboxnew/billcommentsp/batchquerycomment"
+	sandboxGetSignKey   = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey"
+	sandboxMicroPay     = "sandboxnew/pay/micropay"
+	sandboxUnifiedOrder = "sandboxnew/pay/unifiedorder"
+	sandboxOrderQuery   = "sandboxnew/pay/orderquery"
+	sandboxCloseOrder   = "sandboxnew/pay/closeorder"
+	sandboxRefund       = "sandboxnew/pay/refund"
+	sandboxReverse      = "sandboxnew/pay/reverse"
+	sandboxRefundQuery  = "sandboxnew/pay/refundquery"
+	sandboxDownloadBill = "sandboxnew/pay/downloadbill"
+	sandboxReport       = "sandboxnew/payitil/report"
 
 
 	// 支付类型
 	// 支付类型
 	TradeType_Mini   = "JSAPI"  // 小程序支付
 	TradeType_Mini   = "JSAPI"  // 小程序支付
@@ -288,6 +290,18 @@ type MicropayResponse struct {
 	PromotionDetail    string `xml:"promotion_detail,omitempty" json:"promotion_detail,omitempty"`
 	PromotionDetail    string `xml:"promotion_detail,omitempty" json:"promotion_detail,omitempty"`
 }
 }
 
 
+type AuthCodeToOpenIdResponse struct {
+	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	Appid      string `xml:"appid,omitempty" json:"appid,omitempty"`
+	MchId      string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
+	NonceStr   string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
+	Sign       string `xml:"sign,omitempty" json:"sign,omitempty"`
+	ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	ErrCode    string `xml:"err_code,omitempty" json:"err_code,omitempty"`
+	Openid     string `xml:"openid,omitempty" json:"openid,omitempty"`
+}
+
 type TransfersResponse struct {
 type TransfersResponse struct {
 	ReturnCode     string `xml:"return_code,omitempty" json:"return_code,omitempty"`
 	ReturnCode     string `xml:"return_code,omitempty" json:"return_code,omitempty"`
 	ReturnMsg      string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
 	ReturnMsg      string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
@@ -303,6 +317,64 @@ type TransfersResponse struct {
 	PaymentTime    string `xml:"payment_time,omitempty" json:"payment_time,omitempty"`
 	PaymentTime    string `xml:"payment_time,omitempty" json:"payment_time,omitempty"`
 }
 }
 
 
+type ReportResponse struct {
+	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+}
+
+type EntrustPublicResponse struct {
+	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	ResultMsg  string `xml:"result_msg,omitempty" json:"result_msg,omitempty"`
+}
+
+type EntrustAppPreResponse struct {
+	ReturnCode      string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg       string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	ResultCode      string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	ErrCode         string `xml:"err_code,omitempty" json:"err_code,omitempty"`
+	Appid           string `xml:"appid,omitempty" json:"appid,omitempty"`
+	MchId           string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
+	Sign            string `xml:"sign,omitempty" json:"sign,omitempty"`
+	NonceStr        string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
+	PreEntrustwebId string `xml:"pre_entrustweb_id,omitempty" json:"pre_entrustweb_id,omitempty"`
+}
+
+type EntrustH5Response struct {
+	ReturnCode  string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg   string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	ResultCode  string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	ResultMsg   string `xml:"result_msg,omitempty" json:"result_msg,omitempty"`
+	RedirectUrl string `xml:"redirect_url,omitempty" json:"redirect_url,omitempty"`
+}
+
+type EntrustPayingResponse struct {
+	ReturnCode             string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg              string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	ResultCode             string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	Appid                  string `xml:"appid,omitempty" json:"appid,omitempty"`
+	MchId                  string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
+	DeviceInfo             string `xml:"device_info,omitempty" json:"device_info,omitempty"`
+	NonceStr               string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
+	Sign                   string `xml:"sign,omitempty" json:"sign,omitempty"`
+	ErrCode                string `xml:"err_code,omitempty" json:"err_code,omitempty"`
+	ErrCodeDes             string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
+	ContractResultCode     string `xml:"contract_result_code,omitempty" json:"contract_result_code,omitempty"`
+	ContractErrCode        string `xml:"contract_err_code,omitempty" json:"contract_err_code,omitempty"`
+	ContractErrCodeDes     string `xml:"contract_err_code_des,omitempty" json:"contract_err_code_des,omitempty"`
+	PrepayId               string `xml:"prepay_id,omitempty" json:"prepay_id,omitempty"`
+	TradeType              string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
+	CodeUrl                string `xml:"code_url,omitempty" json:"code_url,omitempty"`
+	PlanId                 int    `xml:"plan_id,omitempty" json:"plan_id,omitempty"`
+	RequestSerial          int    `xml:"request_serial,omitempty" json:"request_serial,omitempty"`
+	ContractCode           string `xml:"contract_code,omitempty" json:"contract_code,omitempty"`
+	ContractDisplayAccount string `xml:"contract_display_account,omitempty" json:"contract_display_account,omitempty"`
+	MwebUrl                string `xml:"mweb_url,omitempty" json:"mweb_url,omitempty"`
+	OutTradeNo             string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
+}
+
 type getSignKeyResponse struct {
 type getSignKeyResponse struct {
 	ReturnCode     string `xml:"return_code,omitempty" json:"return_code,omitempty"`
 	ReturnCode     string `xml:"return_code,omitempty" json:"return_code,omitempty"`
 	ReturnMsg      string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
 	ReturnMsg      string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`

+ 4 - 2
wechat/service_api.go

@@ -174,7 +174,8 @@ func VerifySign(apiKey, signType string, bean interface{}) (ok bool, err error)
 		bm := bean.(gopay.BodyMap)
 		bm := bean.(gopay.BodyMap)
 		bodySign := bm.Get("sign")
 		bodySign := bm.Get("sign")
 		bm.Remove("sign")
 		bm.Remove("sign")
-		return getReleaseSign(apiKey, signType, bm) == bodySign, nil
+		sign := getReleaseSign(apiKey, signType, bm)
+		return sign == bodySign, nil
 	}
 	}
 
 
 	bs, err := json.Marshal(bean)
 	bs, err := json.Marshal(bean)
@@ -187,7 +188,8 @@ func VerifySign(apiKey, signType string, bean interface{}) (ok bool, err error)
 	}
 	}
 	bodySign := bm.Get("sign")
 	bodySign := bm.Get("sign")
 	bm.Remove("sign")
 	bm.Remove("sign")
-	return getReleaseSign(apiKey, signType, bm) == bodySign, nil
+	sign := getReleaseSign(apiKey, signType, bm)
+	return sign == bodySign, nil
 }
 }
 
 
 type NotifyResponse struct {
 type NotifyResponse struct {