Files
pig-farm-controller/internal/domain/pig/pig_batch_service_pig_trade.go
2025-10-06 16:19:48 +08:00

155 lines
5.2 KiB
Go

package pig
import (
"errors"
"fmt"
"time"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
"gorm.io/gorm"
)
// SellPigs 处理批量销售猪的业务逻辑。
func (s *pigBatchService) SellPigs(batchID uint, penID uint, quantity int, unitPrice float64, tatalPrice float64, traderName string, tradeDate time.Time, remarks string, operatorID uint) error {
return s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
if quantity <= 0 {
return errors.New("销售数量必须大于0")
}
// 1. 校验猪栏信息
pen, err := s.transferSvc.GetPenByID(tx, penID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPenNotFound
}
return fmt.Errorf("获取猪栏 %d 信息失败: %w", penID, err)
}
// 校验猪栏是否属于该批次
if pen.PigBatchID == nil || *pen.PigBatchID != batchID {
return ErrPenNotAssociatedWithBatch
}
// 2. 业务校验:检查销售数量是否超过猪栏当前猪只数
currentPigsInPen, err := s.transferSvc.GetCurrentPigsInPen(tx, penID)
if err != nil {
return fmt.Errorf("获取猪栏 %d 当前猪只数失败: %w", penID, err)
}
if quantity > currentPigsInPen {
return fmt.Errorf("销售数量 %d 超过猪栏 %d 当前猪只数 %d", quantity, penID, currentPigsInPen)
}
// 3. 记录销售交易 (财务)
sale := &models.PigSale{
PigBatchID: batchID,
SaleDate: tradeDate,
Buyer: traderName,
Quantity: quantity,
UnitPrice: unitPrice,
TotalPrice: tatalPrice, // 总价不一定是单价x数量, 所以要传进来
Remarks: remarks,
OperatorID: operatorID,
}
if err := s.tradeSvc.SellPig(tx, sale); err != nil {
return fmt.Errorf("记录销售交易失败: %w", err)
}
// 4. 创建猪只转移日志 (物理)
transferLog := &models.PigTransferLog{
TransferTime: tradeDate,
PigBatchID: batchID,
PenID: penID,
Quantity: -quantity, // 销售导致数量减少
Type: models.PigTransferTypeSale,
OperatorID: operatorID,
Remarks: fmt.Sprintf("销售给 %s", traderName),
}
if err := s.transferSvc.LogTransfer(tx, transferLog); err != nil {
return fmt.Errorf("创建猪只转移日志失败: %w", err)
}
// 5. 记录批次数量变更日志 (逻辑)
if err := s.updatePigBatchQuantityTx(tx, operatorID, batchID, models.ChangeTypeSale, -quantity,
fmt.Sprintf("猪批次 %d 从猪栏 %d 销售 %d 头猪给 %s", batchID, penID, quantity, traderName),
tradeDate); err != nil {
return fmt.Errorf("更新猪批次数量失败: %w", err)
}
return nil
})
}
// BuyPigs 处理批量购买猪的业务逻辑。
func (s *pigBatchService) BuyPigs(batchID uint, penID uint, quantity int, unitPrice float64, totalPrice float64, traderName string, tradeDate time.Time, remarks string, operatorID uint) error {
return s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
if quantity <= 0 {
return errors.New("采购数量必须大于0")
}
// 1. 校验猪栏信息
pen, err := s.transferSvc.GetPenByID(tx, penID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPenNotFound
}
return fmt.Errorf("获取猪栏 %d 信息失败: %w", penID, err)
}
// 校验猪栏是否属于该批次
if pen.PigBatchID == nil || *pen.PigBatchID != batchID {
return ErrPenNotAssociatedWithBatch
}
// 2. 业务校验:检查猪栏容量,如果超出,在备注中记录警告
currentPigsInPen, err := s.transferSvc.GetCurrentPigsInPen(tx, penID)
if err != nil {
return fmt.Errorf("获取猪栏 %d 当前猪只数失败: %w", penID, err)
}
transferRemarks := fmt.Sprintf("从 %s 采购", traderName)
if currentPigsInPen+quantity > pen.Capacity {
warning := fmt.Sprintf("[警告]猪栏容量超出: 当前 %d, 采购 %d, 容量 %d.", currentPigsInPen, quantity, pen.Capacity)
transferRemarks = fmt.Sprintf("%s %s", transferRemarks, warning)
}
// 3. 记录采购交易 (财务)
purchase := &models.PigPurchase{
PigBatchID: batchID,
PurchaseDate: tradeDate,
Supplier: traderName,
Quantity: quantity,
UnitPrice: unitPrice,
TotalPrice: totalPrice, // 总价不一定是单价x数量, 所以要传进来
Remarks: remarks, // 用户传入的备注
OperatorID: operatorID,
}
if err := s.tradeSvc.BuyPig(tx, purchase); err != nil {
return fmt.Errorf("记录采购交易失败: %w", err)
}
// 4. 创建猪只转移日志 (物理)
transferLog := &models.PigTransferLog{
TransferTime: tradeDate,
PigBatchID: batchID,
PenID: penID,
Quantity: quantity, // 采购导致数量增加
Type: models.PigTransferTypePurchase,
OperatorID: operatorID,
Remarks: transferRemarks, // 包含系统生成的备注和潜在的警告
}
if err := s.transferSvc.LogTransfer(tx, transferLog); err != nil {
return fmt.Errorf("创建猪只转移日志失败: %w", err)
}
// 5. 记录批次数量变更日志 (逻辑)
if err := s.updatePigBatchQuantityTx(tx, operatorID, batchID, models.ChangeTypeBuy, quantity,
fmt.Sprintf("猪批次 %d 在猪栏 %d 采购 %d 头猪从 %s", batchID, penID, quantity, traderName),
tradeDate); err != nil {
return fmt.Errorf("更新猪批次数量失败: %w", err)
}
return nil
})
}