Compare commits

..

6 Commits

Author SHA1 Message Date
47ed819b9d Merge pull request 'issue_39' (#40) from issue_39 into main
Reviewed-on: #40
2025-10-23 16:07:20 +08:00
b1dce77e51 修bug 2025-10-23 16:06:15 +08:00
21607559c4 修bug 2025-10-23 12:00:57 +08:00
af6a00ee47 优化报错 2025-10-23 11:52:08 +08:00
324a533c94 猪群相关接口增加当前总量和当前总存栏量 2025-10-23 11:29:48 +08:00
c1f71050e9 猪栏信息接口增加猪栏当前存栏量 2025-10-23 10:52:40 +08:00
16 changed files with 253 additions and 129 deletions

View File

@@ -4770,6 +4770,9 @@ const docTemplate = `{
"capacity": { "capacity": {
"type": "integer" "type": "integer"
}, },
"current_pig_count": {
"type": "integer"
},
"house_id": { "house_id": {
"type": "integer" "type": "integer"
}, },
@@ -4903,6 +4906,14 @@ const docTemplate = `{
"description": "创建时间", "description": "创建时间",
"type": "string" "type": "string"
}, },
"currentTotalPigsInPens": {
"description": "当前存栏总数",
"type": "integer"
},
"currentTotalQuantity": {
"description": "当前总数",
"type": "integer"
},
"end_date": { "end_date": {
"description": "批次结束日期", "description": "批次结束日期",
"type": "string" "type": "string"

View File

@@ -4762,6 +4762,9 @@
"capacity": { "capacity": {
"type": "integer" "type": "integer"
}, },
"current_pig_count": {
"type": "integer"
},
"house_id": { "house_id": {
"type": "integer" "type": "integer"
}, },
@@ -4895,6 +4898,14 @@
"description": "创建时间", "description": "创建时间",
"type": "string" "type": "string"
}, },
"currentTotalPigsInPens": {
"description": "当前存栏总数",
"type": "integer"
},
"currentTotalQuantity": {
"description": "当前总数",
"type": "integer"
},
"end_date": { "end_date": {
"description": "批次结束日期", "description": "批次结束日期",
"type": "string" "type": "string"

View File

@@ -572,6 +572,8 @@ definitions:
properties: properties:
capacity: capacity:
type: integer type: integer
current_pig_count:
type: integer
house_id: house_id:
type: integer type: integer
id: id:
@@ -660,6 +662,12 @@ definitions:
create_time: create_time:
description: 创建时间 description: 创建时间
type: string type: string
currentTotalPigsInPens:
description: 当前存栏总数
type: integer
currentTotalQuantity:
description: 当前总数
type: integer
end_date: end_date:
description: 批次结束日期 description: 批次结束日期
type: string type: string

View File

@@ -140,7 +140,7 @@ func (a *API) setupRoutes() {
pigBatchGroup.DELETE("/:id", a.pigBatchController.DeletePigBatch) // 删除猪群 pigBatchGroup.DELETE("/:id", a.pigBatchController.DeletePigBatch) // 删除猪群
pigBatchGroup.POST("/assign-pens/:id", a.pigBatchController.AssignEmptyPensToBatch) // 为猪群分配空栏 pigBatchGroup.POST("/assign-pens/:id", a.pigBatchController.AssignEmptyPensToBatch) // 为猪群分配空栏
pigBatchGroup.POST("/reclassify-pen/:fromBatchID", a.pigBatchController.ReclassifyPenToNewBatch) // 将猪栏划拨到新群 pigBatchGroup.POST("/reclassify-pen/:fromBatchID", a.pigBatchController.ReclassifyPenToNewBatch) // 将猪栏划拨到新群
penGroup.DELETE("/remove-pen/:penID/:batchID", a.pigBatchController.RemoveEmptyPenFromBatch) // 从猪群移除空栏 pigBatchGroup.DELETE("/remove-pen/:penID/:batchID", a.pigBatchController.RemoveEmptyPenFromBatch) // 从猪群移除空栏
pigBatchGroup.POST("/move-pigs-into-pen/:id", a.pigBatchController.MovePigsIntoPen) // 将猪只从“虚拟库存”移入指定猪栏 pigBatchGroup.POST("/move-pigs-into-pen/:id", a.pigBatchController.MovePigsIntoPen) // 将猪只从“虚拟库存”移入指定猪栏
pigBatchGroup.POST("/sell-pigs/:id", a.pigBatchController.SellPigs) // 处理卖猪业务 pigBatchGroup.POST("/sell-pigs/:id", a.pigBatchController.SellPigs) // 处理卖猪业务
pigBatchGroup.POST("/buy-pigs/:id", a.pigBatchController.BuyPigs) // 处理买猪业务 pigBatchGroup.POST("/buy-pigs/:id", a.pigBatchController.BuyPigs) // 处理买猪业务

View File

@@ -2,6 +2,7 @@ package management
import ( import (
"errors" "errors"
"fmt"
"strconv" "strconv"
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller" "git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
@@ -25,7 +26,7 @@ func mapAndSendError(c *PigBatchController, ctx *gin.Context, action string, err
controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id)
} else { } else {
c.logger.Errorf("操作[%s]业务逻辑失败: %v", action, err) c.logger.Errorf("操作[%s]业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "操作失败", action, err.Error(), id) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, fmt.Sprintf("操作失败: %v", err), action, err.Error(), id)
} }
} }
@@ -156,7 +157,7 @@ func handleAPIRequestWithResponse[Req any, Resp any](
) { ) {
// 1. 绑定请求体 // 1. 绑定请求体
if err := ctx.ShouldBindJSON(&reqDTO); err != nil { if err := ctx.ShouldBindJSON(&reqDTO); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", reqDTO) controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, fmt.Sprintf("无效的请求体: %v", err), action, fmt.Sprintf("请求体绑定失败: %v", err), reqDTO)
return return
} }

View File

@@ -1 +0,0 @@
package management

View File

@@ -1 +0,0 @@
package management

View File

@@ -1 +0,0 @@
package management

View File

@@ -276,17 +276,7 @@ func (c *PigFarmController) GetPen(ctx *gin.Context) {
return return
} }
resp := dto.PenResponse{ controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pen, action, "获取成功", pen)
ID: pen.ID,
PenNumber: pen.PenNumber,
HouseID: pen.HouseID,
Capacity: pen.Capacity,
Status: pen.Status,
}
if pen.PigBatchID != nil {
resp.PigBatchID = *pen.PigBatchID
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp)
} }
// ListPens godoc // ListPens godoc
@@ -306,22 +296,7 @@ func (c *PigFarmController) ListPens(ctx *gin.Context) {
return return
} }
var resp []dto.PenResponse controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pens, action, "获取成功", pens)
for _, pen := range pens {
res := dto.PenResponse{
ID: pen.ID,
PenNumber: pen.PenNumber,
HouseID: pen.HouseID,
Capacity: pen.Capacity,
Status: pen.Status,
}
if pen.PigBatchID != nil {
res.PigBatchID = *pen.PigBatchID
}
resp = append(resp, res)
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp)
} }
// UpdatePen godoc // UpdatePen godoc
@@ -362,14 +337,12 @@ func (c *PigFarmController) UpdatePen(ctx *gin.Context) {
} }
resp := dto.PenResponse{ resp := dto.PenResponse{
ID: pen.ID, ID: pen.ID,
PenNumber: pen.PenNumber, PenNumber: pen.PenNumber,
HouseID: pen.HouseID, HouseID: pen.HouseID,
Capacity: pen.Capacity, Capacity: pen.Capacity,
Status: pen.Status, Status: pen.Status,
} PigBatchID: pen.PigBatchID,
if pen.PigBatchID != nil {
resp.PigBatchID = *pen.PigBatchID
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp)
} }
@@ -454,7 +427,7 @@ func (c *PigFarmController) UpdatePenStatus(ctx *gin.Context) {
HouseID: pen.HouseID, HouseID: pen.HouseID,
Capacity: pen.Capacity, Capacity: pen.Capacity,
Status: pen.Status, Status: pen.Status,
PigBatchID: *pen.PigBatchID, PigBatchID: pen.PigBatchID,
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp)
} }

View File

@@ -32,16 +32,18 @@ type PigBatchQueryDTO struct {
// PigBatchResponseDTO 定义了猪批次信息的响应结构 // PigBatchResponseDTO 定义了猪批次信息的响应结构
type PigBatchResponseDTO struct { type PigBatchResponseDTO struct {
ID uint `json:"id"` // 批次ID ID uint `json:"id"` // 批次ID
BatchNumber string `json:"batch_number"` // 批次编号 BatchNumber string `json:"batch_number"` // 批次编号
OriginType models.PigBatchOriginType `json:"origin_type"` // 批次来源 OriginType models.PigBatchOriginType `json:"origin_type"` // 批次来源
StartDate time.Time `json:"start_date"` // 批次开始日期 StartDate time.Time `json:"start_date"` // 批次开始日期
EndDate time.Time `json:"end_date"` // 批次结束日期 EndDate time.Time `json:"end_date"` // 批次结束日期
InitialCount int `json:"initial_count"` // 初始数量 InitialCount int `json:"initial_count"` // 初始数量
Status models.PigBatchStatus `json:"status"` // 批次状态 Status models.PigBatchStatus `json:"status"` // 批次状态
IsActive bool `json:"is_active"` // 是否活跃 IsActive bool `json:"is_active"` // 是否活跃
CreateTime time.Time `json:"create_time"` // 创建时间 CurrentTotalQuantity int `json:"currentTotalQuantity"` // 当前总数
UpdateTime time.Time `json:"update_time"` // 更新时间 CurrentTotalPigsInPens int `json:"currentTotalPigsInPens"` // 当前存栏总数
CreateTime time.Time `json:"create_time"` // 创建时间
UpdateTime time.Time `json:"update_time"` // 更新时间
} }
// AssignEmptyPensToBatchRequest 用于为猪批次分配空栏的请求体 // AssignEmptyPensToBatchRequest 用于为猪批次分配空栏的请求体

View File

@@ -11,12 +11,13 @@ type PigHouseResponse struct {
// PenResponse 定义了猪栏信息的响应结构 // PenResponse 定义了猪栏信息的响应结构
type PenResponse struct { type PenResponse struct {
ID uint `json:"id"` ID uint `json:"id"`
PenNumber string `json:"pen_number"` PenNumber string `json:"pen_number"`
HouseID uint `json:"house_id"` HouseID uint `json:"house_id"`
Capacity int `json:"capacity"` Capacity int `json:"capacity"`
Status models.PenStatus `json:"status"` Status models.PenStatus `json:"status"`
PigBatchID uint `json:"pig_batch_id"` PigBatchID *uint `json:"pig_batch_id,omitempty"`
CurrentPigCount int `json:"current_pig_count"`
} }
// CreatePigHouseRequest 定义了创建猪舍的请求结构 // CreatePigHouseRequest 定义了创建猪舍的请求结构

View File

@@ -57,21 +57,23 @@ func NewPigBatchService(domainService domain_pig.PigBatchService, logger *logs.L
} }
// toPigBatchResponseDTO 负责将领域模型转换为应用层DTO这个职责保留在应用层。 // toPigBatchResponseDTO 负责将领域模型转换为应用层DTO这个职责保留在应用层。
func (s *pigBatchService) toPigBatchResponseDTO(batch *models.PigBatch) *dto.PigBatchResponseDTO { func (s *pigBatchService) toPigBatchResponseDTO(batch *models.PigBatch, currentTotalQuantity, currentTotalPigsInPens int) *dto.PigBatchResponseDTO {
if batch == nil { if batch == nil {
return nil return nil
} }
return &dto.PigBatchResponseDTO{ return &dto.PigBatchResponseDTO{
ID: batch.ID, ID: batch.ID,
BatchNumber: batch.BatchNumber, BatchNumber: batch.BatchNumber,
OriginType: batch.OriginType, OriginType: batch.OriginType,
StartDate: batch.StartDate, StartDate: batch.StartDate,
EndDate: batch.EndDate, EndDate: batch.EndDate,
InitialCount: batch.InitialCount, InitialCount: batch.InitialCount,
Status: batch.Status, Status: batch.Status,
IsActive: batch.IsActive(), IsActive: batch.IsActive(),
CreateTime: batch.CreatedAt, CurrentTotalQuantity: currentTotalQuantity,
UpdateTime: batch.UpdatedAt, CurrentTotalPigsInPens: currentTotalPigsInPens,
CreateTime: batch.CreatedAt,
UpdateTime: batch.UpdatedAt,
} }
} }
@@ -94,7 +96,7 @@ func (s *pigBatchService) CreatePigBatch(operatorID uint, dto *dto.PigBatchCreat
} }
// 3. 领域模型 -> DTO // 3. 领域模型 -> DTO
return s.toPigBatchResponseDTO(createdBatch), nil return s.toPigBatchResponseDTO(createdBatch, dto.InitialCount, 0), nil
} }
// GetPigBatch 从领域服务获取数据并转换为DTO同时处理错误转换。 // GetPigBatch 从领域服务获取数据并转换为DTO同时处理错误转换。
@@ -104,8 +106,17 @@ func (s *pigBatchService) GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error)
s.logger.Warnf("应用层: 获取猪批次失败, ID: %d, 错误: %v", id, err) s.logger.Warnf("应用层: 获取猪批次失败, ID: %d, 错误: %v", id, err)
return nil, MapDomainError(err) return nil, MapDomainError(err)
} }
currentTotalQuantity, err := s.domainService.GetCurrentPigQuantity(id)
return s.toPigBatchResponseDTO(batch), nil if err != nil {
s.logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", id, err)
return nil, MapDomainError(err)
}
currentTotalPigsInPens, err := s.domainService.GetTotalPigsInPensForBatch(id)
if err != nil {
s.logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", id, err)
return nil, MapDomainError(err)
}
return s.toPigBatchResponseDTO(batch, currentTotalQuantity, currentTotalPigsInPens), nil
} }
// UpdatePigBatch 协调获取、更新和保存的流程,并处理错误转换。 // UpdatePigBatch 协调获取、更新和保存的流程,并处理错误转换。
@@ -144,8 +155,20 @@ func (s *pigBatchService) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*
return nil, MapDomainError(err) return nil, MapDomainError(err)
} }
// 4. 转换并返回结果 // 4. 填充猪群信息
return s.toPigBatchResponseDTO(updatedBatch), nil currentTotalQuantity, err := s.domainService.GetCurrentPigQuantity(id)
if err != nil {
s.logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", id, err)
return nil, MapDomainError(err)
}
currentTotalPigsInPens, err := s.domainService.GetTotalPigsInPensForBatch(id)
if err != nil {
s.logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", id, err)
return nil, MapDomainError(err)
}
// 5. 转换并返回结果
return s.toPigBatchResponseDTO(updatedBatch, currentTotalQuantity, currentTotalPigsInPens), nil
} }
// DeletePigBatch 将删除操作委托给领域服务,并转换领域错误为应用层错误。 // DeletePigBatch 将删除操作委托给领域服务,并转换领域错误为应用层错误。
@@ -168,7 +191,17 @@ func (s *pigBatchService) ListPigBatches(isActive *bool) ([]*dto.PigBatchRespons
var responseDTOs []*dto.PigBatchResponseDTO var responseDTOs []*dto.PigBatchResponseDTO
for _, batch := range batches { for _, batch := range batches {
responseDTOs = append(responseDTOs, s.toPigBatchResponseDTO(batch)) currentTotalQuantity, err := s.domainService.GetCurrentPigQuantity(batch.ID)
if err != nil {
s.logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", batch.ID, err)
return nil, MapDomainError(err)
}
currentTotalPigsInPens, err := s.domainService.GetTotalPigsInPensForBatch(batch.ID)
if err != nil {
s.logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", batch.ID, err)
return nil, MapDomainError(err)
}
responseDTOs = append(responseDTOs, s.toPigBatchResponseDTO(batch, currentTotalQuantity, currentTotalPigsInPens))
} }
return responseDTOs, nil return responseDTOs, nil

View File

@@ -4,6 +4,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
domain_pig "git.huangwc.com/pig/pig-farm-controller/internal/domain/pig"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "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/models"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
@@ -22,8 +24,8 @@ type PigFarmService interface {
// Pen methods // Pen methods
CreatePen(penNumber string, houseID uint, capacity int) (*models.Pen, error) CreatePen(penNumber string, houseID uint, capacity int) (*models.Pen, error)
GetPenByID(id uint) (*models.Pen, error) GetPenByID(id uint) (*dto.PenResponse, error)
ListPens() ([]models.Pen, error) ListPens() ([]*dto.PenResponse, error)
UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error) UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error)
DeletePen(id uint) error DeletePen(id uint) error
// UpdatePenStatus 更新猪栏状态 // UpdatePenStatus 更新猪栏状态
@@ -35,13 +37,15 @@ type pigFarmService struct {
farmRepository repository.PigFarmRepository farmRepository repository.PigFarmRepository
penRepository repository.PigPenRepository penRepository repository.PigPenRepository
batchRepository repository.PigBatchRepository batchRepository repository.PigBatchRepository
uow repository.UnitOfWork // 工作单元,用于事务管理 pigBatchService domain_pig.PigBatchService // Add domain PigBatchService dependency
uow repository.UnitOfWork // 工作单元,用于事务管理
} }
// NewPigFarmService 创建一个新的 PigFarmService 实例 // NewPigFarmService 创建一个新的 PigFarmService 实例
func NewPigFarmService(farmRepository repository.PigFarmRepository, func NewPigFarmService(farmRepository repository.PigFarmRepository,
penRepository repository.PigPenRepository, penRepository repository.PigPenRepository,
batchRepository repository.PigBatchRepository, batchRepository repository.PigBatchRepository,
pigBatchService domain_pig.PigBatchService,
uow repository.UnitOfWork, uow repository.UnitOfWork,
logger *logs.Logger) PigFarmService { logger *logs.Logger) PigFarmService {
return &pigFarmService{ return &pigFarmService{
@@ -49,6 +53,7 @@ func NewPigFarmService(farmRepository repository.PigFarmRepository,
farmRepository: farmRepository, farmRepository: farmRepository,
penRepository: penRepository, penRepository: penRepository,
batchRepository: batchRepository, batchRepository: batchRepository,
pigBatchService: pigBatchService,
uow: uow, uow: uow,
} }
} }
@@ -132,12 +137,64 @@ func (s *pigFarmService) CreatePen(penNumber string, houseID uint, capacity int)
return pen, err return pen, err
} }
func (s *pigFarmService) GetPenByID(id uint) (*models.Pen, error) { func (s *pigFarmService) GetPenByID(id uint) (*dto.PenResponse, error) {
return s.penRepository.GetPenByID(id) pen, err := s.penRepository.GetPenByID(id)
if err != nil {
return nil, err
}
currentPigCount, err := s.pigBatchService.GetCurrentPigsInPen(id)
if err != nil {
s.logger.Errorf("获取猪栏 %d 存栏量失败: %v", id, err)
currentPigCount = 0 // 如果获取计数时出错则默认为0
}
response := &dto.PenResponse{
ID: pen.ID,
PenNumber: pen.PenNumber,
HouseID: pen.HouseID,
Capacity: pen.Capacity,
Status: pen.Status,
CurrentPigCount: currentPigCount,
}
if pen.PigBatchID != nil {
response.PigBatchID = pen.PigBatchID
}
return response, nil
} }
func (s *pigFarmService) ListPens() ([]models.Pen, error) { func (s *pigFarmService) ListPens() ([]*dto.PenResponse, error) {
return s.penRepository.ListPens() pens, err := s.penRepository.ListPens()
if err != nil {
return nil, err
}
var response []*dto.PenResponse
for _, pen := range pens {
currentPigCount, err := s.pigBatchService.GetCurrentPigsInPen(pen.ID)
if err != nil {
s.logger.Errorf("获取猪栏 %d 存栏量失败: %v", pen.ID, err)
currentPigCount = 0 // 如果获取计数时出错则默认为0
}
penResponse := &dto.PenResponse{
ID: pen.ID,
PenNumber: pen.PenNumber,
HouseID: pen.HouseID,
Capacity: pen.Capacity,
Status: pen.Status,
CurrentPigCount: currentPigCount,
}
if pen.PigBatchID != nil {
penResponse.PigBatchID = pen.PigBatchID
}
response = append(response, penResponse)
}
return response, nil
} }
func (s *pigFarmService) UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error) { func (s *pigFarmService) UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error) {

View File

@@ -97,7 +97,7 @@ func NewApplication(configPath string) (*Application, error) {
pigPenTransferManager, pigTradeManager, pigSickManager) pigPenTransferManager, pigTradeManager, pigSickManager)
// --- 业务逻辑处理器初始化 --- // --- 业务逻辑处理器初始化 ---
pigFarmService := service.NewPigFarmService(pigFarmRepo, pigPenRepo, pigBatchRepo, unitOfWork, logger) pigFarmService := service.NewPigFarmService(pigFarmRepo, pigPenRepo, pigBatchRepo, pigBatchDomain, unitOfWork, logger)
pigBatchService := service.NewPigBatchService(pigBatchDomain, logger) pigBatchService := service.NewPigBatchService(pigBatchDomain, logger)
monitorService := service.NewMonitorService( monitorService := service.NewMonitorService(
sensorDataRepo, sensorDataRepo,

View File

@@ -6,7 +6,6 @@ import (
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
"gorm.io/gorm"
) )
// --- 业务错误定义 --- // --- 业务错误定义 ---
@@ -58,6 +57,10 @@ type PigBatchService interface {
// GetCurrentPigQuantity 获取指定猪批次的当前猪只数量。 // GetCurrentPigQuantity 获取指定猪批次的当前猪只数量。
GetCurrentPigQuantity(batchID uint) (int, error) GetCurrentPigQuantity(batchID uint) (int, error)
// GetCurrentPigsInPen 获取指定猪栏的当前存栏量。
GetCurrentPigsInPen(penID uint) (int, error)
// GetTotalPigsInPensForBatch 获取指定猪群下所有猪栏的当前总存栏数
GetTotalPigsInPensForBatch(batchID uint) (int, error)
UpdatePigBatchQuantity(operatorID uint, batchID uint, changeType models.LogChangeType, changeAmount int, changeReason string, happenedAt time.Time) error UpdatePigBatchQuantity(operatorID uint, batchID uint, changeType models.LogChangeType, changeAmount int, changeReason string, happenedAt time.Time) error
@@ -118,48 +121,3 @@ func NewPigBatchService(
sickSvc: sickSvc, sickSvc: sickSvc,
} }
} }
func (s *pigBatchService) RemoveEmptyPenFromBatch(batchID uint, penID uint) error {
return s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
// 1. 检查猪批次是否存在且活跃
batch, err := s.pigBatchRepo.GetPigBatchByIDTx(tx, batchID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPigBatchNotFound
}
return err
}
if !batch.IsActive() {
return ErrPigBatchNotActive
}
// 2. 检查猪栏是否存在
pen, err := s.transferSvc.GetPenByID(tx, penID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPenNotFound
}
return err
}
// 3. 检查猪栏是否与当前批次关联
if pen.PigBatchID == nil || *pen.PigBatchID != batchID {
return ErrPenNotAssociatedWithBatch
}
// 4. 检查猪栏是否为空
pigsInPen, err := s.transferSvc.GetCurrentPigsInPen(tx, penID)
if err != nil {
return err
}
if pigsInPen > 0 {
return ErrPenNotEmpty
}
// 5. 释放猪栏 (将 pig_batch_id 设置为 nil状态设置为空闲)
if err := s.transferSvc.ReleasePen(tx, penID); err != nil {
return err
}
return nil
})
}

View File

@@ -381,3 +381,75 @@ func (s *pigBatchService) ReclassifyPenToNewBatch(fromBatchID uint, toBatchID ui
return nil return nil
}) })
} }
func (s *pigBatchService) RemoveEmptyPenFromBatch(batchID uint, penID uint) error {
return s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
// 1. 检查猪批次是否存在且活跃
batch, err := s.pigBatchRepo.GetPigBatchByIDTx(tx, batchID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPigBatchNotFound
}
return err
}
if !batch.IsActive() {
return ErrPigBatchNotActive
}
// 2. 检查猪栏是否存在
pen, err := s.transferSvc.GetPenByID(tx, penID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPenNotFound
}
return err
}
// 3. 检查猪栏是否与当前批次关联
if pen.PigBatchID == nil || *pen.PigBatchID != batchID {
return ErrPenNotAssociatedWithBatch
}
// 4. 检查猪栏是否为空
pigsInPen, err := s.transferSvc.GetCurrentPigsInPen(tx, penID)
if err != nil {
return err
}
if pigsInPen > 0 {
return ErrPenNotEmpty
}
// 5. 释放猪栏 (将 pig_batch_id 设置为 nil状态设置为空闲)
if err := s.transferSvc.ReleasePen(tx, penID); err != nil {
return err
}
return nil
})
}
func (s *pigBatchService) GetCurrentPigsInPen(penID uint) (int, error) {
var currentPigs int
err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
pigs, err := s.transferSvc.GetCurrentPigsInPen(tx, penID)
if err != nil {
return err
}
currentPigs = pigs
return nil
})
return currentPigs, err
}
// GetTotalPigsInPensForBatch 实现了获取指定猪群下所有猪栏的当前总存栏数的逻辑。
func (s *pigBatchService) GetTotalPigsInPensForBatch(batchID uint) (int, error) {
var totalPigs int
err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
pigs, err := s.transferSvc.GetTotalPigsInPensForBatchTx(tx, batchID)
if err != nil {
return err
}
totalPigs = pigs
return nil
})
return totalPigs, err
}