# 主数据同步功能说明


## 功能概述

主数据同步由“分类同步 + 物料同步”两条独立链路组成：

1. 分类同步：从 `mdm_wlfl_code` 全量拉取 `01 / 0101 / 010101` 结构的编码，生成 BSE 三层分类。
2. 物料同步：从 `mdm_material_view` 拉取物料主数据，依赖已存在的分类信息完成入库。
3. 物料同步会维护物料与分类绑定关系，并将非主表字段落入属性表。
4. 同步结束后可选地向外部回调推送执行报告。

## 同步入口

### 分类同步接口

- **接口地址**：`POST /base/master-data-sync/categories`
- **权限点**：`base:master-data-sync:categories`
- **请求体**：无（全量同步）
- **返回体**：`MasterDataCategorySyncReport`

字段说明：

- `processedCategories`：本次遍历的分类数量。
- `insertedCategories` / `updatedCategories`：新增或更新的分类记录数。
- `missingParentReferences`：外部数据缺失父级时的降级次数（会挂到根节点）。
- `success`、`message`、`startedAt`、`finishedAt`：同物料同步。

> ⚠️ 分类同步需先于物料同步执行，确保 BSE 中已存在三层分类结构。

### 物料同步接口

- **接口地址**：`POST /base/master-data-sync/execute`
- **权限点**：`base:master-data-sync:execute`
- **请求体**：

   | 字段 | 类型 | 说明 |
  | --- | --- | --- |
  | `since` | `yyyy-MM-dd HH:mm:ss` | （可选）增量同步起始时间，空值表示全量。 |
  | `batchSize` | `Integer` | （可选）单批拉取条数，未填写则使用配置默认值。 |
  | `materialCodes` | `List<String>` | （可选）限定仅同步指定物料编码，留空同步全部。 |
   | `recordLimit` | `Long` | （可选）本次同步允许处理的最大记录数，留空则不做总量限制。 |

**返回体**为 `MasterDataSyncReport`，涵盖以下关键指标：

- `processedRecords`：拉取并处理的记录数。
- `insertedMaterials` / `updatedMaterials`：新增或更新的物料数量。
- `createdClassRelations` / `updatedClassRelations`：物料与分类的关系处理次数。
- `insertedPropertyDefinitions` / `updatedPropertyDefinitions`：属性定义的补齐情况。
- `insertedPropertyValues` / `updatedPropertyValues`：属性值的写入情况。
- `success` + `message`：执行状态及提示语。
- `startedAt` / `finishedAt`：执行起止时间。
- `recordLimit`：若请求指定了总量限制，会在报告中回显该值。

## 数据处理策略

1. **属性字典**：
   - 程序会检查 `MasterDataPropertyDefinition` 枚举列出的全部属性（例如类别编码、规格、材质等）。
   - 若属性定义不存在即创建，存在但名称/排序有差异会自动更新。
2. **分类管理**：
   - 通过分类同步接口预先写入 `01/0101/010101` 三层数据，物料同步阶段仅检查并使用现有分类，如缺失则记录日志并跳过绑定。
3. **物料主体**：
   - 按 `material_code` 进行 upsert，保留基础字段（物料编码、通用信息等）。
4. **分类绑定**：
   - 若物料已有绑定但分类变化，则更新关系；否则创建新绑定。
5. **属性值写入**：
   - 对比新旧值，仅在有变化或缺失时写入，避免无效更新。

## 配置项

在 `application-*.yml` 中通过 `base.master-data-sync` 节点进行控制：

```yaml
base:
  master-data-sync:
    enabled: true                    # 是否开放同步入口
    batch-size: 500                  # 默认批量大小
    source-datasource-name: mdm      # 指向外部 MDM 的动态数据源
    notify-on-success: true          # 成功时是否回调
    notify-on-failure: true          # 失败时是否回调
    callback-url: http://example/callback
    callback-headers:
      X-TOKEN: xxx
    http:
      connect-timeout: 5s
      read-timeout: 30s
      write-timeout: 30s
```

> ⚠️ 请确保在 `datasource.dynamic` 中配置名为 `mdm`（或 `source-datasource-name` 指定值）的数据源，并指向外部 MDM 数据库。

## 数据源说明

- `master`：默认业务库（BSE 表所在库），所有增删改依旧走 `master` 数据源，这部分无需额外配置。
- `mdm`：主数据来源库（外部 MySQL）。`MdmMaterialViewMapper`、`MdmMaterialCategoryMapper` 均通过 `@DS("mdm")` 读取该库。
- `base.master-data-sync.source-datasource-name`：若外部库名称不是 `mdm`，可在此覆盖，示例：

   ```yaml
   base:
      master-data-sync:
         source-datasource-name: mdm
   datasource:
      dynamic:
         datasource:
            master: { ...本地库配置... }
            mdm: { url: jdbc:mysql://mdm-host/mdm, username: xxx, password: yyy }
   ```

> ✅ 强调：主数据读取始终走 `mdm`（或你在 `source-datasource-name` 中声明的别名），不要与默认 `master` 数据源混淆。

## 回调机制

- 当配置了 `callbackUrl` 时，系统会在同步结束后推送 JSON 结果。
- 推送内容为：

```json
{
  "report": { ...MasterDataSyncReport... },
  "errorMessage": "可选的错误提示"
}
```

- 仅成功/失败分别受 `notifyOnSuccess`、`notifyOnFailure` 控制。
- `callbackHeaders` 支持附加认证信息，如 Token、租户标识等。

## 常见问题排查

| 问题 | 检查点 |
| --- | --- |
| 数据源连接失败 | 确认 `mdm` 数据源配置、账号权限、网络可达性。 |
| 同步后未触发回调 | 检查 `callbackUrl`、`notify-on-*` 配置，以及目标地址是否可达。 |
| 属性值未生效 | 查看 `MasterDataPropertyDefinition` 是否包含该字段，或字段值是否为空/仅有空格。 |
| 只需同步单个物料 | 调用接口时在 `materialCodes` 中传入目标编码即可。 |

## 建议的使用流程

1. 配置并验证外部数据源与 `base.master-data-sync` 参数。
2. 先执行“分类同步接口”，确认三层分类齐全。
3. 再执行“物料同步接口”，并确认报表数据、回调通知。
4. 线上场景可定期以 `since` 参数驱动增量物料同步，也可按需指定 `materialCodes` 触发刷新；分类若有改动，可重新全量执行一次分类同步。
