package esign import ( "context" "fmt" "time" "go.uber.org/zap" "tyapi-server/internal/domains/certification/enums" "tyapi-server/internal/domains/certification/repositories" "tyapi-server/internal/domains/certification/value_objects" "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 { // 合同签署成功,认证完成 if err := s.commandRepo.UpdateStatus(ctx, cert.ID, enums.StatusContractSigned); 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.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 }