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.
371 lines
9.2 KiB
Go
371 lines
9.2 KiB
Go
package award
|
|
|
|
import (
|
|
"context"
|
|
"joybuywork/internal/repository/dao"
|
|
"joybuywork/internal/repository/model"
|
|
"joybuywork/internal/repository/mtype"
|
|
"joybuywork/internal/repository/withdefault"
|
|
"joybuywork/internal/service/cmm"
|
|
"joybuywork/internal/service/provider"
|
|
"joybuywork/internal/service/provider/fissionaction"
|
|
"joybuywork/internal/service/provider/projectuser"
|
|
"joybuywork/internal/service/queue/producer"
|
|
"joybuywork/internal/service/queue/types"
|
|
"joybuywork/internal/utils/logic"
|
|
"joybuywork/internal/utils/merr"
|
|
"joybuywork/internal/utils/verify"
|
|
"fmt"
|
|
)
|
|
|
|
type RecordOption func(record *model.FissionRewardRecord)
|
|
|
|
// RewardRecordStatus 设置状态
|
|
func RewardRecordStatus(status int8, failType, failMsg string) RecordOption {
|
|
return func(record *model.FissionRewardRecord) {
|
|
record.Status = status
|
|
record.FailType = failType
|
|
record.FailMsg = failMsg
|
|
}
|
|
}
|
|
|
|
// RewardRecordAnswer 设置题答题目
|
|
func RewardRecordAnswer(answer string, score int32) RecordOption {
|
|
return func(record *model.FissionRewardRecord) {
|
|
record.Answer = answer
|
|
record.Score = score
|
|
}
|
|
}
|
|
|
|
// RewardRecordChildId 设置子活动
|
|
func RewardRecordChildId(childId int64) RecordOption {
|
|
return func(record *model.FissionRewardRecord) {
|
|
record.ChildID = childId
|
|
}
|
|
}
|
|
|
|
type Reward struct {
|
|
logic.Context
|
|
|
|
user *model.FissionUser
|
|
projectId int64
|
|
|
|
coinInfo struct {
|
|
Title string
|
|
ImgURL string
|
|
RewardTitle string
|
|
}
|
|
|
|
async []func()
|
|
}
|
|
|
|
// NewAwardReward 奖品发放验证
|
|
func NewAwardReward(ctx context.Context, dao *dao.Query, projectId int64, user *model.FissionUser) *Reward {
|
|
award := &Reward{
|
|
user: user,
|
|
projectId: projectId,
|
|
}
|
|
|
|
award.Init(ctx, dao, merr.NewBE(ctx))
|
|
|
|
return award
|
|
}
|
|
|
|
// RewardIdsBatch 通过奖品id扣除奖品
|
|
func (s *Reward) RewardIdsBatch(rewardIds []int64, sync bool) (res []*RewardRes, async []func(), err error) {
|
|
m := s.GetDao().FissionCampaignReward
|
|
rewards, err := m.WithContext(s.Ctx).Where(m.ID.In(rewardIds...)).Find()
|
|
if err != nil {
|
|
err = s.BE().MysqlError(err)
|
|
return
|
|
}
|
|
|
|
if len(rewards) == 0 {
|
|
return
|
|
}
|
|
|
|
var rewardMap = make(map[int64]*model.FissionCampaignReward)
|
|
for _, v := range rewards {
|
|
rewardMap[v.ID] = v
|
|
}
|
|
|
|
var sendRewards = make([]*model.FissionCampaignReward, 0, len(rewardIds))
|
|
for _, v := range rewardIds {
|
|
|
|
reward, has := rewardMap[v]
|
|
if !has {
|
|
continue
|
|
}
|
|
|
|
sendRewards = append(sendRewards, reward)
|
|
}
|
|
|
|
if len(sendRewards) == 0 {
|
|
return
|
|
}
|
|
|
|
return s.DeductStockBatch(sendRewards, sync)
|
|
}
|
|
|
|
// DeductStockOne 扣除单个缓存
|
|
func (s *Reward) DeductStockOne(reward *model.FissionCampaignReward, sync bool) (record *model.FissionRewardRecord, info provider.RewardAutoLang, async []func(), err error) {
|
|
res, async, err := s.DeductStockBatch([]*model.FissionCampaignReward{reward}, sync)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return res[0].Record, res[0].Info, async, nil
|
|
}
|
|
|
|
// DeductStockBatch 扣除缓存的批量处理
|
|
func (s *Reward) DeductStockBatch(rewards []*model.FissionCampaignReward, sync bool) (res []*RewardRes, async []func(), err error) {
|
|
var addRewards = make([]*RewardOne, 0, len(rewards))
|
|
|
|
for _, reward := range rewards {
|
|
ok, err1 := NewAwardIssVerify(s.Ctx, s.user, reward).DeductStock().IsOK()
|
|
if err1 != nil {
|
|
err = err1
|
|
return
|
|
}
|
|
|
|
var opts []RecordOption
|
|
if !ok {
|
|
opts = append(opts, RewardRecordStatus(
|
|
mtype.FissionRewardRecordStatusFail,
|
|
mtype.FissionRewardRecordFailTypeCli,
|
|
mtype.FissionRewardRecordFailTypeCliLackMsg,
|
|
))
|
|
}
|
|
|
|
addRewards = append(addRewards, &RewardOne{
|
|
Reward: reward,
|
|
Opts: opts,
|
|
})
|
|
}
|
|
|
|
return s.Batch(addRewards, sync)
|
|
}
|
|
|
|
// One 创建用户奖品
|
|
func (s *Reward) One(reward *model.FissionCampaignReward, sync bool, opts ...RecordOption) (record *model.FissionRewardRecord, info provider.RewardAutoLang, async []func(), err error) {
|
|
var one = &RewardOne{
|
|
Reward: reward,
|
|
Opts: opts,
|
|
}
|
|
|
|
res, async, err := s.Batch([]*RewardOne{one}, sync)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return res[0].Record, res[0].Info, async, nil
|
|
}
|
|
|
|
type RewardOne struct {
|
|
Reward *model.FissionCampaignReward
|
|
Opts []RecordOption
|
|
}
|
|
|
|
type RewardRes struct {
|
|
Record *model.FissionRewardRecord
|
|
Info provider.RewardAutoLang
|
|
Reward *model.FissionCampaignReward
|
|
}
|
|
|
|
// Batch 批量创建用户奖品
|
|
func (s *Reward) Batch(rewards []*RewardOne, sync bool) (res []*RewardRes, async []func(), err error) {
|
|
if len(rewards) == 0 {
|
|
return
|
|
}
|
|
|
|
user := s.user
|
|
|
|
var brIds []int64
|
|
for _, reward := range rewards {
|
|
if reward.Reward.RewardID == 0 {
|
|
continue
|
|
}
|
|
|
|
brIds = append(brIds, reward.Reward.RewardID)
|
|
}
|
|
|
|
var preward *provider.Rewards
|
|
if len(brIds) > 0 {
|
|
preward, err = provider.NewRewards(s.Ctx, s.projectId, brIds...)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
res = make([]*RewardRes, 0, len(rewards))
|
|
|
|
var records = make([]*model.FissionRewardRecord, 0, len(rewards))
|
|
|
|
for _, one := range rewards {
|
|
reward := one.Reward
|
|
|
|
record := withdefault.FissionRewardRecord(&model.FissionRewardRecord{
|
|
CampaignID: user.CampaignID,
|
|
UserID: user.ID,
|
|
RewardID: reward.ID,
|
|
RewardType: reward.RewardType,
|
|
RewardNum: reward.RewardNum,
|
|
Step: reward.Step,
|
|
IsThank: reward.IsThank,
|
|
BaseRewardID: reward.RewardID,
|
|
PropMark: reward.PropMark,
|
|
})
|
|
|
|
if verify.InArray[string](reward.PropMark, mtype.FissionCampaignRewardPropMarkChance, mtype.FissionCampaignRewardPropMarkPoint) || reward.RewardID < 0 {
|
|
record.Status = mtype.FissionRewardRecordStatusSuccess
|
|
}
|
|
|
|
if reward.RewardType == mtype.FissionCampaignRewardTypeChild {
|
|
record.ChildID = reward.CampaignID
|
|
}
|
|
|
|
for _, opt := range one.Opts {
|
|
opt(record)
|
|
}
|
|
|
|
var info provider.RewardAutoLang
|
|
if reward.PropMark == mtype.FissionCampaignRewardPropMarkPoint {
|
|
info.Title, info.ImgUrl, info.RewardTitle, _ = s.getCoinInfo(user.LangMark)
|
|
} else if reward.RewardID != 0 && preward != nil {
|
|
info, _ = preward.InfoAutoLang(reward.RewardID, user.LangMark)
|
|
}
|
|
|
|
record.Title, record.ImgURL = info.Title, info.ImgUrl
|
|
|
|
records = append(records, record)
|
|
res = append(res, &RewardRes{
|
|
Record: nil,
|
|
Info: info,
|
|
Reward: reward,
|
|
})
|
|
}
|
|
|
|
m := s.GetDao().FissionRewardRecord
|
|
err = m.WithContext(s.Ctx).Create(records...)
|
|
if err != nil {
|
|
err = s.BE().MysqlError(err)
|
|
return
|
|
}
|
|
|
|
sm := s.GetDao().FissionRewardRecord.SubTable(user.CampaignID)
|
|
err = sm.WithContext(s.Ctx).Create(records...)
|
|
if err != nil {
|
|
err = s.BE().MysqlError(err)
|
|
return
|
|
}
|
|
|
|
var earnCoin []*projectuser.EarnCoinParam
|
|
for k, record := range records {
|
|
|
|
res[k].Record = record
|
|
|
|
switch record.PropMark {
|
|
case mtype.FissionCampaignRewardPropMarkPoint:
|
|
var operate = mtype.ProjectUserCoinAddReward
|
|
switch res[k].Reward.RewardType {
|
|
case mtype.FissionCampaignRewardTypeTask:
|
|
operate = mtype.ProjectUserCoinAddTask
|
|
}
|
|
|
|
earnCoin = append(earnCoin, &projectuser.EarnCoinParam{
|
|
CoinNum: record.RewardNum,
|
|
IsExpired: res[k].Reward.IsExpired(),
|
|
ExpiredAt: res[k].Reward.ExpiredAt(),
|
|
Source: mtype.ProjectUserCoinSourceCampaign,
|
|
SourceID: record.CampaignID,
|
|
SourceData: map[string]string{
|
|
"reward_id": fmt.Sprintf("%d", record.RewardID),
|
|
"record_id": fmt.Sprintf("%d", record.ID),
|
|
},
|
|
Operate: operate,
|
|
})
|
|
default:
|
|
s.notify(record, res[k].Info)
|
|
}
|
|
|
|
s.markPoint(record)
|
|
}
|
|
|
|
if len(earnCoin) > 0 {
|
|
var pu *projectuser.ProjectUser
|
|
pu, err = projectuser.NewProjectUser(s.Ctx, projectuser.WithInit(s.projectId, s.user.SubUserID))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
err = pu.EarnCoin(earnCoin...)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
if sync {
|
|
for _, do := range s.async {
|
|
do()
|
|
}
|
|
return
|
|
}
|
|
|
|
async = s.async
|
|
|
|
return
|
|
}
|
|
|
|
// 回调
|
|
func (s *Reward) notify(record *model.FissionRewardRecord, info provider.RewardAutoLang) {
|
|
if record.Status != mtype.FissionRewardRecordStatusWait || record.PropMark == mtype.FissionCampaignRewardPropMarkChance {
|
|
return
|
|
}
|
|
|
|
if info.ReceiveType == mtype.RewardReceiveTypeClient {
|
|
_ = s.GetDao().FissionClientReward.WithContext(s.Ctx).Create(withdefault.FissionClientReward(&model.FissionClientReward{
|
|
UserID: s.user.SubUserID,
|
|
ProjectID: s.projectId,
|
|
CampaignID: s.user.CampaignID,
|
|
RecordID: record.ID,
|
|
CreatedAt: record.CreatedAt,
|
|
}))
|
|
return
|
|
}
|
|
|
|
s.async = append(s.async, func() {
|
|
producer.NewCampaignNotice(s.Ctx).CampaignRewardNotify(types.CampaignRewardNotify{
|
|
CampaignId: s.user.CampaignID,
|
|
UserId: s.user.ID,
|
|
UserRewardId: record.ID,
|
|
})
|
|
producer.CheckRewardPush(s.Ctx, 60, types.DelayCommonCheckRewardPush{
|
|
CampaignId: s.user.CampaignID,
|
|
UserId: s.user.ID,
|
|
UserRewardId: record.ID,
|
|
BaseRewardId: record.BaseRewardID,
|
|
})
|
|
})
|
|
}
|
|
|
|
// 埋点
|
|
func (s *Reward) markPoint(record *model.FissionRewardRecord) {
|
|
s.async = append(s.async, func() {
|
|
fissionaction.NewMarkPoint(s.Ctx).InApp(s.user).Reward(record.CreatedAt, record.RewardID, record.ID, record.ChildID, record.RewardType, record.RewardNum)
|
|
})
|
|
}
|
|
|
|
func (s *Reward) getCoinInfo(langMark string) (title, imgUrl, rewardTitle string, err error) {
|
|
|
|
if s.coinInfo.Title != "" {
|
|
return s.coinInfo.Title, s.coinInfo.ImgURL, s.coinInfo.RewardTitle, nil
|
|
}
|
|
|
|
s.coinInfo.Title, s.coinInfo.ImgURL, s.coinInfo.RewardTitle, err = cmm.NewCMM(s.Ctx, s.GetDao()).GetCoinInfo(s.projectId, langMark)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return s.coinInfo.Title, s.coinInfo.ImgURL, s.coinInfo.RewardTitle, nil
|
|
}
|