github.com/chanxuehong/wechat@v0.0.0-20230222024006-36f0325263cd/mch/pay/orderquery.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 // OrderQuery 查询订单. 13 func OrderQuery(clt *core.Client, req map[string]string) (resp map[string]string, err error) { 14 return clt.PostXML(core.APIBaseURL()+"/pay/orderquery", req) 15 } 16 17 type OrderQueryRequest struct { 18 XMLName struct{} `xml:"xml" json:"-"` 19 20 // 下面这些参数至少提供一个 21 TransactionId string `xml:"transaction_id"` // 微信的订单号,优先使用 22 OutTradeNo string `xml:"out_trade_no"` // 商户系统内部的订单号,当没提供transaction_id时需要传这个。 23 24 // 可选参数 25 NonceStr string `xml:"nonce_str"` // 随机字符串,不长于32位。NOTE: 如果为空则系统会自动生成一个随机字符串。 26 SignType string `xml:"sign_type"` // 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5 27 } 28 29 type OrderQueryResponse struct { 30 XMLName struct{} `xml:"xml" json:"-"` 31 32 // 必选返回 33 TradeState string `xml:"trade_state"` // 交易状态 34 TradeStateDesc string `xml:"trade_state_desc"` // 对当前查询订单状态的描述和下一步操作的指引 35 OpenId string `xml:"openid"` // 用户在商户appid下的唯一标识 36 TransactionId string `xml:"transaction_id"` // 微信支付订单号 37 OutTradeNo string `xml:"out_trade_no"` // 商户系统的订单号,与请求一致。 38 TradeType string `xml:"trade_type"` // 调用接口提交的交易类型,取值如下:JSAPI,NATIVE,APP,MICROPAY,详细说明见参数规定 39 BankType string `xml:"bank_type"` // 银行类型,采用字符串类型的银行标识 40 TotalFee int64 `xml:"total_fee"` // 订单总金额,单位为分 41 CashFee int64 `xml:"cash_fee"` // 现金支付金额订单现金支付金额,详见支付金额 42 TimeEnd time.Time `xml:"time_end"` // 订单支付时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则 43 44 // 下面字段都是可选返回的(详细见微信支付文档), 为空值表示没有返回, 程序逻辑里需要判断 45 DeviceInfo string `xml:"device_info"` // 微信支付分配的终端设备号 46 IsSubscribe *bool `xml:"is_subscribe"` // 用户是否关注公众账号 47 SubOpenId string `xml:"sub_openid"` // 用户在子商户appid下的唯一标识 48 SubIsSubscribe *bool `xml:"sub_is_subscribe"` // 用户是否关注子公众账号 49 SettlementTotalFee *int64 `xml:"settlement_total_fee"` // 应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。 50 FeeType string `xml:"fee_type"` // 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 51 CashFeeType string `xml:"cash_fee_type"` // 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 52 Detail string `xml:"detail"` // 商品详情 53 Attach string `xml:"attach"` // 附加数据,原样返回 54 } 55 56 // OrderQuery2 查询订单. 57 // 58 // NOTE: 该函数不支持 代金券 功能, 如果有 代金券 功能请使用 OrderQuery 函数. 59 func OrderQuery2(clt *core.Client, req *OrderQueryRequest) (resp *OrderQueryResponse, err error) { 60 m1 := make(map[string]string, 8) 61 if req.TransactionId != "" { 62 m1["transaction_id"] = req.TransactionId 63 } 64 if req.OutTradeNo != "" { 65 m1["out_trade_no"] = req.OutTradeNo 66 } 67 if req.NonceStr != "" { 68 m1["nonce_str"] = req.NonceStr 69 } else { 70 m1["nonce_str"] = wechatutil.NonceStr() 71 } 72 if req.SignType != "" { 73 m1["sign_type"] = req.SignType 74 } 75 76 m2, err := OrderQuery(clt, m1) 77 if err != nil { 78 return nil, err 79 } 80 81 // 判断 trade_state 82 tradeState := m2["trade_state"] 83 if tradeState != "SUCCESS" { 84 resp = &OrderQueryResponse{ 85 TradeState: tradeState, 86 TradeStateDesc: m2["trade_state_desc"], 87 OutTradeNo: m2["out_trade_no"], 88 Attach: m2["attach"], 89 } 90 return resp, nil 91 } 92 93 resp = &OrderQueryResponse{ 94 TradeState: tradeState, 95 TradeStateDesc: m2["trade_state_desc"], 96 OpenId: m2["openid"], 97 TransactionId: m2["transaction_id"], 98 OutTradeNo: m2["out_trade_no"], 99 TradeType: m2["trade_type"], 100 BankType: m2["bank_type"], 101 DeviceInfo: m2["device_info"], 102 SubOpenId: m2["sub_openid"], 103 FeeType: m2["fee_type"], 104 CashFeeType: m2["cash_fee_type"], 105 Detail: m2["detail"], 106 Attach: m2["attach"], 107 } 108 109 // 校验返回参数 110 if req.TransactionId != "" && resp.TransactionId != "" && req.TransactionId != resp.TransactionId { 111 err = fmt.Errorf("transaction_id mismatch, have: %s, want: %s", resp.TransactionId, req.TransactionId) 112 return nil, err 113 } 114 if req.OutTradeNo != "" && resp.OutTradeNo != "" && req.OutTradeNo != resp.OutTradeNo { 115 err = fmt.Errorf("out_trade_no mismatch, have: %s, want: %s", resp.OutTradeNo, req.OutTradeNo) 116 return nil, err 117 } 118 119 if str := m2["total_fee"]; str != "" { 120 if n, err := strconv.ParseInt(str, 10, 64); err != nil { 121 err = fmt.Errorf("parse total_fee:%q to int64 failed: %s", str, err.Error()) 122 return nil, err 123 } else { 124 resp.TotalFee = n 125 } 126 } 127 if str := m2["cash_fee"]; str != "" { 128 if n, err := strconv.ParseInt(str, 10, 64); err != nil { 129 err = fmt.Errorf("parse cash_fee:%q to int64 failed: %s", str, err.Error()) 130 return nil, err 131 } else { 132 resp.CashFee = n 133 } 134 } 135 if str := m2["time_end"]; str != "" { 136 if t, err := core.ParseTime(str); err != nil { 137 err = fmt.Errorf("parse time_end:%q to time.Time failed: %s", str, err.Error()) 138 return nil, err 139 } else { 140 resp.TimeEnd = t 141 } 142 } 143 144 if str := m2["is_subscribe"]; str != "" { 145 if str == "Y" || str == "y" { 146 resp.IsSubscribe = wechatutil.Bool(true) 147 } else { 148 resp.IsSubscribe = wechatutil.Bool(false) 149 } 150 } 151 if str := m2["sub_is_subscribe"]; str != "" { 152 if str == "Y" || str == "y" { 153 resp.SubIsSubscribe = wechatutil.Bool(true) 154 } else { 155 resp.SubIsSubscribe = wechatutil.Bool(false) 156 } 157 } 158 if str := m2["settlement_total_fee"]; str != "" { 159 if n, err := strconv.ParseInt(str, 10, 64); err != nil { 160 err = fmt.Errorf("parse settlement_total_fee:%q to int64 failed: %s", str, err.Error()) 161 return nil, err 162 } else { 163 resp.SettlementTotalFee = wechatutil.Int64(n) 164 } 165 } 166 return resp, nil 167 }