package service import ( "context" "time" "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/models" ) // PigBatchService 接口定义保持不变,继续作为应用层对外的契约。 type PigBatchService interface { CreatePigBatch(ctx context.Context, operatorID uint, dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) GetPigBatch(ctx context.Context, id uint) (*dto.PigBatchResponseDTO, error) UpdatePigBatch(ctx context.Context, id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) DeletePigBatch(ctx context.Context, id uint) error ListPigBatches(ctx context.Context, isActive *bool) ([]*dto.PigBatchResponseDTO, error) // Pig Pen Management AssignEmptyPensToBatch(ctx context.Context, batchID uint, penIDs []uint, operatorID uint) error ReclassifyPenToNewBatch(ctx context.Context, fromBatchID uint, toBatchID uint, penID uint, operatorID uint, remarks string) error RemoveEmptyPenFromBatch(ctx context.Context, batchID uint, penID uint) error MovePigsIntoPen(ctx context.Context, batchID uint, toPenID uint, quantity int, operatorID uint, remarks string) error // Trade Sub-service SellPigs(ctx context.Context, batchID uint, penID uint, quantity int, unitPrice float64, tatalPrice float64, traderName string, tradeDate time.Time, remarks string, operatorID uint) error BuyPigs(ctx context.Context, batchID uint, penID uint, quantity int, unitPrice float64, tatalPrice float64, traderName string, tradeDate time.Time, remarks string, operatorID uint) error // Transfer Sub-service TransferPigsAcrossBatches(ctx context.Context, sourceBatchID uint, destBatchID uint, fromPenID uint, toPenID uint, quantity uint, operatorID uint, remarks string) error TransferPigsWithinBatch(ctx context.Context, batchID uint, fromPenID uint, toPenID uint, quantity uint, operatorID uint, remarks string) error // Sick Pig Management RecordSickPigs(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error RecordSickPigRecovery(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error RecordSickPigDeath(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error RecordSickPigCull(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error // Normal Pig Management RecordDeath(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, happenedAt time.Time, remarks string) error RecordCull(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, happenedAt time.Time, remarks string) error } // pigBatchService 的实现现在依赖于领域服务接口。 type pigBatchService struct { ctx context.Context domainService domain_pig.PigBatchService } // NewPigBatchService 构造函数被修改,以注入领域服务。 func NewPigBatchService(ctx context.Context, domainService domain_pig.PigBatchService) PigBatchService { return &pigBatchService{ ctx: ctx, domainService: domainService, } } // toPigBatchResponseDTO 负责将领域模型转换为应用层DTO,这个职责保留在应用层。 func (s *pigBatchService) toPigBatchResponseDTO(batch *models.PigBatch, currentTotalQuantity, currentTotalPigsInPens int) *dto.PigBatchResponseDTO { if batch == nil { return nil } return &dto.PigBatchResponseDTO{ ID: batch.ID, BatchNumber: batch.BatchNumber, OriginType: batch.OriginType, StartDate: batch.StartDate, EndDate: batch.EndDate, InitialCount: batch.InitialCount, Status: batch.Status, IsActive: batch.IsActive(), CurrentTotalQuantity: currentTotalQuantity, CurrentTotalPigsInPens: currentTotalPigsInPens, CreateTime: batch.CreatedAt, UpdateTime: batch.UpdatedAt, } } // CreatePigBatch 现在将请求委托给领域服务处理。 func (s *pigBatchService) CreatePigBatch(ctx context.Context, operatorID uint, dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) { serviceCtx, logger := logs.Trace(ctx, s.ctx, "CreatePigBatch") // 1. DTO -> 领域模型 batch := &models.PigBatch{ BatchNumber: dto.BatchNumber, OriginType: dto.OriginType, StartDate: dto.StartDate, InitialCount: dto.InitialCount, Status: dto.Status, } // 2. 调用领域服务 createdBatch, err := s.domainService.CreatePigBatch(serviceCtx, operatorID, batch) if err != nil { logger.Errorf("应用层: 创建猪批次失败: %v", err) return nil, MapDomainError(err) } // 3. 领域模型 -> DTO return s.toPigBatchResponseDTO(createdBatch, dto.InitialCount, 0), nil } // GetPigBatch 从领域服务获取数据并转换为DTO,同时处理错误转换。 func (s *pigBatchService) GetPigBatch(ctx context.Context, id uint) (*dto.PigBatchResponseDTO, error) { serviceCtx, logger := logs.Trace(ctx, s.ctx, "GetPigBatch") batch, err := s.domainService.GetPigBatch(serviceCtx, id) if err != nil { logger.Warnf("应用层: 获取猪批次失败, ID: %d, 错误: %v", id, err) return nil, MapDomainError(err) } currentTotalQuantity, err := s.domainService.GetCurrentPigQuantity(serviceCtx, id) if err != nil { logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", id, err) return nil, MapDomainError(err) } currentTotalPigsInPens, err := s.domainService.GetTotalPigsInPensForBatch(serviceCtx, id) if err != nil { logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", id, err) return nil, MapDomainError(err) } return s.toPigBatchResponseDTO(batch, currentTotalQuantity, currentTotalPigsInPens), nil } // UpdatePigBatch 协调获取、更新和保存的流程,并处理错误转换。 func (s *pigBatchService) UpdatePigBatch(ctx context.Context, id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) { serviceCtx, logger := logs.Trace(ctx, s.ctx, "UpdatePigBatch") // 1. 先获取最新的领域模型 existingBatch, err := s.domainService.GetPigBatch(serviceCtx, id) if err != nil { logger.Warnf("应用层: 更新猪批次失败,获取原批次信息错误, ID: %d, 错误: %v", id, err) return nil, MapDomainError(err) } // 2. 将DTO中的变更应用到模型上 if dto.BatchNumber != nil { existingBatch.BatchNumber = *dto.BatchNumber } if dto.OriginType != nil { existingBatch.OriginType = *dto.OriginType } if dto.StartDate != nil { existingBatch.StartDate = *dto.StartDate } if dto.EndDate != nil { existingBatch.EndDate = *dto.EndDate } if dto.InitialCount != nil { existingBatch.InitialCount = *dto.InitialCount } if dto.Status != nil { existingBatch.Status = *dto.Status } // 3. 调用领域服务执行更新 updatedBatch, err := s.domainService.UpdatePigBatch(serviceCtx, existingBatch) if err != nil { logger.Errorf("应用层: 更新猪批次失败, ID: %d, 错误: %v", id, err) return nil, MapDomainError(err) } // 4. 填充猪群信息 currentTotalQuantity, err := s.domainService.GetCurrentPigQuantity(serviceCtx, id) if err != nil { logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", id, err) return nil, MapDomainError(err) } currentTotalPigsInPens, err := s.domainService.GetTotalPigsInPensForBatch(serviceCtx, id) if err != nil { logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", id, err) return nil, MapDomainError(err) } // 5. 转换并返回结果 return s.toPigBatchResponseDTO(updatedBatch, currentTotalQuantity, currentTotalPigsInPens), nil } // DeletePigBatch 将删除操作委托给领域服务,并转换领域错误为应用层错误。 func (s *pigBatchService) DeletePigBatch(ctx context.Context, id uint) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "DeletePigBatch") err := s.domainService.DeletePigBatch(serviceCtx, id) if err != nil { logger.Errorf("应用层: 删除猪批次失败, ID: %d, 错误: %v", id, err) return MapDomainError(err) } return nil } // ListPigBatches 从领域服务获取列表并进行转换。 func (s *pigBatchService) ListPigBatches(ctx context.Context, isActive *bool) ([]*dto.PigBatchResponseDTO, error) { serviceCtx, logger := logs.Trace(ctx, s.ctx, "ListPigBatches") batches, err := s.domainService.ListPigBatches(serviceCtx, isActive) if err != nil { logger.Errorf("应用层: 批量查询猪批次失败: %v", err) return nil, MapDomainError(err) } var responseDTOs []*dto.PigBatchResponseDTO for _, batch := range batches { currentTotalQuantity, err := s.domainService.GetCurrentPigQuantity(serviceCtx, batch.ID) if err != nil { logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", batch.ID, err) return nil, MapDomainError(err) } currentTotalPigsInPens, err := s.domainService.GetTotalPigsInPensForBatch(serviceCtx, batch.ID) if err != nil { logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", batch.ID, err) return nil, MapDomainError(err) } responseDTOs = append(responseDTOs, s.toPigBatchResponseDTO(batch, currentTotalQuantity, currentTotalPigsInPens)) } return responseDTOs, nil } // AssignEmptyPensToBatch 委托给领域服务 func (s *pigBatchService) AssignEmptyPensToBatch(ctx context.Context, batchID uint, penIDs []uint, operatorID uint) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "AssignEmptyPensToBatch") err := s.domainService.AssignEmptyPensToBatch(serviceCtx, batchID, penIDs, operatorID) if err != nil { logger.Errorf("应用层: 为猪批次分配空栏失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil } // ReclassifyPenToNewBatch 委托给领域服务 func (s *pigBatchService) ReclassifyPenToNewBatch(ctx context.Context, fromBatchID uint, toBatchID uint, penID uint, operatorID uint, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "ReclassifyPenToNewBatch") err := s.domainService.ReclassifyPenToNewBatch(serviceCtx, fromBatchID, toBatchID, penID, operatorID, remarks) if err != nil { logger.Errorf("应用层: 划拨猪栏到新批次失败, 源批次ID: %d, 错误: %v", fromBatchID, err) return MapDomainError(err) } return nil } // RemoveEmptyPenFromBatch 委托给领域服务 func (s *pigBatchService) RemoveEmptyPenFromBatch(ctx context.Context, batchID uint, penID uint) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "RemoveEmptyPenFromBatch") err := s.domainService.RemoveEmptyPenFromBatch(serviceCtx, batchID, penID) if err != nil { logger.Errorf("应用层: 从猪批次移除空栏失败, 批次ID: %d, 猪栏ID: %d, 错误: %v", batchID, penID, err) return MapDomainError(err) } return nil } // MovePigsIntoPen 委托给领域服务 func (s *pigBatchService) MovePigsIntoPen(ctx context.Context, batchID uint, toPenID uint, quantity int, operatorID uint, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "MovePigsIntoPen") err := s.domainService.MovePigsIntoPen(serviceCtx, batchID, toPenID, quantity, operatorID, remarks) if err != nil { logger.Errorf("应用层: 将猪只移入猪栏失败, 批次ID: %d, 目标猪栏ID: %d, 错误: %v", batchID, toPenID, err) return MapDomainError(err) } return nil } // SellPigs 委托给领域服务 func (s *pigBatchService) SellPigs(ctx context.Context, batchID uint, penID uint, quantity int, unitPrice float64, tatalPrice float64, traderName string, tradeDate time.Time, remarks string, operatorID uint) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "SellPigs") err := s.domainService.SellPigs(serviceCtx, batchID, penID, quantity, unitPrice, tatalPrice, traderName, tradeDate, remarks, operatorID) if err != nil { logger.Errorf("应用层: 卖猪失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil } // BuyPigs 委托给领域服务 func (s *pigBatchService) BuyPigs(ctx context.Context, batchID uint, penID uint, quantity int, unitPrice float64, tatalPrice float64, traderName string, tradeDate time.Time, remarks string, operatorID uint) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "BuyPigs") err := s.domainService.BuyPigs(serviceCtx, batchID, penID, quantity, unitPrice, tatalPrice, traderName, tradeDate, remarks, operatorID) if err != nil { logger.Errorf("应用层: 买猪失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil } // TransferPigsAcrossBatches 委托给领域服务 func (s *pigBatchService) TransferPigsAcrossBatches(ctx context.Context, sourceBatchID uint, destBatchID uint, fromPenID uint, toPenID uint, quantity uint, operatorID uint, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "TransferPigsAcrossBatches") err := s.domainService.TransferPigsAcrossBatches(serviceCtx, sourceBatchID, destBatchID, fromPenID, toPenID, quantity, operatorID, remarks) if err != nil { logger.Errorf("应用层: 跨群调栏失败, 源批次ID: %d, 错误: %v", sourceBatchID, err) return MapDomainError(err) } return nil } // TransferPigsWithinBatch 委托给领域服务 func (s *pigBatchService) TransferPigsWithinBatch(ctx context.Context, batchID uint, fromPenID uint, toPenID uint, quantity uint, operatorID uint, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "TransferPigsWithinBatch") err := s.domainService.TransferPigsWithinBatch(serviceCtx, batchID, fromPenID, toPenID, quantity, operatorID, remarks) if err != nil { logger.Errorf("应用层: 群内调栏失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil } // RecordSickPigs 委托给领域服务 func (s *pigBatchService) RecordSickPigs(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordSickPigs") err := s.domainService.RecordSickPigs(serviceCtx, operatorID, batchID, penID, quantity, treatmentLocation, happenedAt, remarks) if err != nil { logger.Errorf("应用层: 记录病猪事件失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil } // RecordSickPigRecovery 委托给领域服务 func (s *pigBatchService) RecordSickPigRecovery(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordSickPigRecovery") err := s.domainService.RecordSickPigRecovery(serviceCtx, operatorID, batchID, penID, quantity, treatmentLocation, happenedAt, remarks) if err != nil { logger.Errorf("应用层: 记录病猪康复事件失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil } // RecordSickPigDeath 委托给领域服务 func (s *pigBatchService) RecordSickPigDeath(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordSickPigDeath") err := s.domainService.RecordSickPigDeath(serviceCtx, operatorID, batchID, penID, quantity, treatmentLocation, happenedAt, remarks) if err != nil { logger.Errorf("应用层: 记录病猪死亡事件失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil } // RecordSickPigCull 委托给领域服务 func (s *pigBatchService) RecordSickPigCull(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordSickPigCull") err := s.domainService.RecordSickPigCull(serviceCtx, operatorID, batchID, penID, quantity, treatmentLocation, happenedAt, remarks) if err != nil { logger.Errorf("应用层: 记录病猪淘汰事件失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil } // RecordDeath 委托给领域服务 func (s *pigBatchService) RecordDeath(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, happenedAt time.Time, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordDeath") err := s.domainService.RecordDeath(serviceCtx, operatorID, batchID, penID, quantity, happenedAt, remarks) if err != nil { logger.Errorf("应用层: 记录正常猪只死亡事件失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil } // RecordCull 委托给领域服务 func (s *pigBatchService) RecordCull(ctx context.Context, operatorID uint, batchID uint, penID uint, quantity int, happenedAt time.Time, remarks string) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordCull") err := s.domainService.RecordCull(serviceCtx, operatorID, batchID, penID, quantity, happenedAt, remarks) if err != nil { logger.Errorf("应用层: 记录正常猪只淘汰事件失败, 批次ID: %d, 错误: %v", batchID, err) return MapDomainError(err) } return nil }