package services import ( "context" "fmt" "github.com/shopspring/decimal" "go.uber.org/zap" "tyapi-server/internal/config" "tyapi-server/internal/domains/finance/entities" "tyapi-server/internal/domains/finance/repositories" ) // WalletAggregateService 钱包聚合服务接口 type WalletAggregateService interface { CreateWallet(ctx context.Context, userID string) (*entities.Wallet, error) Recharge(ctx context.Context, userID string, amount decimal.Decimal) error Deduct(ctx context.Context, userID string, amount decimal.Decimal, apiCallID, transactionID, productID string) error GetBalance(ctx context.Context, userID string) (decimal.Decimal, error) LoadWalletByUserId(ctx context.Context, userID string) (*entities.Wallet, error) } // WalletAggregateServiceImpl 实现 // WalletAggregateServiceImpl 钱包聚合服务实现 type WalletAggregateServiceImpl struct { walletRepo repositories.WalletRepository transactionRepo repositories.WalletTransactionRepository logger *zap.Logger cfg *config.Config } func NewWalletAggregateService( walletRepo repositories.WalletRepository, transactionRepo repositories.WalletTransactionRepository, logger *zap.Logger, cfg *config.Config, ) WalletAggregateService { return &WalletAggregateServiceImpl{ walletRepo: walletRepo, transactionRepo: transactionRepo, logger: logger, cfg: cfg, } } // CreateWallet 创建钱包 func (s *WalletAggregateServiceImpl) CreateWallet(ctx context.Context, userID string) (*entities.Wallet, error) { // 检查是否已存在 w, _ := s.walletRepo.GetByUserID(ctx, userID) if w != nil { return nil, fmt.Errorf("用户已存在钱包") } wallet := entities.NewWallet(userID, decimal.NewFromFloat(s.cfg.Wallet.DefaultCreditLimit)) created, err := s.walletRepo.Create(ctx, *wallet) if err != nil { s.logger.Error("创建钱包失败", zap.Error(err)) return nil, err } s.logger.Info("钱包创建成功", zap.String("user_id", userID), zap.String("wallet_id", created.ID)) return &created, nil } // Recharge 充值 func (s *WalletAggregateServiceImpl) Recharge(ctx context.Context, userID string, amount decimal.Decimal) error { w, err := s.walletRepo.GetByUserID(ctx, userID) if err != nil { return fmt.Errorf("钱包不存在") } // 更新钱包余额 w.AddBalance(amount) ok, err := s.walletRepo.UpdateBalanceWithVersion(ctx, w.ID, w.Balance.String(), w.Version) if err != nil { return err } if !ok { return fmt.Errorf("高并发下充值失败,请重试") } s.logger.Info("钱包充值成功", zap.String("user_id", userID), zap.String("wallet_id", w.ID), zap.String("amount", amount.String()), zap.String("balance_after", w.Balance.String())) return nil } // Deduct 扣款,含欠费规则 func (s *WalletAggregateServiceImpl) Deduct(ctx context.Context, userID string, amount decimal.Decimal, apiCallID, transactionID, productID string) error { w, err := s.walletRepo.GetByUserID(ctx, userID) if err != nil { return fmt.Errorf("钱包不存在") } // 扣减余额 if err := w.SubtractBalance(amount); err != nil { return err } // 更新钱包余额 ok, err := s.walletRepo.UpdateBalanceWithVersion(ctx, w.ID, w.Balance.String(), w.Version) if err != nil { return err } if !ok { return fmt.Errorf("高并发下扣款失败,请重试") } // 创建扣款记录 transaction := entities.NewWalletTransaction(userID, apiCallID, transactionID, productID, amount) _, err = s.transactionRepo.Create(ctx, *transaction) if err != nil { s.logger.Error("创建扣款记录失败", zap.Error(err)) // 不返回错误,因为钱包余额已经更新成功 } s.logger.Info("钱包扣款成功", zap.String("user_id", userID), zap.String("wallet_id", w.ID), zap.String("amount", amount.String()), zap.String("balance_after", w.Balance.String()), zap.String("api_call_id", apiCallID)) return nil } // GetBalance 查询余额 func (s *WalletAggregateServiceImpl) GetBalance(ctx context.Context, userID string) (decimal.Decimal, error) { w, err := s.walletRepo.GetByUserID(ctx, userID) if err != nil { return decimal.Zero, fmt.Errorf("钱包不存在") } return w.Balance, nil } func (s *WalletAggregateServiceImpl) LoadWalletByUserId(ctx context.Context, userID string) (*entities.Wallet, error) { return s.walletRepo.GetByUserID(ctx, userID) }