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.

492 lines
12 KiB
Go

package validevents
import (
"joybuywork/internal/app"
"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/utils/lockdo"
"time"
"gits.branchcn.com/backend/microcode/plugins/derivative/lock"
"gorm.io/gen/field"
)
type referral struct {
base
}
func (s *referral) Event(user *model.FissionUser) (targetNum int32, setHelp bool, err error) {
fc := cmm.NewFirstCreate(s.Ctx, s.GetDao())
player, err := fc.FissionReferral(user)
if err != nil {
return
}
data, err := s._event(user)
if err != nil {
return
}
targetNum = data.targetNum
if data.targetNum == 0 || user.IsHelp == mtype.Yes {
return
}
ticket, err := cache.NewCampaignTicket(s.Ctx).FindByMark(user.CampaignID, mtype.FissionCampaignTicketCustom)
if err != nil {
err = s.BE().CacheError(err)
return
}
var preOk = true
switch ticket.PreEvent {
case mtype.FissionCampaignTicketPreEventInstall:
preOk = player.BindInstall == mtype.Yes
case mtype.FissionCampaignTicketPreEventRegister:
preOk = player.BindRegister == mtype.Yes
}
if !preOk {
return
}
setHelp = true
err = s._eventHelp(user)
if err != nil {
return
}
return
}
func (s *referral) Register(helper, beHelper *model.FissionUser) (setHelp bool, err error) {
player, err := cmm.NewFirstCreate(s.Ctx, s.GetDao()).FissionReferral(helper)
if err != nil {
return
}
if player.BindRegister == mtype.Yes {
return
}
m := s.GetDao().FissionReferral
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(player.ID)).UpdateSimple(m.BindRegister.Value(mtype.Yes))
if err != nil {
err = s.BE().MysqlError(err)
return
}
tasks, setHelp, err := s._getRegisterTasks(helper.CampaignID)
if err != nil || len(tasks) == 0 {
return
}
err = s._fixTaskDo(beHelper, tasks)
if err != nil {
return
}
return
}
func (s *referral) Install(helper, beHelper *model.FissionUser) (setHelp bool, err error) {
player, err := cmm.NewFirstCreate(s.Ctx, s.GetDao()).FissionReferral(helper)
if err != nil {
return
}
if player.BindInstall == mtype.Yes {
return
}
m := s.GetDao().FissionReferral
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(player.ID)).UpdateSimple(m.BindInstall.Value(mtype.Yes))
if err != nil {
err = s.BE().MysqlError(err)
return
}
tasks, setHelp, err := s._getInstallTasks(helper.CampaignID)
if err != nil || len(tasks) == 0 {
return
}
err = s._fixTaskDo(beHelper, tasks)
if err != nil {
return
}
return
}
type referralStepDo func(player *model.FissionReferral, conf *model.FissionCampaignReferral, reward, nextReward *model.FissionCampaignReward, allInviteNum int32) (err error)
type referralCycleDo func(player *model.FissionReferral, conf *model.FissionCampaignReferral, reward *model.FissionCampaignReward) (err error)
type referralDo struct {
step referralStepDo
cycle referralCycleDo
}
func (s *referral) _do(user *model.FissionUser, do referralDo) (err error) {
//防止同一个人并发发礼物超发
lc := app.NewRedisLock(s.Ctx, ckey.FissionParentInviteOnce(user.ID), lock.SetExpire(10*time.Second)).Lock()
defer lc.Release()
if lc.Error() != nil {
return
}
fc := cmm.NewFirstCreate(s.Ctx, s.GetDao())
player, err := fc.FissionReferral(user)
if err != nil {
return
}
// 被限制了
if player.LimitStatus != mtype.FissionReferralLimitStatusNone {
return
}
conf, err := cache.NewCampaignReferral(s.Ctx).FindByCampaignId(player.CampaignID)
if err != nil {
err = s.BE().CacheError(err)
return
}
m := s.GetDao().FissionCampaignReward
rewards, err := cmm.NewCMM(s.Ctx, s.GetDao()).UserAppReward(user, m.Step)
if err != nil {
err = s.BE().MysqlError(err)
return
}
if conf.RewardRule == mtype.FissionReferralRewardRuleStep {
var allInviteNum int32
for _, campaignReward := range rewards {
if campaignReward.InviteNum > allInviteNum {
allInviteNum = campaignReward.InviteNum
}
}
rewardL := len(rewards)
var reward, nextReward *model.FissionCampaignReward
for i, campaignReward := range rewards {
if campaignReward.Step == player.NextStep {
reward = campaignReward
if i < rewardL-1 {
nextReward = rewards[i+1]
}
break
}
}
if nextReward == nil && conf.StepLoop == mtype.Yes {
nextReward = rewards[0]
}
return do.step(player, conf, reward, nextReward, allInviteNum)
} else if conf.RewardRule == mtype.FissionReferralRewardRuleCycle {
return do.cycle(player, conf, rewards[0])
}
return
}
func (s *referral) _eventHelp(helper *model.FissionUser) (err error) {
// 找被助力的人
user, err := cache.NewFissionUser(s.Ctx, helper.CampaignID).FindById(helper.ParentID)
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
return
}
effectNum, err := s._statDirectNum(user.CampaignID, user.ID)
if err != nil {
return
}
do := referralDo{
step: func(player *model.FissionReferral, conf *model.FissionCampaignReferral, reward, nextReward *model.FissionCampaignReward, allInviteNum int32) (err error) {
return s._step(user, effectNum, player, conf, reward, nextReward, allInviteNum)
},
cycle: func(player *model.FissionReferral, conf *model.FissionCampaignReferral, reward *model.FissionCampaignReward) (err error) {
err = s._cycle(user, effectNum, player, conf, reward)
if err != nil {
return
}
return s._extra(user, player, effectNum)
},
}
return s._do(user, do)
}
// 用户固定事件任务
func (s *referral) _fixTaskDo(user *model.FissionUser, tasks []*model.FissionCampaignTask) (err error) {
do := referralDo{
step: func(player *model.FissionReferral, conf *model.FissionCampaignReferral, reward, nextReward *model.FissionCampaignReward, allInviteNum int32) (err error) {
for _, task := range tasks {
switch task.PropMark {
case mtype.FissionCampaignTaskPropMarkChance:
err = s._taskEffectDo(user, task, func() (err error) {
return s._step(user, s.effectNum, player, conf, reward, nextReward, allInviteNum)
})
if err != nil {
return
}
}
}
return
},
cycle: func(player *model.FissionReferral, conf *model.FissionCampaignReferral, reward *model.FissionCampaignReward) (err error) {
for _, task := range tasks {
switch task.PropMark {
case mtype.FissionCampaignTaskPropMarkChance:
err = s._taskEffectDo(user, task, func() (err error) {
err = s._cycle(user, s.effectNum, player, conf, reward)
if err != nil {
return
}
return s._extra(user, player, s.effectNum)
})
if err != nil {
return
}
}
}
return
},
}
return s._do(user, do)
}
// 增加抽奖次数
func (s *referral) _step(user *model.FissionUser, effectNum int64, player *model.FissionReferral, conf *model.FissionCampaignReferral, reward, nextReward *model.FissionCampaignReward, allInviteNum int32) (err error) {
var limitStatus int8
defer func() {
if err != nil {
return
}
err = s._limitStatus(player.ID, limitStatus)
}()
if conf.StepLoop == mtype.Yes && effectNum > int64(conf.InviteLimit) {
limitStatus = mtype.FissionReferralLimitStatusInvite
return
}
//没有下一级任务
if reward == nil {
limitStatus = mtype.FissionReferralLimitStatusFinish
return
}
var inviteNum = effectNum - int64(player.LoopInvite*allInviteNum)
//没有完成
if int64(reward.InviteNum) > inviteNum {
return
}
var decr = int64(reward.RewardNum)
//扣除总预算是否成功
var stock *stocks.Campaign
stock, err = stocks.NewCampaign(s.Ctx, player.CampaignID)
if err != nil {
return
}
ok, _ := stock.DecrPoolAndAdd(player.CampaignID, decr)
if !ok {
limitStatus = mtype.FissionReferralLimitStatusBudget
return
}
_, _, _, err = award.NewAwardReward(s.Ctx, s.GetDao(), s.cpn.ProjectID, user).One(reward, true)
if err != nil {
return
}
if nextReward == nil {
limitStatus = mtype.FissionReferralLimitStatusFinish
return
}
// 初始化奖品的东西
playerM := s.GetDao().FissionReferral
var up []field.AssignExpr
up = append(up, playerM.NextStep.Value(nextReward.Step))
if nextReward.Step <= reward.Step {
up = append(up, playerM.LoopInvite.Add(1))
}
_, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(player.ID)).UpdateSimple(up...)
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}
// 增加抽奖次数
func (s *referral) _cycle(user *model.FissionUser, effectNum int64, player *model.FissionReferral, conf *model.FissionCampaignReferral, reward *model.FissionCampaignReward) (err error) {
var limitStatus int8
defer func() {
if err != nil {
return
}
err = s._limitStatus(player.ID, limitStatus)
}()
if effectNum > int64(conf.InviteLimit) {
limitStatus = mtype.FissionReferralLimitStatusInvite
return
}
key := ckey.FissionUserGetRewardNum(user.ID)
num, err := lockdo.Int64(s.Ctx, key, func() (num int64, err error) {
m := s.GetDao().FissionRewardRecord.SubTable(user.CampaignID)
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
}
var needInvite = int64(reward.InviteNum) //完成任务需要邀请的人数
var decr = int64(reward.RewardNum) //奖品数据
cn := effectNum - (num * needInvite) //总邀请人数 -(完成任务数 * 完成任务需要邀请的人数)= 计算完成任务的邀请人数
//邀请的人不足以获取到奖品
if cn < needInvite {
return
}
//扣除总预算是否成功
var stock *stocks.Campaign
stock, err = stocks.NewCampaign(s.Ctx, player.CampaignID)
if err != nil {
return
}
ok, _ := stock.DecrPoolAndAdd(player.CampaignID, decr)
if !ok {
limitStatus = mtype.FissionReferralLimitStatusBudget
return
}
_, _, _, err = award.NewAwardReward(s.Ctx, s.GetDao(), s.cpn.ProjectID, user).One(reward, true)
if err != nil {
return
}
// 领奖数+1
app.Redis.Cache.Incr(s.Ctx, key)
return
}
func (s *referral) _limitStatus(playerId int64, ls int8) (err error) {
if ls == mtype.FissionReferralLimitStatusNone {
return
}
m := s.GetDao().FissionReferral
var up = []field.AssignExpr{
m.LimitStatus.Value(ls),
}
if ls == mtype.FissionReferralLimitStatusFinish {
up = append(up, m.NextStep.Value(0))
}
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(playerId)).UpdateSimple(up...)
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}
// 额外
func (s *referral) _extra(user *model.FissionUser, player *model.FissionReferral, effectNum int64) (err error) {
m := s.GetDao().FissionCampaignReward
var extras []*model.FissionCampaignReward
var extraReward, nextExtraReward *model.FissionCampaignReward
extras, err = m.WithContext(s.Ctx).Where(
m.CampaignID.Eq(user.CampaignID),
m.RewardType.Eq(mtype.FissionCampaignRewardTypeExtra),
m.IsDel.Eq(mtype.No),
).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
rewardL := len(extras)
for i, extra := range extras {
if extra.Step == player.NextStep {
extraReward = extra
if i < rewardL-1 {
nextExtraReward = extras[i+1]
}
break
}
}
if extraReward == nil {
return
}
//没有达标任务
if int64(extraReward.InviteNum) > effectNum {
return
}
// 额外奖品
_, _, _, err = award.NewAwardReward(s.Ctx, s.GetDao(), s.cpn.ProjectID, user).One(extraReward, true)
if err != nil {
return
}
var nextStep int32
if nextExtraReward != nil {
nextStep = nextExtraReward.Step
}
// 下次的额外奖
playerM := s.GetDao().FissionReferral
_, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(player.ID)).UpdateSimple(playerM.NextStep.Value(nextStep))
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}