package grpc import ( "context" walletv1 "hyapp.local/api/proto/wallet/v1" "hyapp/pkg/xerr" "hyapp/services/wallet-service/internal/domain/ledger" ) // ListPointWithdrawalCoinSellers 返回 wallet 侧已执行 app/status/区域或国家过滤的可信白名单。 func (s *Server) ListPointWithdrawalCoinSellers(ctx context.Context, req *walletv1.ListPointWithdrawalCoinSellersRequest) (*walletv1.ListPointWithdrawalCoinSellersResponse, error) { items, err := s.svc.ListPointWithdrawalCoinSellers(ctx, req.GetAppCode(), req.GetRegionId(), req.GetCountryCode(), req.GetIncludeDisabled()) if err != nil { return nil, xerr.ToGRPCError(err) } response := &walletv1.ListPointWithdrawalCoinSellersResponse{Sellers: make([]*walletv1.PointWithdrawalCoinSellerConfig, 0, len(items))} for _, item := range items { response.Sellers = append(response.Sellers, &walletv1.PointWithdrawalCoinSellerConfig{ AppCode: item.AppCode, SellerUserId: item.SellerUserID, SortOrder: int32(item.SortOrder), PointAmount: item.PointAmount, SellerCoinAmount: item.SellerCoinAmount, ServiceRegionIds: append([]int64(nil), item.ServiceRegionIDs...), ServiceCountryCodes: append([]string(nil), item.ServiceCountryCodes...), Status: item.Status, CreatedAtMs: item.CreatedAtMS, UpdatedAtMs: item.UpdatedAtMS, }) } return response, nil } // TransferPointToCoinSeller 不接受兑换比例字段,确保所有调用方都只能使用数据库白名单快照。 func (s *Server) TransferPointToCoinSeller(ctx context.Context, req *walletv1.TransferPointToCoinSellerRequest) (*walletv1.TransferPointToCoinSellerResponse, error) { receipt, err := s.svc.TransferPointToCoinSeller(ctx, ledger.PointToCoinSellerCommand{ AppCode: req.GetAppCode(), CommandID: req.GetCommandId(), SourceUserID: req.GetSourceUserId(), SellerUserID: req.GetSellerUserId(), PointAmount: req.GetPointAmount(), SourceAssetType: req.GetSourceAssetType(), GrossUSDMinor: req.GetGrossUsdMinor(), SourceCountryCode: req.GetSourceCountryCode(), Reason: req.GetReason(), RegionID: req.GetRegionId(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return &walletv1.TransferPointToCoinSellerResponse{ TransactionId: receipt.TransactionID, SourcePointBalanceAfter: receipt.SourcePointBalanceAfter, SellerBalanceAfter: receipt.SellerBalanceAfter, PointAmount: receipt.PointAmount, SellerCoinAmount: receipt.SellerCoinAmount, RatioPointAmount: receipt.RatioPointAmount, RatioSellerCoinAmount: receipt.RatioSellerCoinAmount, SourceAssetType: receipt.SourceAssetType, GrossUsdMinor: receipt.GrossUSDMinor, FeeUsdMinor: receipt.FeeUSDMinor, NetUsdMinor: receipt.NetUSDMinor, WithdrawFeeBps: receipt.WithdrawFeeBPS, PolicyId: receipt.PolicyID, PolicyVersion: receipt.PolicyVersion, }, nil } // ExchangePointToCoin 把 H5 的钻石输入解释为 POINT,并返回 wallet-service 原子账变后的余额快照。 func (s *Server) ExchangePointToCoin(ctx context.Context, req *walletv1.ExchangePointToCoinRequest) (*walletv1.ExchangePointToCoinResponse, error) { receipt, err := s.svc.ExchangePointToCoin(ctx, ledger.PointToCoinCommand{ AppCode: req.GetAppCode(), CommandID: req.GetCommandId(), UserID: req.GetUserId(), PointAmount: req.GetPointAmount(), SourceAssetType: req.GetSourceAssetType(), RegionID: req.GetRegionId(), NowMS: req.GetNowMs(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return &walletv1.ExchangePointToCoinResponse{ TransactionId: receipt.TransactionID, PointAmount: receipt.PointAmount, CoinAmount: receipt.CoinAmount, PointBalanceAfter: receipt.PointBalanceAfter, CoinBalanceAfter: receipt.CoinBalanceAfter, RatioPointAmount: receipt.RatioPointAmount, RatioCoinAmount: receipt.RatioCoinAmount, SourceAssetType: receipt.SourceAssetType, PolicyId: receipt.PolicyID, PolicyVersion: receipt.PolicyVersion, }, nil } // GetPointWithdrawalConfig 暴露 POINT 提现和兑换所需的最小运行参数,H5 不解析 Admin rule_json。 func (s *Server) GetPointWithdrawalConfig(ctx context.Context, req *walletv1.GetPointWithdrawalConfigRequest) (*walletv1.GetPointWithdrawalConfigResponse, error) { var config ledger.PointWithdrawalRuntimeConfig var err error if req.GetUserId() > 0 { config, err = s.svc.GetPointWithdrawalConfigForUser(ctx, req.GetAppCode(), req.GetUserId(), req.GetRegionId(), req.GetNowMs(), req.GetAssetType()) } else { config, err = s.svc.GetPointWithdrawalConfigForAsset(ctx, req.GetAppCode(), req.GetRegionId(), req.GetNowMs(), req.GetAssetType()) } if err != nil { return nil, xerr.ToGRPCError(err) } return &walletv1.GetPointWithdrawalConfigResponse{ Found: config.Found, PointsPerUsd: config.PointsPerUSD, CoinsPerUsd: config.CoinsPerUSD, FeeBps: int32(config.FeeBPS), MinimumPoints: config.MinimumPoints, PolicyInstanceCode: config.PolicyInstanceCode, PolicyType: config.PolicyType, MinimumWithdrawUsdMinor: config.MinimumWithdrawUSDMinor, AgencyPointShareBps: config.AgencyPointShareBPS, PolicyId: config.PolicyID, PolicyVersion: config.PolicyVersion, AvailabilityEvaluated: config.AvailabilityEvaluated, CoinSellerAvailability: pointWithdrawalAvailabilityToProto(config.CoinSellerAvailability), PlatformAvailability: pointWithdrawalAvailabilityToProto(config.PlatformAvailability), }, nil } func pointWithdrawalAvailabilityToProto(value ledger.PointWithdrawalActionAvailability) *walletv1.PointWithdrawalActionAvailability { return &walletv1.PointWithdrawalActionAvailability{ Allowed: value.Allowed, LimitPeriod: value.LimitPeriod, LimitCount: value.LimitCount, UsedCount: value.UsedCount, RemainingCount: value.RemainingCount, AllowedDays: value.AllowedDays, BlockReason: value.BlockReason, } }