v0.1
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/enums"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/services/state_machine"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -19,40 +18,34 @@ type CertificationAggregateService interface {
|
||||
CreateCertification(ctx context.Context, userID string) (*entities.Certification, error)
|
||||
LoadCertification(ctx context.Context, certificationID string) (*entities.Certification, error)
|
||||
SaveCertification(ctx context.Context, cert *entities.Certification) error
|
||||
|
||||
// 状态转换管理
|
||||
TransitionState(ctx context.Context, certificationID string, targetStatus enums.CertificationStatus, actor enums.ActorType, actorID string, reason string, metadata map[string]interface{}) (*state_machine.StateTransitionResult, error)
|
||||
ValidateStateTransition(ctx context.Context, certificationID string, targetStatus enums.CertificationStatus, actor enums.ActorType) error
|
||||
|
||||
LoadCertificationByUserID(ctx context.Context, userID string) (*entities.Certification, error)
|
||||
LoadCertificationByAuthFlowId(ctx context.Context, authFlowId string) (*entities.Certification, error)
|
||||
LoadCertificationByEsignFlowId(ctx context.Context, esignFlowId string) (*entities.Certification, error)
|
||||
// 业务规则验证
|
||||
ValidateBusinessRules(ctx context.Context, cert *entities.Certification) error
|
||||
CheckInvariance(ctx context.Context, cert *entities.Certification) error
|
||||
|
||||
// 查询方法
|
||||
GetStateInfo(status enums.CertificationStatus) *state_machine.StateConfig
|
||||
GetValidTransitions(ctx context.Context, certificationID string, actor enums.ActorType) ([]*state_machine.StateTransitionRule, error)
|
||||
ExistsByUserID(ctx context.Context, userID string) (bool, error)
|
||||
}
|
||||
|
||||
// CertificationAggregateServiceImpl 认证聚合服务实现
|
||||
type CertificationAggregateServiceImpl struct {
|
||||
commandRepo repositories.CertificationCommandRepository
|
||||
queryRepo repositories.CertificationQueryRepository
|
||||
stateMachine *state_machine.CertificationStateMachine
|
||||
logger *zap.Logger
|
||||
commandRepo repositories.CertificationCommandRepository
|
||||
queryRepo repositories.CertificationQueryRepository
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewCertificationAggregateService 创建认证聚合服务
|
||||
func NewCertificationAggregateService(
|
||||
commandRepo repositories.CertificationCommandRepository,
|
||||
queryRepo repositories.CertificationQueryRepository,
|
||||
stateMachine *state_machine.CertificationStateMachine,
|
||||
logger *zap.Logger,
|
||||
) CertificationAggregateService {
|
||||
return &CertificationAggregateServiceImpl{
|
||||
commandRepo: commandRepo,
|
||||
queryRepo: queryRepo,
|
||||
stateMachine: stateMachine,
|
||||
logger: logger,
|
||||
commandRepo: commandRepo,
|
||||
queryRepo: queryRepo,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,17 +56,15 @@ func (s *CertificationAggregateServiceImpl) CreateCertification(ctx context.Cont
|
||||
s.logger.Info("创建认证申请", zap.String("user_id", userID))
|
||||
|
||||
// 1. 检查用户是否已有认证申请
|
||||
existingCert, err := s.queryRepo.GetByUserID(ctx, userID)
|
||||
if err == nil && existingCert != nil {
|
||||
// 检查现有认证的状态
|
||||
if !existingCert.IsFinalStatus() {
|
||||
return nil, fmt.Errorf("用户已有进行中的认证申请,请先完成或取消现有申请")
|
||||
}
|
||||
|
||||
s.logger.Info("用户已有完成的认证申请,允许创建新申请",
|
||||
zap.String("user_id", userID),
|
||||
zap.String("existing_cert_id", existingCert.ID),
|
||||
zap.String("existing_status", string(existingCert.Status)))
|
||||
exists, err := s.ExistsByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
s.logger.Error("检查用户认证是否存在失败", zap.Error(err), zap.String("user_id", userID))
|
||||
return nil, fmt.Errorf("检查用户认证是否存在失败: %w", err)
|
||||
}
|
||||
if exists {
|
||||
s.logger.Info("用户已有认证申请,不允许创建新申请",
|
||||
zap.String("user_id", userID))
|
||||
return nil, fmt.Errorf("用户已有认证申请")
|
||||
}
|
||||
|
||||
// 2. 创建新的认证聚合根
|
||||
@@ -122,6 +113,48 @@ func (s *CertificationAggregateServiceImpl) LoadCertification(ctx context.Contex
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// LoadCertificationByUserID 加载用户认证聚合根
|
||||
func (s *CertificationAggregateServiceImpl) LoadCertificationByUserID(ctx context.Context, userID string) (*entities.Certification, error) {
|
||||
s.logger.Debug("加载用户认证聚合根", zap.String("user_id", userID))
|
||||
|
||||
// 从查询仓储加载
|
||||
cert, err := s.queryRepo.GetByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
s.logger.Error("加载用户认证聚合根失败", zap.Error(err), zap.String("user_id", userID))
|
||||
return nil, fmt.Errorf("认证申请不存在: %w", err)
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// LoadCertificationByAuthFlowId 加载认证聚合根
|
||||
func (s *CertificationAggregateServiceImpl) LoadCertificationByAuthFlowId(ctx context.Context, authFlowId string) (*entities.Certification, error) {
|
||||
s.logger.Debug("加载认证聚合根", zap.String("auth_flow_id", authFlowId))
|
||||
|
||||
// 从查询仓储加载
|
||||
cert, err := s.queryRepo.FindByAuthFlowID(ctx, authFlowId)
|
||||
if err != nil {
|
||||
s.logger.Error("加载认证聚合根失败", zap.Error(err), zap.String("auth_flow_id", authFlowId))
|
||||
return nil, fmt.Errorf("认证申请不存在: %w", err)
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// LoadCertificationByEsignFlowId 加载认证聚合根
|
||||
func (s *CertificationAggregateServiceImpl) LoadCertificationByEsignFlowId(ctx context.Context, esignFlowId string) (*entities.Certification, error) {
|
||||
s.logger.Debug("加载认证聚合根", zap.String("esign_flow_id", esignFlowId))
|
||||
|
||||
// 从查询仓储加载
|
||||
cert, err := s.queryRepo.FindByEsignFlowID(ctx, esignFlowId)
|
||||
if err != nil {
|
||||
s.logger.Error("加载认证聚合根失败", zap.Error(err), zap.String("esign_flow_id", esignFlowId))
|
||||
return nil, fmt.Errorf("认证申请不存在: %w", err)
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// SaveCertification 保存认证聚合根
|
||||
func (s *CertificationAggregateServiceImpl) SaveCertification(ctx context.Context, cert *entities.Certification) error {
|
||||
s.logger.Debug("保存认证聚合根", zap.String("certification_id", cert.ID))
|
||||
@@ -156,74 +189,6 @@ func (s *CertificationAggregateServiceImpl) SaveCertification(ctx context.Contex
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 状态转换管理 ================
|
||||
|
||||
// TransitionState 执行状态转换
|
||||
func (s *CertificationAggregateServiceImpl) TransitionState(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
targetStatus enums.CertificationStatus,
|
||||
actor enums.ActorType,
|
||||
actorID string,
|
||||
reason string,
|
||||
metadata map[string]interface{},
|
||||
) (*state_machine.StateTransitionResult, error) {
|
||||
s.logger.Info("执行状态转换",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("target_status", string(targetStatus)),
|
||||
zap.String("actor", string(actor)),
|
||||
zap.String("actor_id", actorID))
|
||||
|
||||
// 构建状态转换请求
|
||||
req := &state_machine.StateTransitionRequest{
|
||||
CertificationID: certificationID,
|
||||
TargetStatus: targetStatus,
|
||||
Actor: actor,
|
||||
ActorID: actorID,
|
||||
Reason: reason,
|
||||
Context: metadata,
|
||||
AllowRollback: true,
|
||||
}
|
||||
|
||||
// 执行状态转换
|
||||
result, err := s.stateMachine.ExecuteTransition(ctx, req)
|
||||
if err != nil {
|
||||
s.logger.Error("状态转换执行失败",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.Error(err))
|
||||
return result, err
|
||||
}
|
||||
|
||||
s.logger.Info("状态转换执行成功",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("from_status", string(result.OldStatus)),
|
||||
zap.String("to_status", string(result.NewStatus)))
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ValidateStateTransition 验证状态转换
|
||||
func (s *CertificationAggregateServiceImpl) ValidateStateTransition(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
targetStatus enums.CertificationStatus,
|
||||
actor enums.ActorType,
|
||||
) error {
|
||||
// 加载认证聚合根
|
||||
cert, err := s.LoadCertification(ctx, certificationID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 检查是否可以转换
|
||||
canTransition, message := s.stateMachine.CanTransition(cert, targetStatus, actor)
|
||||
if !canTransition {
|
||||
return fmt.Errorf("状态转换验证失败: %s", message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 业务规则验证 ================
|
||||
|
||||
// ValidateBusinessRules 验证业务规则
|
||||
@@ -280,26 +245,9 @@ func (s *CertificationAggregateServiceImpl) CheckInvariance(ctx context.Context,
|
||||
|
||||
// ================ 查询方法 ================
|
||||
|
||||
// GetStateInfo 获取状态信息
|
||||
func (s *CertificationAggregateServiceImpl) GetStateInfo(status enums.CertificationStatus) *state_machine.StateConfig {
|
||||
return s.stateMachine.GetStateInfo(status)
|
||||
}
|
||||
|
||||
// GetValidTransitions 获取有效的状态转换
|
||||
func (s *CertificationAggregateServiceImpl) GetValidTransitions(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
actor enums.ActorType,
|
||||
) ([]*state_machine.StateTransitionRule, error) {
|
||||
// 加载认证聚合根
|
||||
cert, err := s.LoadCertification(ctx, certificationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取有效转换
|
||||
transitions := s.stateMachine.GetValidTransitions(cert, actor)
|
||||
return transitions, nil
|
||||
// Exists 判断认证是否存在
|
||||
func (s *CertificationAggregateServiceImpl) ExistsByUserID(ctx context.Context, userID string) (bool, error) {
|
||||
return s.queryRepo.ExistsByUserID(ctx, userID)
|
||||
}
|
||||
|
||||
// ================ 私有方法 ================
|
||||
@@ -344,6 +292,17 @@ func (s *CertificationAggregateServiceImpl) validateStatusInvariance(cert *entit
|
||||
if cert.ContractSignedAt == nil {
|
||||
return fmt.Errorf("合同签署状态下必须有签署完成时间")
|
||||
}
|
||||
|
||||
case enums.StatusCompleted:
|
||||
if cert.ContractFileID == "" || cert.EsignFlowID == "" || cert.ContractURL == "" {
|
||||
return fmt.Errorf("认证完成状态下必须有完整的合同信息")
|
||||
}
|
||||
if cert.ContractSignedAt == nil {
|
||||
return fmt.Errorf("认证完成状态下必须有合同签署时间")
|
||||
}
|
||||
if cert.CompletedAt == nil {
|
||||
return fmt.Errorf("认证完成状态下必须有完成时间")
|
||||
}
|
||||
}
|
||||
|
||||
// 失败状态检查
|
||||
@@ -380,5 +339,11 @@ func (s *CertificationAggregateServiceImpl) validateTimestampInvariance(cert *en
|
||||
}
|
||||
}
|
||||
|
||||
if cert.ContractSignedAt != nil && cert.CompletedAt != nil {
|
||||
if cert.ContractSignedAt.After(*cert.CompletedAt) {
|
||||
return fmt.Errorf("合同签署时间不能晚于认证完成时间")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,27 +8,31 @@ import (
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/entities/value_objects"
|
||||
"tyapi-server/internal/domains/certification/enums"
|
||||
"tyapi-server/internal/domains/certification/services/state_machine"
|
||||
|
||||
"tyapi-server/internal/shared/esign"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// WorkflowResult 工作流执行结果
|
||||
type WorkflowResult struct {
|
||||
Success bool `json:"success"`
|
||||
CertificationID string `json:"certification_id"`
|
||||
CurrentStatus enums.CertificationStatus `json:"current_status"`
|
||||
Message string `json:"message"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
StateTransition *state_machine.StateTransitionResult `json:"state_transition,omitempty"`
|
||||
ExecutedAt time.Time `json:"executed_at"`
|
||||
Success bool `json:"success"`
|
||||
CertificationID string `json:"certification_id"`
|
||||
CurrentStatus enums.CertificationStatus `json:"current_status"`
|
||||
Message string `json:"message"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
ExecutedAt time.Time `json:"executed_at"`
|
||||
}
|
||||
|
||||
// SubmitEnterpriseInfoCommand 提交企业信息命令
|
||||
type SubmitEnterpriseInfoCommand struct {
|
||||
CertificationID string `json:"certification_id"`
|
||||
UserID string `json:"user_id"`
|
||||
EnterpriseInfo *value_objects.EnterpriseInfo `json:"enterprise_info"`
|
||||
UserID string `json:"user_id"`
|
||||
EnterpriseInfo *value_objects.EnterpriseInfo `json:"enterprise_info"`
|
||||
}
|
||||
|
||||
// 完成企业认证命令
|
||||
type CompleteEnterpriseVerificationCommand struct {
|
||||
AuthFlowId string `json:"auth_flow_id"`
|
||||
}
|
||||
|
||||
// ApplyContractCommand 申请合同命令
|
||||
@@ -39,16 +43,19 @@ type ApplyContractCommand struct {
|
||||
|
||||
// EsignCallbackCommand e签宝回调命令
|
||||
type EsignCallbackCommand struct {
|
||||
CertificationID string `json:"certification_id"`
|
||||
CallbackType string `json:"callback_type"` // "auth_result" | "sign_result" | "flow_status"
|
||||
CallbackData *state_machine.EsignCallbackData `json:"callback_data"`
|
||||
CertificationID string `json:"certification_id"`
|
||||
CallbackType string `json:"callback_type"` // "auth_result" | "sign_result" | "flow_status"
|
||||
}
|
||||
|
||||
// CertificationWorkflowOrchestrator 认证工作流编排器接口
|
||||
// 负责编排认证业务流程,协调各个领域服务的协作
|
||||
type CertificationWorkflowOrchestrator interface {
|
||||
// 用户操作用例
|
||||
// 提交企业信息
|
||||
SubmitEnterpriseInfo(ctx context.Context, cmd *SubmitEnterpriseInfoCommand) (*WorkflowResult, error)
|
||||
// 完成企业认证
|
||||
CompleteEnterpriseVerification(ctx context.Context, cmd *CompleteEnterpriseVerificationCommand) (*WorkflowResult, error)
|
||||
// 申请合同签署
|
||||
ApplyContract(ctx context.Context, cmd *ApplyContractCommand) (*WorkflowResult, error)
|
||||
|
||||
// e签宝回调处理
|
||||
@@ -57,90 +64,170 @@ type CertificationWorkflowOrchestrator interface {
|
||||
|
||||
// 异常处理
|
||||
HandleFailure(ctx context.Context, certificationID string, failureType string, reason string) (*WorkflowResult, error)
|
||||
RetryOperation(ctx context.Context, certificationID string, operation string) (*WorkflowResult, error)
|
||||
|
||||
// 查询操作
|
||||
GetCertification(ctx context.Context, userID string) (*WorkflowResult, error)
|
||||
GetWorkflowStatus(ctx context.Context, certificationID string) (*WorkflowResult, error)
|
||||
}
|
||||
|
||||
// CertificationWorkflowOrchestratorImpl 认证工作流编排器实现
|
||||
type CertificationWorkflowOrchestratorImpl struct {
|
||||
aggregateService CertificationAggregateService
|
||||
callbackHandler *state_machine.EsignCallbackHandler
|
||||
logger *zap.Logger
|
||||
esignClient *esign.Client
|
||||
}
|
||||
|
||||
// NewCertificationWorkflowOrchestrator 创建认证工作流编排器
|
||||
func NewCertificationWorkflowOrchestrator(
|
||||
aggregateService CertificationAggregateService,
|
||||
callbackHandler *state_machine.EsignCallbackHandler,
|
||||
logger *zap.Logger,
|
||||
esignClient *esign.Client,
|
||||
) CertificationWorkflowOrchestrator {
|
||||
return &CertificationWorkflowOrchestratorImpl{
|
||||
aggregateService: aggregateService,
|
||||
callbackHandler: callbackHandler,
|
||||
logger: logger,
|
||||
esignClient: esignClient,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 用户操作用例 ================
|
||||
|
||||
// GetCertification 获取认证详情
|
||||
func (o *CertificationWorkflowOrchestratorImpl) GetCertification(
|
||||
ctx context.Context,
|
||||
userID string,
|
||||
) (*WorkflowResult, error) {
|
||||
exists, err := o.aggregateService.ExistsByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
o.logger.Error("获取认证信息失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取认证信息失败: %w", err)
|
||||
}
|
||||
var cert *entities.Certification
|
||||
if !exists {
|
||||
cert, err = o.aggregateService.CreateCertification(ctx, userID)
|
||||
if err != nil {
|
||||
o.logger.Error("创建认证信息失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("创建认证信息失败: %w", err)
|
||||
}
|
||||
} else {
|
||||
cert, err = o.aggregateService.LoadCertificationByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
o.logger.Error("获取认证信息失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("认证信息不存在: %w", err)
|
||||
}
|
||||
}
|
||||
meta := cert.GetDataByStatus()
|
||||
return o.createSuccessResult(userID, cert.Status, "获取认证信息成功", meta), nil
|
||||
}
|
||||
|
||||
// SubmitEnterpriseInfo 用户提交企业信息
|
||||
func (o *CertificationWorkflowOrchestratorImpl) SubmitEnterpriseInfo(
|
||||
ctx context.Context,
|
||||
cmd *SubmitEnterpriseInfoCommand,
|
||||
) (*WorkflowResult, error) {
|
||||
o.logger.Info("开始处理企业信息提交",
|
||||
zap.String("certification_id", cmd.CertificationID),
|
||||
zap.String("user_id", cmd.UserID))
|
||||
|
||||
// 1. 验证命令完整性
|
||||
if err := o.validateSubmitEnterpriseInfoCommand(cmd); err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("命令验证失败: %s", err.Error())), err
|
||||
// 1. 检查用户认证是否存在
|
||||
exists, err := o.aggregateService.ExistsByUserID(ctx, cmd.UserID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.UserID, "", fmt.Sprintf("检查用户认证是否存在失败: %s", err.Error())), err
|
||||
}
|
||||
if !exists {
|
||||
// 创建
|
||||
_, err := o.aggregateService.CreateCertification(ctx, cmd.UserID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.UserID, "", fmt.Sprintf("创建认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
}
|
||||
// 1.1 验证企业信息
|
||||
err = cmd.EnterpriseInfo.Validate()
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.UserID, "", fmt.Sprintf("企业信息验证失败: %s", err.Error())), err
|
||||
}
|
||||
|
||||
// 2. 加载认证聚合根
|
||||
cert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
cert, err := o.aggregateService.LoadCertificationByUserID(ctx, cmd.UserID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
return o.createFailureResult(cmd.UserID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
|
||||
// 3. 验证业务前置条件
|
||||
// 3. 验证业务前置条件(暂时没啥用,后面的都会校验)
|
||||
if err := o.validateEnterpriseInfoSubmissionPreconditions(cert, cmd.UserID); err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status, err.Error()), err
|
||||
return o.createFailureResult(cmd.UserID, cert.Status, err.Error()), err
|
||||
}
|
||||
|
||||
// 4. 执行状态转换
|
||||
metadata := map[string]interface{}{
|
||||
"enterprise_info": cmd.EnterpriseInfo,
|
||||
"user_id": cmd.UserID,
|
||||
// 5. 调用e签宝看是否进行过认证
|
||||
respMeta := map[string]interface{}{}
|
||||
|
||||
identity, err := o.esignClient.QueryOrgIdentityInfo(&esign.QueryOrgIdentityRequest{
|
||||
OrgName: cmd.EnterpriseInfo.CompanyName,
|
||||
})
|
||||
if identity != nil && identity.Data.RealnameStatus == 1 {
|
||||
o.logger.Info("企业认证成功", zap.Any("identity", identity))
|
||||
err = cert.CompleteEnterpriseVerification()
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.UserID, cert.Status, err.Error()), err
|
||||
}
|
||||
respMeta = map[string]interface{}{
|
||||
"enterprise_info": cmd.EnterpriseInfo,
|
||||
"next_action": "企业已认证,可进行后续操作",
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
o.logger.Error("e签宝查询企业认证信息失败或未进行企业认证", zap.Error(err))
|
||||
}
|
||||
authURL, err := o.esignClient.GenerateEnterpriseAuth(&esign.EnterpriseAuthRequest{
|
||||
CompanyName: cmd.EnterpriseInfo.CompanyName,
|
||||
UnifiedSocialCode: cmd.EnterpriseInfo.UnifiedSocialCode,
|
||||
LegalPersonName: cmd.EnterpriseInfo.LegalPersonName,
|
||||
LegalPersonID: cmd.EnterpriseInfo.LegalPersonID,
|
||||
TransactorName: cmd.EnterpriseInfo.LegalPersonName,
|
||||
TransactorMobile: cmd.EnterpriseInfo.LegalPersonPhone,
|
||||
TransactorID: cmd.EnterpriseInfo.LegalPersonID,
|
||||
})
|
||||
if err != nil {
|
||||
o.logger.Error("生成企业认证链接失败", zap.Error(err))
|
||||
return o.createFailureResult(cmd.UserID, cert.Status, err.Error()), err
|
||||
}
|
||||
err = cert.SubmitEnterpriseInfo(cmd.EnterpriseInfo, authURL.AuthShortURL, authURL.AuthFlowID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.UserID, cert.Status, err.Error()), err
|
||||
}
|
||||
respMeta = map[string]interface{}{
|
||||
"enterprise_info": cmd.EnterpriseInfo,
|
||||
"authUrl": authURL.AuthURL,
|
||||
"next_action": "请完成企业认证",
|
||||
}
|
||||
}
|
||||
|
||||
result, err := o.aggregateService.TransitionState(
|
||||
ctx,
|
||||
cmd.CertificationID,
|
||||
enums.StatusInfoSubmitted,
|
||||
enums.ActorTypeUser,
|
||||
cmd.UserID,
|
||||
"用户提交企业信息",
|
||||
metadata,
|
||||
)
|
||||
err = o.aggregateService.SaveCertification(ctx, cert)
|
||||
if err != nil {
|
||||
o.logger.Error("企业信息提交状态转换失败", zap.Error(err))
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status, fmt.Sprintf("状态转换失败: %s", err.Error())), err
|
||||
}
|
||||
|
||||
// 5. 执行后续处理(如调用e签宝API)
|
||||
if err := o.triggerEnterpriseVerification(ctx, cmd.CertificationID, cmd.EnterpriseInfo); err != nil {
|
||||
o.logger.Warn("触发企业认证失败", zap.Error(err))
|
||||
// 这里不返回错误,因为状态已经成功转换,e签宝调用失败可以通过重试机制处理
|
||||
return o.createFailureResult(cmd.UserID, cert.Status, err.Error()), err
|
||||
}
|
||||
|
||||
// 6. 构建成功结果
|
||||
return o.createSuccessResult(cmd.CertificationID, enums.StatusInfoSubmitted, "企业信息提交成功", map[string]interface{}{
|
||||
"enterprise_info": cmd.EnterpriseInfo,
|
||||
"next_action": "等待企业认证结果",
|
||||
}, result), nil
|
||||
return o.createSuccessResult(cmd.UserID, enums.StatusInfoSubmitted, "企业信息提交成功", respMeta), nil
|
||||
}
|
||||
|
||||
// CompleteEnterpriseVerification 完成企业认证
|
||||
func (o *CertificationWorkflowOrchestratorImpl) CompleteEnterpriseVerification(
|
||||
ctx context.Context,
|
||||
cmd *CompleteEnterpriseVerificationCommand,
|
||||
) (*WorkflowResult, error) {
|
||||
cert, err := o.aggregateService.LoadCertificationByAuthFlowId(ctx, cmd.AuthFlowId)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.AuthFlowId, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
err = cert.CompleteEnterpriseVerification()
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.AuthFlowId, "", fmt.Sprintf("完成企业认证失败: %s", err.Error())), err
|
||||
}
|
||||
err = o.aggregateService.SaveCertification(ctx, cert)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.AuthFlowId, "", fmt.Sprintf("保存认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
o.logger.Info("完成企业认证", zap.String("certification_id", cert.ID))
|
||||
return o.createSuccessResult(cmd.AuthFlowId, enums.StatusEnterpriseVerified, "企业认证成功", map[string]interface{}{}), nil
|
||||
}
|
||||
|
||||
// ApplyContract 用户申请合同签署
|
||||
@@ -148,55 +235,56 @@ func (o *CertificationWorkflowOrchestratorImpl) ApplyContract(
|
||||
ctx context.Context,
|
||||
cmd *ApplyContractCommand,
|
||||
) (*WorkflowResult, error) {
|
||||
o.logger.Info("开始处理合同申请",
|
||||
zap.String("certification_id", cmd.CertificationID),
|
||||
zap.String("user_id", cmd.UserID))
|
||||
return nil, nil
|
||||
// o.logger.Info("开始处理合同申请",
|
||||
// zap.String("certification_id", cmd.CertificationID),
|
||||
// zap.String("user_id", cmd.UserID))
|
||||
|
||||
// 1. 验证命令完整性
|
||||
if err := o.validateApplyContractCommand(cmd); err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("命令验证失败: %s", err.Error())), err
|
||||
}
|
||||
// // 1. 验证命令完整性
|
||||
// if err := o.validateApplyContractCommand(cmd); err != nil {
|
||||
// return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("命令验证失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 2. 加载认证聚合根
|
||||
cert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
// // 2. 加载认证聚合根
|
||||
// cert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
// if err != nil {
|
||||
// return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 3. 验证业务前置条件
|
||||
if err := o.validateContractApplicationPreconditions(cert, cmd.UserID); err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status, err.Error()), err
|
||||
}
|
||||
// // 3. 验证业务前置条件
|
||||
// if err := o.validateContractApplicationPreconditions(cert, cmd.UserID); err != nil {
|
||||
// return o.createFailureResult(cmd.CertificationID, cert.Status, err.Error()), err
|
||||
// }
|
||||
|
||||
// 4. 执行状态转换
|
||||
result, err := o.aggregateService.TransitionState(
|
||||
ctx,
|
||||
cmd.CertificationID,
|
||||
enums.StatusContractApplied,
|
||||
enums.ActorTypeUser,
|
||||
cmd.UserID,
|
||||
"用户申请合同签署",
|
||||
map[string]interface{}{},
|
||||
)
|
||||
if err != nil {
|
||||
o.logger.Error("合同申请状态转换失败", zap.Error(err))
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status, fmt.Sprintf("状态转换失败: %s", err.Error())), err
|
||||
}
|
||||
// // 4. 执行状态转换
|
||||
// result, err := o.aggregateService.TransitionState(
|
||||
// ctx,
|
||||
// cmd.CertificationID,
|
||||
// enums.StatusContractApplied,
|
||||
// enums.ActorTypeUser,
|
||||
// cmd.UserID,
|
||||
// "用户申请合同签署",
|
||||
// map[string]interface{}{},
|
||||
// )
|
||||
// if err != nil {
|
||||
// o.logger.Error("合同申请状态转换失败", zap.Error(err))
|
||||
// return o.createFailureResult(cmd.CertificationID, cert.Status, fmt.Sprintf("状态转换失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 5. 生成合同和签署链接
|
||||
contractInfo, err := o.generateContractAndSignURL(ctx, cmd.CertificationID, cert)
|
||||
if err != nil {
|
||||
o.logger.Error("生成合同失败", zap.Error(err))
|
||||
// 需要回滚状态
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status, fmt.Sprintf("生成合同失败: %s", err.Error())), err
|
||||
}
|
||||
// // 5. 生成合同和签署链接
|
||||
// contractInfo, err := o.generateContractAndSignURL(ctx, cmd.CertificationID, cert)
|
||||
// if err != nil {
|
||||
// o.logger.Error("生成合同失败", zap.Error(err))
|
||||
// // 需要回滚状态
|
||||
// return o.createFailureResult(cmd.CertificationID, cert.Status, fmt.Sprintf("生成合同失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 6. 构建成功结果
|
||||
return o.createSuccessResult(cmd.CertificationID, enums.StatusContractApplied, "合同申请成功", map[string]interface{}{
|
||||
"contract_sign_url": contractInfo.ContractSignURL,
|
||||
"contract_url": contractInfo.ContractURL,
|
||||
"next_action": "请在规定时间内完成合同签署",
|
||||
}, result), nil
|
||||
// // 6. 构建成功结果
|
||||
// return o.createSuccessResult(cmd.CertificationID, enums.StatusContractApplied, "合同申请成功", map[string]interface{}{
|
||||
// "contract_sign_url": contractInfo.ContractSignURL,
|
||||
// "contract_url": contractInfo.ContractURL,
|
||||
// "next_action": "请在规定时间内完成合同签署",
|
||||
// }, result), nil
|
||||
}
|
||||
|
||||
// ================ e签宝回调处理 ================
|
||||
@@ -209,56 +297,56 @@ func (o *CertificationWorkflowOrchestratorImpl) HandleEnterpriseVerificationCall
|
||||
o.logger.Info("开始处理企业认证回调",
|
||||
zap.String("certification_id", cmd.CertificationID),
|
||||
zap.String("callback_type", cmd.CallbackType))
|
||||
return nil, nil
|
||||
// // 1. 验证回调数据
|
||||
// if err := o.callbackHandler.ValidateCallbackData(cmd.CallbackData); err != nil {
|
||||
// return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("回调数据验证失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 1. 验证回调数据
|
||||
if err := o.callbackHandler.ValidateCallbackData(cmd.CallbackData); err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("回调数据验证失败: %s", err.Error())), err
|
||||
}
|
||||
// // 2. 加载认证聚合根
|
||||
// cert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
// if err != nil {
|
||||
// return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 2. 加载认证聚合根
|
||||
cert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
// // 3. 验证回调处理前置条件
|
||||
// if cert.Status != enums.StatusInfoSubmitted {
|
||||
// return o.createFailureResult(cmd.CertificationID, cert.Status,
|
||||
// fmt.Sprintf("当前状态 %s 不允许处理企业认证回调", enums.GetStatusName(cert.Status))),
|
||||
// fmt.Errorf("无效的状态转换")
|
||||
// }
|
||||
|
||||
// 3. 验证回调处理前置条件
|
||||
if cert.Status != enums.StatusInfoSubmitted {
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status,
|
||||
fmt.Sprintf("当前状态 %s 不允许处理企业认证回调", enums.GetStatusName(cert.Status))),
|
||||
fmt.Errorf("无效的状态转换")
|
||||
}
|
||||
// // 4. 处理回调
|
||||
// err = o.callbackHandler.HandleCallback(ctx, cmd.CertificationID, cmd.CallbackData)
|
||||
// if err != nil {
|
||||
// o.logger.Error("处理企业认证回调失败", zap.Error(err))
|
||||
// return o.createFailureResult(cmd.CertificationID, cert.Status, fmt.Sprintf("回调处理失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 4. 处理回调
|
||||
err = o.callbackHandler.HandleCallback(ctx, cmd.CertificationID, cmd.CallbackData)
|
||||
if err != nil {
|
||||
o.logger.Error("处理企业认证回调失败", zap.Error(err))
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status, fmt.Sprintf("回调处理失败: %s", err.Error())), err
|
||||
}
|
||||
// // 5. 重新加载认证信息获取最新状态
|
||||
// updatedCert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
// if err != nil {
|
||||
// return o.createFailureResult(cmd.CertificationID, cert.Status, "加载更新后的认证信息失败"), err
|
||||
// }
|
||||
|
||||
// 5. 重新加载认证信息获取最新状态
|
||||
updatedCert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status, "加载更新后的认证信息失败"), err
|
||||
}
|
||||
// // 6. 构建结果
|
||||
// message := "企业认证回调处理成功"
|
||||
// data := map[string]interface{}{
|
||||
// "auth_flow_id": cmd.CallbackData.FlowID,
|
||||
// "status": cmd.CallbackData.Status,
|
||||
// }
|
||||
|
||||
// 6. 构建结果
|
||||
message := "企业认证回调处理成功"
|
||||
data := map[string]interface{}{
|
||||
"auth_flow_id": cmd.CallbackData.FlowID,
|
||||
"status": cmd.CallbackData.Status,
|
||||
}
|
||||
// if updatedCert.Status == enums.StatusEnterpriseVerified {
|
||||
// message = "企业认证成功"
|
||||
// data["next_action"] = "可以申请合同签署"
|
||||
// } else if updatedCert.Status == enums.StatusInfoRejected {
|
||||
// message = "企业认证失败"
|
||||
// data["next_action"] = "请修正企业信息后重新提交"
|
||||
// data["failure_reason"] = enums.GetFailureReasonName(updatedCert.FailureReason)
|
||||
// data["failure_message"] = updatedCert.FailureMessage
|
||||
// }
|
||||
|
||||
if updatedCert.Status == enums.StatusEnterpriseVerified {
|
||||
message = "企业认证成功"
|
||||
data["next_action"] = "可以申请合同签署"
|
||||
} else if updatedCert.Status == enums.StatusInfoRejected {
|
||||
message = "企业认证失败"
|
||||
data["next_action"] = "请修正企业信息后重新提交"
|
||||
data["failure_reason"] = enums.GetFailureReasonName(updatedCert.FailureReason)
|
||||
data["failure_message"] = updatedCert.FailureMessage
|
||||
}
|
||||
|
||||
return o.createSuccessResult(cmd.CertificationID, updatedCert.Status, message, data, nil), nil
|
||||
// return o.createSuccessResult(cmd.CertificationID, updatedCert.Status, message, data, nil), nil
|
||||
}
|
||||
|
||||
// HandleContractSignCallback 处理合同签署回调
|
||||
@@ -270,56 +358,58 @@ func (o *CertificationWorkflowOrchestratorImpl) HandleContractSignCallback(
|
||||
zap.String("certification_id", cmd.CertificationID),
|
||||
zap.String("callback_type", cmd.CallbackType))
|
||||
|
||||
// 1. 验证回调数据
|
||||
if err := o.callbackHandler.ValidateCallbackData(cmd.CallbackData); err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("回调数据验证失败: %s", err.Error())), err
|
||||
}
|
||||
// // 1. 验证回调数据
|
||||
// if err := o.callbackHandler.ValidateCallbackData(cmd.CallbackData); err != nil {
|
||||
// return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("回调数据验证失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 2. 加载认证聚合根
|
||||
cert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
// // 2. 加载认证聚合根
|
||||
// cert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
// if err != nil {
|
||||
// return o.createFailureResult(cmd.CertificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 3. 验证回调处理前置条件
|
||||
if cert.Status != enums.StatusContractApplied {
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status,
|
||||
fmt.Sprintf("当前状态 %s 不允许处理合同签署回调", enums.GetStatusName(cert.Status))),
|
||||
fmt.Errorf("无效的状态转换")
|
||||
}
|
||||
// // 3. 验证回调处理前置条件
|
||||
// if cert.Status != enums.StatusContractApplied {
|
||||
// return o.createFailureResult(cmd.CertificationID, cert.Status,
|
||||
// fmt.Sprintf("当前状态 %s 不允许处理合同签署回调", enums.GetStatusName(cert.Status))),
|
||||
// fmt.Errorf("无效的状态转换")
|
||||
// }
|
||||
|
||||
// 4. 处理回调
|
||||
err = o.callbackHandler.HandleCallback(ctx, cmd.CertificationID, cmd.CallbackData)
|
||||
if err != nil {
|
||||
o.logger.Error("处理合同签署回调失败", zap.Error(err))
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status, fmt.Sprintf("回调处理失败: %s", err.Error())), err
|
||||
}
|
||||
// // 4. 处理回调
|
||||
// err = o.callbackHandler.HandleCallback(ctx, cmd.CertificationID, cmd.CallbackData)
|
||||
// if err != nil {
|
||||
// o.logger.Error("处理合同签署回调失败", zap.Error(err))
|
||||
// return o.createFailureResult(cmd.CertificationID, cert.Status, fmt.Sprintf("回调处理失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 5. 重新加载认证信息获取最新状态
|
||||
updatedCert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(cmd.CertificationID, cert.Status, "加载更新后的认证信息失败"), err
|
||||
}
|
||||
// // 5. 重新加载认证信息获取最新状态
|
||||
// updatedCert, err := o.aggregateService.LoadCertification(ctx, cmd.CertificationID)
|
||||
// if err != nil {
|
||||
// return o.createFailureResult(cmd.CertificationID, cert.Status, "加载更新后的认证信息失败"), err
|
||||
// }
|
||||
|
||||
// 6. 构建结果
|
||||
message := "合同签署回调处理成功"
|
||||
data := map[string]interface{}{
|
||||
"esign_flow_id": cmd.CallbackData.FlowID,
|
||||
"status": cmd.CallbackData.Status,
|
||||
}
|
||||
// // 6. 构建结果
|
||||
// message := "合同签署回调处理成功"
|
||||
// data := map[string]interface{}{
|
||||
// "esign_flow_id": cmd.CallbackData.FlowID,
|
||||
// "status": cmd.CallbackData.Status,
|
||||
// }
|
||||
|
||||
if updatedCert.Status == enums.StatusContractSigned {
|
||||
message = "认证完成"
|
||||
data["next_action"] = "认证流程已完成"
|
||||
data["contract_url"] = updatedCert.ContractURL
|
||||
} else if enums.IsFailureStatus(updatedCert.Status) {
|
||||
message = "合同签署失败"
|
||||
data["next_action"] = "可以重新申请合同签署"
|
||||
data["failure_reason"] = enums.GetFailureReasonName(updatedCert.FailureReason)
|
||||
data["failure_message"] = updatedCert.FailureMessage
|
||||
}
|
||||
// if updatedCert.Status == enums.StatusContractSigned {
|
||||
// message = "认证完成"
|
||||
// data["next_action"] = "认证流程已完成"
|
||||
// data["contract_url"] = updatedCert.ContractURL
|
||||
// } else if enums.IsFailureStatus(updatedCert.Status) {
|
||||
// message = "合同签署失败"
|
||||
// data["next_action"] = "可以重新申请合同签署"
|
||||
// data["failure_reason"] = enums.GetFailureReasonName(updatedCert.FailureReason)
|
||||
// data["failure_message"] = updatedCert.FailureMessage
|
||||
// }
|
||||
|
||||
// return o.createSuccessResult(cmd.CertificationID, updatedCert.Status, message, data, nil), nil
|
||||
return nil, nil
|
||||
|
||||
return o.createSuccessResult(cmd.CertificationID, updatedCert.Status, message, data, nil), nil
|
||||
}
|
||||
|
||||
// ================ 异常处理 ================
|
||||
@@ -331,138 +421,61 @@ func (o *CertificationWorkflowOrchestratorImpl) HandleFailure(
|
||||
failureType string,
|
||||
reason string,
|
||||
) (*WorkflowResult, error) {
|
||||
o.logger.Info("开始处理业务失败",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("failure_type", failureType),
|
||||
zap.String("reason", reason))
|
||||
return nil, nil
|
||||
// o.logger.Info("开始处理业务失败",
|
||||
// zap.String("certification_id", certificationID),
|
||||
// zap.String("failure_type", failureType),
|
||||
// zap.String("reason", reason))
|
||||
|
||||
// 1. 加载认证聚合根
|
||||
cert, err := o.aggregateService.LoadCertification(ctx, certificationID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(certificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
// // 1. 加载认证聚合根
|
||||
// cert, err := o.aggregateService.LoadCertification(ctx, certificationID)
|
||||
// if err != nil {
|
||||
// return o.createFailureResult(certificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
// 2. 根据失败类型执行相应处理
|
||||
var targetStatus enums.CertificationStatus
|
||||
var failureReason enums.FailureReason
|
||||
// // 2. 根据失败类型执行相应处理
|
||||
// var targetStatus enums.CertificationStatus
|
||||
// var failureReason enums.FailureReason
|
||||
|
||||
switch failureType {
|
||||
case "enterprise_verification_failed":
|
||||
targetStatus = enums.StatusInfoRejected
|
||||
failureReason = enums.FailureReasonEsignVerificationFailed
|
||||
case "contract_sign_failed":
|
||||
targetStatus = enums.StatusContractRejected
|
||||
failureReason = enums.FailureReasonSignProcessFailed
|
||||
case "contract_expired":
|
||||
targetStatus = enums.StatusContractExpired
|
||||
failureReason = enums.FailureReasonContractExpired
|
||||
default:
|
||||
return o.createFailureResult(certificationID, cert.Status, fmt.Sprintf("未知的失败类型: %s", failureType)),
|
||||
fmt.Errorf("未知的失败类型")
|
||||
}
|
||||
// switch failureType {
|
||||
// case "enterprise_verification_failed":
|
||||
// targetStatus = enums.StatusInfoRejected
|
||||
// failureReason = enums.FailureReasonEsignVerificationFailed
|
||||
// case "contract_sign_failed":
|
||||
// targetStatus = enums.StatusContractRejected
|
||||
// failureReason = enums.FailureReasonSignProcessFailed
|
||||
// case "contract_expired":
|
||||
// targetStatus = enums.StatusContractExpired
|
||||
// failureReason = enums.FailureReasonContractExpired
|
||||
// default:
|
||||
// return o.createFailureResult(certificationID, cert.Status, fmt.Sprintf("未知的失败类型: %s", failureType)),
|
||||
// fmt.Errorf("未知的失败类型")
|
||||
// }
|
||||
|
||||
// 3. 执行状态转换
|
||||
metadata := map[string]interface{}{
|
||||
"failure_reason": failureReason,
|
||||
"failure_message": reason,
|
||||
}
|
||||
// // 3. 执行状态转换
|
||||
// metadata := map[string]interface{}{
|
||||
// "failure_reason": failureReason,
|
||||
// "failure_message": reason,
|
||||
// }
|
||||
|
||||
result, err := o.aggregateService.TransitionState(
|
||||
ctx,
|
||||
certificationID,
|
||||
targetStatus,
|
||||
enums.ActorTypeSystem,
|
||||
"failure_handler",
|
||||
fmt.Sprintf("系统处理失败: %s", reason),
|
||||
metadata,
|
||||
)
|
||||
if err != nil {
|
||||
return o.createFailureResult(certificationID, cert.Status, fmt.Sprintf("失败处理状态转换失败: %s", err.Error())), err
|
||||
}
|
||||
// result, err := o.aggregateService.TransitionState(
|
||||
// ctx,
|
||||
// certificationID,
|
||||
// targetStatus,
|
||||
// enums.ActorTypeSystem,
|
||||
// "failure_handler",
|
||||
// fmt.Sprintf("系统处理失败: %s", reason),
|
||||
// metadata,
|
||||
// )
|
||||
// if err != nil {
|
||||
// return o.createFailureResult(certificationID, cert.Status, fmt.Sprintf("失败处理状态转换失败: %s", err.Error())), err
|
||||
// }
|
||||
|
||||
return o.createSuccessResult(certificationID, targetStatus, "失败处理完成", map[string]interface{}{
|
||||
"failure_type": failureType,
|
||||
"failure_reason": enums.GetFailureReasonName(failureReason),
|
||||
"can_retry": enums.IsRetryable(failureReason),
|
||||
}, result), nil
|
||||
}
|
||||
|
||||
// RetryOperation 重试操作
|
||||
func (o *CertificationWorkflowOrchestratorImpl) RetryOperation(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
operation string,
|
||||
) (*WorkflowResult, error) {
|
||||
o.logger.Info("开始重试操作",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("operation", operation))
|
||||
|
||||
// 1. 加载认证聚合根
|
||||
cert, err := o.aggregateService.LoadCertification(ctx, certificationID)
|
||||
if err != nil {
|
||||
return o.createFailureResult(certificationID, "", fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
|
||||
// 2. 检查是否可以重试
|
||||
if !enums.IsFailureStatus(cert.Status) {
|
||||
return o.createFailureResult(certificationID, cert.Status, "当前状态不是失败状态,无需重试"),
|
||||
fmt.Errorf("不需要重试")
|
||||
}
|
||||
|
||||
if !enums.IsRetryable(cert.FailureReason) {
|
||||
return o.createFailureResult(certificationID, cert.Status,
|
||||
fmt.Sprintf("失败原因 %s 不支持重试", enums.GetFailureReasonName(cert.FailureReason))),
|
||||
fmt.Errorf("不支持重试")
|
||||
}
|
||||
|
||||
if cert.RetryCount >= 3 {
|
||||
return o.createFailureResult(certificationID, cert.Status, "已达到最大重试次数限制"),
|
||||
fmt.Errorf("超过重试限制")
|
||||
}
|
||||
|
||||
// 3. 根据操作类型执行重试
|
||||
var targetStatus enums.CertificationStatus
|
||||
var reason string
|
||||
|
||||
switch operation {
|
||||
case "enterprise_verification":
|
||||
if cert.Status != enums.StatusInfoRejected {
|
||||
return o.createFailureResult(certificationID, cert.Status, "当前状态不支持企业认证重试"),
|
||||
fmt.Errorf("无效的重试操作")
|
||||
}
|
||||
targetStatus = enums.StatusInfoSubmitted
|
||||
reason = "重新提交企业信息"
|
||||
case "contract_application":
|
||||
if cert.Status != enums.StatusContractRejected && cert.Status != enums.StatusContractExpired {
|
||||
return o.createFailureResult(certificationID, cert.Status, "当前状态不支持合同申请重试"),
|
||||
fmt.Errorf("无效的重试操作")
|
||||
}
|
||||
targetStatus = enums.StatusEnterpriseVerified
|
||||
reason = "重置状态,准备重新申请合同"
|
||||
default:
|
||||
return o.createFailureResult(certificationID, cert.Status, fmt.Sprintf("不支持的重试操作: %s", operation)),
|
||||
fmt.Errorf("不支持的重试操作")
|
||||
}
|
||||
|
||||
// 4. 执行状态转换
|
||||
result, err := o.aggregateService.TransitionState(
|
||||
ctx,
|
||||
certificationID,
|
||||
targetStatus,
|
||||
enums.ActorTypeSystem,
|
||||
"retry_handler",
|
||||
reason,
|
||||
map[string]interface{}{},
|
||||
)
|
||||
if err != nil {
|
||||
return o.createFailureResult(certificationID, cert.Status, fmt.Sprintf("重试状态转换失败: %s", err.Error())), err
|
||||
}
|
||||
|
||||
return o.createSuccessResult(certificationID, targetStatus, "重试操作成功", map[string]interface{}{
|
||||
"retry_operation": operation,
|
||||
"retry_count": cert.RetryCount + 1,
|
||||
"next_action": o.getNextActionForStatus(targetStatus),
|
||||
}, result), nil
|
||||
// return o.createSuccessResult(certificationID, targetStatus, "失败处理完成", map[string]interface{}{
|
||||
// "failure_type": failureType,
|
||||
// "failure_reason": enums.GetFailureReasonName(failureReason),
|
||||
// "can_retry": enums.IsRetryable(failureReason),
|
||||
// }, result), nil
|
||||
}
|
||||
|
||||
// ================ 查询操作 ================
|
||||
@@ -512,25 +525,11 @@ func (o *CertificationWorkflowOrchestratorImpl) GetWorkflowStatus(
|
||||
data["contract_signed_at"] = cert.ContractSignedAt
|
||||
}
|
||||
|
||||
return o.createSuccessResult(certificationID, cert.Status, "工作流状态查询成功", data, nil), nil
|
||||
return o.createSuccessResult(certificationID, cert.Status, "工作流状态查询成功", data), nil
|
||||
}
|
||||
|
||||
// ================ 辅助方法 ================
|
||||
|
||||
// validateSubmitEnterpriseInfoCommand 验证提交企业信息命令
|
||||
func (o *CertificationWorkflowOrchestratorImpl) validateSubmitEnterpriseInfoCommand(cmd *SubmitEnterpriseInfoCommand) error {
|
||||
if cmd.CertificationID == "" {
|
||||
return fmt.Errorf("认证ID不能为空")
|
||||
}
|
||||
if cmd.UserID == "" {
|
||||
return fmt.Errorf("用户ID不能为空")
|
||||
}
|
||||
if cmd.EnterpriseInfo == nil {
|
||||
return fmt.Errorf("企业信息不能为空")
|
||||
}
|
||||
return cmd.EnterpriseInfo.Validate()
|
||||
}
|
||||
|
||||
// validateApplyContractCommand 验证申请合同命令
|
||||
func (o *CertificationWorkflowOrchestratorImpl) validateApplyContractCommand(cmd *ApplyContractCommand) error {
|
||||
if cmd.CertificationID == "" {
|
||||
@@ -606,7 +605,6 @@ func (o *CertificationWorkflowOrchestratorImpl) createSuccessResult(
|
||||
status enums.CertificationStatus,
|
||||
message string,
|
||||
data map[string]interface{},
|
||||
stateTransition *state_machine.StateTransitionResult,
|
||||
) *WorkflowResult {
|
||||
return &WorkflowResult{
|
||||
Success: true,
|
||||
@@ -614,7 +612,6 @@ func (o *CertificationWorkflowOrchestratorImpl) createSuccessResult(
|
||||
CurrentStatus: status,
|
||||
Message: message,
|
||||
Data: data,
|
||||
StateTransition: stateTransition,
|
||||
ExecutedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"tyapi-server/internal/config"
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/entities/value_objects"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/infrastructure/external/westdex"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// EnterpriseInfoSubmitRecordService 企业信息提交记录领域服务
|
||||
// 负责与westdex等外部服务交互
|
||||
// 领域服务应无状态
|
||||
|
||||
type EnterpriseInfoSubmitRecordService struct {
|
||||
westdexService *westdex.WestDexService
|
||||
repositories repositories.EnterpriseInfoSubmitRecordRepository
|
||||
appConfig config.AppConfig
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewEnterpriseInfoSubmitRecordService 构造函数
|
||||
func NewEnterpriseInfoSubmitRecordService(westdexService *westdex.WestDexService, repositories repositories.EnterpriseInfoSubmitRecordRepository, appConfig config.AppConfig, logger *zap.Logger) *EnterpriseInfoSubmitRecordService {
|
||||
return &EnterpriseInfoSubmitRecordService{
|
||||
westdexService: westdexService,
|
||||
repositories: repositories,
|
||||
appConfig: appConfig,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Save 保存企业信息提交记录
|
||||
func (s *EnterpriseInfoSubmitRecordService) Save(ctx context.Context, enterpriseInfoSubmitRecord *entities.EnterpriseInfoSubmitRecord) error {
|
||||
exists, err := s.repositories.Exists(ctx, enterpriseInfoSubmitRecord.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return s.repositories.Update(ctx, enterpriseInfoSubmitRecord)
|
||||
}
|
||||
return s.repositories.Create(ctx, enterpriseInfoSubmitRecord)
|
||||
}
|
||||
|
||||
// ValidateWithWestdex 调用westdexService验证企业信息
|
||||
func (s *EnterpriseInfoSubmitRecordService) ValidateWithWestdex(ctx context.Context, info *value_objects.EnterpriseInfo) error {
|
||||
if info == nil {
|
||||
return errors.New("企业信息不能为空")
|
||||
}
|
||||
// 先做本地校验
|
||||
if err := info.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 开发环境下跳过外部验证
|
||||
if s.appConfig.IsDevelopment() {
|
||||
s.logger.Info("开发环境:跳过企业信息外部验证",
|
||||
zap.String("company_name", info.CompanyName),
|
||||
zap.String("legal_person", info.LegalPersonName))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 调用westdexService进行外部校验
|
||||
reqParams := map[string]interface{}{
|
||||
"data": map[string]interface{}{
|
||||
"entname": info.CompanyName,
|
||||
"realname": info.LegalPersonName,
|
||||
"entmark": info.UnifiedSocialCode,
|
||||
"idcard": info.LegalPersonID,
|
||||
},
|
||||
}
|
||||
resp, err := s.westdexService.CallAPI("WEST00021", reqParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resultCode := gjson.GetBytes(resp, "code")
|
||||
if !resultCode.Exists() {
|
||||
return fmt.Errorf("校验企业信息错误")
|
||||
}
|
||||
if resultCode.String() != "00000" {
|
||||
return fmt.Errorf("校验企业信息错误")
|
||||
}
|
||||
|
||||
resultState := gjson.GetBytes(resp, "data.result.state")
|
||||
if !resultState.Exists() {
|
||||
return fmt.Errorf("校验企业信息错误")
|
||||
}
|
||||
if resultState.Int() != 1 {
|
||||
return fmt.Errorf("企业信息不一致")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"tyapi-server/internal/domains/certification/enums"
|
||||
)
|
||||
|
||||
// StateConfig 状态配置
|
||||
type StateConfig struct {
|
||||
Status enums.CertificationStatus `json:"status"`
|
||||
Name string `json:"name"`
|
||||
ProgressPercentage int `json:"progress_percentage"`
|
||||
IsUserActionRequired bool `json:"is_user_action_required"`
|
||||
IsAdminActionRequired bool `json:"is_admin_action_required"`
|
||||
TimestampField string `json:"timestamp_field,omitempty"`
|
||||
Description string `json:"description"`
|
||||
NextValidStatuses []enums.CertificationStatus `json:"next_valid_statuses"`
|
||||
}
|
||||
|
||||
// TransitionConfig 状态转换配置
|
||||
type TransitionConfig struct {
|
||||
From enums.CertificationStatus `json:"from"`
|
||||
To enums.CertificationStatus `json:"to"`
|
||||
Action string `json:"action"`
|
||||
ActionName string `json:"action_name"`
|
||||
AllowUser bool `json:"allow_user"`
|
||||
AllowAdmin bool `json:"allow_admin"`
|
||||
RequiresValidation bool `json:"requires_validation"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// CertificationStateManager 认证状态管理器
|
||||
type CertificationStateManager struct {
|
||||
stateMap map[enums.CertificationStatus]*StateConfig
|
||||
transitionMap map[enums.CertificationStatus][]*TransitionConfig
|
||||
}
|
||||
|
||||
// NewCertificationStateManager 创建认证状态管理器
|
||||
func NewCertificationStateManager() *CertificationStateManager {
|
||||
manager := &CertificationStateManager{
|
||||
stateMap: make(map[enums.CertificationStatus]*StateConfig),
|
||||
transitionMap: make(map[enums.CertificationStatus][]*TransitionConfig),
|
||||
}
|
||||
|
||||
// 初始化状态配置
|
||||
manager.initStateConfigs()
|
||||
return manager
|
||||
}
|
||||
|
||||
// initStateConfigs 初始化状态配置
|
||||
func (manager *CertificationStateManager) initStateConfigs() {
|
||||
// 状态配置
|
||||
states := []*StateConfig{
|
||||
{
|
||||
Status: enums.StatusPending,
|
||||
Name: "待认证",
|
||||
ProgressPercentage: 0,
|
||||
IsUserActionRequired: true,
|
||||
IsAdminActionRequired: false,
|
||||
Description: "等待用户提交企业信息",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusInfoSubmitted},
|
||||
},
|
||||
{
|
||||
Status: enums.StatusInfoSubmitted,
|
||||
Name: "已提交企业信息",
|
||||
ProgressPercentage: 20,
|
||||
IsUserActionRequired: true,
|
||||
IsAdminActionRequired: false,
|
||||
TimestampField: "InfoSubmittedAt",
|
||||
Description: "用户已提交企业信息",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusEnterpriseVerified, enums.StatusInfoSubmitted}, // 可以重新提交
|
||||
},
|
||||
{
|
||||
Status: enums.StatusEnterpriseVerified,
|
||||
Name: "已企业认证",
|
||||
ProgressPercentage: 40,
|
||||
IsUserActionRequired: true,
|
||||
IsAdminActionRequired: false,
|
||||
TimestampField: "EnterpriseVerifiedAt",
|
||||
Description: "企业认证已完成",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusContractApplied},
|
||||
},
|
||||
{
|
||||
Status: enums.StatusContractApplied,
|
||||
Name: "已申请合同",
|
||||
ProgressPercentage: 60,
|
||||
IsUserActionRequired: true,
|
||||
IsAdminActionRequired: false,
|
||||
TimestampField: "ContractAppliedAt",
|
||||
Description: "合同已申请",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusContractSigned},
|
||||
},
|
||||
{
|
||||
Status: enums.StatusContractSigned,
|
||||
Name: "已签署合同",
|
||||
ProgressPercentage: 80,
|
||||
IsUserActionRequired: false,
|
||||
IsAdminActionRequired: false,
|
||||
TimestampField: "ContractSignedAt",
|
||||
Description: "合同已签署",
|
||||
NextValidStatuses: []enums.CertificationStatus{},
|
||||
},
|
||||
// 已完成状态已合并到StatusContractSigned中
|
||||
}
|
||||
|
||||
// 转换配置
|
||||
transitions := []*TransitionConfig{
|
||||
// 提交企业信息
|
||||
{
|
||||
From: enums.StatusPending,
|
||||
To: enums.StatusInfoSubmitted,
|
||||
Action: "submit_info",
|
||||
ActionName: "提交企业信息",
|
||||
AllowUser: true,
|
||||
AllowAdmin: false,
|
||||
RequiresValidation: true,
|
||||
Description: "用户提交企业信息",
|
||||
},
|
||||
// 重新提交企业信息
|
||||
{
|
||||
From: enums.StatusInfoSubmitted,
|
||||
To: enums.StatusInfoSubmitted,
|
||||
Action: "resubmit_info",
|
||||
ActionName: "重新提交企业信息",
|
||||
AllowUser: true,
|
||||
AllowAdmin: false,
|
||||
RequiresValidation: true,
|
||||
Description: "用户重新提交企业信息",
|
||||
},
|
||||
// 企业认证
|
||||
{
|
||||
From: enums.StatusInfoSubmitted,
|
||||
To: enums.StatusEnterpriseVerified,
|
||||
Action: "enterprise_verify",
|
||||
ActionName: "企业认证",
|
||||
AllowUser: true,
|
||||
AllowAdmin: false,
|
||||
RequiresValidation: true,
|
||||
Description: "用户完成企业认证",
|
||||
},
|
||||
// 申请合同
|
||||
{
|
||||
From: enums.StatusEnterpriseVerified,
|
||||
To: enums.StatusContractApplied,
|
||||
Action: "apply_contract",
|
||||
ActionName: "申请合同",
|
||||
AllowUser: true,
|
||||
AllowAdmin: false,
|
||||
RequiresValidation: false,
|
||||
Description: "用户申请合同",
|
||||
},
|
||||
// 签署合同
|
||||
{
|
||||
From: enums.StatusContractApplied,
|
||||
To: enums.StatusContractSigned,
|
||||
Action: "sign_contract",
|
||||
ActionName: "签署合同",
|
||||
AllowUser: true,
|
||||
AllowAdmin: false,
|
||||
RequiresValidation: true,
|
||||
Description: "用户签署合同",
|
||||
},
|
||||
// 合同签署即为认证完成,无需额外状态转换
|
||||
}
|
||||
|
||||
// 构建映射
|
||||
for _, state := range states {
|
||||
manager.stateMap[state.Status] = state
|
||||
}
|
||||
|
||||
for _, transition := range transitions {
|
||||
manager.transitionMap[transition.From] = append(manager.transitionMap[transition.From], transition)
|
||||
}
|
||||
}
|
||||
|
||||
// GetStateConfig 获取状态配置
|
||||
func (manager *CertificationStateManager) GetStateConfig(status enums.CertificationStatus) *StateConfig {
|
||||
return manager.stateMap[status]
|
||||
}
|
||||
|
||||
// GetTransitionConfigs 获取状态转换配置
|
||||
func (manager *CertificationStateManager) GetTransitionConfigs(from enums.CertificationStatus) []*TransitionConfig {
|
||||
return manager.transitionMap[from]
|
||||
}
|
||||
|
||||
// CanTransition 检查是否可以转换
|
||||
func (manager *CertificationStateManager) CanTransition(from enums.CertificationStatus, to enums.CertificationStatus, isUser bool, isAdmin bool) (bool, string) {
|
||||
transitions := manager.GetTransitionConfigs(from)
|
||||
|
||||
for _, transition := range transitions {
|
||||
if transition.To == to {
|
||||
if isUser && !transition.AllowUser {
|
||||
return false, "用户不允许执行此操作"
|
||||
}
|
||||
if isAdmin && !transition.AllowAdmin {
|
||||
return false, "管理员不允许执行此操作"
|
||||
}
|
||||
if !isUser && !isAdmin && (transition.AllowUser || transition.AllowAdmin) {
|
||||
return false, "此操作需要用户或管理员权限"
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
}
|
||||
|
||||
return false, "不支持的状态转换"
|
||||
}
|
||||
|
||||
// GetProgressPercentage 获取进度百分比
|
||||
func (manager *CertificationStateManager) GetProgressPercentage(status enums.CertificationStatus) int {
|
||||
if stateConfig := manager.GetStateConfig(status); stateConfig != nil {
|
||||
return stateConfig.ProgressPercentage
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IsUserActionRequired 检查是否需要用户操作
|
||||
func (manager *CertificationStateManager) IsUserActionRequired(status enums.CertificationStatus) bool {
|
||||
if stateConfig := manager.GetStateConfig(status); stateConfig != nil {
|
||||
return stateConfig.IsUserActionRequired
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsAdminActionRequired 检查是否需要管理员操作
|
||||
func (manager *CertificationStateManager) IsAdminActionRequired(status enums.CertificationStatus) bool {
|
||||
if stateConfig := manager.GetStateConfig(status); stateConfig != nil {
|
||||
return stateConfig.IsAdminActionRequired
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetNextValidStatuses 获取下一个有效状态
|
||||
func (manager *CertificationStateManager) GetNextValidStatuses(status enums.CertificationStatus) []enums.CertificationStatus {
|
||||
if stateConfig := manager.GetStateConfig(status); stateConfig != nil {
|
||||
return stateConfig.NextValidStatuses
|
||||
}
|
||||
return []enums.CertificationStatus{}
|
||||
}
|
||||
@@ -1,455 +0,0 @@
|
||||
package state_machine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/enums"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// CertificationStateMachine 认证状态机
|
||||
// 负责管理认证流程的状态转换、业务规则验证和事件发布
|
||||
type CertificationStateMachine struct {
|
||||
configManager *StateConfigManager
|
||||
repository repositories.CertificationCommandRepository
|
||||
eventPublisher interface{} // TODO: 使用 interfaces.EventPublisher
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewCertificationStateMachine 创建认证状态机
|
||||
func NewCertificationStateMachine(
|
||||
repository repositories.CertificationCommandRepository,
|
||||
eventPublisher interface{}, // TODO: 使用 interfaces.EventPublisher
|
||||
logger *zap.Logger,
|
||||
) *CertificationStateMachine {
|
||||
return &CertificationStateMachine{
|
||||
configManager: NewStateConfigManager(),
|
||||
repository: repository,
|
||||
eventPublisher: eventPublisher,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// StateTransitionRequest 状态转换请求
|
||||
type StateTransitionRequest struct {
|
||||
CertificationID string `json:"certification_id"`
|
||||
TargetStatus enums.CertificationStatus `json:"target_status"`
|
||||
Actor enums.ActorType `json:"actor"`
|
||||
ActorID string `json:"actor_id"`
|
||||
Reason string `json:"reason"`
|
||||
Context map[string]interface{} `json:"context"`
|
||||
AllowRollback bool `json:"allow_rollback"`
|
||||
}
|
||||
|
||||
// StateTransitionResult 状态转换结果
|
||||
type StateTransitionResult struct {
|
||||
Success bool `json:"success"`
|
||||
OldStatus enums.CertificationStatus `json:"old_status"`
|
||||
NewStatus enums.CertificationStatus `json:"new_status"`
|
||||
Message string `json:"message"`
|
||||
TransitionedAt time.Time `json:"transitioned_at"`
|
||||
Events []interface{} `json:"events,omitempty"`
|
||||
}
|
||||
|
||||
// CanTransition 检查是否可以执行状态转换
|
||||
func (sm *CertificationStateMachine) CanTransition(
|
||||
cert *entities.Certification,
|
||||
targetStatus enums.CertificationStatus,
|
||||
actor enums.ActorType,
|
||||
) (bool, string) {
|
||||
// 1. 检查基本状态转换规则
|
||||
canTransition, message := sm.configManager.CanTransition(cert.Status, targetStatus, actor)
|
||||
if !canTransition {
|
||||
return false, message
|
||||
}
|
||||
|
||||
// 2. 检查认证实体的业务规则
|
||||
if canTransition, message := cert.CanTransitionTo(targetStatus, actor); !canTransition {
|
||||
return false, message
|
||||
}
|
||||
|
||||
// 3. 检查是否为最终状态
|
||||
if cert.IsFinalStatus() {
|
||||
return false, "认证已完成,无法进行状态转换"
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// ExecuteTransition 执行状态转换
|
||||
func (sm *CertificationStateMachine) ExecuteTransition(
|
||||
ctx context.Context,
|
||||
req *StateTransitionRequest,
|
||||
) (*StateTransitionResult, error) {
|
||||
sm.logger.Info("开始执行状态转换",
|
||||
zap.String("certification_id", req.CertificationID),
|
||||
zap.String("target_status", string(req.TargetStatus)),
|
||||
zap.String("actor", string(req.Actor)),
|
||||
zap.String("actor_id", req.ActorID))
|
||||
|
||||
// 1. 加载认证聚合根
|
||||
cert, err := sm.loadCertification(ctx, req.CertificationID)
|
||||
if err != nil {
|
||||
return sm.createFailureResult(cert.Status, req.TargetStatus, fmt.Sprintf("加载认证信息失败: %s", err.Error())), err
|
||||
}
|
||||
|
||||
oldStatus := cert.Status
|
||||
|
||||
// 2. 验证转换合法性
|
||||
if canTransition, message := sm.CanTransition(cert, req.TargetStatus, req.Actor); !canTransition {
|
||||
return sm.createFailureResult(oldStatus, req.TargetStatus, message), fmt.Errorf("状态转换验证失败: %s", message)
|
||||
}
|
||||
|
||||
// 3. 验证业务规则
|
||||
if err := sm.validateBusinessRules(cert, req); err != nil {
|
||||
return sm.createFailureResult(oldStatus, req.TargetStatus, fmt.Sprintf("业务规则验证失败: %s", err.Error())), err
|
||||
}
|
||||
|
||||
// 4. 执行状态转换
|
||||
if err := cert.TransitionTo(req.TargetStatus, req.Actor, req.ActorID, req.Reason); err != nil {
|
||||
return sm.createFailureResult(oldStatus, req.TargetStatus, fmt.Sprintf("状态转换执行失败: %s", err.Error())), err
|
||||
}
|
||||
|
||||
// 5. 保存到数据库
|
||||
if err := sm.repository.Update(ctx, *cert); err != nil {
|
||||
// 如果保存失败,需要回滚状态
|
||||
sm.logger.Error("状态转换保存失败,尝试回滚",
|
||||
zap.String("certification_id", req.CertificationID),
|
||||
zap.Error(err))
|
||||
|
||||
if req.AllowRollback {
|
||||
if rollbackErr := sm.rollbackStateTransition(ctx, cert, oldStatus, req.Actor, req.ActorID); rollbackErr != nil {
|
||||
sm.logger.Error("状态回滚失败", zap.Error(rollbackErr))
|
||||
}
|
||||
}
|
||||
|
||||
return sm.createFailureResult(oldStatus, req.TargetStatus, fmt.Sprintf("保存状态转换失败: %s", err.Error())), err
|
||||
}
|
||||
|
||||
// 6. 发布领域事件
|
||||
events := cert.GetDomainEvents()
|
||||
for _, event := range events {
|
||||
// TODO: 实现事件发布
|
||||
// if err := sm.eventPublisher.PublishEvent(ctx, event); err != nil {
|
||||
// sm.logger.Error("发布领域事件失败",
|
||||
// zap.String("certification_id", req.CertificationID),
|
||||
// zap.Error(err))
|
||||
// }
|
||||
sm.logger.Info("领域事件待发布",
|
||||
zap.String("certification_id", req.CertificationID),
|
||||
zap.Any("event", event))
|
||||
}
|
||||
|
||||
// 7. 清理领域事件
|
||||
cert.ClearDomainEvents()
|
||||
|
||||
// 8. 记录成功日志
|
||||
sm.logger.Info("状态转换执行成功",
|
||||
zap.String("certification_id", req.CertificationID),
|
||||
zap.String("from_status", string(oldStatus)),
|
||||
zap.String("to_status", string(req.TargetStatus)),
|
||||
zap.String("actor", string(req.Actor)))
|
||||
|
||||
// 9. 返回成功结果
|
||||
return &StateTransitionResult{
|
||||
Success: true,
|
||||
OldStatus: oldStatus,
|
||||
NewStatus: req.TargetStatus,
|
||||
Message: "状态转换成功",
|
||||
TransitionedAt: time.Now(),
|
||||
Events: events,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetValidTransitions 获取有效的状态转换
|
||||
func (sm *CertificationStateMachine) GetValidTransitions(
|
||||
cert *entities.Certification,
|
||||
actor enums.ActorType,
|
||||
) []*StateTransitionRule {
|
||||
return sm.configManager.GetAllowedTransitions(cert.Status, actor)
|
||||
}
|
||||
|
||||
// GetStateInfo 获取状态信息
|
||||
func (sm *CertificationStateMachine) GetStateInfo(status enums.CertificationStatus) *StateConfig {
|
||||
return sm.configManager.GetStateConfig(status)
|
||||
}
|
||||
|
||||
// ValidateBusinessRules 验证业务规则
|
||||
func (sm *CertificationStateMachine) ValidateBusinessRules(
|
||||
cert *entities.Certification,
|
||||
req *StateTransitionRequest,
|
||||
) error {
|
||||
return sm.validateBusinessRules(cert, req)
|
||||
}
|
||||
|
||||
// IsUserActionRequired 检查是否需要用户操作
|
||||
func (sm *CertificationStateMachine) IsUserActionRequired(status enums.CertificationStatus) bool {
|
||||
return sm.configManager.IsUserActionRequired(status)
|
||||
}
|
||||
|
||||
// GetProgressPercentage 获取进度百分比
|
||||
func (sm *CertificationStateMachine) GetProgressPercentage(status enums.CertificationStatus) int {
|
||||
return sm.configManager.GetStateProgress(status)
|
||||
}
|
||||
|
||||
// ================ 私有方法 ================
|
||||
|
||||
// loadCertification 加载认证聚合根
|
||||
func (sm *CertificationStateMachine) loadCertification(ctx context.Context, certificationID string) (*entities.Certification, error) {
|
||||
// 这里需要通过查询仓储获取认证信息
|
||||
// 由于当前只有命令仓储,这里使用简单的方法
|
||||
// 在实际实现中,应该使用查询仓储
|
||||
cert := &entities.Certification{ID: certificationID}
|
||||
|
||||
// TODO: 实现从查询仓储加载认证信息
|
||||
// cert, err := sm.queryRepository.GetByID(ctx, certificationID)
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("认证信息不存在: %w", err)
|
||||
// }
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// validateBusinessRules 验证业务规则
|
||||
func (sm *CertificationStateMachine) validateBusinessRules(
|
||||
cert *entities.Certification,
|
||||
req *StateTransitionRequest,
|
||||
) error {
|
||||
// 获取转换规则
|
||||
rule := sm.configManager.GetTransitionRule(cert.Status, req.TargetStatus)
|
||||
if rule == nil {
|
||||
return fmt.Errorf("找不到状态转换规则")
|
||||
}
|
||||
|
||||
// 如果不需要验证,直接返回
|
||||
if !rule.RequiresValidation {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 构建验证上下文
|
||||
context := make(map[string]interface{})
|
||||
|
||||
// 添加认证基本信息
|
||||
context["certification_id"] = cert.ID
|
||||
context["user_id"] = cert.UserID
|
||||
context["current_status"] = string(cert.Status)
|
||||
context["retry_count"] = cert.RetryCount
|
||||
context["auth_flow_id"] = cert.AuthFlowID
|
||||
|
||||
// 添加请求中的上下文信息
|
||||
for key, value := range req.Context {
|
||||
context[key] = value
|
||||
}
|
||||
|
||||
// 执行业务规则验证
|
||||
return sm.configManager.ValidateBusinessRules(rule, context)
|
||||
}
|
||||
|
||||
// rollbackStateTransition 回滚状态转换
|
||||
func (sm *CertificationStateMachine) rollbackStateTransition(
|
||||
ctx context.Context,
|
||||
cert *entities.Certification,
|
||||
originalStatus enums.CertificationStatus,
|
||||
actor enums.ActorType,
|
||||
actorID string,
|
||||
) error {
|
||||
sm.logger.Info("开始回滚状态转换",
|
||||
zap.String("certification_id", cert.ID),
|
||||
zap.String("original_status", string(originalStatus)),
|
||||
zap.String("current_status", string(cert.Status)))
|
||||
|
||||
// 直接设置回原状态(跳过业务规则验证)
|
||||
cert.Status = originalStatus
|
||||
|
||||
// 更新审计信息
|
||||
now := time.Now()
|
||||
cert.LastTransitionAt = &now
|
||||
cert.LastTransitionBy = actor
|
||||
cert.LastTransitionActor = actorID
|
||||
|
||||
// 保存回滚结果
|
||||
if err := sm.repository.Update(ctx, *cert); err != nil {
|
||||
return fmt.Errorf("保存回滚状态失败: %w", err)
|
||||
}
|
||||
|
||||
sm.logger.Info("状态转换回滚成功",
|
||||
zap.String("certification_id", cert.ID),
|
||||
zap.String("rollback_to_status", string(originalStatus)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createFailureResult 创建失败结果
|
||||
func (sm *CertificationStateMachine) createFailureResult(
|
||||
oldStatus, targetStatus enums.CertificationStatus,
|
||||
message string,
|
||||
) *StateTransitionResult {
|
||||
return &StateTransitionResult{
|
||||
Success: false,
|
||||
OldStatus: oldStatus,
|
||||
NewStatus: targetStatus,
|
||||
Message: message,
|
||||
TransitionedAt: time.Now(),
|
||||
Events: []interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 状态转换快捷方法 ================
|
||||
|
||||
// TransitionToInfoSubmitted 转换到已提交企业信息状态
|
||||
func (sm *CertificationStateMachine) TransitionToInfoSubmitted(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
actor enums.ActorType,
|
||||
actorID string,
|
||||
enterpriseInfo interface{},
|
||||
) (*StateTransitionResult, error) {
|
||||
req := &StateTransitionRequest{
|
||||
CertificationID: certificationID,
|
||||
TargetStatus: enums.StatusInfoSubmitted,
|
||||
Actor: actor,
|
||||
ActorID: actorID,
|
||||
Reason: "用户提交企业信息",
|
||||
Context: map[string]interface{}{
|
||||
"enterprise_info": enterpriseInfo,
|
||||
},
|
||||
AllowRollback: true,
|
||||
}
|
||||
|
||||
return sm.ExecuteTransition(ctx, req)
|
||||
}
|
||||
|
||||
// TransitionToEnterpriseVerified 转换到已企业认证状态
|
||||
func (sm *CertificationStateMachine) TransitionToEnterpriseVerified(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
authFlowID string,
|
||||
) (*StateTransitionResult, error) {
|
||||
req := &StateTransitionRequest{
|
||||
CertificationID: certificationID,
|
||||
TargetStatus: enums.StatusEnterpriseVerified,
|
||||
Actor: enums.ActorTypeEsign,
|
||||
ActorID: "esign_system",
|
||||
Reason: "e签宝企业认证成功",
|
||||
Context: map[string]interface{}{
|
||||
"auth_flow_id": authFlowID,
|
||||
},
|
||||
AllowRollback: false,
|
||||
}
|
||||
|
||||
return sm.ExecuteTransition(ctx, req)
|
||||
}
|
||||
|
||||
// TransitionToInfoRejected 转换到企业信息被拒绝状态
|
||||
func (sm *CertificationStateMachine) TransitionToInfoRejected(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
failureReason enums.FailureReason,
|
||||
failureMessage string,
|
||||
) (*StateTransitionResult, error) {
|
||||
req := &StateTransitionRequest{
|
||||
CertificationID: certificationID,
|
||||
TargetStatus: enums.StatusInfoRejected,
|
||||
Actor: enums.ActorTypeEsign,
|
||||
ActorID: "esign_system",
|
||||
Reason: "e签宝企业认证失败",
|
||||
Context: map[string]interface{}{
|
||||
"failure_reason": failureReason,
|
||||
"failure_message": failureMessage,
|
||||
},
|
||||
AllowRollback: false,
|
||||
}
|
||||
|
||||
return sm.ExecuteTransition(ctx, req)
|
||||
}
|
||||
|
||||
// TransitionToContractApplied 转换到已申请合同状态
|
||||
func (sm *CertificationStateMachine) TransitionToContractApplied(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
actor enums.ActorType,
|
||||
actorID string,
|
||||
) (*StateTransitionResult, error) {
|
||||
req := &StateTransitionRequest{
|
||||
CertificationID: certificationID,
|
||||
TargetStatus: enums.StatusContractApplied,
|
||||
Actor: actor,
|
||||
ActorID: actorID,
|
||||
Reason: "用户申请合同签署",
|
||||
Context: map[string]interface{}{},
|
||||
AllowRollback: true,
|
||||
}
|
||||
|
||||
return sm.ExecuteTransition(ctx, req)
|
||||
}
|
||||
|
||||
// TransitionToContractSigned 转换到已签署合同状态(认证完成)
|
||||
func (sm *CertificationStateMachine) TransitionToContractSigned(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
contractURL string,
|
||||
) (*StateTransitionResult, error) {
|
||||
req := &StateTransitionRequest{
|
||||
CertificationID: certificationID,
|
||||
TargetStatus: enums.StatusContractSigned,
|
||||
Actor: enums.ActorTypeEsign,
|
||||
ActorID: "esign_system",
|
||||
Reason: "e签宝合同签署成功,认证完成",
|
||||
Context: map[string]interface{}{
|
||||
"contract_url": contractURL,
|
||||
},
|
||||
AllowRollback: false,
|
||||
}
|
||||
|
||||
return sm.ExecuteTransition(ctx, req)
|
||||
}
|
||||
|
||||
// TransitionToContractRejected 转换到合同被拒签状态
|
||||
func (sm *CertificationStateMachine) TransitionToContractRejected(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
failureReason enums.FailureReason,
|
||||
failureMessage string,
|
||||
) (*StateTransitionResult, error) {
|
||||
req := &StateTransitionRequest{
|
||||
CertificationID: certificationID,
|
||||
TargetStatus: enums.StatusContractRejected,
|
||||
Actor: enums.ActorTypeEsign,
|
||||
ActorID: "esign_system",
|
||||
Reason: "合同签署失败",
|
||||
Context: map[string]interface{}{
|
||||
"failure_reason": failureReason,
|
||||
"failure_message": failureMessage,
|
||||
},
|
||||
AllowRollback: false,
|
||||
}
|
||||
|
||||
return sm.ExecuteTransition(ctx, req)
|
||||
}
|
||||
|
||||
// TransitionToContractExpired 转换到合同签署超时状态
|
||||
func (sm *CertificationStateMachine) TransitionToContractExpired(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
failureMessage string,
|
||||
) (*StateTransitionResult, error) {
|
||||
req := &StateTransitionRequest{
|
||||
CertificationID: certificationID,
|
||||
TargetStatus: enums.StatusContractExpired,
|
||||
Actor: enums.ActorTypeSystem,
|
||||
ActorID: "timeout_monitor",
|
||||
Reason: "合同签署超时",
|
||||
Context: map[string]interface{}{
|
||||
"failure_reason": enums.FailureReasonContractExpired,
|
||||
"failure_message": failureMessage,
|
||||
},
|
||||
AllowRollback: false,
|
||||
}
|
||||
|
||||
return sm.ExecuteTransition(ctx, req)
|
||||
}
|
||||
@@ -1,391 +0,0 @@
|
||||
package state_machine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"tyapi-server/internal/domains/certification/enums"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// EsignCallbackData e签宝回调数据结构
|
||||
type EsignCallbackData struct {
|
||||
// 基础信息
|
||||
Action string `json:"action"` // 回调动作类型
|
||||
FlowID string `json:"flow_id"` // 流程ID
|
||||
AccountID string `json:"account_id"` // 账户ID
|
||||
Status string `json:"status"` // 状态
|
||||
Message string `json:"message"` // 消息
|
||||
Timestamp int64 `json:"timestamp"` // 时间戳
|
||||
|
||||
// 扩展数据
|
||||
Data map[string]interface{} `json:"data,omitempty"` // 扩展数据
|
||||
OriginalData string `json:"original_data"` // 原始回调数据
|
||||
}
|
||||
|
||||
// EsignCallbackHandler e签宝回调处理器
|
||||
// 负责处理e签宝的异步回调,将外部回调转换为内部状态转换
|
||||
type EsignCallbackHandler struct {
|
||||
stateMachine *CertificationStateMachine
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewEsignCallbackHandler 创建e签宝回调处理器
|
||||
func NewEsignCallbackHandler(
|
||||
stateMachine *CertificationStateMachine,
|
||||
logger *zap.Logger,
|
||||
) *EsignCallbackHandler {
|
||||
return &EsignCallbackHandler{
|
||||
stateMachine: stateMachine,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// HandleCallback 处理e签宝回调
|
||||
func (h *EsignCallbackHandler) HandleCallback(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
callbackData *EsignCallbackData,
|
||||
) error {
|
||||
h.logger.Info("接收到e签宝回调",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("action", callbackData.Action),
|
||||
zap.String("flow_id", callbackData.FlowID),
|
||||
zap.String("status", callbackData.Status))
|
||||
|
||||
// 根据动作类型分发处理
|
||||
switch callbackData.Action {
|
||||
case "auth_result":
|
||||
return h.handleAuthResult(ctx, certificationID, callbackData)
|
||||
case "sign_result":
|
||||
return h.handleSignResult(ctx, certificationID, callbackData)
|
||||
case "flow_status":
|
||||
return h.handleFlowStatus(ctx, certificationID, callbackData)
|
||||
default:
|
||||
h.logger.Warn("未知的e签宝回调动作",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("action", callbackData.Action))
|
||||
return fmt.Errorf("未知的回调动作: %s", callbackData.Action)
|
||||
}
|
||||
}
|
||||
|
||||
// handleAuthResult 处理企业认证结果回调
|
||||
func (h *EsignCallbackHandler) handleAuthResult(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
callbackData *EsignCallbackData,
|
||||
) error {
|
||||
h.logger.Info("处理企业认证结果回调",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("flow_id", callbackData.FlowID),
|
||||
zap.String("status", callbackData.Status))
|
||||
|
||||
switch callbackData.Status {
|
||||
case "success", "verified", "completed":
|
||||
// 认证成功
|
||||
_, err := h.stateMachine.TransitionToEnterpriseVerified(
|
||||
ctx,
|
||||
certificationID,
|
||||
callbackData.FlowID,
|
||||
)
|
||||
return err
|
||||
|
||||
case "failed", "rejected", "error":
|
||||
// 认证失败
|
||||
failureReason := h.parseAuthFailureReason(callbackData)
|
||||
_, err := h.stateMachine.TransitionToInfoRejected(
|
||||
ctx,
|
||||
certificationID,
|
||||
failureReason,
|
||||
callbackData.Message,
|
||||
)
|
||||
return err
|
||||
|
||||
default:
|
||||
h.logger.Warn("未知的企业认证状态",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("status", callbackData.Status))
|
||||
return fmt.Errorf("未知的认证状态: %s", callbackData.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// handleSignResult 处理合同签署结果回调
|
||||
func (h *EsignCallbackHandler) handleSignResult(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
callbackData *EsignCallbackData,
|
||||
) error {
|
||||
h.logger.Info("处理合同签署结果回调",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("flow_id", callbackData.FlowID),
|
||||
zap.String("status", callbackData.Status))
|
||||
|
||||
switch callbackData.Status {
|
||||
case "signed", "completed", "success":
|
||||
// 签署成功
|
||||
contractURL := h.extractContractURL(callbackData)
|
||||
_, err := h.stateMachine.TransitionToContractSigned(
|
||||
ctx,
|
||||
certificationID,
|
||||
contractURL,
|
||||
)
|
||||
return err
|
||||
|
||||
case "rejected", "refused":
|
||||
// 用户拒绝签署
|
||||
_, err := h.stateMachine.TransitionToContractRejected(
|
||||
ctx,
|
||||
certificationID,
|
||||
enums.FailureReasonContractRejectedByUser,
|
||||
callbackData.Message,
|
||||
)
|
||||
return err
|
||||
|
||||
case "expired", "timeout":
|
||||
// 签署超时
|
||||
_, err := h.stateMachine.TransitionToContractExpired(
|
||||
ctx,
|
||||
certificationID,
|
||||
fmt.Sprintf("合同签署超时: %s", callbackData.Message),
|
||||
)
|
||||
return err
|
||||
|
||||
case "failed", "error":
|
||||
// 签署失败
|
||||
failureReason := h.parseSignFailureReason(callbackData)
|
||||
_, err := h.stateMachine.TransitionToContractRejected(
|
||||
ctx,
|
||||
certificationID,
|
||||
failureReason,
|
||||
callbackData.Message,
|
||||
)
|
||||
return err
|
||||
|
||||
default:
|
||||
h.logger.Warn("未知的合同签署状态",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("status", callbackData.Status))
|
||||
return fmt.Errorf("未知的签署状态: %s", callbackData.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// handleFlowStatus 处理流程状态回调
|
||||
func (h *EsignCallbackHandler) handleFlowStatus(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
callbackData *EsignCallbackData,
|
||||
) error {
|
||||
h.logger.Info("处理流程状态回调",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("flow_id", callbackData.FlowID),
|
||||
zap.String("status", callbackData.Status))
|
||||
|
||||
// 流程状态回调主要用于监控和日志记录
|
||||
// 实际的状态转换由具体的auth_result和sign_result处理
|
||||
|
||||
switch callbackData.Status {
|
||||
case "started", "processing", "in_progress":
|
||||
h.logger.Info("e签宝流程进行中",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("flow_id", callbackData.FlowID))
|
||||
|
||||
case "paused", "suspended":
|
||||
h.logger.Warn("e签宝流程被暂停",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("flow_id", callbackData.FlowID),
|
||||
zap.String("message", callbackData.Message))
|
||||
|
||||
case "cancelled", "terminated":
|
||||
h.logger.Warn("e签宝流程被取消",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("flow_id", callbackData.FlowID),
|
||||
zap.String("message", callbackData.Message))
|
||||
|
||||
default:
|
||||
h.logger.Info("收到其他流程状态",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("status", callbackData.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseAuthFailureReason 解析企业认证失败原因
|
||||
func (h *EsignCallbackHandler) parseAuthFailureReason(callbackData *EsignCallbackData) enums.FailureReason {
|
||||
// 根据e签宝返回的错误信息解析失败原因
|
||||
message := callbackData.Message
|
||||
|
||||
// 检查扩展数据中的错误码
|
||||
if errorCode, exists := callbackData.Data["error_code"]; exists {
|
||||
switch errorCode {
|
||||
case "ENTERPRISE_NOT_FOUND", "ORG_NOT_EXISTS":
|
||||
return enums.FailureReasonEnterpriseNotExists
|
||||
case "INFO_MISMATCH", "ORG_INFO_ERROR":
|
||||
return enums.FailureReasonEnterpriseInfoMismatch
|
||||
case "STATUS_ABNORMAL", "ORG_STATUS_ERROR":
|
||||
return enums.FailureReasonEnterpriseStatusAbnormal
|
||||
case "LEGAL_PERSON_ERROR", "LEGAL_REP_ERROR":
|
||||
return enums.FailureReasonLegalPersonMismatch
|
||||
case "DOCUMENT_INVALID", "ID_CARD_ERROR":
|
||||
return enums.FailureReasonInvalidDocument
|
||||
}
|
||||
}
|
||||
|
||||
// 根据错误消息文本判断
|
||||
if message != "" {
|
||||
if h.containsKeywords(message, []string{"企业不存在", "机构不存在", "not found"}) {
|
||||
return enums.FailureReasonEnterpriseNotExists
|
||||
}
|
||||
if h.containsKeywords(message, []string{"信息不匹配", "信息错误", "mismatch"}) {
|
||||
return enums.FailureReasonEnterpriseInfoMismatch
|
||||
}
|
||||
if h.containsKeywords(message, []string{"状态异常", "status abnormal"}) {
|
||||
return enums.FailureReasonEnterpriseStatusAbnormal
|
||||
}
|
||||
if h.containsKeywords(message, []string{"法定代表人", "legal person", "法人"}) {
|
||||
return enums.FailureReasonLegalPersonMismatch
|
||||
}
|
||||
if h.containsKeywords(message, []string{"证件", "身份证", "document", "id card"}) {
|
||||
return enums.FailureReasonInvalidDocument
|
||||
}
|
||||
}
|
||||
|
||||
// 默认返回e签宝验证失败
|
||||
return enums.FailureReasonEsignVerificationFailed
|
||||
}
|
||||
|
||||
// parseSignFailureReason 解析合同签署失败原因
|
||||
func (h *EsignCallbackHandler) parseSignFailureReason(callbackData *EsignCallbackData) enums.FailureReason {
|
||||
// 根据e签宝返回的错误信息解析失败原因
|
||||
message := callbackData.Message
|
||||
|
||||
// 检查扩展数据中的错误码
|
||||
if errorCode, exists := callbackData.Data["error_code"]; exists {
|
||||
switch errorCode {
|
||||
case "USER_REJECTED", "SIGN_REJECTED":
|
||||
return enums.FailureReasonContractRejectedByUser
|
||||
case "FLOW_EXPIRED", "SIGN_EXPIRED":
|
||||
return enums.FailureReasonContractExpired
|
||||
case "FLOW_ERROR", "SIGN_PROCESS_ERROR":
|
||||
return enums.FailureReasonSignProcessFailed
|
||||
case "ESIGN_ERROR", "SYSTEM_ERROR":
|
||||
return enums.FailureReasonEsignFlowError
|
||||
}
|
||||
}
|
||||
|
||||
// 根据错误消息文本判断
|
||||
if message != "" {
|
||||
if h.containsKeywords(message, []string{"拒绝", "rejected", "refused"}) {
|
||||
return enums.FailureReasonContractRejectedByUser
|
||||
}
|
||||
if h.containsKeywords(message, []string{"过期", "超时", "expired", "timeout"}) {
|
||||
return enums.FailureReasonContractExpired
|
||||
}
|
||||
if h.containsKeywords(message, []string{"流程错误", "process error", "flow error"}) {
|
||||
return enums.FailureReasonSignProcessFailed
|
||||
}
|
||||
}
|
||||
|
||||
// 默认返回e签宝流程错误
|
||||
return enums.FailureReasonEsignFlowError
|
||||
}
|
||||
|
||||
// extractContractURL 提取合同URL
|
||||
func (h *EsignCallbackHandler) extractContractURL(callbackData *EsignCallbackData) string {
|
||||
// 优先从扩展数据中获取
|
||||
if contractURL, exists := callbackData.Data["contract_url"]; exists {
|
||||
if url, ok := contractURL.(string); ok && url != "" {
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
if downloadURL, exists := callbackData.Data["download_url"]; exists {
|
||||
if url, ok := downloadURL.(string); ok && url != "" {
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
if fileURL, exists := callbackData.Data["file_url"]; exists {
|
||||
if url, ok := fileURL.(string); ok && url != "" {
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到URL,返回空字符串
|
||||
h.logger.Warn("未能从回调数据中提取合同URL",
|
||||
zap.Any("callback_data", callbackData.Data))
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// containsKeywords 检查文本是否包含关键词
|
||||
func (h *EsignCallbackHandler) containsKeywords(text string, keywords []string) bool {
|
||||
for _, keyword := range keywords {
|
||||
if len(text) >= len(keyword) {
|
||||
for i := 0; i <= len(text)-len(keyword); i++ {
|
||||
if text[i:i+len(keyword)] == keyword {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ValidateCallbackData 验证回调数据
|
||||
func (h *EsignCallbackHandler) ValidateCallbackData(callbackData *EsignCallbackData) error {
|
||||
if callbackData == nil {
|
||||
return fmt.Errorf("回调数据不能为空")
|
||||
}
|
||||
|
||||
if callbackData.Action == "" {
|
||||
return fmt.Errorf("回调动作不能为空")
|
||||
}
|
||||
|
||||
if callbackData.FlowID == "" {
|
||||
return fmt.Errorf("流程ID不能为空")
|
||||
}
|
||||
|
||||
if callbackData.Status == "" {
|
||||
return fmt.Errorf("状态不能为空")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseCallbackData 解析原始回调数据
|
||||
func (h *EsignCallbackHandler) ParseCallbackData(rawData string) (*EsignCallbackData, error) {
|
||||
var callbackData EsignCallbackData
|
||||
|
||||
if err := json.Unmarshal([]byte(rawData), &callbackData); err != nil {
|
||||
h.logger.Error("解析e签宝回调数据失败", zap.Error(err), zap.String("raw_data", rawData))
|
||||
return nil, fmt.Errorf("解析回调数据失败: %w", err)
|
||||
}
|
||||
|
||||
// 保存原始数据
|
||||
callbackData.OriginalData = rawData
|
||||
|
||||
// 验证数据完整性
|
||||
if err := h.ValidateCallbackData(&callbackData); err != nil {
|
||||
return nil, fmt.Errorf("回调数据验证失败: %w", err)
|
||||
}
|
||||
|
||||
return &callbackData, nil
|
||||
}
|
||||
|
||||
// GetCallbackType 获取回调类型描述
|
||||
func (h *EsignCallbackHandler) GetCallbackType(action string) string {
|
||||
types := map[string]string{
|
||||
"auth_result": "企业认证结果",
|
||||
"sign_result": "合同签署结果",
|
||||
"flow_status": "流程状态更新",
|
||||
}
|
||||
|
||||
if typeName, exists := types[action]; exists {
|
||||
return typeName
|
||||
}
|
||||
|
||||
return "未知类型"
|
||||
}
|
||||
@@ -1,438 +0,0 @@
|
||||
package state_machine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"tyapi-server/internal/domains/certification/enums"
|
||||
)
|
||||
|
||||
// StateConfig 状态配置
|
||||
type StateConfig struct {
|
||||
Status enums.CertificationStatus `json:"status"`
|
||||
Name string `json:"name"`
|
||||
ProgressPercentage int `json:"progress_percentage"`
|
||||
IsUserActionRequired bool `json:"is_user_action_required"`
|
||||
IsSystemAction bool `json:"is_system_action"`
|
||||
TimestampField string `json:"timestamp_field,omitempty"`
|
||||
Description string `json:"description"`
|
||||
NextValidStatuses []enums.CertificationStatus `json:"next_valid_statuses"`
|
||||
AllowedActors []enums.ActorType `json:"allowed_actors"`
|
||||
}
|
||||
|
||||
// StateTransitionRule 状态转换规则
|
||||
type StateTransitionRule struct {
|
||||
FromStatus enums.CertificationStatus `json:"from_status"`
|
||||
ToStatus enums.CertificationStatus `json:"to_status"`
|
||||
TransitionName string `json:"transition_name"`
|
||||
AllowedActors []enums.ActorType `json:"allowed_actors"`
|
||||
RequiresValidation bool `json:"requires_validation"`
|
||||
Description string `json:"description"`
|
||||
BusinessRules []string `json:"business_rules"`
|
||||
}
|
||||
|
||||
// StateConfigManager 状态配置管理器
|
||||
type StateConfigManager struct {
|
||||
stateConfigs map[enums.CertificationStatus]*StateConfig
|
||||
transitionRules map[string]*StateTransitionRule // key: "from_status->to_status"
|
||||
actorPermissions map[enums.ActorType][]string // actor允许的操作
|
||||
}
|
||||
|
||||
// NewStateConfigManager 创建状态配置管理器
|
||||
func NewStateConfigManager() *StateConfigManager {
|
||||
manager := &StateConfigManager{
|
||||
stateConfigs: make(map[enums.CertificationStatus]*StateConfig),
|
||||
transitionRules: make(map[string]*StateTransitionRule),
|
||||
actorPermissions: make(map[enums.ActorType][]string),
|
||||
}
|
||||
|
||||
manager.initializeStateConfigs()
|
||||
manager.initializeTransitionRules()
|
||||
manager.initializeActorPermissions()
|
||||
|
||||
return manager
|
||||
}
|
||||
|
||||
// initializeStateConfigs 初始化状态配置
|
||||
func (m *StateConfigManager) initializeStateConfigs() {
|
||||
configs := []*StateConfig{
|
||||
{
|
||||
Status: enums.StatusPending,
|
||||
Name: "待认证",
|
||||
ProgressPercentage: 0,
|
||||
IsUserActionRequired: true,
|
||||
IsSystemAction: false,
|
||||
Description: "等待用户提交企业信息",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusInfoSubmitted},
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeUser},
|
||||
},
|
||||
{
|
||||
Status: enums.StatusInfoSubmitted,
|
||||
Name: "已提交企业信息",
|
||||
ProgressPercentage: 25,
|
||||
IsUserActionRequired: false,
|
||||
IsSystemAction: true,
|
||||
TimestampField: "InfoSubmittedAt",
|
||||
Description: "企业信息已提交,等待e签宝验证",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusEnterpriseVerified, enums.StatusInfoRejected},
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeEsign, enums.ActorTypeSystem},
|
||||
},
|
||||
{
|
||||
Status: enums.StatusEnterpriseVerified,
|
||||
Name: "已企业认证",
|
||||
ProgressPercentage: 50,
|
||||
IsUserActionRequired: true,
|
||||
IsSystemAction: false,
|
||||
TimestampField: "EnterpriseVerifiedAt",
|
||||
Description: "企业认证完成,用户可申请合同",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusContractApplied},
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeUser},
|
||||
},
|
||||
{
|
||||
Status: enums.StatusContractApplied,
|
||||
Name: "已申请签署合同",
|
||||
ProgressPercentage: 75,
|
||||
IsUserActionRequired: true,
|
||||
IsSystemAction: true,
|
||||
TimestampField: "ContractAppliedAt",
|
||||
Description: "合同已生成,等待用户签署",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusContractSigned, enums.StatusContractRejected, enums.StatusContractExpired},
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeEsign, enums.ActorTypeSystem},
|
||||
},
|
||||
{
|
||||
Status: enums.StatusContractSigned,
|
||||
Name: "认证完成",
|
||||
ProgressPercentage: 100,
|
||||
IsUserActionRequired: false,
|
||||
IsSystemAction: false,
|
||||
TimestampField: "ContractSignedAt",
|
||||
Description: "认证流程已完成",
|
||||
NextValidStatuses: []enums.CertificationStatus{},
|
||||
AllowedActors: []enums.ActorType{},
|
||||
},
|
||||
// 失败状态
|
||||
{
|
||||
Status: enums.StatusInfoRejected,
|
||||
Name: "企业信息被拒绝",
|
||||
ProgressPercentage: 25,
|
||||
IsUserActionRequired: true,
|
||||
IsSystemAction: false,
|
||||
Description: "企业信息验证失败,需要重新提交",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusInfoSubmitted},
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeUser},
|
||||
},
|
||||
{
|
||||
Status: enums.StatusContractRejected,
|
||||
Name: "合同被拒签",
|
||||
ProgressPercentage: 75,
|
||||
IsUserActionRequired: true,
|
||||
IsSystemAction: false,
|
||||
Description: "用户拒绝签署合同",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusEnterpriseVerified},
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeUser, enums.ActorTypeSystem},
|
||||
},
|
||||
{
|
||||
Status: enums.StatusContractExpired,
|
||||
Name: "合同签署超时",
|
||||
ProgressPercentage: 75,
|
||||
IsUserActionRequired: true,
|
||||
IsSystemAction: false,
|
||||
Description: "合同签署链接已过期",
|
||||
NextValidStatuses: []enums.CertificationStatus{enums.StatusEnterpriseVerified},
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeUser, enums.ActorTypeSystem},
|
||||
},
|
||||
}
|
||||
|
||||
for _, config := range configs {
|
||||
m.stateConfigs[config.Status] = config
|
||||
}
|
||||
}
|
||||
|
||||
// initializeTransitionRules 初始化状态转换规则
|
||||
func (m *StateConfigManager) initializeTransitionRules() {
|
||||
rules := []*StateTransitionRule{
|
||||
// 用户提交企业信息
|
||||
{
|
||||
FromStatus: enums.StatusPending,
|
||||
ToStatus: enums.StatusInfoSubmitted,
|
||||
TransitionName: "submit_enterprise_info",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeUser},
|
||||
RequiresValidation: true,
|
||||
Description: "用户提交企业信息",
|
||||
BusinessRules: []string{"enterprise_info_complete", "enterprise_info_valid"},
|
||||
},
|
||||
// e签宝企业认证成功
|
||||
{
|
||||
FromStatus: enums.StatusInfoSubmitted,
|
||||
ToStatus: enums.StatusEnterpriseVerified,
|
||||
TransitionName: "enterprise_verification_success",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeEsign, enums.ActorTypeSystem},
|
||||
RequiresValidation: false,
|
||||
Description: "e签宝企业认证成功",
|
||||
BusinessRules: []string{"auth_flow_id_exists"},
|
||||
},
|
||||
// e签宝企业认证失败
|
||||
{
|
||||
FromStatus: enums.StatusInfoSubmitted,
|
||||
ToStatus: enums.StatusInfoRejected,
|
||||
TransitionName: "enterprise_verification_failed",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeEsign, enums.ActorTypeSystem},
|
||||
RequiresValidation: false,
|
||||
Description: "e签宝企业认证失败",
|
||||
BusinessRules: []string{"failure_reason_provided"},
|
||||
},
|
||||
// 用户申请合同
|
||||
{
|
||||
FromStatus: enums.StatusEnterpriseVerified,
|
||||
ToStatus: enums.StatusContractApplied,
|
||||
TransitionName: "apply_contract",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeUser},
|
||||
RequiresValidation: true,
|
||||
Description: "用户申请合同签署",
|
||||
BusinessRules: []string{"enterprise_verified", "auth_flow_id_exists"},
|
||||
},
|
||||
// e签宝合同签署成功
|
||||
{
|
||||
FromStatus: enums.StatusContractApplied,
|
||||
ToStatus: enums.StatusContractSigned,
|
||||
TransitionName: "contract_sign_success",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeEsign, enums.ActorTypeSystem},
|
||||
RequiresValidation: false,
|
||||
Description: "e签宝合同签署成功",
|
||||
BusinessRules: []string{"contract_info_complete"},
|
||||
},
|
||||
// 合同签署失败
|
||||
{
|
||||
FromStatus: enums.StatusContractApplied,
|
||||
ToStatus: enums.StatusContractRejected,
|
||||
TransitionName: "contract_sign_rejected",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeEsign, enums.ActorTypeSystem},
|
||||
RequiresValidation: false,
|
||||
Description: "用户拒绝签署合同",
|
||||
BusinessRules: []string{"failure_reason_provided"},
|
||||
},
|
||||
// 合同签署超时
|
||||
{
|
||||
FromStatus: enums.StatusContractApplied,
|
||||
ToStatus: enums.StatusContractExpired,
|
||||
TransitionName: "contract_sign_expired",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeEsign, enums.ActorTypeSystem},
|
||||
RequiresValidation: false,
|
||||
Description: "合同签署超时",
|
||||
BusinessRules: []string{"failure_reason_provided"},
|
||||
},
|
||||
// 重新提交企业信息
|
||||
{
|
||||
FromStatus: enums.StatusInfoRejected,
|
||||
ToStatus: enums.StatusInfoSubmitted,
|
||||
TransitionName: "resubmit_enterprise_info",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeUser},
|
||||
RequiresValidation: true,
|
||||
Description: "用户重新提交企业信息",
|
||||
BusinessRules: []string{"enterprise_info_complete", "enterprise_info_valid", "retry_limit_check"},
|
||||
},
|
||||
// 从合同失败状态恢复
|
||||
{
|
||||
FromStatus: enums.StatusContractRejected,
|
||||
ToStatus: enums.StatusEnterpriseVerified,
|
||||
TransitionName: "reset_from_contract_rejected",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeSystem, enums.ActorTypeUser},
|
||||
RequiresValidation: false,
|
||||
Description: "从合同拒签状态恢复",
|
||||
BusinessRules: []string{"retry_limit_check"},
|
||||
},
|
||||
{
|
||||
FromStatus: enums.StatusContractExpired,
|
||||
ToStatus: enums.StatusEnterpriseVerified,
|
||||
TransitionName: "reset_from_contract_expired",
|
||||
AllowedActors: []enums.ActorType{enums.ActorTypeSystem, enums.ActorTypeUser},
|
||||
RequiresValidation: false,
|
||||
Description: "从合同超时状态恢复",
|
||||
BusinessRules: []string{"retry_limit_check"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, rule := range rules {
|
||||
key := string(rule.FromStatus) + "->" + string(rule.ToStatus)
|
||||
m.transitionRules[key] = rule
|
||||
}
|
||||
}
|
||||
|
||||
// initializeActorPermissions 初始化操作者权限
|
||||
func (m *StateConfigManager) initializeActorPermissions() {
|
||||
m.actorPermissions = map[enums.ActorType][]string{
|
||||
enums.ActorTypeUser: {
|
||||
"submit_enterprise_info",
|
||||
"apply_contract",
|
||||
"view_certification",
|
||||
"retry_from_failure",
|
||||
},
|
||||
enums.ActorTypeSystem: {
|
||||
"auto_transition",
|
||||
"system_recovery",
|
||||
"timeout_handling",
|
||||
"data_cleanup",
|
||||
},
|
||||
enums.ActorTypeEsign: {
|
||||
"verification_callback",
|
||||
"sign_callback",
|
||||
"status_notification",
|
||||
},
|
||||
enums.ActorTypeAdmin: {
|
||||
"manual_intervention",
|
||||
"force_transition",
|
||||
"view_all_certifications",
|
||||
"system_configuration",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetStateConfig 获取状态配置
|
||||
func (m *StateConfigManager) GetStateConfig(status enums.CertificationStatus) *StateConfig {
|
||||
return m.stateConfigs[status]
|
||||
}
|
||||
|
||||
// GetTransitionRule 获取状态转换规则
|
||||
func (m *StateConfigManager) GetTransitionRule(fromStatus, toStatus enums.CertificationStatus) *StateTransitionRule {
|
||||
key := string(fromStatus) + "->" + string(toStatus)
|
||||
return m.transitionRules[key]
|
||||
}
|
||||
|
||||
// CanTransition 检查是否可以执行状态转换
|
||||
func (m *StateConfigManager) CanTransition(fromStatus, toStatus enums.CertificationStatus, actor enums.ActorType) (bool, string) {
|
||||
// 获取转换规则
|
||||
rule := m.GetTransitionRule(fromStatus, toStatus)
|
||||
if rule == nil {
|
||||
return false, "不支持的状态转换"
|
||||
}
|
||||
|
||||
// 检查操作者权限
|
||||
allowed := false
|
||||
for _, allowedActor := range rule.AllowedActors {
|
||||
if actor == allowedActor {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !allowed {
|
||||
return false, "操作者无权限执行此转换"
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// GetAllowedTransitions 获取指定状态下允许的转换
|
||||
func (m *StateConfigManager) GetAllowedTransitions(fromStatus enums.CertificationStatus, actor enums.ActorType) []*StateTransitionRule {
|
||||
var allowedTransitions []*StateTransitionRule
|
||||
|
||||
config := m.GetStateConfig(fromStatus)
|
||||
if config == nil {
|
||||
return allowedTransitions
|
||||
}
|
||||
|
||||
for _, toStatus := range config.NextValidStatuses {
|
||||
if canTransition, _ := m.CanTransition(fromStatus, toStatus, actor); canTransition {
|
||||
if rule := m.GetTransitionRule(fromStatus, toStatus); rule != nil {
|
||||
allowedTransitions = append(allowedTransitions, rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allowedTransitions
|
||||
}
|
||||
|
||||
// GetActorPermissions 获取操作者权限
|
||||
func (m *StateConfigManager) GetActorPermissions(actor enums.ActorType) []string {
|
||||
if permissions, exists := m.actorPermissions[actor]; exists {
|
||||
return permissions
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// HasPermission 检查操作者是否有指定权限
|
||||
func (m *StateConfigManager) HasPermission(actor enums.ActorType, permission string) bool {
|
||||
permissions := m.GetActorPermissions(actor)
|
||||
for _, p := range permissions {
|
||||
if p == permission {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ValidateBusinessRules 验证业务规则
|
||||
func (m *StateConfigManager) ValidateBusinessRules(rule *StateTransitionRule, context map[string]interface{}) error {
|
||||
for _, businessRule := range rule.BusinessRules {
|
||||
if err := m.validateSingleBusinessRule(businessRule, context); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateSingleBusinessRule 验证单个业务规则
|
||||
func (m *StateConfigManager) validateSingleBusinessRule(ruleName string, context map[string]interface{}) error {
|
||||
switch ruleName {
|
||||
case "enterprise_info_complete":
|
||||
if enterpriseInfo, exists := context["enterprise_info"]; !exists || enterpriseInfo == nil {
|
||||
return fmt.Errorf("企业信息不能为空")
|
||||
}
|
||||
case "enterprise_info_valid":
|
||||
// 这里可以添加更复杂的企业信息验证逻辑
|
||||
return nil
|
||||
case "auth_flow_id_exists":
|
||||
if authFlowID, exists := context["auth_flow_id"]; !exists || authFlowID == "" {
|
||||
return fmt.Errorf("认证流程ID不能为空")
|
||||
}
|
||||
case "failure_reason_provided":
|
||||
if reason, exists := context["failure_reason"]; !exists || reason == "" {
|
||||
return fmt.Errorf("失败原因不能为空")
|
||||
}
|
||||
case "enterprise_verified":
|
||||
if status, exists := context["current_status"]; !exists || status != string(enums.StatusEnterpriseVerified) {
|
||||
return fmt.Errorf("企业必须先完成认证")
|
||||
}
|
||||
case "contract_info_complete":
|
||||
if contractInfo, exists := context["contract_info"]; !exists || contractInfo == nil {
|
||||
return fmt.Errorf("合同信息不能为空")
|
||||
}
|
||||
case "retry_limit_check":
|
||||
if retryCount, exists := context["retry_count"]; exists {
|
||||
if count, ok := retryCount.(int); ok && count >= 3 {
|
||||
return fmt.Errorf("已达到最大重试次数限制")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetStateProgress 获取状态进度信息
|
||||
func (m *StateConfigManager) GetStateProgress(status enums.CertificationStatus) int {
|
||||
if config := m.GetStateConfig(status); config != nil {
|
||||
return config.ProgressPercentage
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IsUserActionRequired 检查是否需要用户操作
|
||||
func (m *StateConfigManager) IsUserActionRequired(status enums.CertificationStatus) bool {
|
||||
if config := m.GetStateConfig(status); config != nil {
|
||||
return config.IsUserActionRequired
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsSystemAction 检查是否为系统操作状态
|
||||
func (m *StateConfigManager) IsSystemAction(status enums.CertificationStatus) bool {
|
||||
if config := m.GetStateConfig(status); config != nil {
|
||||
return config.IsSystemAction
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetTimestampField 获取状态对应的时间戳字段
|
||||
func (m *StateConfigManager) GetTimestampField(status enums.CertificationStatus) string {
|
||||
if config := m.GetStateConfig(status); config != nil {
|
||||
return config.TimestampField
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user