蛋蛋星球-客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

550 lines
15 KiB

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