package main
import (
"bytes"
"crypto/md5"
"crypto/tls"
"encoding/hex"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
)
var transfers = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"
var KEY = "DJ2E5nA9xjxTQlj4AAWNsF5EJQY12sPA"
//付款订单
type WithdrawOrder struct {
XMLName xml.Name `xml:"xml"`
MchAppid string `xml:"mch_appid"`
Mchid string `xml:"mchid"`
DeviceInfo string `xml:"device_info"`
NonceStr string `xml:"nonce_str"`
Sign string `xml:"sign"`
PartnerTradeNo string `xml:"partner_trade_no"`
Openid string `xml:"openid"`
CheckName string `xml:"check_name"`
Amount int `xml:"amount"`
Desc string `xml:"desc"`
SpbillCreateIp string `xml:"spbill_create_ip"`
}
//付款订单结果
type WithdrawResult struct {
ReturnCode string `xml:"return_code"`
ReturnMsg string `xml:"return_msg"`
ResultCode string `xml:"result_code"`
ErrCodeDes string `xml:"err_code_des"`
PaymentNo string `xml:"payment_no"`
PartnerTradeNo string `xml:"partner_trade_no"`
}
//付款,成功返回自定义订单号,微信订单号,true,失败返回错误信息,false
func WithdrawMoney(appid, mchid, openid, amount, partnerTradeNo, desc, clientIp string) (string, string, bool) {
order := WithdrawOrder{}
order.MchAppid = appid
order.Mchid = mchid
order.Openid = openid
order.Amount, _ = strconv.Atoi(amount)
order.Desc = desc
order.PartnerTradeNo = partnerTradeNo
order.DeviceInfo = "WEB"
order.CheckName = "NO_CHECK" //NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
order.SpbillCreateIp = clientIp
order.NonceStr = "5K8264ILTKCH16CQ2502SI8ZNMTM67VS"
//GetRandomString(32)
order.Sign = strings.ToUpper(md5WithdrawOrder(order))
xmlBody, _ := xml.MarshalIndent(order, " ", " ")
resp, err := SecurePost(transfers, xmlBody)
if err != nil {
return err.Error(), "解析文件错误", false
}
defer resp.Body.Close()
bodyByte, _ := ioutil.ReadAll(resp.Body)
var res WithdrawResult
xmlerr := xml.Unmarshal(bodyByte, &res)
if xmlerr != nil {
return xmlerr.Error(), "", false
}
if res.ReturnCode == "SUCCESS" && res.ResultCode == "SUCCESS" {
return res.PartnerTradeNo, res.PaymentNo, true
}
return res.ReturnMsg, res.ErrCodeDes, false
}
func Md5Str(str string) string {
var hashSign []byte
hash := md5.New()
hash.Write([]byte(str))
hashSign = hash.Sum(nil)
return hex.EncodeToString(hashSign)
}
//md5签名
func md5WithdrawOrder(order WithdrawOrder) string {
o := url.Values{}
o.Add("mch_appid", order.MchAppid)
o.Add("mchid", order.Mchid)
o.Add("device_info", order.DeviceInfo)
o.Add("partner_trade_no", order.PartnerTradeNo)
o.Add("check_name", order.CheckName)
o.Add("amount", strconv.Itoa(order.Amount))
o.Add("spbill_create_ip", order.SpbillCreateIp)
o.Add("desc", order.Desc)
o.Add("nonce_str", order.NonceStr)
o.Add("openid", order.Openid)
r, _ := url.QueryUnescape(o.Encode())
return Md5Str(r + "&key=" + KEY)
}
//ca证书的位置,需要绝对路径
var (
wechatCertPath = `D:/kernel/utils/WeChat/1516803781_20220721_cert/apiclient_cert.pem`
wechatKeyPath = `D:/kernel/utils/WeChat/1516803781_20220721_cert/apiclient_key.pem`
)
var _tlsConfig *tls.Config
//采用单例模式初始化ca
func getTLSConfig() (*tls.Config, error) {
if _tlsConfig != nil {
return _tlsConfig, nil
}
// load cert
cert, err := tls.LoadX509KeyPair(wechatCertPath, wechatKeyPath)
if err != nil {
return nil, err
}
_tlsConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
}
return _tlsConfig, nil
}
//携带ca证书的安全请求
func SecurePost(url string, xmlContent []byte) (*http.Response, error) {
tlsConfig, err := getTLSConfig()
if err != nil {
return nil, err
}
tr := &http.Transport{TLSClientConfig: tlsConfig}
client := &http.Client{Transport: tr}
return client.Post(
url,
"application/xml",
bytes.NewBuffer(xmlContent))
}
func main() {
mch_appid := "14412142"
mchid := "124412412"
openid := "4124412"
//v2:="4124214142"
//mchAPIv3Key:= "124412142142"
partner_trade_no := "10000098201411111234567890"
amount := "30"
desc := "3699"
clientIp := "192.168.0.1"
re, que, st := WithdrawMoney(mch_appid, mchid, openid, amount, partner_trade_no, desc, clientIp)
fmt.Println(re, "1")
fmt.Println(que, "2")
fmt.Println(st, "3")
}