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.
94 lines
2.2 KiB
Go
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,
|
|
}
|
|
}
|