317 lines
9.1 KiB
Go
317 lines
9.1 KiB
Go
|
|
package entities
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"github.com/google/uuid"
|
|||
|
|
"gorm.io/gorm"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ContractType 合同类型枚举
|
|||
|
|
type ContractType string
|
|||
|
|
|
|||
|
|
const (
|
|||
|
|
ContractTypeCooperation ContractType = "cooperation" // 合作协议
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ContractInfo 合同信息聚合根
|
|||
|
|
// 存储企业签署的合同信息,一个企业可以有多个合同
|
|||
|
|
type ContractInfo struct {
|
|||
|
|
// 基础标识
|
|||
|
|
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"合同信息唯一标识"`
|
|||
|
|
EnterpriseInfoID string `gorm:"type:varchar(36);not null;index" json:"enterprise_info_id" comment:"关联企业信息ID"`
|
|||
|
|
UserID string `gorm:"type:varchar(36);not null;index" json:"user_id" comment:"关联用户ID"`
|
|||
|
|
|
|||
|
|
// 合同基本信息
|
|||
|
|
ContractName string `gorm:"type:varchar(255);not null" json:"contract_name" comment:"合同名称"`
|
|||
|
|
ContractType ContractType `gorm:"type:varchar(50);not null;index" json:"contract_type" comment:"合同类型"`
|
|||
|
|
ContractFileID string `gorm:"type:varchar(100);not null" json:"contract_file_id" comment:"合同文件ID"`
|
|||
|
|
ContractFileURL string `gorm:"type:varchar(500);not null" json:"contract_file_url" comment:"合同文件下载链接"`
|
|||
|
|
|
|||
|
|
// 时间戳字段
|
|||
|
|
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:"软删除时间"`
|
|||
|
|
|
|||
|
|
// 关联关系
|
|||
|
|
EnterpriseInfo *EnterpriseInfo `gorm:"foreignKey:EnterpriseInfoID" json:"enterprise_info,omitempty" comment:"关联的企业信息"`
|
|||
|
|
|
|||
|
|
// 领域事件 (不持久化)
|
|||
|
|
domainEvents []interface{} `gorm:"-" json:"-"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TableName 指定数据库表名
|
|||
|
|
func (ContractInfo) TableName() string {
|
|||
|
|
return "contract_infos"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// BeforeCreate GORM钩子:创建前自动生成UUID
|
|||
|
|
func (c *ContractInfo) BeforeCreate(tx *gorm.DB) error {
|
|||
|
|
if c.ID == "" {
|
|||
|
|
c.ID = uuid.New().String()
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================ 工厂方法 ================
|
|||
|
|
|
|||
|
|
// NewContractInfo 创建新的合同信息
|
|||
|
|
func NewContractInfo(enterpriseInfoID, userID, contractName string, contractType ContractType, contractFileID, contractFileURL string) (*ContractInfo, error) {
|
|||
|
|
if enterpriseInfoID == "" {
|
|||
|
|
return nil, fmt.Errorf("企业信息ID不能为空")
|
|||
|
|
}
|
|||
|
|
if userID == "" {
|
|||
|
|
return nil, fmt.Errorf("用户ID不能为空")
|
|||
|
|
}
|
|||
|
|
if contractName == "" {
|
|||
|
|
return nil, fmt.Errorf("合同名称不能为空")
|
|||
|
|
}
|
|||
|
|
if contractType == "" {
|
|||
|
|
return nil, fmt.Errorf("合同类型不能为空")
|
|||
|
|
}
|
|||
|
|
if contractFileID == "" {
|
|||
|
|
return nil, fmt.Errorf("合同文件ID不能为空")
|
|||
|
|
}
|
|||
|
|
if contractFileURL == "" {
|
|||
|
|
return nil, fmt.Errorf("合同文件URL不能为空")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证合同类型
|
|||
|
|
if !isValidContractType(contractType) {
|
|||
|
|
return nil, fmt.Errorf("无效的合同类型: %s", contractType)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
contractInfo := &ContractInfo{
|
|||
|
|
ID: uuid.New().String(),
|
|||
|
|
EnterpriseInfoID: enterpriseInfoID,
|
|||
|
|
UserID: userID,
|
|||
|
|
ContractName: contractName,
|
|||
|
|
ContractType: contractType,
|
|||
|
|
ContractFileID: contractFileID,
|
|||
|
|
ContractFileURL: contractFileURL,
|
|||
|
|
domainEvents: make([]interface{}, 0),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加领域事件
|
|||
|
|
contractInfo.addDomainEvent(&ContractInfoCreatedEvent{
|
|||
|
|
ContractInfoID: contractInfo.ID,
|
|||
|
|
EnterpriseInfoID: enterpriseInfoID,
|
|||
|
|
UserID: userID,
|
|||
|
|
ContractName: contractName,
|
|||
|
|
ContractType: string(contractType),
|
|||
|
|
CreatedAt: time.Now(),
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return contractInfo, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================ 聚合根核心方法 ================
|
|||
|
|
|
|||
|
|
// UpdateContractInfo 更新合同信息
|
|||
|
|
func (c *ContractInfo) UpdateContractInfo(contractName, contractFileID, contractFileURL string) error {
|
|||
|
|
// 验证输入参数
|
|||
|
|
if contractName == "" {
|
|||
|
|
return fmt.Errorf("合同名称不能为空")
|
|||
|
|
}
|
|||
|
|
if contractFileID == "" {
|
|||
|
|
return fmt.Errorf("合同文件ID不能为空")
|
|||
|
|
}
|
|||
|
|
if contractFileURL == "" {
|
|||
|
|
return fmt.Errorf("合同文件URL不能为空")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 记录原始值用于事件
|
|||
|
|
oldContractName := c.ContractName
|
|||
|
|
oldContractFileID := c.ContractFileID
|
|||
|
|
|
|||
|
|
// 更新字段
|
|||
|
|
c.ContractName = contractName
|
|||
|
|
c.ContractFileID = contractFileID
|
|||
|
|
c.ContractFileURL = contractFileURL
|
|||
|
|
|
|||
|
|
// 添加领域事件
|
|||
|
|
c.addDomainEvent(&ContractInfoUpdatedEvent{
|
|||
|
|
ContractInfoID: c.ID,
|
|||
|
|
EnterpriseInfoID: c.EnterpriseInfoID,
|
|||
|
|
UserID: c.UserID,
|
|||
|
|
OldContractName: oldContractName,
|
|||
|
|
NewContractName: contractName,
|
|||
|
|
OldContractFileID: oldContractFileID,
|
|||
|
|
NewContractFileID: contractFileID,
|
|||
|
|
UpdatedAt: time.Now(),
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DeleteContract 删除合同
|
|||
|
|
func (c *ContractInfo) DeleteContract() error {
|
|||
|
|
// 添加领域事件
|
|||
|
|
c.addDomainEvent(&ContractInfoDeletedEvent{
|
|||
|
|
ContractInfoID: c.ID,
|
|||
|
|
EnterpriseInfoID: c.EnterpriseInfoID,
|
|||
|
|
UserID: c.UserID,
|
|||
|
|
ContractName: c.ContractName,
|
|||
|
|
ContractType: string(c.ContractType),
|
|||
|
|
DeletedAt: time.Now(),
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================ 业务规则验证 ================
|
|||
|
|
|
|||
|
|
// ValidateBusinessRules 验证业务规则
|
|||
|
|
func (c *ContractInfo) ValidateBusinessRules() error {
|
|||
|
|
// 基础字段验证
|
|||
|
|
if err := c.validateBasicFields(); err != nil {
|
|||
|
|
return fmt.Errorf("基础字段验证失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 业务规则验证
|
|||
|
|
if err := c.validateBusinessLogic(); err != nil {
|
|||
|
|
return fmt.Errorf("业务规则验证失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// validateBasicFields 验证基础字段
|
|||
|
|
func (c *ContractInfo) validateBasicFields() error {
|
|||
|
|
if c.EnterpriseInfoID == "" {
|
|||
|
|
return fmt.Errorf("企业信息ID不能为空")
|
|||
|
|
}
|
|||
|
|
if c.UserID == "" {
|
|||
|
|
return fmt.Errorf("用户ID不能为空")
|
|||
|
|
}
|
|||
|
|
if c.ContractName == "" {
|
|||
|
|
return fmt.Errorf("合同名称不能为空")
|
|||
|
|
}
|
|||
|
|
if c.ContractType == "" {
|
|||
|
|
return fmt.Errorf("合同类型不能为空")
|
|||
|
|
}
|
|||
|
|
if c.ContractFileID == "" {
|
|||
|
|
return fmt.Errorf("合同文件ID不能为空")
|
|||
|
|
}
|
|||
|
|
if c.ContractFileURL == "" {
|
|||
|
|
return fmt.Errorf("合同文件URL不能为空")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 合同类型验证
|
|||
|
|
if !isValidContractType(c.ContractType) {
|
|||
|
|
return fmt.Errorf("无效的合同类型: %s", c.ContractType)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// validateBusinessLogic 验证业务逻辑
|
|||
|
|
func (c *ContractInfo) validateBusinessLogic() error {
|
|||
|
|
// 合同名称长度限制
|
|||
|
|
if len(c.ContractName) > 255 {
|
|||
|
|
return fmt.Errorf("合同名称长度不能超过255个字符")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 合同文件URL格式验证
|
|||
|
|
if !isValidURL(c.ContractFileURL) {
|
|||
|
|
return fmt.Errorf("合同文件URL格式无效")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================ 查询方法 ================
|
|||
|
|
|
|||
|
|
// GetContractTypeName 获取合同类型名称
|
|||
|
|
func (c *ContractInfo) GetContractTypeName() string {
|
|||
|
|
switch c.ContractType {
|
|||
|
|
case ContractTypeCooperation:
|
|||
|
|
return "合作协议"
|
|||
|
|
default:
|
|||
|
|
return "未知类型"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IsCooperationContract 检查是否为合作协议
|
|||
|
|
func (c *ContractInfo) IsCooperationContract() bool {
|
|||
|
|
return c.ContractType == ContractTypeCooperation
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================ 领域事件管理 ================
|
|||
|
|
|
|||
|
|
// addDomainEvent 添加领域事件
|
|||
|
|
func (c *ContractInfo) addDomainEvent(event interface{}) {
|
|||
|
|
if c.domainEvents == nil {
|
|||
|
|
c.domainEvents = make([]interface{}, 0)
|
|||
|
|
}
|
|||
|
|
c.domainEvents = append(c.domainEvents, event)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetDomainEvents 获取领域事件
|
|||
|
|
func (c *ContractInfo) GetDomainEvents() []interface{} {
|
|||
|
|
return c.domainEvents
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ClearDomainEvents 清除领域事件
|
|||
|
|
func (c *ContractInfo) ClearDomainEvents() {
|
|||
|
|
c.domainEvents = make([]interface{}, 0)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================ 私有验证方法 ================
|
|||
|
|
|
|||
|
|
// isValidContractType 验证合同类型
|
|||
|
|
func isValidContractType(contractType ContractType) bool {
|
|||
|
|
switch contractType {
|
|||
|
|
case ContractTypeCooperation:
|
|||
|
|
return true
|
|||
|
|
default:
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// isValidURL 验证URL格式
|
|||
|
|
func isValidURL(url string) bool {
|
|||
|
|
// 简单的URL格式验证
|
|||
|
|
if len(url) < 10 {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
if url[:7] != "http://" && url[:8] != "https://" {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================ 领域事件定义 ================
|
|||
|
|
|
|||
|
|
// ContractInfoCreatedEvent 合同信息创建事件
|
|||
|
|
type ContractInfoCreatedEvent struct {
|
|||
|
|
ContractInfoID string `json:"contract_info_id"`
|
|||
|
|
EnterpriseInfoID string `json:"enterprise_info_id"`
|
|||
|
|
UserID string `json:"user_id"`
|
|||
|
|
ContractName string `json:"contract_name"`
|
|||
|
|
ContractType string `json:"contract_type"`
|
|||
|
|
CreatedAt time.Time `json:"created_at"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ContractInfoUpdatedEvent 合同信息更新事件
|
|||
|
|
type ContractInfoUpdatedEvent struct {
|
|||
|
|
ContractInfoID string `json:"contract_info_id"`
|
|||
|
|
EnterpriseInfoID string `json:"enterprise_info_id"`
|
|||
|
|
UserID string `json:"user_id"`
|
|||
|
|
OldContractName string `json:"old_contract_name"`
|
|||
|
|
NewContractName string `json:"new_contract_name"`
|
|||
|
|
OldContractFileID string `json:"old_contract_file_id"`
|
|||
|
|
NewContractFileID string `json:"new_contract_file_id"`
|
|||
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ContractInfoDeletedEvent 合同信息删除事件
|
|||
|
|
type ContractInfoDeletedEvent struct {
|
|||
|
|
ContractInfoID string `json:"contract_info_id"`
|
|||
|
|
EnterpriseInfoID string `json:"enterprise_info_id"`
|
|||
|
|
UserID string `json:"user_id"`
|
|||
|
|
ContractName string `json:"contract_name"`
|
|||
|
|
ContractType string `json:"contract_type"`
|
|||
|
|
DeletedAt time.Time `json:"deleted_at"`
|
|||
|
|
}
|