pay.go 3.8 KB

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