package wallet import ( "context" "hyapp/pkg/appcode" "hyapp/pkg/xerr" "hyapp/services/wallet-service/internal/domain/ledger" "strings" "time" ) // ProcessHostSalarySettlementBatch 执行主播/代理工资结算批处理;日结和半月结不清空周期钻石,月底只做逻辑清算标记。 func (s *Service) ProcessHostSalarySettlementBatch(ctx context.Context, command ledger.HostSalarySettlementBatchCommand) (ledger.HostSalarySettlementBatchResult, error) { if s.repository == nil { return ledger.HostSalarySettlementBatchResult{}, xerr.New(xerr.Unavailable, "wallet repository is not configured") } switch strings.TrimSpace(command.SettlementType) { case ledger.HostSalarySettlementModeDaily, ledger.HostSalarySettlementModeHalfMonth, ledger.HostSalarySettlementTypeMonthEnd: default: return ledger.HostSalarySettlementBatchResult{}, xerr.New(xerr.InvalidArgument, "settlement_type is invalid") } if command.BatchSize <= 0 { command.BatchSize = 100 } if command.BatchSize > 500 { command.BatchSize = 500 } if strings.TrimSpace(command.RunID) == "" || strings.TrimSpace(command.WorkerID) == "" { return ledger.HostSalarySettlementBatchResult{}, xerr.New(xerr.InvalidArgument, "run_id and worker_id are required") } command.AppCode = appcode.Normalize(command.AppCode) if command.NowMs <= 0 { command.NowMs = s.now().UTC().UnixMilli() } if strings.TrimSpace(command.CycleKey) == "" { command.CycleKey = hostSalaryCycleKey(command.NowMs) } ctx = appcode.WithContext(ctx, command.AppCode) return s.repository.ProcessHostSalarySettlementBatch(ctx, command) } func hostSalaryCycleKey(nowMs int64) string { // 结算周期按 UTC 月锚定,和送礼入账的 host_period_diamond_accounts.cycle_key 保持同一口径。 return time.UnixMilli(nowMs).UTC().Format("2006-01") } // GetActiveHostSalaryPolicy 读取主播所在区域当前生效的工资政策,返回的 policy 与工资结算使用同一张 runtime 表。 func (s *Service) GetActiveHostSalaryPolicy(ctx context.Context, appCode string, regionID int64, settlementMode string, triggerMode string, nowMs int64) (ledger.HostSalaryPolicy, bool, error) { if regionID <= 0 { return ledger.HostSalaryPolicy{}, false, xerr.New(xerr.InvalidArgument, "region_id is required") } if s.repository == nil { return ledger.HostSalaryPolicy{}, false, xerr.New(xerr.Unavailable, "wallet repository is not configured") } settlementMode = strings.TrimSpace(settlementMode) if settlementMode != "" && settlementMode != ledger.HostSalarySettlementModeDaily && settlementMode != ledger.HostSalarySettlementModeHalfMonth { return ledger.HostSalaryPolicy{}, false, xerr.New(xerr.InvalidArgument, "settlement_mode is invalid") } triggerMode = strings.TrimSpace(triggerMode) if triggerMode != "" && triggerMode != ledger.HostSalarySettlementTriggerAutomatic && triggerMode != ledger.HostSalarySettlementTriggerManual { return ledger.HostSalaryPolicy{}, false, xerr.New(xerr.InvalidArgument, "settlement_trigger_mode is invalid") } if nowMs <= 0 { nowMs = s.now().UTC().UnixMilli() } appCode = appcode.Normalize(appCode) ctx = appcode.WithContext(ctx, appCode) // H5 展示可以不传 trigger mode,此时 automatic/manual 政策都可展示;结算任务仍会传具体 trigger 精确匹配。 return s.repository.GetActiveHostSalaryPolicy(ctx, regionID, settlementMode, triggerMode, nowMs) } // GetHostSalaryProgress 返回主播当前工资周期的钻石累计;没有收礼账户时返回 0,避免 H5 用其他等级系统兜底导致进度口径错误。 func (s *Service) GetHostSalaryProgress(ctx context.Context, appCode string, userID int64, cycleKey string, nowMs int64) (ledger.HostSalaryProgress, error) { if userID <= 0 { return ledger.HostSalaryProgress{}, xerr.New(xerr.InvalidArgument, "host_user_id is required") } if s.repository == nil { return ledger.HostSalaryProgress{}, xerr.New(xerr.Unavailable, "wallet repository is not configured") } if nowMs <= 0 { nowMs = s.now().UTC().UnixMilli() } cycleKey = strings.TrimSpace(cycleKey) if cycleKey == "" { cycleKey = hostSalaryCycleKey(nowMs) } appCode = appcode.Normalize(appCode) ctx = appcode.WithContext(ctx, appCode) return s.repository.GetHostSalaryProgress(ctx, userID, cycleKey) }