448 lines
16 KiB
Go
448 lines
16 KiB
Go
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 ""
|
||
}
|
||
}
|