forked from golang/hotime
183 lines
6.9 KiB
Go
183 lines
6.9 KiB
Go
package pay
|
||
|
||
import (
|
||
"fmt"
|
||
"strconv"
|
||
"time"
|
||
|
||
"gopkg.in/chanxuehong/wechat.v2/mch/core"
|
||
wechatutil "gopkg.in/chanxuehong/wechat.v2/util"
|
||
)
|
||
|
||
// RefundQuery 查询退款.
|
||
func RefundQuery(clt *core.Client, req map[string]string) (resp map[string]string, err error) {
|
||
return clt.PostXML(core.APIBaseURL()+"/pay/refundquery", req)
|
||
}
|
||
|
||
type RefundQueryRequest struct {
|
||
XMLName struct{} `xml:"xml" json:"-"`
|
||
|
||
// 必选参数, 四选一
|
||
TransactionId string `xml:"transaction_id"` // 微信订单号
|
||
OutTradeNo string `xml:"out_trade_no"` // 商户订单号
|
||
OutRefundNo string `xml:"out_refund_no"` // 商户退款单号
|
||
RefundId string `xml:"refund_id"` // 微信退款单号
|
||
|
||
// 可选参数
|
||
NonceStr string `xml:"nonce_str"` // 随机字符串,不长于32位。NOTE: 如果为空则系统会自动生成一个随机字符串。
|
||
SignType string `xml:"sign_type"` // 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
|
||
}
|
||
|
||
type RefundQueryResponse struct {
|
||
XMLName struct{} `xml:"xml" json:"-"`
|
||
|
||
// 必选返回
|
||
TransactionId string `xml:"transaction_id"` // 微信订单号
|
||
OutTradeNo string `xml:"out_trade_no"` // 商户系统内部的订单号
|
||
TotalFee int64 `xml:"total_fee"` // 订单总金额,单位为分,只能为整数,详见支付金额
|
||
CashFee int64 `xml:"cash_fee"` // 现金支付金额,单位为分,只能为整数,详见支付金额
|
||
RefundCount int `xml:"refund_count"` // 退款笔数
|
||
RefundList []RefundItem `xml:"refund_list"` // 退款列表
|
||
|
||
// 下面字段都是可选返回的(详细见微信支付文档), 为空值表示没有返回, 程序逻辑里需要判断
|
||
SettlementTotalFee *int64 `xml:"settlement_total_fee"` // 应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。
|
||
FeeType string `xml:"fee_type"` // 订单金额货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
|
||
CashFeeType string `xml:"cash_fee_type"` // 现金支付货币类型
|
||
}
|
||
|
||
type RefundItem struct {
|
||
XMLName struct{} `xml:"xml" json:"-"`
|
||
|
||
// 必选返回
|
||
OutRefundNo string `xml:"out_refund_no"` // 商户退款单号
|
||
RefundId string `xml:"refund_id"` // 微信退款单号
|
||
RefundFee int64 `xml:"refund_fee"` // 申请退款金额
|
||
RefundStatus string `xml:"refund_status"` // 退款状态
|
||
RefundRecvAccout string `xml:"refund_recv_accout"` // 退款入账账户
|
||
|
||
// 下面字段都是可选返回的(详细见微信支付文档), 为空值表示没有返回, 程序逻辑里需要判断
|
||
RefundChannel string `xml:"refund_channel"` // 退款渠道
|
||
SettlementRefundFee *int64 `xml:"settlement_refund_fee"` // 退款金额
|
||
RefundAccount string `xml:"refund_account"` // 退款资金来源
|
||
RefundSuccessTime time.Time `xml:"refund_success_time"` // 退款成功时间
|
||
}
|
||
|
||
// RefundQuery2 查询退款.
|
||
// NOTE: 该函数不支持 代金券 功能, 如果有 代金券 功能请使用 RefundQuery 函数.
|
||
func RefundQuery2(clt *core.Client, req *RefundQueryRequest) (resp *RefundQueryResponse, err error) {
|
||
m1 := make(map[string]string, 16)
|
||
if req.TransactionId != "" {
|
||
m1["transaction_id"] = req.TransactionId
|
||
}
|
||
if req.OutTradeNo != "" {
|
||
m1["out_trade_no"] = req.OutTradeNo
|
||
}
|
||
if req.OutRefundNo != "" {
|
||
m1["out_refund_no"] = req.OutRefundNo
|
||
}
|
||
if req.RefundId != "" {
|
||
m1["refund_id"] = req.RefundId
|
||
}
|
||
if req.NonceStr != "" {
|
||
m1["nonce_str"] = req.NonceStr
|
||
} else {
|
||
m1["nonce_str"] = wechatutil.NonceStr()
|
||
}
|
||
if req.SignType != "" {
|
||
m1["sign_type"] = req.SignType
|
||
}
|
||
|
||
m2, err := RefundQuery(clt, m1)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
resp = &RefundQueryResponse{
|
||
TransactionId: m2["transaction_id"],
|
||
OutTradeNo: m2["out_trade_no"],
|
||
FeeType: m2["fee_type"],
|
||
CashFeeType: m2["cash_fee_type"],
|
||
}
|
||
|
||
if str := m2["total_fee"]; str != "" {
|
||
if n, err := strconv.ParseInt(str, 10, 64); err != nil {
|
||
err = fmt.Errorf("parse total_fee:%q to int64 failed: %s", str, err.Error())
|
||
return nil, err
|
||
} else {
|
||
resp.TotalFee = n
|
||
}
|
||
}
|
||
if str := m2["cash_fee"]; str != "" {
|
||
if n, err := strconv.ParseInt(str, 10, 64); err != nil {
|
||
err = fmt.Errorf("parse cash_fee:%q to int64 failed: %s", str, err.Error())
|
||
return nil, err
|
||
} else {
|
||
resp.CashFee = n
|
||
}
|
||
}
|
||
if str := m2["refund_count"]; str != "" {
|
||
if n, err := strconv.ParseInt(str, 10, 64); err != nil {
|
||
err = fmt.Errorf("parse refund_count:%q to int64 failed: %s", str, err.Error())
|
||
return nil, err
|
||
} else {
|
||
resp.RefundCount = int(n)
|
||
}
|
||
}
|
||
if str := m2["settlement_total_fee"]; str != "" {
|
||
if n, err := strconv.ParseInt(str, 10, 64); err != nil {
|
||
err = fmt.Errorf("parse settlement_total_fee:%q to int64 failed: %s", str, err.Error())
|
||
return nil, err
|
||
} else {
|
||
resp.SettlementTotalFee = wechatutil.Int64(n)
|
||
}
|
||
}
|
||
|
||
resp.RefundList = make([]RefundItem, resp.RefundCount)
|
||
for i := 0; i < resp.RefundCount; i++ {
|
||
resp.RefundList[i].OutRefundNo = m2["out_refund_no_"+strconv.Itoa(i)]
|
||
resp.RefundList[i].RefundId = m2["refund_id_"+strconv.Itoa(i)]
|
||
resp.RefundList[i].RefundStatus = m2["refund_status_"+strconv.Itoa(i)]
|
||
resp.RefundList[i].RefundRecvAccout = m2["refund_recv_accout_"+strconv.Itoa(i)]
|
||
resp.RefundList[i].RefundChannel = m2["refund_channel_"+strconv.Itoa(i)]
|
||
resp.RefundList[i].RefundAccount = m2["refund_account_"+strconv.Itoa(i)]
|
||
|
||
if str := m2["refund_fee_"+strconv.Itoa(i)]; str != "" {
|
||
if n, err := strconv.ParseInt(str, 10, 64); err != nil {
|
||
err = fmt.Errorf("parse refund_fee_%d:%q to int64 failed: %s", i, str, err.Error())
|
||
return nil, err
|
||
} else {
|
||
resp.RefundList[i].RefundFee = n
|
||
}
|
||
}
|
||
if str := m2["settlement_refund_fee_"+strconv.Itoa(i)]; str != "" {
|
||
if n, err := strconv.ParseInt(str, 10, 64); err != nil {
|
||
err = fmt.Errorf("parse settlement_refund_fee_%d:%q to int64 failed: %s", i, str, err.Error())
|
||
return nil, err
|
||
} else {
|
||
resp.RefundList[i].SettlementRefundFee = wechatutil.Int64(n)
|
||
}
|
||
}
|
||
if str := m2["refund_success_time_"+strconv.Itoa(i)]; str != "" {
|
||
// 2016-07-25 15:26:26
|
||
if t, err := time.ParseInLocation("2006-01-02 15:04:05", str, wechatutil.BeijingLocation); err != nil {
|
||
err = fmt.Errorf("parse refund_success_time_%d:%q to time.Time failed: %s", i, str, err.Error())
|
||
return nil, err
|
||
} else {
|
||
resp.RefundList[i].RefundSuccessTime = t
|
||
}
|
||
}
|
||
}
|
||
|
||
// 校验返回参数
|
||
if req.TransactionId != "" && resp.TransactionId != "" && req.TransactionId != resp.TransactionId {
|
||
err = fmt.Errorf("transaction_id mismatch, have: %s, want: %s", resp.TransactionId, req.TransactionId)
|
||
return nil, err
|
||
}
|
||
if req.OutTradeNo != "" && resp.OutTradeNo != "" && req.OutTradeNo != resp.OutTradeNo {
|
||
err = fmt.Errorf("out_trade_no mismatch, have: %s, want: %s", resp.OutTradeNo, req.OutTradeNo)
|
||
return nil, err
|
||
}
|
||
|
||
return resp, nil
|
||
}
|