实现库存管理相关逻辑
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||
@@ -18,6 +19,16 @@ type RawMaterialListOptions struct {
|
||||
OrderBy string
|
||||
}
|
||||
|
||||
// StockLogListOptions 定义了查询库存日志列表时的筛选条件
|
||||
type StockLogListOptions struct {
|
||||
RawMaterialID *uint32
|
||||
RawMaterialName *string
|
||||
SourceTypes []models.StockLogSourceType
|
||||
StartTime *time.Time
|
||||
EndTime *time.Time
|
||||
OrderBy string
|
||||
}
|
||||
|
||||
// RawMaterialRepository 定义了与原料相关的数据库操作接口
|
||||
type RawMaterialRepository interface {
|
||||
CreateRawMaterial(ctx context.Context, rawMaterial *models.RawMaterial) error
|
||||
@@ -32,6 +43,10 @@ type RawMaterialRepository interface {
|
||||
// 库存日志相关方法
|
||||
CreateRawMaterialStockLog(ctx context.Context, log *models.RawMaterialStockLog) error
|
||||
GetLatestRawMaterialStockLog(ctx context.Context, rawMaterialID uint32) (*models.RawMaterialStockLog, error)
|
||||
// BatchGetLatestStockLogsForMaterials 批量获取一组原料的最新库存日志
|
||||
BatchGetLatestStockLogsForMaterials(ctx context.Context, materialIDs []uint32) (map[uint32]models.RawMaterialStockLog, error)
|
||||
// ListStockLogs 分页列出库存变动日志
|
||||
ListStockLogs(ctx context.Context, opts StockLogListOptions, page, pageSize int) ([]models.RawMaterialStockLog, int64, error)
|
||||
}
|
||||
|
||||
// gormRawMaterialRepository 是 RawMaterialRepository 的 GORM 实现
|
||||
@@ -219,3 +234,87 @@ func (r *gormRawMaterialRepository) GetLatestRawMaterialStockLog(ctx context.Con
|
||||
}
|
||||
return &latestLog, nil
|
||||
}
|
||||
|
||||
// BatchGetLatestStockLogsForMaterials 批量获取一组原料的最新库存日志
|
||||
func (r *gormRawMaterialRepository) BatchGetLatestStockLogsForMaterials(ctx context.Context, materialIDs []uint32) (map[uint32]models.RawMaterialStockLog, error) {
|
||||
repoCtx := logs.AddFuncName(ctx, r.ctx, "BatchGetLatestStockLogsForMaterials")
|
||||
if len(materialIDs) == 0 {
|
||||
return make(map[uint32]models.RawMaterialStockLog), nil
|
||||
}
|
||||
|
||||
var latestLogs []models.RawMaterialStockLog
|
||||
|
||||
// 使用窗口函数 ROW_NUMBER() 来为每个原料的日志分区,并按时间倒序排名。
|
||||
// 这样可以高效地一次性查询出每个原料的最新一条日志。
|
||||
subQuery := r.db.Model(&models.RawMaterialStockLog{}).
|
||||
Select("*, ROW_NUMBER() OVER(PARTITION BY raw_material_id ORDER BY happened_at DESC, id DESC) as rn").
|
||||
Where("raw_material_id IN ?", materialIDs)
|
||||
|
||||
err := r.db.WithContext(repoCtx).
|
||||
Table("(?) as sub", subQuery).
|
||||
Where("rn = 1").
|
||||
Find(&latestLogs).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("批量获取最新库存日志失败: %w", err)
|
||||
}
|
||||
|
||||
// 将结果转换为 map[uint32]models.RawMaterialStockLog 以方便查找
|
||||
logMap := make(map[uint32]models.RawMaterialStockLog, len(latestLogs))
|
||||
for _, log := range latestLogs {
|
||||
logMap[log.RawMaterialID] = log
|
||||
}
|
||||
|
||||
return logMap, nil
|
||||
}
|
||||
|
||||
// ListStockLogs 分页列出库存变动日志
|
||||
func (r *gormRawMaterialRepository) ListStockLogs(ctx context.Context, opts StockLogListOptions, page, pageSize int) ([]models.RawMaterialStockLog, int64, error) {
|
||||
repoCtx := logs.AddFuncName(ctx, r.ctx, "ListStockLogs")
|
||||
var logs []models.RawMaterialStockLog
|
||||
var total int64
|
||||
|
||||
db := r.db.WithContext(repoCtx).Model(&models.RawMaterialStockLog{})
|
||||
|
||||
// 应用筛选条件
|
||||
if opts.RawMaterialID != nil {
|
||||
db = db.Where("raw_material_id = ?", *opts.RawMaterialID)
|
||||
}
|
||||
|
||||
// 新增:按原料名称模糊搜索
|
||||
if opts.RawMaterialName != nil && *opts.RawMaterialName != "" {
|
||||
// 使用子查询找到匹配的原料ID
|
||||
subQuery := r.db.Model(&models.RawMaterial{}).Select("id").Where("name LIKE ?", "%"+*opts.RawMaterialName+"%")
|
||||
db = db.Where("raw_material_id IN (?)", subQuery)
|
||||
}
|
||||
|
||||
if len(opts.SourceTypes) > 0 {
|
||||
db = db.Where("source_type IN ?", opts.SourceTypes)
|
||||
}
|
||||
if opts.StartTime != nil {
|
||||
db = db.Where("happened_at >= ?", *opts.StartTime)
|
||||
}
|
||||
if opts.EndTime != nil {
|
||||
db = db.Where("happened_at <= ?", *opts.EndTime)
|
||||
}
|
||||
|
||||
// 首先计算总数
|
||||
if err := db.Count(&total).Error; err != nil {
|
||||
return nil, 0, fmt.Errorf("统计库存日志总数失败: %w", err)
|
||||
}
|
||||
|
||||
// 然后应用排序、分页并获取数据
|
||||
if opts.OrderBy != "" {
|
||||
db = db.Order(opts.OrderBy)
|
||||
} else {
|
||||
// 默认排序
|
||||
db = db.Order("happened_at DESC, id DESC")
|
||||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
if err := db.Preload("RawMaterial").Offset(offset).Limit(pageSize).Find(&logs).Error; err != nil {
|
||||
return nil, 0, fmt.Errorf("查询库存日志列表失败: %w", err)
|
||||
}
|
||||
|
||||
return logs, total, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user