创建批次时插入一条记录

This commit is contained in:
2025-10-05 18:28:16 +08:00
parent 9c35372720
commit 2aa0f09079
9 changed files with 145 additions and 26 deletions

View File

@@ -0,0 +1,47 @@
package controller
import (
"errors"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
"github.com/gin-gonic/gin"
)
var (
// ErrUserNotFoundInContext 表示在 gin.Context 中未找到用户信息。
ErrUserNotFoundInContext = errors.New("context中未找到用户信息")
// ErrInvalidUserType 表示从 gin.Context 中获取的用户信息类型不正确。
ErrInvalidUserType = errors.New("context中用户信息类型不正确")
)
// GetOperatorIDFromContext 从 gin.Context 中提取操作者ID。
// 假设操作者ID是由 AuthMiddleware 存储到 context 中的 *models.User 对象的 ID 字段。
func GetOperatorIDFromContext(c *gin.Context) (uint, error) {
userVal, exists := c.Get(models.ContextUserKey.String())
if !exists {
return 0, ErrUserNotFoundInContext
}
user, ok := userVal.(*models.User)
if !ok {
return 0, ErrInvalidUserType
}
return user.ID, nil
}
// GetOperatorFromContext 从 gin.Context 中提取操作者。
// 假设操作者是由 AuthMiddleware 存储到 context 中的 *models.User 对象的 字段。
func GetOperatorFromContext(c *gin.Context) (*models.User, error) {
userVal, exists := c.Get(models.ContextUserKey.String())
if !exists {
return nil, ErrUserNotFoundInContext
}
user, ok := userVal.(*models.User)
if !ok {
return nil, ErrInvalidUserType
}
return user, nil
}

View File

@@ -45,7 +45,9 @@ func (c *PigBatchController) CreatePigBatch(ctx *gin.Context) {
return return
} }
respDTO, err := c.service.CreatePigBatch(&req) userID, err := controller.GetOperatorIDFromContext(ctx)
respDTO, err := c.service.CreatePigBatch(userID, &req)
if err != nil { if err != nil {
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪批次失败", action, "业务逻辑失败", req) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪批次失败", action, "业务逻辑失败", req)

View File

@@ -9,7 +9,7 @@ import (
// PigBatchService 接口定义保持不变,继续作为应用层对外的契约。 // PigBatchService 接口定义保持不变,继续作为应用层对外的契约。
type PigBatchService interface { type PigBatchService interface {
CreatePigBatch(dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) CreatePigBatch(operatorID uint, dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error)
GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error) GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error)
UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error)
DeletePigBatch(id uint) error DeletePigBatch(id uint) error
@@ -51,7 +51,7 @@ func (s *pigBatchService) toPigBatchResponseDTO(batch *models.PigBatch) *dto.Pig
} }
// CreatePigBatch 现在将请求委托给领域服务处理。 // CreatePigBatch 现在将请求委托给领域服务处理。
func (s *pigBatchService) CreatePigBatch(dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) { func (s *pigBatchService) CreatePigBatch(operatorID uint, dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) {
// 1. DTO -> 领域模型 // 1. DTO -> 领域模型
batch := &models.PigBatch{ batch := &models.PigBatch{
BatchNumber: dto.BatchNumber, BatchNumber: dto.BatchNumber,
@@ -62,7 +62,7 @@ func (s *pigBatchService) CreatePigBatch(dto *dto.PigBatchCreateDTO) (*dto.PigBa
} }
// 2. 调用领域服务 // 2. 调用领域服务
createdBatch, err := s.domainService.CreatePigBatch(batch) createdBatch, err := s.domainService.CreatePigBatch(operatorID, batch)
if err != nil { if err != nil {
s.logger.Errorf("应用层: 创建猪批次失败: %v", err) s.logger.Errorf("应用层: 创建猪批次失败: %v", err)
return nil, mapDomainError(err) return nil, mapDomainError(err)

View File

@@ -73,6 +73,7 @@ func NewApplication(configPath string) (*Application, error) {
pendingCollectionRepo := repository.NewGormPendingCollectionRepository(storage.GetDB()) pendingCollectionRepo := repository.NewGormPendingCollectionRepository(storage.GetDB())
userActionLogRepo := repository.NewGormUserActionLogRepository(storage.GetDB()) userActionLogRepo := repository.NewGormUserActionLogRepository(storage.GetDB())
pigBatchRepo := repository.NewGormPigBatchRepository(storage.GetDB()) pigBatchRepo := repository.NewGormPigBatchRepository(storage.GetDB())
pigBatchLogRepo := repository.NewGormPigBatchLogRepository(storage.GetDB())
pigFarmRepo := repository.NewGormPigFarmRepository(storage.GetDB()) pigFarmRepo := repository.NewGormPigFarmRepository(storage.GetDB())
pigPenRepo := repository.NewGormPigPenRepository(storage.GetDB()) pigPenRepo := repository.NewGormPigPenRepository(storage.GetDB())
@@ -81,7 +82,7 @@ func NewApplication(configPath string) (*Application, error) {
// 初始化猪群管理领域 // 初始化猪群管理领域
penTransferManager := pig.NewPenTransferManager(pigPenRepo) penTransferManager := pig.NewPenTransferManager(pigPenRepo)
pigBatchDomain := pig.NewPigBatchService(pigBatchRepo, unitOfWork, penTransferManager) pigBatchDomain := pig.NewPigBatchService(pigBatchRepo, pigBatchLogRepo, unitOfWork, penTransferManager)
// --- 业务逻辑处理器初始化 --- // --- 业务逻辑处理器初始化 ---
pigFarmService := service.NewPigFarmService(pigFarmRepo, pigPenRepo, pigBatchRepo, unitOfWork, logger) pigFarmService := service.NewPigFarmService(pigFarmRepo, pigPenRepo, pigBatchRepo, unitOfWork, logger)

View File

@@ -37,7 +37,7 @@ type PigBatchService interface {
TransferPigsAcrossBatches(sourceBatchID uint, destBatchID uint, fromPenID uint, toPenID uint, quantity uint) error TransferPigsAcrossBatches(sourceBatchID uint, destBatchID uint, fromPenID uint, toPenID uint, quantity uint) error
// CreatePigBatch 创建一个新的猪批次。 // CreatePigBatch 创建一个新的猪批次。
CreatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) CreatePigBatch(operatorID uint, batch *models.PigBatch) (*models.PigBatch, error)
// GetPigBatch 根据ID获取单个猪批次的详细信息。 // GetPigBatch 根据ID获取单个猪批次的详细信息。
GetPigBatch(id uint) (*models.PigBatch, error) GetPigBatch(id uint) (*models.PigBatch, error)

View File

@@ -16,29 +16,67 @@ import (
// pigBatchService 是 PigBatchService 接口的具体实现。 // pigBatchService 是 PigBatchService 接口的具体实现。
// 它作为猪群领域的主服务,封装了所有业务逻辑。 // 它作为猪群领域的主服务,封装了所有业务逻辑。
type pigBatchService struct { type pigBatchService struct {
pigBatchRepo repository.PigBatchRepository // 猪批次仓库 pigBatchRepo repository.PigBatchRepository // 猪批次仓库
uow repository.UnitOfWork // 工作单元,用于管理事务 pigBatchLogRepo repository.PigBatchLogRepository // 猪批次日志仓库
transferSvc PenTransferManager // 调栏子服 uow repository.UnitOfWork // 工作单元,用于管理事
transferSvc PenTransferManager // 调栏子服务
} }
// NewPigBatchService 是 pigBatchService 的构造函数。 // NewPigBatchService 是 pigBatchService 的构造函数。
// 它通过依赖注入的方式,创建并返回一个 PigBatchService 接口的实例。 // 它通过依赖注入的方式,创建并返回一个 PigBatchService 接口的实例。
func NewPigBatchService( func NewPigBatchService(
pigBatchRepo repository.PigBatchRepository, pigBatchRepo repository.PigBatchRepository,
pigBatchLogRepo repository.PigBatchLogRepository,
uow repository.UnitOfWork, uow repository.UnitOfWork,
transferSvc PenTransferManager, transferSvc PenTransferManager,
) PigBatchService { ) PigBatchService {
return &pigBatchService{ return &pigBatchService{
pigBatchRepo: pigBatchRepo, pigBatchRepo: pigBatchRepo,
uow: uow, pigBatchLogRepo: pigBatchLogRepo,
transferSvc: transferSvc, uow: uow,
transferSvc: transferSvc,
} }
} }
// CreatePigBatch 实现了创建猪批次的逻辑。 // CreatePigBatch 实现了创建猪批次的逻辑,并同时创建初始批次日志
func (s *pigBatchService) CreatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) { func (s *pigBatchService) CreatePigBatch(operatorID uint, batch *models.PigBatch) (*models.PigBatch, error) {
// 业务规则可以在这里添加,例如检查批次号是否唯一等 // 业务规则可以在这里添加,例如检查批次号是否唯一等
return s.pigBatchRepo.CreatePigBatch(batch)
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: int(createdBatch.InitialCount),
OperatorID: 0, // 假设初始创建没有特定操作员ID或需要从上下文传入
}
// 3. 记录批次日志
if err := s.pigBatchLogRepo.Create(tx, initialLog); err != nil {
return fmt.Errorf("记录初始批次日志失败: %w", err)
}
return nil
})
if err != nil {
return nil, err
}
return createdBatch, nil
} }
// GetPigBatch 实现了获取单个猪批次的逻辑。 // GetPigBatch 实现了获取单个猪批次的逻辑。

View File

@@ -67,16 +67,14 @@ const (
// PigBatchLog 记录了猪批次数量或状态的每一次变更 // PigBatchLog 记录了猪批次数量或状态的每一次变更
type PigBatchLog struct { type PigBatchLog struct {
gorm.Model gorm.Model
PigBatchID uint `gorm:"not null;index;comment:关联的猪批次ID"` PigBatchID uint `gorm:"not null;index;comment:关联的猪批次ID"`
ChangeType LogChangeType `gorm:"size:20;not null;comment:变更类型"` ChangeType LogChangeType `gorm:"size:20;not null;comment:变更类型"`
ChangeCount int `gorm:"not null;comment:数量变化,负数表示减少"` ChangeCount int `gorm:"not null;comment:数量变化,负数表示减少"`
Reason string `gorm:"size:255;comment:变更原因描述"` Reason string `gorm:"size:255;comment:变更原因描述"`
BeforeCount int `gorm:"not null;comment:变更前总数"` BeforeCount int `gorm:"not null;comment:变更前总数"`
AfterCount int `gorm:"not null;comment:变更后总数"` AfterCount int `gorm:"not null;comment:变更后总数"`
BeforeSickCount int `gorm:"not null;comment:变更前病猪数"` OperatorID uint `gorm:"comment:操作员ID"`
AfterSickCount int `gorm:"not null;comment:变更后病猪数"` HappenedAt time.Time `gorm:"primaryKey;comment:事件发生时间"`
OperatorID uint `gorm:"comment:操作员ID"`
HappenedAt time.Time `gorm:"primaryKey;comment:事件发生时间"`
} }
func (PigBatchLog) TableName() string { func (PigBatchLog) TableName() string {

View File

@@ -0,0 +1,27 @@
package repository
import (
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
"gorm.io/gorm"
)
// PigBatchLogRepository 定义了与猪批次日志相关的数据库操作接口。
type PigBatchLogRepository interface {
// Create 在指定的事务中创建一条新的猪批次日志。
Create(tx *gorm.DB, log *models.PigBatchLog) error
}
// gormPigBatchLogRepository 是 PigBatchLogRepository 的 GORM 实现。
type gormPigBatchLogRepository struct {
db *gorm.DB
}
// NewGormPigBatchLogRepository 创建一个新的 PigBatchLogRepository 实例。
func NewGormPigBatchLogRepository(db *gorm.DB) PigBatchLogRepository {
return &gormPigBatchLogRepository{db: db}
}
// Create 实现了创建猪批次日志的逻辑。
func (r *gormPigBatchLogRepository) Create(tx *gorm.DB, log *models.PigBatchLog) error {
return tx.Create(log).Error
}

View File

@@ -8,6 +8,7 @@ import (
// PigBatchRepository 定义了与猪批次相关的数据库操作接口 // PigBatchRepository 定义了与猪批次相关的数据库操作接口
type PigBatchRepository interface { type PigBatchRepository interface {
CreatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) CreatePigBatch(batch *models.PigBatch) (*models.PigBatch, error)
CreatePigBatchTx(tx *gorm.DB, batch *models.PigBatch) (*models.PigBatch, error)
GetPigBatchByID(id uint) (*models.PigBatch, error) GetPigBatchByID(id uint) (*models.PigBatch, error)
GetPigBatchByIDTx(tx *gorm.DB, id uint) (*models.PigBatch, error) GetPigBatchByIDTx(tx *gorm.DB, id uint) (*models.PigBatch, error)
// UpdatePigBatch 更新一个猪批次,返回更新后的批次、受影响的行数和错误 // UpdatePigBatch 更新一个猪批次,返回更新后的批次、受影响的行数和错误
@@ -29,7 +30,12 @@ func NewGormPigBatchRepository(db *gorm.DB) PigBatchRepository {
// CreatePigBatch 创建一个新的猪批次 // CreatePigBatch 创建一个新的猪批次
func (r *gormPigBatchRepository) CreatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) { func (r *gormPigBatchRepository) CreatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) {
if err := r.db.Create(batch).Error; err != nil { return r.CreatePigBatchTx(r.db, batch)
}
// CreatePigBatchTx 在指定的事务中,创建一个新的猪批次
func (r *gormPigBatchRepository) CreatePigBatchTx(tx *gorm.DB, batch *models.PigBatch) (*models.PigBatch, error) {
if err := tx.Create(batch).Error; err != nil {
return nil, err return nil, err
} }
return batch, nil return batch, nil