f
This commit is contained in:
@@ -109,10 +109,13 @@ func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo(
|
||||
s.logger.Info("开始提交企业信息",
|
||||
zap.String("user_id", cmd.UserID))
|
||||
|
||||
// 0. 若该用户已有待审核的提交记录,则不允许重复提交
|
||||
// 0. 若该用户已有待审核(认证状态仍在待审核),则不允许重复提交
|
||||
latestRecord, err := s.enterpriseInfoSubmitRecordRepo.FindLatestByUserID(ctx, cmd.UserID)
|
||||
if err == nil && latestRecord != nil && latestRecord.ManualReviewStatus == "pending" {
|
||||
return nil, fmt.Errorf("您已有待审核的提交,请等待管理员审核后再操作")
|
||||
if err == nil && latestRecord != nil {
|
||||
cert, loadErr := s.aggregateService.LoadCertificationByUserID(ctx, cmd.UserID)
|
||||
if loadErr == nil && cert != nil && cert.Status == enums.StatusInfoPendingReview {
|
||||
return nil, fmt.Errorf("您已有待审核的提交,请等待管理员审核后再操作")
|
||||
}
|
||||
}
|
||||
|
||||
// 1.5 插入企业信息提交记录(包含扩展字段)
|
||||
@@ -259,16 +262,7 @@ func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo(
|
||||
return fmt.Errorf("加载认证信息失败: %s", err.Error())
|
||||
}
|
||||
|
||||
// 已是「已提交企业信息」:说明已通过人工审核,直接返回当前认证数据,前端可刷新到企业认证步骤
|
||||
if cert.Status == enums.StatusInfoSubmitted {
|
||||
response = s.convertToResponse(cert)
|
||||
response.Metadata = map[string]interface{}{
|
||||
"next_action": "您已通过审核,请完成企业认证步骤",
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 4. 提交企业信息进入人工审核(不调用 e签宝,不生成认证链接)
|
||||
// 4. 提交企业信息进入人工审核(不在此处推断审核是否通过)
|
||||
err = cert.SubmitEnterpriseInfoForReview(enterpriseInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("提交企业信息失败: %s", err.Error())
|
||||
@@ -303,6 +297,25 @@ func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo(
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// 审核状态检查(步骤二)
|
||||
// 规则:企业信息提交成功后进入待审核;审核通过后才允许进行企业认证确认(ConfirmAuth)。
|
||||
func (s *CertificationApplicationServiceImpl) checkAuditStatus(ctx context.Context, cert *entities.Certification) error {
|
||||
switch cert.Status {
|
||||
case enums.StatusInfoSubmitted,
|
||||
enums.StatusEnterpriseVerified,
|
||||
enums.StatusContractApplied,
|
||||
enums.StatusContractSigned,
|
||||
enums.StatusCompleted:
|
||||
return nil
|
||||
case enums.StatusInfoPendingReview:
|
||||
return fmt.Errorf("企业信息已提交,正在审核中")
|
||||
case enums.StatusInfoRejected:
|
||||
return fmt.Errorf("企业信息审核未通过")
|
||||
default:
|
||||
return fmt.Errorf("认证状态不正确,当前状态: %s", enums.GetStatusName(cert.Status))
|
||||
}
|
||||
}
|
||||
|
||||
// ConfirmAuth 确认认证状态
|
||||
func (s *CertificationApplicationServiceImpl) ConfirmAuth(
|
||||
ctx context.Context,
|
||||
@@ -314,9 +327,9 @@ func (s *CertificationApplicationServiceImpl) ConfirmAuth(
|
||||
return nil, fmt.Errorf("加载认证信息失败: %s", err.Error())
|
||||
}
|
||||
|
||||
// 企业认证
|
||||
if cert.Status != enums.StatusInfoSubmitted {
|
||||
return nil, fmt.Errorf("认证状态不正确,当前状态: %s", enums.GetStatusName(cert.Status))
|
||||
// 步骤二:审核状态检查(审核通过后才能进入企业认证确认)
|
||||
if err := s.checkAuditStatus(ctx, cert); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
record, err := s.enterpriseInfoSubmitRecordRepo.FindLatestByUserID(ctx, cert.UserID)
|
||||
if err != nil {
|
||||
@@ -730,12 +743,12 @@ func (s *CertificationApplicationServiceImpl) AdminListSubmitRecords(
|
||||
query.Page = 1
|
||||
}
|
||||
filter := repositories.ListSubmitRecordsFilter{
|
||||
Page: query.Page,
|
||||
PageSize: query.PageSize,
|
||||
ManualReviewStatus: query.ManualReviewStatus,
|
||||
CompanyName: query.CompanyName,
|
||||
LegalPersonPhone: query.LegalPersonPhone,
|
||||
LegalPersonName: query.LegalPersonName,
|
||||
Page: query.Page,
|
||||
PageSize: query.PageSize,
|
||||
CertificationStatus: query.CertificationStatus,
|
||||
CompanyName: query.CompanyName,
|
||||
LegalPersonPhone: query.LegalPersonPhone,
|
||||
LegalPersonName: query.LegalPersonName,
|
||||
}
|
||||
result, err := s.enterpriseInfoSubmitRecordRepo.List(ctx, filter)
|
||||
if err != nil {
|
||||
@@ -755,8 +768,6 @@ func (s *CertificationApplicationServiceImpl) AdminListSubmitRecords(
|
||||
LegalPersonName: r.LegalPersonName,
|
||||
SubmitAt: r.SubmitAt,
|
||||
Status: r.Status,
|
||||
ManualReviewStatus: r.ManualReviewStatus,
|
||||
ManualReviewedAt: r.ManualReviewedAt,
|
||||
CertificationStatus: certStatus,
|
||||
})
|
||||
}
|
||||
@@ -805,10 +816,6 @@ func (s *CertificationApplicationServiceImpl) AdminGetSubmitRecordByID(ctx conte
|
||||
VerifiedAt: record.VerifiedAt,
|
||||
FailedAt: record.FailedAt,
|
||||
FailureReason: record.FailureReason,
|
||||
ManualReviewStatus: record.ManualReviewStatus,
|
||||
ManualReviewRemark: record.ManualReviewRemark,
|
||||
ManualReviewedAt: record.ManualReviewedAt,
|
||||
ManualReviewerID: record.ManualReviewerID,
|
||||
CertificationStatus: certStatus,
|
||||
CreatedAt: record.CreatedAt,
|
||||
UpdatedAt: record.UpdatedAt,
|
||||
@@ -821,17 +828,12 @@ func (s *CertificationApplicationServiceImpl) AdminApproveSubmitRecord(ctx conte
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取提交记录失败: %w", err)
|
||||
}
|
||||
if record.ManualReviewStatus != "pending" {
|
||||
return fmt.Errorf("该记录已审核,当前状态: %s", record.ManualReviewStatus)
|
||||
}
|
||||
cert, err := s.aggregateService.LoadCertificationByUserID(ctx, record.UserID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载认证信息失败: %w", err)
|
||||
}
|
||||
|
||||
// 兼容线上脏数据:认证已进入「已提交企业信息」或更后续状态,但提交记录仍是 pending,
|
||||
// 此时无需再走「待审核->通过」的状态机,只需要把提交记录补齐为 approved,避免管理端无法操作。
|
||||
// 说明:后续状态(如已企业认证/合同状态/完成)都意味着企业信息审核已经通过。
|
||||
// 幂等:认证已进入「已提交企业信息」或更后续状态,说明已通过审核,无需重复操作
|
||||
switch cert.Status {
|
||||
case enums.StatusInfoSubmitted,
|
||||
enums.StatusEnterpriseVerified,
|
||||
@@ -840,31 +842,11 @@ func (s *CertificationApplicationServiceImpl) AdminApproveSubmitRecord(ctx conte
|
||||
enums.StatusCompleted,
|
||||
enums.StatusContractRejected,
|
||||
enums.StatusContractExpired:
|
||||
record.MarkManualApproved(adminID, remark)
|
||||
if err := s.enterpriseInfoSubmitRecordService.Save(ctx, record); err != nil {
|
||||
return fmt.Errorf("保存提交记录失败: %w", err)
|
||||
}
|
||||
s.logger.Info("已补齐提交记录人工审核为通过(认证已进入后续状态)",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("admin_id", adminID),
|
||||
zap.String("user_id", record.UserID),
|
||||
zap.String("certification_status", string(cert.Status)),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 兼容线上脏数据:提交记录已落库但当时事务失败导致认证仍为「待认证」,先同步为待审核再执行通过
|
||||
if cert.Status != enums.StatusInfoPendingReview {
|
||||
if err := s.syncCertToPendingReviewIfRecordPending(ctx, cert, record); err != nil {
|
||||
return err
|
||||
}
|
||||
cert, err = s.aggregateService.LoadCertificationByUserID(ctx, record.UserID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载认证信息失败: %w", err)
|
||||
}
|
||||
if cert.Status != enums.StatusInfoPendingReview {
|
||||
return fmt.Errorf("认证状态不是待审核,当前: %s", enums.GetStatusName(cert.Status))
|
||||
}
|
||||
return fmt.Errorf("认证状态不是待审核,当前: %s", enums.GetStatusName(cert.Status))
|
||||
}
|
||||
enterpriseInfo := &certification_value_objects.EnterpriseInfo{
|
||||
CompanyName: record.CompanyName,
|
||||
@@ -886,10 +868,6 @@ func (s *CertificationApplicationServiceImpl) AdminApproveSubmitRecord(ctx conte
|
||||
if err != nil {
|
||||
return fmt.Errorf("生成企业认证链接失败: %w", err)
|
||||
}
|
||||
record.MarkManualApproved(adminID, remark)
|
||||
if err := s.enterpriseInfoSubmitRecordService.Save(ctx, record); err != nil {
|
||||
return fmt.Errorf("保存提交记录失败: %w", err)
|
||||
}
|
||||
if err := cert.ApproveEnterpriseInfoReview(authURL.AuthShortURL, authURL.AuthFlowID, adminID); err != nil {
|
||||
return fmt.Errorf("更新认证状态失败: %w", err)
|
||||
}
|
||||
@@ -909,29 +887,24 @@ func (s *CertificationApplicationServiceImpl) AdminRejectSubmitRecord(ctx contex
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取提交记录失败: %w", err)
|
||||
}
|
||||
if record.ManualReviewStatus != "pending" {
|
||||
return fmt.Errorf("该记录已审核,当前状态: %s", record.ManualReviewStatus)
|
||||
}
|
||||
cert, err := s.aggregateService.LoadCertificationByUserID(ctx, record.UserID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载认证信息失败: %w", err)
|
||||
}
|
||||
// 兼容线上脏数据:提交记录已落库但当时事务失败导致认证仍为「待认证」,先同步为待审核再执行拒绝
|
||||
if cert.Status != enums.StatusInfoPendingReview {
|
||||
if err := s.syncCertToPendingReviewIfRecordPending(ctx, cert, record); err != nil {
|
||||
return err
|
||||
}
|
||||
cert, err = s.aggregateService.LoadCertificationByUserID(ctx, record.UserID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载认证信息失败: %w", err)
|
||||
}
|
||||
if cert.Status != enums.StatusInfoPendingReview {
|
||||
return fmt.Errorf("认证状态不是待审核,当前: %s", enums.GetStatusName(cert.Status))
|
||||
}
|
||||
|
||||
// 幂等:认证已处于拒绝或后续状态,无需重复拒绝
|
||||
switch cert.Status {
|
||||
case enums.StatusInfoRejected,
|
||||
enums.StatusEnterpriseVerified,
|
||||
enums.StatusContractApplied,
|
||||
enums.StatusContractSigned,
|
||||
enums.StatusCompleted,
|
||||
enums.StatusContractRejected,
|
||||
enums.StatusContractExpired:
|
||||
return nil
|
||||
}
|
||||
record.MarkManualRejected(adminID, remark)
|
||||
if err := s.enterpriseInfoSubmitRecordService.Save(ctx, record); err != nil {
|
||||
return fmt.Errorf("保存提交记录失败: %w", err)
|
||||
if cert.Status != enums.StatusInfoPendingReview {
|
||||
return fmt.Errorf("认证状态不是待审核,当前: %s", enums.GetStatusName(cert.Status))
|
||||
}
|
||||
if err := cert.RejectEnterpriseInfoReview(adminID, remark); err != nil {
|
||||
return fmt.Errorf("更新认证状态失败: %w", err)
|
||||
@@ -943,35 +916,75 @@ func (s *CertificationApplicationServiceImpl) AdminRejectSubmitRecord(ctx contex
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 辅助方法 ================
|
||||
|
||||
// syncCertToPendingReviewIfRecordPending 兼容历史脏数据:当认证为「待认证」或「已拒绝」且存在待审核提交记录时,
|
||||
// 用该记录的企业信息把认证同步为「待审核」,便于管理员直接审核通过/拒绝。
|
||||
func (s *CertificationApplicationServiceImpl) syncCertToPendingReviewIfRecordPending(ctx context.Context, cert *entities.Certification, record *entities.EnterpriseInfoSubmitRecord) error {
|
||||
if record.ManualReviewStatus != "pending" {
|
||||
// AdminTransitionCertificationStatus 管理端按用户变更认证状态(以状态机为准)
|
||||
func (s *CertificationApplicationServiceImpl) AdminTransitionCertificationStatus(ctx context.Context, cmd *commands.AdminTransitionCertificationStatusCommand) error {
|
||||
cert, err := s.aggregateService.LoadCertificationByUserID(ctx, cmd.UserID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载认证信息失败: %w", err)
|
||||
}
|
||||
record, err := s.enterpriseInfoSubmitRecordRepo.FindLatestByUserID(ctx, cmd.UserID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找企业信息提交记录失败: %w", err)
|
||||
}
|
||||
if record == nil {
|
||||
return fmt.Errorf("未找到该用户的企业信息提交记录")
|
||||
}
|
||||
switch cmd.TargetStatus {
|
||||
case string(enums.StatusInfoSubmitted):
|
||||
// 审核通过:与 AdminApproveSubmitRecord 一致,推状态并生成企业认证链接
|
||||
switch cert.Status {
|
||||
case enums.StatusInfoSubmitted, enums.StatusEnterpriseVerified, enums.StatusContractApplied,
|
||||
enums.StatusContractSigned, enums.StatusCompleted, enums.StatusContractRejected, enums.StatusContractExpired:
|
||||
return nil
|
||||
}
|
||||
if cert.Status != enums.StatusInfoPendingReview {
|
||||
return fmt.Errorf("认证状态不是待审核,当前: %s", enums.GetStatusName(cert.Status))
|
||||
}
|
||||
enterpriseInfo := &certification_value_objects.EnterpriseInfo{
|
||||
CompanyName: record.CompanyName, UnifiedSocialCode: record.UnifiedSocialCode,
|
||||
LegalPersonName: record.LegalPersonName, LegalPersonID: record.LegalPersonID,
|
||||
LegalPersonPhone: record.LegalPersonPhone, EnterpriseAddress: record.EnterpriseAddress,
|
||||
}
|
||||
authURL, err := s.esignClient.GenerateEnterpriseAuth(&esign.EnterpriseAuthRequest{
|
||||
CompanyName: enterpriseInfo.CompanyName, UnifiedSocialCode: enterpriseInfo.UnifiedSocialCode,
|
||||
LegalPersonName: enterpriseInfo.LegalPersonName, LegalPersonID: enterpriseInfo.LegalPersonID,
|
||||
TransactorName: enterpriseInfo.LegalPersonName, TransactorMobile: enterpriseInfo.LegalPersonPhone, TransactorID: enterpriseInfo.LegalPersonID,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("生成企业认证链接失败: %w", err)
|
||||
}
|
||||
if err := cert.ApproveEnterpriseInfoReview(authURL.AuthShortURL, authURL.AuthFlowID, cmd.AdminID); err != nil {
|
||||
return fmt.Errorf("更新认证状态失败: %w", err)
|
||||
}
|
||||
if err := s.aggregateService.SaveCertification(ctx, cert); err != nil {
|
||||
return fmt.Errorf("保存认证信息失败: %w", err)
|
||||
}
|
||||
s.logger.Info("管理端变更认证状态为通过", zap.String("user_id", cmd.UserID), zap.String("admin_id", cmd.AdminID))
|
||||
return nil
|
||||
case string(enums.StatusInfoRejected):
|
||||
// 审核拒绝
|
||||
if cert.Status == enums.StatusInfoRejected || cert.Status == enums.StatusEnterpriseVerified ||
|
||||
cert.Status == enums.StatusContractApplied || cert.Status == enums.StatusContractSigned || cert.Status == enums.StatusCompleted {
|
||||
return nil
|
||||
}
|
||||
if cert.Status != enums.StatusInfoPendingReview {
|
||||
return fmt.Errorf("认证状态不是待审核,当前: %s", enums.GetStatusName(cert.Status))
|
||||
}
|
||||
if err := cert.RejectEnterpriseInfoReview(cmd.AdminID, cmd.Remark); err != nil {
|
||||
return fmt.Errorf("更新认证状态失败: %w", err)
|
||||
}
|
||||
if err := s.aggregateService.SaveCertification(ctx, cert); err != nil {
|
||||
return fmt.Errorf("保存认证信息失败: %w", err)
|
||||
}
|
||||
s.logger.Info("管理端变更认证状态为拒绝", zap.String("user_id", cmd.UserID), zap.String("admin_id", cmd.AdminID))
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("不支持的目标状态: %s", cmd.TargetStatus)
|
||||
}
|
||||
if cert.Status != enums.StatusPending && cert.Status != enums.StatusInfoRejected {
|
||||
return fmt.Errorf("认证状态不是待审核,当前: %s", enums.GetStatusName(cert.Status))
|
||||
}
|
||||
enterpriseInfo := &certification_value_objects.EnterpriseInfo{
|
||||
CompanyName: record.CompanyName,
|
||||
UnifiedSocialCode: record.UnifiedSocialCode,
|
||||
LegalPersonName: record.LegalPersonName,
|
||||
LegalPersonID: record.LegalPersonID,
|
||||
LegalPersonPhone: record.LegalPersonPhone,
|
||||
EnterpriseAddress: record.EnterpriseAddress,
|
||||
}
|
||||
if err := cert.SubmitEnterpriseInfoForReview(enterpriseInfo); err != nil {
|
||||
return fmt.Errorf("同步认证为待审核失败: %w", err)
|
||||
}
|
||||
if err := s.aggregateService.SaveCertification(ctx, cert); err != nil {
|
||||
return fmt.Errorf("保存认证信息失败: %w", err)
|
||||
}
|
||||
s.logger.Info("已同步认证为待审核(兼容历史脏数据)", zap.String("user_id", cert.UserID), zap.String("record_id", record.ID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 辅助方法 ================
|
||||
|
||||
// convertToResponse 转换实体为响应DTO
|
||||
func (s *CertificationApplicationServiceImpl) convertToResponse(cert *entities.Certification) *responses.CertificationResponse {
|
||||
response := &responses.CertificationResponse{
|
||||
|
||||
Reference in New Issue
Block a user