package ledger import ( "strings" ) const ( // VipProgramTypeLegacyTimed 保持 Lalu 现有的剩余时间累加会员语义。 VipProgramTypeLegacyTimed = "legacy_timed" // VipProgramTypeTieredPrivilegeV1 是 Fami P1 的九级权益体系。 VipProgramTypeTieredPrivilegeV1 = "tiered_privilege_v1" // VipExpiryPolicyExtendRemaining 从当前有效截止时间继续累加购买时长。 VipExpiryPolicyExtendRemaining = "extend_remaining" // VipExpiryPolicyReplaceFromNow 表示高级购买立即丢弃低级剩余时间,并从当前时刻重新计时。 VipExpiryPolicyReplaceFromNow = "replace_from_now" // VipDowngradePurchasePolicyReject 禁止有效会员购买更低等级。 VipDowngradePurchasePolicyReject = "reject" // VipBenefitInheritanceTargetOnly 仅使用目标等级显式配置的权益集合。 VipBenefitInheritanceTargetOnly = "target_only" // VipGrantModeDirectMembership 将后台赠送直接写为真实会员。 VipGrantModeDirectMembership = "direct_membership" // VipGrantModeTrialCard 将后台赠送写入可自由佩戴的背包体验卡。 VipGrantModeTrialCard = "trial_card" // VipTrialCardResourceType 使体验卡复用通用背包和单选装备链路。 VipTrialCardResourceType = "vip_trial_card" // VipEffectiveSourceNone 表示没有有效付费会员或已佩戴体验卡。 VipEffectiveSourceNone = "none" // VipEffectiveSourcePaid 表示最终权益来自真实购买会员。 VipEffectiveSourcePaid = "paid" // VipEffectiveSourceTrial 表示最终权益来自当前佩戴体验卡。 VipEffectiveSourceTrial = "trial" // VipTrialCardStatusActive 表示卡片未被撤销;是否过期仍以 ExpiresAtMS 判定。 VipTrialCardStatusActive = "active" // VipTrialCardStatusRevoked 表示后台已撤销卡片及对应背包权益。 VipTrialCardStatusRevoked = "revoked" // VipBenefitTypeDecoration 表示需要下发或佩戴资源的视觉权益。 VipBenefitTypeDecoration = "decoration" // VipBenefitTypeFunction 表示由 owner service 执行的功能权限。 VipBenefitTypeFunction = "function" // VipExecutionScopeWallet 表示权益由 wallet-service 执行,例如金币返现。 VipExecutionScopeWallet = "wallet" // VipExecutionScopeRoom 表示权益由 Room Cell 所在 room-service 执行。 VipExecutionScopeRoom = "room" // VipExecutionScopeUser 表示权益由用户资料或访客 owner 执行。 VipExecutionScopeUser = "user" // VipExecutionScopeNotice 表示权益由通知投递链路执行。 VipExecutionScopeNotice = "notice" // 以下编码是 P1 跨服务权限契约;数据库、钱包投影和各 owner service 必须使用同一稳定值。 VipBenefitCodeBadgeIdentity = "vip_badge_identity" VipBenefitCodeMedal = "vip_medal" VipBenefitCodeAvatarFrame = "avatar_frame" VipBenefitCodeTitle = "vip_title" VipBenefitCodeChatBubble = "chat_bubble" VipBenefitCodeGift = "vip_gift" VipBenefitCodeEntryEffect = "entry_effect" VipBenefitCodeVisitorHistory = "visitor_history" VipBenefitCodeVoiceWave = "voice_wave" VipBenefitCodeProfileCard = "profile_card" VipBenefitCodeCustomRoomBackground = "custom_room_background" VipBenefitCodeRoomImageMessage = "room_image_message" VipBenefitCodeAnimatedAvatar = "animated_avatar" VipBenefitCodeAnimatedRoomCover = "animated_room_cover" VipBenefitCodeMicSkin = "mic_skin" VipBenefitCodeRoomBorder = "room_border" VipBenefitCodeVehicle = "vehicle" VipBenefitCodeColoredRoomName = "colored_room_name" VipBenefitCodeColoredNickname = "colored_nickname" VipBenefitCodeColoredID = "colored_id" VipBenefitCodeGiftTraySkin = "gift_tray_skin" VipBenefitCodeHideProfileData = "hide_profile_data" VipBenefitCodeCustomAvatarFrame = "custom_avatar_frame" VipBenefitCodeLeaderboardInvisible = "leaderboard_invisible" VipBenefitCodeDailyCoinRebate = "daily_coin_rebate" VipBenefitCodeCustomProfileCard = "custom_profile_card" VipBenefitCodeAnonymousProfileVisit = "anonymous_profile_visit" VipBenefitCodeCustomGift = "custom_gift" VipBenefitCodeRoomEntryNotice = "room_entry_notice" VipBenefitCodeCustomPrettyID = "custom_pretty_id" VipBenefitCodeCustomVehicle = "custom_vehicle" VipBenefitCodeAntiKick = "anti_kick" VipBenefitCodeAntiMute = "anti_mute" VipBenefitCodeOnlineGlobalNotice = "online_global_notice" // VipDailyCoinRebateStatusClaimable 表示返现仍处于当天手动领取窗口。 VipDailyCoinRebateStatusClaimable = "claimable" // VipDailyCoinRebateStatusClaimed 表示金币已经原子入账,WalletTransactionID 必须非空。 VipDailyCoinRebateStatusClaimed = "claimed" // VipDailyCoinRebateStatusExpired 是查询层对超过 UTC 日终但未领取记录的只读投影。 VipDailyCoinRebateStatusExpired = "expired" // VipDailyCoinRebateRunStatusRunning 表示批任务仍需沿 last_user_id 继续分页。 VipDailyCoinRebateRunStatusRunning = "running" // VipDailyCoinRebateRunStatusCompleted 表示当日所有候选会员已经扫描完成。 VipDailyCoinRebateRunStatusCompleted = "completed" ) // VipProgramConfig 是某 App 当前 VIP 状态机的完整规则,不允许调用方再按 app_code 猜规则。 type VipProgramConfig struct { AppCode string ProgramType string LevelCount int32 SameLevelExpiryPolicy string UpgradeExpiryPolicy string DowngradePurchasePolicy string BenefitInheritancePolicy string GrantMode string TrialCardEnabled bool Status string ConfigVersion int64 UpdatedByAdminID int64 CreatedAtMS int64 UpdatedAtMS int64 } // VipBenefit 是可跨服务投影和执行的权益事实;ResourceID=0 表示纯功能或尚未绑定资源。 type VipBenefit struct { BenefitCode string Name string BenefitType string UnlockLevel int32 Status string TrialEnabled bool ResourceID int64 ResourceType string ExecutionScope string AutoEquip bool SortOrder int32 MetadataJSON string CreatedAtMS int64 UpdatedAtMS int64 } // VipRewardItem 是 VIP 资源组权益的轻量展示投影。 type VipRewardItem struct { ResourceID int64 ResourceCode string ResourceType string Name string Quantity int64 ExpiresAtMS int64 AssetURL string PreviewURL string AnimationURL string } // VipLevel 是可购买 VIP 等级配置。 type VipLevel struct { Level int32 Name string Status string PriceCoin int64 DurationMS int64 RewardResourceGroupID int64 RequiredRechargeCoinAmount int64 UserRechargeCoinAmount int64 RechargeGateRequired bool PurchaseLockedReason string RewardItems []VipRewardItem CanPurchase bool SortOrder int32 CreatedAtMS int64 UpdatedAtMS int64 Benefits []VipBenefit ConfigVersion int64 } // UserVip 是用户当前会员状态。是否有效以 ExpiresAtMS 和当前时间判断。 type UserVip struct { UserID int64 Level int32 Name string Active bool StartedAtMS int64 ExpiresAtMS int64 UpdatedAtMS int64 ProgramType string ConfigVersion int64 } // VipTrialCard 把通用背包 entitlement 投影为 VIP 体验卡;装备切换只改变 Equipped, // DurationMS、EffectiveAtMS 和 ExpiresAtMS 始终保留发卡时的绝对计时事实。 type VipTrialCard struct { TrialCardID string EntitlementID string ResourceID int64 UserID int64 Level int32 Name string Status string Equipped bool DurationMS int64 EffectiveAtMS int64 ExpiresAtMS int64 RemainingDurationMS int64 GrantSource string SourceGrantID string CreatedAtMS int64 UpdatedAtMS int64 } // VipUserSettings 是用户可关闭的 VIP 展示偏好。默认值必须由 wallet owner 统一构造, // 不能让 room/gateway 因为数据库尚未物化记录而各自猜不同默认值。 type VipUserSettings struct { AppCode string UserID int64 RoomEntryNoticeEnabled bool OnlineGlobalNoticeEnabled bool UpdatedAtMS int64 } // DefaultVipUserSettings 返回尚未物化时的产品默认:两项通知均开启,UpdatedAtMS=0。 func DefaultVipUserSettings(appCode string, userID int64) VipUserSettings { return VipUserSettings{ AppCode: appCode, UserID: userID, RoomEntryNoticeEnabled: true, OnlineGlobalNoticeEnabled: true, } } // AllowsBenefitSetting 只处理用户可关闭的两项权益;其它权益不受偏好表影响。 func (settings VipUserSettings) AllowsBenefitSetting(benefitCode string) bool { switch strings.ToLower(strings.TrimSpace(benefitCode)) { case VipBenefitCodeRoomEntryNotice: return settings.RoomEntryNoticeEnabled case VipBenefitCodeOnlineGlobalNotice: return settings.OnlineGlobalNoticeEnabled default: return true } } // VipState 是调用方唯一应消费的合并状态。EffectiveBenefits 已按真实/体验来源过滤, // 尤其不会向体验卡返回 TrialEnabled=false 的金币返现资格;可关闭通知还需结合 UserSettings。 type VipState struct { PaidVip UserVip EquippedTrialCard *VipTrialCard EffectiveVip UserVip EffectiveSource string EffectiveBenefits []VipBenefit EvaluatedAtMS int64 ProgramConfig VipProgramConfig UserSettings VipUserSettings } // PurchaseVipCommand 是 App 购买或升级 VIP 的账务命令。 type PurchaseVipCommand struct { AppCode string CommandID string UserID int64 Level int32 } // PurchaseVipReceipt 是购买 VIP 成功后的稳定回执。 type PurchaseVipReceipt struct { OrderID string TransactionID string Vip UserVip CoinSpent int64 CoinBalanceAfter int64 RewardItems []VipRewardItem State VipState } // GrantVipCommand 是活动或后台发放 VIP 的统一入口命令。 type GrantVipCommand struct { AppCode string CommandID string TargetUserID int64 Level int32 GrantSource string OperatorUserID int64 Reason string } // GrantVipReceipt 是赠送 VIP 成功后的稳定回执。 type GrantVipReceipt struct { TransactionID string Vip UserVip RewardItems []VipRewardItem State VipState } // GrantVipTrialCardCommand 是直接按等级和绝对时长发放体验卡的幂等命令。 // ResourceID=0 表示按 level 解析同 App 预置资源;非 0 时也必须匹配该等级的 vip_trial_card。 type GrantVipTrialCardCommand struct { AppCode string CommandID string TargetUserID int64 Level int32 DurationMS int64 ResourceID int64 GrantSource string OperatorUserID int64 Reason string } // GrantVipTrialCardReceipt 返回新卡和重新计算后的有效 VIP 状态;发卡本身不自动佩戴。 type GrantVipTrialCardReceipt struct { TrialCard VipTrialCard State VipState ServerTimeMS int64 } // EquipVipTrialCardCommand 以 entitlement 精确选择背包实例,避免同资源多卡时佩戴错对象。 type EquipVipTrialCardCommand struct { AppCode string RequestID string UserID int64 EntitlementID string } // UnequipVipTrialCardCommand 只清理 vip_trial_card 类型的装备事实,不回收或暂停任一卡片。 type UnequipVipTrialCardCommand struct { AppCode string RequestID string UserID int64 } // CheckVipBenefitResult 是 owner service 执行单项特权时使用的服务端判断结果。 type CheckVipBenefitResult struct { Allowed bool Benefit VipBenefit State VipState DenialReason string EvaluatedAtMS int64 } // AdminVipLevelCommand 是后台保存 VIP 等级配置的完整事实输入。 type AdminVipLevelCommand struct { Level int32 Name string Status string PriceCoin int64 DurationMS int64 RewardResourceGroupID int64 RequiredRechargeCoinAmount int64 SortOrder int32 Benefits []VipBenefit } // AdminVipProgramConfigCommand 是后台保存 App 级 VIP 策略的审计输入。 type AdminVipProgramConfigCommand struct { Config VipProgramConfig OperatorUserID int64 } // UpdateVipUserSettingsCommand 使用指针表达 partial update;nil 字段必须保留数据库原值。 type UpdateVipUserSettingsCommand struct { AppCode string UserID int64 RoomEntryNoticeEnabled *bool OnlineGlobalNoticeEnabled *bool } // VipDailyCoinRebateRun 是单 App、单 UTC 日唯一的配置快照与分页游标。 // LevelAmounts 只在创建 run 时从 active daily_coin_rebate 权益解析,后续分页禁止回读新配置。 type VipDailyCoinRebateRun struct { RunID string TaskDay string DayStartMS int64 DayEndMS int64 ConfigVersion int64 LevelAmounts map[int32]int64 LevelAmountsJSON string Status string LastUserID int64 ScannedCount int64 CreatedCount int64 CreatedAtMS int64 UpdatedAtMS int64 CompletedAtMS int64 } // VipDailyCoinRebate 是日切时生成、当天手动领取的付费 VIP 返现事实。 type VipDailyCoinRebate struct { RebateID string UserID int64 TaskDay string VipLevel int32 VipName string CoinAmount int64 Status string AvailableAtMS int64 ExpiresAtMS int64 ConfigVersion int64 ClaimedAtMS int64 WalletTransactionID string CreatedAtMS int64 UpdatedAtMS int64 } // ProcessVipDailyCoinRebateBatchCommand 由 cron 适配器构造;NowMS 仅由 wallet-service 注入, // repository 不信任调度方的本地时钟。 type ProcessVipDailyCoinRebateBatchCommand struct { AppCode string TaskDay string BatchSize int NowMS int64 } // ProcessVipDailyCoinRebateBatchResult 返回本页计数与持久 run,调度方据 HasMore 继续触发。 type ProcessVipDailyCoinRebateBatchResult struct { Run VipDailyCoinRebateRun ScannedCount int CreatedCount int HasMore bool } // ListVipDailyCoinRebateStatusesQuery 是用户侧返现历史分页查询;状态在读取时按 NowMS 投影。 type ListVipDailyCoinRebateStatusesQuery struct { AppCode string UserID int64 Page int PageSize int RebateIDs []string NowMS int64 } // ClaimVipDailyCoinRebateCommand 只包含调用方可控主键;金额、等级和窗口全部从锁内返现行读取。 type ClaimVipDailyCoinRebateCommand struct { AppCode string CommandID string UserID int64 RebateID string NowMS int64 } // ClaimVipDailyCoinRebateReceipt 是幂等稳定回执;同 command 重放必须返回同一交易和账后余额。 type ClaimVipDailyCoinRebateReceipt struct { Rebate VipDailyCoinRebate TransactionID string CoinBalance AssetBalance } func NormalizeVipGrantSource(source string) string { switch strings.ToLower(strings.TrimSpace(source)) { case VipGrantSourcePurchase: return VipGrantSourcePurchase case VipGrantSourceActivity: return VipGrantSourceActivity case VipGrantSourceAdmin: return VipGrantSourceAdmin case VipGrantSourceManagerCenter: return VipGrantSourceManagerCenter default: return "" } }