You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

300 lines
20 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 合同变更功能设计方案
## 一、需求理解(通俗说明)
- **谁能变更**:只有「已激活」的合同可以发起变更。即:合同状态=可用contract_status='3')且 激活标识=是active_flag='1')。
- **做什么**
1. 做一个「合同变更」列表页,风格和合同信息列表类似,能新增;点新增就跳到「合同变更申请」页。
2. 在「合同变更申请」页里先选一个合同,选完后把该合同的信息、物料等查出来填到页面,用户可修改后提交(暂存或走审批)。
3. 要能按合同查「合同变更历史」——某合同共发生过几次变更、每次变更单号、时间、状态、是否已回写等。
4. 变更审批通过后要把「变更后的内容」写回正式表合同表erp_contract_info、合同物料表erp_contract_material
下面按「表结构」和「业务逻辑」分开说,不写具体代码,只讲逻辑与 SQL 表结构。
---
## 二、表结构设计MySQL
思路:**一次变更 = 一张变更单 + 变更后的合同信息快照 + 变更后的物料快照**。
审批通过后,用快照表的数据去更新正式合同表、合同物料表,并标记「已回写」,便于查历史、防重复回写。
### 1. 合同变更主表erp_contract_change
存「一次变更申请」的公共信息,关联原合同。
| 字段名 | 类型 | 说明 |
| ------------------ | -------------- | --------------------------------------- |
| contract_change_id | bigint, PK, 自增 | 合同变更ID |
| tenant_id | varchar(20) | 租户编号 |
| contract_id | bigint | 原合同ID关联 erp_contract_info.contract_id |
| contract_code | varchar(64) | 原合同编号(冗余,列表展示用) |
| contract_name | varchar(255) | 原合同名称(冗余,列表展示用) |
| change_code | varchar(64) | 变更单编号HTBG-2025-001 |
| change_reason | varchar(500) | 变更原因 |
| change_status | varchar(32) | 变更状态1暂存 2审批中 3可用 |
| flow_status | varchar(32) | 流程状态(与工作流一致) |
| apply_time | datetime | 申请时间 |
| write_back_flag | char(1) | 是否已回写0否 1是 |
| write_back_time | datetime | 回写时间 |
| remark | varchar(255) | 备注 |
| active_flag | char(1) | 激活标识1是 0否 |
| del_flag | char(1) | 删除标志0存在 1删除 |
| create_dept | bigint | 创建部门 |
| create_by | bigint | 创建人 |
| create_time | datetime | 创建时间 |
| update_by | bigint | 更新人 |
| update_time | datetime | 更新时间 |
**说明**
- 列表页、历史记录都查这张表;按 contract_id 查即该合同的变更历史。
- write_back_flag 防止重复回写;只有 change_status='3'(可用)且流程通过后才执行回写并置为 1。
---
### 2. 合同变更信息快照表erp_contract_change_info
存「变更后的合同主信息」快照,字段与 erp_contract_info 对齐(去掉合同主键 contract_id改为关联变更单
- **主键**change_info_idbigint, 自增)。
- **关联**contract_change_idbigint关联 erp_contract_change.contract_change_id
- **其余字段**:与 erp_contract_info 一致(如 contract_code、contract_name、total_price、contract_date、contract_manager_id 等所有业务字段),但这里表示的是「变更后」要写回合同表的值。
- 公共字段tenant_id, remark, del_flag, create_dept, create_by, create_time, update_by, update_time。
**约束**一个变更单对应一条快照1:1。回写时用这条记录 UPDATE erp_contract_info SET ... WHERE contract_id = 主表中的 contract_id。
---
### 3. 合同变更物料快照表erp_contract_change_material
存「变更后的合同物料」快照,字段与 erp_contract_material 对齐。
- **主键**change_material_idbigint, 自增)。
- **关联**contract_change_idbigint不存 contract_id回写时再填原 contract_id
- **其余字段**:与 erp_contract_material 一致(如 material_flag, product_name, specification_description, material_id, amount, unit_id, before_price, tax_rate, including_price, subtotal, remark 等)。
- 公共字段tenant_id, active_flag, del_flag, create_dept, create_by, create_time, update_by, update_time。
**回写逻辑**
- 先按原 contract_id 删除 erp_contract_material 中该合同下所有物料;
- 再把本变更单下 erp_contract_change_material 的记录插入到 erp_contract_materialcontract_id 填原合同ID。
---
### 4. 合同变更付款方式快照表erp_contract_change_payment_method
存「变更后的合同付款方式」快照,字段与 erp_contract_payment_method 一一对齐。
- **主键**change_payment_idbigint, 自增)。
- **关联**contract_change_idbigint关联 erp_contract_change.contract_change_id不存 contract_id回写时再填原 contract_id
- **业务字段**(与 erp_contract_payment_method 一致sort_order、payment_stage_id、payment_deadline、payment_percentage、invoice_percentage、payment_amount、payment_description、remark。
- **公共字段**tenant_id、active_flag、del_flag、create_dept、create_by、create_time、update_by、update_time。
**回写逻辑**
- 先按原 contract_id 删除 erp_contract_payment_method 中该合同下所有付款方式;
- 再把本变更单下 erp_contract_change_payment_method 的记录插入到 erp_contract_payment_methodcontract_id 填原合同ID其他字段从快照表拷贝。
---
## 三、建表 SQL 示例
```sql
-- 合同变更主表
DROP TABLE IF EXISTS `erp_contract_change`;
CREATE TABLE `erp_contract_change` (
`contract_change_id` bigint NOT NULL AUTO_INCREMENT COMMENT '合同变更ID',
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
`contract_id` bigint NOT NULL COMMENT '原合同ID',
`contract_code` varchar(64) DEFAULT NULL COMMENT '原合同编号',
`contract_name` varchar(255) DEFAULT NULL COMMENT '原合同名称',
`change_code` varchar(64) DEFAULT NULL COMMENT '变更单编号',
`change_reason` varchar(500) DEFAULT NULL COMMENT '变更原因',
`change_status` varchar(32) DEFAULT NULL COMMENT '变更状态(1暂存 2审批中 3可用)',
`flow_status` varchar(32) DEFAULT NULL COMMENT '流程状态',
`apply_time` datetime DEFAULT NULL COMMENT '申请时间',
`write_back_flag` char(1) DEFAULT '0' COMMENT '是否已回写(0否 1是)',
`write_back_time` datetime DEFAULT NULL COMMENT '回写时间',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`active_flag` char(1) DEFAULT '1' COMMENT '激活标识(1是 0否)',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`create_by` bigint DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` bigint DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`contract_change_id`),
KEY `idx_contract_id` (`contract_id`),
KEY `idx_change_status` (`change_status`),
KEY `idx_change_code` (`change_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='合同变更主表';
-- 合同变更信息快照表(字段与 erp_contract_info 对齐,此处仅列关键字段,其余按 erp_contract_info 补全)
DROP TABLE IF EXISTS `erp_contract_change_info`;
CREATE TABLE `erp_contract_change_info` (
`change_info_id` bigint NOT NULL AUTO_INCREMENT COMMENT '变更信息快照ID',
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
`contract_change_id` bigint NOT NULL COMMENT '合同变更ID',
`contract_flag` char(1) DEFAULT NULL COMMENT '有无合同(1有 2无)',
`customer_contract_code` varchar(128) DEFAULT NULL COMMENT '客户合同编号',
`contract_code` varchar(64) DEFAULT NULL COMMENT '合同编号',
`contract_name` varchar(255) DEFAULT NULL COMMENT '合同名称',
`contract_category` varchar(32) DEFAULT NULL COMMENT '合同大类',
`contract_type` varchar(32) DEFAULT NULL COMMENT '合同类型',
`business_direction` varchar(16) DEFAULT NULL COMMENT '业务方向',
`contract_dept_id` bigint DEFAULT NULL COMMENT '部门',
`contract_date` datetime DEFAULT NULL COMMENT '合同签订日期',
`total_price` decimal(16,2) DEFAULT NULL COMMENT '合同总价',
`one_customer_id` bigint DEFAULT NULL COMMENT '甲方公司',
`one_represent` varchar(128) DEFAULT NULL COMMENT '甲方授权代表',
`one_date` datetime DEFAULT NULL COMMENT '甲方签字日期',
`two_customer_id` bigint DEFAULT NULL COMMENT '乙方公司',
`two_represent` varchar(128) DEFAULT NULL COMMENT '乙方授权代表',
`two_date` datetime DEFAULT NULL COMMENT '乙方签字日期',
`contract_manager_id` bigint DEFAULT NULL COMMENT '合同负责人',
`template_id` bigint DEFAULT NULL COMMENT '合同模板ID',
`oss_id` varchar(512) DEFAULT NULL COMMENT '附件ID',
`payment_account_id` bigint DEFAULT NULL COMMENT '付款账户ID',
`payment_method` varchar(128) DEFAULT NULL COMMENT '付款方式',
`signature_appendix` bigint DEFAULT NULL COMMENT '签字合同附件',
`warranty_period` int DEFAULT NULL COMMENT '质保期(天)',
`internal_contract_code` varchar(128) DEFAULT NULL COMMENT '内部合同号',
`external_contract_code` varchar(128) DEFAULT NULL COMMENT '外部合同号',
`order_contract_code` varchar(128) DEFAULT NULL COMMENT '订单号',
`project_contract_code` varchar(128) DEFAULT NULL COMMENT '项目号',
`delivery_start` int DEFAULT NULL COMMENT '交付启动期限',
`warranty_period_description` varchar(128) DEFAULT '' COMMENT '质保期描述',
`delivery_location` varchar(255) DEFAULT '' COMMENT '交货地点',
`ship_method` varchar(128) DEFAULT '' COMMENT '运输方式',
`tax_rate` decimal(16,2) DEFAULT NULL COMMENT '合同税率',
`signing_place` varchar(200) DEFAULT '' COMMENT '签订地点',
`material_remark` varchar(500) DEFAULT '' COMMENT '合同物料备注',
`contract_template_flag` char(1) DEFAULT NULL COMMENT '合同模板标识',
`capitalized_amount` varchar(128) DEFAULT NULL COMMENT '合同大写金额',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`create_by` bigint DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` bigint DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`change_info_id`),
UNIQUE KEY `uk_contract_change_id` (`contract_change_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='合同变更信息快照';
-- 合同变更物料快照表(字段与 erp_contract_material 对齐)
DROP TABLE IF EXISTS `erp_contract_change_material`;
CREATE TABLE `erp_contract_change_material` (
`change_material_id` bigint NOT NULL AUTO_INCREMENT COMMENT '变更物料快照ID',
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
`contract_change_id` bigint NOT NULL COMMENT '合同变更ID',
`material_flag` char(1) DEFAULT NULL COMMENT '标准物料标识',
`product_name` varchar(255) DEFAULT NULL COMMENT '产品名称',
`specification_description` varchar(255) DEFAULT NULL COMMENT '规格描述',
`material_id` bigint DEFAULT NULL COMMENT '物料ID',
`relation_material_id` bigint DEFAULT NULL COMMENT '销售物料ID',
`amount` decimal(16,2) DEFAULT NULL COMMENT '数量',
`unit_id` bigint DEFAULT NULL COMMENT '单位ID',
`before_price` decimal(16,2) DEFAULT NULL COMMENT '未税单价',
`tax_rate` decimal(16,2) DEFAULT NULL COMMENT '税率',
`including_price` decimal(16,2) DEFAULT NULL COMMENT '含税单价',
`subtotal` decimal(16,2) DEFAULT NULL COMMENT '小计',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`sort_order` int DEFAULT 0 COMMENT '排序号',
`active_flag` char(1) DEFAULT '1' COMMENT '激活标识',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`create_by` bigint DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` bigint DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`change_material_id`),
KEY `idx_contract_change_id` (`contract_change_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='合同变更物料快照';
-- 合同变更付款方式快照表(字段与 erp_contract_payment_method 对齐)
DROP TABLE IF EXISTS `erp_contract_change_payment_method`;
CREATE TABLE `erp_contract_change_payment_method` (
`change_payment_id` bigint NOT NULL AUTO_INCREMENT COMMENT '变更付款方式快照ID',
`tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '000000' COMMENT '租户编号',
`contract_change_id` bigint NOT NULL COMMENT '合同变更ID',
`sort_order` int NULL DEFAULT NULL COMMENT '排序号',
`payment_stage_id` bigint NULL DEFAULT NULL COMMENT '付款节点ID',
`payment_deadline` decimal(8, 0) NULL DEFAULT NULL COMMENT '支付期限',
`payment_percentage` decimal(8, 0) NULL DEFAULT NULL COMMENT '支付比例',
`invoice_percentage` decimal(8, 0) NULL DEFAULT NULL COMMENT '发票比例',
`payment_amount` decimal(16, 2) NULL DEFAULT NULL COMMENT '支付金额',
`payment_description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '付款条款',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`active_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '激活标识1是 0否',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志0代表存在 1代表删除',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_by` bigint NULL DEFAULT NULL COMMENT '创建人',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` bigint NULL DEFAULT NULL COMMENT '更新人',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`change_payment_id`) USING BTREE,
KEY `idx_contract_change_id` (`contract_change_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='合同变更付款方式快照' ROW_FORMAT=DYNAMIC;
```
说明erp_contract_change_info 若与现有 erp_contract_info 字段有新增需在快照表里同步增加一列保证回写时能完整覆盖。erp_contract_change_payment_method 与 erp_contract_payment_method 字段保持一致,便于回写时逐字段拷贝。
---
## 四、业务逻辑(通俗描述)
### 1. 合同变更列表页(类似合同信息)
- **数据来源**:查表 erp_contract_change可加 del_flag=0、按租户等条件
- **能力**:列表展示变更单号、关联合同、变更状态、申请时间、是否已回写等;支持按合同、状态、时间筛选。
- **新增**:点「新增」跳转到「合同变更申请」页(不传变更单 id即新建
### 2. 合同变更申请页
- **选合同**
- 下拉/选择器只查「可变更」的合同:`erp_contract_info` 中 `contract_status = '3'``active_flag = '1'`(已激活)。
- 若已有合同变更单 id编辑/查看),则直接带出已选的 contract_id。
- **带出合同信息**
- 选好合同后,后端根据 contract_id 查 erp_contract_info、erp_contract_material、**erp_contract_payment_method**,返回前端。
- 前端把合同主信息、物料列表、**付款方式列表**展示在表单中,允许编辑。
- **保存/提交**
- **暂存**:插入或更新 erp_contract_changechange_status=1并插入/更新 erp_contract_change_info 一条、erp_contract_change_material 多条、**erp_contract_change_payment_method 多条**。
- **提交审批**:同上,但 change_status=2并走工作流flow_status 由流程更新)。
### 3. 合同变更历史
- **入口**:可在合同变更列表页增加「按合同查历史」;或在合同信息详情/列表中提供「变更历史」入口。
- **查询**:按 contract_id 查 erp_contract_change按申请时间倒序得到该合同下全部变更单。
- **展示**:变更单号、申请时间、变更状态、是否已回写、变更原因等;点某条可进详情,详情从 erp_contract_change_info、erp_contract_change_material、**erp_contract_change_payment_method** 取数据展示(只读即可)。
### 4. 变更通过后回写合同表、合同物料表与合同付款方式表
- **触发时机**:流程审批通过且 change_status 更新为 '3'(可用)时(可在流程监听/回调里做)。
- **前置条件**write_back_flag = '0',避免重复回写。
- **回写步骤**
1. 用 erp_contract_change 的 contract_id 找到原合同。
2. **合同主信息**:用 erp_contract_change_info 中该 contract_change_id 的唯一一条记录,按字段更新 erp_contract_infoWHERE contract_id = 原 contract_id。注意不更新 contract_id、合同状态等由系统控制的字段只更新业务可变更字段。
3. **合同物料**
- 删除DELETE FROM erp_contract_material WHERE contract_id = 原 contract_id
- 插入:把 erp_contract_change_material 中该 contract_change_id 下的记录逐条 INSERT 到 erp_contract_materialcontract_id 填原 contract_id其他字段从快照表拷贝。
4. **合同付款方式**
- 删除DELETE FROM erp_contract_payment_method WHERE contract_id = 原 contract_id
- 插入:把 erp_contract_change_payment_method 中该 contract_change_id 下的记录逐条 INSERT 到 erp_contract_payment_methodcontract_id 填原 contract_id其他字段从快照表拷贝。
5. 更新 erp_contract_changewrite_back_flag='1', write_back_time=当前时间。
---
## 五、小结
| 项目 | 说明 |
| ----- | ------------------------------------------------------------------------------------------------------------------------ |
| 可变更范围 | 仅合同状态=可用 且 激活标识=是 的合同 |
| 列表与申请 | 列表查 erp_contract_change申请页选合同后查 erp_contract_info + erp_contract_material + erp_contract_payment_method 带出并编辑,保存到变更主表+三张快照表 |
| 历史 | 按 contract_id 查 erp_contract_change详情用 change_info、change_material、change_payment_method |
| 回写 | 审批通过后,用 change_info 更新 contract_info用 change_material 全量替换该 contract_id 下物料,用 change_payment_method 全量替换该 contract_id 下付款方式,并标记已回写 |
按上述表结构与逻辑实现即可满足「只有合同激活后可变更、可查变更历史、变更后内容回写合同表、合同物料表与合同付款方式表」的需求。