# SKU Mapping 业务场景说明

> 创建日期：2026-04-16
> 适用模块：`skus_mapping`、`skus_origin`

---

## 一、业务模型概述

SKU Mapping 是 Datahub 系统中连接客户内部 SKU 体系与电商平台 SKU 体系的桥梁。由于不同平台对 SKU 编码有格式限制（如不能以 `0` 开头、不能包含特殊字符等），系统需要维护一套映射关系，将客户的原始 SKU（`origin_sku`）转换为符合各平台规范的平台 SKU（`platform_outer_sku`）。

**核心实体**：

| 实体 | 表 | 说明 |
|------|------|------|
| Origin SKU | `skus_origin` | 客户内部 SKU 编码，公司级唯一 |
| SKU Mapping | `skus_mapping` | origin_sku → platform_outer_sku 的映射记录 |
| Platform | `platforms` | 电商平台（Shopee、Tmall 等）|
| Store | `stores` | 平台下的具体店铺 |

**映射粒度**：店铺级别 — 同一平台下不同店铺可使用不同的 `platform_outer_sku`。

---

## 二、核心业务场景

### 场景 1：普通映射（1:1）

最基础的场景。一个 `origin_sku` 在一个平台下映射到一个 `platform_outer_sku`。

```
origin_sku: "0032"  →  platform_outer_sku: "C03_0032"  (Shopee)
```

**数据示例**：

| origin_sku_id | platform_id | platform_outer_sku | bundled |
|---------------|-------------|-------------------|---------|
| 1 | 1 (Shopee) | C03_0032 | false |

### 场景 2：多平台映射（1:N）

同一个 `origin_sku` 在多个平台分别生成不同的 `platform_outer_sku`。

```
origin_sku: "0032"
  → Shopee:  "C03_0032"
  → Tmall:   "TM_0032"
  → Lazada:  "LZ_0032"
```

**数据示例**：

| origin_sku_id | platform_id | platform_outer_sku | bundled |
|---------------|-------------|-------------------|---------|
| 1 | 1 (Shopee) | C03_0032 | false |
| 1 | 2 (Tmall) | TM_0032 | false |
| 1 | 3 (Lazada) | LZ_0032 | false |

### 场景 3：同平台多规则映射

同一个 `origin_sku` 在同一个平台下有多个不同的 `platform_outer_sku`（例如不同店铺使用不同编码）。

```
origin_sku: "0032"
  → Shopee 店铺A: "C03_0032"
  → Shopee 店铺B: "SP_CUSTOM_0032"
```

**数据示例**：

| origin_sku_id | platform_id | store_id | platform_outer_sku | bundled |
|---------------|-------------|----------|-------------------|---------|
| 1 | 1 (Shopee) | 101 | C03_0032 | false |
| 1 | 1 (Shopee) | 102 | SP_CUSTOM_0032 | false |

> 唯一索引 `(origin_sku_id, platform_id, platform_outer_sku)` 允许此场景，但防止同一组合产生重复记录。

### 场景 4：组合商品（Bundle）

一个 `platform_outer_sku` 实际对应多个 `origin_sku`，标记 `bundled = true`。典型场景：平台上的"套装"由多个单品组成。

```
platform_outer_sku: "BUNDLE_SUMMER"
  → origin_sku: "SHIRT_001"（上衣）
  → origin_sku: "PANTS_002"（裤子）
  → origin_sku: "HAT_003"（帽子）
```

**数据示例**：

| origin_sku_id | platform_id | platform_outer_sku | bundled |
|---------------|-------------|-------------------|---------|
| 10 (SHIRT) | 1 (Shopee) | BUNDLE_SUMMER | true |
| 11 (PANTS) | 1 (Shopee) | BUNDLE_SUMMER | true |
| 12 (HAT) | 1 (Shopee) | BUNDLE_SUMMER | true |

> 唯一索引允许不同 `origin_sku_id` 共享同一 `platform_outer_sku`，因为三元组 `(origin_sku_id, platform_id, platform_outer_sku)` 各不相同。

---

## 三、使用流程指南

### 3.1 创建映射

1. **选择公司** → 加载该公司下的 Origin SKU 列表
2. **选择 Origin SKU** → 系统自动填充 `origin_sku` 快照字段
3. **选择平台** → 选择目标店铺（可选）
4. **生成 platform_outer_sku**：
   - **前缀模式**：`{prefix}_{origin_sku}`，如 `C03_0032`
   - **前缀+随机模式**：`{prefix}_{random}`，如 `C03_A7K2`
   - **手动模式**：用户直接输入
5. **唯一性预检** → 系统检查 `(origin_sku_id, platform_id, platform_outer_sku)` 是否已存在
6. **重复提示** → 如果同一 origin_sku 在该平台已有映射，提示用户可复用
7. **提交创建**

### 3.2 自动生成逻辑

调用 `POST /api/v1/sku-mappings/generate-sku` 接口时：
- 根据策略参数生成 `platform_outer_sku`
- 同时执行重复检测，返回该 origin_sku 在目标平台下的已有映射
- 前端展示生成结果和重复提示，由用户确认后提交

### 3.3 组合商品处理

创建组合商品映射时：
1. 开启 `bundled` 开关
2. 输入统一的 `platform_outer_sku`（如 `BUNDLE_SUMMER`）
3. 为套装中的每个 origin_sku 分别创建一条映射记录，均使用相同的 `platform_outer_sku` 和 `bundled = true`
4. 查询时可通过 `bundled` 筛选快速定位组合商品映射

---

## 四、实体关系图

```
┌──────────┐     1:N      ┌──────────────┐
│ Company  │─────────────▶│  SkuOrigin   │
│          │              │  (skus_origin)│
└──────────┘              └──────┬───────┘
     │                           │
     │                    origin_sku_id (FK, NOT NULL)
     │                           │
     │   1:N    ┌────────────────▼────────────────┐
     ├─────────▶│          SkuMapping              │
     │          │        (skus_mapping)             │
     │          │                                   │
     │          │  UK: (origin_sku_id, platform_id, │
     │          │       platform_outer_sku)          │
     │          └──────┬──────────┬────────────────┘
     │                 │          │
     │          platform_id    store_id (nullable)
     │                 │          │
     │          ┌──────▼──┐  ┌───▼─────┐
     └─────────▶│Platform │  │  Store  │
                └─────────┘  └─────────┘

组合商品关系：
  SkuOrigin A ──┐
  SkuOrigin B ──┼──▶ 同一 platform_outer_sku (bundled=true)
  SkuOrigin C ──┘
```

---

## 五、注意事项与约束

### 5.1 唯一性约束

- **数据库级**：唯一索引 `uk_origin_platform_sku (origin_sku_id, platform_id, platform_outer_sku)` 确保数据一致性
- **应用级**：Controller 层在 store/update 时执行唯一性预检，返回友好的 422 错误而非数据库异常

### 5.2 必填字段

V2 改进后，以下字段为必填：
- `origin_sku_id`：必须关联有效的 Origin SKU 记录
- `platform_outer_sku`：映射记录必须包含平台编码

### 5.3 数据隔离

- 所有查询通过 `DataScope` 中间件按 `company_id` 隔离
- 跨公司数据不可见

### 5.4 组合商品限制

- 组合商品映射的 `bundled` 字段应统一为 `true`
- 创建组合商品映射时，前端应引导用户为每个组成 SKU 分别创建记录
- 删除组合商品映射时，建议提示用户是否一并删除同组的其他映射

### 5.5 Origin SKU 快照

`skus_mapping.origin_sku` 字段存储的是创建映射时从 `skus_origin.sku` 复制的快照值，用于：
- 即使 Origin SKU 被修改，历史映射记录仍保留原始编码
- 订单匹配时使用快照值进行比对
