iedc-go/vendor/gopkg.in/chanxuehong/wechat.v2/mch/pay/micropay.go
2023-03-03 03:12:15 +08:00

187 lines
7.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package pay
import (
"fmt"
"strconv"
"time"
"gopkg.in/chanxuehong/wechat.v2/mch/core"
"gopkg.in/chanxuehong/wechat.v2/util"
)
// MicroPay 提交刷卡支付.
func MicroPay(clt *core.Client, req map[string]string) (resp map[string]string, err error) {
return clt.PostXML(core.APIBaseURL()+"/pay/micropay", req)
}
type MicroPayRequest struct {
XMLName struct{} `xml:"xml" json:"-"`
// 必选参数
Body string `xml:"body"` // 商品或支付单简要描述
OutTradeNo string `xml:"out_trade_no"` // 商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
TotalFee int64 `xml:"total_fee"` // 订单总金额,单位为分,详见支付金额
SpbillCreateIP string `xml:"spbill_create_ip"` // APP和网页支付提交用户端ipNative支付填调用微信支付API的机器IP。
AuthCode string `xml:"auth_code"` // 扫码支付授权码,设备读取用户微信中的条码或者二维码信息
// 可选参数
DeviceInfo string `xml:"device_info"` // 终端设备号(门店号或收银设备ID)注意PC网页或公众号内支付请传"WEB"
NonceStr string `xml:"nonce_str"` // 随机字符串不长于32位。NOTE: 如果为空则系统会自动生成一个随机字符串。
SignType string `xml:"sign_type"` // 签名类型默认为MD5支持HMAC-SHA256和MD5。
Detail string `xml:"detail"` // 商品名称明细列表
Attach string `xml:"attach"` // 附加数据在查询API和支付通知中原样返回该字段主要用于商户携带订单的自定义数据
FeeType string `xml:"fee_type"` // 符合ISO 4217标准的三位字母代码默认人民币CNY其他值列表详见货币类型
GoodsTag string `xml:"goods_tag"` // 商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠
LimitPay string `xml:"limit_pay"` // no_credit--指定不能使用信用卡支付
SceneInfo string `xml:"scene_info"` // 场景信息
}
type MicroPayResponse struct {
XMLName struct{} `xml:"xml" json:"-"`
// 必选返回
OpenId string `xml:"openid"` // 用户在商户appid下的唯一标识
IsSubscribe bool `xml:"is_subscribe"` // 用户是否关注公众账号
TradeType string `xml:"trade_type"` // 调用接口提交的交易类型取值如下JSAPINATIVEAPPMICROPAY详细说明见参数规定
BankType string `xml:"bank_type"` // 银行类型,采用字符串类型的银行标识
TotalFee int64 `xml:"total_fee"` // 订单总金额,单位为分
CashFee int64 `xml:"cash_fee"` // 现金支付金额订单现金支付金额,详见支付金额
TransactionId string `xml:"transaction_id"` // 微信支付订单号
OutTradeNo string `xml:"out_trade_no"` // 商户系统的订单号,与请求一致。
TimeEnd time.Time `xml:"time_end"` // 订单支付时间格式为yyyyMMddHHmmss如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
// 下面字段都是可选返回的(详细见微信支付文档), 为空值表示没有返回, 程序逻辑里需要判断
DeviceInfo string `xml:"device_info"` // 微信支付分配的终端设备号
SubOpenId string `xml:"sub_openid"` // 子商户appid下用户唯一标识如需返回则请求时需要传sub_appid
SubIsSubscribe *bool `xml:"sub_is_subscribe"` // 用户是否关注子公众账号仅在公众账号类型支付有效取值范围Y或N;Y-关注;N-未关注
FeeType string `xml:"fee_type"` // 货币类型符合ISO 4217标准的三位字母代码默认人民币CNY其他值列表详见货币类型
SettlementTotalFee *int64 `xml:"settlement_total_fee"` // 应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。
CouponFee *int64 `xml:"coupon_fee"` // 代金券金额
CashFeeType string `xml:"cash_fee_type"` // 货币类型符合ISO 4217标准的三位字母代码默认人民币CNY其他值列表详见货币类型
Attach string `xml:"attach"` // 附加数据,原样返回
PromotionDetail string `xml:"promotion_detail"` // 营销详情
}
// MicroPay2 提交刷卡支付.
func MicroPay2(clt *core.Client, req *MicroPayRequest) (resp *MicroPayResponse, err error) {
m1 := make(map[string]string, 24)
m1["body"] = req.Body
m1["out_trade_no"] = req.OutTradeNo
m1["total_fee"] = strconv.FormatInt(req.TotalFee, 10)
m1["spbill_create_ip"] = req.SpbillCreateIP
m1["auth_code"] = req.AuthCode
if req.DeviceInfo != "" {
m1["device_info"] = req.DeviceInfo
}
if req.NonceStr != "" {
m1["nonce_str"] = req.NonceStr
} else {
m1["nonce_str"] = util.NonceStr()
}
if req.SignType != "" {
m1["sign_type"] = req.SignType
}
if req.Detail != "" {
m1["detail"] = req.Detail
}
if req.Attach != "" {
m1["attach"] = req.Attach
}
if req.FeeType != "" {
m1["fee_type"] = req.FeeType
}
if req.GoodsTag != "" {
m1["goods_tag"] = req.GoodsTag
}
if req.LimitPay != "" {
m1["limit_pay"] = req.LimitPay
}
if req.SceneInfo != "" {
m1["scene_info"] = req.SceneInfo
}
m2, err := MicroPay(clt, m1)
if err != nil {
return nil, err
}
resp = &MicroPayResponse{
OpenId: m2["openid"],
TradeType: m2["trade_type"],
BankType: m2["bank_type"],
TransactionId: m2["transaction_id"],
OutTradeNo: m2["out_trade_no"],
DeviceInfo: m2["device_info"],
SubOpenId: m2["sub_openid"],
FeeType: m2["fee_type"],
CashFeeType: m2["cash_fee_type"],
Attach: m2["attach"],
PromotionDetail: m2["promotion_detail"],
}
if str := m2["is_subscribe"]; str != "" {
if str == "Y" || str == "y" {
resp.IsSubscribe = true
}
}
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["time_end"]; str != "" {
if t, err := core.ParseTime(str); err != nil {
err = fmt.Errorf("parse time_end:%q to time.Time failed: %s", str, err.Error())
return nil, err
} else {
resp.TimeEnd = t
}
}
if str := m2["sub_is_subscribe"]; str != "" {
if str == "Y" || str == "y" {
resp.SubIsSubscribe = util.Bool(true)
} else {
resp.SubIsSubscribe = util.Bool(false)
}
}
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 = util.Int64(n)
}
}
if str := m2["coupon_fee"]; str != "" {
if n, err := strconv.ParseInt(str, 10, 64); err != nil {
err = fmt.Errorf("parse coupon_fee:%q to int64 failed: %s", str, err.Error())
return nil, err
} else {
resp.CouponFee = util.Int64(n)
}
}
// 校验返回参数
if req.OutTradeNo != resp.OutTradeNo {
err = fmt.Errorf("out_trade_no mismatch, have: %s, want: %s", resp.OutTradeNo, req.OutTradeNo)
return nil, err
}
if req.TotalFee != resp.TotalFee {
err = fmt.Errorf("total_fee mismatch, have: %d, want: %d", resp.TotalFee, req.TotalFee)
return nil, err
}
return resp, nil
}