From dc9a98e8934904a010e7c5a0ab8af897bb31903a Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Sun, 26 Jul 2026 23:04:18 +0800 Subject: [PATCH] f --- .../certification_application_service_impl.go | 20 ++++++++++++++++--- .../services/api_user_aggregate_service.go | 13 ++++++++++++ .../services/wallet_aggregate_service.go | 12 +++++++---- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/internal/application/certification/certification_application_service_impl.go b/internal/application/certification/certification_application_service_impl.go index 9cd90fe..900c2c6 100644 --- a/internal/application/certification/certification_application_service_impl.go +++ b/internal/application/certification/certification_application_service_impl.go @@ -1697,7 +1697,7 @@ func (s *CertificationApplicationServiceImpl) checkAndUpdateSignStatus(ctx conte } else { reason = "合同签署中" } - err = s.aggregateService.SaveCertification(ctx, cert) + err = s.aggregateService.SaveCertification(txCtx, cert) if err != nil { return fmt.Errorf("保存认证信息失败: %s", err.Error()) } @@ -1767,6 +1767,17 @@ func (s *CertificationApplicationServiceImpl) handleContractAfterSignComplete(ct cert.ContractCode, ) if err != nil { + // 重试场景:合同可能已落库,视为成功继续后续激活 + if strings.Contains(err.Error(), "合同文件ID已存在") { + s.logger.Info("合同文件已存在,跳过重复保存", + zap.String("file_name", fileName), + zap.String("file_id", fileId), + ) + if i == 0 && cert.ContractURL == "" { + cert.ContractURL = qiniuURL + } + continue + } s.logger.Error("保存合同信息到聚合根失败", zap.String("file_name", fileName), zap.Error(err)) continue } @@ -1837,15 +1848,18 @@ func firstNonEmptyStr(values ...string) string { } // completeUserActivationWithoutContract 创建钱包、API用户并在用户域标记完成认证(不依赖合同信息) +// 钱包与 API 用户已存在时幂等跳过,避免重复创建导致事务中止 func (s *CertificationApplicationServiceImpl) completeUserActivationWithoutContract(ctx context.Context, cert *entities.Certification) error { - // 创建钱包 + // 创建钱包(已存在则幂等返回,不中断流程) if _, err := s.walletAggregateService.CreateWallet(ctx, cert.UserID); err != nil { s.logger.Error("创建钱包失败", zap.String("user_id", cert.UserID), zap.Error(err)) + return fmt.Errorf("创建钱包失败: %w", err) } - // 创建API用户 + // 创建API用户(已存在则幂等成功,不重复插入) if err := s.apiUserAggregateService.CreateApiUser(ctx, cert.UserID); err != nil { s.logger.Error("创建API用户失败", zap.String("user_id", cert.UserID), zap.Error(err)) + return fmt.Errorf("创建API用户失败: %w", err) } // 标记用户域完成认证 diff --git a/internal/domains/api/services/api_user_aggregate_service.go b/internal/domains/api/services/api_user_aggregate_service.go index 875f6f0..cc91f84 100644 --- a/internal/domains/api/services/api_user_aggregate_service.go +++ b/internal/domains/api/services/api_user_aggregate_service.go @@ -2,10 +2,14 @@ package services import ( "context" + "errors" "time" + "hyapi-server/internal/config" "hyapi-server/internal/domains/api/entities" repo "hyapi-server/internal/domains/api/repositories" + + "gorm.io/gorm" ) type ApiUserAggregateService interface { @@ -30,6 +34,15 @@ func NewApiUserAggregateService(repo repo.ApiUserRepository, cfg *config.Config) } func (s *ApiUserAggregateServiceImpl) CreateApiUser(ctx context.Context, apiUserId string) error { + // 已存在则幂等成功,避免重复 INSERT 导致 PostgreSQL 事务中止(SQLSTATE 25P02) + existing, err := s.repo.FindByUserId(ctx, apiUserId) + if err == nil && existing != nil { + return nil + } + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } + apiUser, err := entities.NewApiUser(apiUserId, s.cfg.Wallet.BalanceAlert.DefaultEnabled, s.cfg.Wallet.BalanceAlert.DefaultThreshold) if err != nil { return err diff --git a/internal/domains/finance/services/wallet_aggregate_service.go b/internal/domains/finance/services/wallet_aggregate_service.go index b0cb621..74e2db1 100644 --- a/internal/domains/finance/services/wallet_aggregate_service.go +++ b/internal/domains/finance/services/wallet_aggregate_service.go @@ -52,16 +52,20 @@ func NewWalletAggregateService( } } -// CreateWallet 创建钱包 +// CreateWallet 创建钱包(已存在则幂等返回已有钱包,避免重复 INSERT 中止事务) 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("用户已存在钱包") + w, err := s.walletRepo.GetByUserID(ctx, userID) + if err == nil && w != nil { + return w, nil } wallet := entities.NewWallet(userID, decimal.NewFromFloat(s.cfg.Wallet.DefaultCreditLimit)) created, err := s.walletRepo.Create(ctx, *wallet) if err != nil { + // 并发下可能已创建成功,再查一次 + if existing, getErr := s.walletRepo.GetByUserID(ctx, userID); getErr == nil && existing != nil { + return existing, nil + } s.logger.Error("创建钱包失败", zap.Error(err)) return nil, err }