diff --git a/docs/docs.go b/docs/docs.go index 9155de7..d08f2c4 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -3392,6 +3392,12 @@ const docTemplate = `{ ], "summary": "获取当前库存列表", "parameters": [ + { + "type": "boolean", + "description": "只查询有库存的原料", + "name": "has_stock", + "in": "query" + }, { "type": "string", "description": "排序字段, 例如 \"stock DESC\"", @@ -3715,6 +3721,7 @@ const docTemplate = `{ }, { "enum": [ + 7, -1, 0, 1, @@ -3724,12 +3731,12 @@ const docTemplate = `{ 5, -1, 5, - 6, - 7 + 6 ], "type": "integer", "format": "int32", "x-enum-varnames": [ + "_numLevels", "DebugLevel", "InfoLevel", "WarnLevel", @@ -3739,8 +3746,7 @@ const docTemplate = `{ "FatalLevel", "_minLevel", "_maxLevel", - "InvalidLevel", - "_numLevels" + "InvalidLevel" ], "name": "level", "in": "query" @@ -7267,6 +7273,10 @@ const docTemplate = `{ "type": "string", "maxLength": 255 }, + "max_addition_ratio": { + "description": "最大添加比例", + "type": "number" + }, "name": { "description": "原料名称", "type": "string", @@ -8824,6 +8834,10 @@ const docTemplate = `{ "id": { "type": "integer" }, + "max_addition_ratio": { + "description": "最大添加比例", + "type": "number" + }, "name": { "type": "string" }, @@ -9864,6 +9878,10 @@ const docTemplate = `{ "type": "string", "maxLength": 255 }, + "max_addition_ratio": { + "description": "最大添加比例", + "type": "number" + }, "name": { "description": "原料名称", "type": "string", @@ -10586,6 +10604,7 @@ const docTemplate = `{ "type": "integer", "format": "int32", "enum": [ + 7, -1, 0, 1, @@ -10595,10 +10614,10 @@ const docTemplate = `{ 5, -1, 5, - 6, - 7 + 6 ], "x-enum-varnames": [ + "_numLevels", "DebugLevel", "InfoLevel", "WarnLevel", @@ -10608,8 +10627,7 @@ const docTemplate = `{ "FatalLevel", "_minLevel", "_maxLevel", - "InvalidLevel", - "_numLevels" + "InvalidLevel" ] } }, diff --git a/docs/swagger.json b/docs/swagger.json index dd534bf..7687226 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -3384,6 +3384,12 @@ ], "summary": "获取当前库存列表", "parameters": [ + { + "type": "boolean", + "description": "只查询有库存的原料", + "name": "has_stock", + "in": "query" + }, { "type": "string", "description": "排序字段, 例如 \"stock DESC\"", @@ -3707,6 +3713,7 @@ }, { "enum": [ + 7, -1, 0, 1, @@ -3716,12 +3723,12 @@ 5, -1, 5, - 6, - 7 + 6 ], "type": "integer", "format": "int32", "x-enum-varnames": [ + "_numLevels", "DebugLevel", "InfoLevel", "WarnLevel", @@ -3731,8 +3738,7 @@ "FatalLevel", "_minLevel", "_maxLevel", - "InvalidLevel", - "_numLevels" + "InvalidLevel" ], "name": "level", "in": "query" @@ -7259,6 +7265,10 @@ "type": "string", "maxLength": 255 }, + "max_addition_ratio": { + "description": "最大添加比例", + "type": "number" + }, "name": { "description": "原料名称", "type": "string", @@ -8816,6 +8826,10 @@ "id": { "type": "integer" }, + "max_addition_ratio": { + "description": "最大添加比例", + "type": "number" + }, "name": { "type": "string" }, @@ -9856,6 +9870,10 @@ "type": "string", "maxLength": 255 }, + "max_addition_ratio": { + "description": "最大添加比例", + "type": "number" + }, "name": { "description": "原料名称", "type": "string", @@ -10578,6 +10596,7 @@ "type": "integer", "format": "int32", "enum": [ + 7, -1, 0, 1, @@ -10587,10 +10606,10 @@ 5, -1, 5, - 6, - 7 + 6 ], "x-enum-varnames": [ + "_numLevels", "DebugLevel", "InfoLevel", "WarnLevel", @@ -10600,8 +10619,7 @@ "FatalLevel", "_minLevel", "_maxLevel", - "InvalidLevel", - "_numLevels" + "InvalidLevel" ] } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4f31241..50b7304 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -416,6 +416,9 @@ definitions: description: 描述 maxLength: 255 type: string + max_addition_ratio: + description: 最大添加比例 + type: number name: description: 原料名称 maxLength: 100 @@ -1446,6 +1449,9 @@ definitions: type: string id: type: integer + max_addition_ratio: + description: 最大添加比例 + type: number name: type: string raw_material_nutrients: @@ -2160,6 +2166,9 @@ definitions: description: 描述 maxLength: 255 type: string + max_addition_ratio: + description: 最大添加比例 + type: number name: description: 原料名称 maxLength: 100 @@ -2731,6 +2740,7 @@ definitions: - PlanTypeFilterSystem zapcore.Level: enum: + - 7 - -1 - 0 - 1 @@ -2741,10 +2751,10 @@ definitions: - -1 - 5 - 6 - - 7 format: int32 type: integer x-enum-varnames: + - _numLevels - DebugLevel - InfoLevel - WarnLevel @@ -2755,7 +2765,6 @@ definitions: - _minLevel - _maxLevel - InvalidLevel - - _numLevels info: contact: email: divano@example.com @@ -4793,6 +4802,10 @@ paths: get: description: 获取所有原料的当前库存列表,支持分页和过滤。 parameters: + - description: 只查询有库存的原料 + in: query + name: has_stock + type: boolean - description: 排序字段, 例如 "stock DESC" in: query name: order_by @@ -4985,6 +4998,7 @@ paths: name: end_time type: string - enum: + - 7 - -1 - 0 - 1 @@ -4995,12 +5009,12 @@ paths: - -1 - 5 - 6 - - 7 format: int32 in: query name: level type: integer x-enum-varnames: + - _numLevels - DebugLevel - InfoLevel - WarnLevel @@ -5011,7 +5025,6 @@ paths: - _minLevel - _maxLevel - InvalidLevel - - _numLevels - enum: - 邮件 - 企业微信 diff --git a/internal/app/dto/inventory_dto.go b/internal/app/dto/inventory_dto.go index 27ec39d..a695a91 100644 --- a/internal/app/dto/inventory_dto.go +++ b/internal/app/dto/inventory_dto.go @@ -31,6 +31,7 @@ type ListCurrentStockRequest struct { PageSize int `json:"page_size" query:"page_size"` // 每页数量 RawMaterialName *string `json:"raw_material_name" query:"raw_material_name"` // 按原料名称模糊查询 OrderBy string `json:"order_by" query:"order_by"` // 排序字段, 例如 "stock DESC" + HasStock *bool `json:"has_stock" query:"has_stock"` // 只查询有库存的原料 } // ListCurrentStockResponse 是获取当前库存列表的响应结构 diff --git a/internal/app/service/inventory_service.go b/internal/app/service/inventory_service.go index 69cf231..93226c2 100644 --- a/internal/app/service/inventory_service.go +++ b/internal/app/service/inventory_service.go @@ -75,8 +75,9 @@ func (s *inventoryServiceImpl) ListCurrentStock(ctx context.Context, req *dto.Li // 1. 获取分页的原料列表 rawMatOpts := repository.RawMaterialListOptions{ - Name: req.RawMaterialName, - OrderBy: req.OrderBy, // 注意:这里的排序可能需要调整,比如按原料名排序 + Name: req.RawMaterialName, + OrderBy: req.OrderBy, // 注意:这里的排序可能需要调整,比如按原料名排序 + HasStock: req.HasStock, } rawMaterials, total, err := s.rawMatRepo.ListRawMaterials(serviceCtx, rawMatOpts, req.Page, req.PageSize) if err != nil { diff --git a/internal/infra/repository/raw_material_repository.go b/internal/infra/repository/raw_material_repository.go index 3e63cbc..78d6d71 100644 --- a/internal/infra/repository/raw_material_repository.go +++ b/internal/infra/repository/raw_material_repository.go @@ -18,6 +18,7 @@ type RawMaterialListOptions struct { NutrientName *string MinReferencePrice *float32 // 参考价格最小值 MaxReferencePrice *float32 // 参考价格最大值 + HasStock *bool // 是否只查询有库存的原料 OrderBy string } @@ -122,6 +123,22 @@ func (r *gormRawMaterialRepository) ListRawMaterials(ctx context.Context, opts R db = db.Where("reference_price <= ?", *opts.MaxReferencePrice) } + // 筛选有库存的原料 + if opts.HasStock != nil && *opts.HasStock { + // 内部子查询:生成带有 rn 的结果集,GORM 会自动为 models.RawMaterialStockLog 添加 deleted_at IS NULL + rankedLogsQuery := r.db.Model(&models.RawMaterialStockLog{}). + Select("raw_material_id, after_quantity, ROW_NUMBER() OVER(PARTITION BY raw_material_id ORDER BY happened_at DESC, id DESC) as rn") + + // 外部子查询:从 ranked_logs 中筛选 rn=1 且 after_quantity > 0 的 raw_material_id + // GORM 会将 rankedLogsQuery 作为一个子查询嵌入到 FROM 子句中 + latestStockLogSubQuery := r.db.Table("(?) as ranked_logs", rankedLogsQuery). + Select("raw_material_id"). + Where("rn = 1 AND after_quantity > 0") + + // 将这个子查询直接应用到主查询的 WHERE id IN (?) 条件中 + db = db.Where("id IN (?)", latestStockLogSubQuery) + } + // 首先计算总数 if err := db.Count(&total).Error; err != nil { return nil, 0, err diff --git a/project_structure.txt b/project_structure.txt index 5ef3c45..0dd433a 100644 --- a/project_structure.txt +++ b/project_structure.txt @@ -145,6 +145,9 @@ internal/domain/task/task.go internal/infra/config/config.go internal/infra/database/postgres.go internal/infra/database/seeder.go +internal/infra/database/seeder/nutrient_seeder.go +internal/infra/database/seeder/pig_nutrient_requirement_seeder.go +internal/infra/database/seeder/utils.go internal/infra/database/storage.go internal/infra/logs/context.go internal/infra/logs/encoder.go