# 商品分类树（QueryPrimarySecondaryCategory） → stock_goods_category_tree 字段映射

> 生成时间：2026-02-14

## 端点信息

| 属性 | 值 |
|------|-----|
| 接口路径 | `TenantGoodsCategory/QueryPrimarySecondaryCategory` |
| 请求方法 | POST |
| ODS 对应表 | `ods.stock_goods_category_tree` |
| JSON 数据路径 | `data.goodsCategoryList` |

## 字段映射

| JSON 字段 | ODS 列名 | 类型转换 | 说明 |
|-----------|----------|----------|------|
| id | id | int→BIGINT（`parse_int`） | 分类节点主键 ID（在商品分类维度中的唯一标识） |
| tenant_id | tenant_id | int→BIGINT（`parse_int`） | 租户 ID（品牌/商户 ID） |
| category_name | category_name | string→TEXT（原样） | 分类名称（实际业务分类名称） |
| alias_name | alias_name | string→TEXT（原样） | 名称字段，用于展示与辅助识别 |
| pid | pid | int→BIGINT（`parse_int`） | 父级分类 ID |
| business_name | business_name | string→TEXT（原样） | 业务大类名称 |
| tenant_goods_business_id | tenant_goods_business_id | int→BIGINT（`parse_int`） | 业务大类 ID |
| open_salesman | open_salesman | int→INT（`parse_int`） | 是否启用“营业员”或“导购提成”相关的功能开关 |
| categoryBoxes | categoryBoxes | object→JSONB（原样存储） | 子分类数组 |
| sort | sort | int→INT（`parse_int`） | 分类的排序序号，用于前端展示顺序的控制 |
| is_warehousing | is_warehousing | int→INT（`parse_int`） | 本文件可视为“所有参与库存管理的商品分类清单”，因此均为 1 |

## ETL 补充字段

| ODS 列名 | 生成逻辑 |
|-----------|----------|
| content_hash | 对业务字段（排除 ETL 元数据列）计算 SHA-256，用于变更检测与去重 |
| source_file | 固定值：`stock_goods_category_tree.json`，标识原始导出文件 |
| source_endpoint | API 端点路径，如 `TenantGoodsCategory/QueryPrimarySecondaryCategory` |
| fetched_at | ETL 入库时间戳（`TIMESTAMPTZ DEFAULT now()`） |
| payload | 完整原始 JSON 记录快照（`JSONB NOT NULL`），用于回溯与二次解析 |

## 类型转换规则

- **时间戳**：通过 `TypeParser.parse_timestamp()` 转换，支持 ISO 字符串和 Unix 毫秒时间戳，自动处理时区
- **金额**：通过 `TypeParser.parse_decimal(value, scale=2)` 转换，`ROUND_HALF_UP` 四舍五入
- **整数**：通过 `TypeParser.parse_int()` 转换，`None` 保持为 `NULL`
- **字符串**：原样保留，`None` / 空字符串均存为 `NULL` 或空文本
- **布尔值**：API 返回 `true/false`，ODS 存为 `BOOLEAN` 或 `INT`（0/1）
- **JSONB**：`siteProfile`、`payload` 等复合对象直接以 `JSONB` 类型存储
