wxPay.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. package pay
  2. import (
  3. "encoding/json"
  4. "encoding/xml"
  5. "fmt"
  6. "log"
  7. "net/rpc"
  8. "time"
  9. util "app.yhyue.com/moapp/jybase/common"
  10. config "bp.jydev.jianyu360.cn/BaseService/payCenter/entity"
  11. )
  12. const (
  13. WX_REWARD_JSAPI = "a" //微信打赏
  14. WX_DATAEXPORT_NATIVE = "b" //数据导出-扫码支付
  15. WX_DATAEXPORT_JSAPI = "c" //数据导出-微信js支付
  16. WX_DATAEXPORT_APP = "C" //数据导出-微信app支付
  17. WX_DATAREPORT_JSAPI = "d" //数据报告-微信js支付
  18. WX_DATAREPORT_APP = "D" //数据报告-微信app支付
  19. WX_SUBVIP_JSAPI = "e" //VIP订阅-js支付
  20. WX_SUBVIP_APP = "E" //VIP订阅-APP支付
  21. WX_COURSE_JSAPI = "f" //剑鱼招投标课程-js支付
  22. WX_COURSE_APP = "F" //剑鱼招投标课程-APP支付
  23. WX_COURSE_NATIVE = "g" //剑鱼招投标课程-扫码支付
  24. WX_ENTNICHE_APP = "H" //企业商机管理-APP支付
  25. WX_COURSEONLINE_JSAPI = "i" //课程线上课程-js支付
  26. WX_COURSEONLINE_APP = "I" //剑鱼线上课程-APP支付
  27. WX_COURSEONLINE_NATIVE = "j" //剑鱼线上课程-扫码支付
  28. WX_DATAREPORT_NATIVE = "k" //数据报告-扫码支付
  29. WX_SUBVIP_NATIVE = "l" //VIP订阅-扫码支付
  30. WX_ENTNICHE_NATIVE = "m" //商机管理-pc支付
  31. WX_MEMBER_JSAPI = "n" //大会员-微信js支付
  32. WX_MEMBER_APP = "N" //大会员-APP支付
  33. WX_MEMBER_NATIVE = "o" //大会员-PC支付
  34. WX_AIFORECASTPACK_JSAPI = "P" //大会员-AI中标预测包-微信js支付
  35. WX_AIFORECASTPACK_APP = "p" //大会员-AI中标预测包-APP支付
  36. WX_AIFORECASTPACK_NATIVE = "q" //大会员-AI中标预测包-PC支付
  37. WX_BIDFILE_JSAPI = "R" //招标文件解读-微信js支付
  38. WX_BIDFILE_APP = "r" //招标文件解读-APP支付
  39. WX_BIDFILE_NATIVE = "S" //招标文件解读-PC支付
  40. WX_INTEGRAL_JSAPI = "AA" //剑鱼币-微信js支付
  41. WX_INTEGRAL_APP = "AB" //剑鱼币-APP支付
  42. WX_INTEGRAL_NATIVE = "AC" //剑鱼币-PC支付
  43. /*新命名规范
  44. A 「ali阿里支付宝支付」 W 「wx微信支付」
  45. A 「app支付」 J「js支付*仅微信端有」 P「pc扫码支付」
  46. P 「产品标识」 pack 数据包
  47. */
  48. WX_DATAPACK_JSAIP = "WJP" //数据包-微信js支付
  49. WX_DATAPACK_APP = "WAP" //数据包-app支付
  50. WX_DATAPACK_NATIVE = "WPP" //数据包-pc支付
  51. WX_AREAPACK_JSAPI = "WJA" //省份订阅包 微信js支付
  52. WX_AREAPACK_APP = "WAA" //省份订阅包 app微信支付
  53. WX_AREAPACK_NATIVE = "WPA" //省份订阅包 微信pc支付
  54. WX_FILEPACK_JSAPI = "WJF" //附件下载包 微信js支付
  55. WX_FILEPACK_APP = "WAF" //附件下载包 app微信支付
  56. WX_FILEPACK_NATIVE = "WPF" //附件下载包 微信pc支付
  57. WX_BUYERPORTRAITPACK_JSAPI = "WJB" //采购单位画像包 微信js支付
  58. WX_BUYERPORTRAITPACK_APP = "WAB" //采购单位画像包 app微信支付
  59. WX_BUYERPORTRAITPACK_NATIVE = "WPB" //采购单位画像包 微信pc支付
  60. )
  61. var WxStruct *WeixinStruct
  62. type WeixinStruct struct {
  63. Appid string
  64. Mchid string
  65. Appid_app string //微信支付和app支付appid不一致
  66. Key string
  67. Dashang_attachmsg string
  68. Dashang_bodymsg string
  69. Dashang_detailmsg string
  70. sjdc_msg string
  71. Sjbg_msg string
  72. Subvip_msg string
  73. Entniche_msg string
  74. Course_msg string
  75. CourseOnline_msg string
  76. Member_msg string
  77. Aiforecastpage_msg string
  78. Bidfile_msg string
  79. OpenidSwitch *map[string]interface{}
  80. Integral_msg string
  81. DataPack_msg string
  82. AreaPack_msg string
  83. FilePack_msg string
  84. BuyerPortraitPack_msg string
  85. }
  86. func init() {
  87. //payConfig := config.WxPayConf["pay"].(map[string]interface{})
  88. //
  89. //WxStruct = &WeixinStruct{
  90. // Appid: util.ObjToString(config.WxPayConf["appid"]),
  91. // Appid_app: util.ObjToString(config.WxPayConf["appid_app"]),
  92. // Mchid: util.ObjToString(payConfig["mchid"]),
  93. // Key: util.ObjToString(payConfig["key"]),
  94. // Dashang_attachmsg: util.ObjToString(payConfig["attachmsg"]),
  95. // Dashang_bodymsg: util.ObjToString(payConfig["bodymsg"]),
  96. // Dashang_detailmsg: util.ObjToString(payConfig["detailmsg"]),
  97. // sjdc_msg: util.ObjToString(payConfig["sjdc_msg"]),
  98. // Sjbg_msg: util.ObjToString(payConfig["sjbg_msg"]),
  99. // Subvip_msg: util.ObjToString(payConfig["subvip_msg"]),
  100. // Entniche_msg: util.ObjToString(payConfig["entniche_msg"]),
  101. // Course_msg: util.ObjToString(payConfig["course_msg"]),
  102. // CourseOnline_msg: util.ObjToString(payConfig["courseOnline_msg"]),
  103. // Member_msg: util.ObjToString(payConfig["member_msg"]),
  104. // Aiforecastpage_msg: util.ObjToString(payConfig["aiforecastpage_msg"]),
  105. // Bidfile_msg: util.ObjToString(payConfig["bidfile_msg"]),
  106. // OpenidSwitch: util.ObjToMap(config.WxPayConf["openidSwitch"]),
  107. // Integral_msg: util.ObjToString(payConfig["integral_msg"]),
  108. // DataPack_msg: util.ObjToString(payConfig["dataPack_msg"]),
  109. // AreaPack_msg: util.ObjToString(payConfig["areaPack_msg"]),
  110. // FilePack_msg: util.ObjToString(payConfig["filePack_msg"]),
  111. // BuyerPortraitPack_msg: util.ObjToString(payConfig["buyerPortraitPack_msg"]),
  112. //}
  113. }
  114. func (w *WeixinStruct) GetTradeno(tp string) string {
  115. lenRandom := 6 - len([]rune(tp)) //控制长度
  116. tradeno := fmt.Sprintf("%s_%d%s%s", tp, time.Now().UnixNano(), util.GetRandom(lenRandom), util.GetLetterRandom(6))
  117. tradeno = processTradeno(tradeno)
  118. return tradeno
  119. }
  120. //tradeno a:打赏 b:pc端数据导出 c:移动端微信数据导出 C:app数据导出 d:微信端数据报告 D:app端数据报告
  121. func (w *WeixinStruct) CreatePrepayOrder(tradeno, ip, openid, detailmsg string, totalfee int) (string, *map[string]string) {
  122. defer util.Catch()
  123. //测试环境,1分钱
  124. // if config.Config.AllPayMoney > 0 {
  125. // totalfee = config.Config.AllPayMoney
  126. // }
  127. notifyUrl := util.ObjToString(config.PayConf["webdomain"]) + "/jypay/callback/wxPay"
  128. //获取支付标题
  129. attachmsg, bodymsg := "", ""
  130. if tradeno == WX_REWARD_JSAPI { //打赏
  131. attachmsg, bodymsg = w.Dashang_attachmsg, w.Dashang_bodymsg
  132. } else if tradeno == WX_DATAEXPORT_NATIVE || tradeno == WX_DATAEXPORT_JSAPI || tradeno == WX_DATAEXPORT_APP { //数据导出
  133. attachmsg, bodymsg, detailmsg = w.sjdc_msg, w.sjdc_msg, w.sjdc_msg
  134. } else if tradeno == WX_DATAREPORT_JSAPI || tradeno == WX_DATAREPORT_APP || tradeno == WX_DATAREPORT_NATIVE { //数据报告
  135. attachmsg, bodymsg, detailmsg = w.Sjbg_msg, w.Sjbg_msg, w.Sjbg_msg
  136. } else if tradeno == WX_SUBVIP_JSAPI || tradeno == WX_SUBVIP_APP || tradeno == WX_SUBVIP_NATIVE { //vip订阅
  137. attachmsg, bodymsg, detailmsg = w.Subvip_msg, w.Subvip_msg, w.Subvip_msg
  138. } else if tradeno == WX_COURSE_NATIVE || tradeno == WX_COURSE_APP || tradeno == WX_COURSE_JSAPI { //招投标课程
  139. attachmsg, bodymsg, detailmsg = w.Course_msg, w.Course_msg, w.Course_msg
  140. } else if tradeno == WX_ENTNICHE_APP || tradeno == WX_ENTNICHE_NATIVE {
  141. attachmsg, bodymsg, detailmsg = w.Entniche_msg, w.Entniche_msg, w.Entniche_msg
  142. } else if tradeno == WX_COURSEONLINE_APP || tradeno == WX_COURSEONLINE_JSAPI || tradeno == WX_COURSEONLINE_NATIVE {
  143. attachmsg, bodymsg, detailmsg = w.CourseOnline_msg, w.CourseOnline_msg, w.CourseOnline_msg
  144. } else if tradeno == WX_MEMBER_NATIVE || tradeno == WX_MEMBER_APP || tradeno == WX_MEMBER_JSAPI {
  145. attachmsg, bodymsg, detailmsg = w.Member_msg, w.Member_msg, w.Member_msg
  146. } else if tradeno == WX_AIFORECASTPACK_APP || tradeno == WX_AIFORECASTPACK_JSAPI || tradeno == WX_AIFORECASTPACK_NATIVE {
  147. attachmsg, bodymsg, detailmsg = w.Aiforecastpage_msg, w.Aiforecastpage_msg, w.Aiforecastpage_msg
  148. } else if tradeno == WX_BIDFILE_APP || tradeno == WX_BIDFILE_JSAPI || tradeno == WX_BIDFILE_NATIVE {
  149. attachmsg, bodymsg, detailmsg = w.Bidfile_msg, w.Bidfile_msg, w.Bidfile_msg
  150. } else if tradeno == WX_INTEGRAL_APP || tradeno == WX_INTEGRAL_JSAPI || tradeno == WX_INTEGRAL_NATIVE {
  151. attachmsg, bodymsg, detailmsg = w.Integral_msg, w.Integral_msg, w.Integral_msg
  152. } else if tradeno == WX_DATAPACK_APP || tradeno == WX_DATAPACK_JSAIP || tradeno == WX_DATAPACK_NATIVE {
  153. attachmsg, bodymsg, detailmsg = w.DataPack_msg, w.DataPack_msg, w.DataPack_msg
  154. } else if tradeno == WX_AREAPACK_APP || tradeno == WX_AREAPACK_JSAPI || tradeno == WX_AREAPACK_NATIVE {
  155. attachmsg, bodymsg, detailmsg = w.AreaPack_msg, w.AreaPack_msg, w.AreaPack_msg
  156. } else if tradeno == WX_FILEPACK_APP || tradeno == WX_FILEPACK_JSAPI || tradeno == WX_FILEPACK_NATIVE {
  157. attachmsg, bodymsg, detailmsg = w.FilePack_msg, w.FilePack_msg, w.FilePack_msg
  158. } else if tradeno == WX_BUYERPORTRAITPACK_APP || tradeno == WX_BUYERPORTRAITPACK_JSAPI || tradeno == WX_BUYERPORTRAITPACK_NATIVE {
  159. attachmsg, bodymsg, detailmsg = w.BuyerPortraitPack_msg, w.BuyerPortraitPack_msg, w.BuyerPortraitPack_msg
  160. }
  161. //支付类型分类
  162. tradeType, appid := "", w.Appid
  163. if tradeno == WX_REWARD_JSAPI || tradeno == WX_DATAEXPORT_JSAPI || tradeno == WX_DATAREPORT_JSAPI || tradeno == WX_SUBVIP_JSAPI || tradeno == WX_COURSE_JSAPI || tradeno == WX_COURSEONLINE_JSAPI || tradeno == WX_MEMBER_JSAPI || tradeno == WX_AIFORECASTPACK_JSAPI || tradeno == WX_BIDFILE_JSAPI || tradeno == WX_INTEGRAL_JSAPI || tradeno == WX_DATAPACK_JSAIP || tradeno == WX_AREAPACK_JSAPI || tradeno == WX_FILEPACK_JSAPI || tradeno == WX_BUYERPORTRAITPACK_JSAPI { //微信js支付
  164. tradeType = "JSAPI"
  165. } else if tradeno == WX_DATAEXPORT_APP || tradeno == WX_DATAREPORT_APP || tradeno == WX_SUBVIP_APP || tradeno == WX_COURSE_APP || tradeno == WX_ENTNICHE_APP || tradeno == WX_COURSEONLINE_APP || tradeno == WX_MEMBER_APP || tradeno == WX_AIFORECASTPACK_APP || tradeno == WX_BIDFILE_APP || tradeno == WX_INTEGRAL_APP || tradeno == WX_DATAPACK_APP || tradeno == WX_AREAPACK_APP || tradeno == WX_FILEPACK_APP || tradeno == WX_BUYERPORTRAITPACK_APP { //app支付
  166. tradeType = "APP"
  167. appid = w.Appid_app
  168. } else if tradeno == WX_DATAEXPORT_NATIVE || tradeno == WX_COURSE_NATIVE || tradeno == WX_COURSEONLINE_NATIVE || tradeno == WX_DATAREPORT_NATIVE || tradeno == WX_ENTNICHE_NATIVE || tradeno == WX_SUBVIP_NATIVE || tradeno == WX_MEMBER_NATIVE || tradeno == WX_AIFORECASTPACK_NATIVE || tradeno == WX_BIDFILE_NATIVE || tradeno == WX_INTEGRAL_NATIVE || tradeno == WX_DATAPACK_NATIVE || tradeno == WX_AREAPACK_NATIVE || tradeno == WX_FILEPACK_NATIVE || tradeno == WX_BUYERPORTRAITPACK_NATIVE { //扫码支付
  169. tradeType = "NATIVE"
  170. }
  171. tradeno = w.GetTradeno(tradeno)
  172. //测试环境微信支付需要转换对应的正式环境的openid
  173. if w.OpenidSwitch != nil {
  174. if oid, ok := (*(w.OpenidSwitch))[openid]; ok {
  175. openid = oid.(string)
  176. }
  177. }
  178. //获取预订单号
  179. ret, _ := w.GetPrepayId(util.ObjToString(config.PayConf["weixinrpc"]), map[string]string{
  180. "attachmsg": attachmsg,
  181. "bodymsg": bodymsg,
  182. "detailmsg": detailmsg,
  183. "useropenid": openid,
  184. "tradeno": tradeno,
  185. "userip": ip,
  186. "totalfee": fmt.Sprint(totalfee),
  187. "mchid": w.Mchid,
  188. "key": w.Key,
  189. "notifyUrl": notifyUrl,
  190. "appid": appid,
  191. "tradeType": tradeType, //NATIVE JSAPI APP
  192. })
  193. return tradeno, ret
  194. }
  195. //取得预生成订单编号,我们的系统要控制下,别订单重复了
  196. func (w *WeixinStruct) GetPrepayId(weixinrpc string, param map[string]string) (res *map[string]string, e error) {
  197. util.Try(func() {
  198. client, err := rpc.DialHTTP("tcp", weixinrpc)
  199. defer client.Close()
  200. if err != nil {
  201. e = err
  202. log.Println(err.Error())
  203. return
  204. }
  205. var ret []byte
  206. err = client.Call("WeiXinRpc.GetPrepayId", param, &ret)
  207. if err != nil {
  208. e = err
  209. log.Println(err.Error())
  210. } else {
  211. json.Unmarshal(ret, &res)
  212. }
  213. }, func(e interface{}) {})
  214. return
  215. }
  216. //微信支付订单关闭
  217. func (w *WeixinStruct) CloseOrder(tradeno, payWay string) (r bool) {
  218. util.Try(func() {
  219. client, err := rpc.DialHTTP("tcp", util.ObjToString(config.PayConf["weixinrpc"]))
  220. defer client.Close()
  221. if err != nil {
  222. return
  223. }
  224. err = client.Call("WeiXinRpc.CloseOrder",
  225. map[string]string{
  226. "tradeno": tradeno,
  227. "key": w.Key,
  228. "mchid": w.Mchid,
  229. "appid": w.Appid,
  230. }, &r)
  231. if err != nil {
  232. log.Println(err.Error())
  233. return
  234. }
  235. }, func(e interface{}) {})
  236. return r
  237. }
  238. //微信js支付获取支付参数
  239. func (w *WeixinStruct) GetWxjsPaySign(prepayid string) string {
  240. timestamp := time.Now().Unix()
  241. nonceStr := util.GetRandom(16) + util.GetLetterRandom(16)
  242. sign := util.WxSign(fmt.Sprintf("appId=%s&nonceStr=%s&package=%s&signType=%s&timeStamp=%d&key=%s", w.Appid, nonceStr, "prepay_id="+prepayid, "MD5", timestamp, w.Key))
  243. res := map[string]interface{}{
  244. "appId": w.Appid,
  245. "timestamp": fmt.Sprint(timestamp),
  246. "signType": "MD5",
  247. "sign": sign,
  248. "nonceStr": nonceStr,
  249. "prepayId": "prepay_id=" + prepayid,
  250. }
  251. byteArr, _ := json.Marshal(res)
  252. return string(byteArr)
  253. }
  254. //微信app支付 获取支付串
  255. func (wx *WeixinStruct) GetAppWxPayStr(prepayid string) string {
  256. data := struct {
  257. XMLName xml.Name `xml:"xml"`
  258. Appid string `xml:"appid"`
  259. Partnerid string `xml:"partnerid"` //微信支付分配的商户号
  260. Prepayid string `xml:"prepayid"` //微信返回的支付交易会话ID
  261. PackageStr string `xml:"package"` //暂填写固定值Sign=WXPay
  262. Noncestr string `xml:"noncestr"` //随机字符串,不长于32位。
  263. Timestamp string `xml:"timestamp"` //时间戳
  264. Sign string `xml:"sign"` //签名
  265. }{
  266. Appid: wx.Appid_app,
  267. Partnerid: wx.Mchid,
  268. Prepayid: prepayid,
  269. PackageStr: "Sign=WXPay",
  270. Noncestr: util.GetRandom(16) + util.GetLetterRandom(16),
  271. Timestamp: fmt.Sprintf("%d", time.Now().Unix()),
  272. }
  273. data.Sign = util.CreateWxSign(fmt.Sprintf("&key=%s", wx.Key), data)
  274. byteArr, err := json.Marshal(data)
  275. if err != nil {
  276. log.Printf("CreatePrepayOrder Marshal %v\n", err)
  277. return ""
  278. }
  279. return string(byteArr)
  280. }
  281. //获取js支付参数(为方便存库返回string,前端需要转成json)
  282. func GetWxJsPayStr(prepayid string) string {
  283. //获取订单支付字符串
  284. nonceStr := util.GetRandom(16) + util.GetLetterRandom(16)
  285. timestamp := time.Now().Unix()
  286. sign := util.WxSign(fmt.Sprintf("appId=%s&nonceStr=%s&package=%s&signType=%s&timeStamp=%d&key=%s", WxStruct.Appid, nonceStr, "prepay_id="+prepayid, "MD5", timestamp, WxStruct.Key))
  287. m := map[string]interface{}{
  288. "appId": WxStruct.Appid,
  289. "timestamp": fmt.Sprint(timestamp),
  290. "signType": "MD5",
  291. "sign": sign,
  292. "nonceStr": nonceStr,
  293. "prepayId": "prepay_id=" + prepayid,
  294. }
  295. byteArr, err := json.Marshal(m)
  296. if err != nil {
  297. log.Println("GetWxJsPayStr ", err)
  298. return ""
  299. }
  300. return string(byteArr)
  301. }