| 
									
										
										
										
											2025-07-21 15:13:26 +08:00
										 |  |  |  | package esign | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"context" | 
					
						
							|  |  |  |  | 	"fmt" | 
					
						
							|  |  |  |  | 	"time" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	"go.uber.org/zap" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-28 01:46:39 +08:00
										 |  |  |  | 	"tyapi-server/internal/domains/certification/entities/value_objects" | 
					
						
							| 
									
										
										
										
											2025-07-21 15:13:26 +08:00
										 |  |  |  | 	"tyapi-server/internal/domains/certification/enums" | 
					
						
							|  |  |  |  | 	"tyapi-server/internal/domains/certification/repositories" | 
					
						
							|  |  |  |  | 	"tyapi-server/internal/shared/esign" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ================ 常量定义 ================ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const ( | 
					
						
							|  |  |  |  | 	// 企业认证超时时间 | 
					
						
							|  |  |  |  | 	EnterpriseAuthTimeout = 30 * time.Minute | 
					
						
							|  |  |  |  | 	 | 
					
						
							|  |  |  |  | 	// 合同签署超时时间 | 
					
						
							|  |  |  |  | 	ContractSignTimeout = 7 * 24 * time.Hour // 7天 | 
					
						
							|  |  |  |  | 	 | 
					
						
							|  |  |  |  | 	// 回调重试次数 | 
					
						
							|  |  |  |  | 	MaxCallbackRetries = 3 | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ================ 服务实现 ================ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // CertificationEsignService 认证e签宝服务实现 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 业务职责: | 
					
						
							|  |  |  |  | // - 处理企业认证流程 | 
					
						
							|  |  |  |  | // - 处理合同生成和签署 | 
					
						
							|  |  |  |  | // - 处理e签宝回调 | 
					
						
							|  |  |  |  | // - 管理认证状态更新 | 
					
						
							|  |  |  |  | type CertificationEsignService struct { | 
					
						
							|  |  |  |  | 	esignClient   *esign.Client | 
					
						
							|  |  |  |  | 	commandRepo   repositories.CertificationCommandRepository | 
					
						
							|  |  |  |  | 	queryRepo     repositories.CertificationQueryRepository | 
					
						
							|  |  |  |  | 	logger        *zap.Logger | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // NewCertificationEsignService 创建认证e签宝服务 | 
					
						
							|  |  |  |  | func NewCertificationEsignService( | 
					
						
							|  |  |  |  | 	esignClient *esign.Client, | 
					
						
							|  |  |  |  | 	commandRepo repositories.CertificationCommandRepository, | 
					
						
							|  |  |  |  | 	queryRepo repositories.CertificationQueryRepository, | 
					
						
							|  |  |  |  | 	logger *zap.Logger, | 
					
						
							|  |  |  |  | ) *CertificationEsignService { | 
					
						
							|  |  |  |  | 	return &CertificationEsignService{ | 
					
						
							|  |  |  |  | 		esignClient: esignClient, | 
					
						
							|  |  |  |  | 		commandRepo: commandRepo, | 
					
						
							|  |  |  |  | 		queryRepo:   queryRepo, | 
					
						
							|  |  |  |  | 		logger:      logger, | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ================ 企业认证流程 ================ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // StartEnterpriseAuth 开始企业认证 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 业务流程: | 
					
						
							|  |  |  |  | //   1. 调用e签宝企业认证API | 
					
						
							|  |  |  |  | //   2. 更新认证记录的auth_flow_id | 
					
						
							|  |  |  |  | //   3. 更新状态为企业认证中 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 参数: | 
					
						
							|  |  |  |  | //   - ctx: 上下文 | 
					
						
							|  |  |  |  | //   - certificationID: 认证ID | 
					
						
							|  |  |  |  | //   - enterpriseInfo: 企业信息 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 返回: | 
					
						
							|  |  |  |  | //   - authURL: 认证URL | 
					
						
							|  |  |  |  | //   - error: 错误信息 | 
					
						
							|  |  |  |  | func (s *CertificationEsignService) StartEnterpriseAuth( | 
					
						
							|  |  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  |  | 	certificationID string, | 
					
						
							|  |  |  |  | 	enterpriseInfo *value_objects.EnterpriseInfo, | 
					
						
							|  |  |  |  | ) (string, error) { | 
					
						
							|  |  |  |  | 	s.logger.Info("开始企业认证", | 
					
						
							|  |  |  |  | 		zap.String("certification_id", certificationID), | 
					
						
							|  |  |  |  | 		zap.String("company_name", enterpriseInfo.CompanyName)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// TODO: 实现e签宝企业认证API调用 | 
					
						
							|  |  |  |  | 	// 暂时使用模拟响应 | 
					
						
							|  |  |  |  | 	authFlowID := fmt.Sprintf("auth_%s_%d", certificationID, time.Now().Unix()) | 
					
						
							|  |  |  |  | 	authURL := fmt.Sprintf("https://esign.example.com/auth/%s", authFlowID) | 
					
						
							|  |  |  |  | 	 | 
					
						
							|  |  |  |  | 	s.logger.Info("模拟调用e签宝企业认证API", | 
					
						
							|  |  |  |  | 		zap.String("auth_flow_id", authFlowID), | 
					
						
							|  |  |  |  | 		zap.String("auth_url", authURL)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 更新认证记录 | 
					
						
							|  |  |  |  | 	if err := s.commandRepo.UpdateAuthFlowID(ctx, certificationID, authFlowID); err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("更新认证流程ID失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		return "", fmt.Errorf("更新认证流程ID失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	s.logger.Info("企业认证启动成功", | 
					
						
							|  |  |  |  | 		zap.String("certification_id", certificationID), | 
					
						
							|  |  |  |  | 		zap.String("auth_flow_id", authFlowID)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return authURL, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // HandleEnterpriseAuthCallback 处理企业认证回调 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 业务流程: | 
					
						
							|  |  |  |  | //   1. 根据回调信息查找认证记录 | 
					
						
							|  |  |  |  | //   2. 根据回调状态更新认证状态 | 
					
						
							|  |  |  |  | //   3. 如果成功,继续合同生成流程 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 参数: | 
					
						
							|  |  |  |  | //   - ctx: 上下文 | 
					
						
							|  |  |  |  | //   - authFlowID: 认证流程ID | 
					
						
							|  |  |  |  | //   - success: 是否成功 | 
					
						
							|  |  |  |  | //   - message: 回调消息 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 返回: | 
					
						
							|  |  |  |  | //   - error: 错误信息 | 
					
						
							|  |  |  |  | func (s *CertificationEsignService) HandleEnterpriseAuthCallback( | 
					
						
							|  |  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  |  | 	authFlowID string, | 
					
						
							|  |  |  |  | 	success bool, | 
					
						
							|  |  |  |  | 	message string, | 
					
						
							|  |  |  |  | ) error { | 
					
						
							|  |  |  |  | 	s.logger.Info("处理企业认证回调", | 
					
						
							|  |  |  |  | 		zap.String("auth_flow_id", authFlowID), | 
					
						
							|  |  |  |  | 		zap.Bool("success", success)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 查找认证记录 | 
					
						
							|  |  |  |  | 	cert, err := s.queryRepo.FindByAuthFlowID(ctx, authFlowID) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("根据认证流程ID查找认证记录失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		return fmt.Errorf("查找认证记录失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if success { | 
					
						
							|  |  |  |  | 		// 企业认证成功,更新状态 | 
					
						
							|  |  |  |  | 		if err := s.commandRepo.UpdateStatus(ctx, cert.ID, enums.StatusEnterpriseVerified); err != nil { | 
					
						
							|  |  |  |  | 			s.logger.Error("更新认证状态失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 			return fmt.Errorf("更新认证状态失败: %w", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		s.logger.Info("企业认证成功", zap.String("certification_id", cert.ID)) | 
					
						
							|  |  |  |  | 	} else { | 
					
						
							|  |  |  |  | 		// 企业认证失败,更新状态 | 
					
						
							|  |  |  |  | 		if err := s.commandRepo.UpdateStatus(ctx, cert.ID, enums.StatusInfoRejected); err != nil { | 
					
						
							|  |  |  |  | 			s.logger.Error("更新认证状态失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 			return fmt.Errorf("更新认证状态失败: %w", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		s.logger.Info("企业认证失败", zap.String("certification_id", cert.ID), zap.String("reason", message)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ================ 合同管理流程 ================ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GenerateContract 生成认证合同 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 业务流程: | 
					
						
							|  |  |  |  | //   1. 调用e签宝合同生成API | 
					
						
							|  |  |  |  | //   2. 更新认证记录的合同信息 | 
					
						
							|  |  |  |  | //   3. 更新状态为合同已生成 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 参数: | 
					
						
							|  |  |  |  | //   - ctx: 上下文 | 
					
						
							|  |  |  |  | //   - certificationID: 认证ID | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 返回: | 
					
						
							|  |  |  |  | //   - contractSignURL: 合同签署URL | 
					
						
							|  |  |  |  | //   - error: 错误信息 | 
					
						
							|  |  |  |  | func (s *CertificationEsignService) GenerateContract( | 
					
						
							|  |  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  |  | 	certificationID string, | 
					
						
							|  |  |  |  | ) (string, error) { | 
					
						
							|  |  |  |  | 	s.logger.Info("生成认证合同", zap.String("certification_id", certificationID)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// TODO: 实现e签宝合同生成API调用 | 
					
						
							|  |  |  |  | 	// 暂时使用模拟响应 | 
					
						
							|  |  |  |  | 	contractFileID := fmt.Sprintf("contract_%s_%d", certificationID, time.Now().Unix()) | 
					
						
							|  |  |  |  | 	esignFlowID := fmt.Sprintf("flow_%s_%d", certificationID, time.Now().Unix()) | 
					
						
							|  |  |  |  | 	contractURL := fmt.Sprintf("https://esign.example.com/contract/%s", contractFileID) | 
					
						
							|  |  |  |  | 	contractSignURL := fmt.Sprintf("https://esign.example.com/sign/%s", esignFlowID) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	s.logger.Info("模拟调用e签宝合同生成API", | 
					
						
							|  |  |  |  | 		zap.String("contract_file_id", contractFileID), | 
					
						
							|  |  |  |  | 		zap.String("esign_flow_id", esignFlowID)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 更新认证记录 | 
					
						
							|  |  |  |  | 	if err := s.commandRepo.UpdateContractInfo( | 
					
						
							|  |  |  |  | 		ctx, | 
					
						
							|  |  |  |  | 		certificationID, | 
					
						
							|  |  |  |  | 		contractFileID, | 
					
						
							|  |  |  |  | 		esignFlowID, | 
					
						
							|  |  |  |  | 		contractURL, | 
					
						
							|  |  |  |  | 		contractSignURL, | 
					
						
							|  |  |  |  | 	); err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("更新合同信息失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		return "", fmt.Errorf("更新合同信息失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 更新状态 | 
					
						
							|  |  |  |  | 	if err := s.commandRepo.UpdateStatus(ctx, certificationID, enums.StatusContractApplied); err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("更新认证状态失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		return "", fmt.Errorf("更新认证状态失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	s.logger.Info("认证合同生成成功", | 
					
						
							|  |  |  |  | 		zap.String("certification_id", certificationID), | 
					
						
							|  |  |  |  | 		zap.String("contract_file_id", contractFileID)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return contractSignURL, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // HandleContractSignCallback 处理合同签署回调 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 业务流程: | 
					
						
							|  |  |  |  | //   1. 根据回调信息查找认证记录 | 
					
						
							|  |  |  |  | //   2. 根据回调状态更新认证状态 | 
					
						
							|  |  |  |  | //   3. 如果成功,认证流程完成 | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 参数: | 
					
						
							|  |  |  |  | //   - ctx: 上下文 | 
					
						
							|  |  |  |  | //   - esignFlowID: e签宝流程ID | 
					
						
							|  |  |  |  | //   - success: 是否成功 | 
					
						
							|  |  |  |  | //   - signedFileURL: 已签署文件URL | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 返回: | 
					
						
							|  |  |  |  | //   - error: 错误信息 | 
					
						
							|  |  |  |  | func (s *CertificationEsignService) HandleContractSignCallback( | 
					
						
							|  |  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  |  | 	esignFlowID string, | 
					
						
							|  |  |  |  | 	success bool, | 
					
						
							|  |  |  |  | 	signedFileURL string, | 
					
						
							|  |  |  |  | ) error { | 
					
						
							|  |  |  |  | 	s.logger.Info("处理合同签署回调", | 
					
						
							|  |  |  |  | 		zap.String("esign_flow_id", esignFlowID), | 
					
						
							|  |  |  |  | 		zap.Bool("success", success)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 查找认证记录 | 
					
						
							|  |  |  |  | 	cert, err := s.queryRepo.FindByEsignFlowID(ctx, esignFlowID) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("根据e签宝流程ID查找认证记录失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		return fmt.Errorf("查找认证记录失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if success { | 
					
						
							| 
									
										
										
										
											2025-07-28 01:46:39 +08:00
										 |  |  |  | 		// 合同签署成功,更新合同URL | 
					
						
							|  |  |  |  | 		if err := s.commandRepo.UpdateContractInfo(ctx, cert.ID, cert.ContractFileID, cert.EsignFlowID, signedFileURL, cert.ContractSignURL); err != nil { | 
					
						
							|  |  |  |  | 			s.logger.Error("更新合同URL失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 			return fmt.Errorf("更新合同URL失败: %w", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 更新状态到合同已签署 | 
					
						
							| 
									
										
										
										
											2025-07-21 15:13:26 +08:00
										 |  |  |  | 		if err := s.commandRepo.UpdateStatus(ctx, cert.ID, enums.StatusContractSigned); err != nil { | 
					
						
							|  |  |  |  | 			s.logger.Error("更新认证状态失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 			return fmt.Errorf("更新认证状态失败: %w", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-28 01:46:39 +08:00
										 |  |  |  | 		s.logger.Info("合同签署成功", zap.String("certification_id", cert.ID)) | 
					
						
							| 
									
										
										
										
											2025-07-21 15:13:26 +08:00
										 |  |  |  | 	} else { | 
					
						
							|  |  |  |  | 		// 合同签署失败 | 
					
						
							|  |  |  |  | 		if err := s.commandRepo.UpdateStatus(ctx, cert.ID, enums.StatusContractRejected); err != nil { | 
					
						
							|  |  |  |  | 			s.logger.Error("更新认证状态失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 			return fmt.Errorf("更新认证状态失败: %w", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		s.logger.Info("合同签署失败", zap.String("certification_id", cert.ID)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ================ 辅助方法 ================ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GetContractSignURL 获取合同签署URL | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 参数: | 
					
						
							|  |  |  |  | //   - ctx: 上下文 | 
					
						
							|  |  |  |  | //   - certificationID: 认证ID | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // 返回: | 
					
						
							|  |  |  |  | //   - signURL: 签署URL | 
					
						
							|  |  |  |  | //   - error: 错误信息 | 
					
						
							|  |  |  |  | func (s *CertificationEsignService) GetContractSignURL(ctx context.Context, certificationID string) (string, error) { | 
					
						
							|  |  |  |  | 	cert, err := s.queryRepo.GetByID(ctx, certificationID) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return "", fmt.Errorf("获取认证信息失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if cert.ContractSignURL == "" { | 
					
						
							|  |  |  |  | 		return "", fmt.Errorf("合同签署URL尚未生成") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return cert.ContractSignURL, nil | 
					
						
							|  |  |  |  | }  |