wx.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package wx
  2. import (
  3. "encoding/xml"
  4. "errors"
  5. "fmt"
  6. "git.qianqiusoft.com/qianqiusoft/light-apiengine/entitys"
  7. "git.qianqiusoft.com/qianqiusoft/light-apiengine/models"
  8. "git.qianqiusoft.com/qianqiusoft/light-apiengine/utils"
  9. "github.com/silenceper/wechat/js"
  10. "github.com/silenceper/wechat/oauth"
  11. "github.com/silenceper/wechat/pay"
  12. "github.com/silenceper/wechat/util"
  13. "io"
  14. "io/ioutil"
  15. "net/http"
  16. "net/url"
  17. "os"
  18. "strconv"
  19. "strings"
  20. )
  21. // 微信回调处理器
  22. var _wxPayCallbackHandler func(result *pay.NotifyResult)models.SysReturn = nil
  23. // 微信通用登录回调处理器
  24. var _wxLoginCallbackHandler func(ctx *entitys.CtrlContext, body []byte, info *oauth.UserInfo)models.SysReturn = nil
  25. // 注册微信支付回调处理函数
  26. func RegisterWxPayCallbackHandler(handler func(result *pay.NotifyResult)models.SysReturn){
  27. _wxPayCallbackHandler = handler
  28. }
  29. // 调用微信支付回调处理函数
  30. func CallWxPayCallbackHandler(c *entitys.CtrlContext)models.SysReturn{
  31. if _wxPayCallbackHandler == nil{
  32. return models.SysReturn{500, "微信支付回调处理函数为空", nil}
  33. }
  34. data, err := ioutil.ReadAll(c.Ctx.Request.Body)
  35. if err != nil{
  36. fmt.Println("******************----》微信支付回调read request body错误", err.Error())
  37. return models.SysReturn{500, err.Error(), nil}
  38. }
  39. notifyRet := pay.NotifyResult{}
  40. err = xml.Unmarshal(data, &notifyRet)
  41. //err = c.Ctx.BindXML(&notifyRet)
  42. if err != nil{
  43. fmt.Println("******************----》微信支付回调bindxml错误", err.Error())
  44. return models.SysReturn{500, err.Error(), nil}
  45. }
  46. if notifyRet.ResultCode == "SUCCESS" && notifyRet.ReturnCode == "SUCCESS"{
  47. ok, err := VerifyResponseData(data, wxConfig.PayKey)
  48. if err != nil{
  49. fmt.Println("*****************---->微信支付回调验证错误", err.Error())
  50. return models.SysReturn{500, err.Error(), nil}
  51. }
  52. if !ok{
  53. fmt.Println("*****************---->微信支付回调验证错误, ok is false")
  54. return models.SysReturn{500, "", nil}
  55. }
  56. return _wxPayCallbackHandler(&notifyRet)
  57. }else{
  58. fmt.Println("------------------>微信支付失败", notifyRet)
  59. return models.SysReturn{500, "", ""}
  60. }
  61. }
  62. // 注册微信登录回调处理函数
  63. func RegisterWxLoginCallbackHandler(handler func(ctx *entitys.CtrlContext, body []byte, info *oauth.UserInfo)models.SysReturn){
  64. _wxLoginCallbackHandler = handler
  65. }
  66. // 调用微信登录处理函数
  67. func CallWxLoginCallbackHandler(ctx *entitys.CtrlContext, body []byte, info *oauth.UserInfo)models.SysReturn{
  68. if _wxLoginCallbackHandler == nil{
  69. return models.SysReturn{500, "微信登录回调处理函数为空", nil}
  70. }else{
  71. return _wxLoginCallbackHandler(ctx, body, info)
  72. }
  73. }
  74. // 扫码支付
  75. func PayNative(params *PayParams)(*pay.PayResult, error){
  76. ip := utils.GetIP(params.Ctx)
  77. attach := params.Attach
  78. if attach == ""{
  79. attach = params.Ctx.Ctx.GetString("user_id")
  80. if attach == ""{
  81. attach = "attach"
  82. }
  83. }
  84. body := params.Body
  85. if body == ""{
  86. body = "body"
  87. }
  88. if params.OutTradeNo == ""{
  89. return nil, errors.New("交易单号为空")
  90. }
  91. parParams := pay.Params{strconv.Itoa(params.TotalFee), ip, body, attach, params.OutTradeNo, ""}
  92. return wc.GetPay().PreNative(&parParams)
  93. }
  94. // jsapi 支付
  95. func PayJSAPI(params *PayParams)(*JSAPIPayConfig, error){
  96. openId := params.OpenId
  97. if openId == ""{
  98. return nil, errors.New("openid 为空")
  99. }
  100. if params.OutTradeNo == ""{
  101. return nil, errors.New("交易单号为空")
  102. }
  103. attach := params.Attach
  104. if attach == ""{
  105. fmt.Println("--------------------->1")
  106. attach = params.Ctx.Ctx.GetString("user_id")
  107. if attach == ""{
  108. fmt.Println("--------------------->2")
  109. attach = "attach"
  110. }
  111. }
  112. body := params.Body
  113. if body == ""{
  114. body = "body"
  115. }
  116. ip := utils.GetIP(params.Ctx)
  117. fmt.Println("params.Attach", params.Attach, "attach", attach)
  118. payParams := pay.Params{
  119. strconv.Itoa(params.TotalFee),
  120. ip,
  121. body,
  122. attach,
  123. params.OutTradeNo,
  124. params.OpenId,
  125. }
  126. payObj := wc.GetPay()
  127. prePayID, err := payObj.PrePayID(&payParams)
  128. if err != nil{
  129. fmt.Println("----------------->prepayid error", err.Error())
  130. return nil, err
  131. }
  132. nonceStr := util.RandomStr(32)
  133. timestamp := util.GetCurrTs()
  134. pack := "prepay_id=" + prePayID
  135. template := "appId=%s&nonceStr=%s&package=%s&signType=MD5&timeStamp=%s&key=%s"
  136. str := fmt.Sprintf(template, payObj.AppID, nonceStr, pack, strconv.FormatInt(timestamp, 10), payObj.PayKey)
  137. sign := util.MD5Sum(str)
  138. payCfg := pay.Config{timestamp, nonceStr, prePayID, "MD5", sign}
  139. exPayConfig := JSAPIPayConfig{}
  140. exPayConfig.AppId = wxConfig.AppId
  141. exPayConfig.NonceStr = payCfg.NonceStr
  142. exPayConfig.OutTradeNo = params.OutTradeNo
  143. exPayConfig.Package = "prepay_id=" + payCfg.PrePayID
  144. exPayConfig.PaySign = payCfg.Sign
  145. exPayConfig.SignType = payCfg.SignType
  146. exPayConfig.Timestamp = strconv.Itoa(int(payCfg.Timestamp))
  147. if err==nil {
  148. return &exPayConfig, nil
  149. }else{
  150. return nil, err
  151. }
  152. }
  153. // 关闭订单
  154. func CloseOrder(outTradeNo string)(*pay.CloseOrderResult, error){
  155. return wc.GetPay().CloseOrder(outTradeNo)
  156. }
  157. // 获取微信OAuth认证参数
  158. func GetOAuthParams(paramMap map[string]string)(*WxOAuthConfig, error){
  159. config := WxOAuthConfig{}
  160. urlstr := wxConfig.RedirectUrl
  161. paramstr := ""
  162. for k, v := range paramMap{
  163. paramstr += fmt.Sprintf("%s=%s", k, url.QueryEscape(v))
  164. }
  165. if strings.Index(urlstr, "%s") > 0{
  166. urlstr = fmt.Sprintf(urlstr, paramstr)
  167. }
  168. url, err := wxoauth.GetRedirectURL(urlstr, wxConfig.Scope, url.QueryEscape(wxConfig.State))
  169. if err != nil{
  170. return nil, err
  171. }
  172. config.OAuthRedirectUrl = url
  173. config.AppId = wxConfig.AppId
  174. config.State = wxConfig.State
  175. config.Scope = wxConfig.Scope
  176. config.ResponseType = wxConfig.ResponseType
  177. config.AuthUrl = "https://open.weixin.qq.com/connect/oauth2/authorize"
  178. config.RedirectUrl = wxConfig.RedirectUrl
  179. return &config, nil
  180. }
  181. // 获取jssdk配置参数
  182. func GetJSSDKRarams(url string)(*js.Config, error){
  183. return wc.GetJs().GetConfig(url)
  184. }
  185. // 获取token
  186. func GetOpenId(code string)(string, error){
  187. resToken, err := wxoauth.GetUserAccessToken(code)
  188. if err == nil{
  189. addToken(resToken.OpenID, &resToken)
  190. }
  191. return resToken.OpenID, err
  192. }
  193. // 根据code获取用户信息(需scope为 snsapi_userinfo)
  194. func GetUserInfoByCode(code string)(*oauth.UserInfo, error){
  195. openId, err := GetOpenId(code)
  196. if err != nil{
  197. return nil, err
  198. }
  199. return GetUserInfo(openId)
  200. }
  201. // 获取用户信息(需scope为 snsapi_userinfo)
  202. func GetUserInfo(openId string)(*oauth.UserInfo, error){
  203. token := getToken(openId)
  204. if token == nil{
  205. return nil, errors.New("token of openid " + openId + "does not exist")
  206. }
  207. userInfo, err := wxoauth.GetUserInfo(token.AccessToken, openId)
  208. return &userInfo, err
  209. }
  210. /**
  211. * @brief: 根据资源id从微信下载
  212. * @param1 resId: 资源id
  213. * @param2 tagFile: 目标文件
  214. * @return: 错误信息
  215. */
  216. func Download(resId, tagFile string)error{
  217. token, err := wc.GetAccessToken()
  218. if err != nil{
  219. fmt.Println("wc.GetAccessToken()错误", err.Error())
  220. return err
  221. }
  222. mediaUrl := "https://api.weixin.qq.com/cgi-bin/media/get"
  223. downloadUrl := mediaUrl + "?access_token=" + token + "&media_id=" + resId
  224. res, err := http.Get(downloadUrl)
  225. if err != nil{
  226. fmt.Println("请求资源错误:" + err.Error())
  227. return err
  228. }
  229. f, err := os.Create(tagFile)
  230. if err != nil {
  231. fmt.Println("本地创建资源文件:" + err.Error())
  232. return err
  233. }
  234. _, err = io.Copy(f, res.Body)
  235. if err != nil{
  236. fmt.Println("写入本地资源文件:" + err.Error())
  237. return err
  238. }else{
  239. return nil
  240. }
  241. }