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

123 行
3.6 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. beforeAmountValue, _ := decimal.NewFromString(userAmount)
  37. var userWalletFlow model.UserWalletFlow
  38. userWalletFlow.Uid = req.Uid
  39. userWalletFlow.Title = req.Title
  40. userWalletFlow.Kind = req.Kind
  41. userWalletFlow.BeforeAmount = userAmount
  42. userWalletFlow.Amount = amountValue.String()
  43. userWalletFlow.CreateAt = now.Format("2006-01-02 15:04:05")
  44. if req.Direction == "add" {
  45. userWalletFlow.Direction = 1
  46. userWalletFlow.AfterAmount = beforeAmountValue.Add(amountValue).RoundFloor(8).String()
  47. } else if req.Direction == "sub" {
  48. userWalletFlow.Direction = 2
  49. userWalletFlow.AfterAmount = beforeAmountValue.Sub(amountValue).RoundFloor(8).String()
  50. if zhios_order_relate_utils.StrToFloat64(userWalletFlow.AfterAmount) < 0 {
  51. return errors.New("用户钱包余额不足")
  52. }
  53. } else {
  54. err = errors.New("错误的Direction类型")
  55. return err
  56. }
  57. //3、插入 `user_wallet_flow` 记录
  58. userWalletFlowDb := implement.NewUserWalletFlowDb(session.Engine())
  59. _, err = userWalletFlowDb.UserWalletFlowInsertBySession(session, &userWalletFlow)
  60. if err != nil {
  61. return err
  62. }
  63. //4、修改 `user_wallet`的amount值 && 及缓存
  64. err = SetUserWalletAmount(session, userWalletFlow.AfterAmount, req.Uid, true)
  65. if err != nil {
  66. return err
  67. }
  68. return nil
  69. }
  70. // GetUserWalletAmount 获取用户钱包余额
  71. func GetUserWalletAmount(session *xorm.Session, uid int64) (amount string, err error) {
  72. redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid)
  73. amount, err = cache.GetString(redisKey)
  74. if err != nil {
  75. if err.Error() == "redigo: nil returned" {
  76. userWalletDb := implement.NewUserWalletDb(session.Engine())
  77. userVirtualAmount, err := userWalletDb.GetUserVirtualWallet(uid)
  78. if err != nil {
  79. return amount, err
  80. }
  81. if userVirtualAmount == nil {
  82. amount = "0"
  83. } else {
  84. amount = userVirtualAmount.Amount
  85. }
  86. //将获取到的余额值缓存至redis
  87. _ = SetUserWalletAmount(session, amount, uid, false)
  88. return amount, nil
  89. }
  90. return amount, err
  91. }
  92. return amount, nil
  93. }
  94. // SetUserWalletAmount 设置缓存的用户虚拟币积分余额
  95. func SetUserWalletAmount(session *xorm.Session, amount string, uid int64, isUpdateDb bool) error {
  96. redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid)
  97. if isUpdateDb {
  98. _, err := session.Where("uid=?", uid).Update(model.UserWallet{
  99. Uid: uid,
  100. Amount: amount,
  101. })
  102. if err != nil {
  103. return err
  104. }
  105. }
  106. //TODO::默认缓存1小时 (先调整为 20 min)
  107. _, err := cache.SetEx(redisKey, zhios_order_relate_utils.StrToFloat64(amount), 60*20)
  108. if err != nil {
  109. return err
  110. }
  111. return nil
  112. }