438 lines
16 KiB
Go
438 lines
16 KiB
Go
|
|
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 ""
|
|||
|
|
}
|