295 lines
8.5 KiB
Go
295 lines
8.5 KiB
Go
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
|
|
} |