package recipe import ( "context" "errors" "fmt" "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" "gorm.io/gorm" ) // 定义领域特定的错误 var ( ErrRawMaterialNameConflict = fmt.Errorf("原料名称已存在") ErrRawMaterialNotFound = fmt.Errorf("原料不存在") ) // RawMaterialService 定义了原料领域的核心业务服务接口 type RawMaterialService interface { CreateRawMaterial(ctx context.Context, name, description string) (*models.RawMaterial, error) UpdateRawMaterial(ctx context.Context, id uint32, name, description string) (*models.RawMaterial, error) DeleteRawMaterial(ctx context.Context, id uint32) error GetRawMaterial(ctx context.Context, id uint32) (*models.RawMaterial, error) ListRawMaterials(ctx context.Context, opts repository.RawMaterialListOptions, page, pageSize int) ([]models.RawMaterial, int64, error) UpdateRawMaterialNutrients(ctx context.Context, rawMaterialID uint32, nutrients []models.RawMaterialNutrient) error } // rawMaterialServiceImpl 是 RawMaterialService 的实现 type rawMaterialServiceImpl struct { ctx context.Context uow repository.UnitOfWork rawMaterialRepo repository.RawMaterialRepository } // NewRawMaterialService 创建一个新的 RawMaterialService 实例 func NewRawMaterialService(ctx context.Context, uow repository.UnitOfWork, rawMaterialRepo repository.RawMaterialRepository) RawMaterialService { return &rawMaterialServiceImpl{ ctx: ctx, uow: uow, rawMaterialRepo: rawMaterialRepo, } } // CreateRawMaterial 实现了创建原料的核心业务逻辑 func (s *rawMaterialServiceImpl) CreateRawMaterial(ctx context.Context, name, description string) (*models.RawMaterial, error) { serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateRawMaterial") // 检查名称是否已存在 existing, err := s.rawMaterialRepo.GetRawMaterialByName(serviceCtx, name) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("检查原料名称失败: %w", err) } if existing != nil { return nil, ErrRawMaterialNameConflict } rawMaterial := &models.RawMaterial{ Name: name, Description: description, } if err := s.rawMaterialRepo.CreateRawMaterial(serviceCtx, rawMaterial); err != nil { return nil, fmt.Errorf("创建原料失败: %w", err) } return rawMaterial, nil } // UpdateRawMaterial 实现了更新原料的核心业务逻辑 func (s *rawMaterialServiceImpl) UpdateRawMaterial(ctx context.Context, id uint32, name, description string) (*models.RawMaterial, error) { serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateRawMaterial") // 检查要更新的实体是否存在 rawMaterial, err := s.rawMaterialRepo.GetRawMaterialByID(serviceCtx, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrRawMaterialNotFound } return nil, fmt.Errorf("获取待更新的原料失败: %w", err) } // 如果名称有变动,检查新名称是否与其它记录冲突 if rawMaterial.Name != name { existing, err := s.rawMaterialRepo.GetRawMaterialByName(serviceCtx, name) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("检查新的原料名称失败: %w", err) } if existing != nil && existing.ID != id { return nil, ErrRawMaterialNameConflict } } rawMaterial.Name = name rawMaterial.Description = description if err := s.rawMaterialRepo.UpdateRawMaterial(serviceCtx, rawMaterial); err != nil { return nil, fmt.Errorf("更新原料失败: %w", err) } return rawMaterial, nil } // DeleteRawMaterial 实现了删除原料的核心业务逻辑 func (s *rawMaterialServiceImpl) DeleteRawMaterial(ctx context.Context, id uint32) error { serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteRawMaterial") // 检查实体是否存在 _, err := s.rawMaterialRepo.GetRawMaterialByID(serviceCtx, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return ErrRawMaterialNotFound } return fmt.Errorf("获取待删除的原料失败: %w", err) } if err := s.rawMaterialRepo.DeleteRawMaterial(serviceCtx, id); err != nil { return fmt.Errorf("删除原料失败: %w", err) } return nil } // GetRawMaterial 实现了获取单个原料的逻辑 func (s *rawMaterialServiceImpl) GetRawMaterial(ctx context.Context, id uint32) (*models.RawMaterial, error) { serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetRawMaterial") rawMaterial, err := s.rawMaterialRepo.GetRawMaterialByID(serviceCtx, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrRawMaterialNotFound } return nil, fmt.Errorf("获取原料失败: %w", err) } return rawMaterial, nil } // ListRawMaterials 实现了列出原料的逻辑 func (s *rawMaterialServiceImpl) ListRawMaterials(ctx context.Context, opts repository.RawMaterialListOptions, page, pageSize int) ([]models.RawMaterial, int64, error) { serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListRawMaterials") rawMaterials, total, err := s.rawMaterialRepo.ListRawMaterials(serviceCtx, opts, page, pageSize) if err != nil { return nil, 0, fmt.Errorf("获取原料列表失败: %w", err) } return rawMaterials, total, nil } // UpdateRawMaterialNutrients 实现了全量更新原料营养成分的业务逻辑 func (s *rawMaterialServiceImpl) UpdateRawMaterialNutrients(ctx context.Context, rawMaterialID uint32, nutrients []models.RawMaterialNutrient) error { serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateRawMaterialNutrients") // 1. 检查原料是否存在 if _, err := s.rawMaterialRepo.GetRawMaterialByID(serviceCtx, rawMaterialID); err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return ErrRawMaterialNotFound } return fmt.Errorf("获取待更新的原料失败: %w", err) } // 2. 在事务中执行替换操作 err := s.uow.ExecuteInTransaction(serviceCtx, func(tx *gorm.DB) error { // 2.1. 删除旧的关联记录 if err := s.rawMaterialRepo.DeleteNutrientsByRawMaterialIDTx(serviceCtx, tx, rawMaterialID); err != nil { return err // 错误已在仓库层封装,直接返回 } // 2.2. 创建新的关联记录 if err := s.rawMaterialRepo.CreateBatchRawMaterialNutrientsTx(serviceCtx, tx, nutrients); err != nil { return err // 错误已在仓库层封装,直接返回 } return nil }) if err != nil { return fmt.Errorf("更新原料营养成分事务执行失败: %w", err) } // 3. 操作成功,直接返回 nil return nil }