mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-09 08:58:23 +00:00
Merge pull request #2573 from wucm667/feat/redeem-code-expiry
feat(redeem): 兑换码支持设置使用有效期
This commit is contained in:
27 files changed
+676
-38
No files matched your search
@@ -30,6 +30,7 @@ func (r *redeemCodeRepository) Create(ctx context.Context, code *service.RedeemC
|
||||
SetStatus(code.Status).
|
||||
SetNotes(code.Notes).
|
||||
SetValidityDays(code.ValidityDays).
|
||||
SetNillableExpiresAt(code.ExpiresAt).
|
||||
SetNillableUsedBy(code.UsedBy).
|
||||
SetNillableUsedAt(code.UsedAt).
|
||||
SetNillableGroupID(code.GroupID).
|
||||
@@ -56,6 +57,7 @@ func (r *redeemCodeRepository) CreateBatch(ctx context.Context, codes []service.
|
||||
SetStatus(c.Status).
|
||||
SetNotes(c.Notes).
|
||||
SetValidityDays(c.ValidityDays).
|
||||
SetNillableExpiresAt(c.ExpiresAt).
|
||||
SetNillableUsedBy(c.UsedBy).
|
||||
SetNillableUsedAt(c.UsedAt).
|
||||
SetNillableGroupID(c.GroupID)
|
||||
@@ -107,7 +109,28 @@ func (r *redeemCodeRepository) ListWithFilters(ctx context.Context, params pagin
|
||||
q = q.Where(redeemcode.TypeEQ(codeType))
|
||||
}
|
||||
if status != "" {
|
||||
q = q.Where(redeemcode.StatusEQ(status))
|
||||
now := time.Now()
|
||||
switch status {
|
||||
case service.StatusExpired:
|
||||
q = q.Where(redeemcode.Or(
|
||||
redeemcode.StatusEQ(service.StatusExpired),
|
||||
redeemcode.And(
|
||||
redeemcode.StatusEQ(service.StatusUnused),
|
||||
redeemcode.ExpiresAtNotNil(),
|
||||
redeemcode.ExpiresAtLTE(now),
|
||||
),
|
||||
))
|
||||
case service.StatusUnused:
|
||||
q = q.Where(
|
||||
redeemcode.StatusEQ(service.StatusUnused),
|
||||
redeemcode.Or(
|
||||
redeemcode.ExpiresAtIsNil(),
|
||||
redeemcode.ExpiresAtGT(now),
|
||||
),
|
||||
)
|
||||
default:
|
||||
q = q.Where(redeemcode.StatusEQ(status))
|
||||
}
|
||||
}
|
||||
if search != "" {
|
||||
q = q.Where(
|
||||
@@ -158,6 +181,8 @@ func redeemCodeListOrder(params pagination.PaginationParams) []func(*entsql.Sele
|
||||
field = redeemcode.FieldUsedAt
|
||||
case "created_at":
|
||||
field = redeemcode.FieldCreatedAt
|
||||
case "expires_at":
|
||||
field = redeemcode.FieldExpiresAt
|
||||
case "code":
|
||||
field = redeemcode.FieldCode
|
||||
default:
|
||||
@@ -194,6 +219,11 @@ func (r *redeemCodeRepository) Update(ctx context.Context, code *service.RedeemC
|
||||
} else {
|
||||
up.ClearGroupID()
|
||||
}
|
||||
if code.ExpiresAt != nil {
|
||||
up.SetExpiresAt(*code.ExpiresAt)
|
||||
} else {
|
||||
up.ClearExpiresAt()
|
||||
}
|
||||
|
||||
updated, err := up.Save(ctx)
|
||||
if err != nil {
|
||||
@@ -307,6 +337,7 @@ func redeemCodeEntityToService(m *dbent.RedeemCode) *service.RedeemCode {
|
||||
UsedAt: m.UsedAt,
|
||||
Notes: derefString(m.Notes),
|
||||
CreatedAt: m.CreatedAt,
|
||||
ExpiresAt: m.ExpiresAt,
|
||||
GroupID: m.GroupID,
|
||||
ValidityDays: m.ValidityDays,
|
||||
}
|
||||
|
||||
@@ -51,11 +51,13 @@ func (s *RedeemCodeRepoSuite) createGroup(name string) *dbent.Group {
|
||||
// --- Create / CreateBatch / GetByID / GetByCode ---
|
||||
|
||||
func (s *RedeemCodeRepoSuite) TestCreate() {
|
||||
expiresAt := time.Now().UTC().Add(2 * time.Hour)
|
||||
code := &service.RedeemCode{
|
||||
Code: "TEST-CREATE",
|
||||
Type: service.RedeemTypeBalance,
|
||||
Value: 100,
|
||||
Status: service.StatusUnused,
|
||||
Code: "TEST-CREATE",
|
||||
Type: service.RedeemTypeBalance,
|
||||
Value: 100,
|
||||
Status: service.StatusUnused,
|
||||
ExpiresAt: &expiresAt,
|
||||
}
|
||||
|
||||
err := s.repo.Create(s.ctx, code)
|
||||
@@ -65,6 +67,8 @@ func (s *RedeemCodeRepoSuite) TestCreate() {
|
||||
got, err := s.repo.GetByID(s.ctx, code.ID)
|
||||
s.Require().NoError(err, "GetByID")
|
||||
s.Require().Equal("TEST-CREATE", got.Code)
|
||||
s.Require().NotNil(got.ExpiresAt)
|
||||
s.Require().WithinDuration(expiresAt, *got.ExpiresAt, time.Second)
|
||||
}
|
||||
|
||||
func (s *RedeemCodeRepoSuite) TestCreateBatch() {
|
||||
@@ -166,6 +170,23 @@ func (s *RedeemCodeRepoSuite) TestListWithFilters_Status() {
|
||||
s.Require().Equal(service.StatusUsed, codes[0].Status)
|
||||
}
|
||||
|
||||
func (s *RedeemCodeRepoSuite) TestListWithFilters_StatusExpiredByExpiresAt() {
|
||||
past := time.Now().UTC().Add(-time.Hour)
|
||||
future := time.Now().UTC().Add(time.Hour)
|
||||
s.Require().NoError(s.repo.Create(s.ctx, &service.RedeemCode{Code: "STAT-EXPIRED-BY-TIME", Type: service.RedeemTypeBalance, Value: 0, Status: service.StatusUnused, ExpiresAt: &past}))
|
||||
s.Require().NoError(s.repo.Create(s.ctx, &service.RedeemCode{Code: "STAT-UNUSED-FUTURE", Type: service.RedeemTypeBalance, Value: 0, Status: service.StatusUnused, ExpiresAt: &future}))
|
||||
|
||||
expired, _, err := s.repo.ListWithFilters(s.ctx, pagination.PaginationParams{Page: 1, PageSize: 10}, "", service.StatusExpired, "")
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(expired, 1)
|
||||
s.Require().Equal("STAT-EXPIRED-BY-TIME", expired[0].Code)
|
||||
|
||||
unused, _, err := s.repo.ListWithFilters(s.ctx, pagination.PaginationParams{Page: 1, PageSize: 10}, "", service.StatusUnused, "")
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(unused, 1)
|
||||
s.Require().Equal("STAT-UNUSED-FUTURE", unused[0].Code)
|
||||
}
|
||||
|
||||
func (s *RedeemCodeRepoSuite) TestListWithFilters_Search() {
|
||||
s.Require().NoError(s.repo.Create(s.ctx, &service.RedeemCode{Code: "ALPHA-CODE", Type: service.RedeemTypeBalance, Value: 0, Status: service.StatusUnused}))
|
||||
s.Require().NoError(s.repo.Create(s.ctx, &service.RedeemCode{Code: "BETA-CODE", Type: service.RedeemTypeBalance, Value: 0, Status: service.StatusUnused}))
|
||||
|
||||
Reference in new issue
Block a user