issue_39 #40
| @@ -4906,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" | ||||||
|   | |||||||
| @@ -4898,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" | ||||||
|   | |||||||
| @@ -662,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 | ||||||
|   | |||||||
| @@ -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 用于为猪批次分配空栏的请求体 | ||||||
|   | |||||||
| @@ -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.GetCurrentPigsInPen(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.GetCurrentPigsInPen(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.GetCurrentPigsInPen(id) | ||||||
|  | 	if err != nil { | ||||||
|  | 		s.logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", id, err) | ||||||
|  | 		return nil, MapDomainError(err) | ||||||
|  | 	} | ||||||
|  | 	currentTotalPigsInPens, err := s.domainService.GetCurrentPigsInPen(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.GetCurrentPigsInPen(batch.ID) | ||||||
|  | 		if err != nil { | ||||||
|  | 			s.logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", batch.ID, err) | ||||||
|  | 			return nil, MapDomainError(err) | ||||||
|  | 		} | ||||||
|  | 		currentTotalPigsInPens, err := s.domainService.GetCurrentPigsInPen(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 | ||||||
|   | |||||||
| @@ -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" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // --- 业务错误定义 --- | // --- 业务错误定义 --- | ||||||
| @@ -60,6 +59,8 @@ type PigBatchService interface { | |||||||
| 	GetCurrentPigQuantity(batchID uint) (int, error) | 	GetCurrentPigQuantity(batchID uint) (int, error) | ||||||
| 	// GetCurrentPigsInPen 获取指定猪栏的当前存栏量。 | 	// GetCurrentPigsInPen 获取指定猪栏的当前存栏量。 | ||||||
| 	GetCurrentPigsInPen(penID uint) (int, error) | 	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 | ||||||
|  |  | ||||||
| @@ -120,61 +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 |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| 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 |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user