From 97752d09a6208287b21884ba006c4287c6cec0fd Mon Sep 17 00:00:00 2001 From: Mongo Date: Sat, 28 Oct 2017 00:32:08 +0800 Subject: [PATCH] add jsapi payment demo version --- context/context.go | 2 + pay/pay.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++ util/http.go | 21 +++++++++++ wechat.go | 9 +++++ 4 files changed, 123 insertions(+) create mode 100644 pay/pay.go diff --git a/context/context.go b/context/context.go index 1975863..8dd09ff 100644 --- a/context/context.go +++ b/context/context.go @@ -13,6 +13,8 @@ type Context struct { AppSecret string Token string EncodingAESKey string + PayMchID string + PayNotifyURL string Cache cache.Cache diff --git a/pay/pay.go b/pay/pay.go new file mode 100644 index 0000000..66c133b --- /dev/null +++ b/pay/pay.go @@ -0,0 +1,91 @@ +package pay + +import ( + "crypto/md5" + "strings" + "github.com/silenceper/wechat/context" + "github.com/silenceper/wechat/util" +) + +var payGateway := "https://api.mch.weixin.qq.com/pay/unifiedorder" + +// Pay struct extends context +type Pay struct { + *context.Context +} + +// PayParams was NEEDED when request unifiedorder +type PayParams struct { + TotalFee string + CreateIP string + Body string + OutTradeNo string +} + +type PayResult struct { + Success bool + PrePayID string +} + +//PayRequest +type payRequest struct { + AppID string `xml:"appid"` + MchID string `xml:"mch_id"` + NotifyUrl string `xml:"notify_url"` //通知地址 + DeviceInfo string `xml:"device_info,omitempty"` + NonceStr string `xml:"nonce_str"` + Sign string `xml:"sign"` + SignType string `xml:"sign_type,omitempty"` + Body string `xml:"body"` + Detail string `xml:"detail,omitempty"` + Attach string `xml:"attach,omitempty"` //附加数据 + OutTradeNo string `xml:"out_trade_no"` //商户订单号 + FeeType string `xml:"fee_type,omitempty"` //标价币种 + TotalFee string `xml:"total_fee"` //标价金额 + SpbillCreateIp string `xml:"spbill_create_ip"` //终端IP + TimeStart string `xml:"time_start,omitempty"` //交易起始时间 + TimeExpire string `xml:"time_expire,omitempty"` //交易结束时间 + GoodsTag string `xml:"goods_tag,omitempty"` //订单优惠标记 + TradeType string `xml:"trade_type"` //交易类型 + ProductId string `xml:"product_id,omitempty"` //商品ID + LimitPay string `xml:"limit_pay,omitempty"` // + OpenID string `xml:"openid,omitempty"` //用户标识 + SceneInfo string `xml:"scene_info,omitempty"` //场景信息 +} + +type payResponse struct { + +} + +// NewPay return an instance of Pay package +func NewPay(ctx *context.Context) *Pay { + pay := Pay{Context: ctx} + return &pay +} + +// PrePayId will request wechat merchant api and request for a pre payment order id +func (pcf *Pay) PrePayId(p *PayParams) payResult *PayResult { + nonceStr := util.RandomStr(32) + pType = "JSAPI" + template := "appid=%s&body=%s&mch_id=%s&nonce_str=%s¬ify_url=%s&out_trade_no=%s&spbill_create_ip=%s&total_fee=%s&trade_type" + stringA := fmt.Sprintf(template, pcf.AppID, p.Body, pcf.MchID, nonceStr, pcf.NotifyUrl, p.OutTradeNo, p.CreateIP, p.TotalFee, pType) + signature := md5.Sum(stringA + pcf.PayKey) + sign := strings.ToUpper(signature) + request := payRequest{ + AppID: pcf.AppID, + MchID: pcf.MchID, + NotifyUrl: pcf.NotifyUrl, + NonceStr: util.RandomStr(32), + Sign: sign, + Body: p.Body, + OutTradeNo: p.OutTradeNo, + TotalFee: p.TotalFee, + SpbillCreateIp: params.CreateIP, + OpenID: params.OpenID, + } + ret, err := util.PostXML(payGateway, request) + if err != nil { + + } + fmt.Println(string(ret)) +} \ No newline at end of file diff --git a/util/http.go b/util/http.go index ca98ae7..ff6edca 100644 --- a/util/http.go +++ b/util/http.go @@ -3,6 +3,7 @@ package util import ( "bytes" "encoding/json" + "encoding/xml" "fmt" "io" "io/ioutil" @@ -120,3 +121,23 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte respBody, err = ioutil.ReadAll(resp.Body) return } + +//PostXML perform a HTTP/POST request with XML body +func PostXML(uri string, obj interface{}) ([]byte, error) { + xmlData, err := xml.Marshal(obj) + if err != nil { + return nil, err + } + + body := bytes.NewBuffer(xmlData) + response, err := http.Post(uri, "application/xml;charset=utf-8", body) + if err != nil { + return nil, err + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return nil, fmt.Errorf("http get error : uri=%v , statusCode=%v", uri, response.StatusCode) + } + return ioutil.ReadAll(response.Body) +} diff --git a/wechat.go b/wechat.go index e48de19..1dcdd2f 100644 --- a/wechat.go +++ b/wechat.go @@ -13,6 +13,7 @@ import ( "github.com/silenceper/wechat/server" "github.com/silenceper/wechat/template" "github.com/silenceper/wechat/user" + "github.com/silenceper/wechat/pay" ) // Wechat struct @@ -26,6 +27,9 @@ type Config struct { AppSecret string Token string EncodingAESKey string + PayMchID string + PayNotifyURL string //支付的通知接口 + PayKey string //商家后台设置的支付 key Cache cache.Cache } @@ -87,3 +91,8 @@ func (wc *Wechat) GetUser() *user.User { func (wc *Wechat) GetTemplate() *template.Template { return template.NewTemplate(wc.Context) } + +// GetPay 返回支付消息的实例 +func (wc *Wechat) GetPay() *pay.Pay { + return pay.NewPay(wc.Context) +}