2025-11-23 15:16:45 +08:00
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/recipe"
|
|
|
|
|
"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"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 定义原料服务特定的错误
|
|
|
|
|
var (
|
|
|
|
|
ErrRawMaterialNameConflict = errors.New("原料名称已存在")
|
|
|
|
|
ErrRawMaterialNotFound = errors.New("原料不存在")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// RawMaterialService 定义了原料相关的应用服务接口
|
|
|
|
|
type RawMaterialService interface {
|
|
|
|
|
CreateRawMaterial(ctx context.Context, req *dto.CreateRawMaterialRequest) (*dto.RawMaterialResponse, error)
|
|
|
|
|
UpdateRawMaterial(ctx context.Context, id uint32, req *dto.UpdateRawMaterialRequest) (*dto.RawMaterialResponse, error)
|
|
|
|
|
DeleteRawMaterial(ctx context.Context, id uint32) error
|
|
|
|
|
GetRawMaterial(ctx context.Context, id uint32) (*dto.RawMaterialResponse, error)
|
|
|
|
|
ListRawMaterials(ctx context.Context, req *dto.ListRawMaterialRequest) (*dto.ListRawMaterialResponse, error)
|
|
|
|
|
UpdateRawMaterialNutrients(ctx context.Context, id uint32, req *dto.UpdateRawMaterialNutrientsRequest) (*dto.RawMaterialResponse, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// rawMaterialServiceImpl 是 RawMaterialService 接口的实现
|
|
|
|
|
type rawMaterialServiceImpl struct {
|
|
|
|
|
ctx context.Context
|
|
|
|
|
recipeSvc recipe.Service
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewRawMaterialService 创建一个新的 RawMaterialService 实例
|
|
|
|
|
func NewRawMaterialService(ctx context.Context, recipeSvc recipe.Service) RawMaterialService {
|
|
|
|
|
return &rawMaterialServiceImpl{
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
recipeSvc: recipeSvc,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateRawMaterial 创建原料
|
|
|
|
|
func (s *rawMaterialServiceImpl) CreateRawMaterial(ctx context.Context, req *dto.CreateRawMaterialRequest) (*dto.RawMaterialResponse, error) {
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateRawMaterial")
|
|
|
|
|
|
2025-11-27 15:52:38 +08:00
|
|
|
rawMaterial, err := s.recipeSvc.CreateRawMaterial(serviceCtx, req.Name, req.Description, req.ReferencePrice, req.MaxAdditionRatio)
|
2025-11-23 15:16:45 +08:00
|
|
|
if err != nil {
|
|
|
|
|
if errors.Is(err, recipe.ErrRawMaterialNameConflict) {
|
|
|
|
|
return nil, ErrRawMaterialNameConflict
|
|
|
|
|
}
|
|
|
|
|
return nil, fmt.Errorf("创建原料失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dto.ConvertRawMaterialToDTO(rawMaterial), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdateRawMaterial 更新原料
|
|
|
|
|
func (s *rawMaterialServiceImpl) UpdateRawMaterial(ctx context.Context, id uint32, req *dto.UpdateRawMaterialRequest) (*dto.RawMaterialResponse, error) {
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateRawMaterial")
|
|
|
|
|
|
2025-11-27 15:52:38 +08:00
|
|
|
rawMaterial, err := s.recipeSvc.UpdateRawMaterial(serviceCtx, id, req.Name, req.Description, req.ReferencePrice, req.MaxAdditionRatio)
|
2025-11-23 15:16:45 +08:00
|
|
|
if err != nil {
|
|
|
|
|
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
|
|
|
|
|
return nil, ErrRawMaterialNotFound
|
|
|
|
|
}
|
|
|
|
|
if errors.Is(err, recipe.ErrRawMaterialNameConflict) {
|
|
|
|
|
return nil, ErrRawMaterialNameConflict
|
|
|
|
|
}
|
|
|
|
|
return nil, fmt.Errorf("更新原料失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
return dto.ConvertRawMaterialToDTO(rawMaterial), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeleteRawMaterial 删除原料
|
|
|
|
|
func (s *rawMaterialServiceImpl) DeleteRawMaterial(ctx context.Context, id uint32) error {
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteRawMaterial")
|
|
|
|
|
err := s.recipeSvc.DeleteRawMaterial(serviceCtx, id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
|
|
|
|
|
return ErrRawMaterialNotFound
|
|
|
|
|
}
|
|
|
|
|
return fmt.Errorf("删除原料失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetRawMaterial 获取单个原料
|
|
|
|
|
func (s *rawMaterialServiceImpl) GetRawMaterial(ctx context.Context, id uint32) (*dto.RawMaterialResponse, error) {
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetRawMaterial")
|
|
|
|
|
|
|
|
|
|
rawMaterial, err := s.recipeSvc.GetRawMaterial(serviceCtx, id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
|
|
|
|
|
return nil, ErrRawMaterialNotFound
|
|
|
|
|
}
|
|
|
|
|
return nil, fmt.Errorf("获取原料失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
return dto.ConvertRawMaterialToDTO(rawMaterial), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ListRawMaterials 列出原料
|
|
|
|
|
func (s *rawMaterialServiceImpl) ListRawMaterials(ctx context.Context, req *dto.ListRawMaterialRequest) (*dto.ListRawMaterialResponse, error) {
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListRawMaterials")
|
|
|
|
|
|
|
|
|
|
opts := repository.RawMaterialListOptions{
|
2025-11-25 20:03:36 +08:00
|
|
|
Name: req.Name,
|
|
|
|
|
NutrientName: req.NutrientName,
|
|
|
|
|
MinReferencePrice: req.MinReferencePrice,
|
|
|
|
|
MaxReferencePrice: req.MaxReferencePrice,
|
|
|
|
|
OrderBy: req.OrderBy,
|
2025-11-23 15:16:45 +08:00
|
|
|
}
|
|
|
|
|
rawMaterials, total, err := s.recipeSvc.ListRawMaterials(serviceCtx, opts, req.Page, req.PageSize)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("获取原料列表失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dto.ConvertRawMaterialListToDTO(rawMaterials, total, req.Page, req.PageSize), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdateRawMaterialNutrients 全量更新原料的营养成分
|
|
|
|
|
func (s *rawMaterialServiceImpl) UpdateRawMaterialNutrients(ctx context.Context, id uint32, req *dto.UpdateRawMaterialNutrientsRequest) (*dto.RawMaterialResponse, error) {
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateRawMaterialNutrients")
|
|
|
|
|
|
|
|
|
|
// 1. 将 DTO 转换为领域模型
|
|
|
|
|
nutrients := make([]models.RawMaterialNutrient, len(req.Nutrients))
|
|
|
|
|
for i, item := range req.Nutrients {
|
|
|
|
|
nutrients[i] = models.RawMaterialNutrient{
|
|
|
|
|
RawMaterialID: id,
|
|
|
|
|
NutrientID: item.NutrientID,
|
|
|
|
|
Value: item.Value,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 调用领域服务执行更新命令
|
|
|
|
|
err := s.recipeSvc.UpdateRawMaterialNutrients(serviceCtx, id, nutrients)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
|
|
|
|
|
return nil, ErrRawMaterialNotFound
|
|
|
|
|
}
|
|
|
|
|
// 此处可以根据领域层可能返回的其他特定错误进行转换
|
|
|
|
|
return nil, fmt.Errorf("更新原料营养成分失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 更新成功后,调用查询服务获取最新的原料信息
|
|
|
|
|
updatedRawMaterial, err := s.recipeSvc.GetRawMaterial(serviceCtx, id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
|
|
|
|
|
// 理论上不应该发生,因为刚更新成功
|
|
|
|
|
return nil, ErrRawMaterialNotFound
|
|
|
|
|
}
|
|
|
|
|
return nil, fmt.Errorf("更新后获取原料信息失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 将领域模型转换为 DTO 并返回
|
|
|
|
|
return dto.ConvertRawMaterialToDTO(updatedRawMaterial), nil
|
|
|
|
|
}
|