197 lines
6.2 KiB
Go
197 lines
6.2 KiB
Go
package pig
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"time"
|
||
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// --- 领域服务实现 ---
|
||
|
||
// CreatePigBatch 实现了创建猪批次的逻辑,并同时创建初始批次日志。
|
||
func (s *pigBatchService) CreatePigBatch(operatorID uint, batch *models.PigBatch) (*models.PigBatch, error) {
|
||
// 业务规则可以在这里添加,例如检查批次号是否唯一等
|
||
|
||
var createdBatch *models.PigBatch
|
||
err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
|
||
// 1. 创建猪批次
|
||
// 注意: 此处依赖一个假设存在的 pigBatchRepo.CreatePigBatchTx 方法
|
||
var err error
|
||
createdBatch, err = s.pigBatchRepo.CreatePigBatchTx(tx, batch)
|
||
if err != nil {
|
||
return fmt.Errorf("创建猪批次失败: %w", err)
|
||
}
|
||
|
||
// 2. 创建初始批次日志
|
||
initialLog := &models.PigBatchLog{
|
||
PigBatchID: createdBatch.ID,
|
||
HappenedAt: time.Now(),
|
||
ChangeType: models.ChangeTypeCorrection, // 初始创建可视为一种校正
|
||
ChangeCount: createdBatch.InitialCount,
|
||
Reason: fmt.Sprintf("创建了新的猪批次 %s,初始数量 %d", createdBatch.BatchNumber, createdBatch.InitialCount),
|
||
BeforeCount: 0, // 初始创建前数量为0
|
||
AfterCount: createdBatch.InitialCount,
|
||
OperatorID: operatorID,
|
||
}
|
||
|
||
// 3. 记录批次日志
|
||
if err := s.pigBatchLogRepo.CreateTx(tx, initialLog); err != nil {
|
||
return fmt.Errorf("记录初始批次日志失败: %w", err)
|
||
}
|
||
|
||
return nil
|
||
})
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return createdBatch, nil
|
||
}
|
||
|
||
// GetPigBatch 实现了获取单个猪批次的逻辑。
|
||
func (s *pigBatchService) GetPigBatch(id uint) (*models.PigBatch, error) {
|
||
batch, err := s.pigBatchRepo.GetPigBatchByID(id)
|
||
if err != nil {
|
||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||
return nil, ErrPigBatchNotFound
|
||
}
|
||
return nil, err
|
||
}
|
||
return batch, nil
|
||
}
|
||
|
||
// UpdatePigBatch 实现了更新猪批次的逻辑。
|
||
func (s *pigBatchService) UpdatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) {
|
||
// 可以在这里添加更新前的业务校验
|
||
updatedBatch, rowsAffected, err := s.pigBatchRepo.UpdatePigBatch(batch)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if rowsAffected == 0 {
|
||
return nil, ErrPigBatchNotFound // 如果没有行被更新,可能意味着记录不存在
|
||
}
|
||
return updatedBatch, nil
|
||
}
|
||
|
||
// DeletePigBatch 实现了删除猪批次的逻辑,并包含业务规则校验。
|
||
func (s *pigBatchService) DeletePigBatch(id uint) error {
|
||
return s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
|
||
// 1. 获取猪批次信息
|
||
batch, err := s.pigBatchRepo.GetPigBatchByIDTx(tx, id) // 使用事务内方法
|
||
if err != nil {
|
||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||
return ErrPigBatchNotFound
|
||
}
|
||
return err
|
||
}
|
||
|
||
// 2. 核心业务规则:检查猪批次是否为活跃状态
|
||
if batch.IsActive() {
|
||
return ErrPigBatchActive // 如果活跃,则不允许删除
|
||
}
|
||
|
||
// 3. 释放所有关联的猪栏
|
||
// 获取该批次下所有猪栏
|
||
pensInBatch, err := s.transferSvc.GetPensByBatchID(tx, id)
|
||
if err != nil {
|
||
return fmt.Errorf("获取猪批次 %d 关联猪栏失败: %w", id, err)
|
||
}
|
||
|
||
// 逐一释放猪栏
|
||
for _, pen := range pensInBatch {
|
||
if err := s.transferSvc.ReleasePen(tx, pen.ID); err != nil {
|
||
return fmt.Errorf("释放猪栏 %d 失败: %w", pen.ID, err)
|
||
}
|
||
}
|
||
|
||
// 4. 执行删除猪批次
|
||
rowsAffected, err := s.pigBatchRepo.DeletePigBatchTx(tx, id)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if rowsAffected == 0 {
|
||
return ErrPigBatchNotFound
|
||
}
|
||
|
||
return nil
|
||
})
|
||
}
|
||
|
||
// ListPigBatches 实现了批量查询猪批次的逻辑。
|
||
func (s *pigBatchService) ListPigBatches(isActive *bool) ([]*models.PigBatch, error) {
|
||
return s.pigBatchRepo.ListPigBatches(isActive)
|
||
}
|
||
|
||
// GetCurrentPigQuantity 实现了获取指定猪批次的当前猪只数量的逻辑。
|
||
func (s *pigBatchService) GetCurrentPigQuantity(batchID uint) (int, error) {
|
||
var getErr error
|
||
var quantity int
|
||
err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
|
||
quantity, getErr = s.getCurrentPigQuantityTx(tx, batchID)
|
||
return getErr
|
||
})
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
return quantity, nil
|
||
}
|
||
|
||
// getCurrentPigQuantityTx 实现了获取指定猪批次的当前猪只数量的逻辑。
|
||
func (s *pigBatchService) getCurrentPigQuantityTx(tx *gorm.DB, batchID uint) (int, error) {
|
||
// 1. 获取猪批次初始信息
|
||
batch, err := s.pigBatchRepo.GetPigBatchByIDTx(tx, batchID)
|
||
if err != nil {
|
||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||
return 0, ErrPigBatchNotFound
|
||
}
|
||
return 0, fmt.Errorf("获取猪批次 %d 初始信息失败: %w", batchID, err)
|
||
}
|
||
|
||
// 2. 尝试获取该批次的最后一条日志记录
|
||
lastLog, err := s.pigBatchLogRepo.GetLastLogByBatchIDTx(tx, batchID)
|
||
if err != nil {
|
||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||
// 如果没有找到任何日志记录(除了初始创建),则当前数量就是初始数量
|
||
return batch.InitialCount, nil
|
||
}
|
||
return 0, fmt.Errorf("获取猪批次 %d 最后一条日志失败: %w", batchID, err)
|
||
}
|
||
|
||
// 3. 如果找到最后一条日志,则当前数量为该日志的 AfterCount
|
||
return lastLog.AfterCount, nil
|
||
}
|
||
|
||
func (s *pigBatchService) UpdatePigBatchQuantity(operatorID uint, batchID uint, changeType models.LogChangeType, changeAmount int, changeReason string, happenedAt time.Time) error {
|
||
return s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
|
||
return s.updatePigBatchQuantityTx(tx, operatorID, batchID, changeType, changeAmount, changeReason, happenedAt)
|
||
})
|
||
}
|
||
|
||
func (s *pigBatchService) updatePigBatchQuantityTx(tx *gorm.DB, operatorID uint, batchID uint, changeType models.LogChangeType, changeAmount int, changeReason string, happenedAt time.Time) error {
|
||
lastLog, err := s.pigBatchLogRepo.GetLastLogByBatchIDTx(tx, batchID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
// 检查数量不应该减到小于零
|
||
if changeAmount < 0 {
|
||
if lastLog.AfterCount+changeAmount < 0 {
|
||
return ErrInvalidOperation
|
||
}
|
||
}
|
||
pigBatchLog := &models.PigBatchLog{
|
||
PigBatchID: batchID,
|
||
ChangeType: changeType,
|
||
ChangeCount: changeAmount,
|
||
Reason: changeReason,
|
||
BeforeCount: lastLog.AfterCount,
|
||
AfterCount: lastLog.AfterCount + changeAmount,
|
||
OperatorID: operatorID,
|
||
HappenedAt: happenedAt,
|
||
}
|
||
return s.pigBatchLogRepo.CreateTx(tx, pigBatchLog)
|
||
}
|