From ad3cc913b06d3d00ff2bc2816863351642ccc6d0 Mon Sep 17 00:00:00 2001 From: baiyuxiong Date: Fri, 5 Mar 2021 11:46:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=80=80=E6=AC=BE=20bug=20?= =?UTF-8?q?=E5=8F=8A=E5=A2=9E=E5=8A=A0=E4=BB=98=E6=AC=BE=E5=88=B0=E9=9B=B6?= =?UTF-8?q?=E9=92=B1=E7=9A=84=E6=94=AF=E4=BB=98=20(#373)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix refund bug and add transfer to wallet support * fmt code * fix golangci-lint * fix golangci-lint --- pay/refund/refund.go | 13 ++- pay/transfer/transfer_wallet.go | 138 ++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 pay/transfer/transfer_wallet.go diff --git a/pay/refund/refund.go b/pay/refund/refund.go index d64a91d..c7eea9b 100644 --- a/pay/refund/refund.go +++ b/pay/refund/refund.go @@ -24,6 +24,7 @@ func NewRefund(cfg *config.Config) *Refund { //Params 调用参数 type Params struct { TransactionID string + OutTradeNo string OutRefundNo string TotalFee string RefundFee string @@ -39,7 +40,8 @@ type request struct { NonceStr string `xml:"nonce_str"` Sign string `xml:"sign"` SignType string `xml:"sign_type,omitempty"` - TransactionID string `xml:"transaction_id"` + TransactionID string `xml:"transaction_id,omitempty"` + OutTradeNo string `xml:"out_trade_no,omitempty"` OutRefundNo string `xml:"out_refund_no"` TotalFee string `xml:"total_fee"` RefundFee string `xml:"refund_fee"` @@ -83,7 +85,12 @@ func (refund *Refund) Refund(p *Params) (rsp Response, err error) { param["refund_fee"] = p.RefundFee param["total_fee"] = p.TotalFee param["sign_type"] = util.SignTypeMD5 - param["transaction_id"] = p.TransactionID + if p.TransactionID != "" { + param["transaction_id"] = p.TransactionID + } + if p.OutTradeNo != "" { + param["out_trade_no"] = p.OutTradeNo + } if p.NotifyURL != "" { param["notify_url"] = p.NotifyURL } @@ -101,9 +108,11 @@ func (refund *Refund) Refund(p *Params) (rsp Response, err error) { SignType: util.SignTypeMD5, TransactionID: p.TransactionID, OutRefundNo: p.OutRefundNo, + OutTradeNo: p.OutTradeNo, TotalFee: p.TotalFee, RefundFee: p.RefundFee, RefundDesc: p.RefundDesc, + NotifyURL: p.NotifyURL, } rawRet, err := util.PostXMLWithTLS(refundGateway, req, p.RootCa, refund.MchID) if err != nil { diff --git a/pay/transfer/transfer_wallet.go b/pay/transfer/transfer_wallet.go new file mode 100644 index 0000000..b6dcc91 --- /dev/null +++ b/pay/transfer/transfer_wallet.go @@ -0,0 +1,138 @@ +package transfer + +import ( + "encoding/xml" + "fmt" + "strconv" + + "github.com/silenceper/wechat/v2/pay/config" + "github.com/silenceper/wechat/v2/util" +) + +// 付款到零钱 +// https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2 +var walletTransferGateway = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers" + +// Transfer struct extends context +type Transfer struct { + *config.Config +} + +// NewTransfer return an instance of Transfer package +func NewTransfer(cfg *config.Config) *Transfer { + transfer := Transfer{cfg} + return &transfer +} + +//Params 调用参数 +type Params struct { + DeviceInfo string + PartnerTradeNo string + OpenID string + CheckName bool + ReUserName string + Amount int + Desc string + SpbillCreateIP string + RootCa string //ca证书 +} + +//request 接口请求参数 +type request struct { + AppID string `xml:"mch_appid"` + MchID string `xml:"mchid"` + NonceStr string `xml:"nonce_str"` + Sign string `xml:"sign"` + DeviceInfo string `xml:"device_info,omitempty"` + PartnerTradeNo string `xml:"partner_trade_no"` + OpenID string `xml:"openid"` + CheckName string `xml:"check_name"` + ReUserName string `xml:"re_user_name,omitempty"` + Amount int `xml:"amount"` + Desc string `xml:"desc"` + SpbillCreateIP string `xml:"spbill_create_ip,omitempty"` +} + +//Response 接口返回 +type Response struct { + ReturnCode string `xml:"return_code"` + ReturnMsg string `xml:"return_msg"` + AppID string `xml:"appid,omitempty"` + MchID string `xml:"mch_id,omitempty"` + DeviceInfo string `xml:"device_info,omitempty"` + NonceStr string `xml:"nonce_str,omitempty"` + ResultCode string `xml:"result_code,omitempty"` + ErrCode string `xml:"err_code,omitempty"` + ErrCodeDes string `xml:"err_code_des,omitempty"` + PartnerTradeNo string `xml:"partner_trade_no"` + PaymentNo string `xml:"payment_no"` + PaymentTime string `xml:"payment_time"` +} + +//WalletTransfer 付款到零钱 +func (transfer *Transfer) WalletTransfer(p *Params) (rsp Response, err error) { + nonceStr := util.RandomStr(32) + param := make(map[string]string) + param["mch_appid"] = transfer.AppID + param["mchid"] = transfer.MchID + param["nonce_str"] = nonceStr + param["partner_trade_no"] = p.PartnerTradeNo + param["openid"] = p.OpenID + param["amount"] = strconv.Itoa(p.Amount) + param["desc"] = p.Desc + if p.DeviceInfo != "" { + param["device_info"] = p.DeviceInfo + } + if p.CheckName { + param["check_name"] = "FORCE_CHECK" + param["re_user_name"] = p.ReUserName + } else { + param["check_name"] = "NO_CHECK" + } + if p.SpbillCreateIP != "" { + param["spbill_create_ip"] = p.SpbillCreateIP + } + + sign, err := util.ParamSign(param, transfer.Key) + if err != nil { + return + } + + req := request{ + AppID: transfer.AppID, + MchID: transfer.MchID, + NonceStr: nonceStr, + Sign: sign, + DeviceInfo: p.DeviceInfo, + PartnerTradeNo: p.PartnerTradeNo, + OpenID: p.OpenID, + Amount: p.Amount, + Desc: p.Desc, + SpbillCreateIP: p.SpbillCreateIP, + } + if p.CheckName { + req.CheckName = "FORCE_CHECK" + req.ReUserName = p.ReUserName + } else { + req.CheckName = "NO_CHECK" + } + + rawRet, err := util.PostXMLWithTLS(walletTransferGateway, req, p.RootCa, transfer.MchID) + if err != nil { + return + } + err = xml.Unmarshal(rawRet, &rsp) + if err != nil { + return + } + if rsp.ReturnCode == "SUCCESS" { + if rsp.ResultCode == "SUCCESS" { + err = nil + return + } + err = fmt.Errorf("transfer error, errcode=%s,errmsg=%s", rsp.ErrCode, rsp.ErrCodeDes) + return + } + err = fmt.Errorf("[msg : xmlUnmarshalError] [rawReturn : %s] [sign : %s]", string(rawRet), sign) + return +}