301 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			301 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package esign
 | ||
| 
 | ||
| import (
 | ||
| 	"context"
 | ||
| 	"fmt"
 | ||
| 	"time"
 | ||
| 
 | ||
| 	"go.uber.org/zap"
 | ||
| 
 | ||
| 	"tyapi-server/internal/domains/certification/entities/value_objects"
 | ||
| 	"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 {
 | ||
| 		// 合同签署成功,更新合同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)
 | ||
| 		}
 | ||
| 
 | ||
| 		// 更新状态到合同已签署
 | ||
| 		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
 | ||
| }  |