Files
pig-farm-controller/internal/app/service/pig_farm_service.go
2025-10-04 01:28:05 +08:00

259 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"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 (
ErrHouseContainsPens = errors.New("无法删除包含猪栏的猪舍")
ErrHouseNotFound = errors.New("指定的猪舍不存在")
ErrPenInUse = errors.New("猪栏正在被活跃批次使用,无法删除")
ErrPenNotFound = errors.New("指定的猪栏不存在")
ErrPenStatusInvalidForOccupiedPen = errors.New("猪栏已被批次占用,无法设置为非占用状态")
ErrPenStatusInvalidForUnoccupiedPen = errors.New("猪栏未被批次占用,无法设置为占用状态")
)
// PigFarmService 提供了猪场资产管理的业务逻辑
type PigFarmService interface {
// PigHouse methods
CreatePigHouse(name, description string) (*models.PigHouse, error)
GetPigHouseByID(id uint) (*models.PigHouse, error)
ListPigHouses() ([]models.PigHouse, error)
UpdatePigHouse(id uint, name, description string) (*models.PigHouse, error)
DeletePigHouse(id uint) error
// Pen methods
CreatePen(penNumber string, houseID uint, capacity int) (*models.Pen, error)
GetPenByID(id uint) (*models.Pen, error)
ListPens() ([]models.Pen, error)
UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error)
DeletePen(id uint) error
// UpdatePenStatus 更新猪栏状态
UpdatePenStatus(id uint, newStatus models.PenStatus) (*models.Pen, error)
}
type pigFarmService struct {
logger *logs.Logger
repo repository.PigFarmRepository
uow repository.UnitOfWork // 工作单元,用于事务管理
}
// NewPigFarmService 创建一个新的 PigFarmService 实例
func NewPigFarmService(repo repository.PigFarmRepository, uow repository.UnitOfWork, logger *logs.Logger) PigFarmService {
return &pigFarmService{
logger: logger,
repo: repo,
uow: uow,
}
}
// --- PigHouse Implementation ---
func (s *pigFarmService) CreatePigHouse(name, description string) (*models.PigHouse, error) {
house := &models.PigHouse{
Name: name,
Description: description,
}
err := s.repo.CreatePigHouse(house)
return house, err
}
func (s *pigFarmService) GetPigHouseByID(id uint) (*models.PigHouse, error) {
return s.repo.GetPigHouseByID(id)
}
func (s *pigFarmService) ListPigHouses() ([]models.PigHouse, error) {
return s.repo.ListPigHouses()
}
func (s *pigFarmService) UpdatePigHouse(id uint, name, description string) (*models.PigHouse, error) {
house := &models.PigHouse{
Model: gorm.Model{ID: id},
Name: name,
Description: description,
}
rowsAffected, err := s.repo.UpdatePigHouse(house)
if err != nil {
return nil, err
}
if rowsAffected == 0 {
return nil, ErrHouseNotFound
}
// 返回更新后的完整信息
return s.repo.GetPigHouseByID(id)
}
func (s *pigFarmService) DeletePigHouse(id uint) error {
// 业务逻辑:检查猪舍是否包含猪栏
penCount, err := s.repo.CountPensInHouse(id)
if err != nil {
return err
}
if penCount > 0 {
return ErrHouseContainsPens
}
// 调用仓库层进行删除
rowsAffected, err := s.repo.DeletePigHouse(id)
if err != nil {
return err
}
if rowsAffected == 0 {
return ErrHouseNotFound
}
return nil
}
// --- Pen Implementation ---
func (s *pigFarmService) CreatePen(penNumber string, houseID uint, capacity int) (*models.Pen, error) {
// 业务逻辑:验证所属猪舍是否存在
_, err := s.repo.GetPigHouseByID(houseID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, ErrHouseNotFound
}
return nil, err
}
pen := &models.Pen{
PenNumber: penNumber,
HouseID: houseID,
Capacity: capacity,
Status: models.PenStatusEmpty,
}
err = s.repo.CreatePen(pen)
return pen, err
}
func (s *pigFarmService) GetPenByID(id uint) (*models.Pen, error) {
return s.repo.GetPenByID(id)
}
func (s *pigFarmService) ListPens() ([]models.Pen, error) {
return s.repo.ListPens()
}
func (s *pigFarmService) UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error) {
// 业务逻辑:验证所属猪舍是否存在
_, err := s.repo.GetPigHouseByID(houseID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, ErrHouseNotFound
}
return nil, err
}
pen := &models.Pen{
Model: gorm.Model{ID: id},
PenNumber: penNumber,
HouseID: houseID,
Capacity: capacity,
Status: status,
}
rowsAffected, err := s.repo.UpdatePen(pen)
if err != nil {
return nil, err
}
if rowsAffected == 0 {
return nil, ErrPenNotFound
}
// 返回更新后的完整信息
return s.repo.GetPenByID(id)
}
func (s *pigFarmService) DeletePen(id uint) error {
// 业务逻辑:检查猪栏是否被活跃批次使用
pen, err := s.repo.GetPenByID(id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPenNotFound // 猪栏不存在
}
return err
}
// 检查猪栏是否关联了活跃批次
// 注意pen.PigBatchID 是指针类型,需要检查是否为 nil
if pen.PigBatchID != nil && *pen.PigBatchID != 0 {
pigBatch, err := s.repo.GetPigBatchByID(*pen.PigBatchID)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
// 如果批次活跃,则不能删除猪栏
if pigBatch != nil && pigBatch.IsActive() {
return ErrPenInUse
}
}
// 调用仓库层进行删除
rowsAffected, err := s.repo.DeletePen(id)
if err != nil {
return err
}
if rowsAffected == 0 {
return ErrPenNotFound
}
return nil
}
// UpdatePenStatus 更新猪栏状态
func (s *pigFarmService) UpdatePenStatus(id uint, newStatus models.PenStatus) (*models.Pen, error) {
var updatedPen *models.Pen
err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
pen, err := s.repo.GetPenByIDTx(tx, id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPenNotFound
}
s.logger.Errorf("更新猪栏状态失败: 获取猪栏 %d 信息错误: %v", id, err)
return fmt.Errorf("获取猪栏 %d 信息失败: %w", id, err)
}
// 业务逻辑:根据猪栏的 PigBatchID 和当前状态,判断是否允许设置为 newStatus
if pen.PigBatchID != nil && *pen.PigBatchID != 0 { // 猪栏已被批次占用
if newStatus == models.PenStatusEmpty { // 猪栏已被批次占用,不能直接设置为空闲
return ErrPenStatusInvalidForOccupiedPen
}
} else { // 猪栏未被批次占用 (PigBatchID == nil)
if newStatus == models.PenStatusOccupied { // 猪栏未被批次占用,不能设置为占用
return ErrPenStatusInvalidForUnoccupiedPen
}
}
// 如果新状态与旧状态相同,则无需更新
if pen.Status == newStatus {
updatedPen = pen // 返回原始猪栏,因为没有实际更新
return nil
}
updates := map[string]interface{}{
"status": newStatus,
}
if err := s.repo.UpdatePenFields(tx, id, updates); err != nil {
s.logger.Errorf("更新猪栏 %d 状态失败: %v", id, err)
return fmt.Errorf("更新猪栏 %d 状态失败: %w", id, err)
}
// 获取更新后的猪栏信息
updatedPen, err = s.repo.GetPenByIDTx(tx, id)
if err != nil {
s.logger.Errorf("更新猪栏状态后获取猪栏 %d 信息失败: %v", id, err)
return fmt.Errorf("更新猪栏状态后获取猪栏 %d 信息失败: %w", id, err)
}
return nil
})
if err != nil {
return nil, err
}
return updatedPen, nil
}