new-api/controller/promo_code_user.go
zizi 0ff2fff94d feat: add promo code management and payment settings
Add default-web promo code CRUD, user/channel concurrency controls, and domestic Alipay/Wxpay billing settings. Harden promo code validation and preserve explicit zero concurrency limits with backend regression coverage.
2026-05-20 21:45:28 +08:00

94 lines
2.2 KiB
Go

package controller
import (
"errors"
"time"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/model"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
const invalidPromoCodeReason = "invalid"
type validatePromoCodeRequest struct {
Code string `json:"code"`
Amount int `json:"amount"`
}
type validatePromoCodeResponse struct {
Valid bool `json:"valid"`
Reason string `json:"reason"`
PromoCodeId int `json:"promo_code_id"`
BonusAmount int `json:"bonus_amount"`
Code string `json:"code"`
}
func ValidatePromoCode(c *gin.Context) {
var req validatePromoCodeRequest
if err := c.ShouldBindJSON(&req); err != nil {
common.ApiError(c, err)
return
}
code := normalizePromoCode(req.Code)
if !isPromoCodeSyntaxValid(code) {
common.ApiSuccess(c, newInvalidPromoCodeResponse(code))
return
}
promoCode, err := model.GetPromoCodeByCode(code)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
common.ApiSuccess(c, newInvalidPromoCodeResponse(code))
return
}
common.ApiError(c, err)
return
}
if promoCode.Status != 1 {
common.ApiSuccess(c, newInvalidPromoCodeResponse(code))
return
}
if promoCode.ExpiresAt != nil && promoCode.ExpiresAt.Before(time.Now()) {
common.ApiSuccess(c, newInvalidPromoCodeResponse(code))
return
}
if promoCode.MaxUses > 0 && promoCode.UsedCount >= promoCode.MaxUses {
common.ApiSuccess(c, newInvalidPromoCodeResponse(code))
return
}
if req.Amount < promoCode.MinRechargeAmount {
common.ApiSuccess(c, newInvalidPromoCodeResponse(code))
return
}
userId := c.GetInt("id")
if _, err := model.GetPromoCodeUsageByCodeAndUser(promoCode.Id, userId); err == nil {
common.ApiSuccess(c, newInvalidPromoCodeResponse(code))
return
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
common.ApiError(c, err)
return
}
common.ApiSuccess(c, validatePromoCodeResponse{
Valid: true,
Reason: "",
PromoCodeId: promoCode.Id,
BonusAmount: promoCode.BonusAmount,
Code: promoCode.Code,
})
}
func newInvalidPromoCodeResponse(code string) validatePromoCodeResponse {
return validatePromoCodeResponse{
Valid: false,
Reason: invalidPromoCodeReason,
Code: code,
}
}