# 库存汇总报表（GetGoodsStockReport）

> 自动生成于 2026-02-13 | 数据来源：实时 API

## 基本信息

| 属性 | 值 |
|------|-----|
| 接口路径 | `TenantGoods/GetGoodsStockReport` |
| 完整 URL | `https://pc.ficoo.vip/apiprod/admin/v1/TenantGoods/GetGoodsStockReport` |
| 请求方法 | `POST` |
| Content-Type | `application/json` |
| 鉴权方式 | Bearer Token（`Authorization` 头） |
| ODS 对应表 | `goods_stock_summary` |
| 分页方式 | `page` + `limit`（最大 100） |
| 时间范围 | 需要（startTime / endTime） |

## 请求参数

| 参数名 | 类型 | 示例值 | 说明 |
|--------|------|--------|------|
| `siteId` | int | `2790685415443269` | 门店 ID |
| `startTime` | string | `"2026-02-01 08:00:00"` | 查询起始时间 |
| `endTime` | string | `"2026-02-13 08:00:00"` | 查询结束时间 |
| `page` | int | `1` | 页码（从 1 开始） |
| `limit` | int | `100` | 每页条数（最大 100） |

## 响应字段（共 14 个）

| # | 字段名 | 类型 | 示例值 |
|---|--------|------|--------|
| 1 | `siteGoodsId` | int | 3089190204491141 |
| 2 | `goodsName` | string | '小合味道' |
| 3 | `goodsUnit` | string | '桶' |
| 4 | `goodsCategoryId` | int | 2791941988405125 |
| 5 | `goodsCategorySecondId` | int | 2793236829620037 |
| 6 | `rangeStartStock` | int | 0 |
| 7 | `rangeEndStock` | int | 22 |
| 8 | `rangeIn` | int | 24 |
| 9 | `rangeOut` | int | -2 |
| 10 | `rangeInventory` | int | 0 |
| 11 | `rangeSale` | int | 2 |
| 12 | `rangeSaleMoney` | float | 16.0 |
| 13 | `currentStock` | int | 22 |
| 14 | `categoryName` | string | '零食' |

## 详细字段分析

> 以下内容迁移自旧版 `goods_stock_summary-Analysis.md`，包含字段的业务含义、枚举值、跨表关联等详细说明。

每个元素就是某个 门店商品（siteGoodsId）在一个查询时间区间内的库存汇总。
二、字段分组说明（含类型 / 是否枚举 / 枚举值）
1. 商品主键与基本信息
1.1 siteGoodsId

类型：int

特征：

161 条记录中 161 个唯一值。

与 “门店商品档案” (20251110_051132_…1.json) 中 orderGoodsList 里的 id 完全一一对应。

含义：

门店商品 ID，本库存汇总表的主键，对应某个具体商品在本店的唯一标识。

关联：

库存汇总.siteGoodsId = 门店商品档案.id

也与库存变动记录（库存变化记录1）里的 siteGoodsId 对应（库存流水的外键）。

1.2 goodsName

类型：string

特征：

每条记录一个商品名，共 161 个不同值（与 siteGoodsId 一一对应）。

例："东方树叶", "红烧牛肉面", "薯片" 等。

含义：

商品名称，冗余于门店商品档案的 goods_name。

结构意义：

方便直接阅读汇总报表，无需再次联表取商品档案。

1.3 goodsUnit

类型：string

特征：

典型取值（枚举）：

"包"：59 条

"瓶"：46 条

"个"：17 条

"份"：13 条

"根"：10 条

"盒", "杯", "桶", "盘", "支" 等

与门店商品档案中的 unit 字段完全一致。

含义：

商品的计量单位（售卖单位）。

小结：siteGoodsId + goodsName + goodsUnit 在结构上确定一条“门店商品”的维度信息，和“门店商品档案”的字段是完全对齐的。

2. 分类维度字段
2.1 goodsCategoryId

类型：int

特征：

非空，161 条记录中有 9 个不同的 ID。

每一个 goodsCategoryId 对应 唯一一个 categoryName（一对一）。

含义：

一级商品分类 ID。

枚举映射（由数据直接推得）：

2791941988405125 → "零食"
2790683528350539 → "酒水"
2792062778003333 → "香烟"
2793217944864581 → "其他"
2791942087561093 → "雪糕"
2790683528350535 → "器材"
2793220945250117 → "小吃"
2790683528350533 → "槟榔"
2790683528350545 → "果盘"


（ID 是系统内部编码，你这边可以当“分类主键”。）

2.2 goodsCategorySecondId

类型：int

特征：

非空，有 14 个不同的 ID。

每个二级 ID 对应一个更细的类目（比如不同品牌/系列），但名称在本文件中没有给出。

含义：

二级（次级）商品分类 ID，是 goodsCategoryId 的下级分类。

关联：

在库存变动类 JSON / 商品分类 JSON（之前看到的分类导出）中，有完整的分类树，可通过这些 ID 找回二级分类名称。

2.3 categoryName

类型：string

特征：

枚举值恰好 9 个，分别是：

"零食", "酒水", "香烟", "其他", "雪糕", "器材", "小吃", "槟榔", "果盘"

与 goodsCategoryId 一一对应。

含义：

一级分类名称，属于冗余字段，用于直接展示。

结构结论：

分类主键：goodsCategoryId（一级）＋ goodsCategorySecondId（二级）

分类名称：categoryName 仅给了一级中文名，二级名需要到分类表/门店商品档案中再查。

3. 库存数量相关字段（全部为整数）
3.1 rangeStartStock

类型：int

特征：

非空，有 61 个不同数值。

示例值：0, 1, 2, 4, 7, 8, 29 ...

含义：

查询区间 起始时刻 的库存数量（期初库存）。

结构作用：

与下方各类“变动量”一起构成库存平衡公式。

3.2 rangeEndStock

类型：int

特征：

非空，有 61 个不同数值。

示例值： 0, 1, 5, 7, 8, 16 ...

含义：

查询区间 结束时刻 的库存数量（期末库存）。

3.3 rangeIn

类型：int

特征：

非空，多为正整数或 0。

示例值：0, 30, 90, 450 ...

含义：

查询区间内的 入库数量汇总（正值），包括采购入库、调拨入库等。

3.4 rangeOut

类型：int

特征：

有 64 个不同值，且全部为 0 或负数：

0（36次）、-1、-2、-3、-4、-7、-8、-14、-35 ……

含义：

查询区间内的 出库数量汇总，以 负数 表示从库存扣减（出库/销售）。

结构公式验证（关键）：

对每一条记录，都满足：

rangeStartStock + rangeIn + rangeInventory + rangeOut = rangeEndStock


即：期初 + 入库 + 盘点调整 + 出库 = 期末
当前数据中 rangeInventory 全为 0，那么简化为：
rangeStartStock + rangeIn + rangeOut = rangeEndStock。

3.5 rangeInventory

类型：int

特征：

所有 161 条记录均为 0。

含义：

查询区间内的 盘点调整净变动量（盘盈–盘亏）。

当前数据状态：

这段时间内没有发生盘点或盘点对库存无净影响，所以全为 0。

结构意义：

在有盘点的场景，这个字段会承担“非正常出入库”的调整职责，并参与上面的平衡公式。

3.6 currentStock

类型：int

特征：

非空，61 个不同值。

示例值：0, 1, 2, 3, 4, 5, 6, 7, 10, 14 ...

大部分记录里，currentStock 与 rangeEndStock 相等；但有 17 条 存在差异（通常是小差值，例如 rangeEndStock=74, currentStock=72）。

含义（推断）：

导出时刻的实时库存数量。

与 rangeEndStock 关系：

rangeEndStock 是“查询时间段结束瞬间”的库存；

currentStock 是“导出时当前瞬间”的库存。

这说明：在查询区间之后，可能又发生了一些出入库，导致当前库存与期末库存略有差异。

结构小结：

(rangeStartStock, rangeIn, rangeOut, rangeInventory, rangeEndStock) 构成一个严格的库存平衡关系。

currentStock 则是另一个时间点的库存快照，在结构上属于“附加状态字段”，不参与那个公式。

4. 销量与销售金额（汇总）
4.1 rangeSale

类型：int

特征：

非空，有 65 个不同的整数。

示例：0, 1, 2, 3, 4, 5, 6, 8, 13, 14 ...

含义：

查询区间内，该商品的 销售数量汇总（售出多少“包/瓶/份”等）。

与 rangeOut 的关系（结构上）：

对绝大多数以“销售出库”为主的商品，rangeOut 的绝对值与 rangeSale 大致一致（也可能有非销售出库，比如报损/调拨），这一点需要结合库存变动明细来判断，但属于业务层逻辑，这里不展开。

4.2 rangeSaleMoney

类型：float

特征：

非空，有 102 个不同的浮点值。

示例：0.0, 48.0, 30.0, 40.0, 280.0, 60.0, 50.0, 15.0 ...

很多数值看起来是整数金额，但用 float 存储，为以后兼容小数价格预留空间。

含义：

查询区间内，该商品销售的 金额小计（按商品维度汇总）。

结构特征（不做业绩解读，只谈结构）：

对于有销量的记录，可以通过简单比例验证：

单品成交单价 ≈ rangeSaleMoney / rangeSale


如某商品记录：

rangeSale = 62

rangeSaleMoney = 744.0

求比值 ≈ 12.0 → 对应门店商品档案中的 sale_price。

也就是说：在结构上，rangeSaleMoney 与 “汇总数量 × 单价” 对应关系非常一致，说明这个字段确实是商品维度的销售金额汇总。

这里我仅确认字段之间的 计量逻辑与结构关系，不做任何“好/坏”的业务评价。

三、与其它 JSON 的关联关系（结构层面）
1. 与“门店商品档案” JSON 的关系

通过实际比对：

库存汇总.siteGoodsId = 门店商品档案.orderGoodsList.id

库存汇总.goodsName = 门店商品档案.goods_name

库存汇总.goodsUnit = 门店商品档案.unit

库存汇总.goodsCategoryId = 门店商品档案.goods_category_id

库存汇总.goodsCategorySecondId = 门店商品档案.goods_second_category_id

结构含义：

门店商品档案：静态维度表，包含商品的售价、成本、是否计库存、分类名称等。

库存汇总：针对同一批 id 做的“某一时间范围内的库存+销量汇总”。

因此，你可以把“库存汇总”看成是对“门店商品档案”的一个衍生事实表，按照商品维度聚合库存与销售信息。

2. 与“库存变化记录”（库存流水）的关系

虽然你这份导出里“库存变化记录”在另外一个 JSON 中（字段里有 siteGoodsId、stockType 等），但从字段名和使用方式可以推断：

库存变化记录：

粒度：一条库存变动（一笔入库/出库/盘点等）。

重要字段：

siteGoodsId：对应库存汇总中的 siteGoodsId。

stockType：入库、出库、盘点等类型枚举。

changeNum：每次变动数量。

库存汇总：

粒度：某商品在查询区间内的汇总。

字段：rangeIn, rangeOut, rangeInventory 等就是对库存变化记录按 siteGoodsId + 时间区间 汇总出来的结果。

结构关系可以概括为：

库存变化记录（明细表）
    ↓ 按 siteGoodsId + 时间范围聚合
库存汇总（汇总表）


这使得你在需要追查明细时，可以从“汇总 → 明细”下钻。

3. 与“门店销售记录”的关系

从字段设计看：

门店销售记录中有：

site_goods_id：门店商品 ID

ledger_amount：单条销售明细金额

ledger_count：销售数量

库存汇总中有：

siteGoodsId：门店商品 ID

rangeSale：总销售数量（在时间范围内）

rangeSaleMoney：总销售金额（在时间范围内）

结构上可以理解为：

门店销售记录 是 每一个销售明细；

库存汇总 是在某时间段对这些明细按商品维度做的 汇总。

两者之间通过 siteGoodsId/site_goods_id 联接，同时需要根据时间条件约束订单时间，这一点在结构上是清晰的。

4. 与商品分类树（库存变化记录2 / 分类 JSON）的关系

在之前分类 JSON 中，你有一个分类树结构（有 id, pid, category_name, categoryBoxes 等）：

库存汇总.goodsCategoryId 对应 分类树中的某个一级分类 id。

库存汇总.goodsCategorySecondId 对应其子分类（分类树中某个 pid=一级分类id 的节点）。

categoryName 与分类树中的 category_name 对应（一级节点）。

结构关系：

分类树 JSON （全局分类维表）
     ↑          ↑
goodsCategoryId goodsCategorySecondId
     ↑          ↑
  库存汇总 （事实表）

四、结构层面可以注意的一些“关系和约束”

全部是字段设计/数值关系层面，不涉及盈利或经营分析：

库存平衡公式存在且逐条成立

对每一条记录，都可以验证：

rangeStartStock + rangeIn + rangeInventory + rangeOut = rangeEndStock


当前导出中 rangeInventory = 0，所以简化公式为：

rangeStartStock + rangeIn + rangeOut = rangeEndStock


严格成立说明：

系统在生成库存汇总时，确实是从明细出入库数据做了完整计算，而不是凭输入数据临时凑数。

出库量采用“负数”表示

rangeOut 不再定义为“出库数量（正数）”，而是直接记 负数。

好处是：公式中无需写“–出库量”，直接做代数求和。

这个习惯在后续做数据集成或迁移时需要注意，避免重复取绝对值/重复取负。

区分“期末库存”与“当前库存”两个时间点

rangeEndStock：查询时间段的期末库存。

currentStock：导出那一刻的库存快照。

二者不一定相等（有部分记录存在差 1–4 的差值），说明结构上清晰区分了查询区间和当前状态。

汇总粒度清晰：每个 siteGoodsId 仅一条记录

siteGoodsId 在本文件中不重复，说明这是按商品聚合后的汇总层，没有再分仓库、批次、货位等维度。

如果未来需要按仓/货位维度汇总，结构可能会出现类似 warehouseId 之类的新字段，从这份数据来看目前没有。

金额与数量之间存在一致的单价模式

对于 rangeSale > 0 的商品，rangeSaleMoney / rangeSale 与门店商品档案中的 sale_price 一致，这只是结构上的一致性检查：

说明 rangeSaleMoney 并不是某种复杂的计算结果，而是“销售数量 × 单价”的汇总。

这在系统设计上有利于做“金额与数量对账”。

分类 ID 与中文名称一一对应

goodsCategoryId 和 categoryName 的关系是一对一，没有出现“同一 categoryName 对应多 ID”的情况。

这说明在该门店中，一级分类的结构比较干净，没有重复创建多个 ID 对应相同名称的情况；对你的后续系统对接来说，这一层结构相对简单，只需要维护一套映射即可。

五、小结

20251110_043308_库存汇总.json 本质上是：

以 门店商品（siteGoodsId） 为粒度，

在某个查询时间范围内，对该商品的：

期初库存（rangeStartStock）

入库量（rangeIn）

出库量（rangeOut，负数）

盘点调整（rangeInventory）

期末库存（rangeEndStock）

销售数量（rangeSale）

销售金额（rangeSaleMoney）
做了一次结构化汇总；

同时给出了当前时点库存快照（currentStock），并冗余了商品名、单位、一级分类名等维度信息。

在全局数据模型里，它与 门店商品档案 / 库存变动明细 / 门店销售明细 / 分类树 等文件通过主键（siteGoodsId、分类 ID）和时间条件构成一套“明细–汇总–维度”相互嵌套的结构，这对于后续做数据迁移、数据仓库建模或者跨系统字段映射都比较有价值。
