util.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. package pay
  2. import (
  3. "crypto"
  4. "crypto/rand"
  5. "crypto/rsa"
  6. "crypto/sha256"
  7. "crypto/x509"
  8. "encoding/base64"
  9. "encoding/pem"
  10. "errors"
  11. "fmt"
  12. "hash"
  13. "log"
  14. "strings"
  15. "sync"
  16. "time"
  17. config "bp.jydev.jianyu360.cn/BaseService/payCenter/entity"
  18. // "util"
  19. qutil "app.yhyue.com/moapp/jybase/common"
  20. )
  21. /*
  22. 数据库字段 | 页面dotype
  23. -----------------------
  24. vip订阅 | subvip
  25. 企业商机管理 | entniche
  26. 历史数据 | dataexport
  27. 招投标课程 | course
  28. 数据报告 | datareport
  29. 中标必听课 | onlineCourse
  30. 大会员 | member
  31. AI中标预测包 | aiForecastPack
  32. 招标文件解读 | bidfile
  33. */
  34. var (
  35. vipMap = map[string]string{
  36. "wx_js": WX_SUBVIP_JSAPI,
  37. "wx_app": WX_SUBVIP_APP,
  38. "wx_pc": WX_SUBVIP_NATIVE,
  39. "ali_app": ALI_SUBVIP_APP,
  40. "ali_pc": ALI_SUBVIP_NATIVE,
  41. }
  42. entnicheMap = map[string]string{
  43. "wx_app": WX_ENTNICHE_APP,
  44. "wx_pc": WX_ENTNICHE_NATIVE,
  45. "ali_app": ALI_ENTNICHE_APP,
  46. "ali_pc": ALI_ENTNICHE_NATIVE,
  47. //"wx_js": "",
  48. }
  49. dataexportMap = map[string]string{
  50. "wx_js": WX_DATAEXPORT_JSAPI,
  51. "wx_app": WX_DATAEXPORT_APP,
  52. "wx_pc": WX_DATAEXPORT_NATIVE,
  53. "ali_app": ALI_DATAEXPORT_APP,
  54. "ali_pc": ALI_DATAEXPORT_NATIVE,
  55. }
  56. courseMap = map[string]string{
  57. "wx_js": WX_COURSE_JSAPI,
  58. "wx_app": WX_COURSE_APP,
  59. "wx_pc": WX_COURSE_NATIVE,
  60. "ali_app": ALI_COURSE_APP,
  61. "ali_pc": ALI_COURSE_NATIVE,
  62. }
  63. datareportMap = map[string]string{
  64. "wx_js": WX_DATAREPORT_JSAPI,
  65. "wx_app": WX_DATAREPORT_APP,
  66. "wx_pc": WX_DATAREPORT_NATIVE,
  67. "ali_app": ALI_DATAREPORT_APP,
  68. "ali_pc": ALI_DATAREPORT_NATIVE,
  69. }
  70. onlineCourseMap = map[string]string{
  71. "wx_js": WX_COURSEONLINE_JSAPI,
  72. "wx_app": WX_COURSEONLINE_APP,
  73. "wx_pc": WX_COURSEONLINE_NATIVE,
  74. "ali_app": ALI_COURSEONLINE_APP,
  75. "ali_pc": ALI_COURSEONLINE_NATIVE,
  76. }
  77. //大会员
  78. memberMap = map[string]string{
  79. "wx_js": WX_MEMBER_JSAPI,
  80. "wx_app": WX_MEMBER_APP,
  81. "wx_pc": WX_MEMBER_NATIVE,
  82. "ali_app": ALI_MEMBER_APP,
  83. "ali_pc": ALI_MEMBER_NATIVE,
  84. }
  85. //AI中标预测包
  86. aiForecastPackMap = map[string]string{
  87. "wx_js": WX_AIFORECASTPACK_JSAPI,
  88. "wx_app": WX_AIFORECASTPACK_APP,
  89. "wx_pc": WX_AIFORECASTPACK_NATIVE,
  90. "ali_app": ALI_AIFORECASTPACK_APP,
  91. "ali_pc": ALI_AIFORECASTPACK_NATIVE,
  92. }
  93. bifileMap = map[string]string{
  94. "wx_js": WX_BIDFILE_JSAPI,
  95. "wx_app": WX_BIDFILE_APP,
  96. "wx_pc": WX_BIDFILE_NATIVE,
  97. "ali_app": ALI_BIDFILE_APP,
  98. "ali_pc": ALI_BIDFILE_NATIVE,
  99. }
  100. //剑鱼币
  101. integralMap = map[string]string{
  102. "wx_js": WX_INTEGRAL_JSAPI,
  103. "wx_app": WX_INTEGRAL_APP,
  104. "wx_pc": WX_INTEGRAL_NATIVE,
  105. "ali_app": ALI_INTEGRAL_APP,
  106. "ali_pc": ALI_INTEGRAL_NATIVE,
  107. }
  108. //数据流量包
  109. dataPackMap = map[string]string{
  110. "wx_js": WX_DATAPACK_JSAIP,
  111. "wx_app": WX_DATAPACK_APP,
  112. "wx_pc": WX_DATAPACK_NATIVE,
  113. "ali_app": ALI_DATAPACK_APP,
  114. "ali_pc": ALI_DATAPACK_NATIVE,
  115. }
  116. //省份订阅包
  117. areaPackMap = map[string]string{
  118. "wx_js": WX_AREAPACK_JSAPI,
  119. "wx_app": WX_AREAPACK_APP,
  120. "wx_pc": WX_AREAPACK_NATIVE,
  121. "ali_app": ALI_AREAPACK_APP,
  122. "ali_pc": ALI_AREAPACK_NATIVE,
  123. }
  124. //附件下载包
  125. filePackMap = map[string]string{
  126. "wx_js": WX_FILEPACK_JSAPI,
  127. "wx_app": WX_FILEPACK_APP,
  128. "wx_pc": WX_FILEPACK_NATIVE,
  129. "ali_app": ALI_FILEPACK_APP,
  130. "ali_pc": ALI_FILEPACK_NATIVE,
  131. }
  132. //采购单位画像包
  133. buyerPortraitPackMap = map[string]string{
  134. "wx_js": WX_BUYERPORTRAITPACK_JSAPI,
  135. "wx_app": WX_BUYERPORTRAITPACK_APP,
  136. "wx_pc": WX_BUYERPORTRAITPACK_NATIVE,
  137. "ali_app": ALI_BUYERPORTRAITPACK_APP,
  138. "ali_pc": ALI_BUYERPORTRAITPACK_NATIVE,
  139. }
  140. PayWayAndSign = map[string]map[string]string{
  141. "subvip": vipMap,
  142. "entniche": entnicheMap,
  143. "dataexport": dataexportMap,
  144. "course": courseMap,
  145. "datareport": datareportMap,
  146. "onlineCourse": onlineCourseMap,
  147. "member": memberMap,
  148. "aiForecastPack": aiForecastPackMap,
  149. "bidfile": bifileMap,
  150. "integral": integralMap,
  151. "areaPack": areaPackMap,
  152. "filePack": filePackMap,
  153. "buyerPortraitPack": buyerPortraitPackMap,
  154. "VIP订阅": vipMap,
  155. "企业商机管理": entnicheMap,
  156. "历史数据": dataexportMap,
  157. "招投标课程": courseMap,
  158. "数据报告": datareportMap,
  159. "中标必听课": onlineCourseMap,
  160. "大会员": memberMap,
  161. "大会员-AI中标预测包": aiForecastPackMap,
  162. "招标文件解读": bifileMap,
  163. "大会员-招标文件解读": bifileMap,
  164. "剑鱼币": integralMap,
  165. "数据流量包": dataPackMap,
  166. "省份订阅包": areaPackMap,
  167. "附件下载包": filePackMap,
  168. "采购单位画像包": buyerPortraitPackMap,
  169. }
  170. varOrderCode *orderCode
  171. ProductType = map[string]string{
  172. "subvip": "VIP订阅",
  173. "entniche": "企业商机管理",
  174. "dataexport": "历史数据",
  175. "datareport": "数据报告",
  176. "onlineCourse": "中标必听课",
  177. "member": "大会员",
  178. "aiForecastPack": "大会员-AI中标预测包",
  179. "integral": "剑鱼币",
  180. "dataPack": "数据流量包",
  181. "areaPack": "省份订阅包",
  182. "filePack": "附件下载包",
  183. }
  184. )
  185. type orderCode struct {
  186. pool chan string
  187. all *sync.Map
  188. lock *sync.Mutex
  189. }
  190. func (o *orderCode) gc() {
  191. varOrderCode.all.Range(func(key, value interface{}) bool {
  192. if time.Now().Day() != value.(int) {
  193. varOrderCode.all.Delete(key)
  194. }
  195. return true
  196. })
  197. time.AfterFunc(24*time.Hour, o.gc)
  198. }
  199. func init() {
  200. varOrderCode = &orderCode{
  201. pool: make(chan string, 20),
  202. all: &sync.Map{},
  203. lock: &sync.Mutex{},
  204. }
  205. varOrderCode.gc()
  206. for i := 0; i < 10; i++ {
  207. go func() {
  208. varOrderCode.lock.Lock()
  209. defer varOrderCode.lock.Unlock()
  210. for {
  211. o := fmt.Sprintf("%d%s", time.Now().Unix()+900000000, qutil.GetRandom(2))
  212. if _, ok := varOrderCode.all.Load(o); ok {
  213. continue
  214. }
  215. varOrderCode.all.Store(o, time.Now().Day())
  216. varOrderCode.pool <- o
  217. }
  218. }()
  219. }
  220. }
  221. /*
  222. 公共创建订单
  223. price 价格
  224. productSign 产品种类标识
  225. ip 用户ip(仅微信支付需要)
  226. openid 用户openid(仅微信支付需要)
  227. payWay 支付方式
  228. */
  229. func CreateOrderPay(price int, productSign, ip, openid, payWay string) (tradeno, prepayid, payParam string, err error) {
  230. switch payWay {
  231. case "wx_js", "wx_app", "wx_pc": //微信公众号支付,微信app支付,微信扫码支付
  232. var ret *map[string]string
  233. tradeno, ret = WxStruct.CreatePrepayOrder(productSign, ip, openid, "", price)
  234. log.Println(tradeno, ret)
  235. if ret == nil {
  236. err = errors.New("创建异常")
  237. return
  238. }
  239. if (*ret)["status"] != "1" {
  240. errMsg := "创建微信订单出错"
  241. if (*ret)["errcodedes"] != "" {
  242. errMsg = (*ret)["errcodedes"]
  243. } else if (*ret)["errcode"] != "" {
  244. errMsg = (*ret)["errcode"]
  245. }
  246. err = errors.New(errMsg)
  247. return
  248. }
  249. prepayid = qutil.ObjToString((*ret)["prepayid"])
  250. if payWay == "wx_js" {
  251. payParam = WxStruct.GetWxjsPaySign(prepayid)
  252. } else if payWay == "wx_app" {
  253. payParam = WxStruct.GetAppWxPayStr(prepayid)
  254. } else if payWay == "wx_pc" {
  255. payParam = (*ret)["codeurl"]
  256. }
  257. case "ali_app", "ali_pc": //支付宝app支付,支付宝扫码支付
  258. payParam, tradeno, err = Alipay.GetOrderPayParam(qutil.Float64All(price), productSign)
  259. if err != nil {
  260. err = errors.New("创建支付宝订单出错")
  261. return
  262. }
  263. }
  264. return
  265. }
  266. //创建订单号
  267. func GetOrderCode(id ...string) string {
  268. //2020-08-01之前的规则 fmt.Sprintf("%s%s", time.Now().Format("150405"), qutil.GetRandom(6))
  269. return <-varOrderCode.pool
  270. }
  271. //关闭订单
  272. func CloseDataExportOrder(payWay, tradeno, prepayTime string) (status bool) {
  273. //如果订单超时 则不用关闭订单
  274. t, err := time.ParseInLocation("2006-01-02 15:04:05", prepayTime, time.Local)
  275. if err == nil {
  276. if t.Add(time.Hour * 2).Before(time.Now()) {
  277. return true
  278. }
  279. }
  280. //没有选择支付方式或者是测试数据
  281. if payWay == "" || payWay == "测试使用" || payWay == "transferAccounts" || tradeno == "" {
  282. return true
  283. }
  284. log.Printf("%s取消订单,订单号%s\n", payWay, tradeno)
  285. if strings.HasPrefix(payWay, "ali_") {
  286. status = Alipay.CloseOrder(tradeno)
  287. } else if strings.HasPrefix(payWay, "wx_") {
  288. status = WxStruct.CloseOrder(tradeno, payWay)
  289. }
  290. if !status {
  291. log.Printf("%s订单关闭失败:%s\n", payWay, tradeno)
  292. }
  293. return status
  294. }
  295. //加载秘钥
  296. func parsePrivateKey(key string) (*rsa.PrivateKey, error) {
  297. block, _ := pem.Decode([]byte(key))
  298. if block == nil {
  299. return nil, errors.New("私钥格式不正确")
  300. }
  301. if strings.ToUpper(block.Type) != "RSA PRIVATE KEY" {
  302. return nil, errors.New("私钥类型不正确" + block.Type)
  303. }
  304. rsaPrivateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
  305. if err != nil {
  306. return nil, err
  307. }
  308. return rsaPrivateKey.(*rsa.PrivateKey), nil
  309. }
  310. //加载支付宝后台公钥
  311. func parseAliPayPublicKey(key string) (*rsa.PublicKey, error) {
  312. publicKeyDecoded, err := base64.StdEncoding.DecodeString(key)
  313. if err != nil {
  314. return nil, err
  315. }
  316. pub, err := x509.ParsePKIXPublicKey(publicKeyDecoded)
  317. if err != nil {
  318. return nil, err
  319. }
  320. if pub, ok := pub.(*rsa.PublicKey); ok {
  321. return pub, nil
  322. }
  323. return nil, errors.New("rsa.PublicKey 断言出错")
  324. }
  325. //生成加密token
  326. func (a *aliPayStruct) getSign(data []byte) (signature string, err error) {
  327. var h hash.Hash
  328. var hType crypto.Hash
  329. h = sha256.New()
  330. hType = crypto.SHA256
  331. //}
  332. h.Write(data)
  333. d := h.Sum(nil)
  334. bs, err := rsa.SignPKCS1v15(rand.Reader, a.PrivateKey, hType, d)
  335. if err != nil {
  336. return "", err
  337. }
  338. signature = base64.StdEncoding.EncodeToString(bs)
  339. return
  340. }
  341. //处理商户订单号
  342. func processTradeno(tradeno string) string {
  343. devTradenoSign := qutil.ObjToString(config.PayConf["devTradenoSign"])
  344. if devTradenoSign != "" {
  345. tradeno = devTradenoSign + tradeno
  346. tradeno = string([]rune(tradeno)[:len([]rune(tradeno))-len([]rune(devTradenoSign))])
  347. }
  348. return tradeno
  349. }