You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
424 lines
11 KiB
Go
424 lines
11 KiB
Go
package campaignnotice
|
|
|
|
import (
|
|
"joybuywork/internal/app"
|
|
"joybuywork/internal/consts"
|
|
"joybuywork/internal/consts/ckey"
|
|
"joybuywork/internal/repository/cache"
|
|
"joybuywork/internal/repository/model"
|
|
"joybuywork/internal/repository/mtype"
|
|
"joybuywork/internal/service/cmm"
|
|
"joybuywork/internal/service/provider/award"
|
|
"joybuywork/internal/service/provider/stocks"
|
|
"joybuywork/internal/service/queue/producer"
|
|
"joybuywork/internal/service/queue/types"
|
|
"joybuywork/internal/utils/lockdo"
|
|
"joybuywork/internal/utils/logic"
|
|
"time"
|
|
)
|
|
|
|
type RewardLimitUp struct {
|
|
logic.Logic
|
|
|
|
Req *types.RewardLimitUp
|
|
}
|
|
|
|
func (s *RewardLimitUp) Exec() (err error) {
|
|
cpn, err := cache.NewCampaign(s.Ctx).FindById(s.Req.CampaignId)
|
|
if err != nil {
|
|
err = s.BE().CacheError(err)
|
|
return
|
|
}
|
|
|
|
switch cpn.FissionID {
|
|
case consts.IdReferral, consts.IdWinTogether:
|
|
app.Redis.Cache.Del(s.Ctx, ckey.FissionCampaignRewardLimitPool(cpn.ID))
|
|
stocks.NewCleaner(s.Ctx, cpn.ID).ClearCampaign()
|
|
default:
|
|
|
|
}
|
|
|
|
switch cpn.FissionID {
|
|
case consts.IdReferral:
|
|
return s._referral(cpn)
|
|
case consts.IdWinTogether:
|
|
return s._win(cpn)
|
|
case consts.IdGrow:
|
|
return s._grow(cpn)
|
|
default:
|
|
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// 版本控制执行
|
|
func (s *RewardLimitUp) _verDone(cpnId int64, fn func() (bool, error)) (err error) {
|
|
key := ckey.FissionRewardLimitUpVer(cpnId)
|
|
now := time.Now()
|
|
|
|
for {
|
|
if app.NewVerControl(s.Ctx, key).HasNewVersion(now) {
|
|
return
|
|
}
|
|
|
|
end, err1 := fn()
|
|
if err1 != nil || end {
|
|
err = err1
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *RewardLimitUp) _grow(cpn *model.FissionCampaign) (err error) {
|
|
var id int64
|
|
limit := 50
|
|
|
|
rewardM := s.GetDao().FissionCampaignReward
|
|
rewardList, err := rewardM.WithContext(s.Ctx).Where(rewardM.ID.In(s.Req.RewardIds...)).Find()
|
|
if err != nil {
|
|
err = s.BE().MysqlError(err)
|
|
return
|
|
}
|
|
|
|
var ids []int64
|
|
var rewardMap = make(map[int64]*model.FissionCampaignReward)
|
|
for _, reward := range rewardList {
|
|
rewardMap[reward.ID] = reward
|
|
ids = append(ids, reward.ID)
|
|
}
|
|
|
|
m := s.GetDao().FissionRewardRecord
|
|
ms := s.GetDao().FissionRewardRecord.SubTable(cpn.ID)
|
|
return s._verDone(cpn.ID, func() (bool, error) {
|
|
|
|
var list []*model.FissionRewardRecord
|
|
list, err = ms.WithContext(s.Ctx).
|
|
Where(
|
|
ms.CampaignID.Eq(cpn.ID),
|
|
ms.RewardID.In(ids...),
|
|
ms.Status.Eq(mtype.FissionRewardRecordStatusFail),
|
|
ms.FailMsg.Eq(mtype.FissionRewardRecordFailTypeCliLackMsg),
|
|
ms.ID.Gt(id),
|
|
).Limit(limit).Order(ms.ID).Find()
|
|
if err != nil {
|
|
return false, s.BE().MysqlError(err)
|
|
}
|
|
|
|
if len(list) == 0 {
|
|
return true, nil
|
|
}
|
|
|
|
var recordIds []int64
|
|
var pushRecords []*model.FissionRewardRecord
|
|
for _, record := range list {
|
|
ok, _ := award.NewAwardIssVerify(s.Ctx, nil, rewardMap[record.RewardID]).DeductStock().IsOK()
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
recordIds = append(recordIds, record.ID)
|
|
pushRecords = append(pushRecords, record)
|
|
}
|
|
|
|
if len(recordIds) == 0 {
|
|
return true, nil
|
|
}
|
|
|
|
_, _ = m.WithContext(s.Ctx).Where(m.ID.In(recordIds...)).UpdateSimple(
|
|
m.Status.Value(mtype.FissionRewardRecordStatusWait),
|
|
m.FailType.Value(""),
|
|
m.FailMsg.Value(""),
|
|
)
|
|
|
|
_, _ = ms.WithContext(s.Ctx).Where(ms.ID.In(recordIds...)).UpdateSimple(
|
|
ms.Status.Value(mtype.FissionRewardRecordStatusWait),
|
|
ms.FailType.Value(""),
|
|
ms.FailMsg.Value(""),
|
|
)
|
|
|
|
for _, record := range pushRecords {
|
|
producer.NewCampaignNotice(s.Ctx).CampaignRewardNotify(types.CampaignRewardNotify{
|
|
CampaignId: record.CampaignID,
|
|
UserId: record.UserID,
|
|
UserRewardId: record.ID,
|
|
})
|
|
}
|
|
|
|
l := len(list)
|
|
id = list[l-1].ID
|
|
return l < limit, nil
|
|
})
|
|
}
|
|
|
|
func (s *RewardLimitUp) _referral(cpn *model.FissionCampaign) (err error) {
|
|
conf, err := cache.NewCampaignReferral(s.Ctx).FindByCampaignId(cpn.ID)
|
|
if err != nil {
|
|
err = s.BE().CacheError(err)
|
|
return
|
|
}
|
|
|
|
var id int64
|
|
limit := 20
|
|
m := s.GetDao().FissionReferral
|
|
|
|
return s._verDone(cpn.FissionID, func() (bool, error) {
|
|
var list []*model.FissionReferral
|
|
list, err = m.WithContext(s.Ctx).
|
|
Where(
|
|
m.CampaignID.Eq(cpn.ID),
|
|
m.LimitStatus.Eq(mtype.FissionReferralLimitStatusBudget),
|
|
m.ID.Gt(id),
|
|
).Limit(limit).Order(m.ID).Find()
|
|
if err != nil {
|
|
return false, s.BE().MysqlError(err)
|
|
}
|
|
|
|
if len(list) == 0 {
|
|
return true, nil
|
|
}
|
|
|
|
var userId []int64
|
|
for _, v := range list {
|
|
userId = append(userId, v.UserID)
|
|
}
|
|
|
|
userM := s.GetDao().FissionUser.SubTable(cpn.ID)
|
|
var users []*model.FissionUser
|
|
users, err = userM.WithContext(s.Ctx).Where(userM.ID.In(userId...)).Find()
|
|
if err != nil {
|
|
return false, s.BE().MysqlError(err)
|
|
}
|
|
|
|
var userMap = make(map[int64]*model.FissionUser, len(users))
|
|
for _, v := range users {
|
|
userMap[v.ID] = v
|
|
}
|
|
|
|
for _, v := range list {
|
|
err = s._compensate(cpn, userMap[v.UserID], conf.RewardRule, conf.StepLoop, conf.RewardLimit, v.NextStep, v.LoopInvite, func(limitStatus int8, nextStep, loopInvite int32) (err error) {
|
|
playerM := s.GetDao().FissionReferral
|
|
_, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(v.ID)).UpdateSimple(playerM.LimitStatus.Value(limitStatus))
|
|
if err != nil {
|
|
err = s.BE().MysqlError(err)
|
|
return
|
|
}
|
|
return
|
|
})
|
|
}
|
|
|
|
l := len(list)
|
|
id = list[l-1].ID
|
|
return l < limit, nil
|
|
})
|
|
}
|
|
|
|
func (s *RewardLimitUp) _win(cpn *model.FissionCampaign) (err error) {
|
|
conf, err := cache.NewCampaignWin(s.Ctx).FindByCampaignId(cpn.ID)
|
|
if err != nil {
|
|
err = s.BE().CacheError(err)
|
|
return
|
|
}
|
|
|
|
var id int64
|
|
limit := 20
|
|
m := s.GetDao().FissionWin
|
|
return s._verDone(cpn.FissionID, func() (bool, error) {
|
|
var list []*model.FissionWin
|
|
list, err = m.WithContext(s.Ctx).
|
|
Where(
|
|
m.CampaignID.Eq(cpn.ID),
|
|
m.LimitStatus.Eq(mtype.FissionReferralLimitStatusBudget),
|
|
m.ID.Gt(id),
|
|
).Limit(limit).Order(m.ID).Find()
|
|
if err != nil {
|
|
return false, s.BE().MysqlError(err)
|
|
}
|
|
|
|
if len(list) == 0 {
|
|
return true, nil
|
|
}
|
|
|
|
var userId []int64
|
|
for _, v := range list {
|
|
userId = append(userId, v.UserID)
|
|
}
|
|
|
|
userM := s.GetDao().FissionUser.SubTable(cpn.ID)
|
|
var users []*model.FissionUser
|
|
users, err = userM.WithContext(s.Ctx).Where(userM.ID.In(userId...)).Find()
|
|
if err != nil {
|
|
return false, s.BE().MysqlError(err)
|
|
}
|
|
|
|
var userMap = make(map[int64]*model.FissionUser, len(users))
|
|
for _, v := range users {
|
|
userMap[v.ID] = v
|
|
}
|
|
|
|
for _, v := range list {
|
|
err = s._compensate(cpn, userMap[v.UserID], conf.RewardRule, conf.StepLoop, conf.RewardLimit, v.NextStep, v.LoopInvite, func(limitStatus int8, nextStep, loopInvite int32) (err error) {
|
|
playerM := s.GetDao().FissionWin
|
|
_, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(v.ID)).UpdateSimple(playerM.LimitStatus.Value(limitStatus))
|
|
if err != nil {
|
|
err = s.BE().MysqlError(err)
|
|
return
|
|
}
|
|
return
|
|
})
|
|
}
|
|
|
|
l := len(list)
|
|
id = list[l-1].ID
|
|
return l < limit, nil
|
|
})
|
|
}
|
|
|
|
func (s *RewardLimitUp) _compensate(cpn *model.FissionCampaign, user *model.FissionUser, rewardRule, stepLoop int8, rewardLimit, nextStep, loopInvite int32, limitDo limitDo) (err error) {
|
|
rewards, err := cmm.NewUserAppReward(s.Ctx).Get(s.GetDao(), user, s.GetDao().FissionCampaignReward.Step)
|
|
if err != nil {
|
|
err = s.BE().MysqlError(err)
|
|
return
|
|
}
|
|
|
|
m := s.GetDao().FissionUser.SubTable(user.CampaignID)
|
|
statKey := ckey.FissionUserInviteStat(user.ID)
|
|
num, err := lockdo.Int64(s.Ctx, statKey, func() (num int64, err error) {
|
|
return m.WithContext(s.Ctx).Where(
|
|
m.CampaignID.Eq(user.CampaignID),
|
|
m.ParentID.Eq(user.ID),
|
|
m.IsHelp.Eq(mtype.Yes),
|
|
).Count()
|
|
})
|
|
if err != nil {
|
|
err = s.BE().CacheError(err)
|
|
return
|
|
}
|
|
|
|
switch rewardRule {
|
|
case mtype.FissionReferralRewardRuleStep:
|
|
return s._step(cpn, user, num, rewards, stepLoop, nextStep, loopInvite, rewardLimit, limitDo)
|
|
case mtype.FissionReferralRewardRuleCycle:
|
|
return s._cycle(cpn, user, num, rewards, rewardLimit, limitDo)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
type limitDo func(limitStatus int8, nextStep, loopInvite int32) (err error)
|
|
|
|
func (s *RewardLimitUp) _step(cpn *model.FissionCampaign, user *model.FissionUser, effectNum int64, rewards []*model.FissionCampaignReward, stepLoop int8, nextStep, loopInvite, rewardLimit int32, limitDo limitDo) (err error) {
|
|
var stepMap = make(map[int32]*model.FissionCampaignReward, len(rewards))
|
|
var inviteAll int32
|
|
var maxStep int32
|
|
for _, reward := range rewards {
|
|
inviteAll += reward.InviteNum
|
|
stepMap[reward.Step] = reward
|
|
if reward.Step > maxStep {
|
|
maxStep = reward.Step
|
|
}
|
|
}
|
|
|
|
for {
|
|
|
|
if stepLoop == mtype.Yes && (loopInvite*inviteAll) >= rewardLimit {
|
|
return limitDo(mtype.FissionReferralLimitStatusInvite, nextStep, loopInvite)
|
|
}
|
|
|
|
cn := int32(effectNum) - (loopInvite * inviteAll)
|
|
|
|
reward, ok := stepMap[nextStep]
|
|
if !ok {
|
|
return limitDo(mtype.FissionReferralLimitStatusFinish, 0, loopInvite)
|
|
}
|
|
|
|
if reward.InviteNum > cn {
|
|
return limitDo(mtype.FissionReferralLimitStatusNone, reward.Step, loopInvite)
|
|
}
|
|
|
|
var decr = int64(reward.RewardNum) //奖品数据
|
|
|
|
//扣除总预算是否成功
|
|
var stock *stocks.Campaign
|
|
stock, err = stocks.NewCampaign(s.Ctx, cpn.ID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
decrOk, _ := stock.DecrPoolAndAdd(cpn.ID, decr)
|
|
if !decrOk {
|
|
return limitDo(mtype.FissionReferralLimitStatusBudget, reward.Step, loopInvite)
|
|
}
|
|
|
|
_, _, _, err = award.NewAwardReward(s.Ctx, s.GetDao(), cpn.ProjectID, user).One(reward, true)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
nextStep++
|
|
|
|
if nextStep > maxStep && stepLoop == mtype.Yes {
|
|
nextStep = 1
|
|
loopInvite++
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func (s *RewardLimitUp) _cycle(cpn *model.FissionCampaign, user *model.FissionUser, effectNum int64, rewards []*model.FissionCampaignReward, rewardLimit int32, limitDo limitDo) (err error) {
|
|
|
|
key := ckey.FissionUserGetRewardNum(user.ID)
|
|
num, err := lockdo.Int64(s.Ctx, key, func() (num int64, err error) {
|
|
m := s.GetDao().FissionRewardRecord.SubTable(cpn.ID)
|
|
return m.WithContext(s.Ctx).Where(
|
|
m.UserID.Eq(user.ID),
|
|
m.RewardType.Eq(mtype.FissionCampaignRewardTypeApp),
|
|
).Count()
|
|
})
|
|
|
|
if err != nil {
|
|
err = s.BE().CacheError(err)
|
|
return
|
|
}
|
|
|
|
reward := rewards[0]
|
|
|
|
var needInvite = int64(reward.InviteNum) //完成任务需要邀请的人数
|
|
var decr = int64(reward.RewardNum) //奖品数据
|
|
|
|
for {
|
|
cn := effectNum - (num * needInvite) //总邀请人数 -(完成任务数 * 完成任务需要邀请的人数)= 计算完成任务的邀请人数
|
|
|
|
//邀请的人不足以获取到奖品
|
|
if cn < needInvite {
|
|
return limitDo(mtype.FissionReferralLimitStatusNone, -1, 0)
|
|
}
|
|
|
|
if (num * needInvite) >= int64(rewardLimit) {
|
|
return limitDo(mtype.FissionReferralLimitStatusInvite, -1, 0)
|
|
}
|
|
|
|
//扣除总预算是否成功
|
|
var stock *stocks.Campaign
|
|
stock, err = stocks.NewCampaign(s.Ctx, cpn.ID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
decrOk, _ := stock.DecrPoolAndAdd(cpn.ID, decr)
|
|
if !decrOk {
|
|
return limitDo(mtype.FissionReferralLimitStatusBudget, -1, 0)
|
|
}
|
|
|
|
_, _, _, err = award.NewAwardReward(s.Ctx, s.GetDao(), cpn.ProjectID, user).One(reward, true)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// 领奖数+1
|
|
app.Redis.Cache.Incr(s.Ctx, key)
|
|
num++
|
|
}
|
|
}
|