From 55bd0305857164a1f6aba55ae8dcc2048d115bb0 Mon Sep 17 00:00:00 2001 From: zhx Date: Mon, 29 Jun 2026 18:31:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=B3=E6=9E=84=E6=B8=B8=E6=88=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/internal/modules/hostorg/service.go | 82 +++++++++++++++---- .../internal/modules/hostorg/service_test.go | 73 +++++++++++++++++ 2 files changed, 138 insertions(+), 17 deletions(-) diff --git a/server/admin/internal/modules/hostorg/service.go b/server/admin/internal/modules/hostorg/service.go index 4f8d7d06..3a0ff77a 100644 --- a/server/admin/internal/modules/hostorg/service.go +++ b/server/admin/internal/modules/hostorg/service.go @@ -10,21 +10,25 @@ import ( "hyapp-admin-server/internal/integration/userclient" "hyapp-admin-server/internal/integration/walletclient" walletv1 "hyapp.local/api/proto/wallet/v1" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) const ( - coinSellerMerchantAssetType = "COIN_SELLER_COIN" - coinSellerStockTypePurchase = "usdt_purchase" - coinSellerStockTypeDeduction = "usdt_deduction" - coinSellerStockTypeCompensate = "coin_compensation" - agencyStatusDeleted = "deleted" - membershipStatusActive = "active" - paidCurrencyUSDT = "USDT" - sortByDiamond = "diamond" - sortByMerchantBalance = "merchant_balance" - sortBySalaryWallet = "salary_wallet" - sortByTotalRechargeUSDT = "total_recharge_usdt" - bdLeaderPositionAliasMaxRunes = 64 + coinSellerMerchantAssetType = "COIN_SELLER_COIN" + coinSellerStockTypePurchase = "usdt_purchase" + coinSellerStockTypeDeduction = "usdt_deduction" + coinSellerStockTypeCompensate = "coin_compensation" + agencyStatusDeleted = "deleted" + membershipStatusActive = "active" + paidCurrencyUSDT = "USDT" + sortByDiamond = "diamond" + sortByMerchantBalance = "merchant_balance" + sortBySalaryWallet = "salary_wallet" + sortByTotalRechargeUSDT = "total_recharge_usdt" + bdLeaderPositionAliasMaxRunes = 64 + hostOrgInternalUserIDMinDigits = 15 ) type Service struct { @@ -481,18 +485,62 @@ func (s *Service) resolveDisplayUserID(ctx context.Context, requestID string, di if displayUserID <= 0 { return 0, fmt.Errorf("display_user_id is required") } + rawID := strconv.FormatInt(displayUserID, 10) + userIDChecked := false + if len(strings.TrimLeft(rawID, "0")) >= hostOrgInternalUserIDMinDigits { + // 团队后台新合约的 targetUserId 可能是内部雪花 user_id;长数字先按 user_id 确认,避免把内部 ID 误送到短号解析。 + userIDChecked = true + found, err := s.userIDExists(ctx, requestID, displayUserID) + if err != nil { + return 0, err + } + if found { + return displayUserID, nil + } + } identity, err := s.userClient.ResolveDisplayUserID(ctx, userclient.ResolveDisplayUserIDRequest{ RequestID: requestID, Caller: "hyapp-admin-server", - DisplayUserID: strconv.FormatInt(displayUserID, 10), + DisplayUserID: rawID, }) if err != nil { - return 0, err + if !isGRPCNotFound(err) { + return 0, err + } + } else if identity != nil && identity.UserID > 0 { + return identity.UserID, nil } - if identity == nil || identity.UserID <= 0 { - return 0, fmt.Errorf("display_user_id %d not found", displayUserID) + + if !userIDChecked { + // 当前 active 短号解析失败后,短数字仍可能是本地/旧后台直接填写的真实 user_id 或 held 默认短号;只读 GetUser 做存在性确认,不改变 user-service 的 active 短号协议。 + found, err := s.userIDExists(ctx, requestID, displayUserID) + if err != nil { + return 0, err + } + if found { + return displayUserID, nil + } } - return identity.UserID, nil + return 0, fmt.Errorf("display_user_id %d not found", displayUserID) +} + +func (s *Service) userIDExists(ctx context.Context, requestID string, userID int64) (bool, error) { + user, err := s.userClient.GetUser(ctx, userclient.GetUserRequest{ + RequestID: requestID, + Caller: "hyapp-admin-server", + UserID: userID, + }) + if err != nil { + if isGRPCNotFound(err) { + return false, nil + } + return false, err + } + return user != nil && user.UserID > 0, nil +} + +func isGRPCNotFound(err error) bool { + return status.Code(err) == codes.NotFound } func normalizeBDLeaderPositionAlias(value string) (string, error) { diff --git a/server/admin/internal/modules/hostorg/service_test.go b/server/admin/internal/modules/hostorg/service_test.go index aeef0e9e..79317def 100644 --- a/server/admin/internal/modules/hostorg/service_test.go +++ b/server/admin/internal/modules/hostorg/service_test.go @@ -1,13 +1,86 @@ package hostorg import ( + "context" "encoding/json" + "reflect" + "strconv" "strings" "testing" "hyapp-admin-server/internal/integration/userclient" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) +type fakeHostOrgUserClient struct { + userclient.Client + users map[int64]*userclient.User + displays map[string]*userclient.UserIdentity + calls []string +} + +func (f *fakeHostOrgUserClient) GetUser(_ context.Context, req userclient.GetUserRequest) (*userclient.User, error) { + f.calls = append(f.calls, "get:"+strconv.FormatInt(req.UserID, 10)) + if user := f.users[req.UserID]; user != nil { + return user, nil + } + return nil, status.Error(codes.NotFound, "user not found") +} + +func (f *fakeHostOrgUserClient) ResolveDisplayUserID(_ context.Context, req userclient.ResolveDisplayUserIDRequest) (*userclient.UserIdentity, error) { + f.calls = append(f.calls, "resolve:"+req.DisplayUserID) + if identity := f.displays[req.DisplayUserID]; identity != nil { + return identity, nil + } + return nil, status.Error(codes.NotFound, "display_user_id not found") +} + +func TestResolveDisplayUserIDFallsBackToNumericUserID(t *testing.T) { + client := &fakeHostOrgUserClient{ + users: map[int64]*userclient.User{ + 123456: {UserID: 123456, DisplayUserID: "9999", DefaultDisplayUserID: "123456"}, + }, + displays: map[string]*userclient.UserIdentity{}, + } + service := NewService(client, nil, nil) + + userID, err := service.resolveDisplayUserID(context.Background(), "req-held-default", 123456) + if err != nil { + t.Fatalf("resolveDisplayUserID returned error: %v", err) + } + if userID != 123456 { + t.Fatalf("fallback user id mismatch: got %d", userID) + } + if want := []string{"resolve:123456", "get:123456"}; !reflect.DeepEqual(client.calls, want) { + t.Fatalf("calls mismatch: got %v want %v", client.calls, want) + } +} + +func TestResolveDisplayUserIDKeepsActiveDisplayPriority(t *testing.T) { + client := &fakeHostOrgUserClient{ + users: map[int64]*userclient.User{ + 123456: {UserID: 123456, DisplayUserID: "9999", DefaultDisplayUserID: "123456"}, + }, + displays: map[string]*userclient.UserIdentity{ + "123456": {UserID: 88, DisplayUserID: "123456"}, + }, + } + service := NewService(client, nil, nil) + + userID, err := service.resolveDisplayUserID(context.Background(), "req-active-display", 123456) + if err != nil { + t.Fatalf("resolveDisplayUserID returned error: %v", err) + } + if userID != 88 { + t.Fatalf("active display user id mismatch: got %d", userID) + } + if want := []string{"resolve:123456"}; !reflect.DeepEqual(client.calls, want) { + t.Fatalf("calls mismatch: got %v want %v", client.calls, want) + } +} + // TestNormalizeListQueryAllowsComputedSorts 锁定后台列表支持的计算排序字段不会在查询归一化时被清掉。 func TestNormalizeListQueryAllowsComputedSorts(t *testing.T) { for _, sortBy := range []string{sortByMerchantBalance, sortBySalaryWallet, sortByTotalRechargeUSDT} {