609 lines
23 KiB
Go
609 lines
23 KiB
Go
|
|
package certification
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"fmt"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"go.uber.org/zap"
|
|||
|
|
|
|||
|
|
"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/repositories"
|
|||
|
|
"tyapi-server/internal/domains/certification/services"
|
|||
|
|
user_entities "tyapi-server/internal/domains/user/entities"
|
|||
|
|
user_repositories "tyapi-server/internal/domains/user/repositories"
|
|||
|
|
"tyapi-server/internal/shared/ocr"
|
|||
|
|
"tyapi-server/internal/shared/storage"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// CertificationApplicationServiceImpl 认证应用服务实现
|
|||
|
|
type CertificationApplicationServiceImpl struct {
|
|||
|
|
certRepo repositories.CertificationRepository
|
|||
|
|
licenseRepo repositories.LicenseUploadRecordRepository
|
|||
|
|
faceVerifyRepo repositories.FaceVerifyRecordRepository
|
|||
|
|
contractRepo repositories.ContractRecordRepository
|
|||
|
|
certService *services.CertificationService
|
|||
|
|
stateMachine *services.CertificationStateMachine
|
|||
|
|
storageService storage.StorageService
|
|||
|
|
ocrService ocr.OCRService
|
|||
|
|
enterpriseInfoRepo user_repositories.EnterpriseInfoRepository
|
|||
|
|
logger *zap.Logger
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewCertificationApplicationService 创建认证应用服务
|
|||
|
|
func NewCertificationApplicationService(
|
|||
|
|
certRepo repositories.CertificationRepository,
|
|||
|
|
licenseRepo repositories.LicenseUploadRecordRepository,
|
|||
|
|
faceVerifyRepo repositories.FaceVerifyRecordRepository,
|
|||
|
|
contractRepo repositories.ContractRecordRepository,
|
|||
|
|
certService *services.CertificationService,
|
|||
|
|
stateMachine *services.CertificationStateMachine,
|
|||
|
|
storageService storage.StorageService,
|
|||
|
|
ocrService ocr.OCRService,
|
|||
|
|
enterpriseInfoRepo user_repositories.EnterpriseInfoRepository,
|
|||
|
|
logger *zap.Logger,
|
|||
|
|
) CertificationApplicationService {
|
|||
|
|
return &CertificationApplicationServiceImpl{
|
|||
|
|
certRepo: certRepo,
|
|||
|
|
licenseRepo: licenseRepo,
|
|||
|
|
faceVerifyRepo: faceVerifyRepo,
|
|||
|
|
contractRepo: contractRepo,
|
|||
|
|
certService: certService,
|
|||
|
|
stateMachine: stateMachine,
|
|||
|
|
storageService: storageService,
|
|||
|
|
ocrService: ocrService,
|
|||
|
|
enterpriseInfoRepo: enterpriseInfoRepo,
|
|||
|
|
logger: logger,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CreateCertification 创建认证申请
|
|||
|
|
func (s *CertificationApplicationServiceImpl) CreateCertification(ctx context.Context, cmd *commands.CreateCertificationCommand) (*responses.CertificationResponse, error) {
|
|||
|
|
// 使用领域服务创建认证申请
|
|||
|
|
certification, err := s.certService.CreateCertification(ctx, cmd.UserID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建响应
|
|||
|
|
response := &responses.CertificationResponse{
|
|||
|
|
ID: certification.ID,
|
|||
|
|
UserID: certification.UserID,
|
|||
|
|
Status: certification.Status,
|
|||
|
|
StatusName: string(certification.Status),
|
|||
|
|
Progress: certification.GetProgressPercentage(),
|
|||
|
|
IsUserActionRequired: certification.IsUserActionRequired(),
|
|||
|
|
IsAdminActionRequired: certification.IsAdminActionRequired(),
|
|||
|
|
InfoSubmittedAt: certification.InfoSubmittedAt,
|
|||
|
|
FaceVerifiedAt: certification.FaceVerifiedAt,
|
|||
|
|
ContractAppliedAt: certification.ContractAppliedAt,
|
|||
|
|
ContractApprovedAt: certification.ContractApprovedAt,
|
|||
|
|
ContractSignedAt: certification.ContractSignedAt,
|
|||
|
|
CompletedAt: certification.CompletedAt,
|
|||
|
|
ContractURL: certification.ContractURL,
|
|||
|
|
SigningURL: certification.SigningURL,
|
|||
|
|
RejectReason: certification.RejectReason,
|
|||
|
|
CreatedAt: certification.CreatedAt,
|
|||
|
|
UpdatedAt: certification.UpdatedAt,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
s.logger.Info("认证申请创建成功",
|
|||
|
|
zap.String("certification_id", certification.ID),
|
|||
|
|
zap.String("user_id", cmd.UserID),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
return response, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CreateEnterpriseInfo 创建企业信息
|
|||
|
|
func (s *CertificationApplicationServiceImpl) CreateEnterpriseInfo(ctx context.Context, cmd *commands.CreateEnterpriseInfoCommand) (*responses.EnterpriseInfoResponse, error) {
|
|||
|
|
// 检查用户是否已有企业信息
|
|||
|
|
existingInfo, err := s.enterpriseInfoRepo.GetByUserID(ctx, cmd.UserID)
|
|||
|
|
if err == nil && existingInfo != nil {
|
|||
|
|
return nil, fmt.Errorf("用户已有企业信息")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查统一社会信用代码是否已存在
|
|||
|
|
exists, err := s.enterpriseInfoRepo.CheckUnifiedSocialCodeExists(ctx, cmd.UnifiedSocialCode, "")
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("检查企业信息失败: %w", err)
|
|||
|
|
}
|
|||
|
|
if exists {
|
|||
|
|
return nil, fmt.Errorf("统一社会信用代码已存在")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建企业信息
|
|||
|
|
enterpriseInfo := &user_entities.EnterpriseInfo{
|
|||
|
|
UserID: cmd.UserID,
|
|||
|
|
CompanyName: cmd.CompanyName,
|
|||
|
|
UnifiedSocialCode: cmd.UnifiedSocialCode,
|
|||
|
|
LegalPersonName: cmd.LegalPersonName,
|
|||
|
|
LegalPersonID: cmd.LegalPersonID,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
createdEnterpriseInfo, err := s.enterpriseInfoRepo.Create(ctx, *enterpriseInfo)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("创建企业信息失败", zap.Error(err))
|
|||
|
|
return nil, fmt.Errorf("创建企业信息失败: %w", err)
|
|||
|
|
}
|
|||
|
|
s.logger.Info("企业信息创建成功",
|
|||
|
|
zap.String("user_id", cmd.UserID),
|
|||
|
|
zap.String("enterprise_id", enterpriseInfo.ID),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
return &responses.EnterpriseInfoResponse{
|
|||
|
|
ID: createdEnterpriseInfo.ID,
|
|||
|
|
CompanyName: enterpriseInfo.CompanyName,
|
|||
|
|
UnifiedSocialCode: enterpriseInfo.UnifiedSocialCode,
|
|||
|
|
LegalPersonName: enterpriseInfo.LegalPersonName,
|
|||
|
|
LegalPersonID: enterpriseInfo.LegalPersonID,
|
|||
|
|
IsOCRVerified: enterpriseInfo.IsOCRVerified,
|
|||
|
|
IsFaceVerified: enterpriseInfo.IsFaceVerified,
|
|||
|
|
CreatedAt: enterpriseInfo.CreatedAt,
|
|||
|
|
UpdatedAt: enterpriseInfo.UpdatedAt,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UploadLicense 上传营业执照
|
|||
|
|
func (s *CertificationApplicationServiceImpl) UploadLicense(ctx context.Context, cmd *commands.UploadLicenseCommand) (*responses.UploadLicenseResponse, error) {
|
|||
|
|
// 1. 业务规则验证 - 调用领域服务
|
|||
|
|
if err := s.certService.ValidateLicenseUpload(ctx, cmd.UserID, cmd.FileName, cmd.FileSize); err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 上传文件到存储服务
|
|||
|
|
uploadResult, err := s.storageService.UploadFile(ctx, cmd.FileBytes, cmd.FileName)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("上传营业执照失败", zap.Error(err))
|
|||
|
|
return nil, fmt.Errorf("上传营业执照失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 创建营业执照上传记录 - 调用领域服务
|
|||
|
|
licenseRecord, err := s.certService.CreateLicenseUploadRecord(ctx, cmd.UserID, cmd.FileName, cmd.FileSize, uploadResult)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("创建营业执照记录失败", zap.Error(err))
|
|||
|
|
return nil, fmt.Errorf("创建营业执照记录失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 4. 异步处理OCR识别 - 使用任务队列或后台任务
|
|||
|
|
go s.processOCRAsync(ctx, licenseRecord.ID, cmd.FileBytes)
|
|||
|
|
|
|||
|
|
s.logger.Info("营业执照上传成功",
|
|||
|
|
zap.String("user_id", cmd.UserID),
|
|||
|
|
zap.String("license_id", licenseRecord.ID),
|
|||
|
|
zap.String("file_url", uploadResult.URL),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 5. 构建响应
|
|||
|
|
response := &responses.UploadLicenseResponse{
|
|||
|
|
UploadRecordID: licenseRecord.ID,
|
|||
|
|
FileURL: uploadResult.URL,
|
|||
|
|
OCRProcessed: false,
|
|||
|
|
OCRSuccess: false,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 6. 如果OCR处理很快完成,尝试获取结果
|
|||
|
|
// 这里可以添加一个简单的轮询机制,或者使用WebSocket推送结果
|
|||
|
|
// 暂时返回基础信息,前端可以通过查询接口获取OCR结果
|
|||
|
|
|
|||
|
|
return response, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UploadBusinessLicense 上传营业执照并同步OCR识别
|
|||
|
|
func (s *CertificationApplicationServiceImpl) UploadBusinessLicense(ctx context.Context, userID string, fileBytes []byte, fileName string) (*responses.UploadLicenseResponse, error) {
|
|||
|
|
s.logger.Info("开始处理营业执照上传",
|
|||
|
|
zap.String("user_id", userID),
|
|||
|
|
zap.String("file_name", fileName),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 调用领域服务进行上传和OCR识别
|
|||
|
|
uploadRecord, ocrResult, err := s.certService.UploadBusinessLicense(ctx, userID, fileBytes, fileName)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("营业执照上传失败", zap.Error(err))
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建响应
|
|||
|
|
response := &responses.UploadLicenseResponse{
|
|||
|
|
UploadRecordID: uploadRecord.ID,
|
|||
|
|
FileURL: uploadRecord.FileURL,
|
|||
|
|
OCRProcessed: uploadRecord.OCRProcessed,
|
|||
|
|
OCRSuccess: uploadRecord.OCRSuccess,
|
|||
|
|
OCRConfidence: uploadRecord.OCRConfidence,
|
|||
|
|
OCRErrorMessage: uploadRecord.OCRErrorMessage,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果OCR成功,添加识别结果
|
|||
|
|
if ocrResult != nil && uploadRecord.OCRSuccess {
|
|||
|
|
response.EnterpriseName = ocrResult.CompanyName
|
|||
|
|
response.CreditCode = ocrResult.UnifiedSocialCode
|
|||
|
|
response.LegalPerson = ocrResult.LegalPersonName
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
s.logger.Info("营业执照上传完成",
|
|||
|
|
zap.String("user_id", userID),
|
|||
|
|
zap.String("upload_record_id", uploadRecord.ID),
|
|||
|
|
zap.Bool("ocr_success", uploadRecord.OCRSuccess),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
return response, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SubmitEnterpriseInfo 提交企业信息
|
|||
|
|
func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo(ctx context.Context, cmd *commands.SubmitEnterpriseInfoCommand) (*responses.EnterpriseInfoResponse, error) {
|
|||
|
|
// 根据用户ID获取认证申请
|
|||
|
|
certification, err := s.certRepo.GetByUserID(ctx, cmd.UserID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("用户尚未创建认证申请: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置认证ID
|
|||
|
|
cmd.CertificationID = certification.ID
|
|||
|
|
|
|||
|
|
// 调用领域服务提交企业信息
|
|||
|
|
if err := s.certService.SubmitEnterpriseInfo(ctx, certification.ID); err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建企业信息
|
|||
|
|
enterpriseInfo := &user_entities.EnterpriseInfo{
|
|||
|
|
UserID: cmd.UserID,
|
|||
|
|
CompanyName: cmd.CompanyName,
|
|||
|
|
UnifiedSocialCode: cmd.UnifiedSocialCode,
|
|||
|
|
LegalPersonName: cmd.LegalPersonName,
|
|||
|
|
LegalPersonID: cmd.LegalPersonID,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
*enterpriseInfo, err = s.enterpriseInfoRepo.Create(ctx, *enterpriseInfo)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("创建企业信息失败", zap.Error(err))
|
|||
|
|
return nil, fmt.Errorf("创建企业信息失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
s.logger.Info("企业信息提交成功",
|
|||
|
|
zap.String("user_id", cmd.UserID),
|
|||
|
|
zap.String("certification_id", certification.ID),
|
|||
|
|
zap.String("enterprise_id", enterpriseInfo.ID),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
return &responses.EnterpriseInfoResponse{
|
|||
|
|
ID: enterpriseInfo.ID,
|
|||
|
|
CompanyName: enterpriseInfo.CompanyName,
|
|||
|
|
UnifiedSocialCode: enterpriseInfo.UnifiedSocialCode,
|
|||
|
|
LegalPersonName: enterpriseInfo.LegalPersonName,
|
|||
|
|
LegalPersonID: enterpriseInfo.LegalPersonID,
|
|||
|
|
IsOCRVerified: enterpriseInfo.IsOCRVerified,
|
|||
|
|
IsFaceVerified: enterpriseInfo.IsFaceVerified,
|
|||
|
|
CreatedAt: enterpriseInfo.CreatedAt,
|
|||
|
|
UpdatedAt: enterpriseInfo.UpdatedAt,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// InitiateFaceVerify 发起人脸识别验证
|
|||
|
|
func (s *CertificationApplicationServiceImpl) InitiateFaceVerify(ctx context.Context, cmd *commands.InitiateFaceVerifyCommand) (*responses.FaceVerifyResponse, error) {
|
|||
|
|
// 根据用户ID获取认证申请 - 这里需要从Handler传入用户ID
|
|||
|
|
// 由于cmd中没有UserID字段,我们需要修改Handler的调用方式
|
|||
|
|
// 暂时使用certificationID来获取认证申请
|
|||
|
|
certification, err := s.certRepo.GetByID(ctx, cmd.CertificationID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("认证申请不存在: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用领域服务发起人脸识别
|
|||
|
|
faceVerifyRecord, err := s.certService.InitiateFaceVerify(ctx, certification.ID, cmd.RealName, cmd.IDCardNumber)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建验证URL(这里应该根据实际的人脸识别服务生成)
|
|||
|
|
verifyURL := fmt.Sprintf("/api/certification/face-verify/%s?return_url=%s", faceVerifyRecord.ID, cmd.ReturnURL)
|
|||
|
|
|
|||
|
|
s.logger.Info("人脸识别验证发起成功",
|
|||
|
|
zap.String("certification_id", certification.ID),
|
|||
|
|
zap.String("face_verify_id", faceVerifyRecord.ID),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
return &responses.FaceVerifyResponse{
|
|||
|
|
CertifyID: faceVerifyRecord.ID,
|
|||
|
|
VerifyURL: verifyURL,
|
|||
|
|
ExpiresAt: faceVerifyRecord.ExpiresAt,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ApplyContract 申请合同
|
|||
|
|
func (s *CertificationApplicationServiceImpl) ApplyContract(ctx context.Context, userID string) (*responses.CertificationResponse, error) {
|
|||
|
|
// 根据用户ID获取认证申请
|
|||
|
|
certification, err := s.certRepo.GetByUserID(ctx, userID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("用户尚未创建认证申请: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用领域服务申请合同
|
|||
|
|
if err := s.certService.ApplyContract(ctx, certification.ID); err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重新获取更新后的认证申请
|
|||
|
|
updatedCertification, err := s.certRepo.GetByID(ctx, certification.ID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
s.logger.Info("合同申请成功",
|
|||
|
|
zap.String("user_id", userID),
|
|||
|
|
zap.String("certification_id", certification.ID),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
return s.buildCertificationResponse(&updatedCertification), nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetCertificationStatus 获取认证状态
|
|||
|
|
func (s *CertificationApplicationServiceImpl) GetCertificationStatus(ctx context.Context, query *queries.GetCertificationStatusQuery) (*responses.CertificationResponse, error) {
|
|||
|
|
// 根据用户ID获取认证申请
|
|||
|
|
certification, err := s.certRepo.GetByUserID(ctx, query.UserID)
|
|||
|
|
if err != nil {
|
|||
|
|
// 如果用户没有认证申请,返回一个表示未开始的状态
|
|||
|
|
if err.Error() == "认证申请不存在" || err.Error() == "record not found" {
|
|||
|
|
return &responses.CertificationResponse{
|
|||
|
|
ID: "",
|
|||
|
|
UserID: query.UserID,
|
|||
|
|
Status: "not_started",
|
|||
|
|
StatusName: "未开始认证",
|
|||
|
|
Progress: 0,
|
|||
|
|
IsUserActionRequired: true,
|
|||
|
|
IsAdminActionRequired: false,
|
|||
|
|
InfoSubmittedAt: nil,
|
|||
|
|
FaceVerifiedAt: nil,
|
|||
|
|
ContractAppliedAt: nil,
|
|||
|
|
ContractApprovedAt: nil,
|
|||
|
|
ContractSignedAt: nil,
|
|||
|
|
CompletedAt: nil,
|
|||
|
|
ContractURL: "",
|
|||
|
|
SigningURL: "",
|
|||
|
|
RejectReason: "",
|
|||
|
|
CreatedAt: time.Time{},
|
|||
|
|
UpdatedAt: time.Time{},
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建响应
|
|||
|
|
response := s.buildCertificationResponse(certification)
|
|||
|
|
|
|||
|
|
return response, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetCertificationDetails 获取认证详情
|
|||
|
|
func (s *CertificationApplicationServiceImpl) GetCertificationDetails(ctx context.Context, query *queries.GetCertificationDetailsQuery) (*responses.CertificationResponse, error) {
|
|||
|
|
// 根据用户ID获取认证申请
|
|||
|
|
certification, err := s.certRepo.GetByUserID(ctx, query.UserID)
|
|||
|
|
if err != nil {
|
|||
|
|
// 如果用户没有认证申请,返回错误
|
|||
|
|
if err.Error() == "认证申请不存在" || err.Error() == "record not found" {
|
|||
|
|
return nil, fmt.Errorf("用户尚未创建认证申请")
|
|||
|
|
}
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取认证申请详细信息
|
|||
|
|
certificationWithDetails, err := s.certService.GetCertificationWithDetails(ctx, certification.ID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建响应
|
|||
|
|
response := s.buildCertificationResponse(certificationWithDetails)
|
|||
|
|
|
|||
|
|
// 添加企业信息
|
|||
|
|
if certification.UserID != "" {
|
|||
|
|
enterpriseInfo, err := s.enterpriseInfoRepo.GetByUserID(ctx, certification.UserID)
|
|||
|
|
if err == nil && enterpriseInfo != nil {
|
|||
|
|
response.Enterprise = &responses.EnterpriseInfoResponse{
|
|||
|
|
ID: enterpriseInfo.ID,
|
|||
|
|
CompanyName: enterpriseInfo.CompanyName,
|
|||
|
|
UnifiedSocialCode: enterpriseInfo.UnifiedSocialCode,
|
|||
|
|
LegalPersonName: enterpriseInfo.LegalPersonName,
|
|||
|
|
LegalPersonID: enterpriseInfo.LegalPersonID,
|
|||
|
|
IsOCRVerified: enterpriseInfo.IsOCRVerified,
|
|||
|
|
IsFaceVerified: enterpriseInfo.IsFaceVerified,
|
|||
|
|
CreatedAt: enterpriseInfo.CreatedAt,
|
|||
|
|
UpdatedAt: enterpriseInfo.UpdatedAt,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return response, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CompleteFaceVerify 完成人脸识别验证
|
|||
|
|
func (s *CertificationApplicationServiceImpl) CompleteFaceVerify(ctx context.Context, faceVerifyID string, isSuccess bool) error {
|
|||
|
|
return s.certService.CompleteFaceVerify(ctx, faceVerifyID, isSuccess)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ApproveContract 管理员审核合同
|
|||
|
|
func (s *CertificationApplicationServiceImpl) ApproveContract(ctx context.Context, certificationID, adminID, signingURL, approvalNotes string) error {
|
|||
|
|
return s.certService.ApproveContract(ctx, certificationID, adminID, signingURL, approvalNotes)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RejectContract 管理员拒绝合同
|
|||
|
|
func (s *CertificationApplicationServiceImpl) RejectContract(ctx context.Context, certificationID, adminID, rejectReason string) error {
|
|||
|
|
return s.certService.RejectContract(ctx, certificationID, adminID, rejectReason)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CompleteContractSign 完成合同签署
|
|||
|
|
func (s *CertificationApplicationServiceImpl) CompleteContractSign(ctx context.Context, certificationID, contractURL string) error {
|
|||
|
|
return s.certService.CompleteContractSign(ctx, certificationID, contractURL)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CompleteCertification 完成认证
|
|||
|
|
func (s *CertificationApplicationServiceImpl) CompleteCertification(ctx context.Context, certificationID string) error {
|
|||
|
|
return s.certService.CompleteCertification(ctx, certificationID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RetryStep 重试认证步骤
|
|||
|
|
func (s *CertificationApplicationServiceImpl) RetryStep(ctx context.Context, cmd *commands.RetryStepCommand) error {
|
|||
|
|
switch cmd.Step {
|
|||
|
|
case "face_verify":
|
|||
|
|
return s.certService.RetryFaceVerify(ctx, cmd.CertificationID)
|
|||
|
|
case "restart":
|
|||
|
|
return s.certService.RestartCertification(ctx, cmd.CertificationID)
|
|||
|
|
default:
|
|||
|
|
return fmt.Errorf("不支持的重试步骤: %s", cmd.Step)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetCertificationProgress 获取认证进度
|
|||
|
|
func (s *CertificationApplicationServiceImpl) GetCertificationProgress(ctx context.Context, userID string) (map[string]interface{}, error) {
|
|||
|
|
// 根据用户ID获取认证申请
|
|||
|
|
certification, err := s.certRepo.GetByUserID(ctx, userID)
|
|||
|
|
if err != nil {
|
|||
|
|
// 如果用户没有认证申请,返回未开始状态
|
|||
|
|
if err.Error() == "认证申请不存在" || err.Error() == "record not found" {
|
|||
|
|
return map[string]interface{}{
|
|||
|
|
"certification_id": "",
|
|||
|
|
"user_id": userID,
|
|||
|
|
"current_status": "not_started",
|
|||
|
|
"status_name": "未开始认证",
|
|||
|
|
"progress_percentage": 0,
|
|||
|
|
"is_user_action_required": true,
|
|||
|
|
"is_admin_action_required": false,
|
|||
|
|
"next_valid_statuses": []string{"pending"},
|
|||
|
|
"message": "用户尚未开始认证流程",
|
|||
|
|
"created_at": nil,
|
|||
|
|
"updated_at": nil,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取认证进度
|
|||
|
|
return s.certService.GetCertificationProgress(ctx, certification.ID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RetryFaceVerify 重试人脸识别
|
|||
|
|
func (s *CertificationApplicationServiceImpl) RetryFaceVerify(ctx context.Context, userID string) (*responses.FaceVerifyResponse, error) {
|
|||
|
|
// 根据用户ID获取认证申请
|
|||
|
|
certification, err := s.certRepo.GetByUserID(ctx, userID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("用户尚未创建认证申请: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用领域服务重试人脸识别
|
|||
|
|
if err := s.certService.RetryFaceVerify(ctx, certification.ID); err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重新发起人脸识别
|
|||
|
|
faceVerifyRecord, err := s.certService.InitiateFaceVerify(ctx, certification.ID, "", "")
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建验证URL
|
|||
|
|
verifyURL := fmt.Sprintf("/api/certification/face-verify/%s", faceVerifyRecord.ID)
|
|||
|
|
|
|||
|
|
return &responses.FaceVerifyResponse{
|
|||
|
|
CertifyID: faceVerifyRecord.ID,
|
|||
|
|
VerifyURL: verifyURL,
|
|||
|
|
ExpiresAt: faceVerifyRecord.ExpiresAt,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RetryContractSign 重试合同签署
|
|||
|
|
func (s *CertificationApplicationServiceImpl) RetryContractSign(ctx context.Context, userID string) (*responses.CertificationResponse, error) {
|
|||
|
|
// 根据用户ID获取认证申请
|
|||
|
|
certification, err := s.certRepo.GetByUserID(ctx, userID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("用户尚未创建认证申请: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重新获取更新后的认证申请
|
|||
|
|
updatedCertification, err := s.certRepo.GetByID(ctx, certification.ID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
s.logger.Info("合同签署重试准备完成",
|
|||
|
|
zap.String("user_id", userID),
|
|||
|
|
zap.String("certification_id", certification.ID),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
return s.buildCertificationResponse(&updatedCertification), nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RestartCertification 重新开始认证
|
|||
|
|
func (s *CertificationApplicationServiceImpl) RestartCertification(ctx context.Context, certificationID string) error {
|
|||
|
|
return s.certService.RestartCertification(ctx, certificationID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// buildCertificationResponse 构建认证响应
|
|||
|
|
func (s *CertificationApplicationServiceImpl) buildCertificationResponse(certification *entities.Certification) *responses.CertificationResponse {
|
|||
|
|
return &responses.CertificationResponse{
|
|||
|
|
ID: certification.ID,
|
|||
|
|
UserID: certification.UserID,
|
|||
|
|
Status: certification.Status,
|
|||
|
|
StatusName: string(certification.Status),
|
|||
|
|
Progress: certification.GetProgressPercentage(),
|
|||
|
|
IsUserActionRequired: certification.IsUserActionRequired(),
|
|||
|
|
IsAdminActionRequired: certification.IsAdminActionRequired(),
|
|||
|
|
InfoSubmittedAt: certification.InfoSubmittedAt,
|
|||
|
|
FaceVerifiedAt: certification.FaceVerifiedAt,
|
|||
|
|
ContractAppliedAt: certification.ContractAppliedAt,
|
|||
|
|
ContractApprovedAt: certification.ContractApprovedAt,
|
|||
|
|
ContractSignedAt: certification.ContractSignedAt,
|
|||
|
|
CompletedAt: certification.CompletedAt,
|
|||
|
|
ContractURL: certification.ContractURL,
|
|||
|
|
SigningURL: certification.SigningURL,
|
|||
|
|
RejectReason: certification.RejectReason,
|
|||
|
|
CreatedAt: certification.CreatedAt,
|
|||
|
|
UpdatedAt: certification.UpdatedAt,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// processOCRAsync 异步处理OCR识别
|
|||
|
|
func (s *CertificationApplicationServiceImpl) processOCRAsync(ctx context.Context, licenseID string, fileBytes []byte) {
|
|||
|
|
// 调用领域服务处理OCR识别
|
|||
|
|
if err := s.certService.ProcessOCRAsync(ctx, licenseID, fileBytes); err != nil {
|
|||
|
|
s.logger.Error("OCR处理失败",
|
|||
|
|
zap.String("license_id", licenseID),
|
|||
|
|
zap.Error(err),
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetLicenseOCRResult 获取营业执照OCR识别结果
|
|||
|
|
func (s *CertificationApplicationServiceImpl) GetLicenseOCRResult(ctx context.Context, recordID string) (*responses.UploadLicenseResponse, error) {
|
|||
|
|
// 获取营业执照上传记录
|
|||
|
|
licenseRecord, err := s.licenseRepo.GetByID(ctx, recordID)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("获取营业执照记录失败", zap.Error(err))
|
|||
|
|
return nil, fmt.Errorf("获取营业执照记录失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建响应
|
|||
|
|
response := &responses.UploadLicenseResponse{
|
|||
|
|
UploadRecordID: licenseRecord.ID,
|
|||
|
|
FileURL: licenseRecord.FileURL,
|
|||
|
|
OCRProcessed: licenseRecord.OCRProcessed,
|
|||
|
|
OCRSuccess: licenseRecord.OCRSuccess,
|
|||
|
|
OCRConfidence: licenseRecord.OCRConfidence,
|
|||
|
|
OCRErrorMessage: licenseRecord.OCRErrorMessage,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果OCR成功,解析OCR结果
|
|||
|
|
if licenseRecord.OCRSuccess && licenseRecord.OCRRawData != "" {
|
|||
|
|
// 这里可以解析OCR原始数据,提取企业信息
|
|||
|
|
// 简化处理,直接返回原始数据中的关键信息
|
|||
|
|
// 实际项目中可以使用JSON解析
|
|||
|
|
response.EnterpriseName = "已识别" // 从OCR数据中提取
|
|||
|
|
response.CreditCode = "已识别" // 从OCR数据中提取
|
|||
|
|
response.LegalPerson = "已识别" // 从OCR数据中提取
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return response, nil
|
|||
|
|
}
|