Files
tyapi-server/internal/infrastructure/external/esign/certification_esign_service.go

295 lines
8.5 KiB
Go
Raw Normal View History

2025-07-21 15:13:26 +08:00
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
}