2025-07-11 21:05:58 +08:00
|
|
|
|
package entities
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-07-21 15:13:26 +08:00
|
|
|
|
"errors"
|
|
|
|
|
|
"fmt"
|
2025-07-11 21:05:58 +08:00
|
|
|
|
"time"
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
"tyapi-server/internal/domains/certification/entities/value_objects"
|
2025-07-11 21:05:58 +08:00
|
|
|
|
"tyapi-server/internal/domains/certification/enums"
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
"github.com/google/uuid"
|
2025-07-11 21:05:58 +08:00
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// Certification 认证聚合根
|
|
|
|
|
|
// 这是企业认证流程的核心聚合根,封装了完整的认证业务逻辑和状态管理
|
2025-07-11 21:05:58 +08:00
|
|
|
|
type Certification struct {
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// === 基础信息 ===
|
2025-07-28 01:46:39 +08:00
|
|
|
|
ID string `gorm:"primaryKey;type:varchar(64)" json:"id" comment:"认证申请唯一标识"`
|
|
|
|
|
|
UserID string `gorm:"type:varchar(36);not null;unique" json:"user_id" comment:"申请用户ID"`
|
2025-07-13 16:36:20 +08:00
|
|
|
|
Status enums.CertificationStatus `gorm:"type:varchar(50);not null;index" json:"status" comment:"当前认证状态"`
|
2025-07-11 21:05:58 +08:00
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// === 流程时间戳 - 记录每个关键步骤的完成时间 ===
|
2025-07-28 01:46:39 +08:00
|
|
|
|
InfoSubmittedAt *time.Time `json:"info_submitted_at,omitempty" comment:"企业信息提交时间"`
|
|
|
|
|
|
EnterpriseVerifiedAt *time.Time `json:"enterprise_verified_at,omitempty" comment:"企业认证完成时间"`
|
|
|
|
|
|
ContractAppliedAt *time.Time `json:"contract_applied_at,omitempty" comment:"合同申请时间"`
|
|
|
|
|
|
ContractSignedAt *time.Time `json:"contract_signed_at,omitempty" comment:"合同签署完成时间"`
|
|
|
|
|
|
CompletedAt *time.Time `json:"completed_at,omitempty" comment:"认证完成时间"`
|
|
|
|
|
|
ContractFileCreatedAt *time.Time `json:"contract_file_created_at,omitempty" comment:"合同文件生成时间"`
|
2025-07-11 21:05:58 +08:00
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// === e签宝相关信息 ===
|
|
|
|
|
|
AuthFlowID string `gorm:"type:varchar(500)" json:"auth_flow_id,omitempty" comment:"企业认证流程ID"`
|
2025-07-28 01:46:39 +08:00
|
|
|
|
AuthURL string `gorm:"type:varchar(500)" json:"auth_url,omitempty" comment:"企业认证链接"`
|
2025-07-20 20:53:26 +08:00
|
|
|
|
ContractFileID string `gorm:"type:varchar(500)" json:"contract_file_id,omitempty" comment:"合同文件ID"`
|
|
|
|
|
|
EsignFlowID string `gorm:"type:varchar(500)" json:"esign_flow_id,omitempty" comment:"签署流程ID"`
|
|
|
|
|
|
ContractURL string `gorm:"type:varchar(500)" json:"contract_url,omitempty" comment:"合同文件访问链接"`
|
|
|
|
|
|
ContractSignURL string `gorm:"type:varchar(500)" json:"contract_sign_url,omitempty" comment:"合同签署链接"`
|
2025-07-11 21:05:58 +08:00
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// === 失败信息 ===
|
|
|
|
|
|
FailureReason enums.FailureReason `gorm:"type:varchar(100)" json:"failure_reason,omitempty" comment:"失败原因"`
|
|
|
|
|
|
FailureMessage string `gorm:"type:text" json:"failure_message,omitempty" comment:"失败详细信息"`
|
|
|
|
|
|
RetryCount int `gorm:"default:0" json:"retry_count" comment:"重试次数"`
|
|
|
|
|
|
|
|
|
|
|
|
// === 审计信息 ===
|
|
|
|
|
|
LastTransitionAt *time.Time `json:"last_transition_at,omitempty" comment:"最后状态转换时间"`
|
|
|
|
|
|
LastTransitionBy enums.ActorType `gorm:"type:varchar(20)" json:"last_transition_by,omitempty" comment:"最后操作者类型"`
|
|
|
|
|
|
LastTransitionActor string `gorm:"type:varchar(100)" json:"last_transition_actor,omitempty" comment:"最后操作者ID"`
|
2025-07-11 21:05:58 +08:00
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// === 系统字段 ===
|
2025-07-11 21:05:58 +08:00
|
|
|
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"`
|
|
|
|
|
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"`
|
|
|
|
|
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"`
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
|
|
|
|
|
// === 领域事件 (不持久化) ===
|
|
|
|
|
|
domainEvents []interface{} `gorm:"-" json:"-"`
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TableName 指定数据库表名
|
|
|
|
|
|
func (Certification) TableName() string {
|
|
|
|
|
|
return "certifications"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// BeforeCreate GORM钩子:创建前自动生成UUID
|
|
|
|
|
|
func (c *Certification) BeforeCreate(tx *gorm.DB) error {
|
|
|
|
|
|
if c.ID == "" {
|
|
|
|
|
|
c.ID = uuid.New().String()
|
|
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
|
|
|
|
|
// 设置初始状态
|
|
|
|
|
|
if c.Status == "" {
|
|
|
|
|
|
c.Status = enums.StatusPending
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// ================ 工厂方法 ================
|
|
|
|
|
|
|
|
|
|
|
|
// NewCertification 创建新的认证申请
|
|
|
|
|
|
func NewCertification(userID string) (*Certification, error) {
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
return nil, errors.New("用户ID不能为空")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
certification := &Certification{
|
|
|
|
|
|
ID: uuid.New().String(),
|
|
|
|
|
|
UserID: userID,
|
|
|
|
|
|
Status: enums.StatusPending,
|
|
|
|
|
|
RetryCount: 0,
|
|
|
|
|
|
domainEvents: make([]interface{}, 0),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加领域事件
|
|
|
|
|
|
certification.addDomainEvent(&CertificationCreatedEvent{
|
|
|
|
|
|
CertificationID: certification.ID,
|
|
|
|
|
|
UserID: userID,
|
|
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return certification, nil
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// ================ 状态转换方法 ================
|
|
|
|
|
|
|
|
|
|
|
|
// CanTransitionTo 检查是否可以转换到目标状态
|
|
|
|
|
|
func (c *Certification) CanTransitionTo(targetStatus enums.CertificationStatus, actor enums.ActorType) (bool, string) {
|
|
|
|
|
|
// 检查状态转换规则
|
|
|
|
|
|
if !enums.CanTransitionTo(c.Status, targetStatus) {
|
|
|
|
|
|
return false, fmt.Sprintf("不允许从 %s 转换到 %s", enums.GetStatusName(c.Status), enums.GetStatusName(targetStatus))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查操作者权限
|
|
|
|
|
|
if !c.validateActorPermission(targetStatus, actor) {
|
|
|
|
|
|
return false, fmt.Sprintf("%s 无权执行此状态转换", enums.GetActorTypeName(actor))
|
|
|
|
|
|
}
|
|
|
|
|
|
return true, ""
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// TransitionTo 执行状态转换
|
|
|
|
|
|
func (c *Certification) TransitionTo(targetStatus enums.CertificationStatus, actor enums.ActorType, actorID string, reason string) error {
|
|
|
|
|
|
// 验证转换合法性
|
|
|
|
|
|
canTransition, message := c.CanTransitionTo(targetStatus, actor)
|
|
|
|
|
|
if !canTransition {
|
|
|
|
|
|
return fmt.Errorf("状态转换失败: %s", message)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
oldStatus := c.Status
|
|
|
|
|
|
|
|
|
|
|
|
// 执行状态转换
|
|
|
|
|
|
c.Status = targetStatus
|
|
|
|
|
|
c.updateTimestampByStatus(targetStatus)
|
|
|
|
|
|
c.updateTransitionAudit(actor, actorID)
|
|
|
|
|
|
|
|
|
|
|
|
// 清除失败信息(如果转换到成功状态)
|
|
|
|
|
|
if !enums.IsFailureStatus(targetStatus) {
|
|
|
|
|
|
c.clearFailureInfo()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加状态转换事件
|
|
|
|
|
|
c.addDomainEvent(&CertificationStatusChangedEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
FromStatus: oldStatus,
|
|
|
|
|
|
ToStatus: targetStatus,
|
|
|
|
|
|
Actor: actor,
|
|
|
|
|
|
ActorID: actorID,
|
|
|
|
|
|
Reason: reason,
|
|
|
|
|
|
TransitionedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================ 业务操作方法 ================
|
|
|
|
|
|
|
|
|
|
|
|
// SubmitEnterpriseInfo 提交企业信息
|
2025-07-28 01:46:39 +08:00
|
|
|
|
func (c *Certification) SubmitEnterpriseInfo(enterpriseInfo *value_objects.EnterpriseInfo, authURL string, authFlowID string) error {
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// 验证当前状态
|
|
|
|
|
|
if c.Status != enums.StatusPending && c.Status != enums.StatusInfoRejected {
|
|
|
|
|
|
return fmt.Errorf("当前状态 %s 不允许提交企业信息", enums.GetStatusName(c.Status))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证企业信息
|
|
|
|
|
|
if err := enterpriseInfo.Validate(); err != nil {
|
|
|
|
|
|
return fmt.Errorf("企业信息验证失败: %w", err)
|
|
|
|
|
|
}
|
2025-07-28 01:46:39 +08:00
|
|
|
|
if authURL != "" {
|
|
|
|
|
|
c.AuthURL = authURL
|
|
|
|
|
|
}
|
|
|
|
|
|
if authFlowID != "" {
|
|
|
|
|
|
c.AuthFlowID = authFlowID
|
|
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// 状态转换
|
|
|
|
|
|
if err := c.TransitionTo(enums.StatusInfoSubmitted, enums.ActorTypeUser, c.UserID, "用户提交企业信息"); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加业务事件
|
|
|
|
|
|
c.addDomainEvent(&EnterpriseInfoSubmittedEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
EnterpriseInfo: enterpriseInfo,
|
|
|
|
|
|
SubmittedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// 完成企业认证
|
|
|
|
|
|
func (c *Certification) CompleteEnterpriseVerification() error {
|
|
|
|
|
|
if c.Status != enums.StatusInfoSubmitted {
|
|
|
|
|
|
return fmt.Errorf("当前状态 %s 不允许完成企业认证", enums.GetStatusName(c.Status))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := c.TransitionTo(enums.StatusEnterpriseVerified, enums.ActorTypeSystem, "system", "企业认证成功"); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.addDomainEvent(&EnterpriseVerificationSuccessEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
AuthFlowID: "",
|
|
|
|
|
|
VerifiedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// HandleEnterpriseVerificationCallback 处理企业认证回调
|
|
|
|
|
|
func (c *Certification) HandleEnterpriseVerificationCallback(success bool, authFlowID string, failureReason enums.FailureReason, message string) error {
|
|
|
|
|
|
// 验证当前状态
|
|
|
|
|
|
if c.Status != enums.StatusInfoSubmitted {
|
|
|
|
|
|
return fmt.Errorf("当前状态 %s 不允许处理企业认证回调", enums.GetStatusName(c.Status))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.AuthFlowID = authFlowID
|
|
|
|
|
|
|
|
|
|
|
|
if success {
|
|
|
|
|
|
// 认证成功
|
|
|
|
|
|
if err := c.TransitionTo(enums.StatusEnterpriseVerified, enums.ActorTypeEsign, "esign_system", "企业认证成功"); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.addDomainEvent(&EnterpriseVerificationSuccessEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
AuthFlowID: authFlowID,
|
|
|
|
|
|
VerifiedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 认证失败
|
|
|
|
|
|
c.setFailureInfo(failureReason, message)
|
|
|
|
|
|
|
|
|
|
|
|
if err := c.TransitionTo(enums.StatusInfoRejected, enums.ActorTypeEsign, "esign_system", "企业认证失败"); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.addDomainEvent(&EnterpriseVerificationFailedEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
AuthFlowID: authFlowID,
|
|
|
|
|
|
FailureReason: failureReason,
|
|
|
|
|
|
FailureMessage: message,
|
|
|
|
|
|
FailedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// ApplyContract 申请合同签署
|
2025-07-28 01:46:39 +08:00
|
|
|
|
func (c *Certification) ApplyContract(EsignFlowID string, ContractSignURL string) error {
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// 验证当前状态
|
|
|
|
|
|
if c.Status != enums.StatusEnterpriseVerified {
|
|
|
|
|
|
return fmt.Errorf("当前状态 %s 不允许申请合同", enums.GetStatusName(c.Status))
|
|
|
|
|
|
}
|
|
|
|
|
|
// 状态转换
|
|
|
|
|
|
if err := c.TransitionTo(enums.StatusContractApplied, enums.ActorTypeUser, c.UserID, "用户申请合同签署"); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2025-07-28 01:46:39 +08:00
|
|
|
|
c.EsignFlowID = EsignFlowID
|
|
|
|
|
|
c.ContractSignURL = ContractSignURL
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
c.ContractFileCreatedAt = &now
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// 添加业务事件
|
|
|
|
|
|
c.addDomainEvent(&ContractAppliedEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
AppliedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// AddContractFileID 生成合同文件
|
|
|
|
|
|
func (c *Certification) AddContractFileID(contractFileID string, contractURL string) error {
|
|
|
|
|
|
c.ContractFileID = contractFileID
|
|
|
|
|
|
c.ContractURL = contractURL
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
c.ContractFileCreatedAt = &now
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// UpdateContractInfo 更新合同信息
|
|
|
|
|
|
func (c *Certification) UpdateContractInfo(contractInfo *value_objects.ContractInfo) error {
|
|
|
|
|
|
// 验证合同信息
|
|
|
|
|
|
if err := contractInfo.Validate(); err != nil {
|
|
|
|
|
|
return fmt.Errorf("合同信息验证失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新合同相关字段
|
|
|
|
|
|
c.ContractFileID = contractInfo.ContractFileID
|
|
|
|
|
|
c.EsignFlowID = contractInfo.EsignFlowID
|
|
|
|
|
|
c.ContractURL = contractInfo.ContractURL
|
|
|
|
|
|
c.ContractSignURL = contractInfo.ContractSignURL
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// SignSuccess 签署成功
|
|
|
|
|
|
func (c *Certification) SignSuccess() error {
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// 验证当前状态
|
|
|
|
|
|
if c.Status != enums.StatusContractApplied {
|
|
|
|
|
|
return fmt.Errorf("当前状态 %s 不允许处理合同签署回调", enums.GetStatusName(c.Status))
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
if err := c.TransitionTo(enums.StatusContractSigned, enums.ActorTypeEsign, "esign_system", "合同签署成功"); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
c.addDomainEvent(&ContractSignedEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
SignedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// ContractRejection 处理合同拒签
|
|
|
|
|
|
func (c *Certification) ContractRejection(message string) error {
|
|
|
|
|
|
// 验证当前状态
|
|
|
|
|
|
if c.Status != enums.StatusContractApplied {
|
|
|
|
|
|
return fmt.Errorf("当前状态 %s 不允许处理合同拒签", enums.GetStatusName(c.Status))
|
|
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// 设置失败信息
|
|
|
|
|
|
c.setFailureInfo(enums.FailureReasonContractRejectedByUser, message)
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// 状态转换
|
|
|
|
|
|
if err := c.TransitionTo(enums.StatusContractRejected, enums.ActorTypeEsign, "esign_system", "合同签署被拒绝"); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// 添加业务事件
|
|
|
|
|
|
c.addDomainEvent(&ContractSignFailedEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
FailureReason: enums.FailureReasonContractRejectedByUser,
|
|
|
|
|
|
FailureMessage: message,
|
|
|
|
|
|
FailedAt: time.Now(),
|
|
|
|
|
|
})
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ContractExpiration 处理合同过期
|
|
|
|
|
|
func (c *Certification) ContractExpiration() error {
|
|
|
|
|
|
// 验证当前状态
|
|
|
|
|
|
if c.Status != enums.StatusContractApplied {
|
|
|
|
|
|
return fmt.Errorf("当前状态 %s 不允许处理合同过期", enums.GetStatusName(c.Status))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置失败信息
|
|
|
|
|
|
c.setFailureInfo(enums.FailureReasonContractExpired, "合同签署已超时")
|
|
|
|
|
|
|
|
|
|
|
|
// 状态转换
|
|
|
|
|
|
if err := c.TransitionTo(enums.StatusContractExpired, enums.ActorTypeSystem, "system", "合同签署超时"); err != nil {
|
|
|
|
|
|
return err
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// 添加业务事件
|
|
|
|
|
|
c.addDomainEvent(&ContractSignFailedEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
FailureReason: enums.FailureReasonContractExpired,
|
|
|
|
|
|
FailureMessage: "合同签署已超时",
|
|
|
|
|
|
FailedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
return nil
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// RetryFromFailure 从失败状态重试
|
|
|
|
|
|
func (c *Certification) RetryFromFailure(actor enums.ActorType, actorID string) error {
|
|
|
|
|
|
if !enums.IsFailureStatus(c.Status) {
|
|
|
|
|
|
return errors.New("当前状态不是失败状态,无需重试")
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// 检查重试次数限制
|
|
|
|
|
|
if c.RetryCount >= 3 {
|
|
|
|
|
|
return errors.New("已达到最大重试次数限制")
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
|
|
|
|
|
// 检查失败原因是否可重试
|
|
|
|
|
|
if !enums.IsRetryable(c.FailureReason) {
|
|
|
|
|
|
return fmt.Errorf("失败原因 %s 不支持重试", enums.GetFailureReasonName(c.FailureReason))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var targetStatus enums.CertificationStatus
|
|
|
|
|
|
var reason string
|
|
|
|
|
|
|
|
|
|
|
|
switch c.Status {
|
|
|
|
|
|
case enums.StatusInfoRejected:
|
|
|
|
|
|
targetStatus = enums.StatusInfoSubmitted
|
|
|
|
|
|
reason = "重新提交企业信息"
|
|
|
|
|
|
case enums.StatusContractRejected, enums.StatusContractExpired:
|
|
|
|
|
|
targetStatus = enums.StatusEnterpriseVerified
|
|
|
|
|
|
reason = "重置状态,准备重新申请合同"
|
|
|
|
|
|
default:
|
|
|
|
|
|
return fmt.Errorf("不支持从状态 %s 重试", enums.GetStatusName(c.Status))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 增加重试次数
|
|
|
|
|
|
c.RetryCount++
|
|
|
|
|
|
|
|
|
|
|
|
// 状态转换
|
|
|
|
|
|
if err := c.TransitionTo(targetStatus, actor, actorID, reason); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加重试事件
|
|
|
|
|
|
c.addDomainEvent(&CertificationRetryEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
FromStatus: c.Status,
|
|
|
|
|
|
ToStatus: targetStatus,
|
|
|
|
|
|
RetryCount: c.RetryCount,
|
|
|
|
|
|
RetriedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// CompleteCertification 完成认证
|
|
|
|
|
|
func (c *Certification) CompleteCertification() error {
|
|
|
|
|
|
// 验证当前状态
|
|
|
|
|
|
if c.Status != enums.StatusContractSigned {
|
|
|
|
|
|
return fmt.Errorf("当前状态 %s 不允许完成认证", enums.GetStatusName(c.Status))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证合同信息完整性
|
|
|
|
|
|
if c.ContractFileID == "" || c.EsignFlowID == "" || c.ContractURL == "" {
|
|
|
|
|
|
return errors.New("合同信息不完整,无法完成认证")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 状态转换
|
|
|
|
|
|
if err := c.TransitionTo(enums.StatusCompleted, enums.ActorTypeSystem, "system", "系统处理完成,认证成功"); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加业务事件
|
|
|
|
|
|
c.addDomainEvent(&CertificationCompletedEvent{
|
|
|
|
|
|
CertificationID: c.ID,
|
|
|
|
|
|
UserID: c.UserID,
|
|
|
|
|
|
CompletedAt: time.Now(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// ================ 查询方法 ================
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// GetDataByStatus 根据当前状态获取对应的数据
|
|
|
|
|
|
func (c *Certification) GetDataByStatus() map[string]interface{} {
|
|
|
|
|
|
data := map[string]interface{}{}
|
|
|
|
|
|
switch c.Status {
|
|
|
|
|
|
case enums.StatusInfoSubmitted:
|
|
|
|
|
|
data["auth_url"] = c.AuthURL
|
|
|
|
|
|
case enums.StatusInfoRejected:
|
|
|
|
|
|
data["failure_reason"] = c.FailureReason
|
|
|
|
|
|
data["failure_message"] = c.FailureMessage
|
|
|
|
|
|
case enums.StatusEnterpriseVerified:
|
|
|
|
|
|
data["ContractURL"] = c.ContractURL
|
|
|
|
|
|
case enums.StatusContractApplied:
|
|
|
|
|
|
data["contract_sign_url"] = c.ContractSignURL
|
|
|
|
|
|
case enums.StatusContractSigned:
|
|
|
|
|
|
case enums.StatusCompleted:
|
|
|
|
|
|
data["completed_at"] = c.CompletedAt
|
|
|
|
|
|
case enums.StatusContractRejected:
|
|
|
|
|
|
data["failure_reason"] = c.FailureReason
|
|
|
|
|
|
data["failure_message"] = c.FailureMessage
|
|
|
|
|
|
}
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
|
|
|
|
|
// GetProgress 获取认证进度百分比
|
|
|
|
|
|
func (c *Certification) GetProgress() int {
|
|
|
|
|
|
return enums.GetProgressPercentage(c.Status)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IsUserActionRequired 是否需要用户操作
|
|
|
|
|
|
func (c *Certification) IsUserActionRequired() bool {
|
|
|
|
|
|
return enums.IsUserActionRequired(c.Status)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetCurrentStatusName 获取当前状态名称
|
|
|
|
|
|
func (c *Certification) GetCurrentStatusName() string {
|
|
|
|
|
|
return enums.GetStatusName(c.Status)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetUserActionHint 获取用户操作提示
|
|
|
|
|
|
func (c *Certification) GetUserActionHint() string {
|
|
|
|
|
|
return enums.GetUserActionHint(c.Status)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetAvailableActions 获取当前可执行的操作
|
|
|
|
|
|
func (c *Certification) GetAvailableActions() []string {
|
|
|
|
|
|
actions := make([]string, 0)
|
|
|
|
|
|
|
|
|
|
|
|
switch c.Status {
|
|
|
|
|
|
case enums.StatusPending:
|
|
|
|
|
|
actions = append(actions, "submit_enterprise_info")
|
|
|
|
|
|
case enums.StatusEnterpriseVerified:
|
|
|
|
|
|
actions = append(actions, "apply_contract")
|
|
|
|
|
|
case enums.StatusInfoRejected, enums.StatusContractRejected, enums.StatusContractExpired:
|
|
|
|
|
|
if enums.IsRetryable(c.FailureReason) && c.RetryCount < 3 {
|
|
|
|
|
|
actions = append(actions, "retry")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return actions
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IsFinalStatus 是否为最终状态
|
|
|
|
|
|
func (c *Certification) IsFinalStatus() bool {
|
|
|
|
|
|
return enums.IsFinalStatus(c.Status)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// IsCompleted 是否已完成
|
2025-07-21 15:13:26 +08:00
|
|
|
|
func (c *Certification) IsCompleted() bool {
|
2025-07-28 01:46:39 +08:00
|
|
|
|
return c.Status == enums.StatusCompleted
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-20 20:53:26 +08:00
|
|
|
|
// GetNextValidStatuses 获取下一个有效状态
|
|
|
|
|
|
func (c *Certification) GetNextValidStatuses() []enums.CertificationStatus {
|
2025-07-21 15:13:26 +08:00
|
|
|
|
return enums.GetNextValidStatuses(c.Status)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetFailureInfo 获取失败信息
|
|
|
|
|
|
func (c *Certification) GetFailureInfo() (enums.FailureReason, string) {
|
|
|
|
|
|
return c.FailureReason, c.FailureMessage
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// IsContractFileExpired 判断合同文件是否过期(生成后50分钟过期)
|
|
|
|
|
|
func (c *Certification) IsContractFileExpired() bool {
|
|
|
|
|
|
if c.ContractFileCreatedAt == nil && c.Status == enums.StatusEnterpriseVerified {
|
|
|
|
|
|
// 60分钟前
|
|
|
|
|
|
t := time.Now().Add(-60 * time.Minute)
|
|
|
|
|
|
c.ContractFileCreatedAt = &t
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
if c.ContractFileCreatedAt != nil {
|
|
|
|
|
|
return time.Since(*c.ContractFileCreatedAt) > 50*time.Minute
|
|
|
|
|
|
}
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IsContractFileNeedUpdate 是否需要更新合同文件
|
|
|
|
|
|
func (c *Certification) IsContractFileNeedUpdate() bool {
|
|
|
|
|
|
if c.IsContractFileExpired() && c.Status == enums.StatusEnterpriseVerified {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// ================ 业务规则验证 ================
|
|
|
|
|
|
|
|
|
|
|
|
// ValidateBusinessRules 验证业务规则
|
|
|
|
|
|
func (c *Certification) ValidateBusinessRules() error {
|
|
|
|
|
|
// 基础验证
|
|
|
|
|
|
if c.UserID == "" {
|
|
|
|
|
|
return errors.New("用户ID不能为空")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !enums.IsValidStatus(c.Status) {
|
|
|
|
|
|
return fmt.Errorf("无效的认证状态: %s", c.Status)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 状态相关验证
|
|
|
|
|
|
switch c.Status {
|
|
|
|
|
|
case enums.StatusEnterpriseVerified:
|
2025-07-28 01:46:39 +08:00
|
|
|
|
if c.ContractURL == "" {
|
|
|
|
|
|
return errors.New("企业认证成功后,合同文件ID和合同URL不能为空")
|
2025-07-21 15:13:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
case enums.StatusContractSigned:
|
|
|
|
|
|
if c.ContractFileID == "" || c.EsignFlowID == "" {
|
|
|
|
|
|
return errors.New("合同签署状态下必须有完整的合同信息")
|
|
|
|
|
|
}
|
2025-07-28 01:46:39 +08:00
|
|
|
|
case enums.StatusCompleted:
|
|
|
|
|
|
if c.ContractFileID == "" || c.EsignFlowID == "" || c.ContractURL == "" {
|
|
|
|
|
|
return errors.New("认证完成状态下必须有完整的合同信息")
|
|
|
|
|
|
}
|
|
|
|
|
|
if c.CompletedAt == nil {
|
|
|
|
|
|
return errors.New("认证完成状态下必须有完成时间")
|
|
|
|
|
|
}
|
2025-07-20 20:53:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// 失败状态验证
|
|
|
|
|
|
if enums.IsFailureStatus(c.Status) {
|
|
|
|
|
|
if c.FailureReason == "" {
|
|
|
|
|
|
return errors.New("失败状态下必须有失败原因")
|
|
|
|
|
|
}
|
|
|
|
|
|
if !enums.IsValidFailureReason(c.FailureReason) {
|
|
|
|
|
|
return fmt.Errorf("无效的失败原因: %s", c.FailureReason)
|
|
|
|
|
|
}
|
2025-07-20 20:53:26 +08:00
|
|
|
|
}
|
2025-07-21 15:13:26 +08:00
|
|
|
|
|
|
|
|
|
|
return nil
|
2025-07-20 20:53:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 15:13:26 +08:00
|
|
|
|
// validateActorPermission 验证操作者权限
|
|
|
|
|
|
func (c *Certification) validateActorPermission(targetStatus enums.CertificationStatus, actor enums.ActorType) bool {
|
|
|
|
|
|
// 定义状态转换的权限规则
|
|
|
|
|
|
permissions := map[enums.CertificationStatus][]enums.ActorType{
|
2025-07-28 01:46:39 +08:00
|
|
|
|
enums.StatusInfoSubmitted: {enums.ActorTypeUser, enums.ActorTypeAdmin},
|
2025-07-21 15:13:26 +08:00
|
|
|
|
enums.StatusEnterpriseVerified: {enums.ActorTypeEsign, enums.ActorTypeSystem, enums.ActorTypeAdmin},
|
|
|
|
|
|
enums.StatusInfoRejected: {enums.ActorTypeEsign, enums.ActorTypeSystem, enums.ActorTypeAdmin},
|
2025-07-28 01:46:39 +08:00
|
|
|
|
enums.StatusContractApplied: {enums.ActorTypeUser, enums.ActorTypeAdmin},
|
2025-07-21 15:13:26 +08:00
|
|
|
|
enums.StatusContractSigned: {enums.ActorTypeEsign, enums.ActorTypeSystem, enums.ActorTypeAdmin},
|
|
|
|
|
|
enums.StatusContractRejected: {enums.ActorTypeEsign, enums.ActorTypeSystem, enums.ActorTypeAdmin},
|
|
|
|
|
|
enums.StatusContractExpired: {enums.ActorTypeEsign, enums.ActorTypeSystem, enums.ActorTypeAdmin},
|
2025-07-28 01:46:39 +08:00
|
|
|
|
enums.StatusCompleted: {enums.ActorTypeSystem, enums.ActorTypeAdmin},
|
2025-07-21 15:13:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
allowedActors, exists := permissions[targetStatus]
|
|
|
|
|
|
if !exists {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, allowedActor := range allowedActors {
|
|
|
|
|
|
if actor == allowedActor {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================ 辅助方法 ================
|
|
|
|
|
|
|
|
|
|
|
|
// updateTimestampByStatus 根据状态更新对应的时间戳
|
|
|
|
|
|
func (c *Certification) updateTimestampByStatus(status enums.CertificationStatus) {
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
|
|
|
|
|
|
switch status {
|
|
|
|
|
|
case enums.StatusInfoSubmitted:
|
|
|
|
|
|
c.InfoSubmittedAt = &now
|
|
|
|
|
|
case enums.StatusEnterpriseVerified:
|
|
|
|
|
|
c.EnterpriseVerifiedAt = &now
|
|
|
|
|
|
case enums.StatusContractApplied:
|
|
|
|
|
|
c.ContractAppliedAt = &now
|
|
|
|
|
|
case enums.StatusContractSigned:
|
|
|
|
|
|
c.ContractSignedAt = &now
|
2025-07-28 01:46:39 +08:00
|
|
|
|
case enums.StatusCompleted:
|
|
|
|
|
|
c.CompletedAt = &now
|
2025-07-21 15:13:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// updateTransitionAudit 更新状态转换审计信息
|
|
|
|
|
|
func (c *Certification) updateTransitionAudit(actor enums.ActorType, actorID string) {
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
c.LastTransitionAt = &now
|
|
|
|
|
|
c.LastTransitionBy = actor
|
|
|
|
|
|
c.LastTransitionActor = actorID
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// setFailureInfo 设置失败信息
|
|
|
|
|
|
func (c *Certification) setFailureInfo(reason enums.FailureReason, message string) {
|
|
|
|
|
|
c.FailureReason = reason
|
|
|
|
|
|
c.FailureMessage = message
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// clearFailureInfo 清除失败信息
|
|
|
|
|
|
func (c *Certification) clearFailureInfo() {
|
|
|
|
|
|
c.FailureReason = ""
|
|
|
|
|
|
c.FailureMessage = ""
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================ 领域事件管理 ================
|
|
|
|
|
|
|
|
|
|
|
|
// addDomainEvent 添加领域事件
|
|
|
|
|
|
func (c *Certification) addDomainEvent(event interface{}) {
|
|
|
|
|
|
if c.domainEvents == nil {
|
|
|
|
|
|
c.domainEvents = make([]interface{}, 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
c.domainEvents = append(c.domainEvents, event)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetDomainEvents 获取领域事件
|
|
|
|
|
|
func (c *Certification) GetDomainEvents() []interface{} {
|
|
|
|
|
|
return c.domainEvents
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ClearDomainEvents 清除领域事件
|
|
|
|
|
|
func (c *Certification) ClearDomainEvents() {
|
|
|
|
|
|
c.domainEvents = make([]interface{}, 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================ 领域事件定义 ================
|
|
|
|
|
|
|
|
|
|
|
|
// CertificationCreatedEvent 认证创建事件
|
|
|
|
|
|
type CertificationCreatedEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
CreatedAt time.Time `json:"created_at"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CertificationStatusChangedEvent 认证状态变更事件
|
|
|
|
|
|
type CertificationStatusChangedEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
FromStatus enums.CertificationStatus `json:"from_status"`
|
|
|
|
|
|
ToStatus enums.CertificationStatus `json:"to_status"`
|
|
|
|
|
|
Actor enums.ActorType `json:"actor"`
|
|
|
|
|
|
ActorID string `json:"actor_id"`
|
|
|
|
|
|
Reason string `json:"reason"`
|
|
|
|
|
|
TransitionedAt time.Time `json:"transitioned_at"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// EnterpriseInfoSubmittedEvent 企业信息提交事件
|
|
|
|
|
|
type EnterpriseInfoSubmittedEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
EnterpriseInfo *value_objects.EnterpriseInfo `json:"enterprise_info"`
|
|
|
|
|
|
SubmittedAt time.Time `json:"submitted_at"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// EnterpriseVerificationSuccessEvent 企业认证成功事件
|
|
|
|
|
|
type EnterpriseVerificationSuccessEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
AuthFlowID string `json:"auth_flow_id"`
|
|
|
|
|
|
VerifiedAt time.Time `json:"verified_at"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// EnterpriseVerificationFailedEvent 企业认证失败事件
|
|
|
|
|
|
type EnterpriseVerificationFailedEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
AuthFlowID string `json:"auth_flow_id"`
|
|
|
|
|
|
FailureReason enums.FailureReason `json:"failure_reason"`
|
|
|
|
|
|
FailureMessage string `json:"failure_message"`
|
|
|
|
|
|
FailedAt time.Time `json:"failed_at"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ContractAppliedEvent 合同申请事件
|
|
|
|
|
|
type ContractAppliedEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
AppliedAt time.Time `json:"applied_at"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ContractSignedEvent 合同签署成功事件
|
|
|
|
|
|
type ContractSignedEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
ContractURL string `json:"contract_url"`
|
|
|
|
|
|
SignedAt time.Time `json:"signed_at"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ContractSignFailedEvent 合同签署失败事件
|
|
|
|
|
|
type ContractSignFailedEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
FailureReason enums.FailureReason `json:"failure_reason"`
|
|
|
|
|
|
FailureMessage string `json:"failure_message"`
|
|
|
|
|
|
FailedAt time.Time `json:"failed_at"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CertificationCompletedEvent 认证完成事件
|
|
|
|
|
|
type CertificationCompletedEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
CompletedAt time.Time `json:"completed_at"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CertificationRetryEvent 认证重试事件
|
|
|
|
|
|
type CertificationRetryEvent struct {
|
|
|
|
|
|
CertificationID string `json:"certification_id"`
|
|
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
|
|
FromStatus enums.CertificationStatus `json:"from_status"`
|
|
|
|
|
|
ToStatus enums.CertificationStatus `json:"to_status"`
|
|
|
|
|
|
RetryCount int `json:"retry_count"`
|
|
|
|
|
|
RetriedAt time.Time `json:"retried_at"`
|
2025-07-11 21:05:58 +08:00
|
|
|
|
}
|