初始提交:飞球 ETL 系统全量代码

This commit is contained in:
Neo
2026-02-13 08:05:34 +08:00
commit 3c51f5485d
441 changed files with 117631 additions and 0 deletions

View File

@@ -0,0 +1,547 @@
# 库存汇总报表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 或负数:
036次、-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导出那一刻的库存快照。
二者不一定相等(有部分记录存在差 14 的差值),说明结构上清晰区分了查询区间和当前状态。
汇总粒度清晰:每个 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和时间条件构成一套“明细汇总维度”相互嵌套的结构这对于后续做数据迁移、数据仓库建模或者跨系统字段映射都比较有价值。