# BD_Manual：goods_stock_movements（库存变动流水）

> ODS 表：`ods.goods_stock_movements`
> DWD 表：`dwd.dwd_goods_stock_movement`（事实表，无 ex 扩展表）
> API 接口：库存变动记录列表
> JSON 路径：`goods_stock_movements.json → data.goodsStockList`
> 装载方式：事实表按 `create_time` 增量加载（`DwdLoadTask`）
> 代码位置：`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`

---

## 1. dwd_goods_stock_movement

| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|----------|------|---------|---------|---------|-------------|
| `site_goods_stock_id` | BIGINT | `sitegoodsstockid`（ODS 驼峰 → PG 小写） | FACT_MAPPINGS (cast bigint) | 库存变动记录唯一标识（PK） | 飞球雪花 ID |
| `tenant_id` | BIGINT | `tenantid` | FACT_MAPPINGS (cast bigint) | 租户 ID | 飞球租户 ID |
| `site_id` | BIGINT | `siteid` | FACT_MAPPINGS (cast bigint) | 门店 ID | 飞球门店 ID |
| `site_goods_id` | BIGINT | `sitegoodsid` | FACT_MAPPINGS (cast bigint) | 门店商品 ID，关联 `dim_store_goods.site_goods_id` | 飞球商品 ID |
| `goods_name` | TEXT | `goodsname` | FACT_MAPPINGS | 商品名称 | 如 `百威啤酒` |
| `goods_category_id` | BIGINT | `goodscategoryid` | FACT_MAPPINGS (cast bigint) | 一级商品分类 ID | 飞球分类 ID |
| `goods_second_category_id` | BIGINT | `goodssecondcategoryid` | FACT_MAPPINGS (cast bigint) | 二级商品分类 ID | 飞球分类 ID |
| `unit` | TEXT | `unit` | FACT_MAPPINGS | 计量单位 | 如 `瓶`、`包`、`张` |
| `price` | NUMERIC(18,4) | `price` | FACT_MAPPINGS (cast numeric) | 商品单价（元） | 金额值 |
| `stock_type` | INTEGER | `stocktype` | FACT_MAPPINGS (cast integer) | 库存变动类型枚举（详见下方枚举表） | `1`/`2`/`4`/`7`/`8`/`9` |
| `change_num` | NUMERIC(18,4) | `changenum` | FACT_MAPPINGS (cast numeric) | 变动数量（正数为增加，负数为减少） | 正/负数值 |
| `start_num` | NUMERIC(18,4) | `startnum` | FACT_MAPPINGS (cast numeric) | 变动前库存量 | `0.0000` ~ 正数 |
| `end_num` | NUMERIC(18,4) | `endnum` | FACT_MAPPINGS (cast numeric) | 变动后库存量 | `0.0000` ~ 正数 |
| `change_num_a` | NUMERIC(18,4) | `changenuma` | FACT_MAPPINGS (cast numeric) | 辅助单位变动量（用于双单位商品，如"箱→瓶"换算） | 数值或 0 |
| `start_num_a` | NUMERIC(18,4) | `startnuma` | FACT_MAPPINGS (cast numeric) | 辅助单位变动前库存 | 数值或 0 |
| `end_num_a` | NUMERIC(18,4) | `endnuma` | FACT_MAPPINGS (cast numeric) | 辅助单位变动后库存 | 数值或 0 |
| `remark` | TEXT | `remark` | FACT_MAPPINGS | 备注说明 | 如 `结账退货`、`采购退货`、`系统自动领用`，或 NULL |
| `operator_name` | TEXT | `operatorname` | FACT_MAPPINGS | 操作人姓名 | 姓名或 NULL |
| `create_time` | TIMESTAMPTZ | `createtime` | FACT_MAPPINGS (cast timestamptz) | 变动发生时间 | ISO 时间戳 |
| `fetched_at` | TIMESTAMPTZ | `fetched_at` | 自动映射 | ETL 采集时间戳 | ISO 时间戳 |

---

## 2. stock_type 枚举值详解

| stock_type | 含义 | 典型 remark | 数据量 |
|-----------|------|------------|--------|
| 1 | 销售出库 | NULL（系统自动扣减） | 29,573 条 |
| 2 | 采购入库 | NULL | 1,033 条 |
| 4 | 退货入库 | `结账退货` | 3,300 条 |
| 7 | 采购退货（出库） | `采购退货` | 33 条 |
| 8 | 领用出库 | `系统自动领用` | 1,033 条 |
| 9 | 领用退回（入库） | `系统自动领用退回` | 33 条 |

---

## 3. ODS 列名映射说明

ODS DDL 中列名使用驼峰式（如 `siteGoodsStockId`），PostgreSQL 在无引号时自动小写化。FACT_MAPPINGS 中使用带引号的 ODS 列名以正确引用。部分列（`unit`、`price`、`remark`）在 ODS 中已是小写，无需引号。

---

## 4. 代码引用

- FACT_MAPPINGS：`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dwd_goods_stock_movement"]`
- TABLE_MAP：`"dwd.dwd_goods_stock_movement" → "ods.goods_stock_movements"`
- DWS 下游：暂无直接 DWS 汇总（库存汇总基于 `dwd_goods_stock_summary`）
