diff --git a/services/game-service/internal/service/game/service_test.go b/services/game-service/internal/service/game/service_test.go index c66e87e0..3f5d2a0f 100644 --- a/services/game-service/internal/service/game/service_test.go +++ b/services/game-service/internal/service/game/service_test.go @@ -994,6 +994,9 @@ func TestHandleLeaderCCChangeCoinAcceptsAppAccessTokenAndTokenOnlyProbe(t *testi if wallet.lastApply.GetUserId() != 42 || wallet.lastApply.GetGameId() != "101" || wallet.lastApply.GetCommandId() != "game:lingxian:order_app_token_1" { t.Fatalf("wallet command must use token user and request game: %+v", wallet.lastApply) } + if repo.order.RegionID != 100 { + t.Fatalf("app-token game order must resolve current user region before publishing: %+v", repo.order) + } } func TestHandleYomiGetTokenAndUserInfo(t *testing.T) { diff --git a/services/game-service/internal/service/game/yomi_adapter.go b/services/game-service/internal/service/game/yomi_adapter.go index e65af4cf..3b3cb5af 100644 --- a/services/game-service/internal/service/game/yomi_adapter.go +++ b/services/game-service/internal/service/game/yomi_adapter.go @@ -297,6 +297,21 @@ type yomiCoinChangeResult struct { } func (s *Service) applyYomiCoinChange(ctx context.Context, app string, req *gamev1.CallbackRequest, session gamedomain.LaunchSession, providerOrderID string, providerRoundID string, opType string, amount int64, roomID string, requestHash string) (yomiCoinChangeResult, error) { + regionID, countryID := session.RegionID, session.CountryID + if regionID <= 0 || countryID <= 0 { + // Baishun/Lingxian/Reyou/ZeeOne 允许直接把 App access token 当厂商会话,此时 JWT 只携带用户身份, + // 没有启动会话里的区域快照。钱包改账前补齐主数据维度,保证订单和 GameOrderSettled 不会落入 region_id=0。 + resolvedRegionID, resolvedCountryID, err := s.resolveUserDimensions(ctx, app, req.GetMeta().GetRequestId(), session.UserID) + if err != nil { + return yomiCoinChangeResult{}, err + } + if regionID <= 0 { + regionID = resolvedRegionID + } + if countryID <= 0 { + countryID = resolvedCountryID + } + } // order_id 用平台订单号稳定派生,保证厂商重试、服务重启、并发请求都命中同一条订单。 order := gamedomain.GameOrder{ AppCode: app, @@ -308,8 +323,8 @@ func (s *Service) applyYomiCoinChange(ctx context.Context, app string, req *game ProviderGameID: session.ProviderGameID, UserID: session.UserID, RoomID: strings.TrimSpace(firstNonEmpty(roomID, session.RoomID)), - RegionID: session.RegionID, - CountryID: session.CountryID, + RegionID: regionID, + CountryID: countryID, OpType: opType, CoinAmount: amount, Status: gamedomain.OrderStatusWalletApplying,