github.com/chanxuehong/wechat@v0.0.0-20230222024006-36f0325263cd/mch/pay/refundquery.go (about) 1 package pay 2 3 import ( 4 "fmt" 5 "strconv" 6 "time" 7 8 "github.com/chanxuehong/wechat/mch/core" 9 wechatutil "github.com/chanxuehong/wechat/util" 10 ) 11 12 // RefundQuery 查询退款. 13 func RefundQuery(clt *core.Client, req map[string]string) (resp map[string]string, err error) { 14 return clt.PostXML(core.APIBaseURL()+"/pay/refundquery", req) 15 } 16 17 type RefundQueryRequest struct { 18 XMLName struct{} `xml:"xml" json:"-"` 19 20 // 必选参数, 四选一 21 TransactionId string `xml:"transaction_id"` // 微信订单号 22 OutTradeNo string `xml:"out_trade_no"` // 商户订单号 23 OutRefundNo string `xml:"out_refund_no"` // 商户退款单号 24 RefundId string `xml:"refund_id"` // 微信退款单号 25 26 // 可选参数 27 NonceStr string `xml:"nonce_str"` // 随机字符串,不长于32位。NOTE: 如果为空则系统会自动生成一个随机字符串。 28 SignType string `xml:"sign_type"` // 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5 29 } 30 31 type RefundQueryResponse struct { 32 XMLName struct{} `xml:"xml" json:"-"` 33 34 // 必选返回 35 TransactionId string `xml:"transaction_id"` // 微信订单号 36 OutTradeNo string `xml:"out_trade_no"` // 商户系统内部的订单号 37 TotalFee int64 `xml:"total_fee"` // 订单总金额,单位为分,只能为整数,详见支付金额 38 CashFee int64 `xml:"cash_fee"` // 现金支付金额,单位为分,只能为整数,详见支付金额 39 RefundCount int `xml:"refund_count"` // 退款笔数 40 RefundList []RefundItem `xml:"refund_list"` // 退款列表 41 42 // 下面字段都是可选返回的(详细见微信支付文档), 为空值表示没有返回, 程序逻辑里需要判断 43 SettlementTotalFee *int64 `xml:"settlement_total_fee"` // 应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。 44 FeeType string `xml:"fee_type"` // 订单金额货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 45 CashFeeType string `xml:"cash_fee_type"` // 现金支付货币类型 46 } 47 48 type RefundItem struct { 49 XMLName struct{} `xml:"xml" json:"-"` 50 51 // 必选返回 52 OutRefundNo string `xml:"out_refund_no"` // 商户退款单号 53 RefundId string `xml:"refund_id"` // 微信退款单号 54 RefundFee int64 `xml:"refund_fee"` // 申请退款金额 55 RefundStatus string `xml:"refund_status"` // 退款状态 56 RefundRecvAccout string `xml:"refund_recv_accout"` // 退款入账账户 57 58 // 下面字段都是可选返回的(详细见微信支付文档), 为空值表示没有返回, 程序逻辑里需要判断 59 RefundChannel string `xml:"refund_channel"` // 退款渠道 60 SettlementRefundFee *int64 `xml:"settlement_refund_fee"` // 退款金额 61 RefundAccount string `xml:"refund_account"` // 退款资金来源 62 RefundSuccessTime time.Time `xml:"refund_success_time"` // 退款成功时间 63 } 64 65 // RefundQuery2 查询退款. 66 // 67 // NOTE: 该函数不支持 代金券 功能, 如果有 代金券 功能请使用 RefundQuery 函数. 68 func RefundQuery2(clt *core.Client, req *RefundQueryRequest) (resp *RefundQueryResponse, err error) { 69 m1 := make(map[string]string, 16) 70 if req.TransactionId != "" { 71 m1["transaction_id"] = req.TransactionId 72 } 73 if req.OutTradeNo != "" { 74 m1["out_trade_no"] = req.OutTradeNo 75 } 76 if req.OutRefundNo != "" { 77 m1["out_refund_no"] = req.OutRefundNo 78 } 79 if req.RefundId != "" { 80 m1["refund_id"] = req.RefundId 81 } 82 if req.NonceStr != "" { 83 m1["nonce_str"] = req.NonceStr 84 } else { 85 m1["nonce_str"] = wechatutil.NonceStr() 86 } 87 if req.SignType != "" { 88 m1["sign_type"] = req.SignType 89 } 90 91 m2, err := RefundQuery(clt, m1) 92 if err != nil { 93 return nil, err 94 } 95 96 resp = &RefundQueryResponse{ 97 TransactionId: m2["transaction_id"], 98 OutTradeNo: m2["out_trade_no"], 99 FeeType: m2["fee_type"], 100 CashFeeType: m2["cash_fee_type"], 101 } 102 103 if str := m2["total_fee"]; str != "" { 104 if n, err := strconv.ParseInt(str, 10, 64); err != nil { 105 err = fmt.Errorf("parse total_fee:%q to int64 failed: %s", str, err.Error()) 106 return nil, err 107 } else { 108 resp.TotalFee = n 109 } 110 } 111 if str := m2["cash_fee"]; str != "" { 112 if n, err := strconv.ParseInt(str, 10, 64); err != nil { 113 err = fmt.Errorf("parse cash_fee:%q to int64 failed: %s", str, err.Error()) 114 return nil, err 115 } else { 116 resp.CashFee = n 117 } 118 } 119 if str := m2["refund_count"]; str != "" { 120 if n, err := strconv.ParseInt(str, 10, 64); err != nil { 121 err = fmt.Errorf("parse refund_count:%q to int64 failed: %s", str, err.Error()) 122 return nil, err 123 } else { 124 resp.RefundCount = int(n) 125 } 126 } 127 if str := m2["settlement_total_fee"]; str != "" { 128 if n, err := strconv.ParseInt(str, 10, 64); err != nil { 129 err = fmt.Errorf("parse settlement_total_fee:%q to int64 failed: %s", str, err.Error()) 130 return nil, err 131 } else { 132 resp.SettlementTotalFee = wechatutil.Int64(n) 133 } 134 } 135 136 resp.RefundList = make([]RefundItem, resp.RefundCount) 137 for i := 0; i < resp.RefundCount; i++ { 138 resp.RefundList[i].OutRefundNo = m2["out_refund_no_"+strconv.Itoa(i)] 139 resp.RefundList[i].RefundId = m2["refund_id_"+strconv.Itoa(i)] 140 resp.RefundList[i].RefundStatus = m2["refund_status_"+strconv.Itoa(i)] 141 resp.RefundList[i].RefundRecvAccout = m2["refund_recv_accout_"+strconv.Itoa(i)] 142 resp.RefundList[i].RefundChannel = m2["refund_channel_"+strconv.Itoa(i)] 143 resp.RefundList[i].RefundAccount = m2["refund_account_"+strconv.Itoa(i)] 144 145 if str := m2["refund_fee_"+strconv.Itoa(i)]; str != "" { 146 if n, err := strconv.ParseInt(str, 10, 64); err != nil { 147 err = fmt.Errorf("parse refund_fee_%d:%q to int64 failed: %s", i, str, err.Error()) 148 return nil, err 149 } else { 150 resp.RefundList[i].RefundFee = n 151 } 152 } 153 if str := m2["settlement_refund_fee_"+strconv.Itoa(i)]; str != "" { 154 if n, err := strconv.ParseInt(str, 10, 64); err != nil { 155 err = fmt.Errorf("parse settlement_refund_fee_%d:%q to int64 failed: %s", i, str, err.Error()) 156 return nil, err 157 } else { 158 resp.RefundList[i].SettlementRefundFee = wechatutil.Int64(n) 159 } 160 } 161 if str := m2["refund_success_time_"+strconv.Itoa(i)]; str != "" { 162 // 2016-07-25 15:26:26 163 if t, err := time.ParseInLocation("2006-01-02 15:04:05", str, wechatutil.BeijingLocation); err != nil { 164 err = fmt.Errorf("parse refund_success_time_%d:%q to time.Time failed: %s", i, str, err.Error()) 165 return nil, err 166 } else { 167 resp.RefundList[i].RefundSuccessTime = t 168 } 169 } 170 } 171 172 // 校验返回参数 173 if req.TransactionId != "" && resp.TransactionId != "" && req.TransactionId != resp.TransactionId { 174 err = fmt.Errorf("transaction_id mismatch, have: %s, want: %s", resp.TransactionId, req.TransactionId) 175 return nil, err 176 } 177 if req.OutTradeNo != "" && resp.OutTradeNo != "" && req.OutTradeNo != resp.OutTradeNo { 178 err = fmt.Errorf("out_trade_no mismatch, have: %s, want: %s", resp.OutTradeNo, req.OutTradeNo) 179 return nil, err 180 } 181 182 return resp, nil 183 }