pay.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package pay
  2. import (
  3. "encoding/xml"
  4. "errors"
  5. "fmt"
  6. "github.com/silenceper/wechat/context"
  7. "github.com/silenceper/wechat/util"
  8. )
  9. var payGateway = "https://api.mch.weixin.qq.com/pay/unifiedorder"
  10. // Pay struct extends context
  11. type Pay struct {
  12. *context.Context
  13. }
  14. // Params was NEEDED when request unifiedorder
  15. // 传入的参数,用于生成 prepay_id 的必需参数
  16. type Params struct {
  17. TotalFee string
  18. CreateIP string
  19. Body string
  20. OutTradeNo string
  21. OpenID string
  22. TradeType string
  23. }
  24. // Config 是传出用于 jsdk 用的参数
  25. type Config struct {
  26. Timestamp int64
  27. NonceStr string
  28. PrePayID string
  29. SignType string
  30. Sign string
  31. }
  32. // PreOrder 是 unifie order 接口的返回
  33. type PreOrder struct {
  34. ReturnCode string `xml:"return_code"`
  35. ReturnMsg string `xml:"return_msg"`
  36. AppID string `xml:"appid,omitempty"`
  37. MchID string `xml:"mch_id,omitempty"`
  38. NonceStr string `xml:"nonce_str,omitempty"`
  39. Sign string `xml:"sign,omitempty"`
  40. ResultCode string `xml:"result_code,omitempty"`
  41. TradeType string `xml:"trade_type,omitempty"`
  42. PrePayID string `xml:"prepay_id,omitempty"`
  43. CodeURL string `xml:"code_url,omitempty"`
  44. ErrCode string `xml:"err_code,omitempty"`
  45. ErrCodeDes string `xml:"err_code_des,omitempty"`
  46. }
  47. //payRequest 接口请求参数
  48. type payRequest struct {
  49. AppID string `xml:"appid"`
  50. MchID string `xml:"mch_id"`
  51. DeviceInfo string `xml:"device_info,omitempty"`
  52. NonceStr string `xml:"nonce_str"`
  53. Sign string `xml:"sign"`
  54. SignType string `xml:"sign_type,omitempty"`
  55. Body string `xml:"body"`
  56. Detail string `xml:"detail,omitempty"`
  57. Attach string `xml:"attach,omitempty"` //附加数据
  58. OutTradeNo string `xml:"out_trade_no"` //商户订单号
  59. FeeType string `xml:"fee_type,omitempty"` //标价币种
  60. TotalFee string `xml:"total_fee"` //标价金额
  61. SpbillCreateIP string `xml:"spbill_create_ip"` //终端IP
  62. TimeStart string `xml:"time_start,omitempty"` //交易起始时间
  63. TimeExpire string `xml:"time_expire,omitempty"` //交易结束时间
  64. GoodsTag string `xml:"goods_tag,omitempty"` //订单优惠标记
  65. NotifyURL string `xml:"notify_url"` //通知地址
  66. TradeType string `xml:"trade_type"` //交易类型
  67. ProductID string `xml:"product_id,omitempty"` //商品ID
  68. LimitPay string `xml:"limit_pay,omitempty"` //
  69. OpenID string `xml:"openid,omitempty"` //用户标识
  70. SceneInfo string `xml:"scene_info,omitempty"` //场景信息
  71. }
  72. // NewPay return an instance of Pay package
  73. func NewPay(ctx *context.Context) *Pay {
  74. pay := Pay{Context: ctx}
  75. return &pay
  76. }
  77. // PrePayOrder return data for invoke wechat payment
  78. func (pcf *Pay) PrePayOrder(p *Params) (payOrder PreOrder, err error) {
  79. nonceStr := util.RandomStr(32)
  80. template := "appid=%s&body=%s&mch_id=%s&nonce_str=%s&notify_url=%s&openid=%s&out_trade_no=%s&spbill_create_ip=%s&total_fee=%s&trade_type=%s&key=%s"
  81. str := fmt.Sprintf(template, pcf.AppID, p.Body, pcf.PayMchID, nonceStr, pcf.PayNotifyURL, p.OpenID, p.OutTradeNo, p.CreateIP, p.TotalFee, p.TradeType, pcf.PayKey)
  82. sign := util.MD5Sum(str)
  83. request := payRequest{
  84. AppID: pcf.AppID,
  85. MchID: pcf.PayMchID,
  86. NonceStr: nonceStr,
  87. Sign: sign,
  88. Body: p.Body,
  89. OutTradeNo: p.OutTradeNo,
  90. TotalFee: p.TotalFee,
  91. SpbillCreateIP: p.CreateIP,
  92. NotifyURL: pcf.PayNotifyURL,
  93. TradeType: p.TradeType,
  94. OpenID: p.OpenID,
  95. }
  96. rawRet, err := util.PostXML(payGateway, request)
  97. if err != nil {
  98. return
  99. }
  100. err = xml.Unmarshal(rawRet, &payOrder)
  101. if err != nil {
  102. return
  103. }
  104. if payOrder.ReturnCode == "SUCCESS" {
  105. //pay success
  106. if payOrder.ResultCode == "SUCCESS" {
  107. err = nil
  108. return
  109. }
  110. err = errors.New(payOrder.ErrCode + payOrder.ErrCodeDes)
  111. return
  112. }
  113. err = errors.New("[msg : xmlUnmarshalError] [rawReturn : " + string(rawRet) + "] [params : " + str + "] [sign : " + sign + "]")
  114. return
  115. }
  116. // PrePayID will request wechat merchant api and request for a pre payment order id
  117. func (pcf *Pay) PrePayID(p *Params) (prePayID string, err error) {
  118. order, err := pcf.PrePayOrder(p)
  119. if err != nil {
  120. return
  121. }
  122. if order.PrePayID == "" {
  123. err = errors.New("empty prepayid")
  124. }
  125. prePayID = order.PrePayID
  126. return
  127. }