蛋蛋星球-制度模式
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

122 行
3.5 KiB

  1. package rule
  2. import (
  3. "code.fnuoos.com/EggPlanet/egg_models.git/src/implement"
  4. "code.fnuoos.com/EggPlanet/egg_models.git/src/model"
  5. zhios_order_relate_utils "code.fnuoos.com/EggPlanet/egg_models.git/utils"
  6. "code.fnuoos.com/EggPlanet/egg_system_rules.git/md"
  7. "code.fnuoos.com/EggPlanet/egg_system_rules.git/svc"
  8. "code.fnuoos.com/EggPlanet/egg_system_rules.git/utils/cache"
  9. "errors"
  10. "fmt"
  11. "github.com/shopspring/decimal"
  12. "time"
  13. "xorm.io/xorm"
  14. )
  15. // DealUserWallet 处理给用户金额
  16. func DealUserWallet(session *xorm.Session, req md.DealUserWalletReq) (err error) {
  17. if req.Amount < 0 {
  18. req.Amount = 0
  19. }
  20. //1、分布式锁阻拦
  21. requestIdPrefix := fmt.Sprintf(md.UserWalletRedisKey, req.Uid)
  22. cb, err := svc.HandleDistributedLockForUserWallet(zhios_order_relate_utils.Int64ToStr(req.Uid), requestIdPrefix)
  23. if err != nil {
  24. return err
  25. }
  26. if cb != nil {
  27. defer cb() // 释放锁
  28. }
  29. //2、计算&&组装数据
  30. now := time.Now()
  31. userAmount, err := GetUserWalletAmount(session, req.Uid)
  32. if err != nil {
  33. return err
  34. }
  35. amountValue := decimal.NewFromFloat(req.Amount).RoundFloor(4)
  36. var userWalletFlow model.UserWalletFlow
  37. userWalletFlow.Uid = req.Uid
  38. userWalletFlow.Title = req.Title
  39. userWalletFlow.Kind = req.Kind
  40. userWalletFlow.BeforeAmount = userAmount
  41. userWalletFlow.Amount = amountValue.String()
  42. userWalletFlow.CreateAt = now.Format("2006-01-02 15:04:05")
  43. if req.Direction == "add" {
  44. userWalletFlow.Direction = 1
  45. userWalletFlow.AfterAmount = amountValue.Add(amountValue).RoundFloor(8).String()
  46. } else if req.Direction == "sub" {
  47. userWalletFlow.Direction = 2
  48. userWalletFlow.AfterAmount = amountValue.Sub(amountValue).RoundFloor(8).String()
  49. if zhios_order_relate_utils.StrToFloat64(userWalletFlow.AfterAmount) < 0 {
  50. return errors.New("用户钱包余额不足")
  51. }
  52. } else {
  53. err = errors.New("错误的Direction类型")
  54. return err
  55. }
  56. //3、插入 `user_wallet_flow` 记录
  57. userWalletFlowDb := implement.NewUserWalletFlowDb(session.Engine())
  58. _, err = userWalletFlowDb.UserWalletFlowInsertBySession(session, &userWalletFlow)
  59. if err != nil {
  60. return err
  61. }
  62. //4、修改 `user_wallet`的amount值 && 及缓存
  63. err = SetUserWalletAmount(session, userWalletFlow.AfterAmount, req.Uid, true)
  64. if err != nil {
  65. return err
  66. }
  67. return nil
  68. }
  69. // GetUserWalletAmount 获取用户钱包余额
  70. func GetUserWalletAmount(session *xorm.Session, uid int64) (amount string, err error) {
  71. redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid)
  72. amount, err = cache.GetString(redisKey)
  73. if err != nil {
  74. if err.Error() == "redigo: nil returned" {
  75. userWalletDb := implement.NewUserWalletDb(session.Engine())
  76. userVirtualAmount, err := userWalletDb.GetUserVirtualWallet(uid)
  77. if err != nil {
  78. return amount, err
  79. }
  80. if userVirtualAmount == nil {
  81. amount = "0"
  82. } else {
  83. amount = userVirtualAmount.Amount
  84. }
  85. //将获取到的余额值缓存至redis
  86. _ = SetUserWalletAmount(session, amount, uid, false)
  87. return amount, nil
  88. }
  89. return amount, err
  90. }
  91. return amount, nil
  92. }
  93. // SetUserWalletAmount 设置缓存的用户虚拟币积分余额
  94. func SetUserWalletAmount(session *xorm.Session, amount string, uid int64, isUpdateDb bool) error {
  95. redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid)
  96. if isUpdateDb {
  97. _, err := session.Where("uid=?", uid).Update(model.UserWallet{
  98. Uid: uid,
  99. Amount: amount,
  100. })
  101. if err != nil {
  102. return err
  103. }
  104. }
  105. //TODO::默认缓存1小时 (先调整为 20 min)
  106. _, err := cache.SetEx(redisKey, zhios_order_relate_utils.StrToFloat64(amount), 60*20)
  107. if err != nil {
  108. return err
  109. }
  110. return nil
  111. }