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.

605 lines
14 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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"
"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 win struct {
base
}
func (s *win) Event(user *model.FissionUser) (targetNum int32, setHelp bool, err error) {
fc := cmm.NewFirstCreate(s.Ctx, s.GetDao())
player, err := fc.FissionWin(user)
if err != nil {
return
}
defer func() {
if err != nil {
return
}
err = s._newcomerReward(user, player.ID, setHelp)
}()
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 *win) Register(helper, beHelper *model.FissionUser) (setHelp bool, err error) {
player, err := cmm.NewFirstCreate(s.Ctx, s.GetDao()).FissionWin(helper)
if err != nil {
return
}
defer func() {
if err != nil {
return
}
err = s._newcomerReward(helper, player.ID, setHelp)
}()
if player.BindRegister == mtype.Yes {
return
}
m := s.GetDao().FissionWin
_, 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 *win) Install(helper, beHelper *model.FissionUser) (setHelp bool, err error) {
player, err := cmm.NewFirstCreate(s.Ctx, s.GetDao()).FissionWin(helper)
if err != nil {
return
}
defer func() {
if err != nil {
return
}
err = s._newcomerReward(helper, player.ID, setHelp)
}()
if player.BindInstall == mtype.Yes {
return
}
m := s.GetDao().FissionWin
_, 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
}
// 一起赢发放新人奖
func (s *win) _newcomerReward(user *model.FissionUser, playerId int64, setHelp bool) (err error) {
conf, err := cache.NewCampaignWin(s.Ctx).FindByCampaignId(user.CampaignID)
if err != nil {
err = s.BE().CacheError(err)
return
}
switch conf.NewcomerCond {
case mtype.FissionNewcomerCondInstall:
if user.Source != mtype.FissionUserSourceInstall || !s.Req.NewUser {
return
}
case mtype.FissionNewcomerCondHelp:
if user.IsHelp == mtype.Yes || !setHelp {
return
}
case mtype.FissionNewcomerCondInstallAndHelp:
if user.Source != mtype.FissionUserSourceInstall || user.IsHelp == mtype.Yes || !setHelp {
return
}
}
if !app.NewRedisLock(s.Ctx, ckey.FissionWinNewcomerOnce(user.ID)).SoftLock() {
return
}
rewardM := s.GetDao().FissionCampaignReward
rl, err := rewardM.WithContext(s.Ctx).Where(
rewardM.CampaignID.Eq(user.CampaignID),
rewardM.RewardType.Eq(mtype.FissionCampaignRewardTypeNewcomer),
rewardM.IsDel.Eq(mtype.No),
).Find()
if err != nil {
return s.BE().MysqlError(err)
}
var randMap = make(map[int64]*model.FissionCampaignReward)
for _, v := range rl {
randMap[v.ID] = v
}
var reward *model.FissionCampaignReward
for _, v := range randMap {
reward = v
break
}
record, _, async, err := award.NewAwardReward(s.Ctx, s.GetDao(), s.cpn.ProjectID, user).One(reward, false)
if err != nil || record == nil {
return
}
provider.NewFissionClue(s.Ctx, user.ID).AddNewcomerReward(record.ID)
s.MP().InApp(user).Newcomer(record.CreatedAt, record.RewardID, record.ID)
playerM := s.GetDao().FissionWin
_, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(playerId)).UpdateSimple(playerM.IsNewcomer.Value(mtype.Yes))
if err != nil {
err = s.BE().MysqlError(err)
return
}
// 如果为没有用户id,就不用通知客户
if user.SubUserID == "" {
return
}
s.AddAfterRun(func() (err error) {
// 执行异步任务
for _, do := range async {
do()
}
return
})
return
}
type winStepDo func(player *model.FissionWin, conf *model.FissionCampaignWin, reward, nextReward *model.FissionCampaignReward, allInviteNum int32) (err error)
type winCycleDo func(player *model.FissionWin, conf *model.FissionCampaignWin, reward *model.FissionCampaignReward) (err error)
type winDo struct {
step winStepDo
cycle winCycleDo
}
func (s *win) _do(user *model.FissionUser, do winDo) (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.FissionWin(user)
if err != nil {
return
}
// 被限制了
if player.LimitStatus != mtype.FissionReferralLimitStatusNone {
return
}
conf, err := cache.NewCampaignWin(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 *win) _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 := winDo{
step: func(player *model.FissionWin, conf *model.FissionCampaignWin, reward, nextReward *model.FissionCampaignReward, allInviteNum int32) (err error) {
return s._step(user, effectNum, player, conf, reward, nextReward, allInviteNum)
},
cycle: func(player *model.FissionWin, conf *model.FissionCampaignWin, 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 *win) _fixTaskDo(user *model.FissionUser, tasks []*model.FissionCampaignTask) (err error) {
do := winDo{
step: func(player *model.FissionWin, conf *model.FissionCampaignWin, 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.FissionWin, conf *model.FissionCampaignWin, 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 *win) _step(user *model.FissionUser, effectNum int64, player *model.FissionWin, conf *model.FissionCampaignWin, 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().FissionWin
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 *win) _cycle(user *model.FissionUser, effectNum int64, player *model.FissionWin, conf *model.FissionCampaignWin, 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 *win) _limitStatus(playerId int64, ls int8) (err error) {
if ls == mtype.FissionReferralLimitStatusNone {
return
}
m := s.GetDao().FissionWin
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 *win) _extra(user *model.FissionUser, player *model.FissionWin, 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().FissionWin
_, 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
}