# Contract 领域重构指南

## 1. 范围

本文档只做 Contract 领域的项目侧梳理。

当前优先关注：

- `contract.contract_type`
- `contract.code`
- `contract.currency`

## 2. 字段盘点

### 2.1 `contract_type`

当前实现：

- `app/modules/contract/enums.py` 定义了 `ContractType`
- 取值：`product`、`service`、`project`
- `Contract` 模型里是 `String`
- `ContractCreate` 里是 `str | None`
- 同步 schema `schemas/contract/contract.py` 里也是 `str`

当前使用：

- 是合同主表核心分类字段
- 合同结算服务里会按 `contract_type == "project"` 分支处理工程类合同

项目侧取值范围：

- `product`
- `service`
- `project`

集团侧差异：

- 集团侧 `enum_config.Contract.contract_type` 当前只有 `product`、`service`
- 项目侧比集团侧多一个 `project`
- 同步 schema 当前没有把它收紧成 enum

结论：

- 保留为代码 enum
- 先统一“是否正式保留 `project`”

### 2.2 `code`

当前实现：

- 模型里是普通 `String`
- 没有本地正式 enum
- 初始化侧实际依赖 `contract_config` / `contract_code_dict` / `supply_chain_group`

当前使用：

- 初始化合同时，`code` 承担业务子类型编码职责，例如 `EPC`、`PC`、`KY`、`JL`
- 不是单纯的“自由合同编号”

项目侧取值范围：

- 当前无法从单一代码 enum 列出权威全集
- 本地已明确出现的典型值包括：`EPC`、`PC`、`PF`、`CG`、`OSC`、`KY`、`JL`、`E`、`SCYW`、`ZJ`、`TY`、`NB`、`XB`、`ZB`、`GS`、`CN`、`QT`

集团侧差异：

- 集团侧 `enum_config.Contract.code` 已明确把这类值当成正式候选项，并且按项目类型变化
- 同步 schema 里的 `code` 仍是普通 `str`
- 项目侧现在没有把这组值沉成统一的字段配置或正式 enum

结论：

- 不建议继续当自由字符串处理
- 更适合迁到 `field_config`，或至少统一走配置表来源

### 2.3 `currency`

当前实现：

- 模型里是 `String`
- 默认值 `CNY`
- schema 里是普通字符串

当前使用：

- 当前主要是合同基础信息字段
- 没看到复杂分支逻辑

项目侧取值范围：

- 当前代码里唯一明确值是默认值 `CNY`

集团侧差异：

- 当前没看到集团侧 `enum_config` 对这个字段给出正式候选项
- 同步 schema 里也是 `str`

结论：

- 先保持字符串字段
- 如果未来真的出现多币种，再决定是否需要正式枚举

## 3. 重点结论

- `contract_type` 应保留为代码 enum，但要先明确是否保留 `project`。
- `code` 当前实际上承担合同业务子类型职责，不应继续当自由字符串处理。
- `currency` 当前没有足够证据说明要做枚举化。

## 4. 待修改项清单

1. 统一 `ContractType` 的正式定义源。
2. 确认 `contract_type=project` 是否继续作为正式值保留。
3. 为 `contract_type` 在 schema 层补 enum 校验。
4. 把 `contract.code` 从“自由字符串”改成统一配置来源。
5. 评估 `contract.code` 是否直接迁到 `field_config`。
6. 区分清楚 `contract.code` 与“合同编号/contract_sn”的职责，避免一个字段同时承担两层语义。

## 5. 按本轮要求的改造落点

contract 领域本轮要直接收口 3 条链路：

- 初始化
- create 校验
- 下拉列表

### 5.1 初始化

当前合同初始化已经走 `contract_config`。

因此这轮初始化改造的核心不是重做合同初始化，而是：

- 把 `contract.code` 明确成正式字段级配置来源
- 后续让合同初始化、物资初始化、前端下拉都围绕这套配置工作

`contract_type` 继续保留为代码 enum，不迁到 `field_config`。

### 5.2 Create 校验

当前 `ContractService.create()` 的校验主要依赖：

- `contarct_type_dict`
- `contract_code_dict`
- service / product 的硬编码白名单

这和初始化使用的 `contract_config` 不是同一真源。

本轮目标是：

- `contract_type` 继续按代码 enum 校验
- `contract.code` 改成通过新的 config 工具校验
- 避免继续新增 `if contract_type == ... and code in [...]` 这种硬编码白名单

### 5.3 下拉列表

当前合同下拉接口：

- `/contract/type/list`
- `/contract/sub-type/list`

其中：

- `type/list` 直接读代码字典
- `sub-type/list` 先写死过滤列表，再读代码字典

这和初始化 `contract_config` 不一致。

本轮目标是：

- 合同类型列表继续由代码 enum 提供
- 合同子类型列表改为动态读取 config
- 保证前端看到的 code 列表和初始化、create 校验同源

### 5.4 清理项

本轮 contract 领域改造完成后，应清理：

- 只用于 `contract.code` 下拉和校验的旧硬编码 code 白名单
- 只承担旧合同子类型翻译的代码字典入口

但下面这些不应误删：

- `ContractType` enum
- 其它真正稳定的固定语义 enum

## 6. 测试关注点

contract 领域 service 层集成测试至少覆盖：

1. 初始化：`contract_config` 能正确初始化合同，并继续驱动下游结算/物资链路。
2. 下拉：合同子类型下拉是否来自目标 config，且与初始化 code 集一致。
3. Create：合法 `contract_type + code` 创建成功，非法 code 明确报错。

