diff --git a/internal/api/app/store.go b/internal/api/app/store.go index 70b9b64..6ff833b 100755 --- a/internal/api/app/store.go +++ b/internal/api/app/store.go @@ -1,6 +1,8 @@ package app import ( + "time" + "bindbox-game/internal/code" "bindbox-game/internal/pkg/core" "bindbox-game/internal/pkg/logger" @@ -120,7 +122,8 @@ func (h *storeHandler) ListStoreItemsForApp() core.HandlerFunc { list[i] = listStoreItem{ID: it.ID, Kind: "item_card", Name: it.Name, Price: it.Price, PointsRequired: pts, Status: it.Status, Supported: true} } case "coupon": - q := h.readDB.SystemCoupons.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.SystemCoupons.Status.Eq(1), h.readDB.SystemCoupons.ShowInMiniapp.Eq(1)) + now := time.Now() + q := h.readDB.SystemCoupons.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.SystemCoupons.Status.Eq(1), h.readDB.SystemCoupons.ShowInMiniapp.Eq(1), h.readDB.SystemCoupons.ValidEnd.Gt(now)) // 关键词筛选 if req.Keyword != "" { q = q.Where(h.readDB.SystemCoupons.Name.Like("%" + req.Keyword + "%")) diff --git a/internal/api/user/points_redeem_coupon_app.go b/internal/api/user/points_redeem_coupon_app.go index 651c1c8..964849b 100755 --- a/internal/api/user/points_redeem_coupon_app.go +++ b/internal/api/user/points_redeem_coupon_app.go @@ -1,11 +1,13 @@ package app import ( + "net/http" + "strconv" + "time" + "bindbox-game/internal/code" "bindbox-game/internal/pkg/core" "bindbox-game/internal/pkg/validation" - "net/http" - "strconv" ) type redeemCouponRequest struct { @@ -52,6 +54,10 @@ func (h *handler) RedeemPointsToCoupon() core.HandlerFunc { ctx.AbortWithError(core.Error(http.StatusBadRequest, 150002, "only amount coupons supported")) return } + if !sc.ValidEnd.IsZero() && sc.ValidEnd.Before(time.Now()) { + ctx.AbortWithError(core.Error(http.StatusBadRequest, 150005, "该优惠券模板已过期,无法兑换")) + return + } // sc.DiscountValue 是优惠券面值(分),直接用于扣除 // 例如:30 元优惠券 = 3000 分 needCents := sc.DiscountValue diff --git a/internal/service/activity/activity_order_service.go b/internal/service/activity/activity_order_service.go index 133249c..adc55ef 100755 --- a/internal/service/activity/activity_order_service.go +++ b/internal/service/activity/activity_order_service.go @@ -229,8 +229,7 @@ func (s *activityOrderService) applyCouponWithLock(ctx context.Context, tx *dao. // 如果是金额券,status=1。 // 如果是满减券,status=1。 if uc.Status != 1 { - fmt.Printf("[优惠券] 状态不可用 id=%d status=%d\n", userCouponID, uc.Status) - return 0, nil, nil + return 0, nil, fmt.Errorf("优惠券不可用") } fmt.Printf("[优惠券] 用户券ID=%d 开始=%s 结束=%s 余额=%d\n", userCouponID, uc.ValidStart.Format(time.RFC3339), func() string { @@ -243,25 +242,20 @@ func (s *activityOrderService) applyCouponWithLock(ctx context.Context, tx *dao. sc, _ := tx.SystemCoupons.WithContext(ctx).Where(tx.SystemCoupons.ID.Eq(uc.CouponID), tx.SystemCoupons.Status.Eq(1)).First() now := time.Now() if sc == nil { - fmt.Printf("[优惠券] 模板不存在 用户券ID=%d\n", userCouponID) - return 0, nil, nil + return 0, nil, fmt.Errorf("优惠券模板不存在") } if uc.ValidStart.After(now) { - fmt.Printf("[优惠券] 未到开始时间 用户券ID=%d\n", userCouponID) - return 0, nil, nil + return 0, nil, fmt.Errorf("优惠券未到使用时间") } if !uc.ValidEnd.IsZero() && uc.ValidEnd.Before(now) { - fmt.Printf("[优惠券] 已过期 用户券ID=%d\n", userCouponID) - return 0, nil, nil + return 0, nil, fmt.Errorf("优惠券已过期") } scopeOK := (sc.ScopeType == 1) || (sc.ScopeType == 2 && sc.ActivityID == activityID) if !scopeOK { - fmt.Printf("[优惠券] 范围不匹配 用户券ID=%d scope_type=%d\n", userCouponID, sc.ScopeType) - return 0, nil, nil + return 0, nil, fmt.Errorf("优惠券不适用于当前活动") } if order.TotalAmount < sc.MinSpend { - fmt.Printf("[优惠券] 未达使用门槛 用户券ID=%d min_spend(分)=%d 订单总额(分)=%d\n", userCouponID, sc.MinSpend, order.TotalAmount) - return 0, nil, nil + return 0, nil, fmt.Errorf("订单金额未达优惠券使用门槛") } // 50% 封顶 diff --git a/internal/service/user/coupon_add.go b/internal/service/user/coupon_add.go index 87c6df8..1cbcdd2 100755 --- a/internal/service/user/coupon_add.go +++ b/internal/service/user/coupon_add.go @@ -26,6 +26,9 @@ func (s *service) AddCoupon(ctx context.Context, userID int64, couponID int64) e }()) return errors.New("coupon not found or disabled") } + if !tpl.ValidEnd.IsZero() && tpl.ValidEnd.Before(time.Now()) { + return errors.New("coupon template expired") + } // 配额检查:若 TotalQuantity > 0 则限制发放总量 if tpl.TotalQuantity > 0 { issued, ierr := s.readDB.UserCoupons.WithContext(ctx).Where(s.readDB.UserCoupons.CouponID.Eq(couponID)).Count() diff --git a/internal/service/user/coupons_list.go b/internal/service/user/coupons_list.go index 1a4befc..42c1f14 100755 --- a/internal/service/user/coupons_list.go +++ b/internal/service/user/coupons_list.go @@ -53,12 +53,22 @@ func (s *service) ListAppCoupons(ctx context.Context, userID int64, status int32 Where("`"+tableName+"`.user_id = ?", userID) switch status { - case 1: // 有效:余额 > 0 且 未过期 - db = db.Where(tableName+".balance_amount > ? AND "+tableName+".valid_end > ? AND "+tableName+".status IN (?, ?, ?)", 0, now, 1, 2, 4) + 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 <= ?", 0, 3, now) + 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 > ? AND "+tableName+".status IN (?, ?, ?)", 0, now, 1, 2, 4) + 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 {