# 合同管理 — 03 DDL 差异清单(步骤 4/5) > **日期**:2026-05-31 > **对比源**:CRM 权威 `docs/sql/sx.sql` vs 门户基线 `docs/sql/shanxia2.0.sql` > **增量脚本**:`docs/sql/incremental_crm_contract_rewrite.sql` > **ORM**:`backend/app/models/crm_models.py`(步骤 15+ 须同步 `CrmContractProductPriceTier`) --- ## 1. 表级差异总览 | 表 | sx.sql (CRM) | shanxia2.0.sql | 结论 | |----|--------------|----------------|------| | `crm_contract` | ✅ | ✅ | 业务字段基本齐全;**缺部分列表索引** | | `crm_contract_approval` | ✅ | ✅ | 已按门户公共字段对齐 | | `crm_contract_change` | ✅ | ✅ | 已对齐 | | `crm_contract_product` | ✅ | ✅ | 已对齐(无 `version`,可接受) | | `crm_contract_template` | ✅ | ✅ | 门户 `uk_template_no` 含 `tenant_no`,更合理 | | `crm_contract_product_price_tier` | ✅ | ❌ **整表缺失** | **必须新建**(框架合同提交审批) | 共 **6** 张合同相关表;门户缺 **1** 张整表。 --- ## 2. 门户 vs CRM 建模约定(不需改回 CRM) 移植 Python 时 **保持门户约定**,不做 bigint 回退: | 维度 | CRM (`sx.sql`) | 门户 (`shanxia2.0.sql`) | |------|----------------|---------------------------| | 主键 | `bigint AUTO_INCREMENT` | `varchar(64)` UUID | | 租户 | `tenant_id` varchar(20) | `tenant_no` varchar(64) | | 部门 | `create_dept` bigint | `create_dept_id` varchar(64) | | 乐观锁 | `version` int | `version_no` int(仅 `crm_contract`) | | 公共字段 | 无 `order_num` | `order_num` + 标准审计字段 | | 软删 | `del_flag` tinyint | `del_flag` smallint | 外键 ID 列在门户均为 `varchar(64)`,与 Java `Long` 不同 — API 层用 string 传输。 --- ## 3. `crm_contract` 字段对比 ### 3.1 业务字段 | 字段 | sx | shanxia2.0 | 说明 | |------|----|------------|------| | 主体/金额/日期/状态/甲乙方/模板/供方/结算 | ✅ | ✅ | 已对齐 | | `template_content` | longtext | longtext | ✅ | | `settlement_clause_drafts` | longtext | longtext | ✅ | | `supplier_id` | bigint | varchar(64) | ✅ 类型差异见 §2 | | `attachment_files` | varchar(1000) | varchar(2000) | 门户更大,保留 | | `owner_user_id` | NOT NULL | nullable | 门户允许空;Java 新增时会填当前用户 | | `remark` | varchar(500) | varchar(512) | 细微差异,保留门户 | **sx 与门户均无**(前端 VO 有、Java 可能写 remark):`execute_start_date`、`expected_end_date`、`actual_end_date`、`execute_remark`、`complete_remark`、`invalid_remark` — 当前 **不落库** 或走 `remark`;重写后端时与 Java 行为一致即可(Java ServiceImpl 的 finish/start 主要改 status)。 ### 3.2 索引差异(门户缺失 → 建议补) | 索引 | sx | shanxia2.0 | 用途 | |------|----|------------|------| | `uk_contract_no_del_flag` (contract_no, del_flag) | ✅ | ❌ | 编号唯一(门户应加 **tenant_no**) | | `idx_owner_user_id` | ✅ | ❌ | Tab「我的合同」 | | `idx_status` | ✅ | ❌ | Tab executing/finished/invalid | | `idx_sign_date` | ✅ | ❌ | 签订日期筛选 | | `idx_end_date` | ✅ | ❌ | 到期提醒 C21 | | `idx_create_time` | ✅ | ❌ | 默认排序 create_time DESC | 门户已有:`idx_customer_id`、`idx_tenant`、`idx_opportunity_id`、`idx_quote_id`、`idx_supplier_id`、`idx_parent_contract_id`、`idx_approval_status`、`idx_performance_status`、`idx_contract_nature`。 --- ## 4. `crm_contract_approval` | 项 | sx | shanxia2.0 | |----|----|------------| | 审批字段 step/result/is_current 等 | ✅ | ✅ | | `version` | ✅ | ❌ | 非必须 | | 索引 | 与门户一致 | ✅ | | **无需 ALTER**(表已存在且满足 §10 审批流)。 --- ## 5. `crm_contract_product` | 项 | sx | shanxia2.0 | |----|----|------------| | 产品/交付字段 | ✅ | ✅ | | `idx_delivery_status` | ✅ | ✅ | | `version` | ✅ | ❌ | 可接受 | **无需 ALTER**。 --- ## 6. `crm_contract_change` / `crm_contract_template` 与 sx 业务字段一致;门户已含 `tenant_no` + 公共字段。模板表唯一键门户为 `(template_no, tenant_no)`,优于 sx 单字段唯一。 **无需 ALTER**。 --- ## 7. `crm_contract_product_price_tier`(缺失 — 阻塞框架合同) ### sx 最终结构(含 CRM 增量脚本) | 字段 | 类型 | 说明 | |------|------|------| | `id` | bigint → **门户 varchar(64)** | 主键 | | `contract_id` | FK 合同 | | | `contract_product_id` | FK 合同产品 | | | `start_date` / `end_date` | date | 调价区间 | | `price` | decimal(15,2) | 含税单价 | | `letter_oss_ids` | varchar(4000) | JSON 数组,**多张调价函** | | `letter_oss_id` | bigint nullable | 废弃字段,兼容只读 | | `sort` | int | | | + 门户公共字段 | | `tenant_no`…`del_flag` | Java `validateFrameworkContractForSubmitApproval` 校验 **letter_oss_ids**(见 `02-business-logic.md` §10.5)。 ### ORM 状态 `crm_models.py` **尚无** `CrmContractProductPriceTier` — 步骤 15 与 DDL 同步新增。 --- ## 8. 增量脚本内容摘要 文件:`docs/sql/incremental_crm_contract_rewrite.sql` | 序号 | 操作 | |------|------| | S1 | `CREATE TABLE crm_contract_product_price_tier`(门户字段规范) | | S2 | `crm_contract` 补索引:`idx_status`、`idx_owner_user_id`、`idx_sign_date`、`idx_end_date`、`idx_create_time` | | S3 | `crm_contract` 唯一约束:`uk_contract_tenant_no (contract_no, tenant_no)` — 租户内全局唯一(含软删不复用);历史曾为 `uk_contract_tenant_no_del` | **执行顺序**:测试库手动执行 → 验证 → 步骤 15 更新 ORM → 后端实现 tier CRUD。 --- ## 9. 部署检查清单 - [ ] 在目标库执行 `incremental_crm_contract_rewrite.sql` - [ ] 确认 `SHOW INDEX FROM crm_contract` 含 §3.2 索引 - [ ] 确认 `crm_contract_product_price_tier` 存在 - [ ] 更新 `shanxia2.0.sql` 全量快照(可选,下次全量导出时合并) - [ ] `crm_models.py` 增加 `CrmContractProductPriceTier`(步骤 15) --- ## 变更记录 | 日期 | 说明 | |------|------| | 2026-05-31 | 步骤 4/5:sx vs shanxia2.0 六表对比 + 增量 SQL |