# BD_Manual：store_goods_master（门店商品档案）

> ODS 表：`ods.store_goods_master`
> DWD 表：`dwd.dim_store_goods`（主表）、`dwd.dim_store_goods_ex`（扩展表）
> API 接口：门店商品列表
> JSON 路径：`store_goods_master.json → data.orderGoodsList`
> 装载方式：SCD2 维度合并（`DwdLoadTask`）
> 代码位置：`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`

---

## 1. dim_store_goods（主表）

| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|----------|------|---------|---------|---------|-------------|
| `site_goods_id` | BIGINT | `id` | FACT_MAPPINGS | 门店商品唯一标识（PK 之一） | 飞球雪花 ID |
| `tenant_id` | BIGINT | `tenant_id` | 自动映射 | 租户 ID | 飞球租户 ID |
| `site_id` | BIGINT | `site_id` | 自动映射 | 门店 ID | 飞球门店 ID |
| `tenant_goods_id` | BIGINT | `tenant_goods_id` | 自动映射 | 租户商品 ID，关联 `dim_tenant_goods` | 飞球商品 ID |
| `goods_name` | TEXT | `goods_name` | 自动映射 | 商品名称 | 如 `百威啤酒` |
| `goods_category_id` | BIGINT | `goods_category_id` | 自动映射 | 一级分类 ID | 飞球分类 ID |
| `goods_second_category_id` | BIGINT | `goods_second_category_id` | 自动映射 | 二级分类 ID | 飞球分类 ID |
| `category_level1_name` | TEXT | `onecategoryname` | FACT_MAPPINGS | 一级分类名称 | 如 `酒水` |
| `category_level2_name` | TEXT | `twocategoryname` | FACT_MAPPINGS | 二级分类名称 | 如 `啤酒` |
| `batch_stock_qty` | INTEGER | `batch_stock_quantity` | FACT_MAPPINGS | 批次库存数量（按批次管理的库存）。⚠️ 2026-02-20 修正映射源（原错误映射自 `stock`，即当前库存） | 数值 |
| `sale_qty` | INTEGER | `sale_num` | FACT_MAPPINGS | 累计销售数量 | 数值 |
| `total_sales_qty` | INTEGER | `total_sales` | FACT_MAPPINGS | 累计销售总额 | 数值 |
| `sale_price` | NUMERIC(18,2) | `sale_price` | 自动映射 | 商品售价（元） | 金额值 |
| `created_at` | TIMESTAMPTZ | `create_time` | FACT_MAPPINGS | 商品创建时间 | ISO 时间戳 |
| `updated_at` | TIMESTAMPTZ | `update_time` | FACT_MAPPINGS | 商品最后更新时间 | ISO 时间戳 |
| `avg_monthly_sales` | NUMERIC(18,4) | `average_monthly_sales` | FACT_MAPPINGS | 月均销量 | 数值 |
| `goods_state` | INTEGER | `goods_state` | 自动映射 | 商品状态 | 枚举值 |
| `enable_status` | INTEGER | `enable_status` | 自动映射 | 启用状态 | 枚举值 |
| `send_state` | INTEGER | `send_state` | 自动映射 | 配送状态 | 枚举值 |
| `is_delete` | INTEGER | `is_delete` | 自动映射 | 是否已删除：0=正常，1=已删除 | `0` / `1` |
| `commodity_code` | TEXT | `commodity_code` | FACT_MAPPINGS | 商品编码 | 编码字符串 |
| `not_sale` | INTEGER | `not_sale` | FACT_MAPPINGS | 是否停售：0=在售，1=停售 | `0` / `1` |
| `scd2_*` | — | — | DWD 元数据 | SCD2 慢变维度追踪字段 | — |

---

## 2. dim_store_goods_ex（扩展表）

| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|----------|------|---------|---------|---------|-------------|
| `site_goods_id` | BIGINT | `id` | FACT_MAPPINGS | 门店商品唯一标识（PK 之一） | 同主表 |
| `site_name` | TEXT | `sitename` | FACT_MAPPINGS | 门店名称快照 | 如 `朗朗桌球` |
| `unit` | TEXT | `unit` | 自动映射 | 计量单位 | 如 `瓶`、`包` |
| `goods_barcode` | TEXT | `goods_bar_code` | FACT_MAPPINGS | 商品条码 | 条码字符串或 NULL |
| `goods_cover_url` | TEXT | `goods_cover` | FACT_MAPPINGS | 商品封面图 URL | HTTPS 链接或 NULL |
| `pinyin_initial` | TEXT | `pinyin_initial` | 自动映射 | 拼音首字母（用于搜索） | 如 `BWPJ` |
| `stock_qty` | INTEGER | `stock` | FACT_MAPPINGS | 当前库存数量（实时库存） | 数值 |
| `stock_secondary_qty` | INTEGER | `stock_a` | FACT_MAPPINGS | 辅助单位库存数量（双单位商品） | 数值 |
| `safety_stock_qty` | INTEGER | `safe_stock` | FACT_MAPPINGS | 安全库存数量（低于此值触发预警） | 数值 |
| `cost_price` | NUMERIC(18,4) | `cost_price` | 自动映射 | 成本价（元） | 金额值 |
| `cost_price_type` | INTEGER | `cost_price_type` | 自动映射 | 成本价类型 | 枚举值 |
| `provisional_total_cost` | NUMERIC(18,2) | `provisional_total_cost` | FACT_MAPPINGS | 暂估总成本（元），按暂估价计算的库存成本。⚠️ 2026-02-20 修正映射源（原错误映射自 `total_purchase_cost`，即实际采购成本） | 金额值 |
| `total_purchase_cost` | NUMERIC(18,2) | `total_purchase_cost` | 自动映射 | 实际采购总成本（元） | 金额值 |
| `min_discount_price` | NUMERIC(18,2) | `min_discount_price` | 自动映射 | 最低折扣价（元） | 金额值 |
| `is_discountable` | INTEGER | `able_discount` | FACT_MAPPINGS | 是否可打折：0=不可，1=可 | `0` / `1` |
| `days_on_shelf` | INTEGER | `days_available` | FACT_MAPPINGS | 上架天数 | 正整数 |
| `audit_status` | INTEGER | `audit_status` | 自动映射 | 审核状态 | 枚举值 |
| `sale_channel` | INTEGER | `sale_channel` | 自动映射 | 销售渠道 | 枚举值 |
| `is_warehousing` | INTEGER | `is_warehousing` | 自动映射 | 是否入库管理：0=否，1=是 | `0` / `1` |
| `freeze_status` | INTEGER | `freeze` | FACT_MAPPINGS | 冻结状态：0=正常，1=冻结 | `0` / `1` |
| `forbid_sell_status` | INTEGER | `forbid_sell_status` | 自动映射 | 禁售状态 | 枚举值 |
| `able_site_transfer` | INTEGER | `able_site_transfer` | 自动映射 | 是否允许门店间调拨：0=否，1=是 | `0` / `1` |
| `custom_label_type` | INTEGER | `custom_label_type` | 自动映射 | 自定义标签类型 | 枚举值 |
| `option_required` | INTEGER | `option_required` | 自动映射 | 是否必选规格：0=否，1=是 | `0` / `1` |
| `remark` | TEXT | `remark` | FACT_MAPPINGS | 商品备注 | 自由文本或 NULL |
| `sort_order` | INTEGER | `sort` | FACT_MAPPINGS | 排序序号 | 正整数 |
| `batch_stock_quantity` | NUMERIC | `batch_stock_quantity` | 自动映射 | 批次库存数量（冗余，与主表 `batch_stock_qty` 同源） | 数值 |
| `time_slot_sale` | INTEGER | `time_slot_sale` | FACT_MAPPINGS | 分时段销售标记（当前观测全部为 2）。2026-02-21 新增 | `2` |
| `scd2_*` | — | — | DWD 元数据 | SCD2 慢变维度追踪字段 | — |

---

## 3. 映射修正记录

| 日期 | 字段 | 修正内容 |
|------|------|---------|
| 2026-02-20 | `batch_stock_qty` | ODS 源从 `stock`（当前库存）修正为 `batch_stock_quantity`（批次库存）。验证：仅 7.3% 行两列值相等 |
| 2026-02-20 | `provisional_total_cost` | ODS 源从 `total_purchase_cost`（实际采购成本）修正为 `provisional_total_cost`（暂估成本）。验证：93.5% 行相等但 113 行不同 |
| 2026-02-21 | `time_slot_sale` | 新增字段。ODS `ods.store_goods_master` + DWD `dwd.dim_store_goods_ex` 同步新增 `time_slot_sale INTEGER`。API 返回值当前全部为 `2` |

---

## 4. 跳过字段说明

| ODS 字段 | 跳过原因 |
|---------|---------|
| ~~`time_slot_sale`~~ | ~~ODS 列不存在~~ → 2026-02-21 已新增，见映射修正记录 |
| `goodsStockWarningInfo` | JSONB 嵌套对象，展开不在本次范围内 |

---

## 5. 代码引用

- FACT_MAPPINGS：`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dim_store_goods"]` / `FACT_MAPPINGS["dwd.dim_store_goods_ex"]`
- TABLE_MAP：`"dwd.dim_store_goods" → "ods.store_goods_master"`
- DWS 下游：`dws_finance_daily_task.py`（财务日报，商品维度关联）
- 迁移脚本：`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-20__fix_store_goods_master_mapping.sql`（已归档）
- 迁移脚本：`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-21__add_time_slot_sale_merge_commodity_code.sql`（已归档）
