Jerry 6 лет назад
Родитель
Сommit
662214a14e
8 измененных файлов с 474 добавлено и 80 удалено
  1. 25 25
      alipay/client.go
  2. 167 8
      qq/client.go
  3. 156 6
      qq/model.go
  4. 44 0
      qq/param.go
  5. 39 0
      qq/service_api.go
  6. 1 1
      release_note.txt
  7. 6 5
      wechat/client.go
  8. 36 35
      wechat/model.go

+ 25 - 25
alipay/client.go

@@ -49,7 +49,7 @@ func (a *Client) TradeFastPayRefundQuery(bm gopay.BodyMap) (aliRsp *TradeFastpay
 		bs []byte
 	)
 	if bm.Get("out_trade_no") == gopay.NULL && bm.Get("trade_no") == gopay.NULL {
-		return nil, errors.New("out_trade_no and trade_no are not allowed to be NULL at the same time")
+		return nil, errors.New("out_trade_no and trade_no are not allowed to be null at the same time")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.fastpay.refund.query"); err != nil {
 		return
@@ -73,7 +73,7 @@ func (a *Client) TradeOrderSettle(bm gopay.BodyMap) (aliRsp *TradeOrderSettleRes
 		bs []byte
 	)
 	if bm.Get("out_request_no") == gopay.NULL || bm.Get("trade_no") == gopay.NULL {
-		return nil, errors.New("out_request_no or trade_no are not allowed to be NULL")
+		return nil, errors.New("out_request_no or trade_no are not allowed to be null")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.order.settle"); err != nil {
 		return
@@ -97,7 +97,7 @@ func (a *Client) TradeCreate(bm gopay.BodyMap) (aliRsp *TradeCreateResponse, err
 		bs []byte
 	)
 	if bm.Get("out_trade_no") == gopay.NULL && bm.Get("buyer_id") == gopay.NULL {
-		return nil, errors.New("out_trade_no and buyer_id are not allowed to be NULL at the same time")
+		return nil, errors.New("out_trade_no and buyer_id are not allowed to be null at the same time")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.create"); err != nil {
 		return
@@ -121,7 +121,7 @@ func (a *Client) TradeClose(bm gopay.BodyMap) (aliRsp *TradeCloseResponse, err e
 		bs []byte
 	)
 	if bm.Get("out_trade_no") == gopay.NULL && bm.Get("trade_no") == gopay.NULL {
-		return nil, errors.New("out_trade_no and trade_no are not allowed to be NULL at the same time")
+		return nil, errors.New("out_trade_no and trade_no are not allowed to be null at the same time")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.close"); err != nil {
 		return
@@ -145,7 +145,7 @@ func (a *Client) TradeCancel(bm gopay.BodyMap) (aliRsp *TradeCancelResponse, err
 		bs []byte
 	)
 	if bm.Get("out_trade_no") == gopay.NULL && bm.Get("trade_no") == gopay.NULL {
-		return nil, errors.New("out_trade_no and trade_no are not allowed to be NULL at the same time")
+		return nil, errors.New("out_trade_no and trade_no are not allowed to be null at the same time")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.cancel"); err != nil {
 		return
@@ -169,7 +169,7 @@ func (a *Client) TradeRefund(bm gopay.BodyMap) (aliRsp *TradeRefundResponse, err
 		bs []byte
 	)
 	if bm.Get("out_trade_no") == gopay.NULL && bm.Get("trade_no") == gopay.NULL {
-		return nil, errors.New("out_trade_no and trade_no are not allowed to be NULL at the same time")
+		return nil, errors.New("out_trade_no and trade_no are not allowed to be null at the same time")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.refund"); err != nil {
 		return nil, err
@@ -193,7 +193,7 @@ func (a *Client) TradePageRefund(bm gopay.BodyMap) (aliRsp *TradePageRefundRespo
 		bs []byte
 	)
 	if bm.Get("out_trade_no") == gopay.NULL && bm.Get("trade_no") == gopay.NULL {
-		return nil, errors.New("out_trade_no and trade_no are not allowed to be NULL at the same time")
+		return nil, errors.New("out_trade_no and trade_no are not allowed to be null at the same time")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.page.refund"); err != nil {
 		return
@@ -215,7 +215,7 @@ func (a *Client) TradePageRefund(bm gopay.BodyMap) (aliRsp *TradePageRefundRespo
 func (a *Client) TradePrecreate(bm gopay.BodyMap) (aliRsp *TradePrecreateResponse, err error) {
 	var bs []byte
 	if bm.Get("out_trade_no") == gopay.NULL {
-		return nil, errors.New("out_trade_no is not allowed to be NULL")
+		return nil, errors.New("out_trade_no is not allowed to be null")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.precreate"); err != nil {
 		return
@@ -241,7 +241,7 @@ func (a *Client) TradePrecreate(bm gopay.BodyMap) (aliRsp *TradePrecreateRespons
 func (a *Client) TradePay(bm gopay.BodyMap) (aliRsp *TradePayResponse, err error) {
 	var bs []byte
 	if bm.Get("out_trade_no") == gopay.NULL {
-		return nil, errors.New("out_trade_no is not allowed to be NULL")
+		return nil, errors.New("out_trade_no is not allowed to be null")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.pay"); err != nil {
 		return
@@ -265,7 +265,7 @@ func (a *Client) TradeQuery(bm gopay.BodyMap) (aliRsp *TradeQueryResponse, err e
 		bs []byte
 	)
 	if bm.Get("out_trade_no") == gopay.NULL && bm.Get("trade_no") == gopay.NULL {
-		return nil, errors.New("out_trade_no and trade_no are not allowed to be NULL at the same time")
+		return nil, errors.New("out_trade_no and trade_no are not allowed to be null at the same time")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.query"); err != nil {
 		return
@@ -287,7 +287,7 @@ func (a *Client) TradeQuery(bm gopay.BodyMap) (aliRsp *TradeQueryResponse, err e
 func (a *Client) TradeAppPay(bm gopay.BodyMap) (payParam string, err error) {
 	var bs []byte
 	if bm.Get("out_trade_no") == gopay.NULL {
-		return gopay.NULL, errors.New("out_trade_no is not allowed to be NULL")
+		return gopay.NULL, errors.New("out_trade_no is not allowed to be null")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.trade.app.pay"); err != nil {
 		return gopay.NULL, err
@@ -301,7 +301,7 @@ func (a *Client) TradeAppPay(bm gopay.BodyMap) (payParam string, err error) {
 func (a *Client) TradeWapPay(bm gopay.BodyMap) (payUrl string, err error) {
 	var bs []byte
 	if bm.Get("out_trade_no") == gopay.NULL {
-		return gopay.NULL, errors.New("out_trade_no is not allowed to be NULL")
+		return gopay.NULL, errors.New("out_trade_no is not allowed to be null")
 	}
 	bm.Set("product_code", "QUICK_WAP_WAY")
 	if bs, err = a.doAliPay(bm, "alipay.trade.wap.pay"); err != nil {
@@ -316,7 +316,7 @@ func (a *Client) TradeWapPay(bm gopay.BodyMap) (payUrl string, err error) {
 func (a *Client) TradePagePay(bm gopay.BodyMap) (payUrl string, err error) {
 	var bs []byte
 	if bm.Get("out_trade_no") == gopay.NULL {
-		return gopay.NULL, errors.New("out_trade_no is not allowed to be NULL")
+		return gopay.NULL, errors.New("out_trade_no is not allowed to be null")
 	}
 	bm.Set("product_code", "FAST_INSTANT_TRADE_PAY")
 	if bs, err = a.doAliPay(bm, "alipay.trade.page.pay"); err != nil {
@@ -331,7 +331,7 @@ func (a *Client) TradePagePay(bm gopay.BodyMap) (payUrl string, err error) {
 func (a *Client) FundTransToaccountTransfer(bm gopay.BodyMap) (aliRsp *FundTransToaccountTransferResponse, err error) {
 	var bs []byte
 	if bm.Get("out_biz_no") == gopay.NULL {
-		return nil, errors.New("out_biz_no is not allowed to be NULL")
+		return nil, errors.New("out_biz_no is not allowed to be null")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.fund.trans.toaccount.transfer"); err != nil {
 		return
@@ -359,10 +359,10 @@ func (a *Client) TradeOrderinfoSync(body gopay.BodyMap) {
 func (a *Client) SystemOauthToken(bm gopay.BodyMap) (aliRsp *SystemOauthTokenResponse, err error) {
 	var bs []byte
 	if bm.Get("grant_type") == gopay.NULL {
-		return nil, errors.New("grant_type is not allowed to be NULL")
+		return nil, errors.New("grant_type is not allowed to be null")
 	}
 	if bm.Get("code") == gopay.NULL && bm.Get("refresh_token") == gopay.NULL {
-		return nil, errors.New("code and refresh_token are not allowed to be NULL at the same time")
+		return nil, errors.New("code and refresh_token are not allowed to be null at the same time")
 	}
 	if bs, err = systemOauthToken(a.AppId, a.PrivateKey, bm, "alipay.system.oauth.token", a.IsProd); err != nil {
 		return
@@ -404,10 +404,10 @@ func (a *Client) UserInfoShare() (aliRsp *UserInfoShareResponse, err error) {
 func (a *Client) OpenAuthTokenApp(bm gopay.BodyMap) (aliRsp *OpenAuthTokenAppResponse, err error) {
 	var bs []byte
 	if bm.Get("grant_type") == gopay.NULL {
-		return nil, errors.New("grant_type is not allowed to be NULL")
+		return nil, errors.New("grant_type is not allowed to be null")
 	}
 	if bm.Get("code") == gopay.NULL && bm.Get("refresh_token") == gopay.NULL {
-		return nil, errors.New("code and refresh_token are not allowed to be NULL at the same time")
+		return nil, errors.New("code and refresh_token are not allowed to be null at the same time")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.open.auth.token.app"); err != nil {
 		return
@@ -434,7 +434,7 @@ func (a *Client) ZhimaCreditScoreGet(bm gopay.BodyMap) (aliRsp *ZhimaCreditScore
 		bm.Set("product_code", "w1010100100000000001")
 	}
 	if bm.Get("transaction_id") == gopay.NULL {
-		return nil, errors.New("transaction_id is not allowed to be NULL")
+		return nil, errors.New("transaction_id is not allowed to be null")
 	}
 	if bs, err = a.doAliPay(bm, "zhima.credit.score.get"); err != nil {
 		return
@@ -458,16 +458,16 @@ func (a *Client) UserCertifyOpenInit(bm gopay.BodyMap) (aliRsp *UserCertifyOpenI
 		bs []byte
 	)
 	if bm.Get("biz_code") == gopay.NULL {
-		return nil, errors.New("biz_code is not allowed to be NULL")
+		return nil, errors.New("biz_code is not allowed to be null")
 	}
 	if bm.Get("outer_order_no") == gopay.NULL {
-		return nil, errors.New("outer_order_no is not allowed to be NULL")
+		return nil, errors.New("outer_order_no is not allowed to be null")
 	}
 	if bm.Get("identity_param") == gopay.NULL {
-		return nil, errors.New("identity_param is not allowed to be NULL")
+		return nil, errors.New("identity_param is not allowed to be null")
 	}
 	if bm.Get("merchant_config") == gopay.NULL {
-		return nil, errors.New("merchant_config is not allowed to be NULL")
+		return nil, errors.New("merchant_config is not allowed to be null")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.user.certify.open.initialize"); err != nil {
 		return
@@ -492,7 +492,7 @@ func (a *Client) UserCertifyOpenCertify(bm gopay.BodyMap) (certifyUrl string, er
 		bs []byte
 	)
 	if bm.Get("certify_id") == gopay.NULL {
-		return gopay.NULL, errors.New("certify_id is not allowed to be NULL")
+		return gopay.NULL, errors.New("certify_id is not allowed to be null")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.user.certify.open.certify"); err != nil {
 		return gopay.NULL, err
@@ -508,7 +508,7 @@ func (a *Client) UserCertifyOpenQuery(bm gopay.BodyMap) (aliRsp *UserCertifyOpen
 		bs []byte
 	)
 	if bm.Get("certify_id") == gopay.NULL {
-		return nil, errors.New("certify_id is not allowed to be NULL")
+		return nil, errors.New("certify_id is not allowed to be null")
 	}
 	if bs, err = a.doAliPay(bm, "alipay.user.certify.open.query"); err != nil {
 		return

+ 167 - 8
qq/client.go

@@ -25,22 +25,23 @@ type Client struct {
 //    mchId:商户ID
 //    ApiKey:API秘钥值
 func NewClient(mchId, apiKey string) (client *Client) {
-	return &Client{
-		MchId:  mchId,
-		ApiKey: apiKey,
+	if mchId != gopay.NULL && apiKey != gopay.NULL {
+		return &Client{
+			MchId:  mchId,
+			ApiKey: apiKey,
+		}
 	}
+	return nil
 }
 
 // 提交付款码支付
-//    文档地址:https://qpay.qq.com/buss/wiki/43/1157
+//    文档地址:https://qpay.qq.com/buss/wiki/1/1122
 func (q *Client) MicroPay(bm gopay.BodyMap) (qqRsp *MicroPayResponse, err error) {
-	err = bm.CheckEmptyError("sub_mch_id", "nonce_str", "body", "out_trade_no", "total_fee", "spbill_create_ip", "device_info", "auth_code")
+	err = bm.CheckEmptyError("nonce_str", "body", "out_trade_no", "total_fee", "spbill_create_ip", "device_info", "auth_code")
 	if err != nil {
 		return nil, err
 	}
-	if bm.Get("trade_type") == gopay.NULL {
-		bm.Set("trade_type", TradeType_MicroPay)
-	}
+	bm.Set("trade_type", TradeType_MicroPay)
 	bs, err := q.doQQ(bm, qqMicroPay, nil)
 	if err != nil {
 		return nil, err
@@ -52,6 +53,164 @@ func (q *Client) MicroPay(bm gopay.BodyMap) (qqRsp *MicroPayResponse, err error)
 	return qqRsp, nil
 }
 
+// 撤销订单
+//    文档地址:https://qpay.qq.com/buss/wiki/1/1125
+func (q *Client) Reverse(bm gopay.BodyMap) (qqRsp *ReverseResponse, err error) {
+	err = bm.CheckEmptyError("sub_mch_id", "nonce_str", "out_trade_no", "op_user_id", "op_user_passwd")
+	if err != nil {
+		return nil, err
+	}
+	bs, err := q.doQQ(bm, qqReverse, nil)
+	if err != nil {
+		return nil, err
+	}
+	qqRsp = new(ReverseResponse)
+	if err = xml.Unmarshal(bs, qqRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err.Error())
+	}
+	return qqRsp, nil
+}
+
+// 统一下单
+//    文档地址:https://qpay.qq.com/buss/wiki/38/1203
+func (q *Client) UnifiedOrder(bm gopay.BodyMap) (qqRsp *UnifiedOrderResponse, err error) {
+	err = bm.CheckEmptyError("nonce_str", "body", "out_trade_no", "total_fee", "spbill_create_ip", "trade_type", "notify_url")
+	if err != nil {
+		return nil, err
+	}
+	bs, err := q.doQQ(bm, qqUnifiedOrder, nil)
+	if err != nil {
+		return nil, err
+	}
+	qqRsp = new(UnifiedOrderResponse)
+	if err = xml.Unmarshal(bs, qqRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err.Error())
+	}
+	return qqRsp, nil
+}
+
+// 订单查询
+//    文档地址:https://qpay.qq.com/buss/wiki/38/1205
+func (q *Client) OrderQuery(bm gopay.BodyMap) (qqRsp *OrderQueryResponse, err error) {
+	err = bm.CheckEmptyError("nonce_str")
+	if err != nil {
+		return nil, err
+	}
+	if bm.Get("out_trade_no") == gopay.NULL && bm.Get("transaction_id") == gopay.NULL {
+		return nil, errors.New("out_trade_no and transaction_id are not allowed to be null at the same time")
+	}
+	bs, err := q.doQQ(bm, qqOrderQuery, nil)
+	if err != nil {
+		return nil, err
+	}
+	qqRsp = new(OrderQueryResponse)
+	if err = xml.Unmarshal(bs, qqRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err.Error())
+	}
+	return qqRsp, nil
+}
+
+// 关闭订单
+//    文档地址:https://qpay.qq.com/buss/wiki/38/1206
+func (q *Client) CloseOrder(bm gopay.BodyMap) (qqRsp *CloseOrderResponse, err error) {
+	err = bm.CheckEmptyError("nonce_str", "out_trade_no")
+	if err != nil {
+		return nil, err
+	}
+	bs, err := q.doQQ(bm, qqOrderClose, nil)
+	if err != nil {
+		return nil, err
+	}
+	qqRsp = new(CloseOrderResponse)
+	if err = xml.Unmarshal(bs, qqRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err.Error())
+	}
+	return qqRsp, nil
+}
+
+// 申请退款
+//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
+//    文档地址:https://qpay.qq.com/buss/wiki/38/1207
+func (q *Client) Refund(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (qqRsp *RefundResponse, err error) {
+	err = bm.CheckEmptyError("nonce_str", "out_refund_no", "refund_fee", "op_user_id", "op_user_passwd")
+	if err != nil {
+		return nil, err
+	}
+	if bm.Get("out_trade_no") == gopay.NULL && bm.Get("transaction_id") == gopay.NULL {
+		return nil, errors.New("out_trade_no and transaction_id are not allowed to be null at the same time")
+	}
+	tlsConfig, err := q.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath)
+	if err != nil {
+		return nil, err
+	}
+	bs, err := q.doQQ(bm, qqRefund, tlsConfig)
+	if err != nil {
+		return nil, err
+	}
+	qqRsp = new(RefundResponse)
+	if err = xml.Unmarshal(bs, qqRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err.Error())
+	}
+	return qqRsp, nil
+}
+
+// 退款查询
+//    文档地址:https://qpay.qq.com/buss/wiki/38/1208
+func (q *Client) RefundQuery(bm gopay.BodyMap) (qqRsp *RefundQueryResponse, err error) {
+	err = bm.CheckEmptyError("nonce_str")
+	if err != nil {
+		return nil, err
+	}
+	if bm.Get("refund_id") == gopay.NULL && bm.Get("out_refund_no") == gopay.NULL && bm.Get("transaction_id") == gopay.NULL && bm.Get("out_trade_no") == gopay.NULL {
+		return nil, errors.New("refund_id, out_refund_no, out_trade_no, transaction_id are not allowed to be null at the same time")
+	}
+	bs, err := q.doQQ(bm, qqRefundQuery, nil)
+	if err != nil {
+		return nil, err
+	}
+	qqRsp = new(RefundQueryResponse)
+	if err = xml.Unmarshal(bs, qqRsp); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err.Error())
+	}
+	return qqRsp, nil
+}
+
+// 交易账单
+//    文档地址:https://qpay.qq.com/buss/wiki/38/1209
+func (q *Client) StatementDown(bm gopay.BodyMap) (qqRsp string, err error) {
+	err = bm.CheckEmptyError("nonce_str", "bill_date", "bill_type")
+	if err != nil {
+		return gopay.NULL, err
+	}
+	billType := bm.Get("bill_type")
+	if billType != "ALL" && billType != "SUCCESS" && billType != "REFUND" && billType != "RECHAR" {
+		return gopay.NULL, errors.New("bill_type error, please reference: https://qpay.qq.com/buss/wiki/38/1209")
+	}
+	bs, err := q.doQQ(bm, qqStatementDown, nil)
+	if err != nil {
+		return gopay.NULL, err
+	}
+	return string(bs), nil
+}
+
+// 资金账单
+//    文档地址:https://qpay.qq.com/buss/wiki/38/3089
+func (q *Client) AccRoll(bm gopay.BodyMap) (qqRsp string, err error) {
+	err = bm.CheckEmptyError("nonce_str", "bill_date", "acc_type")
+	if err != nil {
+		return gopay.NULL, err
+	}
+	accType := bm.Get("acc_type")
+	if accType != "CASH" && accType != "MARKETING" {
+		return gopay.NULL, errors.New("acc_type error, please reference: https://qpay.qq.com/buss/wiki/38/3089")
+	}
+	bs, err := q.doQQ(bm, qqAccRoll, nil)
+	if err != nil {
+		return gopay.NULL, err
+	}
+	return string(bs), nil
+}
+
 // 向QQ发送请求
 func (q *Client) doQQ(bm gopay.BodyMap, url string, tlsConfig *tls.Config) (bs []byte, err error) {
 	bm.Set("mch_id", q.MchId)

+ 156 - 6
qq/model.go

@@ -24,19 +24,37 @@ const (
 	SignType_HMAC_SHA256 = "HMAC-SHA256"
 )
 
+type NotifyRequest struct {
+	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"`
+	DeviceInfo    string `xml:"device_info,omitempty" json:"device_info,omitempty"`
+	TradeType     string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
+	TradeState    string `xml:"trade_state,omitempty" json:"trade_state,omitempty"`
+	BankType      string `xml:"bank_type,omitempty" json:"bank_type,omitempty"`
+	FeeType       string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
+	TotalFee      int    `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
+	CashFee       int    `xml:"cash_fee,omitempty" json:"cash_fee,omitempty"`
+	CouponFee     int    `xml:"coupon_fee,omitempty" json:"coupon_fee,omitempty"`
+	TransactionId string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
+	OutTradeNo    string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
+	Attach        string `xml:"attach,omitempty" json:"attach,omitempty"`
+	TimeEnd       string `xml:"time_end,omitempty" json:"time_end,omitempty"`
+	Openid        string `xml:"openid,omitempty" json:"openid,omitempty"`
+}
+
 type MicroPayResponse struct {
 	ReturnCode     string `xml:"return_code,omitempty" json:"return_code,omitempty"`
 	ReturnMsg      string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
 	RetCode        string `xml:"retcode,omitempty" json:"retcode,omitempty"`
 	RetMsg         string `xml:"retmsg,omitempty" json:"retmsg,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"`
 	ResultCode     string `xml:"result_code,omitempty" json:"result_code,omitempty"`
 	ErrCode        string `xml:"err_code,omitempty" json:"err_code,omitempty"`
 	ErrCodeDes     string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
-	Sign           string `xml:"sign,omitempty" json:"sign,omitempty"`
-	Appid          string `xml:"appid,omitempty" json:"appid,omitempty"`
-	SubAppid       string `xml:"sub_appid,omitempty" json:"sub_appid,omitempty"`
-	MchId          string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
-	SubMchId       string `xml:"sub_mch_id,omitempty" json:"sub_mch_id,omitempty"`
 	NonceStr       string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
 	DeviceInfo     string `xml:"device_info,omitempty" json:"device_info,omitempty"`
 	TradeType      string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
@@ -45,6 +63,7 @@ type MicroPayResponse struct {
 	FeeType        string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
 	TotalFee       int    `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
 	CashFee        int    `xml:"cash_fee,omitempty" json:"cash_fee,omitempty"`
+	CouponFee      int    `xml:"coupon_fee,omitempty" json:"coupon_fee,omitempty"`
 	CouponFee0     int    `xml:"coupon_fee_0,omitempty" json:"coupon_fee_0,omitempty"`
 	CouponFee1     int    `xml:"coupon_fee_1,omitempty" json:"coupon_fee_1,omitempty"`
 	TransactionId  string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
@@ -53,5 +72,136 @@ type MicroPayResponse struct {
 	TimeEnd        string `xml:"time_end,omitempty" json:"time_end,omitempty"`
 	TradeStateDesc string `xml:"trade_state_desc,omitempty" json:"trade_state_desc,omitempty"`
 	Openid         string `xml:"openid,omitempty" json:"openid,omitempty"`
-	SubOpenid      string `xml:"sub_openid,omitempty" json:"sub_openid,omitempty"`
+}
+
+type ReverseResponse struct {
+	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	RetCode    string `xml:"retcode,omitempty" json:"retcode,omitempty"`
+	RetMsg     string `xml:"retmsg,omitempty" json:"retmsg,omitempty"`
+	Appid      string `xml:"appid,omitempty" json:"appid,omitempty"`
+	SubAppid   string `xml:"sub_appid,omitempty" json:"sub_appid,omitempty"`
+	MchId      string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
+	SubMchId   string `xml:"sub_mch_id,omitempty" json:"sub_mch_id,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"`
+	ErrCodeDes string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
+	NonceStr   string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
+	Recall     string `json:"recall,omitempty"`
+}
+
+type UnifiedOrderResponse struct {
+	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	RetCode    string `xml:"retcode,omitempty" json:"retcode,omitempty"`
+	RetMsg     string `xml:"retmsg,omitempty" json:"retmsg,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"`
+	ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	ErrCode    string `xml:"err_code,omitempty" json:"err_code,omitempty"`
+	ErrCodeDes string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
+	NonceStr   string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
+	TradeType  string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
+	PrepayId   string `xml:"prepay_id,omitempty" json:"prepay_id,omitempty"`
+	CodeUrl    string `xml:"code_url,omitempty" json:"code_url,omitempty"`
+}
+
+type OrderQueryResponse struct {
+	ReturnCode     string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg      string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	RetCode        string `xml:"retcode,omitempty" json:"retcode,omitempty"`
+	RetMsg         string `xml:"retmsg,omitempty" json:"retmsg,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"`
+	ResultCode     string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	ErrCode        string `xml:"err_code,omitempty" json:"err_code,omitempty"`
+	ErrCodeDes     string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
+	NonceStr       string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
+	DeviceInfo     string `xml:"device_info,omitempty" json:"device_info,omitempty"`
+	TradeType      string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
+	TradeState     string `xml:"trade_state,omitempty" json:"trade_state,omitempty"`
+	BankType       string `xml:"bank_type,omitempty" json:"bank_type,omitempty"`
+	FeeType        string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
+	TotalFee       int    `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
+	CashFee        int    `xml:"cash_fee,omitempty" json:"cash_fee,omitempty"`
+	CouponFee      int    `xml:"coupon_fee,omitempty" json:"coupon_fee,omitempty"`
+	TransactionId  string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
+	OutTradeNo     string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
+	Attach         string `xml:"attach,omitempty" json:"attach,omitempty"`
+	TimeEnd        string `xml:"time_end,omitempty" json:"time_end,omitempty"`
+	TradeStateDesc string `xml:"trade_state_desc,omitempty" json:"trade_state_desc,omitempty"`
+	Openid         string `xml:"openid,omitempty" json:"openid,omitempty"`
+}
+
+type CloseOrderResponse struct {
+	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	RetCode    string `xml:"retcode,omitempty" json:"retcode,omitempty"`
+	RetMsg     string `xml:"retmsg,omitempty" json:"retmsg,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"`
+	ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	ErrCode    string `xml:"err_code,omitempty" json:"err_code,omitempty"`
+	ErrCodeDes string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
+	NonceStr   string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
+}
+
+type RefundResponse struct {
+	ReturnCode    string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg     string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	RetCode       string `xml:"retcode,omitempty" json:"retcode,omitempty"`
+	RetMsg        string `xml:"retmsg,omitempty" json:"retmsg,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"`
+	ResultCode    string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	ErrCode       string `xml:"err_code,omitempty" json:"err_code,omitempty"`
+	ErrCodeDes    string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
+	NonceStr      string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
+	TransactionId string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
+	OutTradeNo    string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
+	TotalFee      int    `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
+	OutRefundNo   string `xml:"out_refund_no,omitempty" json:"out_refund_no,omitempty"`
+	RefundId      string `xml:"refund_id,omitempty" json:"refund_id,omitempty"`
+	RefundChannel string `xml:"refund_channel,omitempty" json:"refund_channel,omitempty"`
+	RefundFee     int    `xml:"refund_fee,omitempty" json:"refund_fee,omitempty"`
+}
+
+type RefundQueryResponse struct {
+	ReturnCode        string `xml:"return_code,omitempty" json:"return_code,omitempty"`
+	ReturnMsg         string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
+	RetCode           string `xml:"retcode,omitempty" json:"retcode,omitempty"`
+	RetMsg            string `xml:"retmsg,omitempty" json:"retmsg,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"`
+	ResultCode        string `xml:"result_code,omitempty" json:"result_code,omitempty"`
+	ErrCode           string `xml:"err_code,omitempty" json:"err_code,omitempty"`
+	ErrCodeDes        string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
+	NonceStr          string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
+	TransactionId     string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
+	OutTradeNo        string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
+	TotalFee          int    `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
+	CashFee           int    `xml:"cash_fee,omitempty" json:"cash_fee,omitempty"`
+	FeeType           string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
+	OutRefundNo0      string `xml:"out_refund_no_0,omitempty" json:"out_refund_no_0,omitempty"`
+	OutRefundNo1      string `xml:"out_refund_no_1,omitempty" json:"out_refund_no_1,omitempty"`
+	RefundId0         string `xml:"refund_id_0,omitempty" json:"refund_id_0,omitempty"`
+	RefundId1         string `xml:"refund_id_1,omitempty" json:"refund_id_1,omitempty"`
+	RefundChannel0    string `xml:"refund_channel_0,omitempty" json:"refund_channel_0,omitempty"`
+	RefundChannel1    string `xml:"refund_channel_1,omitempty" json:"refund_channel_1,omitempty"`
+	RefundFee0        int    `xml:"refund_fee_0,omitempty" json:"refund_fee_0,omitempty"`
+	RefundFee1        int    `xml:"refund_fee_1,omitempty" json:"refund_fee_1,omitempty"`
+	CouponRefundFee0  int    `xml:"coupon_refund_fee_0,omitempty" json:"coupon_refund_fee_0,omitempty"`
+	CouponRefundFee1  int    `xml:"coupon_refund_fee_1,omitempty" json:"coupon_refund_fee_1,omitempty"`
+	CashRefundFee0    int    `xml:"cash_refund_fee_0,omitempty" json:"cash_refund_fee_0,omitempty"`
+	CashRefundFee1    int    `xml:"cash_refund_fee_1,omitempty" json:"cash_refund_fee_1,omitempty"`
+	RefundStatus0     string `xml:"refund_status_0,omitempty" json:"refund_status_0,omitempty"`
+	RefundStatus1     string `xml:"refund_status_1,omitempty" json:"refund_status_1,omitempty"`
+	RefundRecvAccout0 string `xml:"refund_recv_accout_0,omitempty" json:"refund_recv_accout_0,omitempty"`
+	RefundRecvAccout1 string `xml:"refund_recv_accout_1,omitempty" json:"refund_recv_accout_1,omitempty"`
 }

+ 44 - 0
qq/param.go

@@ -4,8 +4,12 @@ import (
 	"crypto/hmac"
 	"crypto/md5"
 	"crypto/sha256"
+	"crypto/tls"
+	"crypto/x509"
 	"encoding/hex"
 	"encoding/xml"
+	"errors"
+	"fmt"
 	"hash"
 	"io/ioutil"
 	"strings"
@@ -71,3 +75,43 @@ func getReleaseSign(apiKey string, signType string, bm gopay.BodyMap) (sign stri
 	h.Write([]byte(bm.EncodeWeChatSignParams(apiKey)))
 	return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
 }
+
+func (q *Client) addCertConfig(certFilePath, keyFilePath, pkcs12FilePath string) (tlsConfig *tls.Config, err error) {
+	var (
+		pkcs        []byte
+		certificate tls.Certificate
+		pkcsPool    = x509.NewCertPool()
+	)
+
+	if certFilePath == gopay.NULL && keyFilePath == gopay.NULL && pkcs12FilePath == gopay.NULL {
+		q.mu.RLock()
+		pkcsPool.AppendCertsFromPEM(q.Pkcs12File)
+		certificate, err = tls.X509KeyPair(q.CertFile, q.KeyFile)
+		q.mu.RUnlock()
+		if err != nil {
+			return nil, fmt.Errorf("tls.X509KeyPair:%s", err.Error())
+		}
+		tlsConfig = &tls.Config{
+			Certificates:       []tls.Certificate{certificate},
+			RootCAs:            pkcsPool,
+			InsecureSkipVerify: true}
+		return tlsConfig, nil
+	}
+
+	if certFilePath != gopay.NULL && keyFilePath != gopay.NULL && pkcs12FilePath != gopay.NULL {
+		if pkcs, err = ioutil.ReadFile(pkcs12FilePath); err != nil {
+			return nil, fmt.Errorf("ioutil.ReadFile:%s", err.Error())
+		}
+		pkcsPool.AppendCertsFromPEM(pkcs)
+		if certificate, err = tls.LoadX509KeyPair(certFilePath, keyFilePath); err != nil {
+			return nil, fmt.Errorf("tls.LoadX509KeyPair:%s", err.Error())
+		}
+		tlsConfig = &tls.Config{
+			Certificates:       []tls.Certificate{certificate},
+			RootCAs:            pkcsPool,
+			InsecureSkipVerify: true}
+		return tlsConfig, nil
+	}
+
+	return nil, errors.New("certificate file path must be all input or all input null")
+}

+ 39 - 0
qq/service_api.go

@@ -0,0 +1,39 @@
+package qq
+
+import (
+	"encoding/xml"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+
+	"github.com/iGoogle-ink/gopay"
+)
+
+// 解析QQ支付异步通知的结果到BodyMap
+//    req:*http.Request
+//    返回参数bm:Notify请求的参数
+//    返回参数err:错误信息
+func ParseNotifyResultToBodyMap(req *http.Request) (bm gopay.BodyMap, err error) {
+	bs, err := ioutil.ReadAll(io.LimitReader(req.Body, int64(2<<20))) // default 2MB change the size you want;
+	if err != nil {
+		return nil, fmt.Errorf("ioutil.ReadAll:%s", err.Error())
+	}
+	bm = make(gopay.BodyMap)
+	if err = xml.Unmarshal(bs, &bm); err != nil {
+		return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err.Error())
+	}
+	return
+}
+
+// 解析QQ支付异步通知的参数
+//    req:*http.Request
+//    返回参数notifyReq:Notify请求的参数
+//    返回参数err:错误信息
+func ParseNotifyResult(req *http.Request) (notifyReq *NotifyRequest, err error) {
+	notifyReq = new(NotifyRequest)
+	if err = xml.NewDecoder(req.Body).Decode(notifyReq); err != nil {
+		return nil, fmt.Errorf("xml.NewDecoder:%s", err.Error())
+	}
+	return
+}

+ 1 - 1
release_note.txt

@@ -39,7 +39,7 @@
    (2) 支付宝:修改公共API方法:gopay.VerifyAliPaySign(),支付宝异步验签支持传入 BodyMap
    (3) 微信:新增Client方法:client.AddCertFileByte(),添加微信证书 Byte 数组
    (4) 微信:新增Client方法:client.AddCertFilePath(),添加微信证书 Path 路径
-   (5) 微信:微信Client需要证书的方法,如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",如方法需单独使用证书,则传证书Path
+   (5) 微信:微信Client需要证书的方法,如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
    (6) BodyMap 的Set方法去掉switch判断,直接赋值
    (7) WeChatClient、AliPayClient 加锁
    (8) 修改部分小问题和部分样式

+ 6 - 5
wechat/client.go

@@ -80,6 +80,7 @@ func (w *Client) UnifiedOrder(bm gopay.BodyMap) (wxRsp *UnifiedOrderResponse, er
 func (w *Client) QueryOrder(bm gopay.BodyMap) (wxRsp *QueryOrderResponse, err error) {
 	var bs []byte
 	if w.IsProd {
+		re
 		bs, err = w.doWeChat(bm, wxOrderquery, nil)
 	} else {
 		bs, err = w.doWeChat(bm, wxSandboxOrderquery, nil)
@@ -114,7 +115,7 @@ func (w *Client) CloseOrder(bm gopay.BodyMap) (wxRsp *CloseOrderResponse, err er
 }
 
 // 撤销订单
-//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",如方法需单独使用证书,则传证书Path
+//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
 func (w *Client) Reverse(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (wxRsp *ReverseResponse, err error) {
 	var (
@@ -140,7 +141,7 @@ func (w *Client) Reverse(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12File
 }
 
 // 申请退款
-//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",如方法需单独使用证书,则传证书Path
+//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
 func (w *Client) Refund(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (wxRsp *RefundResponse, err error) {
 	var (
@@ -201,7 +202,7 @@ func (w *Client) DownloadBill(bm gopay.BodyMap) (wxRsp string, err error) {
 }
 
 // 下载资金账单
-//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",如方法需单独使用证书,则传证书Path
+//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    貌似不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7
 func (w *Client) DownloadFundFlow(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (wxRsp string, err error) {
@@ -225,7 +226,7 @@ func (w *Client) DownloadFundFlow(bm gopay.BodyMap, certFilePath, keyFilePath, p
 }
 
 // 拉取订单评价数据
-//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",如方法需单独使用证书,则传证书Path
+//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    貌似不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_17&index=11
 func (w *Client) BatchQueryComment(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (wxRsp string, err error) {
@@ -250,7 +251,7 @@ func (w *Client) BatchQueryComment(bm gopay.BodyMap, certFilePath, keyFilePath,
 }
 
 // 企业向微信用户个人付款
-//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",如方法需单独使用证书,则传证书Path
+//    注意:如已使用client.AddCertFilePath()或client.AddCertFileByte()添加过证书,参数certFilePath、keyFilePath、pkcs12FilePath全传空字符串 "",否则,3证书Path均不可空
 //    注意:此方法未支持沙箱环境,默认正式环境,转账请慎重
 //    文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1
 func (w *Client) Transfer(bm gopay.BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (wxRsp *TransfersResponse, err error) {

+ 36 - 35
wechat/model.go

@@ -58,6 +58,42 @@ const (
 	SignType_HMAC_SHA256 = "HMAC-SHA256"
 )
 
+// Notify
+type NotifyRequest 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"`
+	ErrCodeDes         string `xml:"err_code_des,omitempty" json:"err_code_des,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"`
+	SignType           string `xml:"sign_type,omitempty" json:"sign_type,omitempty"`
+	Openid             string `xml:"openid,omitempty" json:"openid,omitempty"`
+	IsSubscribe        string `xml:"is_subscribe,omitempty" json:"is_subscribe,omitempty"`
+	TradeType          string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
+	BankType           string `xml:"bank_type,omitempty" json:"bank_type,omitempty"`
+	TotalFee           int    `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
+	SettlementTotalFee int    `xml:"settlement_total_fee,omitempty" json:"settlement_total_fee,omitempty"`
+	FeeType            string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
+	CashFee            int    `xml:"cash_fee,omitempty" json:"cash_fee,omitempty"`
+	CashFeeType        string `xml:"cash_fee_type,omitempty" json:"cash_fee_type,omitempty"`
+	CouponFee          int    `xml:"coupon_fee,omitempty" json:"coupon_fee,omitempty"`
+	CouponCount        int    `xml:"coupon_count,omitempty" json:"coupon_count,omitempty"`
+	CouponType0        string `xml:"coupon_type_0,omitempty" json:"coupon_type_0,omitempty"`
+	CouponType1        string `xml:"coupon_type_1,omitempty" json:"coupon_type_1,omitempty"`
+	CouponId0          string `xml:"coupon_id_0,omitempty" json:"coupon_id_0,omitempty"`
+	CouponId1          string `xml:"coupon_id_1,omitempty" json:"coupon_id_1,omitempty"`
+	CouponFee0         int    `xml:"coupon_fee_0,omitempty" json:"coupon_fee_0,omitempty"`
+	CouponFee1         int    `xml:"coupon_fee_1,omitempty" json:"coupon_fee_1,omitempty"`
+	TransactionId      string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
+	OutTradeNo         string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
+	Attach             string `xml:"attach,omitempty" json:"attach,omitempty"`
+	TimeEnd            string `xml:"time_end,omitempty" json:"time_end,omitempty"`
+}
+
 type UnifiedOrderResponse struct {
 	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
 	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
@@ -274,41 +310,6 @@ type getSignKeyResponse struct {
 	SandboxSignkey string `xml:"sandbox_signkey,omitempty" json:"sandbox_signkey,omitempty"`
 }
 
-type NotifyRequest 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"`
-	ErrCodeDes         string `xml:"err_code_des,omitempty" json:"err_code_des,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"`
-	SignType           string `xml:"sign_type,omitempty" json:"sign_type,omitempty"`
-	Openid             string `xml:"openid,omitempty" json:"openid,omitempty"`
-	IsSubscribe        string `xml:"is_subscribe,omitempty" json:"is_subscribe,omitempty"`
-	TradeType          string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
-	BankType           string `xml:"bank_type,omitempty" json:"bank_type,omitempty"`
-	TotalFee           int    `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
-	SettlementTotalFee int    `xml:"settlement_total_fee,omitempty" json:"settlement_total_fee,omitempty"`
-	FeeType            string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
-	CashFee            int    `xml:"cash_fee,omitempty" json:"cash_fee,omitempty"`
-	CashFeeType        string `xml:"cash_fee_type,omitempty" json:"cash_fee_type,omitempty"`
-	CouponFee          int    `xml:"coupon_fee,omitempty" json:"coupon_fee,omitempty"`
-	CouponCount        int    `xml:"coupon_count,omitempty" json:"coupon_count,omitempty"`
-	CouponType0        string `xml:"coupon_type_0,omitempty" json:"coupon_type_0,omitempty"`
-	CouponType1        string `xml:"coupon_type_1,omitempty" json:"coupon_type_1,omitempty"`
-	CouponId0          string `xml:"coupon_id_0,omitempty" json:"coupon_id_0,omitempty"`
-	CouponId1          string `xml:"coupon_id_1,omitempty" json:"coupon_id_1,omitempty"`
-	CouponFee0         int    `xml:"coupon_fee_0,omitempty" json:"coupon_fee_0,omitempty"`
-	CouponFee1         int    `xml:"coupon_fee_1,omitempty" json:"coupon_fee_1,omitempty"`
-	TransactionId      string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
-	OutTradeNo         string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
-	Attach             string `xml:"attach,omitempty" json:"attach,omitempty"`
-	TimeEnd            string `xml:"time_end,omitempty" json:"time_end,omitempty"`
-}
-
 type RefundNotifyRequest struct {
 	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
 	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`