蛋蛋星球-客户端
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 

608 rader
17 KiB

  1. package hdl
  2. import (
  3. "applet/app/cfg"
  4. "applet/app/db"
  5. "applet/app/e"
  6. alipay "applet/app/lib/gopay"
  7. "applet/app/md"
  8. "applet/app/svc"
  9. "applet/app/utils"
  10. "applet/app/utils/cache"
  11. "code.fnuoos.com/EggPlanet/egg_models.git/src/implement"
  12. "code.fnuoos.com/EggPlanet/egg_models.git/src/model"
  13. rule2 "code.fnuoos.com/EggPlanet/egg_system_rules.git"
  14. "code.fnuoos.com/EggPlanet/egg_system_rules.git/enum"
  15. enum2 "code.fnuoos.com/EggPlanet/egg_system_rules.git/enum"
  16. md2 "code.fnuoos.com/EggPlanet/egg_system_rules.git/md"
  17. "code.fnuoos.com/EggPlanet/egg_system_rules.git/rule"
  18. md3 "code.fnuoos.com/EggPlanet/egg_system_rules.git/rule/egg_energy/md"
  19. "code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit"
  20. "errors"
  21. "fmt"
  22. "github.com/gin-gonic/gin"
  23. "github.com/go-pay/gopay"
  24. alipay2 "github.com/go-pay/gopay/alipay"
  25. "github.com/jinzhu/copier"
  26. "time"
  27. )
  28. // GetAmountFlow
  29. // @Summary 蛋蛋星球-钱包-余额明细(获取)
  30. // @Tags 钱包
  31. // @Description 余额明细(获取)
  32. // @Accept json
  33. // @Produce json
  34. // @param Authorization header string true "验证参数Bearer和token空格拼接"
  35. // @Param limit query string true "每页大小"
  36. // @Param page query string true "页数"
  37. // @Param startAt query string false "开始时间"
  38. // @Param endAt query string false "结束时间"
  39. // @Param direction query string false "流水方向(1.收入 2.支出 0.全部)"
  40. // @Success 200 {object} md.GetAmountFlowResp "具体数据"
  41. // @Failure 400 {object} md.Response "具体错误"
  42. // @Router /api/v1/wallet/amountFlow [GET]
  43. func GetAmountFlow(c *gin.Context) {
  44. pageStr := c.DefaultQuery("page", "1")
  45. limitStr := c.DefaultQuery("limit", "10")
  46. startAt := c.Query("startAt")
  47. endAt := c.Query("endAt")
  48. directionStr := c.Query("direction")
  49. val, exists := c.Get("user")
  50. if !exists {
  51. e.OutErr(c, e.ERR_USER_CHECK_ERR, nil)
  52. return
  53. }
  54. user, ok := val.(*model.User)
  55. if !ok {
  56. e.OutErr(c, e.ERR_USER_CHECK_ERR, nil)
  57. return
  58. }
  59. direction := 0
  60. switch directionStr {
  61. case "1":
  62. direction = 1
  63. case "2":
  64. direction = 2
  65. }
  66. page := utils.StrToInt(pageStr)
  67. limit := utils.StrToInt(limitStr)
  68. flowDb := implement.NewUserWalletFlowDb(db.Db)
  69. flows, total, err := flowDb.UserWalletFlowFindByCoinAndUser(page, limit, user.Id, startAt, endAt, direction, false, 0, 0)
  70. if err != nil {
  71. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  72. return
  73. }
  74. list := make([]md.WalletFlowNode, 0, len(flows))
  75. for _, flow := range flows {
  76. temp := md.WalletFlowNode{
  77. Id: flow.Id,
  78. Uid: flow.Uid,
  79. Direction: flow.Direction,
  80. Amount: flow.Amount,
  81. BeforeAmount: flow.BeforeAmount,
  82. AfterAmount: flow.AfterAmount,
  83. SysFee: flow.SysFee,
  84. OrdId: flow.OrdId,
  85. Title: flow.Title,
  86. Kind: flow.Kind,
  87. State: flow.State,
  88. Memo: flow.Memo,
  89. CreateTime: flow.CreateAt,
  90. UpdateTime: flow.UpdateAt,
  91. }
  92. list = append(list, temp)
  93. }
  94. resp := md.GetAmountFlowResp{
  95. List: list,
  96. Paginate: md.Paginate{
  97. Limit: limit,
  98. Page: page,
  99. Total: total,
  100. },
  101. }
  102. e.OutSuc(c, resp, nil)
  103. }
  104. // WithdrawGetAmount
  105. // @Summary 蛋蛋星球-钱包-提现余额(获取)
  106. // @Tags 钱包
  107. // @Description 提现余额(获取)
  108. // @Accept json
  109. // @Produce json
  110. // @param Authorization header string true "验证参数Bearer和token空格拼接"
  111. // @Success 200 {object} md.WithdrawGetAmountResp "具体数据"
  112. // @Failure 400 {object} md.Response "具体错误"
  113. // @Router /api/v1/wallet/withdraw/index [GET]
  114. func WithdrawGetAmount(c *gin.Context) {
  115. val, exists := c.Get("user")
  116. if !exists {
  117. e.OutErr(c, e.ERR_USER_CHECK_ERR, nil)
  118. return
  119. }
  120. user, ok := val.(*model.User)
  121. if !ok {
  122. e.OutErr(c, e.ERR_USER_CHECK_ERR, nil)
  123. return
  124. }
  125. walletDb := implement.NewUserWalletDb(db.Db)
  126. wallet, err := walletDb.GetUserVirtualWallet(user.Id)
  127. if err != nil {
  128. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  129. return
  130. }
  131. resp := md.WithdrawGetAmountResp{
  132. Amount: wallet.Amount,
  133. }
  134. e.OutSuc(c, resp, nil)
  135. }
  136. // WithdrawApply
  137. // @Summary 蛋蛋星球-钱包-发起提现
  138. // @Tags 钱包
  139. // @Description 发起提现
  140. // @Accept json
  141. // @Produce json
  142. // @param Authorization header string true "验证参数Bearer和token空格拼接"
  143. // @Param req body md.WithdrawApplyReq true "具体参数"
  144. // @Success 200 {string} "success"
  145. // @Failure 400 {object} md.Response "具体错误"
  146. // @Router /api/v1/wallet/withdraw/apply [POST]
  147. func WithdrawApply(c *gin.Context) {
  148. var req md.WithdrawApplyReq
  149. err := c.ShouldBindJSON(&req)
  150. if err != nil {
  151. err = svc.HandleValidateErr(err)
  152. err1 := err.(e.E)
  153. e.OutErr(c, err1.Code, err1.Error())
  154. return
  155. }
  156. user := svc.GetUser(c)
  157. var userId, openId string
  158. var kind int
  159. //sysCfgDb := implement.NewSysCfgDb(db.Db, cache.GetPool().Get())
  160. //sysCfgMap := sysCfgDb.SysCfgFindWithDb(enum.AlipayAppId, enum.WxAppId)
  161. if req.Kind == enum.FinWithdrawApplyWithdrawKindForAli.String() {
  162. alipayUserInfoDb := implement.NewAlipayUserInfoDb(db.Db)
  163. aliInfo, err := alipayUserInfoDb.GetAlipayUserInfo(user.Id)
  164. if err != nil {
  165. e.OutErr(c, e.ERR, err.Error())
  166. return
  167. }
  168. if aliInfo == nil {
  169. e.OutErr(c, e.ERR, "支付宝用户信息未授权")
  170. return
  171. }
  172. //appId = sysCfgMap[enum.AlipayAppId]
  173. userId = aliInfo.UserId
  174. openId = aliInfo.OpenId
  175. kind = int(enum.FinWithdrawApplyWithdrawKindForAli)
  176. } else if req.Kind == enum.FinWithdrawApplyWithdrawKindForWx.String() {
  177. wxUserInfoDb := implement.NewWxUserInfoDb(db.Db)
  178. wxInfo, err := wxUserInfoDb.GetWxUserInfo(user.Id)
  179. if err != nil {
  180. e.OutErr(c, e.ERR, err.Error())
  181. return
  182. }
  183. if wxInfo == nil {
  184. e.OutErr(c, e.ERR, "微信用户信息未授权")
  185. return
  186. }
  187. //appId = sysCfgMap[enum.WxAppId]
  188. userId = wxInfo.UserId
  189. openId = wxInfo.OpenId
  190. kind = int(enum.FinWithdrawApplyWithdrawKindForWx)
  191. } else {
  192. e.OutErr(c, e.ERR, "未知的提现类型")
  193. return
  194. }
  195. //1、判断是否可以提现
  196. err, realAmount, fee, isAuto, isFirst := svc.CheckWithdraw(c, req.Amount)
  197. if err != nil {
  198. e.OutErr(c, e.ERR, err.Error())
  199. return
  200. }
  201. // 2、加锁 防止并发提取
  202. mutexKey := fmt.Sprintf("egg_app_withdraw_apply:%s", utils.Int64ToStr(user.Id))
  203. withdrawAvailable, err := cache.Do("SET", mutexKey, 1, "EX", 5, "NX")
  204. if err != nil {
  205. e.OutErr(c, e.ERR, err)
  206. return
  207. }
  208. if withdrawAvailable != "OK" {
  209. e.OutErr(c, e.ERR, e.NewErr(400000, "请求过于频繁,请稍后再试"))
  210. return
  211. }
  212. // 开启事务
  213. session := db.Db.NewSession()
  214. defer session.Close()
  215. err = session.Begin()
  216. if err != nil {
  217. session.Rollback()
  218. e.OutErr(c, e.ERR_DB_ORM, err)
  219. return
  220. }
  221. //3、处理用户余额
  222. dealUserWalletReq := md2.DealUserWalletReq{
  223. Direction: "sub",
  224. Kind: int(enum.UserWithdrawApply),
  225. Title: enum.UserWithdrawApply.String(),
  226. Uid: user.Id,
  227. Amount: utils.StrToFloat64(req.Amount),
  228. }
  229. rule2.Init(cfg.RedisAddr)
  230. err = rule.DealUserWallet(session, dealUserWalletReq)
  231. if err != nil {
  232. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  233. session.Rollback()
  234. return
  235. }
  236. //4、新增提现记录
  237. now := time.Now()
  238. id := utils.StrToInt64(utils.OrderUUID(int(user.Id)))
  239. finWithdrawApplyDb := implement.NewFinWithdrawApplyDb(db.Db)
  240. finWithdrawApply := &model.FinWithdrawApply{
  241. Id: id,
  242. Uid: user.Id,
  243. AdmId: 0,
  244. Amount: req.Amount,
  245. RealAmount: realAmount,
  246. Fee: fee,
  247. Type: func(isAuto bool) int {
  248. if isAuto {
  249. return 2
  250. }
  251. return 1
  252. }(isAuto),
  253. WithdrawAccount: userId,
  254. WithdrawName: openId,
  255. Reason: 0,
  256. PaymentDate: "",
  257. State: 0,
  258. WithdrawKind: kind,
  259. IsFirst: func(isFirst bool) int {
  260. if isFirst {
  261. return 1
  262. }
  263. return 0
  264. }(isFirst),
  265. Memo: "",
  266. UpdateAt: now.Format("2006-01-02 15:04:05"),
  267. CreateAt: now.Format("2006-01-02 15:04:05"),
  268. }
  269. insertAffected, err := finWithdrawApplyDb.FinWithdrawApplyInsertOneBySession(session, finWithdrawApply)
  270. if err != nil {
  271. session.Rollback()
  272. e.OutErr(c, e.ERR_DB_ORM, err)
  273. return
  274. }
  275. if insertAffected <= 0 {
  276. session.Rollback()
  277. e.OutErr(c, e.ERR_DB_ORM, "生成提现单失败")
  278. return
  279. }
  280. err = session.Begin()
  281. if err != nil {
  282. session.Rollback()
  283. e.OutErr(c, e.ERR_DB_ORM, err)
  284. return
  285. }
  286. err = session.Commit()
  287. if err != nil {
  288. _ = session.Rollback()
  289. e.OutErr(c, e.ERR_DB_ORM, err)
  290. return
  291. }
  292. //5、推入mq
  293. if isAuto {
  294. //更改提现单记录状态
  295. finWithdrawApply.State = int(enum.FinWithdrawApplyStateForIng)
  296. updateAffected, err1 := finWithdrawApplyDb.UpdateFinWithdrawApply(finWithdrawApply, "state")
  297. if err1 != nil {
  298. e.OutErr(c, e.ERR_DB_ORM, err1.Error())
  299. return
  300. }
  301. if updateAffected <= 0 {
  302. e.OutErr(c, e.ERR_DB_ORM, "更新提现单状态失败")
  303. return
  304. }
  305. ch, err1 := rabbit.Cfg.Pool.GetChannel()
  306. if err1 != nil {
  307. e.OutErr(c, e.ERR_INIT_RABBITMQ, err1.Error())
  308. return
  309. }
  310. defer ch.Release()
  311. var data md3.EggFinWithdrawApplyData
  312. err = copier.Copy(&data, &finWithdrawApply)
  313. if err != nil {
  314. e.OutErr(c, e.ERR, err.Error())
  315. return
  316. }
  317. ch.Publish(md3.EggAppExchange, utils.SerializeStr(data), md3.EggFinWithdrawApply)
  318. }
  319. e.OutSuc(c, "success", nil)
  320. }
  321. // GetWithdrawCondition
  322. // @Summary 蛋蛋星球-钱包-提现条件(获取)
  323. // @Tags 钱包
  324. // @Description 提现条件(获取)
  325. // @Accept json
  326. // @Produce json
  327. // @param Authorization header string true "验证参数Bearer和token空格拼接"
  328. // @Success 200 {object} md.GetWithdrawConditionResp "具体数据"
  329. // @Failure 400 {object} md.Response "具体错误"
  330. // @Router /api/v1/wallet/withdraw/condition [GET]
  331. func GetWithdrawCondition(c *gin.Context) {
  332. user := svc.GetUser(c)
  333. settingDb := implement.NewFinWithdrawSettingDb(db.Db)
  334. setting, err := settingDb.FinWithdrawSettingGetOne()
  335. if err != nil {
  336. e.OutErr(c, e.ERR_DB_ORM, err)
  337. return
  338. }
  339. //1. 判断是否为第一次提现
  340. isFirst := false
  341. has, err := db.Db.Where("uid = ?", user.Id).
  342. Get(model.FinWithdrawApply{})
  343. if !has { //第一次提现
  344. isFirst = true
  345. }
  346. resp := svc.GetWithdrawCondition(user, setting, isFirst)
  347. alipayUserInfoDb := implement.NewAlipayUserInfoDb(db.Db)
  348. alipayInfo, err := alipayUserInfoDb.GetAlipayUserInfo(user.Id)
  349. if err != nil {
  350. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  351. return
  352. }
  353. if alipayInfo != nil {
  354. resp.IsBindAlipay = true
  355. }
  356. userInfoDb := implement.NewWxUserInfoDb(db.Db)
  357. wxUserInfo, err := userInfoDb.GetWxUserInfo(user.Id)
  358. if err != nil {
  359. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  360. return
  361. }
  362. if wxUserInfo != nil {
  363. resp.IsBindWx = true
  364. }
  365. e.OutSuc(c, resp, nil)
  366. }
  367. // LaunchBindAlipayAccount
  368. // @Summary 蛋蛋星球-钱包-发起绑定支付宝获得URL
  369. // @Tags 钱包
  370. // @Description 发起绑定支付宝获得URL
  371. // @Accept json
  372. // @Produce json
  373. // @param Authorization header string true "验证参数Bearer和token空格拼接"
  374. // @Success 200 {string} "Url"
  375. // @Failure 400 {object} md.Response "具体错误"
  376. // @Router /api/v1/wallet/withdraw/launchBindAlipay [GET]
  377. func LaunchBindAlipayAccount(c *gin.Context) {
  378. client, err := alipay.InitAlipay(nil)
  379. if err != nil {
  380. e.OutErr(c, e.ERR, err.Error())
  381. return
  382. }
  383. appId := client.AppId
  384. scope := "auth_user"
  385. redisConn := cache.GetPool().Get()
  386. sysCfgDb := implement.NewSysCfgDb(db.Db, redisConn)
  387. sysCfgs, err := sysCfgDb.SysCfgGetAll()
  388. if err != nil {
  389. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  390. return
  391. }
  392. if sysCfgs == nil {
  393. e.OutErr(c, e.ERR_CFG_CACHE, nil)
  394. return
  395. }
  396. cfgMap := make(map[string]string, len(*sysCfgs))
  397. for _, cfg := range *sysCfgs {
  398. cfgMap[cfg.Key] = cfg.Val
  399. }
  400. targetId := utils.UUIDHexString()
  401. alipayPrivateKey := cfgMap[enum2.AlipayPrivateKey]
  402. pid := cfgMap[enum2.AlipayPid]
  403. bm := make(gopay.BodyMap)
  404. bm.Set("apiname", "com.alipay.account.auth")
  405. bm.Set("app_id", appId)
  406. bm.Set("app_name", "mc")
  407. bm.Set("auth_type", "AUTHACCOUNT")
  408. bm.Set("biz_type", "openservice")
  409. bm.Set("pid", pid)
  410. bm.Set("product_id", "APP_FAST_LOGIN")
  411. bm.Set("scope", scope)
  412. bm.Set("sign_type", "RSA2")
  413. bm.Set("method", "alipay.open.auth.sdk.code.get")
  414. bm.Set("target_id", targetId)
  415. privateKey, err := utils.StringToPrivateKey(alipayPrivateKey)
  416. if err != nil {
  417. e.OutErr(c, e.ERR, err.Error())
  418. return
  419. }
  420. sign, err := alipay2.GetRsaSign(bm, alipay2.RSA2, privateKey)
  421. if err != nil {
  422. e.OutErr(c, e.ERR, err.Error())
  423. return
  424. }
  425. resUrl := fmt.Sprintf("apiname=com.alipay.account.auth&app_id=%s&app_name=mc&"+
  426. "auth_type=AUTHACCOUNT&biz_type=openservice&method=alipay.open.auth.sdk.code.get"+
  427. "&pid=%s&product_id=APP_FAST_LOGIN&scope=%s&sign_type=RSA2&"+
  428. "target_id=%s&sign=%s", appId, pid, scope, targetId, sign)
  429. e.OutSuc(c, resUrl, nil)
  430. }
  431. // BindAlipayAccount
  432. // @Summary 蛋蛋星球-钱包-绑定支付宝
  433. // @Tags 钱包
  434. // @Description 绑定支付宝
  435. // @Accept json
  436. // @Produce json
  437. // @param Authorization header string true "验证参数Bearer和token空格拼接"
  438. // @Param req body md.BindAlipayAccountReq true "具体参数"
  439. // @Success 200 {string} "success"
  440. // @Failure 400 {object} md.Response "具体错误"
  441. // @Router /api/v1/wallet/withdraw/bindAlipay [POST]
  442. func BindAlipayAccount(c *gin.Context) {
  443. var req md.BindAlipayAccountReq
  444. err := c.ShouldBindJSON(&req)
  445. if err != nil {
  446. err = svc.HandleValidateErr(err)
  447. err1 := err.(e.E)
  448. e.OutErr(c, err1.Code, err1.Error())
  449. return
  450. }
  451. user := svc.GetUser(c)
  452. var alipayStruct *alipay.InitAlipayStruct
  453. client, err := alipay.InitAlipay(alipayStruct)
  454. if err != nil {
  455. e.OutErr(c, e.ERR, err.Error())
  456. return
  457. }
  458. bm := make(gopay.BodyMap)
  459. bm = bm.Set("grant_type", "authorization_code")
  460. bm = bm.Set("code", req.AuthCode)
  461. systemOauthToken, err := client.SystemOauthToken(c, bm)
  462. if err != nil {
  463. e.OutErr(c, e.ERR, err.Error())
  464. return
  465. }
  466. info, err := client.UserInfoShare(c, systemOauthToken.Response.AccessToken)
  467. if err != nil {
  468. e.OutErr(c, e.ERR, err.Error())
  469. return
  470. }
  471. infoDb := implement.NewAlipayUserInfoDb(db.Db)
  472. userInfo, err := infoDb.GetAlipayUserInfo(user.Id)
  473. if err != nil {
  474. e.OutErr(c, e.ERR, err.Error())
  475. return
  476. }
  477. now := time.Now()
  478. if userInfo == nil {
  479. m := model.AlipayUserInfo{
  480. Uid: user.Id,
  481. UserId: info.Response.UserId,
  482. OpenId: info.Response.OpenId,
  483. AppId: client.AppId,
  484. UserName: info.Response.NickName,
  485. Ext: "",
  486. CreateAt: now.Format("2006-01-02 15:04:05"),
  487. UpdateAt: now.Format("2006-01-02 15:04:05"),
  488. }
  489. _, err = infoDb.AlipayUserInfoInsert(&m)
  490. if err != nil {
  491. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  492. return
  493. }
  494. } else {
  495. cols := []string{"open_id", "app_id", "user_id", "user_name"}
  496. m := model.AlipayUserInfo{
  497. Id: userInfo.Id,
  498. Uid: userInfo.Uid,
  499. UserId: info.Response.UserId,
  500. OpenId: info.Response.OpenId,
  501. AppId: client.AppId,
  502. UserName: info.Response.NickName,
  503. Ext: "",
  504. CreateAt: userInfo.CreateAt,
  505. UpdateAt: now.Format("2006-01-02 15:04:05"),
  506. }
  507. _, err := infoDb.UpdateAlipayUserInfo(&m, cols...)
  508. if err != nil {
  509. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  510. return
  511. }
  512. }
  513. e.OutSuc(c, "success", nil)
  514. }
  515. // BindWxPayAccount
  516. // @Summary 蛋蛋星球-钱包-绑定微信支付
  517. // @Tags 钱包
  518. // @Description 绑定微信支付
  519. // @Accept json
  520. // @Produce json
  521. // @param Authorization header string true "验证参数Bearer和token空格拼接"
  522. // @Param req body md.BindWxPayAccountReq true "具体参数"
  523. // @Success 200 {string} "success"
  524. // @Failure 400 {object} md.Response "具体错误"
  525. // @Router /api/v1/wallet/withdraw/bindWxPay [POST]
  526. func BindWxPayAccount(c *gin.Context) {
  527. var req md.BindWxPayAccountReq
  528. err := c.ShouldBindJSON(&req)
  529. if err != nil {
  530. err = svc.HandleValidateErr(err)
  531. err1 := err.(e.E)
  532. e.OutErr(c, err1.Code, err1.Error())
  533. return
  534. }
  535. user := svc.GetUser(c)
  536. wxUserInfoDb := implement.NewWxUserInfoDb(db.Db)
  537. wxUserInfo, err := wxUserInfoDb.GetWxUserInfo(user.Id)
  538. if err != nil {
  539. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  540. return
  541. }
  542. if wxUserInfo != nil {
  543. e.OutErr(c, e.ERR, errors.New("用户已绑定过微信").Error())
  544. return
  545. }
  546. now := time.Now()
  547. newWxUserInfo := model.WxUserInfo{
  548. Uid: user.Id,
  549. UserId: req.UserId,
  550. OpenId: req.OpenId,
  551. AppId: req.AppId,
  552. Ext: req.Ext,
  553. CreateAt: now.Format("2006-01-02 15:04:05"),
  554. UpdateAt: now.Format("2006-01-02 15:04:05"),
  555. }
  556. affected, err := wxUserInfoDb.WxUserInfoInsert(&newWxUserInfo)
  557. if err != nil {
  558. e.OutErr(c, e.ERR_DB_ORM, err.Error())
  559. return
  560. }
  561. if affected <= 0 {
  562. e.OutErr(c, e.ERR, errors.New("绑定失败"))
  563. }
  564. e.OutSuc(c, "success", nil)
  565. }