package integration import ( "context" "time" walletv1 "hyapp.local/api/proto/wallet/v1" "hyapp/services/cron-service/internal/scheduler" ) // WalletCronClient delegates wallet-owned salary settlement batches to wallet-service. type WalletCronClient struct { client walletv1.WalletCronServiceClient } var walletCronNowUTC = func() time.Time { return time.Now().UTC() } // NewWalletCronClient creates scheduler handlers backed by wallet-service gRPC. func NewWalletCronClient(client walletv1.WalletCronServiceClient) *WalletCronClient { return &WalletCronClient{client: client} } func (c *WalletCronClient) ProcessHostSalaryDailySettlementBatch(ctx context.Context, req scheduler.BatchRequest) (scheduler.BatchResult, error) { resp, err := c.client.ProcessHostSalaryDailySettlementBatch(ctx, walletCronBatchRequest(req)) return walletCronBatchResult(resp), err } func (c *WalletCronClient) ProcessHostSalaryHalfMonthSettlementBatch(ctx context.Context, req scheduler.BatchRequest) (scheduler.BatchResult, error) { if !isHostSalaryHalfMonthDue(walletCronNowUTC()) { // 半月结是否适用于某个主播由后台工资政策 settlement_mode 决定;cron 这里只负责在月中打开一次全局触发窗口。 return scheduler.BatchResult{}, nil } resp, err := c.client.ProcessHostSalaryHalfMonthSettlementBatch(ctx, walletCronBatchRequest(req)) return walletCronBatchResult(resp), err } func (c *WalletCronClient) ProcessHostSalaryMonthEndBatch(ctx context.Context, req scheduler.BatchRequest) (scheduler.BatchResult, error) { if !isHostSalaryMonthEndDue(walletCronNowUTC()) { // 月末批次负责最终等级差额、剩余钻石折美元和周期关闭;非月末触发只记录一次空跑,不进入 wallet 账务。 return scheduler.BatchResult{}, nil } resp, err := c.client.ProcessHostSalaryMonthEndBatch(ctx, walletCronBatchRequest(req)) return walletCronBatchResult(resp), err } func isHostSalaryHalfMonthDue(now time.Time) bool { return now.UTC().Day() == 15 } func isHostSalaryMonthEndDue(now time.Time) bool { utc := now.UTC() return utc.AddDate(0, 0, 1).Day() == 1 } func walletCronBatchRequest(req scheduler.BatchRequest) *walletv1.CronBatchRequest { // scheduler 的 RunID 同时作为请求幂等标识传给 wallet;wallet 内部会继续按主播和周期生成账务幂等键。 return &walletv1.CronBatchRequest{ RequestId: req.RunID, AppCode: req.AppCode, RunId: req.RunID, WorkerId: req.WorkerID, BatchSize: int32(req.BatchSize), LockTtlMs: req.LockTTL.Milliseconds(), } } func walletCronBatchResult(resp *walletv1.CronBatchResponse) scheduler.BatchResult { if resp == nil { return scheduler.BatchResult{} } return scheduler.BatchResult{ ClaimedCount: int(resp.GetClaimedCount()), ProcessedCount: int(resp.GetProcessedCount()), SuccessCount: int(resp.GetSuccessCount()), FailureCount: int(resp.GetFailureCount()), HasMore: resp.GetHasMore(), } }