修复(#79): 促销管理后台API + 审查问题修复
- 实现促销管理接口:规则CRUD、优惠价配置、使用记录查询 - 修复 UpsertPrices 新增记录时提前 return 的问题 - DeleteRule/DeletePrice 不存在记录返回 code=404 - SetPromoPriceRequest.items 空数组校验 - 分页参数限制 page>0、1<=size<=200 - 下单侧促销价格按数量档总价口径计算(含 #87 修复) Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
func TestPromoPriceItemsMustNotBeEmpty(t *testing.T) {
|
||||
validate := validator.New()
|
||||
req := SetPromoPriceRequest{
|
||||
PromoRuleId: 1,
|
||||
Items: []PromoPriceItem{},
|
||||
}
|
||||
|
||||
if err := validate.Struct(req); err == nil {
|
||||
t.Fatal("expected empty promo price items to fail validation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromoListPageSizeLimit(t *testing.T) {
|
||||
validate := validator.New()
|
||||
tests := []struct {
|
||||
name string
|
||||
req any
|
||||
}{
|
||||
{
|
||||
name: "rule list",
|
||||
req: GetPromoRuleListRequest{
|
||||
Page: 1,
|
||||
Size: 201,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "price list",
|
||||
req: GetPromoPriceListRequest{
|
||||
PromoRuleId: 1,
|
||||
Page: 1,
|
||||
Size: 201,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "usage list",
|
||||
req: GetPromoUsageListRequest{
|
||||
Page: 1,
|
||||
Size: 201,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := validate.Struct(tt.req); err == nil {
|
||||
t.Fatal("expected page size greater than 200 to fail validation")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -316,6 +316,45 @@ type ContactRequest struct {
|
||||
Notes string `json:"notes" validate:"max=2000"`
|
||||
}
|
||||
|
||||
type PromoPrice struct {
|
||||
Id int64 `json:"id"`
|
||||
SubscribeId int64 `json:"subscribe_id"`
|
||||
PromoRuleId int64 `json:"promo_rule_id"`
|
||||
Quantity int64 `json:"quantity"`
|
||||
PromoPrice int64 `json:"promo_price"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type PromoPriceItem struct {
|
||||
SubscribeId int64 `json:"subscribe_id" validate:"required,gt=0"`
|
||||
Quantity int64 `json:"quantity" validate:"required,gt=0,lte=1000"`
|
||||
PromoPrice int64 `json:"promo_price" validate:"required,gt=0"`
|
||||
}
|
||||
|
||||
type PromoRule struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
Priority int64 `json:"priority"`
|
||||
Enabled bool `json:"enabled"`
|
||||
StartTime *int64 `json:"start_time"`
|
||||
EndTime *int64 `json:"end_time"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type PromoUsage struct {
|
||||
Id int64 `json:"id"`
|
||||
UserId int64 `json:"user_id"`
|
||||
PromoRuleId int64 `json:"promo_rule_id"`
|
||||
SubscribeId int64 `json:"subscribe_id"`
|
||||
OrderNo string `json:"order_no"`
|
||||
PromoPrice int64 `json:"promo_price"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
|
||||
type Coupon struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -375,6 +414,16 @@ type CreateCouponRequest struct {
|
||||
Enable *bool `json:"enable,omitempty"`
|
||||
}
|
||||
|
||||
type CreatePromoRuleRequest struct {
|
||||
Name string `json:"name" validate:"required,max=100"`
|
||||
Type string `json:"type" validate:"required,oneof=new_user inactive_user campaign"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
Priority int64 `json:"priority" validate:"gte=0"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
StartTime *int64 `json:"start_time"`
|
||||
EndTime *int64 `json:"end_time"`
|
||||
}
|
||||
|
||||
type CreateDocumentRequest struct {
|
||||
Title string `json:"title" validate:"required"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
@@ -1096,6 +1145,48 @@ type GetCouponListResponse struct {
|
||||
List []Coupon `json:"list"`
|
||||
}
|
||||
|
||||
type GetPromoPriceListRequest struct {
|
||||
PromoRuleId int64 `form:"promo_rule_id" validate:"required,gt=0"`
|
||||
Page int64 `form:"page" validate:"required,gt=0"`
|
||||
Size int64 `form:"size" validate:"required,gt=0,lte=200"`
|
||||
}
|
||||
|
||||
type GetPromoPriceListResponse struct {
|
||||
Total int64 `json:"total"`
|
||||
List []PromoPrice `json:"list"`
|
||||
}
|
||||
|
||||
type GetPromoRuleDetailRequest struct {
|
||||
Id int64 `uri:"id" validate:"required,gt=0"`
|
||||
}
|
||||
|
||||
type GetPromoRuleListRequest struct {
|
||||
Page int64 `form:"page" validate:"required,gt=0"`
|
||||
Size int64 `form:"size" validate:"required,gt=0,lte=200"`
|
||||
Type string `form:"type" validate:"omitempty,oneof=new_user inactive_user campaign"`
|
||||
Enabled *bool `form:"enabled"`
|
||||
Search string `form:"search,omitempty"`
|
||||
}
|
||||
|
||||
type GetPromoRuleListResponse struct {
|
||||
Total int64 `json:"total"`
|
||||
List []PromoRule `json:"list"`
|
||||
}
|
||||
|
||||
type GetPromoUsageListRequest struct {
|
||||
Page int64 `form:"page" validate:"required,gt=0"`
|
||||
Size int64 `form:"size" validate:"required,gt=0,lte=200"`
|
||||
RuleId int64 `form:"rule_id,omitempty"`
|
||||
UserId int64 `form:"user_id,omitempty"`
|
||||
SubscribeId int64 `form:"subscribe_id,omitempty"`
|
||||
OrderNo string `form:"order_no,omitempty"`
|
||||
}
|
||||
|
||||
type GetPromoUsageListResponse struct {
|
||||
Total int64 `json:"total"`
|
||||
List []PromoUsage `json:"list"`
|
||||
}
|
||||
|
||||
type GetDetailRequest struct {
|
||||
Id int64 `form:"id" validate:"required"`
|
||||
}
|
||||
@@ -3130,6 +3221,30 @@ type UpdateCouponRequest struct {
|
||||
Enable *bool `json:"enable,omitempty"`
|
||||
}
|
||||
|
||||
type SetPromoPriceRequest struct {
|
||||
PromoRuleId int64 `json:"promo_rule_id" validate:"required,gt=0"`
|
||||
Items []PromoPriceItem `json:"items" validate:"required,min=1,dive"`
|
||||
}
|
||||
|
||||
type DeletePromoPriceRequest struct {
|
||||
Id int64 `uri:"id" validate:"required,gt=0"`
|
||||
}
|
||||
|
||||
type DeletePromoRuleRequest struct {
|
||||
Id int64 `uri:"id" validate:"required,gt=0"`
|
||||
}
|
||||
|
||||
type UpdatePromoRuleRequest struct {
|
||||
Id int64 `uri:"id" validate:"required,gt=0"`
|
||||
Name string `json:"name" validate:"required,max=100"`
|
||||
Type string `json:"type" validate:"required,oneof=new_user inactive_user campaign"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
Priority int64 `json:"priority" validate:"gte=0"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
StartTime *int64 `json:"start_time"`
|
||||
EndTime *int64 `json:"end_time"`
|
||||
}
|
||||
|
||||
type UpdateDocumentRequest struct {
|
||||
Id int64 `json:"id" validate:"required"`
|
||||
Title string `json:"title" validate:"required"`
|
||||
|
||||
Reference in New Issue
Block a user