From bf1e0729e9a74acafa4006f82fa488f26a2ddcf7 Mon Sep 17 00:00:00 2001 From: yinq Date: Sat, 7 Mar 2026 15:42:11 +0800 Subject: [PATCH] =?UTF-8?q?1.0.76=20=E5=90=88=E5=90=8C=E6=BF=80=E6=B4=BB?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E4=BC=98=E5=8C=96=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E6=A0=87=E8=AF=86=E9=80=89=E6=8B=A9=E4=B8=8E?= =?UTF-8?q?=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/sql/design-contract-change.md | 300 +++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 script/sql/design-contract-change.md diff --git a/script/sql/design-contract-change.md b/script/sql/design-contract-change.md new file mode 100644 index 00000000..36ad54d8 --- /dev/null +++ b/script/sql/design-contract-change.md @@ -0,0 +1,300 @@ +# 合同变更功能设计方案 + +## 一、需求理解(通俗说明) + +- **谁能变更**:只有「已激活」的合同可以发起变更。即:合同状态=可用(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_id(bigint, 自增)。 +- **关联**:contract_change_id(bigint,关联 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_id(bigint, 自增)。 +- **关联**:contract_change_id(bigint),不存 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_material,contract_id 填原合同ID。 + +--- + +### 4. 合同变更付款方式快照表:erp_contract_change_payment_method + +存「变更后的合同付款方式」快照,字段与 erp_contract_payment_method 一一对齐。 + +- **主键**:change_payment_id(bigint, 自增)。 +- **关联**:contract_change_id(bigint),关联 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_method,contract_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_change(change_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_info(WHERE 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_material,contract_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_method,contract_id 填原 contract_id,其他字段从快照表拷贝。 + 5. 更新 erp_contract_change:write_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 下付款方式,并标记已回写 | + +按上述表结构与逻辑实现即可满足「只有合同激活后可变更、可查变更历史、变更后内容回写合同表、合同物料表与合同付款方式表」的需求。 \ No newline at end of file