├── constant
└── pay.go
├── util
├── xml.go
└── util.go
├── pay_test.go
├── pay.go
├── common
├── common.go
├── wechat.go
└── alipay.go
├── README.md
├── client
├── http.go
├── aliapp.go
├── wechatapp.go
├── aliweb.go
└── wechatweb.go
└── callback.go
/constant/pay.go:
--------------------------------------------------------------------------------
1 | package constant
2 |
3 | const (
4 | ALI_WEB = iota + 1
5 | ALI_APP
6 | WECHAT
7 | )
8 |
--------------------------------------------------------------------------------
/util/xml.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "bytes"
5 | "encoding/xml"
6 | "io"
7 | "strings"
8 | )
9 |
10 | func XmlToMap(xmlData []byte) (map[string]string, error) {
11 | decoder := xml.NewDecoder(bytes.NewReader(xmlData))
12 | m := make(map[string]string)
13 | var token xml.Token
14 | var err error
15 | var k string
16 | for token, err = decoder.Token(); err == nil; token, err = decoder.Token() {
17 | if v, ok := token.(xml.StartElement); ok {
18 | k = v.Name.Local
19 | continue
20 | }
21 | if v, ok := token.(xml.CharData); ok {
22 | data := string(v.Copy())
23 | if strings.TrimSpace(data) == "" {
24 | continue
25 | }
26 | m[k] = data
27 | }
28 | }
29 |
30 | if err != nil && err != io.EOF {
31 | return nil, err
32 | }
33 | return m, nil
34 | }
35 |
--------------------------------------------------------------------------------
/util/util.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "net"
7 | "time"
8 | )
9 |
10 | //RandomStr 获取一个随机字符串
11 | func RandomStr() string {
12 | return fmt.Sprintf("%d", time.Now().UnixNano())
13 | }
14 |
15 | // LocalIP 获取机器的IP
16 | func LocalIP() string {
17 | info, _ := net.InterfaceAddrs()
18 | for _, addr := range info {
19 | ipNet, ok := addr.(*net.IPNet)
20 | if !ok {
21 | continue
22 | }
23 | if !ipNet.IP.IsLoopback() && ipNet.IP.To4() != nil {
24 | return ipNet.IP.String()
25 | }
26 | }
27 | return ""
28 | }
29 |
30 | func MapStringToStruct(m map[string]string, i interface{}) error {
31 | bin, err := json.Marshal(m)
32 | if err != nil {
33 | return err
34 | }
35 | err = json.Unmarshal(bin, i)
36 | if err != nil {
37 | return err
38 | }
39 | return nil
40 | }
41 |
--------------------------------------------------------------------------------
/pay_test.go:
--------------------------------------------------------------------------------
1 | package pays_with_go
2 |
3 | import (
4 | "fmt"
5 | "./client"
6 | "./common"
7 | "./constant"
8 | "net/http"
9 | "testing"
10 | )
11 |
12 | //测试
13 | func TestPay(t *testing.T) {
14 | initClient()
15 | initHandle()
16 | charge := new(common.Charge)
17 | charge.PayMethod = constant.WECHAT
18 | charge.MoneyFee = 1
19 | charge.Describe = "测试订单"
20 | charge.TradeNum = "8888888888"
21 |
22 | fdata, err := do(charge)
23 | if err != nil {
24 | t.Error(err)
25 | }
26 | fmt.Println(fdata)
27 | }
28 |
29 | //初始化客户端
30 | func initClient() {
31 | client.InitAliAppClient(&client.AliAppClient{
32 | PartnerID: "xxx",
33 | SellerID: "xxxx",
34 | AppID: "xxx",
35 | PrivateKey: nil,
36 | PublicKey: nil,
37 | })
38 | }
39 |
40 | //初始化处理
41 | func initHandle() {
42 | http.HandleFunc("callback/aliappcallback", func(w http.ResponseWriter, r *http.Request) {
43 | aliResult, err := AliAppCallback(w, r)
44 | if err != nil {
45 | fmt.Println(err)
46 | //log.xxx
47 | return
48 | }
49 | selfHandler(aliResult)
50 | })
51 | }
52 |
53 | func selfHandler(i interface{}) {
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/pay.go:
--------------------------------------------------------------------------------
1 | package pays_with_go
2 |
3 | import (
4 | "errors"
5 | "./client"
6 | "./common"
7 | "./constant"
8 | "strconv"
9 | )
10 | //pay
11 | func do(charge *common.Charge) (string, error) {
12 | err := checkCharge(charge)
13 | if err != nil {
14 | //log.Error(err, charge)
15 | return "", err
16 | }
17 |
18 | ct := getPayClient(charge.PayMethod)
19 | re, err := ct.Pay(charge)
20 | if err != nil {
21 | //log.Error("支付失败:", err, charge)
22 | return "", err
23 | }
24 | return re, err
25 | }
26 |
27 | func checkCharge(charge *common.Charge) error {
28 | var id uint64
29 | var err error
30 | if charge.UserID == "" {
31 | id = 0
32 | } else {
33 | id, err = strconv.ParseUint(charge.UserID, 10, -1)
34 | if err != nil {
35 | return err
36 | }
37 | }
38 | if id < 0 {
39 | return errors.New("userID less than 0")
40 | }
41 | if charge.PayMethod < 0 {
42 | return errors.New("payMethod less than 0")
43 | }
44 | if charge.MoneyFee < 0 {
45 | return errors.New("totalFee less than 0")
46 | }
47 |
48 | if charge.CallbackURL == "" {
49 | return errors.New("callbackURL is NULL")
50 | }
51 | return nil
52 | }
53 |
54 | // getPayClient 得到需要支付的客户端
55 |
56 | func getPayClient(payMethod int64) common.PayClient {
57 | //如果使用余额支付
58 | switch payMethod {
59 | case constant.ALI_WEB:
60 | return client.DefaultAliWebClient()
61 | case constant.ALI_APP:
62 | return client.DefaultAliAppClient()
63 | case constant.WECHAT:
64 | return client.DefaultWechatAppClient()
65 | }
66 | return nil
67 | }
68 |
--------------------------------------------------------------------------------
/common/common.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import ()
4 |
5 | // PayClient 支付客户端接口
6 | type PayClient interface {
7 | Pay(charge *Charge) (string, error)
8 | //检查签名
9 | //CheckSign(data []byte, sign []byte) error
10 | }
11 |
12 | // Charge 支付参数
13 | type Charge struct {
14 | TradeNum string `json:"tradeNum,omitempty"`
15 | Origin string `json:"origin,omitempty"`
16 | UserID string `json:"userId,omitempty"`
17 | PayMethod int64 `json:"payMethod,omitempty"`
18 | MoneyFee int64 `json:"MoneyFee,omitempty"`
19 | CallbackURL string `json:"callbackURL,omitempty"`
20 | ReturnURL string `json:"returnURL,omitempty"`
21 | ShowURL string `json:"showURL,omitempty"`
22 | Describe string `json:"describe,omitempty"`
23 | OpenID string `json:"openid,omitempty"`
24 | }
25 |
26 | //PayCallback 支付返回
27 | type PayCallback struct {
28 | Origin string `json:"origin"`
29 | TradeNum string `json:"trade_num"`
30 | OrderNum string `json:"order_num"`
31 | CallBackURL string `json:"callback_url"`
32 | Status int64 `json:"status"`
33 | }
34 |
35 | // CallbackReturn 回调业务代码时的参数
36 | type CallbackReturn struct {
37 | IsSucceed bool `json:"isSucceed"`
38 | OrderNum string `json:"orderNum"`
39 | TradeNum string `json:"tradeNum"`
40 | UserID string `json:"userID"`
41 | MoneyFee int64 `json:"moneyFee"`
42 | Sign string `json:"sign"`
43 | ThirdDiscount int64 `json:"thirdDiscount"`
44 | }
45 |
46 | // BaseResult 支付结果
47 | type BaseResult struct {
48 | IsSucceed bool // 是否交易成功
49 | TradeNum string // 交易流水号
50 | MoneyFee int64 // 支付金额
51 | TradeTime string // 交易时间
52 | ContractNum string // 交易单号
53 | UserInfo string // 支付账号信息(有可能有,有可能没有)
54 | ThirdDiscount int64 // 第三方优惠
55 | }
56 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # golang支付合集(包括微信支付,支付宝,后期会加入聚合支付)
2 |
3 | * golang支付库
4 | 想必gopher们都会抱怨go成熟的包太少,特别是go语言支付这块,网上的代码基本没有能用的,要么不全,要么有硬伤,所以结合网上和自己经验,抽出时间写的一部分代码,封装下分享出来,希望能给大家一点借鉴意义。
5 | * 支持的支付方式
6 | 目前支持微信app,支付宝网页版,支付宝app。要是谁有新的支付方式也可以合并。
7 |
8 | * 项目开源协议:[GPL v3](https://opensource.org/licenses/GPL-3.0)
9 |
10 | * 使用方法
11 |
12 | * #####1. git clone https://github.com/shirdonliao/pays_with_go.git 或者 go get github.com/shirdonliao/pays_with_go
13 |
14 | * #####2. 在自己的项目里调用,示例代码如下,确保填入自己的配置参数,开发中有问题欢迎留言或者关注公众号:codebigdata
15 |
16 | ```javascript
17 | package main
18 |
19 | import (
20 | "fmt"
21 | "github.com/shirdonliao/pays_with_go"
22 | "github.com/shirdonliao/pays_with_go/client"
23 | "github.com/shirdonliao/pays_with_go/common"
24 | "github.com/shirdonliao/pays_with_go/constant"
25 | "net/http"
26 | )
27 | func main() {
28 | //设置支付宝账号信息
29 | initClient()
30 | //设置回调函数
31 | initHandle()
32 |
33 | //支付
34 | charge := new(common.Charge)
35 | charge.PayMethod = constant.WECHAT //支付方式
36 | charge.MoneyFee = 1 // 支付钱单位分
37 | charge.Describe = "测试订单" //支付描述
38 | charge.TradeNum = "88888888" //交易号
39 | charge.CallbackURL = "http://127.0.0.1/callback/aliappcallback" //回调地址必须跟下面一样
40 |
41 | fdata, err := gopay.Pay(charge)
42 | if err != nil {
43 | fmt.Println(err)
44 | return
45 | }
46 | fmt.Println(fdata)
47 | }
48 |
49 | //
50 | func initClient() {
51 | client.InitAliAppClient(&client.AliAppClient{
52 | PartnerID: "xxx",
53 | SellerID: "xxxx",
54 | AppID: "xxx",
55 | PrivateKey: nil,
56 | PublicKey: nil,
57 | })
58 | }
59 |
60 |
61 | func initHandle() {
62 | http.HandleFunc("callback/aliappcallback", func(w http.ResponseWriter, r *http.Request) {
63 | //返回支付结果
64 | aliResult, err := gopay.AliAppCallback(w, r)
65 | if err != nil {
66 | fmt.Println(err)
67 | //log.xxx
68 | return
69 | }
70 | //接下来处理自己的逻辑
71 | fmt.Println(aliResult)
72 | })
73 | }
74 | ```
75 |
--------------------------------------------------------------------------------
/client/http.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "crypto/tls"
5 | "io/ioutil"
6 | "net/http"
7 | "strings"
8 | "time"
9 | )
10 |
11 | var (
12 | tokenServer string
13 | tokenUsername string
14 | tokenPassword string
15 | payClientCertFile string
16 | payClientKeyFile string
17 | payClientRootCert string
18 |
19 | HTTPC *HTTPClient
20 | HTTPSC *HTTPSClient
21 | )
22 |
23 | func init() {
24 | HTTPC = &HTTPClient{}
25 | HTTPSC = NewHTTPSClient()
26 | }
27 |
28 | // HTTPSClient HTTPS客户端结构
29 | type HTTPSClient struct {
30 | http.Client
31 | }
32 |
33 | // GetDefaultClient 返回默认的客户端
34 | func GetDefaultClient() *HTTPSClient {
35 | return HTTPSC
36 | }
37 |
38 | // NewHTTPSClient 新建https客户端
39 | // func NewHTTPSClient(certFile string, keyFile string) *HTTPSClient {
40 | // cert, err := tls.LoadX509KeyPair(certFile, keyFile)
41 | // if err != nil {
42 | // log.Error("load x509 cert error:", err)
43 | // return nil
44 | // }
45 | // config := &tls.Config{
46 | // Certificates: []tls.Certificate{cert},
47 | // }
48 | // config.BuildNameToCertificate()
49 | // tr := &http.Transport{TLSClientConfig: config}
50 | // client := &http.Client{Transport: tr}
51 | // return &HTTPSClient{
52 | // Client: *client,
53 | // }
54 | // }
55 |
56 | // NewHTTPSClient 获取默认https客户端
57 | func NewHTTPSClient() *HTTPSClient {
58 | config := &tls.Config {InsecureSkipVerify:true}
59 | tr := &http.Transport{TLSClientConfig: config}
60 | client := http.Client{
61 | Transport: tr,
62 | Timeout: 15 * time.Second,
63 | }
64 | return &HTTPSClient{
65 | Client: client,
66 | }
67 | }
68 |
69 | // PostData 提交post数据
70 | func (c *HTTPSClient) PostData(url string, contentType string, data string) ([]byte, error) {
71 | resp, err := c.Post(url, contentType, strings.NewReader(data))
72 | if err != nil {
73 | return nil, err
74 | }
75 | defer resp.Body.Close()
76 | return ioutil.ReadAll(resp.Body)
77 | }
78 |
79 | // HTTPClient http客户端
80 | type HTTPClient struct {
81 | http.Client
82 | }
83 |
84 | // PostData post数据
85 | func (c *HTTPClient) PostData(url, format string, data string) ([]byte, error) {
86 | resp, err := c.Post(url, format, strings.NewReader(data))
87 | if err != nil {
88 | return nil, err
89 | }
90 | defer resp.Body.Close()
91 | return ioutil.ReadAll(resp.Body)
92 | }
93 |
--------------------------------------------------------------------------------
/common/wechat.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | // WeChatResult 微信支付返回
4 | type WeChatReResult struct {
5 | ReturnCode string `xml:"return_code"`
6 | ReturnMsg string `xml:"return_msg"`
7 |
8 | AppID string `xml:"appid"`
9 | MchID string `xml:"mch_id"`
10 | DeviceInfo string `xml:"device_info"`
11 | NonceStr string `xml:"nonce_str"`
12 | Sign string `xml:"sign"`
13 | ResultCode string `xml:"result_code"`
14 | ErrCode string `xml:"err_code"`
15 | ErrCodeDes string `xml:"err_code_des"`
16 |
17 | TradeType string `xml:"trade_type"`
18 | PrepayID string `xml:"prepay_id"`
19 | CodeURL string `xml:"code_url"`
20 | }
21 |
22 | // WechatBaseResult 基本信息
23 | type WechatBaseResult struct {
24 | ReturnCode string `xml:"return_code"`
25 | ReturnMsg string `xml:"return_msg"`
26 | }
27 |
28 | // WechatReturnData 返回通用数据
29 | type WechatReturnData struct {
30 | AppID string `xml:"appid,emitempty"`
31 | MchID string `xml:"mch_id,emitempty"`
32 | DeviceInfo string `xml:"device_info,emitempty"`
33 | NonceStr string `xml:"nonce_str,emitempty"`
34 | Sign string `xml:"sign,emitempty"`
35 | ResultCode string `xml:"result_code,emitempty"`
36 | ErrCode string `xml:"err_code,emitempty"`
37 | ErrCodeDes string `xml:"err_code_des,emitempty"`
38 | }
39 |
40 | // WechatResultData 结果通用数据
41 | type WechatResultData struct {
42 | OpenID string `xml:"openid,emitempty"`
43 | IsSubscribe string `xml:"is_subscribe,emitempty"`
44 | TradeType string `xml:"trade_type,emitempty"`
45 | BankType string `xml:"bank_type,emitempty"`
46 | FeeType string `xml:"fee_type,emitempty"`
47 | TotalFee int64 `xml:"total_fee,emitempty"`
48 | CashFeeType string `xml:"cash_fee_type,emitempty"`
49 | CashFee int64 `xml:"cash_fee,emitempty"`
50 | TransactionID string `xml:"transaction_id,emitempty"`
51 | OutTradeNO string `xml:"out_trade_no,emitempty"`
52 | Attach string `xml:"attach,emitempty"`
53 | TimeEnd string `xml:"time_end,emitempty"`
54 | }
55 |
56 | type WeChatPayResult struct {
57 | WechatBaseResult
58 | WechatReturnData
59 | WechatResultData
60 | }
61 |
62 | type WeChatQueryResult struct {
63 | WechatBaseResult
64 | WechatReturnData
65 | WechatResultData
66 | TradeState string `xml:"trade_state"`
67 | TradeStateDesc string `xml:"trade_state_desc"`
68 | }
69 |
--------------------------------------------------------------------------------
/common/alipay.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | // AliWebPayResult 支付宝支付结果回调
4 | type AliWebPayResult struct {
5 | NotifyTime string `json:"notify_time"`
6 | NotifyType string `json:"notify_type"`
7 | NotifyID string `json:"notify_id"`
8 | SignType string `json:"sign_type"`
9 | Sign string `json:"sign"`
10 | OutTradeNum string `json:"out_trade_no"`
11 | Subject string `json:"subject"`
12 | PayMentType string `json:"payment_type"`
13 | TradeNum string `json:"trade_no"`
14 | TradeStatus string `json:"trade_status"`
15 | GmtPayMent string `json:"gmt_payment"`
16 | GmtClose string `json:"gmt_close"`
17 | SellerEmail string `json:"seller_email"`
18 | BuyerEmail string `json:"buyer_email"`
19 | SellerID string `json:"seller_id"`
20 | BuyerID string `json:"buyer_id"`
21 | Price string `json:"price"`
22 | TotalFee string `json:"total_fee"`
23 | Quantity string `json:"quantity"`
24 | Body string `json:"body"`
25 | Discount string `json:"discount"`
26 | IsTotalFeeAdjust string `json:"is_total_fee_adjust"`
27 | UseCoupon string `json:"use_coupon"`
28 | RefundStatus string `json:"refund_status"`
29 | GmtRefund string `json:"gmt_refund"`
30 | }
31 |
32 | type AliQueryResult struct {
33 | TradeNo string `json:"trade_no"`
34 | OutTradeNo string `json:"out_trade_no"`
35 | OpenID string `json:"open_id"`
36 | BuyerLogonID string `json:"buyer_logon_id"`
37 | TradeStatus string `json:"trade_status"`
38 | TotalAmount string `json:"total_amount"`
39 | ReceiptAmount string `json:"receipt_amount"`
40 | BuyerPayAmount string `json:"BuyerPayAmount"`
41 | PointAmount string `json:"point_amount"`
42 | InvoiceAmount string `json:"invoice_amount"`
43 | SendPayDate string `json:"send_pay_date"`
44 | AlipayStoreID string `json:"alipay_store_id"`
45 | StoreID string `json:"store_id"`
46 | TerminalID string `json:"terminal_id"`
47 | FundBillList []struct {
48 | FundChannel string `json:"fund_channel"`
49 | Amount string `json:"amount"`
50 | } `json:"fund_bill_list"`
51 | StoreName string `json:"store_name"`
52 | BuyerUserID string `json:"buyer_user_id"`
53 | DiscountGoodsDetail string `json:"discount_goods_detail"`
54 | IndustrySepcDetail string `json:"industry_sepc_detail"`
55 | }
56 |
--------------------------------------------------------------------------------
/client/aliapp.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "crypto"
5 | "crypto/rand"
6 | "crypto/rsa"
7 | "crypto/sha1"
8 | "encoding/base64"
9 | "fmt"
10 | "../common"
11 | "log"
12 | "net/url"
13 | "sort"
14 | "strings"
15 | )
16 |
17 | var defaultAliAppClient *AliAppClient
18 |
19 | type AliAppClient struct {
20 | PartnerID string //合作者ID
21 | SellerID string
22 | AppID string // 应用ID
23 | PrivateKey *rsa.PrivateKey
24 | PublicKey *rsa.PublicKey
25 | }
26 |
27 | func InitAliAppClient(c *AliAppClient) {
28 | defaultAliAppClient = c
29 | }
30 |
31 | // DefaultAliAppClient 得到默认支付宝app客户端
32 | func DefaultAliAppClient() *AliAppClient {
33 | return defaultAliAppClient
34 | }
35 |
36 | func (aa *AliAppClient) Pay(charge *common.Charge) (string, error) {
37 | data := make(map[string]string)
38 | data["service"] = "mobile.securitypay.pay"
39 | data["partner"] = aa.PartnerID
40 | data["_input_charset"] = "utf-8"
41 | data["notify_url"] = charge.CallbackURL
42 |
43 | data["out_trade_no"] = charge.TradeNum
44 | data["subject"] = charge.Describe
45 | data["payment_type"] = "1"
46 | data["seller_id"] = aa.SellerID
47 | data["total_fee"] = fmt.Sprintf("%.2f", float64(charge.MoneyFee)/float64(100))
48 | data["body"] = charge.Describe
49 |
50 | sign, err := aa.GenSign(data)
51 | if err != nil {
52 | return "", err
53 | }
54 | data["sign"] = sign
55 | data["sign_type"] = "RSA"
56 |
57 | var re []string
58 | for k, v := range data {
59 | re = append(re, fmt.Sprintf("%s=%s", k, v))
60 | }
61 | return strings.Join(re, "&"), nil
62 | }
63 |
64 | // GenSign 产生签名
65 | func (aa *AliAppClient) GenSign(m map[string]string) (string, error) {
66 | delete(m, "sign_type")
67 | delete(m, "sign")
68 | var data []string
69 | for k, v := range m {
70 | if v == "" {
71 | continue
72 | }
73 | data = append(data, fmt.Sprintf("%s=%s", k, v))
74 | }
75 | sort.Strings(data)
76 | signData := strings.Join(data, "&")
77 | s := sha1.New()
78 | _, err := s.Write([]byte(signData))
79 | if err != nil {
80 | log.Println(err)
81 | }
82 | hashByte := s.Sum(nil)
83 | signByte, err := aa.PrivateKey.Sign(rand.Reader, hashByte, crypto.SHA1)
84 | if err != nil {
85 | return "", err
86 | }
87 | return url.QueryEscape(base64.StdEncoding.EncodeToString(signByte)), nil
88 | }
89 |
90 | // CheckSign 检测签名
91 | func (aa *AliAppClient) CheckSign(data string, sign string) error {
92 | signByte, err := base64.StdEncoding.DecodeString(sign)
93 | if err != nil {
94 | return err
95 | }
96 | s := sha1.New()
97 | _, err = s.Write([]byte(data))
98 | if err != nil {
99 | return err
100 | }
101 | hash := s.Sum(nil)
102 | return rsa.VerifyPKCS1v15(aa.PublicKey, crypto.SHA1, hash[:], signByte)
103 | }
104 |
--------------------------------------------------------------------------------
/client/wechatapp.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "bytes"
5 | "crypto/md5"
6 | "encoding/json"
7 | "encoding/xml"
8 | "errors"
9 | "fmt"
10 | "../common"
11 | "../util"
12 | "sort"
13 | "strings"
14 | "time"
15 | )
16 |
17 | var defaultWechatAppClient *WechatAppClient
18 |
19 | // DefaultWechatAppClient 默认微信app客户端
20 | func DefaultWechatAppClient() *WechatAppClient {
21 | return defaultWechatAppClient
22 | }
23 |
24 | // WechatAppClient 微信app支付
25 | type WechatAppClient struct {
26 | AppID string // AppID
27 | MchID string // 商户号ID
28 | callbackURL string // 回调地址
29 | Key string // 密钥
30 | PayURL string // 支付地址
31 | }
32 |
33 | func InitWechatClient(c *WechatAppClient) {
34 | defaultWechatAppClient = c
35 | }
36 |
37 | // Pay 支付
38 | func (wechat *WechatAppClient) Pay(charge *common.Charge) (string, error) {
39 | var m = make(map[string]string)
40 | m["appid"] = wechat.AppID
41 | m["mch_id"] = wechat.MchID
42 | m["nonce_str"] = util.RandomStr()
43 | m["body"] = charge.Describe
44 | m["out_trade_no"] = charge.TradeNum
45 | m["total_fee"] = fmt.Sprintf("%d", charge.MoneyFee)
46 | m["spbill_create_ip"] = util.LocalIP()
47 | m["notify_url"] = wechat.callbackURL
48 | m["trade_type"] = "APP"
49 |
50 | sign, err := wechat.GenSign(m)
51 | if err != nil {
52 | return "", err
53 | }
54 | m["sign"] = sign
55 | // 转出xml结构
56 | buf := bytes.NewBufferString("")
57 | for k, v := range m {
58 | buf.WriteString(fmt.Sprintf("<%s>%s>", k, v, k))
59 | }
60 | xmlStr := fmt.Sprintf("