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.

251 lines
5.2 KiB
Go

package award
import (
"context"
"joybuywork/internal/repository/cache"
"joybuywork/internal/repository/dao"
"joybuywork/internal/repository/dbcheck"
"joybuywork/internal/repository/model"
"joybuywork/internal/repository/mtype"
"joybuywork/internal/service/provider/stocks"
"joybuywork/internal/utils/merr"
)
const (
IssVerifyPointDeductStock = "DeductStock" // 扣除库存
IssVerifyPointDeductPreStock = "DeductSelectStock" // 扣除预备库存
IssVerifyPointRuleFilter = "RuleFilter" // 规则过滤
IssVerifyPointUnlock = "Unlock" // 解锁
)
type IssVerify struct {
ctx context.Context
be *merr.BusinessError
user *model.FissionUser
reward *model.FissionCampaignReward
unlimitStock bool // 不限制库存
hasFail bool // 是否校验失败
point string // 当前校验节点
err error // 错误信息
failDone []func() // 验证不通过要做一些操作,如:返还库存
}
// NewAwardIssVerify 奖品发放验证
func NewAwardIssVerify(ctx context.Context, user *model.FissionUser, reward *model.FissionCampaignReward) *IssVerify {
return &IssVerify{
ctx: ctx,
be: merr.NewBE(ctx),
user: user,
reward: reward,
unlimitStock: reward.IsThank == mtype.Yes ||
reward.Stock == -1 ||
reward.PropMark == mtype.FissionCampaignRewardPropMarkPoint,
}
}
// IsOK 校验结果
func (s *IssVerify) IsOK() (bool, error) {
if s.err != nil {
return false, s.err
}
if s.hasFail {
for _, f := range s.failDone {
f()
}
}
return !s.hasFail, nil
}
// PointOK 返回验证节点,如果错误,当前返回节点校验不通过
func (s *IssVerify) PointOK() (point string, ok bool, err error) {
if s.err != nil {
err = s.err
return
}
if s.hasFail {
for _, f := range s.failDone {
f()
}
point = s.point
return
}
ok = true
return
}
// DeductStock 扣除库存
func (s *IssVerify) DeductStock() (next *IssVerify) {
if s.err != nil || s.hasFail {
return s
}
s.point = IssVerifyPointDeductStock
reward := s.reward
stock, err := stocks.NewCampaignReward(s.ctx, reward.ID)
if err != nil {
s.err = err
return s.setVerify(false, err)
}
// 如果是谢谢参与奖,增加使用库存
if s.unlimitStock {
err = stock.AddUseStock(1)
if err != nil {
s.err = err
return s.setVerify(false, err)
}
s.failDone = append(s.failDone, func() {
// 还原库存
_ = stock.AddUseStock(-1)
})
return s.setVerify(true, nil)
}
ok, err := stock.DecrPoolAndAdd(reward.ID, 1)
if err != nil || !ok {
s.err = err
return s.setVerify(false, err)
}
s.failDone = append(s.failDone, func() {
// 还原库存
_, _ = stock.DecrPoolAndAdd(reward.ID, -1)
})
return s.setVerify(true, nil)
}
// DeductSelectStock 扣除选择库存
func (s *IssVerify) DeductSelectStock() (next *IssVerify) {
if s.err != nil || s.hasFail {
return s
}
s.point = IssVerifyPointDeductPreStock
reward := s.reward
stock, err := stocks.NewCampaignRewardSelect(s.ctx, reward.ID)
if err != nil {
s.err = err
return s.setVerify(false, err)
}
// 如果是谢谢参与奖,增加使用库存
if s.unlimitStock {
err = stock.AddUseStock(1)
if err != nil {
s.err = err
return s.setVerify(false, err)
}
s.failDone = append(s.failDone, func() {
// 还原库存
_ = stock.AddUseStock(-1)
})
return s.setVerify(true, nil)
}
ok, err := stock.DecrPoolAndAdd(reward.ID, 1)
if err != nil || !ok {
s.err = err
return s.setVerify(false, err)
}
s.failDone = append(s.failDone, func() {
// 还原库存
_, _ = stock.DecrPoolAndAdd(reward.ID, -1)
})
return s.setVerify(true, nil)
}
// RuleFilter 规则过滤
func (s *IssVerify) RuleFilter() (next *IssVerify) {
if s.err != nil || s.hasFail {
return s
}
s.point = IssVerifyPointRuleFilter
if s.reward.HasRule == mtype.No || s.reward.IsThank == mtype.Yes {
return s.setVerify(true, nil)
}
rule, err := cache.NewCampaignRewardRule(s.ctx).FindByRewardId(s.reward.ID)
if err != nil {
return s.setVerify(false, s.be.CacheError(err))
}
if rule == nil {
return s.setVerify(true, nil)
}
m := dao.FissionRewardRecord.SubTable(s.user.CampaignID)
if rule.CampaignLimit > 0 {
var count int64
count, err = m.WithContext(s.ctx).Where(m.UserID.Eq(s.user.ID), m.RewardID.Eq(s.reward.ID)).Count()
if err != nil {
return s.setVerify(false, s.be.MysqlError(err))
}
if count >= int64(rule.CampaignLimit) {
return s.setVerify(false, nil)
}
}
return s.setVerify(true, nil)
}
// Unlock 解锁
func (s *IssVerify) Unlock() (next *IssVerify) {
if s.err != nil || s.hasFail {
return s
}
s.point = IssVerifyPointUnlock
if s.reward.OpenTask == mtype.No || s.reward.IsThank == mtype.Yes {
return s.setVerify(true, nil)
}
cpnId, userId, rewardId := s.user.CampaignID, s.user.ID, s.reward.ID
m := dao.FissionUnlockReward
ulr, err := m.WithContext(s.ctx).Where(
m.CampaignID.Eq(cpnId),
m.UserID.Eq(userId),
m.RewardID.Eq(rewardId),
).Take()
if err = dbcheck.DbError(err); err != nil {
s.err = err
return s.setVerify(false, err)
}
if ulr == nil {
return s.setVerify(false, nil)
}
return s.setVerify(true, nil)
}
// 设置验证信息
func (s *IssVerify) setVerify(ok bool, err error) *IssVerify {
s.err = err
if !ok {
s.hasFail = true
}
return s
}