package resource import ( "strings" "unicode/utf8" "hyapp/services/wallet-service/internal/domain/ledger" ) const ( TypeAvatarFrame = "avatar_frame" TypeProfileCard = "profile_card" TypeCoin = "coin" TypeVehicle = "vehicle" TypeChatBubble = "chat_bubble" TypeBadge = "badge" TypeFloatingScreen = "floating_screen" TypeGift = "gift" TypeMicSeatIcon = "mic_seat_icon" TypeMicSeatAnimation = "mic_seat_animation" TypeEmojiPack = "emoji_pack" StatusActive = "active" StatusDisabled = "disabled" GrantStrategyWalletCredit = "wallet_credit" GrantStrategyNewEntitlement = "new_entitlement" GrantStrategyExtendExpiry = "extend_expiry" GrantStrategyIncreaseQuantity = "increase_quantity" GrantStrategySetActiveFlag = "set_active_flag" GrantSubjectResource = "resource" GrantSubjectGroup = "resource_group" GrantSourceAdmin = "admin" GrantSourceManagerCenter = "manager_center" GrantSourceGrowthLevel = "growth_level" GrantSourceAchievement = "achievement" GrantSourceResourceShop = "resource_shop" GrantStatusDone = "succeeded" ResultWalletCredit = "wallet_credit" ResultEntitlement = "entitlement" GroupItemTypeResource = "resource" GroupItemTypeWalletAsset = "wallet_asset" GiftTypeNormal = "normal" GiftTypeCP = "cp" GiftTypeLucky = "lucky" GiftTypeSuperLucky = "super_lucky" GiftTypeExclusive = "exclusive" GiftTypeNoble = "noble" GiftTypeFlag = "flag" GiftTypeActivity = "activity" GiftTypeMagic = "magic" GiftTypeCustom = "custom" GiftTypeTabKeyNormal = "Gift" GiftTypeTabKeyCP = "CP" GiftTypeTabKeyLucky = "Lucky" GiftTypeTabKeySuperLucky = "Super Lucky" GiftTypeTabKeyExclusive = "Exclusive" GiftTypeTabKeyNoble = "Noble" GiftTypeTabKeyFlag = "Flag" GiftTypeTabKeyActivity = "Activity" GiftTypeTabKeyMagic = "Magic" GiftTypeTabKeyCustom = "Custom" GiftEffectAnimation = "animation" GiftEffectMusic = "music" GiftEffectGlobalBroadcast = "global_broadcast" PriceTypeCoin = "coin" PriceTypeFree = "free" ShopDurationOneDay int32 = 1 ShopDurationThreeDays int32 = 3 ShopDurationSevenDays int32 = 7 ) type Resource struct { AppCode string ResourceID int64 ResourceCode string ResourceType string Name string Status string Grantable bool GrantStrategy string WalletAssetType string WalletAssetAmount int64 PriceType string CoinPrice int64 GiftPointAmount int64 UsageScopes []string AssetURL string PreviewURL string AnimationURL string MetadataJSON string SortOrder int32 CreatedByUserID int64 UpdatedByUserID int64 CreatedAtMS int64 UpdatedAtMS int64 ManagerGrantEnabled bool } type ResourceGroupItem struct { GroupItemID int64 GroupID int64 ItemType string ResourceID int64 Resource Resource WalletAssetType string WalletAssetAmount int64 Quantity int64 DurationMS int64 SortOrder int32 CreatedAtMS int64 UpdatedAtMS int64 } type ResourceGroup struct { AppCode string GroupID int64 GroupCode string Name string Status string Description string SortOrder int32 Items []ResourceGroupItem CreatedByUserID int64 UpdatedByUserID int64 CreatedAtMS int64 UpdatedAtMS int64 } type GiftConfig struct { AppCode string GiftID string ResourceID int64 Resource Resource Status string Name string SortOrder int32 PresentationJSON string PriceVersion string CoinPrice int64 GiftPointAmount int64 HeatValue int64 GiftTypeCode string ChargeAssetType string EffectiveFromMS int64 EffectiveToMS int64 EffectTypes []string CreatedByUserID int64 UpdatedByUserID int64 CreatedAtMS int64 UpdatedAtMS int64 RegionIDs []int64 } type GiftTypeConfig struct { AppCode string TypeCode string Name string TabKey string Status string SortOrder int32 CreatedByUserID int64 UpdatedByUserID int64 CreatedAtMS int64 UpdatedAtMS int64 } type ResourceShopItem struct { AppCode string ShopItemID int64 ResourceID int64 Resource Resource Status string DurationDays int32 PriceType string CoinPrice int64 EffectiveFromMS int64 EffectiveToMS int64 SortOrder int32 CreatedByUserID int64 UpdatedByUserID int64 CreatedAtMS int64 UpdatedAtMS int64 } type UserResourceEntitlement struct { AppCode string EntitlementID string UserID int64 ResourceID int64 Resource Resource Status string Quantity int64 RemainingQuantity int64 EffectiveAtMS int64 ExpiresAtMS int64 SourceGrantID string CreatedAtMS int64 UpdatedAtMS int64 Equipped bool } type ResourceGrantItem struct { GrantItemID int64 GrantID string ResourceID int64 ResourceSnapshotJSON string Quantity int64 DurationMS int64 ResultType string WalletTransactionID string EntitlementID string CreatedAtMS int64 } type ResourceGrant struct { AppCode string GrantID string CommandID string TargetUserID int64 GrantSource string GrantSubjectType string GrantSubjectID string Status string Reason string OperatorUserID int64 Items []ResourceGrantItem CreatedAtMS int64 UpdatedAtMS int64 } type ListResourcesQuery struct { AppCode string ResourceType string Status string Keyword string Page int32 PageSize int32 ActiveOnly bool ManagerGrantOnly bool } type ResourceCommand struct { AppCode string ResourceID int64 ResourceCode string ResourceType string Name string Status string Grantable bool GrantStrategy string WalletAssetType string WalletAssetAmount int64 PriceType string CoinPrice int64 GiftPointAmount int64 UsageScopes []string AssetURL string PreviewURL string AnimationURL string MetadataJSON string SortOrder int32 OperatorUserID int64 ManagerGrantEnabled bool } type StatusCommand struct { AppCode string ID int64 StringID string Status string OperatorUserID int64 } type ResourceGroupItemInput struct { ItemType string ResourceID int64 WalletAssetType string WalletAssetAmount int64 Quantity int64 DurationMS int64 SortOrder int32 } type ListResourceGroupsQuery struct { AppCode string Status string Keyword string Page int32 PageSize int32 ActiveOnly bool } type ResourceGroupCommand struct { AppCode string GroupID int64 GroupCode string Name string Status string Description string SortOrder int32 Items []ResourceGroupItemInput OperatorUserID int64 } type ListGiftConfigsQuery struct { AppCode string Status string Keyword string Page int32 PageSize int32 ActiveOnly bool RegionID int64 FilterRegion bool } type ListGiftTypeConfigsQuery struct { AppCode string Status string ActiveOnly bool } type GiftConfigCommand struct { AppCode string GiftID string ResourceID int64 Status string Name string SortOrder int32 PresentationJSON string PriceVersion string CoinPrice int64 GiftPointAmount int64 HeatValue int64 EffectiveAtMS int64 GiftTypeCode string ChargeAssetType string EffectiveFromMS int64 EffectiveToMS int64 EffectTypes []string OperatorUserID int64 RegionIDs []int64 } type GiftTypeConfigCommand struct { AppCode string TypeCode string Name string TabKey string Status string SortOrder int32 OperatorUserID int64 } type GrantResourceCommand struct { AppCode string CommandID string TargetUserID int64 ResourceID int64 Quantity int64 DurationMS int64 Reason string OperatorUserID int64 GrantSource string } type GrantResourceGroupCommand struct { AppCode string CommandID string TargetUserID int64 GroupID int64 Reason string OperatorUserID int64 GrantSource string } type ListUserResourcesQuery struct { AppCode string UserID int64 ResourceType string ActiveOnly bool } type EquipUserResourceCommand struct { AppCode string UserID int64 ResourceID int64 EntitlementID string } type ListResourceGrantsQuery struct { AppCode string TargetUserID int64 Status string Page int32 PageSize int32 } type ResourceShopItemInput struct { ShopItemID int64 ResourceID int64 Status string DurationDays int32 EffectiveFromMS int64 EffectiveToMS int64 SortOrder int32 } type ListResourceShopItemsQuery struct { AppCode string ResourceType string Status string Keyword string Page int32 PageSize int32 ActiveOnly bool } type ResourceShopItemsCommand struct { AppCode string Items []ResourceShopItemInput OperatorUserID int64 } type ResourceShopItemStatusCommand struct { AppCode string ShopItemID int64 Status string OperatorUserID int64 } type ResourceShopPurchaseCommand struct { AppCode string CommandID string UserID int64 ShopItemID int64 } type ResourceShopPurchaseReceipt struct { OrderID string TransactionID string ShopItem ResourceShopItem Resource UserResourceEntitlement Balance ledger.AssetBalance CoinSpent int64 GrantID string } // BadgeGrantOutbox is a wallet resource grant event relayed to activity-service badge display projection. type BadgeGrantOutbox struct { AppCode string EventID string EventType string CommandID string UserID int64 GrantID string GrantSource string PayloadJSON string Status string AttemptCount int32 FailureReason string CreatedAtMS int64 UpdatedAtMS int64 Items []BadgeGrantItem } // BadgeGrantItem is the badge subset of a resource grant item. type BadgeGrantItem struct { ResourceID int64 `json:"resource_id"` ResourceCode string `json:"resource_code"` ResourceType string `json:"resource_type"` Name string `json:"name"` EntitlementID string `json:"entitlement_id"` ResourceSnapshotJSON string `json:"resource_snapshot_json"` MetadataJSON string `json:"metadata_json"` } func NormalizeStatus(value string) string { value = strings.ToLower(strings.TrimSpace(value)) if value == "" { return StatusActive } return value } func NormalizeGrantSource(value string) string { value = strings.ToLower(strings.TrimSpace(value)) if value == "" { return GrantSourceAdmin } return value } func ValidResourceType(value string) bool { switch strings.ToLower(strings.TrimSpace(value)) { case TypeAvatarFrame, TypeProfileCard, TypeCoin, TypeVehicle, TypeChatBubble, TypeBadge, TypeFloatingScreen, TypeGift, TypeMicSeatIcon, TypeMicSeatAnimation, TypeEmojiPack: return true default: return false } } func ResourceTypeSellableInShop(value string) bool { switch NormalizeResourceType(value) { case TypeAvatarFrame, TypeProfileCard, TypeVehicle, TypeChatBubble, TypeBadge, TypeMicSeatIcon, TypeMicSeatAnimation: return true default: return false } } func ValidShopDurationDays(value int32) bool { switch value { case ShopDurationOneDay, ShopDurationThreeDays, ShopDurationSevenDays: return true default: return false } } func ValidStatus(value string) bool { switch NormalizeStatus(value) { case StatusActive, StatusDisabled: return true default: return false } } func ValidGrantStrategy(value string) bool { switch strings.ToLower(strings.TrimSpace(value)) { case GrantStrategyWalletCredit, GrantStrategyNewEntitlement, GrantStrategyExtendExpiry, GrantStrategyIncreaseQuantity, GrantStrategySetActiveFlag: return true default: return false } } func NormalizeGroupItemType(value string) string { value = strings.ToLower(strings.TrimSpace(value)) if value == "" { return GroupItemTypeResource } return value } func ValidGroupItemType(value string) bool { switch NormalizeGroupItemType(value) { case GroupItemTypeResource, GroupItemTypeWalletAsset: return true default: return false } } func NormalizeResourceType(value string) string { return strings.ToLower(strings.TrimSpace(value)) } func NormalizeGrantStrategy(value string) string { return strings.ToLower(strings.TrimSpace(value)) } func NormalizeWalletAssetType(value string) string { return strings.ToUpper(strings.TrimSpace(value)) } func NormalizePriceType(value string) string { return strings.ToLower(strings.TrimSpace(value)) } func ValidPriceType(value string) bool { switch NormalizePriceType(value) { case PriceTypeCoin, PriceTypeFree: return true default: return false } } func NormalizeGiftTypeCode(value string) string { value = strings.ToLower(strings.TrimSpace(value)) value = strings.ReplaceAll(value, "-", "_") if value == "" { return GiftTypeNormal } return value } func ValidGiftTypeCode(value string) bool { value = NormalizeGiftTypeCode(value) if value == "" || len(value) > 32 { return false } for index, char := range value { if index == 0 && (char < 'a' || char > 'z') { return false } if (char >= 'a' && char <= 'z') || (char >= '0' && char <= '9') || char == '_' { continue } return false } return true } func NormalizeGiftTypeTabKey(value string) string { return strings.TrimSpace(value) } func ValidGiftTypeTabKey(value string) bool { value = NormalizeGiftTypeTabKey(value) return value != "" && utf8.RuneCountInString(value) <= 32 } func DefaultGiftTypeConfigs(appCode string) []GiftTypeConfig { appCode = strings.TrimSpace(appCode) defaults := []GiftTypeConfig{ {TypeCode: GiftTypeNormal, Name: "普通礼物", TabKey: GiftTypeTabKeyNormal, Status: StatusActive, SortOrder: 10}, {TypeCode: GiftTypeCP, Name: "CP礼物", TabKey: GiftTypeTabKeyCP, Status: StatusActive, SortOrder: 20}, {TypeCode: GiftTypeLucky, Name: "幸运礼物", TabKey: GiftTypeTabKeyLucky, Status: StatusActive, SortOrder: 30}, {TypeCode: GiftTypeSuperLucky, Name: "超级幸运礼物", TabKey: GiftTypeTabKeySuperLucky, Status: StatusActive, SortOrder: 40}, {TypeCode: GiftTypeExclusive, Name: "专属礼物", TabKey: GiftTypeTabKeyExclusive, Status: StatusActive, SortOrder: 50}, {TypeCode: GiftTypeNoble, Name: "贵族礼物", TabKey: GiftTypeTabKeyNoble, Status: StatusActive, SortOrder: 60}, {TypeCode: GiftTypeFlag, Name: "国旗礼物", TabKey: GiftTypeTabKeyFlag, Status: StatusActive, SortOrder: 70}, {TypeCode: GiftTypeActivity, Name: "活动礼物", TabKey: GiftTypeTabKeyActivity, Status: StatusActive, SortOrder: 80}, {TypeCode: GiftTypeMagic, Name: "魔法礼物", TabKey: GiftTypeTabKeyMagic, Status: StatusActive, SortOrder: 90}, {TypeCode: GiftTypeCustom, Name: "定制礼物", TabKey: GiftTypeTabKeyCustom, Status: StatusActive, SortOrder: 100}, } for index := range defaults { defaults[index].AppCode = appCode } return defaults } func NormalizeGiftEffectType(value string) string { return strings.ToLower(strings.TrimSpace(value)) } func ValidGiftEffectType(value string) bool { switch NormalizeGiftEffectType(value) { case GiftEffectAnimation, GiftEffectMusic, GiftEffectGlobalBroadcast: return true default: return false } } func IsWalletCredit(resource Resource) bool { return NormalizeGrantStrategy(resource.GrantStrategy) == GrantStrategyWalletCredit } func IsCoinResource(resource Resource) bool { return NormalizeResourceType(resource.ResourceType) == TypeCoin } func WalletAssetForCoin() string { return ledger.AssetCoin }