366 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			366 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package value_objects
 | ||
| 
 | ||
| import (
 | ||
| 	"errors"
 | ||
| 	"fmt"
 | ||
| 	"regexp"
 | ||
| 	"strings"
 | ||
| )
 | ||
| 
 | ||
| // EnterpriseInfo 企业信息值对象
 | ||
| // 封装企业认证所需的核心信息,包含完整的业务规则验证
 | ||
| type EnterpriseInfo struct {
 | ||
| 	// 企业基本信息
 | ||
| 	CompanyName       string `json:"company_name"`        // 企业名称
 | ||
| 	UnifiedSocialCode string `json:"unified_social_code"` // 统一社会信用代码
 | ||
| 
 | ||
| 	// 法定代表人信息
 | ||
| 	LegalPersonName  string `json:"legal_person_name"`  // 法定代表人姓名
 | ||
| 	LegalPersonID    string `json:"legal_person_id"`    // 法定代表人身份证号
 | ||
| 	LegalPersonPhone string `json:"legal_person_phone"` // 法定代表人手机号
 | ||
| 
 | ||
| 	// 企业详细信息
 | ||
| 	RegisteredAddress string `json:"registered_address"` // 注册地址
 | ||
| 	EnterpriseAddress string `json:"enterprise_address"` // 企业地址(新增)
 | ||
| }
 | ||
| 
 | ||
| // NewEnterpriseInfo 创建企业信息值对象
 | ||
| func NewEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) (*EnterpriseInfo, error) {
 | ||
| 	info := &EnterpriseInfo{
 | ||
| 		CompanyName:       strings.TrimSpace(companyName),
 | ||
| 		UnifiedSocialCode: strings.TrimSpace(unifiedSocialCode),
 | ||
| 		LegalPersonName:   strings.TrimSpace(legalPersonName),
 | ||
| 		LegalPersonID:     strings.TrimSpace(legalPersonID),
 | ||
| 		LegalPersonPhone:  strings.TrimSpace(legalPersonPhone),
 | ||
| 		EnterpriseAddress: strings.TrimSpace(enterpriseAddress),
 | ||
| 	}
 | ||
| 
 | ||
| 	if err := info.Validate(); err != nil {
 | ||
| 		return nil, fmt.Errorf("企业信息验证失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	return info, nil
 | ||
| }
 | ||
| 
 | ||
| // Validate 验证企业信息的完整性和格式
 | ||
| func (e *EnterpriseInfo) Validate() error {
 | ||
| 	if err := e.validateCompanyName(); err != nil {
 | ||
| 		return err
 | ||
| 	}
 | ||
| 
 | ||
| 	if err := e.validateUnifiedSocialCode(); err != nil {
 | ||
| 		return err
 | ||
| 	}
 | ||
| 
 | ||
| 	if err := e.validateLegalPersonName(); err != nil {
 | ||
| 		return err
 | ||
| 	}
 | ||
| 
 | ||
| 	if err := e.validateLegalPersonID(); err != nil {
 | ||
| 		return err
 | ||
| 	}
 | ||
| 
 | ||
| 	if err := e.validateLegalPersonPhone(); err != nil {
 | ||
| 		return err
 | ||
| 	}
 | ||
| 
 | ||
| 	if err := e.validateEnterpriseAddress(); err != nil {
 | ||
| 		return err
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // validateCompanyName 验证企业名称
 | ||
| func (e *EnterpriseInfo) validateCompanyName() error {
 | ||
| 	if e.CompanyName == "" {
 | ||
| 		return errors.New("企业名称不能为空")
 | ||
| 	}
 | ||
| 
 | ||
| 	if len(e.CompanyName) < 2 {
 | ||
| 		return errors.New("企业名称长度不能少于2个字符")
 | ||
| 	}
 | ||
| 
 | ||
| 	if len(e.CompanyName) > 100 {
 | ||
| 		return errors.New("企业名称长度不能超过100个字符")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 检查是否包含非法字符(允许括号)
 | ||
| 	invalidChars := []string{
 | ||
| 		"`", "~", "!", "@", "#", "$", "%", "^", "&", "*",
 | ||
| 		"+", "=", "{", "}", "[", "]", "【", "】", "\\", "|", ";", ":", "'", "\"", "<", ">", ",", ".", "?", "/",
 | ||
| 	}
 | ||
| 	for _, char := range invalidChars {
 | ||
| 		if strings.Contains(e.CompanyName, char) {
 | ||
| 			return fmt.Errorf("企业名称不能包含特殊字符: %s", char)
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // validateUnifiedSocialCode 验证统一社会信用代码
 | ||
| func (e *EnterpriseInfo) validateUnifiedSocialCode() error {
 | ||
| 	if e.UnifiedSocialCode == "" {
 | ||
| 		return errors.New("统一社会信用代码不能为空")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 统一社会信用代码格式验证(18位数字和字母)
 | ||
| 	pattern := `^[0-9A-HJ-NPQRTUWXY]{2}[0-9]{6}[0-9A-HJ-NPQRTUWXY]{10}$`
 | ||
| 	matched, err := regexp.MatchString(pattern, e.UnifiedSocialCode)
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("统一社会信用代码格式验证错误: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	if !matched {
 | ||
| 		return errors.New("统一社会信用代码格式不正确,应为18位数字和字母组合")
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // validateLegalPersonName 验证法定代表人姓名
 | ||
| func (e *EnterpriseInfo) validateLegalPersonName() error {
 | ||
| 	if e.LegalPersonName == "" {
 | ||
| 		return errors.New("法定代表人姓名不能为空")
 | ||
| 	}
 | ||
| 
 | ||
| 	if len(e.LegalPersonName) < 2 {
 | ||
| 		return errors.New("法定代表人姓名长度不能少于2个字符")
 | ||
| 	}
 | ||
| 
 | ||
| 	if len(e.LegalPersonName) > 50 {
 | ||
| 		return errors.New("法定代表人姓名长度不能超过50个字符")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 中文姓名格式验证
 | ||
| 	pattern := "^[一-龥·]+$"
 | ||
| 	matched, err := regexp.MatchString(pattern, e.LegalPersonName)
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("法定代表人姓名格式验证错误: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	if !matched {
 | ||
| 		return errors.New("法定代表人姓名只能包含中文字符和间隔号")
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // validateLegalPersonID 验证法定代表人身份证号
 | ||
| func (e *EnterpriseInfo) validateLegalPersonID() error {
 | ||
| 	if e.LegalPersonID == "" {
 | ||
| 		return errors.New("法定代表人身份证号不能为空")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 身份证号格式验证(18位)
 | ||
| 	if len(e.LegalPersonID) != 18 {
 | ||
| 		return errors.New("身份证号必须为18位")
 | ||
| 	}
 | ||
| 
 | ||
| 	pattern := `^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$`
 | ||
| 	matched, err := regexp.MatchString(pattern, e.LegalPersonID)
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("身份证号格式验证错误: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	if !matched {
 | ||
| 		return errors.New("身份证号格式不正确")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 身份证号校验码验证
 | ||
| 	if !e.validateIDChecksum() {
 | ||
| 		return errors.New("身份证号校验码错误")
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // validateIDChecksum 验证身份证号校验码
 | ||
| func (e *EnterpriseInfo) validateIDChecksum() bool {
 | ||
| 	if len(e.LegalPersonID) != 18 {
 | ||
| 		return false
 | ||
| 	}
 | ||
| 
 | ||
| 	// 加权因子
 | ||
| 	weights := []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
 | ||
| 	// 校验码对应表
 | ||
| 	checkCodes := []string{"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"}
 | ||
| 
 | ||
| 	sum := 0
 | ||
| 	for i := 0; i < 17; i++ {
 | ||
| 		digit := int(e.LegalPersonID[i] - '0')
 | ||
| 		sum += digit * weights[i]
 | ||
| 	}
 | ||
| 
 | ||
| 	checkCodeIndex := sum % 11
 | ||
| 	expectedCheckCode := checkCodes[checkCodeIndex]
 | ||
| 	actualCheckCode := strings.ToUpper(string(e.LegalPersonID[17]))
 | ||
| 
 | ||
| 	return expectedCheckCode == actualCheckCode
 | ||
| }
 | ||
| 
 | ||
| // validateLegalPersonPhone 验证法定代表人手机号
 | ||
| func (e *EnterpriseInfo) validateLegalPersonPhone() error {
 | ||
| 	if e.LegalPersonPhone == "" {
 | ||
| 		return errors.New("法定代表人手机号不能为空")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 手机号格式验证(11位数字,1开头)
 | ||
| 	pattern := `^1[3-9]\d{9}$`
 | ||
| 	matched, err := regexp.MatchString(pattern, e.LegalPersonPhone)
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("手机号格式验证错误: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	if !matched {
 | ||
| 		return errors.New("手机号格式不正确,应为11位数字且以1开头")
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // validateEnterpriseAddress 验证企业地址
 | ||
| func (e *EnterpriseInfo) validateEnterpriseAddress() error {
 | ||
| 	if strings.TrimSpace(e.EnterpriseAddress) == "" {
 | ||
| 		return errors.New("企业地址不能为空")
 | ||
| 	}
 | ||
| 	if len(e.EnterpriseAddress) < 5 {
 | ||
| 		return errors.New("企业地址长度不能少于5个字符")
 | ||
| 	}
 | ||
| 	if len(e.EnterpriseAddress) > 200 {
 | ||
| 		return errors.New("企业地址长度不能超过200个字符")
 | ||
| 	}
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // IsComplete 检查企业信息是否完整
 | ||
| func (e *EnterpriseInfo) IsComplete() bool {
 | ||
| 	return e.CompanyName != "" &&
 | ||
| 		e.UnifiedSocialCode != "" &&
 | ||
| 		e.LegalPersonName != "" &&
 | ||
| 		e.LegalPersonID != "" &&
 | ||
| 		e.LegalPersonPhone != "" &&
 | ||
| 		e.EnterpriseAddress != ""
 | ||
| }
 | ||
| 
 | ||
| // IsDetailComplete 检查企业详细信息是否完整
 | ||
| func (e *EnterpriseInfo) IsDetailComplete() bool {
 | ||
| 	return e.IsComplete() &&
 | ||
| 		e.RegisteredAddress != "" &&
 | ||
| 		e.EnterpriseAddress != ""
 | ||
| }
 | ||
| 
 | ||
| // GetDisplayName 获取显示用的企业名称
 | ||
| func (e *EnterpriseInfo) GetDisplayName() string {
 | ||
| 	if e.CompanyName == "" {
 | ||
| 		return "未知企业"
 | ||
| 	}
 | ||
| 	return e.CompanyName
 | ||
| }
 | ||
| 
 | ||
| // GetMaskedUnifiedSocialCode 获取脱敏的统一社会信用代码
 | ||
| func (e *EnterpriseInfo) GetMaskedUnifiedSocialCode() string {
 | ||
| 	if len(e.UnifiedSocialCode) != 18 {
 | ||
| 		return e.UnifiedSocialCode
 | ||
| 	}
 | ||
| 
 | ||
| 	// 保留前6位和后4位,中间用*替代
 | ||
| 	return e.UnifiedSocialCode[:6] + "********" + e.UnifiedSocialCode[14:]
 | ||
| }
 | ||
| 
 | ||
| // GetMaskedLegalPersonID 获取脱敏的法定代表人身份证号
 | ||
| func (e *EnterpriseInfo) GetMaskedLegalPersonID() string {
 | ||
| 	if len(e.LegalPersonID) != 18 {
 | ||
| 		return e.LegalPersonID
 | ||
| 	}
 | ||
| 
 | ||
| 	// 保留前6位和后4位,中间用*替代
 | ||
| 	return e.LegalPersonID[:6] + "********" + e.LegalPersonID[14:]
 | ||
| }
 | ||
| 
 | ||
| // GetMaskedLegalPersonPhone 获取脱敏的法定代表人手机号
 | ||
| func (e *EnterpriseInfo) GetMaskedLegalPersonPhone() string {
 | ||
| 	if len(e.LegalPersonPhone) != 11 {
 | ||
| 		return e.LegalPersonPhone
 | ||
| 	}
 | ||
| 
 | ||
| 	// 保留前3位和后4位,中间用*替代
 | ||
| 	return e.LegalPersonPhone[:3] + "****" + e.LegalPersonPhone[7:]
 | ||
| }
 | ||
| 
 | ||
| // Equals 比较两个企业信息是否相等
 | ||
| func (e *EnterpriseInfo) Equals(other *EnterpriseInfo) bool {
 | ||
| 	if other == nil {
 | ||
| 		return false
 | ||
| 	}
 | ||
| 
 | ||
| 	return e.CompanyName == other.CompanyName &&
 | ||
| 		e.UnifiedSocialCode == other.UnifiedSocialCode &&
 | ||
| 		e.LegalPersonName == other.LegalPersonName &&
 | ||
| 		e.LegalPersonID == other.LegalPersonID &&
 | ||
| 		e.LegalPersonPhone == other.LegalPersonPhone
 | ||
| }
 | ||
| 
 | ||
| // Clone 创建企业信息的副本
 | ||
| func (e *EnterpriseInfo) Clone() *EnterpriseInfo {
 | ||
| 	return &EnterpriseInfo{
 | ||
| 		CompanyName:       e.CompanyName,
 | ||
| 		UnifiedSocialCode: e.UnifiedSocialCode,
 | ||
| 		LegalPersonName:   e.LegalPersonName,
 | ||
| 		LegalPersonID:     e.LegalPersonID,
 | ||
| 		LegalPersonPhone:  e.LegalPersonPhone,
 | ||
| 		RegisteredAddress: e.RegisteredAddress,
 | ||
| 		EnterpriseAddress: e.EnterpriseAddress,
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // String 返回企业信息的字符串表示
 | ||
| func (e *EnterpriseInfo) String() string {
 | ||
| 	return fmt.Sprintf("企业信息[名称:%s, 信用代码:%s, 法人:%s]",
 | ||
| 		e.CompanyName,
 | ||
| 		e.GetMaskedUnifiedSocialCode(),
 | ||
| 		e.LegalPersonName)
 | ||
| }
 | ||
| 
 | ||
| // ToMap 转换为map格式(用于序列化)
 | ||
| func (e *EnterpriseInfo) ToMap() map[string]interface{} {
 | ||
| 	return map[string]interface{}{
 | ||
| 		"company_name":        e.CompanyName,
 | ||
| 		"unified_social_code": e.UnifiedSocialCode,
 | ||
| 		"legal_person_name":   e.LegalPersonName,
 | ||
| 		"legal_person_id":     e.LegalPersonID,
 | ||
| 		"legal_person_phone":  e.LegalPersonPhone,
 | ||
| 		"registered_address":  e.RegisteredAddress,
 | ||
| 		"enterprise_address":  e.EnterpriseAddress,
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // FromMap 从map格式创建企业信息(用于反序列化)
 | ||
| func FromMap(data map[string]interface{}) (*EnterpriseInfo, error) {
 | ||
| 	getString := func(key string) string {
 | ||
| 		if val, exists := data[key]; exists {
 | ||
| 			if str, ok := val.(string); ok {
 | ||
| 				return strings.TrimSpace(str)
 | ||
| 			}
 | ||
| 		}
 | ||
| 		return ""
 | ||
| 	}
 | ||
| 
 | ||
| 	info := &EnterpriseInfo{
 | ||
| 		CompanyName:       getString("company_name"),
 | ||
| 		UnifiedSocialCode: getString("unified_social_code"),
 | ||
| 		LegalPersonName:   getString("legal_person_name"),
 | ||
| 		LegalPersonID:     getString("legal_person_id"),
 | ||
| 		LegalPersonPhone:  getString("legal_person_phone"),
 | ||
| 		RegisteredAddress: getString("registered_address"),
 | ||
| 		EnterpriseAddress: getString("enterprise_address"),
 | ||
| 	}
 | ||
| 
 | ||
| 	if err := info.Validate(); err != nil {
 | ||
| 		return nil, fmt.Errorf("从Map创建企业信息失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	return info, nil
 | ||
| }
 |