2025-07-28 01:46:39 +08:00
|
|
|
|
package services
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
|
|
|
|
|
|
|
"tyapi-server/internal/domains/user/entities"
|
|
|
|
|
|
"tyapi-server/internal/domains/user/repositories"
|
|
|
|
|
|
"tyapi-server/internal/domains/user/repositories/queries"
|
|
|
|
|
|
"tyapi-server/internal/shared/interfaces"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// UserAggregateService 用户聚合服务接口
|
|
|
|
|
|
// 负责用户聚合根的生命周期管理和业务规则验证
|
|
|
|
|
|
type UserAggregateService interface {
|
|
|
|
|
|
// 聚合根管理
|
|
|
|
|
|
CreateUser(ctx context.Context, phone, password string) (*entities.User, error)
|
|
|
|
|
|
LoadUser(ctx context.Context, userID string) (*entities.User, error)
|
|
|
|
|
|
SaveUser(ctx context.Context, user *entities.User) error
|
|
|
|
|
|
LoadUserByPhone(ctx context.Context, phone string) (*entities.User, error)
|
|
|
|
|
|
|
|
|
|
|
|
// 业务规则验证
|
|
|
|
|
|
ValidateBusinessRules(ctx context.Context, user *entities.User) error
|
|
|
|
|
|
CheckInvariance(ctx context.Context, user *entities.User) error
|
|
|
|
|
|
|
|
|
|
|
|
// 查询方法
|
|
|
|
|
|
ExistsByPhone(ctx context.Context, phone string) (bool, error)
|
|
|
|
|
|
ExistsByID(ctx context.Context, userID string) (bool, error)
|
|
|
|
|
|
|
|
|
|
|
|
// 用户管理方法
|
|
|
|
|
|
GetUserByID(ctx context.Context, userID string) (*entities.User, error)
|
|
|
|
|
|
UpdateLoginStats(ctx context.Context, userID string) error
|
|
|
|
|
|
ListUsers(ctx context.Context, query *queries.ListUsersQuery) ([]*entities.User, int64, error)
|
|
|
|
|
|
GetUserStats(ctx context.Context) (*repositories.UserStats, error)
|
|
|
|
|
|
|
|
|
|
|
|
// 企业信息管理
|
2025-07-30 00:51:22 +08:00
|
|
|
|
CreateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error
|
|
|
|
|
|
UpdateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error
|
2025-07-28 01:46:39 +08:00
|
|
|
|
GetUserWithEnterpriseInfo(ctx context.Context, userID string) (*entities.User, error)
|
|
|
|
|
|
ValidateEnterpriseInfo(ctx context.Context, userID string) error
|
|
|
|
|
|
CheckUnifiedSocialCodeExists(ctx context.Context, unifiedSocialCode string, excludeUserID string) (bool, error)
|
|
|
|
|
|
|
|
|
|
|
|
// 认证域专用:写入/覆盖企业信息
|
2025-07-30 00:51:22 +08:00
|
|
|
|
CreateOrUpdateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error
|
2025-07-28 01:46:39 +08:00
|
|
|
|
CompleteCertification(ctx context.Context, userID string) error
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UserAggregateServiceImpl 用户聚合服务实现
|
|
|
|
|
|
type UserAggregateServiceImpl struct {
|
|
|
|
|
|
userRepo repositories.UserRepository
|
|
|
|
|
|
eventBus interfaces.EventBus
|
|
|
|
|
|
logger *zap.Logger
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewUserAggregateService 创建用户聚合服务
|
|
|
|
|
|
func NewUserAggregateService(
|
|
|
|
|
|
userRepo repositories.UserRepository,
|
|
|
|
|
|
eventBus interfaces.EventBus,
|
|
|
|
|
|
logger *zap.Logger,
|
|
|
|
|
|
) UserAggregateService {
|
|
|
|
|
|
return &UserAggregateServiceImpl{
|
|
|
|
|
|
userRepo: userRepo,
|
|
|
|
|
|
eventBus: eventBus,
|
|
|
|
|
|
logger: logger,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================ 聚合根管理 ================
|
|
|
|
|
|
|
|
|
|
|
|
// CreateUser 创建用户
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) CreateUser(ctx context.Context, phone, password string) (*entities.User, error) {
|
|
|
|
|
|
s.logger.Debug("创建用户聚合根", zap.String("phone", phone))
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 检查手机号是否已注册
|
|
|
|
|
|
exists, err := s.ExistsByPhone(ctx, phone)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("检查手机号失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if exists {
|
|
|
|
|
|
return nil, fmt.Errorf("手机号已注册")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 创建用户聚合根
|
|
|
|
|
|
user, err := entities.NewUser(phone, password)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("创建用户失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 调用聚合根方法进行注册
|
|
|
|
|
|
if err := user.Register(); err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("用户注册失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 验证业务规则
|
|
|
|
|
|
if err := s.ValidateBusinessRules(ctx, user); err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("业务规则验证失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 保存到仓储
|
|
|
|
|
|
if err := s.SaveUser(ctx, user); err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("保存用户失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s.logger.Info("用户创建成功",
|
|
|
|
|
|
zap.String("user_id", user.ID),
|
|
|
|
|
|
zap.String("phone", phone),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return user, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// LoadUser 根据ID加载用户聚合根
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) LoadUser(ctx context.Context, userID string) (*entities.User, error) {
|
|
|
|
|
|
s.logger.Debug("加载用户聚合根", zap.String("user_id", userID))
|
|
|
|
|
|
|
|
|
|
|
|
user, err := s.userRepo.GetByID(ctx, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("用户不存在: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证业务规则
|
|
|
|
|
|
if err := s.ValidateBusinessRules(ctx, &user); err != nil {
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Warn("用户业务规则验证失败",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.String("user_id", userID),
|
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &user, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SaveUser 保存用户聚合根
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) SaveUser(ctx context.Context, user *entities.User) error {
|
|
|
|
|
|
s.logger.Debug("保存用户聚合根", zap.String("user_id", user.ID))
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 验证业务规则
|
|
|
|
|
|
if err := s.ValidateBusinessRules(ctx, user); err != nil {
|
|
|
|
|
|
return fmt.Errorf("业务规则验证失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 检查聚合根是否存在
|
|
|
|
|
|
exists, err := s.userRepo.Exists(ctx, user.ID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("检查用户存在性失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 保存到仓储
|
|
|
|
|
|
if exists {
|
|
|
|
|
|
err = s.userRepo.Update(ctx, *user)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
s.logger.Error("更新用户聚合根失败", zap.Error(err))
|
|
|
|
|
|
return fmt.Errorf("更新用户失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
createdUser, err := s.userRepo.Create(ctx, *user)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
s.logger.Error("创建用户聚合根失败", zap.Error(err))
|
|
|
|
|
|
return fmt.Errorf("创建用户失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 更新用户ID(如果仓储生成了新的ID)
|
|
|
|
|
|
if createdUser.ID != "" {
|
|
|
|
|
|
user.ID = createdUser.ID
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 发布领域事件
|
|
|
|
|
|
if err := s.publishDomainEvents(ctx, user); err != nil {
|
|
|
|
|
|
s.logger.Error("发布领域事件失败", zap.Error(err))
|
|
|
|
|
|
// 不返回错误,因为数据已保存成功
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s.logger.Debug("用户聚合根保存成功", zap.String("user_id", user.ID))
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// LoadUserByPhone 根据手机号加载用户聚合根
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) LoadUserByPhone(ctx context.Context, phone string) (*entities.User, error) {
|
|
|
|
|
|
s.logger.Debug("根据手机号加载用户聚合根", zap.String("phone", phone))
|
|
|
|
|
|
|
|
|
|
|
|
user, err := s.userRepo.GetByPhone(ctx, phone)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("用户不存在: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证业务规则
|
|
|
|
|
|
if err := s.ValidateBusinessRules(ctx, user); err != nil {
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Warn("用户业务规则验证失败",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.String("phone", phone),
|
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return user, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================ 业务规则验证 ================
|
|
|
|
|
|
|
|
|
|
|
|
// ValidateBusinessRules 验证业务规则
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) ValidateBusinessRules(ctx context.Context, user *entities.User) error {
|
|
|
|
|
|
s.logger.Debug("验证用户业务规则", zap.String("user_id", user.ID))
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 实体内部业务规则验证
|
|
|
|
|
|
if err := user.ValidateBusinessRules(); err != nil {
|
|
|
|
|
|
return fmt.Errorf("实体业务规则验证失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 跨聚合根业务规则验证
|
|
|
|
|
|
if err := s.validateCrossAggregateRules(ctx, user); err != nil {
|
|
|
|
|
|
return fmt.Errorf("跨聚合根业务规则验证失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 领域级业务规则验证
|
|
|
|
|
|
if err := s.validateDomainRules(ctx, user); err != nil {
|
|
|
|
|
|
return fmt.Errorf("领域业务规则验证失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CheckInvariance 检查聚合根不变量
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) CheckInvariance(ctx context.Context, user *entities.User) error {
|
|
|
|
|
|
s.logger.Debug("检查用户聚合根不变量", zap.String("user_id", user.ID))
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 检查手机号唯一性
|
|
|
|
|
|
exists, err := s.ExistsByPhone(ctx, user.Phone)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("检查手机号唯一性失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if exists {
|
|
|
|
|
|
// 检查是否是同一个用户
|
|
|
|
|
|
existingUser, err := s.LoadUserByPhone(ctx, user.Phone)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("获取现有用户失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if existingUser.ID != user.ID {
|
|
|
|
|
|
return fmt.Errorf("手机号已被其他用户使用")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// validateCrossAggregateRules 验证跨聚合根业务规则
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) validateCrossAggregateRules(ctx context.Context, user *entities.User) error {
|
|
|
|
|
|
// 1. 检查手机号唯一性(排除自己)
|
|
|
|
|
|
existingUser, err := s.userRepo.GetByPhone(ctx, user.Phone)
|
|
|
|
|
|
if err == nil && existingUser.ID != user.ID {
|
|
|
|
|
|
return fmt.Errorf("手机号已被其他用户使用")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// validateDomainRules 验证领域级业务规则
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) validateDomainRules(ctx context.Context, user *entities.User) error {
|
|
|
|
|
|
// 这里可以添加领域级的业务规则验证
|
|
|
|
|
|
// 比如:检查手机号是否在黑名单中、检查用户权限等
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================ 查询方法 ================
|
|
|
|
|
|
|
|
|
|
|
|
// ExistsByPhone 检查手机号是否存在
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) ExistsByPhone(ctx context.Context, phone string) (bool, error) {
|
|
|
|
|
|
_, err := s.userRepo.GetByPhone(ctx, phone)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return false, nil // 用户不存在,返回false
|
|
|
|
|
|
}
|
|
|
|
|
|
return true, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ExistsByID 检查用户ID是否存在
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) ExistsByID(ctx context.Context, userID string) (bool, error) {
|
|
|
|
|
|
return s.userRepo.Exists(ctx, userID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetUserByID 根据ID获取用户聚合根
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) GetUserByID(ctx context.Context, userID string) (*entities.User, error) {
|
|
|
|
|
|
return s.LoadUser(ctx, userID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateLoginStats 更新用户登录统计
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) UpdateLoginStats(ctx context.Context, userID string) error {
|
|
|
|
|
|
user, err := s.LoadUser(ctx, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("用户不存在: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
user.IncrementLoginCount()
|
|
|
|
|
|
|
|
|
|
|
|
if err := s.SaveUser(ctx, user); err != nil {
|
|
|
|
|
|
s.logger.Error("更新用户登录统计失败", zap.Error(err))
|
|
|
|
|
|
return fmt.Errorf("更新用户登录统计失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s.logger.Info("用户登录统计更新成功", zap.String("user_id", userID))
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================ 企业信息管理 ================
|
|
|
|
|
|
|
|
|
|
|
|
// CreateEnterpriseInfo 创建企业信息
|
2025-07-30 00:51:22 +08:00
|
|
|
|
func (s *UserAggregateServiceImpl) CreateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error {
|
2025-07-28 01:46:39 +08:00
|
|
|
|
s.logger.Debug("创建企业信息", zap.String("user_id", userID))
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 加载用户聚合根
|
|
|
|
|
|
user, err := s.LoadUser(ctx, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("用户不存在: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 检查是否已有企业信息
|
|
|
|
|
|
if user.HasEnterpriseInfo() {
|
|
|
|
|
|
return fmt.Errorf("用户已有企业信息")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 检查统一社会信用代码唯一性
|
|
|
|
|
|
exists, err := s.CheckUnifiedSocialCodeExists(ctx, unifiedSocialCode, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("检查统一社会信用代码失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if exists {
|
|
|
|
|
|
return fmt.Errorf("统一社会信用代码已被使用")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 使用聚合根方法创建企业信息
|
2025-07-30 00:51:22 +08:00
|
|
|
|
err = user.CreateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress)
|
2025-07-28 01:46:39 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("创建企业信息失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 验证业务规则
|
|
|
|
|
|
if err := s.ValidateBusinessRules(ctx, user); err != nil {
|
|
|
|
|
|
return fmt.Errorf("业务规则验证失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 保存聚合根
|
|
|
|
|
|
err = s.SaveUser(ctx, user)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
s.logger.Error("保存用户聚合根失败", zap.Error(err))
|
|
|
|
|
|
return fmt.Errorf("保存企业信息失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s.logger.Info("企业信息创建成功", zap.String("user_id", userID))
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateEnterpriseInfo 更新企业信息
|
2025-07-30 00:51:22 +08:00
|
|
|
|
func (s *UserAggregateServiceImpl) UpdateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error {
|
2025-07-28 01:46:39 +08:00
|
|
|
|
s.logger.Debug("更新企业信息", zap.String("user_id", userID))
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 加载用户聚合根
|
|
|
|
|
|
user, err := s.LoadUser(ctx, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("用户不存在: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 检查是否有企业信息
|
|
|
|
|
|
if !user.HasEnterpriseInfo() {
|
|
|
|
|
|
return fmt.Errorf("用户暂无企业信息")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 检查统一社会信用代码唯一性(排除自己)
|
|
|
|
|
|
exists, err := s.CheckUnifiedSocialCodeExists(ctx, unifiedSocialCode, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("检查统一社会信用代码失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if exists {
|
|
|
|
|
|
return fmt.Errorf("统一社会信用代码已被其他用户使用")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 使用聚合根方法更新企业信息
|
2025-07-30 00:51:22 +08:00
|
|
|
|
err = user.UpdateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress)
|
2025-07-28 01:46:39 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("更新企业信息失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 验证业务规则
|
|
|
|
|
|
if err := s.ValidateBusinessRules(ctx, user); err != nil {
|
|
|
|
|
|
return fmt.Errorf("业务规则验证失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 保存聚合根
|
|
|
|
|
|
err = s.SaveUser(ctx, user)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
s.logger.Error("保存用户聚合根失败", zap.Error(err))
|
|
|
|
|
|
return fmt.Errorf("保存企业信息失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s.logger.Info("企业信息更新成功", zap.String("user_id", userID))
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetUserWithEnterpriseInfo 获取用户信息(包含企业信息)
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) GetUserWithEnterpriseInfo(ctx context.Context, userID string) (*entities.User, error) {
|
|
|
|
|
|
s.logger.Debug("获取用户信息(包含企业信息)", zap.String("user_id", userID))
|
|
|
|
|
|
|
|
|
|
|
|
// 加载用户聚合根(包含企业信息)
|
|
|
|
|
|
user, err := s.userRepo.GetByIDWithEnterpriseInfo(ctx, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("用户不存在: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证业务规则
|
|
|
|
|
|
if err := s.ValidateBusinessRules(ctx, &user); err != nil {
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Warn("用户业务规则验证失败",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.String("user_id", userID),
|
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &user, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ValidateEnterpriseInfo 验证企业信息
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) ValidateEnterpriseInfo(ctx context.Context, userID string) error {
|
|
|
|
|
|
s.logger.Debug("验证企业信息", zap.String("user_id", userID))
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 加载用户聚合根
|
|
|
|
|
|
user, err := s.LoadUser(ctx, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("用户不存在: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 使用聚合根方法验证企业信息
|
|
|
|
|
|
err = user.ValidateEnterpriseInfo()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("企业信息验证失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CheckUnifiedSocialCodeExists 检查统一社会信用代码是否存在
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) CheckUnifiedSocialCodeExists(ctx context.Context, unifiedSocialCode string, excludeUserID string) (bool, error) {
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Debug("检查统一社会信用代码是否存在",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.String("unified_social_code", unifiedSocialCode),
|
|
|
|
|
|
zap.String("exclude_user_id", excludeUserID),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 参数验证
|
|
|
|
|
|
if unifiedSocialCode == "" {
|
|
|
|
|
|
return false, fmt.Errorf("统一社会信用代码不能为空")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 通过用户仓库查询统一社会信用代码是否存在
|
|
|
|
|
|
exists, err := s.userRepo.ExistsByUnifiedSocialCode(ctx, unifiedSocialCode, excludeUserID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
s.logger.Error("查询统一社会信用代码失败", zap.Error(err))
|
|
|
|
|
|
return false, fmt.Errorf("查询企业信息失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if exists {
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Info("统一社会信用代码已存在",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.String("unified_social_code", unifiedSocialCode),
|
|
|
|
|
|
zap.String("exclude_user_id", excludeUserID),
|
|
|
|
|
|
)
|
|
|
|
|
|
} else {
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Debug("统一社会信用代码不存在",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.String("unified_social_code", unifiedSocialCode),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return exists, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CreateOrUpdateEnterpriseInfo 认证域专用:写入/覆盖企业信息
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) CreateOrUpdateEnterpriseInfo(
|
|
|
|
|
|
ctx context.Context,
|
2025-07-30 00:51:22 +08:00
|
|
|
|
userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string,
|
2025-07-28 01:46:39 +08:00
|
|
|
|
) error {
|
|
|
|
|
|
user, err := s.LoadUser(ctx, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("用户不存在: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if user.EnterpriseInfo == nil {
|
2025-07-30 00:51:22 +08:00
|
|
|
|
enterpriseInfo, err := entities.NewEnterpriseInfo(userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress)
|
2025-07-28 01:46:39 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
user.EnterpriseInfo = enterpriseInfo
|
|
|
|
|
|
} else {
|
2025-07-30 00:51:22 +08:00
|
|
|
|
err := user.EnterpriseInfo.UpdateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress)
|
2025-07-28 01:46:39 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return s.SaveUser(ctx, user)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CompleteCertification 完成认证
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) CompleteCertification(ctx context.Context, userID string) error {
|
|
|
|
|
|
user, err := s.LoadUser(ctx, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("用户不存在: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
user.CompleteCertification()
|
|
|
|
|
|
return s.SaveUser(ctx, user)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ListUsers 获取用户列表
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) ListUsers(ctx context.Context, query *queries.ListUsersQuery) ([]*entities.User, int64, error) {
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Debug("获取用户列表",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.Int("page", query.Page),
|
|
|
|
|
|
zap.Int("page_size", query.PageSize),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 直接调用仓储层查询用户列表
|
|
|
|
|
|
users, total, err := s.userRepo.ListUsers(ctx, query)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
s.logger.Error("查询用户列表失败", zap.Error(err))
|
|
|
|
|
|
return nil, 0, fmt.Errorf("查询用户列表失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Info("用户列表查询成功",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.Int("count", len(users)),
|
|
|
|
|
|
zap.Int64("total", total),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return users, total, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetUserStats 获取用户统计信息
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) GetUserStats(ctx context.Context) (*repositories.UserStats, error) {
|
|
|
|
|
|
s.logger.Debug("获取用户统计信息")
|
|
|
|
|
|
|
|
|
|
|
|
// 直接调用仓储层查询用户统计信息
|
|
|
|
|
|
stats, err := s.userRepo.GetStats(ctx)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
s.logger.Error("查询用户统计信息失败", zap.Error(err))
|
|
|
|
|
|
return nil, fmt.Errorf("查询用户统计信息失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Info("用户统计信息查询成功",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.Int64("total_users", stats.TotalUsers),
|
|
|
|
|
|
zap.Int64("active_users", stats.ActiveUsers),
|
|
|
|
|
|
zap.Int64("certified_users", stats.CertifiedUsers),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return stats, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================ 私有方法 ================
|
|
|
|
|
|
|
|
|
|
|
|
// publishDomainEvents 发布领域事件
|
|
|
|
|
|
func (s *UserAggregateServiceImpl) publishDomainEvents(ctx context.Context, user *entities.User) error {
|
|
|
|
|
|
events := user.GetDomainEvents()
|
|
|
|
|
|
if len(events) == 0 {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
|
// 这里需要将领域事件转换为标准事件格式
|
|
|
|
|
|
// 暂时跳过,后续可以完善事件转换逻辑
|
2025-07-30 00:51:22 +08:00
|
|
|
|
s.logger.Debug("发布领域事件",
|
2025-07-28 01:46:39 +08:00
|
|
|
|
zap.String("user_id", user.ID),
|
|
|
|
|
|
zap.Any("event", event),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清除已发布的事件
|
|
|
|
|
|
user.ClearDomainEvents()
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
2025-07-30 00:51:22 +08:00
|
|
|
|
}
|