# BD_Manual：DWS 库存汇总（日/周/月）

> DWS 表：`dws.dws_goods_stock_daily_summary`、`dws.dws_goods_stock_weekly_summary`、`dws.dws_goods_stock_monthly_summary`
> DWD 数据源：`dwd.dwd_goods_stock_summary`
> 任务代码：`DWS_GOODS_STOCK_DAILY`、`DWS_GOODS_STOCK_WEEKLY`、`DWS_GOODS_STOCK_MONTHLY`
> 代码位置：`apps/etl/connectors/feiqiu/tasks/dws/goods_stock_daily_task.py`、`goods_stock_weekly_task.py`、`goods_stock_monthly_task.py`
> DDL 位置：`docs/database/ddl/etl_feiqiu__dws.sql`
> 迁移脚本：`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-20__create_dws_goods_stock_summary.sql`（已归档）

---

## 1. 表结构（三张表结构相同）

| DWS 列名 | 类型 | 业务含义 | 取值范围/示例 |
|----------|------|---------|-------------|
| `site_id` | BIGINT | 门店 ID（PK 之一） | 飞球门店 ID |
| `tenant_id` | BIGINT | 租户 ID | 飞球租户 ID |
| `stat_date` | DATE | 统计日期（PK 之一）。日度=当天日期，周度=ISO 周一日期，月度=月首日期 | 如 `2026-01-15`、`2026-01-13`（周一）、`2026-01-01`（月首） |
| `site_goods_id` | BIGINT | 门店商品 ID（PK 之一），关联 `dim_store_goods.site_goods_id` | 飞球商品 ID |
| `goods_name` | TEXT | 商品名称 | 如 `百威啤酒` |
| `goods_unit` | TEXT | 计量单位 | 如 `瓶`、`包` |
| `goods_category_id` | BIGINT | 一级商品分类 ID | 飞球分类 ID |
| `goods_category_second_id` | BIGINT | 二级商品分类 ID | 飞球分类 ID |
| `category_name` | TEXT | 一级分类名称 | 如 `酒水` |
| `range_start_stock` | NUMERIC | 期初库存（统计周期起点的库存量） | 数值 |
| `range_end_stock` | NUMERIC | 期末库存（统计周期终点的库存量） | 数值 |
| `range_in` | NUMERIC | 入库数量（统计周期内的采购/调拨入库总量） | 数值 |
| `range_out` | NUMERIC | 出库数量（统计周期内的调拨出库/报损总量） | 数值 |
| `range_sale` | NUMERIC | 销售数量（统计周期内的销售出库总量） | 数值 |
| `range_sale_money` | NUMERIC(12,2) | 销售金额（元），统计周期内的销售总金额 | 金额值 |
| `range_inventory` | NUMERIC | 盘点调整量（统计周期内的盘盈/盘亏净量） | 正/负数值 |
| `current_stock` | NUMERIC | 当前库存（统计周期末的实时库存量） | 数值 |
| `stat_period` | TEXT | 汇总粒度标识 | `'daily'` / `'weekly'` / `'monthly'` |
| `created_at` | TIMESTAMPTZ | 记录创建时间 | 自动填充 `now()` |
| `updated_at` | TIMESTAMPTZ | 记录最后更新时间 | 自动填充 `now()` |

---

## 2. 主键

`(site_id, stat_date, site_goods_id)` — 按门店、日期、商品维度唯一。

---

## 3. 粒度说明

| 表名 | 粒度 | stat_date 规则 | stat_period |
|------|------|---------------|-------------|
| `dws_goods_stock_daily_summary` | 日 | 当天日期 | `'daily'` |
| `dws_goods_stock_weekly_summary` | 周 | ISO 周一日期 | `'weekly'` |
| `dws_goods_stock_monthly_summary` | 月 | 月首日期（如 `2026-01-01`） | `'monthly'` |

---

## 4. 聚合逻辑

- extract：从 `dwd.dwd_goods_stock_summary` 按时间范围查询
- transform：按粒度对 `fetched_at` 进行分组聚合
  - `range_start_stock`：取周期内最早记录的 `range_start_stock`
  - `range_end_stock`：取周期内最晚记录的 `range_end_stock`
  - `range_in` / `range_out` / `range_sale` / `range_inventory`：SUM 汇总
  - `range_sale_money`：SUM 汇总
  - `current_stock`：取周期内最晚记录的 `current_stock`
  - `goods_name` / `goods_unit` / `category_name`：取最晚记录的值
- load：upsert 写入目标表，主键冲突时更新

---

## 5. 前置依赖

- `dwd.dwd_goods_stock_summary` 表必须已创建并有数据
- ODS 任务配置 `requires_window=True` 必须已生效并重新采集

---

## 6. 代码引用

- 任务代码：`tasks/dws/goods_stock_daily_task.py`、`goods_stock_weekly_task.py`、`goods_stock_monthly_task.py`
- 继承：`BaseDwsTask`（`tasks/dws/base_dws_task.py`）
- 任务注册：`DWS_GOODS_STOCK_DAILY`、`DWS_GOODS_STOCK_WEEKLY`、`DWS_GOODS_STOCK_MONTHLY`
