package grpc import ( "context" walletv1 "hyapp.local/api/proto/wallet/v1" "hyapp/pkg/appcode" "hyapp/pkg/xerr" "hyapp/services/wallet-service/internal/domain/ledger" ) // 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(), SenderRegionID: req.GetSenderRegionId(), TargetIsHost: req.GetTargetIsHost(), TargetHostRegionID: req.GetTargetHostRegionId(), TargetAgencyOwnerUserID: req.GetTargetAgencyOwnerUserId(), EntitlementID: req.GetEntitlementId(), ChargeSource: req.GetChargeSource(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return debitGiftResponseFromReceipt(receipt), nil } // DebitDirectGift 处理私聊送礼账务命令;私聊没有房间状态,区域和主播身份必须由 gateway 注入。 func (s *Server) DebitDirectGift(ctx context.Context, req *walletv1.DebitDirectGiftRequest) (*walletv1.DebitGiftResponse, error) { ctx = appcode.WithContext(ctx, req.GetAppCode()) receipt, err := s.svc.DebitDirectGift(ctx, ledger.DebitGiftCommand{ AppCode: req.GetAppCode(), CommandID: req.GetCommandId(), SenderUserID: req.GetSenderUserId(), TargetUserID: req.GetTargetUserId(), GiftID: req.GetGiftId(), GiftCount: req.GetGiftCount(), PriceVersion: req.GetPriceVersion(), RegionID: req.GetRegionId(), SenderRegionID: req.GetSenderRegionId(), TargetIsHost: req.GetTargetIsHost(), TargetHostRegionID: req.GetTargetHostRegionId(), TargetAgencyOwnerUserID: req.GetTargetAgencyOwnerUserId(), EntitlementID: req.GetEntitlementId(), ChargeSource: req.GetChargeSource(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return debitGiftResponseFromReceipt(receipt), nil } // BatchDebitGift 只负责批量目标 protobuf 转换;同事务扣费和幂等由 wallet service/repository 保证。 func (s *Server) BatchDebitGift(ctx context.Context, req *walletv1.BatchDebitGiftRequest) (*walletv1.BatchDebitGiftResponse, error) { ctx = appcode.WithContext(ctx, req.GetAppCode()) targets := make([]ledger.DebitGiftTargetCommand, 0, len(req.GetTargets())) for _, target := range req.GetTargets() { targets = append(targets, ledger.DebitGiftTargetCommand{ CommandID: target.GetCommandId(), TargetUserID: target.GetTargetUserId(), TargetIsHost: target.GetTargetIsHost(), TargetHostRegionID: target.GetTargetHostRegionId(), TargetAgencyOwnerUserID: target.GetTargetAgencyOwnerUserId(), }) } receipt, err := s.svc.BatchDebitGift(ctx, ledger.BatchDebitGiftCommand{ AppCode: req.GetAppCode(), CommandID: req.GetCommandId(), RoomID: req.GetRoomId(), SenderUserID: req.GetSenderUserId(), GiftID: req.GetGiftId(), GiftCount: req.GetGiftCount(), PriceVersion: req.GetPriceVersion(), RegionID: req.GetRegionId(), SenderRegionID: req.GetSenderRegionId(), Targets: targets, EntitlementID: req.GetEntitlementId(), ChargeSource: req.GetChargeSource(), }) if err != nil { return nil, xerr.ToGRPCError(err) } response := &walletv1.BatchDebitGiftResponse{ Aggregate: debitGiftResponseFromReceipt(receipt.Aggregate), Receipts: make([]*walletv1.BatchDebitGiftReceipt, 0, len(receipt.Targets)), } for _, target := range receipt.Targets { response.Receipts = append(response.Receipts, &walletv1.BatchDebitGiftReceipt{ TargetUserId: target.TargetUserID, CommandId: target.CommandID, Billing: debitGiftResponseFromReceipt(target.Receipt), }) } return response, nil } // DebitRobotGift 扣机器人专用金币;该入口只供内部机器人房间编排链路调用。 func (s *Server) DebitRobotGift(ctx context.Context, req *walletv1.DebitRobotGiftRequest) (*walletv1.DebitGiftResponse, error) { ctx = appcode.WithContext(ctx, req.GetAppCode()) receipt, err := s.svc.DebitRobotGift(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(), SenderRegionID: req.GetSenderRegionId(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return debitGiftResponseFromReceipt(receipt), nil } func debitGiftResponseFromReceipt(receipt ledger.Receipt) *walletv1.DebitGiftResponse { 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, CpRelationType: receipt.CPRelationType, GiftName: receipt.GiftName, GiftIconUrl: receipt.GiftIconURL, GiftAnimationUrl: receipt.GiftAnimationURL, GiftEffectTypes: receipt.GiftEffectTypes, PriceVersion: receipt.PriceVersion, HostPeriodDiamondAdded: receipt.HostPeriodDiamondAdded, HostPeriodCycleKey: receipt.HostPeriodCycleKey, EntitlementId: receipt.EntitlementID, ChargeSource: receipt.ChargeSource, GiftIncomeCoinAmount: receipt.GiftIncomeCoinAmount, GiftIncomeBalanceAfter: receipt.GiftIncomeBalanceAfter, } }