743 lines
28 KiB
Go
743 lines
28 KiB
Go
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
walletv1 "hyapp.local/api/proto/wallet/v1"
|
|
"hyapp/pkg/appcode"
|
|
"hyapp/pkg/xerr"
|
|
"hyapp/services/wallet-service/internal/domain/ledger"
|
|
walletservice "hyapp/services/wallet-service/internal/service/wallet"
|
|
)
|
|
|
|
// Server 把 wallet-service 用例层适配为 gRPC 接口。
|
|
type Server struct {
|
|
walletv1.UnimplementedWalletServiceServer
|
|
|
|
svc *walletservice.Service
|
|
}
|
|
|
|
// NewServer 创建 wallet gRPC server。
|
|
func NewServer(svc *walletservice.Service) *Server {
|
|
return &Server{svc: svc}
|
|
}
|
|
|
|
// DebitGift 只负责 protobuf 转换和错误映射,扣费规则在 service/repository。
|
|
func (s *Server) DebitGift(ctx context.Context, req *walletv1.DebitGiftRequest) (*walletv1.DebitGiftResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
receipt, err := s.svc.DebitGift(ctx, ledger.DebitGiftCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
RoomID: req.GetRoomId(),
|
|
SenderUserID: req.GetSenderUserId(),
|
|
TargetUserID: req.GetTargetUserId(),
|
|
GiftID: req.GetGiftId(),
|
|
GiftCount: req.GetGiftCount(),
|
|
PriceVersion: req.GetPriceVersion(),
|
|
RegionID: req.GetRegionId(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
|
|
return &walletv1.DebitGiftResponse{
|
|
BillingReceiptId: receipt.BillingReceiptID,
|
|
BalanceAfter: receipt.BalanceAfter,
|
|
TransactionId: receipt.TransactionID,
|
|
CoinSpent: receipt.CoinSpent,
|
|
ChargeAssetType: receipt.ChargeAssetType,
|
|
ChargeAmount: receipt.ChargeAmount,
|
|
GiftPointAdded: receipt.GiftPointAdded,
|
|
HeatValue: receipt.HeatValue,
|
|
GiftTypeCode: receipt.GiftTypeCode,
|
|
PriceVersion: receipt.PriceVersion,
|
|
}, nil
|
|
}
|
|
|
|
// GetBalances 返回用户多资产余额投影。
|
|
func (s *Server) GetBalances(ctx context.Context, req *walletv1.GetBalancesRequest) (*walletv1.GetBalancesResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
balances, err := s.svc.GetBalances(ctx, req.GetUserId(), req.GetAssetTypes())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
|
|
response := &walletv1.GetBalancesResponse{Balances: make([]*walletv1.AssetBalance, 0, len(balances))}
|
|
for _, balance := range balances {
|
|
response.Balances = append(response.Balances, &walletv1.AssetBalance{
|
|
AppCode: balance.AppCode,
|
|
AssetType: balance.AssetType,
|
|
AvailableAmount: balance.AvailableAmount,
|
|
FrozenAmount: balance.FrozenAmount,
|
|
Version: balance.Version,
|
|
})
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
// GetWalletOverview 返回钱包首页摘要,供我的页和钱包二级页复用。
|
|
func (s *Server) GetWalletOverview(ctx context.Context, req *walletv1.GetWalletOverviewRequest) (*walletv1.GetWalletOverviewResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
overview, err := s.svc.GetWalletOverview(ctx, req.GetUserId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.GetWalletOverviewResponse{
|
|
Balances: balancesToProto(overview.Balances),
|
|
FeatureFlags: walletFeatureFlagsToProto(overview.FeatureFlags),
|
|
}, nil
|
|
}
|
|
|
|
// GetWalletValueSummary 返回我的页钱包卡片最小金币余额。
|
|
func (s *Server) GetWalletValueSummary(ctx context.Context, req *walletv1.GetWalletValueSummaryRequest) (*walletv1.GetWalletValueSummaryResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
summary, err := s.svc.GetWalletValueSummary(ctx, req.GetUserId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.GetWalletValueSummaryResponse{Summary: &walletv1.WalletValueSummary{
|
|
CoinAmount: summary.CoinAmount,
|
|
UpdatedAtMs: summary.UpdatedAtMS,
|
|
}}, nil
|
|
}
|
|
|
|
// GetUserGiftWall 返回当前用户收到礼物的聚合墙;调用方负责限定 user_id 为当前登录用户。
|
|
func (s *Server) GetUserGiftWall(ctx context.Context, req *walletv1.GetUserGiftWallRequest) (*walletv1.GetUserGiftWallResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
wall, err := s.svc.GetUserGiftWall(ctx, req.GetUserId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &walletv1.GetUserGiftWallResponse{
|
|
Items: make([]*walletv1.GiftWallItem, 0, len(wall.Items)),
|
|
GiftKindCount: wall.GiftKindCount,
|
|
GiftTotalCount: wall.GiftTotalCount,
|
|
TotalValue: wall.TotalValue,
|
|
TotalCoinValue: wall.TotalCoinValue,
|
|
TotalDiamondValue: wall.TotalDiamondValue,
|
|
TotalGiftPoint: wall.TotalGiftPoint,
|
|
TotalHeatValue: wall.TotalHeatValue,
|
|
}
|
|
for _, item := range wall.Items {
|
|
resp.Items = append(resp.Items, giftWallItemToProto(item))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// ListRechargeProducts 返回当前用户区域可用的充值渠道和档位。
|
|
func (s *Server) ListRechargeProducts(ctx context.Context, req *walletv1.ListRechargeProductsRequest) (*walletv1.ListRechargeProductsResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
products, channels, err := s.svc.ListRechargeProducts(ctx, req.GetUserId(), req.GetRegionId(), req.GetPlatform())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &walletv1.ListRechargeProductsResponse{Channels: channels, Products: make([]*walletv1.RechargeProduct, 0, len(products))}
|
|
for _, product := range products {
|
|
resp.Products = append(resp.Products, rechargeProductToProto(product))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// ConfirmGooglePayment 校验 Google Play purchase token 并完成钱包入账。
|
|
func (s *Server) ConfirmGooglePayment(ctx context.Context, req *walletv1.ConfirmGooglePaymentRequest) (*walletv1.ConfirmGooglePaymentResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
receipt, err := s.svc.ConfirmGooglePayment(ctx, ledger.GooglePaymentCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
UserID: req.GetUserId(),
|
|
RegionID: req.GetRegionId(),
|
|
ProductID: req.GetProductId(),
|
|
ProductCode: req.GetProductCode(),
|
|
PackageName: req.GetPackageName(),
|
|
PurchaseToken: req.GetPurchaseToken(),
|
|
OrderID: req.GetOrderId(),
|
|
PurchaseTimeMS: req.GetPurchaseTimeMs(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.ConfirmGooglePaymentResponse{
|
|
PaymentOrderId: receipt.PaymentOrderID,
|
|
TransactionId: receipt.TransactionID,
|
|
Status: receipt.Status,
|
|
ProductId: receipt.ProductID,
|
|
ProductCode: receipt.ProductCode,
|
|
CoinAmount: receipt.CoinAmount,
|
|
Balance: balanceToProto(receipt.Balance),
|
|
IdempotentReplay: receipt.IdempotentReplay,
|
|
ConsumeState: receipt.ConsumeState,
|
|
}, nil
|
|
}
|
|
|
|
// ListAdminRechargeProducts 返回后台内购配置列表。
|
|
func (s *Server) ListAdminRechargeProducts(ctx context.Context, req *walletv1.ListAdminRechargeProductsRequest) (*walletv1.ListAdminRechargeProductsResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
products, total, err := s.svc.ListAdminRechargeProducts(ctx, ledger.ListRechargeProductsQuery{
|
|
AppCode: req.GetAppCode(),
|
|
Status: req.GetStatus(),
|
|
Platform: req.GetPlatform(),
|
|
RegionID: req.GetRegionId(),
|
|
Keyword: req.GetKeyword(),
|
|
Page: req.GetPage(),
|
|
PageSize: req.GetPageSize(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &walletv1.ListAdminRechargeProductsResponse{Products: make([]*walletv1.RechargeProduct, 0, len(products)), Total: total}
|
|
for _, product := range products {
|
|
resp.Products = append(resp.Products, rechargeProductToProto(product))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// CreateRechargeProduct 创建后台内购商品配置。
|
|
func (s *Server) CreateRechargeProduct(ctx context.Context, req *walletv1.CreateRechargeProductRequest) (*walletv1.RechargeProductResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
product, err := s.svc.CreateRechargeProduct(ctx, ledger.RechargeProductCommand{
|
|
AppCode: req.GetAppCode(),
|
|
AmountMicro: req.GetAmountMicro(),
|
|
CoinAmount: req.GetCoinAmount(),
|
|
ProductName: req.GetProductName(),
|
|
Description: req.GetDescription(),
|
|
Platform: req.GetPlatform(),
|
|
RegionIDs: req.GetRegionIds(),
|
|
Enabled: req.GetEnabled(),
|
|
OperatorUserID: req.GetOperatorUserId(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.RechargeProductResponse{Product: rechargeProductToProto(product)}, nil
|
|
}
|
|
|
|
// UpdateRechargeProduct 修改后台内购商品配置。
|
|
func (s *Server) UpdateRechargeProduct(ctx context.Context, req *walletv1.UpdateRechargeProductRequest) (*walletv1.RechargeProductResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
product, err := s.svc.UpdateRechargeProduct(ctx, ledger.RechargeProductCommand{
|
|
AppCode: req.GetAppCode(),
|
|
ProductID: req.GetProductId(),
|
|
AmountMicro: req.GetAmountMicro(),
|
|
CoinAmount: req.GetCoinAmount(),
|
|
ProductName: req.GetProductName(),
|
|
Description: req.GetDescription(),
|
|
Platform: req.GetPlatform(),
|
|
RegionIDs: req.GetRegionIds(),
|
|
Enabled: req.GetEnabled(),
|
|
OperatorUserID: req.GetOperatorUserId(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.RechargeProductResponse{Product: rechargeProductToProto(product)}, nil
|
|
}
|
|
|
|
// DeleteRechargeProduct 删除后台内购商品配置。
|
|
func (s *Server) DeleteRechargeProduct(ctx context.Context, req *walletv1.DeleteRechargeProductRequest) (*walletv1.DeleteRechargeProductResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
if err := s.svc.DeleteRechargeProduct(ctx, req.GetAppCode(), req.GetProductId()); err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.DeleteRechargeProductResponse{Deleted: true}, nil
|
|
}
|
|
|
|
// GetDiamondExchangeConfig 返回钻石兑换配置。
|
|
func (s *Server) GetDiamondExchangeConfig(ctx context.Context, req *walletv1.GetDiamondExchangeConfigRequest) (*walletv1.GetDiamondExchangeConfigResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
rules, err := s.svc.GetDiamondExchangeConfig(ctx, req.GetUserId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &walletv1.GetDiamondExchangeConfigResponse{Rules: make([]*walletv1.DiamondExchangeRule, 0, len(rules))}
|
|
for _, rule := range rules {
|
|
resp.Rules = append(resp.Rules, &walletv1.DiamondExchangeRule{
|
|
ExchangeType: rule.ExchangeType,
|
|
FromAssetType: rule.FromAssetType,
|
|
ToAssetType: rule.ToAssetType,
|
|
FromAmount: rule.FromAmount,
|
|
ToAmount: rule.ToAmount,
|
|
Enabled: rule.Enabled,
|
|
})
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func rechargeProductToProto(product ledger.RechargeProduct) *walletv1.RechargeProduct {
|
|
return &walletv1.RechargeProduct{
|
|
AppCode: product.AppCode,
|
|
ProductId: product.ProductID,
|
|
ProductCode: product.ProductCode,
|
|
ProductName: product.ProductName,
|
|
Description: product.Description,
|
|
Platform: product.Platform,
|
|
Channel: product.Channel,
|
|
CurrencyCode: product.CurrencyCode,
|
|
AmountMicro: product.AmountMicro,
|
|
AmountMinor: product.AmountMinor,
|
|
CoinAmount: product.CoinAmount,
|
|
PolicyVersion: product.PolicyVersion,
|
|
Status: product.Status,
|
|
Enabled: product.Enabled,
|
|
SortOrder: product.SortOrder,
|
|
RegionIds: product.RegionIDs,
|
|
ResourceAssetType: product.ResourceAssetType,
|
|
CreatedByUserId: product.CreatedByUserID,
|
|
UpdatedByUserId: product.UpdatedByUserID,
|
|
CreatedAtMs: product.CreatedAtMS,
|
|
UpdatedAtMs: product.UpdatedAtMS,
|
|
}
|
|
}
|
|
|
|
// ListWalletTransactions 返回当前用户钱包流水。
|
|
func (s *Server) ListWalletTransactions(ctx context.Context, req *walletv1.ListWalletTransactionsRequest) (*walletv1.ListWalletTransactionsResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
items, total, err := s.svc.ListWalletTransactions(ctx, ledger.ListWalletTransactionsQuery{
|
|
AppCode: req.GetAppCode(),
|
|
UserID: req.GetUserId(),
|
|
AssetType: req.GetAssetType(),
|
|
Page: req.GetPage(),
|
|
PageSize: req.GetPageSize(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &walletv1.ListWalletTransactionsResponse{Transactions: make([]*walletv1.WalletTransaction, 0, len(items)), Total: total}
|
|
for _, item := range items {
|
|
resp.Transactions = append(resp.Transactions, &walletv1.WalletTransaction{
|
|
EntryId: item.EntryID,
|
|
TransactionId: item.TransactionID,
|
|
BizType: item.BizType,
|
|
AssetType: item.AssetType,
|
|
AvailableDelta: item.AvailableDelta,
|
|
FrozenDelta: item.FrozenDelta,
|
|
AvailableAfter: item.AvailableAfter,
|
|
FrozenAfter: item.FrozenAfter,
|
|
CounterpartyUserId: item.CounterpartyUserID,
|
|
RoomId: item.RoomID,
|
|
CreatedAtMs: item.CreatedAtMS,
|
|
})
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// ApplyWithdrawal 创建提现申请并冻结美元余额。
|
|
func (s *Server) ApplyWithdrawal(ctx context.Context, req *walletv1.ApplyWithdrawalRequest) (*walletv1.ApplyWithdrawalResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
withdrawal, balance, err := s.svc.ApplyWithdrawal(ctx, ledger.WithdrawalCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
UserID: req.GetUserId(),
|
|
Amount: req.GetAmount(),
|
|
PayoutAccount: req.GetPayoutAccount(),
|
|
Reason: req.GetReason(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.ApplyWithdrawalResponse{
|
|
Withdrawal: withdrawalToProto(withdrawal),
|
|
Balance: balanceToProto(balance),
|
|
}, nil
|
|
}
|
|
|
|
// ListVipPackages 返回当前 VIP 和可购买包列表。
|
|
func (s *Server) ListVipPackages(ctx context.Context, req *walletv1.ListVipPackagesRequest) (*walletv1.ListVipPackagesResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
current, levels, err := s.svc.ListVipPackages(ctx, req.GetUserId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &walletv1.ListVipPackagesResponse{CurrentVip: vipToProto(current), Packages: make([]*walletv1.VipLevel, 0, len(levels))}
|
|
for _, level := range levels {
|
|
resp.Packages = append(resp.Packages, vipLevelToProto(level))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetMyVip 返回当前登录用户 VIP 状态。
|
|
func (s *Server) GetMyVip(ctx context.Context, req *walletv1.GetMyVipRequest) (*walletv1.GetMyVipResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
vip, err := s.svc.GetMyVip(ctx, req.GetUserId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.GetMyVipResponse{Vip: vipToProto(vip)}, nil
|
|
}
|
|
|
|
// PurchaseVip 购买、续期或升级 VIP。
|
|
func (s *Server) PurchaseVip(ctx context.Context, req *walletv1.PurchaseVipRequest) (*walletv1.PurchaseVipResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
receipt, err := s.svc.PurchaseVip(ctx, ledger.PurchaseVipCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
UserID: req.GetUserId(),
|
|
Level: req.GetLevel(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.PurchaseVipResponse{
|
|
OrderId: receipt.OrderID,
|
|
TransactionId: receipt.TransactionID,
|
|
Vip: vipToProto(receipt.Vip),
|
|
CoinSpent: receipt.CoinSpent,
|
|
CoinBalanceAfter: receipt.CoinBalanceAfter,
|
|
RewardItems: vipRewardItemsToProto(receipt.RewardItems),
|
|
}, nil
|
|
}
|
|
|
|
// GrantVip 统一处理活动和后台赠送 VIP。
|
|
func (s *Server) GrantVip(ctx context.Context, req *walletv1.GrantVipRequest) (*walletv1.GrantVipResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
receipt, err := s.svc.GrantVip(ctx, ledger.GrantVipCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
TargetUserID: req.GetTargetUserId(),
|
|
Level: req.GetLevel(),
|
|
GrantSource: req.GetGrantSource(),
|
|
OperatorUserID: req.GetOperatorUserId(),
|
|
Reason: req.GetReason(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.GrantVipResponse{
|
|
TransactionId: receipt.TransactionID,
|
|
Vip: vipToProto(receipt.Vip),
|
|
RewardItems: vipRewardItemsToProto(receipt.RewardItems),
|
|
ServerTimeMs: time.Now().UnixMilli(),
|
|
}, nil
|
|
}
|
|
|
|
// ListAdminVipLevels 返回后台 VIP 配置。
|
|
func (s *Server) ListAdminVipLevels(ctx context.Context, req *walletv1.ListAdminVipLevelsRequest) (*walletv1.ListAdminVipLevelsResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
levels, err := s.svc.ListAdminVipLevels(ctx)
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &walletv1.ListAdminVipLevelsResponse{Levels: make([]*walletv1.VipLevel, 0, len(levels)), ServerTimeMs: time.Now().UnixMilli()}
|
|
for _, level := range levels {
|
|
resp.Levels = append(resp.Levels, vipLevelToProto(level))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// UpdateAdminVipLevels 保存后台 VIP 配置。
|
|
func (s *Server) UpdateAdminVipLevels(ctx context.Context, req *walletv1.UpdateAdminVipLevelsRequest) (*walletv1.UpdateAdminVipLevelsResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
commands := make([]ledger.AdminVipLevelCommand, 0, len(req.GetLevels()))
|
|
for _, item := range req.GetLevels() {
|
|
if item == nil {
|
|
continue
|
|
}
|
|
commands = append(commands, ledger.AdminVipLevelCommand{
|
|
Level: item.GetLevel(),
|
|
Name: item.GetName(),
|
|
Status: item.GetStatus(),
|
|
PriceCoin: item.GetPriceCoin(),
|
|
DurationMS: item.GetDurationMs(),
|
|
RewardResourceGroupID: item.GetRewardResourceGroupId(),
|
|
RequiredRechargeCoinAmount: item.GetRequiredRechargeCoinAmount(),
|
|
SortOrder: item.GetSortOrder(),
|
|
})
|
|
}
|
|
levels, err := s.svc.UpdateAdminVipLevels(ctx, commands, req.GetOperatorUserId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &walletv1.UpdateAdminVipLevelsResponse{Levels: make([]*walletv1.VipLevel, 0, len(levels)), ServerTimeMs: time.Now().UnixMilli()}
|
|
for _, level := range levels {
|
|
resp.Levels = append(resp.Levels, vipLevelToProto(level))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// AdminCreditAsset 处理后台手动调账,公网权限和审计入口由 gateway/admin 层控制。
|
|
func (s *Server) AdminCreditAsset(ctx context.Context, req *walletv1.AdminCreditAssetRequest) (*walletv1.AdminCreditAssetResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
balance, transactionID, err := s.svc.AdminCreditAsset(ctx, ledger.AdminCreditAssetCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
TargetUserID: req.GetTargetUserId(),
|
|
AssetType: req.GetAssetType(),
|
|
Amount: req.GetAmount(),
|
|
OperatorUserID: req.GetOperatorUserId(),
|
|
Reason: req.GetReason(),
|
|
EvidenceRef: req.GetEvidenceRef(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
|
|
return &walletv1.AdminCreditAssetResponse{
|
|
TransactionId: transactionID,
|
|
Balance: &walletv1.AssetBalance{
|
|
AppCode: balance.AppCode,
|
|
AssetType: balance.AssetType,
|
|
AvailableAmount: balance.AvailableAmount,
|
|
FrozenAmount: balance.FrozenAmount,
|
|
Version: balance.Version,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func balancesToProto(balances []ledger.AssetBalance) []*walletv1.AssetBalance {
|
|
items := make([]*walletv1.AssetBalance, 0, len(balances))
|
|
for _, balance := range balances {
|
|
items = append(items, balanceToProto(balance))
|
|
}
|
|
return items
|
|
}
|
|
|
|
func balanceToProto(balance ledger.AssetBalance) *walletv1.AssetBalance {
|
|
return &walletv1.AssetBalance{
|
|
AppCode: balance.AppCode,
|
|
AssetType: balance.AssetType,
|
|
AvailableAmount: balance.AvailableAmount,
|
|
FrozenAmount: balance.FrozenAmount,
|
|
Version: balance.Version,
|
|
}
|
|
}
|
|
|
|
func giftWallItemToProto(item ledger.GiftWallItem) *walletv1.GiftWallItem {
|
|
return &walletv1.GiftWallItem{
|
|
GiftId: item.GiftID,
|
|
GiftName: item.GiftName,
|
|
ResourceId: item.ResourceID,
|
|
Resource: giftWallResourceToProto(item.Resource),
|
|
ResourceSnapshotJson: item.ResourceSnapshotJSON,
|
|
GiftTypeCode: item.GiftTypeCode,
|
|
PresentationJson: item.PresentationJSON,
|
|
GiftCount: item.GiftCount,
|
|
TotalValue: item.TotalValue,
|
|
TotalCoinValue: item.TotalCoinValue,
|
|
TotalDiamondValue: item.TotalDiamondValue,
|
|
TotalGiftPoint: item.TotalGiftPoint,
|
|
TotalHeatValue: item.TotalHeatValue,
|
|
ChargeAssetType: item.ChargeAssetType,
|
|
LastPriceVersion: item.LastPriceVersion,
|
|
FirstReceivedAtMs: item.FirstReceivedAtMS,
|
|
LastReceivedAtMs: item.LastReceivedAtMS,
|
|
SortOrder: item.SortOrder,
|
|
}
|
|
}
|
|
|
|
func giftWallResourceToProto(resource ledger.GiftWallResource) *walletv1.Resource {
|
|
if resource.ResourceID == 0 {
|
|
return nil
|
|
}
|
|
return &walletv1.Resource{
|
|
AppCode: resource.AppCode,
|
|
ResourceId: resource.ResourceID,
|
|
ResourceCode: resource.ResourceCode,
|
|
ResourceType: resource.ResourceType,
|
|
Name: resource.Name,
|
|
Status: resource.Status,
|
|
Grantable: resource.Grantable,
|
|
GrantStrategy: resource.GrantStrategy,
|
|
WalletAssetType: resource.WalletAssetType,
|
|
WalletAssetAmount: resource.WalletAssetAmount,
|
|
UsageScopes: resource.UsageScopes,
|
|
AssetUrl: resource.AssetURL,
|
|
PreviewUrl: resource.PreviewURL,
|
|
AnimationUrl: resource.AnimationURL,
|
|
MetadataJson: resource.MetadataJSON,
|
|
SortOrder: resource.SortOrder,
|
|
CreatedAtMs: resource.CreatedAtMS,
|
|
UpdatedAtMs: resource.UpdatedAtMS,
|
|
}
|
|
}
|
|
|
|
func walletFeatureFlagsToProto(flags ledger.WalletFeatureFlags) *walletv1.WalletFeatureFlags {
|
|
return &walletv1.WalletFeatureFlags{
|
|
RechargeEnabled: flags.RechargeEnabled,
|
|
DiamondExchangeEnabled: flags.DiamondExchangeEnabled,
|
|
WithdrawEnabled: flags.WithdrawEnabled,
|
|
}
|
|
}
|
|
|
|
func withdrawalToProto(withdrawal ledger.WithdrawalRequest) *walletv1.WithdrawalRequest {
|
|
return &walletv1.WithdrawalRequest{
|
|
WithdrawalId: withdrawal.WithdrawalID,
|
|
UserId: withdrawal.UserID,
|
|
AssetType: withdrawal.AssetType,
|
|
Amount: withdrawal.Amount,
|
|
Status: withdrawal.Status,
|
|
PayoutAccount: withdrawal.PayoutAccount,
|
|
Reason: withdrawal.Reason,
|
|
CreatedAtMs: withdrawal.CreatedAtMS,
|
|
UpdatedAtMs: withdrawal.UpdatedAtMS,
|
|
}
|
|
}
|
|
|
|
func vipToProto(vip ledger.UserVip) *walletv1.UserVip {
|
|
return &walletv1.UserVip{
|
|
UserId: vip.UserID,
|
|
Level: vip.Level,
|
|
Name: vip.Name,
|
|
Active: vip.Active,
|
|
StartedAtMs: vip.StartedAtMS,
|
|
ExpiresAtMs: vip.ExpiresAtMS,
|
|
UpdatedAtMs: vip.UpdatedAtMS,
|
|
}
|
|
}
|
|
|
|
func vipLevelToProto(level ledger.VipLevel) *walletv1.VipLevel {
|
|
return &walletv1.VipLevel{
|
|
Level: level.Level,
|
|
Name: level.Name,
|
|
Status: level.Status,
|
|
PriceCoin: level.PriceCoin,
|
|
DurationMs: level.DurationMS,
|
|
RewardResourceGroupId: level.RewardResourceGroupID,
|
|
RewardItems: vipRewardItemsToProto(level.RewardItems),
|
|
CanPurchase: level.CanPurchase,
|
|
SortOrder: level.SortOrder,
|
|
RechargeGateRequired: level.RechargeGateRequired,
|
|
RequiredRechargeCoinAmount: level.RequiredRechargeCoinAmount,
|
|
UserRechargeCoinAmount: level.UserRechargeCoinAmount,
|
|
PurchaseLockedReason: level.PurchaseLockedReason,
|
|
CreatedAtMs: level.CreatedAtMS,
|
|
UpdatedAtMs: level.UpdatedAtMS,
|
|
}
|
|
}
|
|
|
|
func vipRewardItemsToProto(items []ledger.VipRewardItem) []*walletv1.VipRewardItem {
|
|
resp := make([]*walletv1.VipRewardItem, 0, len(items))
|
|
for _, item := range items {
|
|
resp = append(resp, &walletv1.VipRewardItem{
|
|
ResourceId: item.ResourceID,
|
|
ResourceCode: item.ResourceCode,
|
|
ResourceType: item.ResourceType,
|
|
Name: item.Name,
|
|
Quantity: item.Quantity,
|
|
ExpiresAtMs: item.ExpiresAtMS,
|
|
})
|
|
}
|
|
return resp
|
|
}
|
|
|
|
// CreditTaskReward 处理 activity-service 任务奖励金币入账。
|
|
func (s *Server) CreditTaskReward(ctx context.Context, req *walletv1.CreditTaskRewardRequest) (*walletv1.CreditTaskRewardResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
receipt, err := s.svc.CreditTaskReward(ctx, ledger.TaskRewardCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
TargetUserID: req.GetTargetUserId(),
|
|
Amount: req.GetAmount(),
|
|
TaskType: req.GetTaskType(),
|
|
TaskID: req.GetTaskId(),
|
|
CycleKey: req.GetCycleKey(),
|
|
Reason: req.GetReason(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
|
|
return &walletv1.CreditTaskRewardResponse{
|
|
TransactionId: receipt.TransactionID,
|
|
Amount: receipt.Amount,
|
|
GrantedAtMs: receipt.GrantedAtMS,
|
|
Balance: &walletv1.AssetBalance{
|
|
AppCode: receipt.Balance.AppCode,
|
|
AssetType: receipt.Balance.AssetType,
|
|
AvailableAmount: receipt.Balance.AvailableAmount,
|
|
FrozenAmount: receipt.Balance.FrozenAmount,
|
|
Version: receipt.Balance.Version,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// ApplyGameCoinChange 处理 game-service 发起的游戏专用金币改账。
|
|
func (s *Server) ApplyGameCoinChange(ctx context.Context, req *walletv1.ApplyGameCoinChangeRequest) (*walletv1.ApplyGameCoinChangeResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
receipt, err := s.svc.ApplyGameCoinChange(ctx, ledger.GameCoinChangeCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
UserID: req.GetUserId(),
|
|
PlatformCode: req.GetPlatformCode(),
|
|
GameID: req.GetGameId(),
|
|
ProviderOrderID: req.GetProviderOrderId(),
|
|
ProviderRoundID: req.GetProviderRoundId(),
|
|
OpType: req.GetOpType(),
|
|
CoinAmount: req.GetCoinAmount(),
|
|
RoomID: req.GetRoomId(),
|
|
RequestHash: req.GetRequestHash(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &walletv1.ApplyGameCoinChangeResponse{
|
|
WalletTransactionId: receipt.TransactionID,
|
|
BalanceAfter: receipt.BalanceAfter,
|
|
IdempotentReplay: receipt.IdempotentReplay,
|
|
}, nil
|
|
}
|
|
|
|
// AdminCreditCoinSellerStock 处理后台币商进货或金币补偿,币商身份由 admin-server 先行校验。
|
|
func (s *Server) AdminCreditCoinSellerStock(ctx context.Context, req *walletv1.AdminCreditCoinSellerStockRequest) (*walletv1.AdminCreditCoinSellerStockResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
receipt, err := s.svc.AdminCreditCoinSellerStock(ctx, ledger.CoinSellerStockCreditCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
SellerUserID: req.GetSellerUserId(),
|
|
StockType: req.GetStockType(),
|
|
CoinAmount: req.GetCoinAmount(),
|
|
PaidCurrencyCode: req.GetPaidCurrencyCode(),
|
|
PaidAmountMicro: req.GetPaidAmountMicro(),
|
|
PaymentRef: req.GetPaymentRef(),
|
|
EvidenceRef: req.GetEvidenceRef(),
|
|
OperatorUserID: req.GetOperatorUserId(),
|
|
Reason: req.GetReason(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
|
|
return &walletv1.AdminCreditCoinSellerStockResponse{
|
|
TransactionId: receipt.TransactionID,
|
|
SellerUserId: receipt.SellerUserID,
|
|
StockType: receipt.StockType,
|
|
CoinAmount: receipt.CoinAmount,
|
|
PaidCurrencyCode: receipt.PaidCurrencyCode,
|
|
PaidAmountMicro: receipt.PaidAmountMicro,
|
|
CountsAsSellerRecharge: receipt.CountsAsSellerRecharge,
|
|
BalanceAfter: receipt.BalanceAfter,
|
|
CreatedAtMs: receipt.CreatedAtMS,
|
|
}, nil
|
|
}
|
|
|
|
// TransferCoinFromSeller 处理币商转玩家金币,调用方必须先完成币商身份校验。
|
|
func (s *Server) TransferCoinFromSeller(ctx context.Context, req *walletv1.TransferCoinFromSellerRequest) (*walletv1.TransferCoinFromSellerResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
|
receipt, err := s.svc.TransferCoinFromSeller(ctx, ledger.CoinSellerTransferCommand{
|
|
AppCode: req.GetAppCode(),
|
|
CommandID: req.GetCommandId(),
|
|
SellerUserID: req.GetSellerUserId(),
|
|
TargetUserID: req.GetTargetUserId(),
|
|
SellerRegionID: req.GetSellerRegionId(),
|
|
TargetRegionID: req.GetTargetRegionId(),
|
|
Amount: req.GetAmount(),
|
|
Reason: req.GetReason(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
|
|
return &walletv1.TransferCoinFromSellerResponse{
|
|
TransactionId: receipt.TransactionID,
|
|
SellerBalanceAfter: receipt.SellerBalanceAfter,
|
|
TargetBalanceAfter: receipt.TargetBalanceAfter,
|
|
Amount: receipt.Amount,
|
|
RechargeUsdMinor: receipt.RechargeUSDMinor,
|
|
RechargeCurrencyCode: receipt.RechargeCurrencyCode,
|
|
RechargePolicyId: receipt.RechargePolicyID,
|
|
RechargePolicyVersion: receipt.RechargePolicyVersion,
|
|
RechargePolicyCoinAmount: receipt.RechargePolicyCoinAmount,
|
|
RechargePolicyUsdMinorAmount: receipt.RechargePolicyUSDMinorUnit,
|
|
}, nil
|
|
}
|