# 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 明确报错。