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 }