广告平台(站长使用)
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.

svc_deal_medium_amount.go 4.4 KiB

2 months ago
1 month ago
2 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package svc
  2. import (
  3. "applet/app/md"
  4. "applet/app/utils/cache"
  5. db "code.fnuoos.com/zhimeng/model.git/src"
  6. "code.fnuoos.com/zhimeng/model.git/src/super/implement"
  7. "code.fnuoos.com/zhimeng/model.git/src/super/model"
  8. zhios_order_relate_utils "code.fnuoos.com/zhimeng/model.git/utils"
  9. zhios_order_relate_logx "code.fnuoos.com/zhimeng/model.git/utils/logx"
  10. "errors"
  11. "fmt"
  12. "github.com/shopspring/decimal"
  13. "strconv"
  14. "time"
  15. "xorm.io/xorm"
  16. )
  17. // DealMediumAmount 处理给媒体余额
  18. func DealMediumAmount(session *xorm.Session, req md.DealMediumAmount) (err error) {
  19. if req.Amount < 0 {
  20. req.Amount = 0
  21. }
  22. //1、分布式锁阻拦
  23. requestIdPrefix := fmt.Sprintf(md.DealMediumAmountRequestIdPrefix, req.Mid, req.MediumId)
  24. cb, err := HandleBalanceDistributedLockForMedium(req.Mid, strconv.Itoa(req.MediumId), requestIdPrefix)
  25. if err != nil {
  26. return err
  27. }
  28. if cb != nil {
  29. defer cb() // 释放锁
  30. }
  31. //2、计算&&组装数据
  32. now := time.Now()
  33. userAmount, err := GetMediumAmount(session, req.Mid, req.MediumId, true)
  34. if err != nil {
  35. return err
  36. }
  37. userAmountValue := decimal.NewFromFloat(zhios_order_relate_utils.StrToFloat64(userAmount))
  38. amountValue := decimal.NewFromFloat(req.Amount).RoundFloor(4)
  39. var finUserFlow = model.FinMediumFlow{
  40. MediumId: req.MediumId,
  41. Type: req.Type,
  42. Amount: amountValue.String(),
  43. BeforeAmount: userAmount,
  44. OrdId: req.OrdId,
  45. Kind: req.Kind,
  46. Memo: req.Memo,
  47. CreateAt: now.Format("2006-01-02 15:04:05"),
  48. UpdateAt: now.Format("2006-01-02 15:04:05"),
  49. }
  50. if req.Type == md.FinMediumFlowDirectionIncome {
  51. finUserFlow.AfterAmount = userAmountValue.Add(amountValue).RoundFloor(4).String()
  52. } else if req.Type == md.FinMediumFlowDirectionExpenditure {
  53. finUserFlow.AfterAmount = userAmountValue.Sub(amountValue).RoundFloor(4).String()
  54. } else {
  55. err = errors.New("错误的kind类型")
  56. return err
  57. }
  58. if zhios_order_relate_utils.StrToFloat64(finUserFlow.AfterAmount) < 0 {
  59. zhios_order_relate_utils.FilePutContents("medium_amount_not", zhios_order_relate_utils.SerializeStr(map[string]interface{}{
  60. "medium_id": finUserFlow.MediumId,
  61. "amount": finUserFlow.Amount,
  62. "before_amount": finUserFlow.BeforeAmount,
  63. "memo": finUserFlow.Memo,
  64. "mid": req.Mid,
  65. }))
  66. return errors.New("媒体余额不足")
  67. }
  68. //3、插入 `fin_user_flow` 记录
  69. affected, err := session.Insert(&finUserFlow)
  70. if affected == 0 || err != nil {
  71. _ = zhios_order_relate_logx.Warn(err)
  72. return err
  73. }
  74. //4、修改 `user_profile`的fin_valid值 && 及缓存
  75. err = SetCacheMediumAmount(session, req.Mid, finUserFlow.AfterAmount, req.MediumId, true)
  76. if err != nil {
  77. return err
  78. }
  79. return nil
  80. }
  81. // GetMediumAmount 获取媒体余额
  82. func GetMediumAmount(session *xorm.Session, masterId string, mediumId int, isForceUpdate bool) (amount string, err error) {
  83. if isForceUpdate {
  84. mediumListDb := implement.NewMediumListDb(db.Db)
  85. medium, err1 := mediumListDb.GetMediumListBySession(session, mediumId)
  86. if err1 != nil {
  87. return amount, err1
  88. }
  89. if medium == nil {
  90. amount = "0"
  91. } else {
  92. amount = medium.Amount
  93. }
  94. //将获取到的余额值缓存至redis
  95. _ = SetCacheMediumAmount(session, masterId, amount, mediumId, false)
  96. } else {
  97. redisKey := fmt.Sprintf(md.MediumAmountRedisKey, masterId, mediumId)
  98. amount, err = cache.GetString(redisKey)
  99. if err != nil && err.Error() != "redigo: nil returned" {
  100. return
  101. }
  102. mediumListDb := implement.NewMediumListDb(db.Db)
  103. medium, err1 := mediumListDb.GetMediumListBySession(session, mediumId)
  104. if err1 != nil {
  105. return amount, err1
  106. }
  107. if medium == nil {
  108. amount = "0"
  109. } else {
  110. amount = medium.Amount
  111. }
  112. //将获取到的余额值缓存至redis
  113. _ = SetCacheMediumAmount(session, masterId, amount, mediumId, false)
  114. }
  115. return amount, nil
  116. }
  117. // SetCacheMediumAmount 设置缓存的用户余额
  118. func SetCacheMediumAmount(session *xorm.Session, masterId, amount string, mediumId int, isUpdateDb bool) error {
  119. redisKey := fmt.Sprintf(md.MediumAmountRedisKey, masterId, mediumId)
  120. if isUpdateDb {
  121. _, err := session.Where("medium_id=?", mediumId).Update(model.MediumList{
  122. MediumId: mediumId,
  123. Amount: amount,
  124. })
  125. if err != nil {
  126. return err
  127. }
  128. }
  129. //TODO::默认缓存1小时 (先调整为 2 min)
  130. _, err := cache.SetEx(redisKey, zhios_order_relate_utils.StrToFloat64(amount), 60*0.5)
  131. if err != nil {
  132. return err
  133. }
  134. return nil
  135. }