蛋蛋星球-客户端
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.
 
 
 
 
 

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