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)
 | 
						||
}
 |