ls 5 years ago
parent
commit
d89c52b54e
6 changed files with 231 additions and 107 deletions
  1. 33 0
      request.go
  2. 19 20
      wechat/client.go
  3. 0 5
      wechat/const.go
  4. 22 15
      wechat/mini.go
  5. 129 0
      wechat/pay.go
  6. 28 67
      wechat/request.go

+ 33 - 0
request.go

@@ -4,6 +4,9 @@ import (
 	"compress/gzip"
 	"crypto/tls"
 	"crypto/x509"
+	"encoding/json"
+	"encoding/xml"
+	"errors"
 	"io"
 	"io/ioutil"
 	"net"
@@ -44,6 +47,36 @@ type HTTPMessage struct {
 	Header     http.Header
 }
 
+// JSON Body to JSON
+func (m HTTPMessage) JSON(dest interface{}) (err error) {
+	if m.StatusCode != http.StatusOK {
+		err = errors.New(`StatusCode not 200`)
+		return
+	}
+	err = json.Unmarshal(m.Body, &dest)
+	return
+}
+
+// XML Body to XML
+func (m HTTPMessage) XML(dest interface{}) (err error) {
+	if m.StatusCode != http.StatusOK {
+		err = errors.New(`StatusCode not 200`)
+		return
+	}
+	err = xml.Unmarshal(m.Body, &dest)
+	return
+}
+
+// JSONQuery Body to JSONQuery
+func (m HTTPMessage) JSONQuery() (jq *JSONQuery, err error) {
+	if m.StatusCode != http.StatusOK {
+		err = errors.New(`StatusCode not 200`)
+		return
+	}
+	jq, err = NewJSONQuery(m.Body)
+	return
+}
+
 func newRequest(method, uri, certPath, keyPath string, header map[string]string, body io.Reader) (res *http.Response, err error) {
 	t := &http.Transport{
 		Dial: func(netw, addr string) (net.Conn, error) {

+ 19 - 20
wechat/client.go

@@ -1,7 +1,6 @@
 package wechat
 
 import (
-	"encoding/json"
 	"fmt"
 	"net/url"
 	"time"
@@ -95,7 +94,7 @@ func (wc Client) GetOpenID(code string) (jq *myth.JSONQuery, err error) {
 }
 
 // GetUserInfo user info
-func (wc Client) GetUserInfo(openid string) (res UserInfo, err error) {
+func (wc Client) GetUserInfo(openid string) (info UserInfo, err error) {
 	uri := BaseURL + "/cgi-bin/user/info?"
 
 	if wc.AccessToken, err = wc.getToken(); err != nil {
@@ -107,17 +106,17 @@ func (wc Client) GetUserInfo(openid string) (res UserInfo, err error) {
 	args.Add("lang", "zh_CN")
 
 	uri += args.Encode()
-	var body []byte
-	body, err = getBody(uri)
+
+	var msg myth.HTTPMessage
+	msg, err = getBody(uri)
 	if err == nil {
-		err = json.Unmarshal(body, &res)
+		err = msg.JSON(&info)
 	}
-
 	return
 }
 
 // GetUserList user list
-func (wc Client) GetUserList(nextOpenID string) (res UserList, err error) {
+func (wc Client) GetUserList(nextOpenID string) (list UserList, err error) {
 	uri := BaseURL + "/cgi-bin/user/get?"
 
 	if wc.AccessToken, err = wc.getToken(); err != nil {
@@ -128,17 +127,17 @@ func (wc Client) GetUserList(nextOpenID string) (res UserList, err error) {
 	args.Add("next_openid", nextOpenID)
 
 	uri += args.Encode()
-	var body []byte
-	body, err = getBody(uri)
+
+	var msg myth.HTTPMessage
+	msg, err = getBody(uri)
 	if err == nil {
-		err = json.Unmarshal(body, &res)
+		err = msg.JSON(&list)
 	}
-
 	return
 }
 
 // GetMaterial 永久资料
-func (wc Client) GetMaterial(mtype string, offset, count int) (res Material, err error) {
+func (wc Client) GetMaterial(mtype string, offset, count int) (material Material, err error) {
 	uri := BaseURL + "/cgi-bin/material/batchget_material?"
 
 	if wc.AccessToken, err = wc.getToken(); err != nil {
@@ -155,12 +154,11 @@ func (wc Client) GetMaterial(mtype string, offset, count int) (res Material, err
 	data["count"] = count
 
 	uri += args.Encode()
-	var body []byte
 
-	params, err := json.Marshal(data)
-	body, err = postJSONBody(uri, params)
+	var msg myth.HTTPMessage
+	msg, err = postJSON(uri, data)
 	if err == nil {
-		err = json.Unmarshal(body, &res)
+		err = msg.JSON(&material)
 	}
 
 	return
@@ -238,10 +236,11 @@ func (wc Client) SendTemplateMessage(template TemplateMessage) (jq *myth.JSONQue
 	args.Add("access_token", wc.AccessToken)
 
 	uri += args.Encode()
-	data, err := json.Marshal(template)
-	if err != nil {
-		return
+
+	var msg myth.HTTPMessage
+	msg, err = postJSON(uri, template)
+	if err == nil {
+		jq, err = msg.JSONQuery()
 	}
-	jq, err = postJSON(uri, data)
 	return
 }

+ 0 - 5
wechat/const.go

@@ -17,8 +17,6 @@ const (
 
 	// PayURLUnifiedOrder pay 付款
 	PayURLUnifiedOrder = `/pay/unifiedorder`
-	// PayURLUnifiedQuery order query 订单查询
-	PayURLUnifiedQuery = `/pay/orderquery`
 	// PayURLPayRefund pay refund 退款
 	PayURLPayRefund = `/secapi/pay/refund`
 	// PayURLPapPay 委托代扣申请扣款
@@ -32,7 +30,4 @@ const (
 	PayTradeTypeNative = `NATIVE`
 	// PayTradeTypeAPP APP APP支付
 	PayTradeTypeAPP = `APP`
-
-	// MiniURLOpenID 小程序获取 OpenID
-	MiniURLOpenID = `/sns/jscode2session`
 )

+ 22 - 15
wechat/mini.go

@@ -4,8 +4,6 @@ import (
 	"net/url"
 	"time"
 
-	"encoding/json"
-
 	"git.chuangxin1.com/cx/myth"
 )
 
@@ -85,11 +83,19 @@ func (mc *MiniClient) TemplateList(offset, count int) (body []byte, err error) {
 	params := make(map[string]interface{})
 	params["offset"] = offset
 	params["count"] = count
-	data, err := json.Marshal(params)
-	if err != nil {
-		return
+
+	var msg myth.HTTPMessage
+	msg, err = postJSON(uri, params)
+	if err == nil {
+		body = msg.Body
 	}
-	body, err = postJSONBody(uri, data)
+	/*
+		data, err := json.Marshal(params)
+		if err != nil {
+			return
+		}
+		body, err = postJSONBody(uri, data)
+		// */
 
 	return
 }
@@ -105,12 +111,12 @@ func (mc *MiniClient) TemplateSend(template MiniTemplateMessage) (jq *myth.JSONQ
 	args.Add("access_token", mc.AccessToken)
 
 	uri += args.Encode()
-	data, err := json.Marshal(template)
-	if err != nil {
-		return
-	}
-	jq, err = postJSON(uri, data)
 
+	var msg myth.HTTPMessage
+	msg, err = postJSON(uri, template)
+	if err == nil {
+		jq, err = msg.JSONQuery()
+	}
 	return
 }
 
@@ -125,11 +131,12 @@ func (mc *MiniClient) UniformSend(template MiniUniformMessage) (jq *myth.JSONQue
 	args.Add("access_token", mc.AccessToken)
 
 	uri += args.Encode()
-	data, err := json.Marshal(template)
-	if err != nil {
-		return
+
+	var msg myth.HTTPMessage
+	msg, err = postJSON(uri, template)
+	if err == nil {
+		jq, err = msg.JSONQuery()
 	}
-	jq, err = postJSON(uri, data)
 
 	return
 }

+ 129 - 0
wechat/pay.go

@@ -0,0 +1,129 @@
+package wechat
+
+import (
+	"encoding/xml"
+
+	"git.chuangxin1.com/cx/myth"
+)
+
+// PayConfig WeChat pay configure
+type PayConfig struct {
+	AppID      string `json:"appid"`
+	MchID      string `json:"mchid"`
+	Key        string `json:"key"`
+	AppSecret  string `json:"appsecret"`
+	SSLCert    string `json:"sslcert"`
+	SSLKey     string `json:"sslkey"`
+	ContractID string `json:"contractid"`
+	NotifyURL  string `json:"notify_url"`
+}
+
+// PayUnifiedOrder https://api.mch.weixin.qq.com/pay/unifiedorder
+type PayUnifiedOrder struct {
+	XMLName        xml.Name `xml:"xml"`
+	AppID          string   `xml:"appid"`
+	MchID          string   `xml:"mch_id"`
+	Body           string   `xml:"body"`
+	NonceStr       string   `xml:"nonce_str"`
+	NotifyURL      string   `xml:"notify_url"`
+	TradeType      string   `xml:"trade_type"`
+	OpenID         string   `xml:"openid"`
+	SpbillCreateIP string   `xml:"spbill_create_ip"`
+	TimeStart      string   `xml:"time_start"`
+	TotalFee       int      `xml:"total_fee"`
+	OutTradeNo     string   `xml:"out_trade_no"`
+	Attach         string   `xml:"attach"`
+	Sign           string   `xml:"sign"`
+}
+
+// PayOrderQuery https://api.mch.weixin.qq.com/pay/orderquery
+type PayOrderQuery struct {
+	XMLName       xml.Name `xml:"xml"`
+	AppID         string   `xml:"appid"`
+	MchID         string   `xml:"mch_id"`
+	NonceStr      string   `xml:"nonce_str"`
+	TransactionID string   `xml:"transaction_id,omitempty"`
+	OutTradeNo    string   `xml:"out_trade_no,omitempty"`
+	Sign          string   `xml:"sign"`
+}
+
+// FormPayNotify notify
+type FormPayNotify struct {
+	XMLName  xml.Name `xml:"xml" json:"_,omitempty"`
+	AppID    string   `form:"appid" xml:"appid"`
+	Attach   string   `form:"attach" xml:"attach"`
+	BankType string   `form:"bank_type" xml:"bank_type"`
+	CashFee  int      `form:"cash_fee" xml:"cash_fee"`
+	FeeType  string   `form:"fee_type" xml:"fee_type"`
+
+	MchID       string `form:"mch_id" xml:"mch_id"`
+	IsSubscribe string `form:"is_subscribe" xml:"is_subscribe"`
+	NonceStr    string `form:"nonce_str" xml:"nonce_str"`
+	OpenID      string `form:"openid" xml:"openid"`
+	OutTradeNo  string `form:"out_trade_no" xml:"out_trade_no"`
+
+	ResultCode string `form:"result_code" xml:"result_code"`
+	ReturnMsg  string `form:"return_msg" xml:"return_msg"`
+	ReturnCode string `form:"return_code" xml:"return_code"`
+	ErrCodeDes string `form:"err_code_des" xml:"err_code_des"`
+	ErrCode    string `form:"err_code" xml:"err_code"`
+
+	Sign     string `form:"sign" xml:"sign"`
+	TimeEnd  string `form:"time_end" xml:"time_end"`
+	TotalFee int    `form:"total_fee" xml:"total_fee"`
+
+	TradeType     string `form:"trade_type" xml:"trade_type"`
+	TransactionID string `form:"transaction_id" xml:"transaction_id"`
+	ContractID    string `form:"contract_id" xml:"contract_id"`
+}
+
+// PayReply pay reply
+type PayReply struct {
+	XMLName        xml.Name `xml:"xml" json:"_,omitempty"`
+	ReturnCode     string   `xml:"return_code"`
+	ReturnMsg      string   `xml:"return_msg"`
+	AppID          string   `xml:"appid"`
+	MchID          string   `xml:"mch_id"`
+	NonceStr       string   `xml:"nonce_str"`
+	Sign           string   `xml:"sign"`
+	ResultCode     string   `xml:"result_code"`
+	PrePayID       string   `xml:"prepay_id"`
+	TradeType      string   `xml:"trade_type"`
+	URL            string   `xml:"code_url"`
+	ErrCode        string   `xml:"err_code"`
+	ErrCodeDes     string   `xml:"err_code_des"`
+	OpenID         string   `xml:"openid"`
+	Attach         string   `xml:"attach"`
+	IsSubscribe    string   `xml:"is_subscribe"`
+	BankType       string   `xml:"bank_type"`
+	CashFee        string   `xml:"cash_fee"`
+	FeeType        string   `xml:"fee_type"`
+	OutTradeNo     string   `xml:"out_trade_no"`
+	TimeEnd        string   `xml:"time_end"`
+	TotalFee       string   `xml:"total_fee"`
+	TradeState     string   `xml:"trade_state"`
+	TradeStateDesc string   `xml:"trade_state_desc"`
+	TransactionID  string   `xml:"transaction_id"`
+	ContractID     string   `form:"contract_id" xml:"contract_id"`
+}
+
+// PayQuery order query 订单查询
+func PayQuery(cpyid int, config PayConfig, order PayOrderQuery) (reply PayReply, err error) {
+	m := make(map[string]interface{})
+
+	m["appid"] = order.AppID
+	m["mch_id"] = order.MchID
+	m["out_trade_no"] = order.OutTradeNo
+	m["nonce_str"] = order.NonceStr
+	//m["transaction_id"] = order.TransactionID
+
+	order.Sign = Sign(m, config.Key)
+
+	var msg myth.HTTPMessage
+	msg, err = postXML(PayHost+`/pay/orderquery`, order)
+	if err == nil {
+		err = msg.XML(&reply)
+	}
+
+	return
+}

+ 28 - 67
wechat/request.go

@@ -3,31 +3,15 @@ package wechat
 import (
 	"bytes"
 	"encoding/json"
+	"encoding/xml"
 	"errors"
 
 	"git.chuangxin1.com/cx/myth"
 )
 
-func checkErrorWithBody(msg myth.HTTPMessage) (body []byte, err error) {
+func checkJSONError(msg myth.HTTPMessage) (jq *myth.JSONQuery, err error) {
 	if msg.StatusCode == 200 {
-		var res ResponseMsg
-		err = json.Unmarshal(msg.Body, &res)
-		if err == nil {
-			if res.ErrCode != ErrReqOk {
-				err = errors.New(res.ErrMsg)
-			} else {
-				body = msg.Body
-			}
-		}
-	} else {
-		err = errors.New(`HTTP StatusCode not 200`)
-	}
-	return
-}
-
-func checkError(msg myth.HTTPMessage) (jq *myth.JSONQuery, err error) {
-	if msg.StatusCode == 200 {
-		jq, err = myth.NewJSONQuery(msg.Body)
+		jq, err = msg.JSONQuery()
 		if err != nil {
 			return
 		}
@@ -44,86 +28,63 @@ func checkError(msg myth.HTTPMessage) (jq *myth.JSONQuery, err error) {
 			}
 			err = errors.New(msg)
 		}
-		/*
-			err = json.Unmarshal(msg.Body, &res)
-			if err == nil {
-				if res.ErrCode != ErrReqOk {
-					err = errors.New(res.ErrMsg)
-				}
-			}
-			// */
 	} else {
 		err = errors.New(`HTTP StatusCode not 200`)
 	}
 	return
 }
 
+// getJSON 获取 JSON 格式返回数据
 func getJSON(uri string) (jq *myth.JSONQuery, err error) {
 	var msg myth.HTTPMessage
-	if msg, err = myth.Get(uri, "", "", map[string]string{}); err != nil {
-		return
-	}
-	jq, err = checkError(msg)
-	return
-}
 
-func getBody(uri string) (body []byte, err error) {
-	var msg myth.HTTPMessage
-	if msg, err = myth.Get(uri, "", "", map[string]string{}); err != nil {
+	headers := make(map[string]string)
+	headers["Accept-Encoding"] = "gzip, deflate, br"
+	headers["Accept"] = "application/json"
+	if msg, err = myth.Get(uri, "", "", headers); err != nil {
 		return
 	}
-	body, err = checkErrorWithBody(msg)
+	jq, err = checkJSONError(msg)
 	return
 }
 
-func postXML(url string, data []byte) (jq *myth.JSONQuery, err error) {
-	var (
-		msg     myth.HTTPMessage
-		headers = make(map[string]string)
-	)
-
+// getBody 获取原始返回数据
+func getBody(uri string) (msg myth.HTTPMessage, err error) {
+	headers := make(map[string]string)
 	headers["Accept-Encoding"] = "gzip, deflate, br"
-	headers["Accept"] = "application/json"
-	headers["Content-Type"] = "application/xml; charset=utf-8"
-	msg, err = myth.Post(url, "", "", headers, bytes.NewReader(data))
-	if err != nil {
-		return
-	}
-	jq, err = checkError(msg)
+
+	msg, err = myth.Get(uri, "", "", headers)
 	return
 }
 
-func postJSON(url string, data []byte) (jq *myth.JSONQuery, err error) {
-	var (
-		msg     myth.HTTPMessage
-		headers = make(map[string]string)
-	)
+func postJSON(url string, args interface{}) (msg myth.HTTPMessage, err error) {
+	headers := make(map[string]string)
 
 	headers["Accept-Encoding"] = "gzip, deflate, br"
-	headers["Accept"] = "application/json"
 	headers["Content-Type"] = "application/json; charset=utf-8"
-	msg, err = myth.Post(url, "", "", headers, bytes.NewReader(data))
+
+	var data []byte
+	data, err = json.Marshal(args)
 	if err != nil {
 		return
 	}
-	jq, err = checkError(msg)
+	msg, err = myth.Post(url, "", "", headers, bytes.NewReader(data))
+
 	return
 }
 
-func postJSONBody(uri string, data []byte) (body []byte, err error) {
-	var (
-		msg     myth.HTTPMessage
-		headers = make(map[string]string)
-	)
+func postXML(url string, args interface{}) (msg myth.HTTPMessage, err error) {
+	headers := make(map[string]string)
 
 	headers["Accept-Encoding"] = "gzip, deflate, br"
-	headers["Accept"] = "application/json"
-	headers["Content-Type"] = "application/json; charset=utf-8"
-	msg, err = myth.Post(uri, "", "", headers, bytes.NewReader(data))
+	headers["Content-Type"] = "application/xml; charset=utf-8"
+
+	var data []byte
+	data, err = xml.Marshal(args)
 	if err != nil {
 		return
 	}
-	body, err = checkErrorWithBody(msg)
+	msg, err = myth.Post(url, "", "", headers, bytes.NewReader(data))
 
 	return
 }