02_cal_level_profit.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package period_profit
  2. import (
  3. "app/commons/constant"
  4. "app/commons/core"
  5. "app/commons/model/entity"
  6. "app/commons/utils"
  7. "fmt"
  8. "github.com/shopspring/decimal"
  9. )
  10. // 计算等级奖励
  11. // 根据等级配置 计算每个等级可获得比例
  12. // 统计各等级人数
  13. // 平均分配计算 -- 生成待发放奖励记录
  14. // 加权分配计算 -- 生成待发放奖励记录 -- 以真实小区业绩加权
  15. func (s *Service) calLevelProfit(periodNo string) error {
  16. levelMap, err := s.LevelConfigMapFromCache()
  17. if err != nil {
  18. return err
  19. }
  20. nowPeriodJob, err := s.FirstStakePeriodJob(s.DB().
  21. Where("job_state", entity.PeriodJobStateRunning).
  22. Where("period_no", periodNo).
  23. Where("level_profit_is_cal", false))
  24. if err != nil {
  25. return err
  26. }
  27. if nowPeriodJob.StaticSymbolProfit.LessThanOrEqual(decimal.Zero) {
  28. core.JobLog.Warnf("期:%s 静态收益为:%s,跳过等级收益计算", periodNo, nowPeriodJob.StaticSymbolProfit)
  29. return nil
  30. }
  31. periodProfit := nowPeriodJob.StaticSymbolProfit
  32. periodUsdProfit := nowPeriodJob.StaticUsdProfit
  33. price := nowPeriodJob.Price
  34. profitRecords := make([]*entity.UserProfitRecord, 0)
  35. for k, v := range levelMap {
  36. core.JobLog.Infof("计算等级:%d 收益", k)
  37. records, err := s.avgWeightedLevelProfit(periodNo, v, periodUsdProfit, price, periodProfit)
  38. if err != nil {
  39. return err
  40. }
  41. if len(records) > 0 {
  42. profitRecords = append(profitRecords, records...)
  43. }
  44. }
  45. if len(profitRecords) > 0 {
  46. txDb := s.DB().Begin()
  47. err = txDb.CreateInBatches(profitRecords, 200).Error
  48. if err != nil {
  49. txDb.Rollback()
  50. return err
  51. }
  52. txDb.Commit()
  53. }
  54. return nil
  55. }
  56. // 根据等级计算均分收益
  57. func (s *Service) avgWeightedLevelProfit(periodNo string, levelConfig *entity.SysLevelConfig, usdProfit, symbolProfit, price decimal.Decimal) ([]*entity.UserProfitRecord, error) {
  58. dailyJobDate, err := utils.PeriodNoToDailyDate(periodNo) // 期任务格式转化为 日任务格式
  59. if err != nil {
  60. return nil, err
  61. }
  62. profitRecords := make([]*entity.UserProfitRecord, 0)
  63. levelSymbolProfit := symbolProfit.Mul(levelConfig.StaticRatio) // 当期该等级可分配总数量
  64. levelUsdAmount := usdProfit.Mul(levelConfig.StaticRatio) // 当期该等级可分配总U数
  65. // 等级均分总数
  66. totalAvgProfit := levelSymbolProfit.Mul(levelConfig.AvgRatio)
  67. totalAvgUsdProfit := levelUsdAmount.Mul(levelConfig.AvgRatio)
  68. // 加权分配总数
  69. totalWeightedProfit := levelSymbolProfit.Mul(levelConfig.WeightedRatio)
  70. totalWeightedUsdProfit := levelUsdAmount.Mul(levelConfig.WeightedRatio)
  71. allLevelUserQuota, err := s.BatchUserQuota(s.DB().Where("level", levelConfig.Level))
  72. if err != nil {
  73. return profitRecords, err
  74. }
  75. // 均分计算
  76. countUser := len(allLevelUserQuota)
  77. core.JobLog.Infof("等级:%d 用户数:%d", levelConfig.Level, countUser)
  78. if countUser == 0 {
  79. return profitRecords, nil
  80. }
  81. avgRatio := decimal.NewFromFloat(1).Div(decimal.NewFromInt(int64(countUser))) // 每人可获得均分比例
  82. avgPerUserSymbolProfit := totalAvgProfit.Mul(avgRatio) // 当前等级每人可获得SYMBOL数量 == 拆分为 均分与加权
  83. avgPerUserUsdProfit := totalAvgUsdProfit.Mul(avgRatio) // 当前等级每人可获得USD数量 == 拆分为 均分与加权
  84. // 计算加权分配数量
  85. allFewAc := decimal.Zero // 等级达标总小区业绩
  86. for _, quota := range allLevelUserQuota {
  87. allFewAc = allFewAc.Add(quota.FewTeamAchievement)
  88. }
  89. weightedPerAcSymbolRatio := totalWeightedProfit.Mul(allFewAc) // 1U 业绩可获得 加权奖励比例
  90. weightedPerAcUsdRatio := totalWeightedUsdProfit.Mul(allFewAc) // 1U 业绩可获得 加权奖励比例
  91. for _, userQuota := range allLevelUserQuota {
  92. // 均分记录
  93. avgBs := constant.BsById(constant.BsDynamicLevelAvgProfit)
  94. avgBs.ContextValue = fmt.Sprintf("%d", userQuota.UserId)
  95. avgBs.ContextName = userQuota.TableName()
  96. avgBs.Desc = fmt.Sprintf("%s-期:%s-Level:%d-perUserSymbolProfit:%s", avgBs.BusinessName, periodNo, levelConfig.Level, avgPerUserSymbolProfit)
  97. profitInfo := &entity.ProfitInfo{
  98. RawUserId: userQuota.UserId,
  99. RawUserUid: userQuota.Uid,
  100. RewardUserId: userQuota.UserId,
  101. RewardUserUid: userQuota.Uid,
  102. RewardSymbol: constant.CoinSymbolTD,
  103. SymbolUsdPrice: price,
  104. CapitalUsd: totalAvgUsdProfit,
  105. RewardRatio: avgRatio,
  106. RewardUsdValue: avgPerUserUsdProfit,
  107. RewardQuantity: avgPerUserSymbolProfit,
  108. RewardPeriod: periodNo,
  109. RewardDate: dailyJobDate,
  110. }
  111. profitRecord := s.BuildUserProfitRecord(profitInfo, avgBs)
  112. profitRecords = append(profitRecords, profitRecord)
  113. // 加权分配
  114. weightedBs := constant.BsById(constant.BsDynamicLevelWeightedProfit)
  115. weightedBs.ContextValue = fmt.Sprintf("%d", userQuota.UserId)
  116. weightedBs.ContextName = userQuota.TableName()
  117. userWeightedProfit := userQuota.FewTeamAchievement.Mul(weightedPerAcSymbolRatio)
  118. userWeightedUsdProfit := userQuota.FewTeamAchievement.Mul(weightedPerAcUsdRatio)
  119. weightedBs.Desc = fmt.Sprintf("%s-期:%s-Level:%d-userWeightedProfit:%s", avgBs.BusinessName, periodNo, levelConfig.Level, userWeightedProfit)
  120. weightedProfitInfo := &entity.ProfitInfo{
  121. RawUserId: userQuota.UserId,
  122. RawUserUid: userQuota.Uid,
  123. RewardUserId: userQuota.UserId,
  124. RewardUserUid: userQuota.Uid,
  125. RewardSymbol: constant.CoinSymbolTD,
  126. SymbolUsdPrice: price,
  127. CapitalUsd: userQuota.FewTeamAchievement,
  128. RewardRatio: weightedPerAcUsdRatio,
  129. RewardUsdValue: userWeightedUsdProfit,
  130. RewardQuantity: userWeightedProfit,
  131. RewardPeriod: periodNo,
  132. RewardDate: dailyJobDate,
  133. }
  134. weightedProfitRecord := s.BuildUserProfitRecord(weightedProfitInfo, weightedBs)
  135. profitRecords = append(profitRecords, weightedProfitRecord)
  136. }
  137. return profitRecords, nil
  138. }