ea586e3ba2
Co-authored-by: multica-agent <github@multica.ai>
129 lines
3.6 KiB
Go
129 lines
3.6 KiB
Go
package promo
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
promoModel "github.com/perfect-panel/server/internal/model/promo"
|
|
"github.com/perfect-panel/server/internal/svc"
|
|
"github.com/perfect-panel/server/internal/types"
|
|
"github.com/perfect-panel/server/pkg/xerr"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const (
|
|
enabledRulesCacheKey = "promo:rules:enabled"
|
|
subscribePromoKeyFmt = "promo:subscribe:%d"
|
|
)
|
|
|
|
type ruleParams struct {
|
|
WindowHours int `json:"window_hours"`
|
|
InactiveMonths int `json:"inactive_months"`
|
|
}
|
|
|
|
func validateRulePayload(ruleType string, params json.RawMessage, priority, startTime, endTime int64) error {
|
|
if priority < 0 {
|
|
return xerr.NewErrCodeMsg(xerr.InvalidParams, "priority must be greater than or equal to 0")
|
|
}
|
|
if startTime >= endTime {
|
|
return xerr.NewErrCodeMsg(xerr.InvalidParams, "start_time must be less than end_time")
|
|
}
|
|
|
|
var p ruleParams
|
|
if len(params) == 0 || !json.Valid(params) {
|
|
return xerr.NewErrCodeMsg(xerr.InvalidParams, "params must be valid json")
|
|
}
|
|
if err := json.Unmarshal(params, &p); err != nil {
|
|
return xerr.NewErrCodeMsg(xerr.InvalidParams, "params must be valid json object")
|
|
}
|
|
|
|
switch ruleType {
|
|
case promoModel.RuleTypeNewUser:
|
|
if p.WindowHours <= 0 {
|
|
return xerr.NewErrCodeMsg(xerr.InvalidParams, "params.window_hours must be greater than 0")
|
|
}
|
|
case promoModel.RuleTypeInactiveUser:
|
|
if p.InactiveMonths <= 0 {
|
|
return xerr.NewErrCodeMsg(xerr.InvalidParams, "params.inactive_months must be greater than 0")
|
|
}
|
|
case promoModel.RuleTypeCampaign:
|
|
return nil
|
|
default:
|
|
return xerr.NewErrCodeMsg(xerr.InvalidParams, "type must be new_user, inactive_user or campaign")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func toRuleResponse(data *promoModel.Rule) types.PromoRule {
|
|
resp := types.PromoRule{
|
|
Id: data.Id,
|
|
Name: data.Name,
|
|
Type: data.Type,
|
|
Params: json.RawMessage(data.Params),
|
|
Priority: data.Priority,
|
|
Enabled: data.Enabled,
|
|
CreatedAt: data.CreatedAt.UnixMilli(),
|
|
UpdatedAt: data.UpdatedAt.UnixMilli(),
|
|
}
|
|
if data.StartTime != nil {
|
|
resp.StartTime = data.StartTime.UnixMilli()
|
|
}
|
|
if data.EndTime != nil {
|
|
resp.EndTime = data.EndTime.UnixMilli()
|
|
}
|
|
return resp
|
|
}
|
|
|
|
func toPriceResponse(data *promoModel.SubscribePromo, unitPrice int64) types.PromoPrice {
|
|
return types.PromoPrice{
|
|
Id: data.Id,
|
|
SubscribeId: data.SubscribeId,
|
|
PromoRuleId: data.PromoRuleId,
|
|
PromoPrice: data.PromoPrice,
|
|
UnitPrice: unitPrice,
|
|
CreatedAt: data.CreatedAt.UnixMilli(),
|
|
UpdatedAt: data.UpdatedAt.UnixMilli(),
|
|
}
|
|
}
|
|
|
|
func toUsageResponse(data *promoModel.Usage) types.PromoUsage {
|
|
return types.PromoUsage{
|
|
Id: data.Id,
|
|
UserId: data.UserId,
|
|
PromoRuleId: data.PromoRuleId,
|
|
SubscribeId: data.SubscribeId,
|
|
OrderNo: data.OrderNo,
|
|
PromoPrice: data.PromoPrice,
|
|
CreatedAt: data.CreatedAt.UnixMilli(),
|
|
}
|
|
}
|
|
|
|
func ruleTimes(startTime, endTime int64) (*time.Time, *time.Time) {
|
|
start := time.UnixMilli(startTime)
|
|
end := time.UnixMilli(endTime)
|
|
return &start, &end
|
|
}
|
|
|
|
func clearRuleCache(ctx context.Context, svcCtx *svc.ServiceContext) {
|
|
if svcCtx != nil && svcCtx.Redis != nil {
|
|
_ = svcCtx.Redis.Del(ctx, enabledRulesCacheKey).Err()
|
|
}
|
|
}
|
|
|
|
func clearSubscribePromoCache(ctx context.Context, svcCtx *svc.ServiceContext, ids ...int64) {
|
|
if svcCtx == nil || svcCtx.Redis == nil || len(ids) == 0 {
|
|
return
|
|
}
|
|
keys := make([]string, 0, len(ids))
|
|
for _, id := range ids {
|
|
keys = append(keys, fmt.Sprintf(subscribePromoKeyFmt, id))
|
|
}
|
|
_ = svcCtx.Redis.Del(ctx, keys...).Err()
|
|
}
|
|
|
|
func wrapQueryError(msg string, err error) error {
|
|
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "%s: %v", msg, err.Error())
|
|
}
|