bindbox-game/internal/service/user/coupons_list.go
Zuncle 4ffd8e8326 fix: 修复过期优惠券仍可兑换/使用的漏洞
- store.go: 积分商城优惠券列表加 valid_end > now 过滤
- coupons_list.go: 修复 NULL valid_end 被错误排除,无截止日期券正确显示为有效
- activity_order_service.go: 过期/不可用券下单返回明确错误,不再静默跳过
- points_redeem_coupon_app.go: 积分兑换前校验模板 valid_end
- coupon_add.go: 发券前校验模板 valid_end,过期拒绝发放
2026-03-18 21:58:25 +08:00

92 lines
2.8 KiB
Go
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package user
import (
"context"
"time"
"bindbox-game/internal/repository/mysql/model"
)
func (s *service) ListCoupons(ctx context.Context, userID int64, page, pageSize int) (items []*model.UserCoupons, total int64, err error) {
return s.ListCouponsByStatus(ctx, userID, 1, page, pageSize)
}
// ListCouponsByStatus 按状态获取用户优惠券列表
func (s *service) ListCouponsByStatus(ctx context.Context, userID int64, status int32, page, pageSize int) (items []*model.UserCoupons, total int64, err error) {
q := s.readDB.UserCoupons.WithContext(ctx).ReadDB().Where(
s.readDB.UserCoupons.UserID.Eq(userID),
s.readDB.UserCoupons.Status.Eq(status),
)
total, err = q.Count()
if err != nil {
return nil, 0, err
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
if pageSize > 100 {
pageSize = 100
}
items, err = q.Order(s.readDB.UserCoupons.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
return items, total, nil
}
// ListAppCoupons APP端查看优惠券
// status=1 有效(未使用+使用中) status=2 已失效(用完+已使用+已过期)
func (s *service) ListAppCoupons(ctx context.Context, userID int64, status int32, page, pageSize int) (items []*model.UserCoupons, total int64, err error) {
u := s.readDB.UserCoupons
c := s.readDB.SystemCoupons
now := time.Now()
tableName := u.TableName()
sysTableName := c.TableName()
db := u.UnderlyingDB().WithContext(ctx).
Table(tableName).
Select("`"+tableName+"`.*").
Joins("LEFT JOIN `"+sysTableName+"` ON `"+sysTableName+"`.id = `"+tableName+"`.coupon_id").
Where("`"+tableName+"`.user_id = ?", userID)
switch status {
case 1: // 有效:余额 > 0 且 未过期NULL/零值 valid_end 视为永久有效)
db = db.Where(
tableName+".balance_amount > ? AND "+
"("+tableName+".valid_end IS NULL OR "+tableName+".valid_end = ? OR "+tableName+".valid_end > ?) AND "+
tableName+".status IN (?, ?, ?)",
0, time.Time{}, now, 1, 2, 4,
)
case 2: // 已失效:余额用完 OR 已标记过期 OR 已过截止时间
db = db.Where("("+tableName+".balance_amount = ?) OR "+tableName+".status = ? OR ("+tableName+".valid_end IS NOT NULL AND "+tableName+".valid_end != ? AND "+tableName+".valid_end <= ?)", 0, 3, time.Time{}, now)
default:
db = db.Where(
tableName+".balance_amount > ? AND "+
"("+tableName+".valid_end IS NULL OR "+tableName+".valid_end = ? OR "+tableName+".valid_end > ?) AND "+
tableName+".status IN (?, ?, ?)",
0, time.Time{}, now, 1, 2, 4,
)
}
if err = db.Count(&total).Error; err != nil {
return nil, 0, err
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
err = db.Order("`" + tableName + "`.id DESC").Offset((page - 1) * pageSize).Limit(pageSize).Scan(&items).Error
if err != nil {
return nil, 0, err
}
return items, total, nil
}