package mysql import ( "encoding/json" "hyapp/pkg/xerr" "hyapp/services/wallet-service/internal/domain/ledger" resourcedomain "hyapp/services/wallet-service/internal/domain/resource" "sort" "strings" ) func normalizeGiftConfigCommand(command resourcedomain.GiftConfigCommand) resourcedomain.GiftConfigCommand { command.GiftID = strings.TrimSpace(command.GiftID) command.Status = resourcedomain.NormalizeStatus(command.Status) command.Name = strings.TrimSpace(command.Name) command.PresentationJSON = normalizeJSONObject(command.PresentationJSON) command.CPRelationType = normalizeCPRelationType(command.CPRelationType) command.PriceVersion = strings.TrimSpace(command.PriceVersion) command.RegionIDs = normalizeRegionIDs(command.RegionIDs) command.GiftTypeCode = resourcedomain.NormalizeGiftTypeCode(command.GiftTypeCode) command.ChargeAssetType = strings.ToUpper(strings.TrimSpace(command.ChargeAssetType)) if command.ChargeAssetType == "" { command.ChargeAssetType = ledger.AssetCoin } command.EffectTypes = normalizeGiftEffectTypes(command.EffectTypes) command.GiftPointAmount = 0 if command.EffectiveAtMS < 0 { command.EffectiveAtMS = 0 } if command.EffectiveFromMS < 0 { command.EffectiveFromMS = 0 } if command.EffectiveToMS < 0 { command.EffectiveToMS = 0 } return command } func validateGiftConfigCommand(command resourcedomain.GiftConfigCommand) error { if command.GiftID == "" || command.ResourceID <= 0 || command.Name == "" || command.PriceVersion == "" { return xerr.New(xerr.InvalidArgument, "gift config command is incomplete") } if !resourcedomain.ValidStatus(command.Status) { return xerr.New(xerr.InvalidArgument, "status is invalid") } if command.CoinPrice < 0 || command.HeatValue < 0 { return xerr.New(xerr.InvalidArgument, "gift price is invalid") } if !resourcedomain.ValidGiftTypeCode(command.GiftTypeCode) { return xerr.New(xerr.InvalidArgument, "gift type is invalid") } if command.CPRelationType != "" && command.GiftTypeCode != resourcedomain.GiftTypeCP { return xerr.New(xerr.InvalidArgument, "cp relation type requires cp gift type") } if !ledger.ValidGiftChargeAssetType(command.ChargeAssetType) { return xerr.New(xerr.InvalidArgument, "gift charge asset type is invalid") } if command.EffectiveFromMS > 0 && command.EffectiveToMS > 0 && command.EffectiveToMS <= command.EffectiveFromMS { return xerr.New(xerr.InvalidArgument, "gift effective time range is invalid") } for _, effectType := range command.EffectTypes { if !resourcedomain.ValidGiftEffectType(effectType) { return xerr.New(xerr.InvalidArgument, "gift effect type is invalid") } } if len(command.RegionIDs) == 0 { return xerr.New(xerr.InvalidArgument, "gift regions are required") } for _, regionID := range command.RegionIDs { if regionID < 0 { return xerr.New(xerr.InvalidArgument, "gift region is invalid") } } return nil } func normalizeGiftEffectTypes(values []string) []string { seen := make(map[string]struct{}, len(values)) out := make([]string, 0, len(values)) for _, value := range values { value = resourcedomain.NormalizeGiftEffectType(value) if value == "" { continue } if _, ok := seen[value]; ok { continue } seen[value] = struct{}{} out = append(out, value) } sort.Strings(out) return out } func cpRelationTypeFromPresentationJSON(value string) string { var payload map[string]any if err := json.Unmarshal([]byte(normalizeJSONObject(value)), &payload); err != nil { return "" } if raw, ok := payload["cp_relation_type"].(string); ok { return normalizeCPRelationType(raw) } return "" } func giftPresentationWithCPRelationType(value string, relationType string) string { relationType = normalizeCPRelationType(relationType) var payload map[string]any if err := json.Unmarshal([]byte(normalizeJSONObject(value)), &payload); err != nil || payload == nil { payload = map[string]any{} } if relationType == "" { delete(payload, "cp_relation_type") } else { payload["cp_relation_type"] = relationType } encoded, err := json.Marshal(payload) if err != nil { return "{}" } return string(encoded) } func normalizeCPRelationType(value string) string { switch strings.ToLower(strings.TrimSpace(value)) { case "cp": return "cp" case "brother": return "brother" case "sister": return "sister" default: return "" } }