Files
tyapi-server/internal/application/certification/certification_application_service_impl.go
2025-07-20 20:53:26 +08:00

456 lines
17 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package certification
import (
"context"
"errors"
"fmt"
"time"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/application/certification/dto/commands"
"tyapi-server/internal/application/certification/dto/queries"
"tyapi-server/internal/application/certification/dto/responses"
"tyapi-server/internal/domains/certification/entities"
"tyapi-server/internal/domains/certification/enums"
"tyapi-server/internal/domains/certification/services"
user_entities "tyapi-server/internal/domains/user/entities"
user_services "tyapi-server/internal/domains/user/services"
"tyapi-server/internal/shared/database"
esign_service "tyapi-server/internal/shared/esign"
)
// CertificationApplicationServiceImpl 认证应用服务实现
// 负责业务流程编排、事务管理、数据转换,不直接操作仓库
type CertificationApplicationServiceImpl struct {
certManagementService *services.CertificationManagementService
certWorkflowService *services.CertificationWorkflowService
certificationEsignService *services.CertificationEsignService
enterpriseService *user_services.EnterpriseService
esignService *esign_service.Client
enterpriseRecordService *services.EnterpriseInfoSubmitRecordService
smsCodeService *user_services.SMSCodeService
txManager *database.TransactionManager
logger *zap.Logger
}
// NewCertificationApplicationService 创建认证应用服务
func NewCertificationApplicationService(
certManagementService *services.CertificationManagementService,
certWorkflowService *services.CertificationWorkflowService,
certificationEsignService *services.CertificationEsignService,
enterpriseService *user_services.EnterpriseService,
esignService *esign_service.Client,
enterpriseRecordService *services.EnterpriseInfoSubmitRecordService,
smsCodeService *user_services.SMSCodeService,
txManager *database.TransactionManager,
logger *zap.Logger,
) CertificationApplicationService {
return &CertificationApplicationServiceImpl{
certManagementService: certManagementService,
certWorkflowService: certWorkflowService,
certificationEsignService: certificationEsignService,
enterpriseService: enterpriseService,
esignService: esignService,
enterpriseRecordService: enterpriseRecordService,
smsCodeService: smsCodeService,
txManager: txManager,
logger: logger,
}
}
// SubmitEnterpriseInfo 提交企业信息
// 业务流程1. 验证企业信息 2. 创建或获取认证申请 3. 使用事务执行状态转换和创建记录
func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo(ctx context.Context, cmd *commands.SubmitEnterpriseInfoCommand) (*responses.CertificationResponse, error) {
// 1. 验证短信验证码
if err := s.smsCodeService.VerifyCode(ctx, cmd.LegalPersonPhone, cmd.VerificationCode, user_entities.SMSSceneCertification); err != nil {
return nil, fmt.Errorf("验证码错误或已过期")
}
// 2. 验证企业信息(检查统一社会信用代码是否已存在)
exists, err := s.enterpriseService.CheckUnifiedSocialCodeExists(ctx, cmd.UnifiedSocialCode, "")
if err != nil {
return nil, fmt.Errorf("检查企业信息失败: %w", err)
}
if exists {
return nil, fmt.Errorf("统一社会信用代码已存在")
}
// 3. 获取或创建认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, cmd.UserID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
certification, err = s.certManagementService.CreateCertification(ctx, cmd.UserID)
if err != nil {
return nil, fmt.Errorf("创建认证申请失败: %w", err)
}
} else {
return nil, fmt.Errorf("获取认证申请失败: %w", err)
}
}
// 4. 创建记录
if certification.Status != enums.StatusPending && certification.Status != enums.StatusInfoSubmitted {
return nil, fmt.Errorf("当前状态不允许提交企业信息")
}
_, err = s.enterpriseRecordService.CreateEnterpriseInfoSubmitRecord(ctx, cmd.UserID, cmd.CompanyName, cmd.UnifiedSocialCode, cmd.LegalPersonName, cmd.LegalPersonID, cmd.LegalPersonPhone)
if err != nil {
return nil, fmt.Errorf("企业信息提交失败: %w", err)
}
s.logger.Info("企业信息提交成功",
zap.String("user_id", cmd.UserID),
zap.String("certification_id", certification.ID),
zap.String("company_name", cmd.CompanyName),
)
// 转换状态
err = s.certWorkflowService.SubmitEnterpriseInfo(ctx, certification.ID)
if err != nil {
return nil, fmt.Errorf("转换状态失败: %w", err)
}
// 5. 检查企业是否已经认证
hasCertification, err := s.certManagementService.CheckCertification(ctx, cmd.CompanyName, cmd.UnifiedSocialCode)
if err != nil {
return nil, fmt.Errorf("检查企业认证状态失败: %w", err)
}
if hasCertification {
// 如果企业已经认证,则直接完成认证
err = s.completeEnterpriseAuth(ctx, certification)
if err != nil {
return nil, fmt.Errorf("完成企业认证失败: %w", err)
}
}
// 6. 重新获取认证申请数据
certification, err = s.certManagementService.GetCertificationByID(ctx, certification.ID)
if err != nil {
return nil, fmt.Errorf("获取认证申请失败: %w", err)
}
return s.buildCertificationResponse(certification), nil
}
// GetEnterpriseAuthURL 获取企业认证链接
// 业务流程1. 获取认证申请 2. 获取企业信息提交记录 3. 生成e签宝认证文件 4. 返回认证链接
func (s *CertificationApplicationServiceImpl) GetEnterpriseAuthURL(ctx context.Context, userID string) (*responses.EnterpriseAuthURLResponse, error) {
// 1. 获取认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, userID)
if err != nil {
return nil, fmt.Errorf("用户尚未创建认证申请: %w", err)
}
// 2. 检查认证状态
if certification.Status != enums.StatusInfoSubmitted {
return nil, fmt.Errorf("当前状态不允许进行企业认证")
}
// 3. 获取企业信息提交记录
enterpriseRecord, err := s.enterpriseRecordService.GetLatestByUserID(ctx, userID)
if err != nil {
return nil, fmt.Errorf("获取企业信息失败: %w", err)
}
// 4. 生成e签宝认证文件
authReq := &esign_service.EnterpriseAuthRequest{
CompanyName: enterpriseRecord.CompanyName,
UnifiedSocialCode: enterpriseRecord.UnifiedSocialCode,
LegalPersonName: enterpriseRecord.LegalPersonName,
LegalPersonID: enterpriseRecord.LegalPersonID,
TransactorName: enterpriseRecord.LegalPersonName,
TransactorMobile: enterpriseRecord.LegalPersonPhone,
TransactorID: enterpriseRecord.LegalPersonID,
}
authResp, err := s.esignService.GenerateEnterpriseAuth(authReq)
if err != nil {
s.logger.Error("生成企业认证文件失败",
zap.String("user_id", userID),
zap.String("certification_id", certification.ID),
zap.Error(err),
)
return nil, fmt.Errorf("生成企业认证文件失败: %w", err)
}
s.logger.Info("获取企业认证链接成功",
zap.String("user_id", userID),
zap.String("certification_id", certification.ID),
zap.String("esign_flow_id", authResp.AuthFlowID),
)
return &responses.EnterpriseAuthURLResponse{
AuthURL: authResp.AuthURL,
ShortURL: authResp.AuthShortURL,
ExpireAt: time.Now().AddDate(0, 0, 7).Format(time.RFC3339),
}, nil
}
// ApplyContract 申请合同文件
// 业务流程1. 获取认证申请 2. 获取企业信息 3. 生成e签宝合同文件
func (s *CertificationApplicationServiceImpl) ApplyContract(ctx context.Context, userID string) (*responses.CertificationResponse, error) {
// 1. 获取认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, userID)
if err != nil {
return nil, fmt.Errorf("用户尚未创建认证申请: %w", err)
}
// 2. 获取企业信息
enterpriseInfo, err := s.enterpriseService.GetEnterpriseInfo(ctx, userID)
if err != nil {
return nil, fmt.Errorf("获取企业信息失败: %w", err)
}
// 4. 生成e签宝合同
components := map[string]string{
"JFQY": "海南学宇思网络科技有限公司",
"JFFR": "刘福思",
"YFQY": enterpriseInfo.CompanyName,
"YFFR": enterpriseInfo.LegalPersonName,
"QDRQ": time.Now().Format("2006-01-02"),
}
_, err = s.certificationEsignService.FillTemplate(ctx, certification, components)
if err != nil {
return nil, fmt.Errorf("生成e签宝合同失败: %w", err)
}
// 6. 重新获取更新后的认证申请数据
updatedCertification, err := s.certManagementService.GetCertificationByID(ctx, certification.ID)
if err != nil {
return nil, err
}
return s.buildCertificationResponse(updatedCertification), nil
}
// GetContractSignURL 获取合同签署链接
// 业务流程1. 获取认证申请 2. 获取企业信息 3. 获取签署链接
func (s *CertificationApplicationServiceImpl) GetContractSignURL(ctx context.Context, cmd *commands.GetContractSignURLCommand) (*responses.ContractSignURLResponse, error) {
// 1. 获取认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, cmd.UserID)
if err != nil {
return nil, fmt.Errorf("用户尚未创建认证申请: %w", err)
}
// 2. 检查认证状态
if certification.Status != enums.StatusContractApplied {
return nil, fmt.Errorf("当前状态不允许获取签署链接")
}
// 3. 获取企业信息
enterpriseInfo, err := s.enterpriseService.GetEnterpriseInfo(ctx, cmd.UserID)
if err != nil {
return nil, fmt.Errorf("获取企业信息失败: %w", err)
}
if certification.ContractFileID == "" {
return nil, fmt.Errorf("请先申请合同文件")
}
// 5. 发起签署
signRecord, err := s.certificationEsignService.InitiateSign(ctx, certification, enterpriseInfo)
if err != nil {
return nil, fmt.Errorf("获取签署链接失败: %w", err)
}
// 转换状态
err = s.certWorkflowService.ApplyContract(ctx, certification.ID)
if err != nil {
return nil, fmt.Errorf("转换状态失败: %w", err)
}
// 6. 计算过期时间7天后
expireAt := time.Now().AddDate(0, 0, 7).Format(time.RFC3339)
s.logger.Info("获取签署链接成功",
zap.String("user_id", cmd.UserID),
zap.String("certification_id", certification.ID),
zap.String("sign_flow_id", signRecord.EsignFlowID),
)
return &responses.ContractSignURLResponse{
SignURL: signRecord.SignURL,
ShortURL: signRecord.SignShortURL,
SignFlowID: signRecord.EsignFlowID,
ExpireAt: expireAt,
}, nil
}
// CompleteContractSign 完成合同签署
// 业务流程1. 获取认证申请 2. 完成合同签署 3. 自动完成认证
func (s *CertificationApplicationServiceImpl) CompleteContractSign(ctx context.Context, cmd *commands.CompleteContractSignCommand) error {
// 1. 获取认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, cmd.UserID)
if err != nil {
return fmt.Errorf("用户尚未创建认证申请: %w", err)
}
if certification.Status != enums.StatusContractApplied {
return fmt.Errorf("当前状态不允许完成合同签署")
}
// 2. 完成合同签署(状态转换)
if err := s.certWorkflowService.CompleteContractSign(ctx, certification.ID, cmd.ContractURL); err != nil {
return err
}
// 3. 重新获取认证申请
updatedCertification, err := s.certManagementService.GetCertificationByID(ctx, certification.ID)
if err != nil {
return err
}
// 4. 如果合同已签署,自动完成认证
if updatedCertification.Status == enums.StatusContractSigned {
if err := s.certWorkflowService.CompleteCertification(ctx, certification.ID); err != nil {
return err
}
}
s.logger.Info("合同签署完成",
zap.String("user_id", cmd.UserID),
zap.String("certification_id", certification.ID),
zap.String("contract_url", cmd.ContractURL),
)
return nil
}
// GetCertificationStatus 获取认证状态
// 业务流程1. 获取认证申请 2. 构建响应数据
func (s *CertificationApplicationServiceImpl) GetCertificationStatus(ctx context.Context, query *queries.GetCertificationStatusQuery) (*responses.CertificationResponse, error) {
// 1. 获取认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, query.UserID)
if err != nil {
// 如果用户没有认证申请,返回一个表示未开始的状态
if errors.Is(err, gorm.ErrRecordNotFound) {
return &responses.CertificationResponse{
ID: "",
UserID: query.UserID,
Status: "not_started",
StatusName: "未开始认证",
Progress: 0,
IsUserActionRequired: true,
InfoSubmittedAt: nil,
EnterpriseVerifiedAt: nil,
ContractAppliedAt: nil,
ContractSignedAt: nil,
CompletedAt: nil,
ContractURL: "",
CreatedAt: time.Time{},
UpdatedAt: time.Time{},
}, nil
}
return nil, err
}
// 2. 构建响应
return s.buildCertificationResponse(certification), nil
}
// GetCertificationDetails 获取认证详情
// 业务流程1. 获取认证申请 2. 获取企业信息 3. 构建响应数据
func (s *CertificationApplicationServiceImpl) GetCertificationDetails(ctx context.Context, query *queries.GetCertificationDetailsQuery) (*responses.CertificationResponse, error) {
// 1. 获取认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, query.UserID)
if err != nil {
// 如果用户没有认证申请,返回错误
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("用户尚未创建认证申请")
}
return nil, err
}
// 2. 构建响应
response := s.buildCertificationResponse(certification)
// 3. 添加企业信息
if certification.UserID != "" {
enterpriseInfo, err := s.enterpriseService.GetEnterpriseInfo(ctx, certification.UserID)
if err == nil && enterpriseInfo != nil {
response.Enterprise = s.buildEnterpriseInfoResponse(enterpriseInfo)
}
}
return response, nil
}
// GetCertificationProgress 获取认证进度
// 业务流程1. 获取认证申请 2. 获取进度信息
func (s *CertificationApplicationServiceImpl) GetCertificationProgress(ctx context.Context, userID string) (map[string]interface{}, error) {
// 1. 获取认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, userID)
if err != nil {
// 如果用户没有认证申请,返回未开始状态
if errors.Is(err, gorm.ErrRecordNotFound) {
return map[string]interface{}{
"certification_id": "",
"user_id": userID,
"current_status": "not_started",
"status_name": "未开始认证",
"progress_percentage": 0,
"is_user_action_required": true,
"next_valid_statuses": []string{"pending"},
"message": "用户尚未开始认证流程",
"created_at": nil,
"updated_at": nil,
}, nil
}
return nil, err
}
// 2. 获取认证进度
return s.certManagementService.GetCertificationProgress(ctx, certification.ID)
}
// buildCertificationResponse 构建认证响应
func (s *CertificationApplicationServiceImpl) buildCertificationResponse(certification *entities.Certification) *responses.CertificationResponse {
return &responses.CertificationResponse{
ID: certification.ID,
UserID: certification.UserID,
Status: certification.Status,
StatusName: certification.GetStatusName(),
Progress: certification.GetProgressPercentage(),
IsUserActionRequired: certification.IsUserActionRequired(),
InfoSubmittedAt: certification.InfoSubmittedAt,
EnterpriseVerifiedAt: certification.EnterpriseVerifiedAt,
ContractAppliedAt: certification.ContractAppliedAt,
ContractSignedAt: certification.ContractSignedAt,
CompletedAt: certification.CompletedAt,
ContractURL: certification.ContractURL,
CreatedAt: certification.CreatedAt,
UpdatedAt: certification.UpdatedAt,
}
}
// buildEnterpriseInfoResponse 构建企业信息响应
func (s *CertificationApplicationServiceImpl) buildEnterpriseInfoResponse(enterpriseInfo *user_entities.EnterpriseInfo) *responses.EnterpriseInfoResponse {
return &responses.EnterpriseInfoResponse{
ID: enterpriseInfo.ID,
CompanyName: enterpriseInfo.CompanyName,
UnifiedSocialCode: enterpriseInfo.UnifiedSocialCode,
LegalPersonName: enterpriseInfo.LegalPersonName,
LegalPersonID: enterpriseInfo.LegalPersonID,
CreatedAt: enterpriseInfo.CreatedAt,
UpdatedAt: enterpriseInfo.UpdatedAt,
}
}
// 企业认证成功后操作
func (s *CertificationApplicationServiceImpl) completeEnterpriseAuth(ctx context.Context, certification *entities.Certification) error {
err := s.txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
// 1. 获取企业信息提交记录
enterpriseRecord, err := s.enterpriseRecordService.GetLatestByUserID(txCtx, certification.UserID)
if err != nil {
return fmt.Errorf("获取企业信息失败: %w", err)
}
// 2. 转换状态
if err := s.certWorkflowService.CompleteEnterpriseVerification(txCtx, certification.ID); err != nil {
return err
}
// 3. 创建企业信息
_, err = s.enterpriseService.CreateEnterpriseInfo(txCtx, certification.UserID, enterpriseRecord.CompanyName, enterpriseRecord.UnifiedSocialCode, enterpriseRecord.LegalPersonName, enterpriseRecord.LegalPersonID)
if err != nil {
s.logger.Warn("创建用户企业信息失败", zap.Error(err))
return err
}
return nil
})
if err != nil {
return fmt.Errorf("完成企业认证失败: %w", err)
}
return nil
}