From bee96a1d36c86068cd5a7eb69f4e3294a8123b04 Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期五, 03 七月 2026 18:02:55 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_business' into dev_business

---
 yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java               |   18 
 sql/mysql/mes_auto_code_rule_init.sql                                                                                      |  523 +++++++++++++++
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java                        |   30 
 yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java                                   |    6 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java      |   37 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/api/contract/CrmContractApiImpl.java                            |   39 +
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/api/report/CrmReportApiImpl.java                                |    2 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java    |    4 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationServiceImpl.java              |  156 ----
 yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java                           |   14 
 docs/crm_erp_integration_frontend.md                                                                                       |  199 ++++++
 docs/contract_approval_change.md                                                                                           |  271 ++++++++
 docs/contract_product_field_change.md                                                                                      |  211 ++++++
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java            |   12 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java                       |    4 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java                    |  128 +++
 yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java                       |   65 +
 .claude/rules/sql-script.md                                                                                                |    6 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java                                   |   11 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java        |   45 +
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java                      |    4 
 yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/api/contract/CrmContractApi.java                            |   30 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java                            |    5 
 /dev/null                                                                                                                  |   56 -
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/quotation/CrmSaleQuotationStatusEnum.java                 |   10 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationService.java                  |   25 
 yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java                                       |    3 
 .claude/rules/compile-check.md                                                                                             |    2 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java |    4 
 yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java          |    6 
 30 files changed, 1,633 insertions(+), 293 deletions(-)

diff --git a/.claude/rules/compile-check.md b/.claude/rules/compile-check.md
index 7ef5049..46227e5 100644
--- a/.claude/rules/compile-check.md
+++ b/.claude/rules/compile-check.md
@@ -13,6 +13,8 @@
 | CRM 妯″潡 | MdmItemApi | MDM 鐗╂枡鎺ュ彛 |
 | CRM 妯″潡 | MdmUnitMeasureApi | MDM 璁¢噺鍗曚綅鎺ュ彛 |
 | CRM 妯″潡 | BpmProcessInstanceApi | BPM 娴佺▼瀹炰緥鎺ュ彛 |
+| CRM 妯″潡 | BpmCategoryService | BPM 鍒嗙被鏈嶅姟 |
+| CRM 妯″潡 | BpmProcessDefinitionService | BPM 娴佺▼瀹氫箟鏈嶅姟 |
 | ERP 妯″潡 | CrmCustomerApi | CRM 瀹㈡埛鎺ュ彛 |
 | ERP 妯″潡 | MdmItemApi | MDM 鐗╂枡鎺ュ彛 |
 
diff --git a/.claude/rules/sql-script.md b/.claude/rules/sql-script.md
new file mode 100644
index 0000000..19b1ccb
--- /dev/null
+++ b/.claude/rules/sql-script.md
@@ -0,0 +1,6 @@
+# SQL 鑴氭湰瑙勮寖
+
+## 瑙勫垯
+
+- SQL 鑴氭湰涓笉瑕佸寘鍚� tenant_id 瀛楁锛岄」鐩笉浣跨敤澶氱鎴锋ā寮忋��
+- INSERT 璇彞鍙寘鍚繀瑕佺殑涓氬姟瀛楁锛屼笉闇�瑕� tenant_id銆�
\ No newline at end of file
diff --git a/docs/contract_approval_change.md b/docs/contract_approval_change.md
new file mode 100644
index 0000000..03b35cb
--- /dev/null
+++ b/docs/contract_approval_change.md
@@ -0,0 +1,271 @@
+# 鍚堝悓瀹℃壒娴佺▼鍙樻洿
+
+## 鍙樻洿璇存槑
+
+1. **閿�鍞姤浠峰彇娑� BPM 瀹℃牳**锛氶攢鍞姤浠峰崟涓嶅啀璧板鎵规祦绋嬶紝绠�鍖栦负鑽夌 鈫� 宸茶浆鍚堝悓涓ょ鐘舵��
+2. **鍚堝悓瀹℃壒鍔ㄦ�侀�夋嫨娴佺▼**锛氬垱寤哄悎鍚屽悗锛岄渶鐢ㄦ埛鎵嬪姩閫夋嫨瀹℃壒娴佺▼骞舵彁浜ゅ鎵癸紙绫讳技閲囪喘鐢宠锛�
+
+---
+
+## 鏁版嵁搴撳彉鏇� SQL
+
+```sql
+-- =============================================
+-- 1. 鍚堝悓浜у搧琛ㄥ瓧娈靛彉鏇达紙绉婚櫎鏃у瓧娈碉級
+-- =============================================
+ALTER TABLE `crm_contract_product` DROP COLUMN `product_id`;
+ALTER TABLE `crm_contract_product` DROP COLUMN `product_price`;
+
+-- =============================================
+-- 2. BPM 鍒嗙被鍒涘缓锛堝悎鍚屽鎵癸級
+-- =============================================
+INSERT INTO `bpm_category` (`name`, `code`, `description`, `status`, `sort`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
+VALUES ('鍚堝悓瀹℃壒', 'contract_approve', '鍚堝悓瀹℃壒娴佺▼鍒嗙被', 0, 0, '1', NOW(), '1', NOW(), b'0');
+
+-- =============================================
+-- 3. 閿�鍞姤浠风姸鎬佸瓧娈垫洿鏂帮紙绠�鍖栫姸鎬侊級
+-- =============================================
+-- 鐘舵�佸�煎彉鏇达細0=鑽夌, 10=宸茶浆鍚堝悓
+-- 鍘� status 瀛楁鍊奸渶瑕佹竻鐞嗭細10(瀹℃壒涓�)銆�20(宸查�氳繃)銆�30(宸叉嫆缁�)銆�40(宸插彇娑�) 鏀逛负 0(鑽夌)
+UPDATE `crm_sale_quotation` SET `status` = 0 WHERE `status` IN (10, 20, 30, 40);
+-- 宸茶浆鍚堝悓鐨勪繚鎸佷笉鍙橈紙status=50 鏀逛负 status=10锛�
+UPDATE `crm_sale_quotation` SET `status` = 10 WHERE `status` = 50;
+
+-- =============================================
+-- 4. 鍚堝悓瀹℃壒鐘舵�佸瓧娈垫洿鏂帮紙璁剧疆榛樿鍊硷級
+-- =============================================
+-- 灏� audit_status 涓� NULL 鐨勮褰曡缃负 0锛堟湭鎻愪氦锛�
+UPDATE `crm_contract` SET `audit_status` = 0 WHERE `audit_status` IS NULL;
+
+-- =============================================
+-- 4. 鎶ヤ环鍗曚骇鍝佹槑缁嗚〃锛堝鏋滆〃涓嶅瓨鍦ㄩ渶鍒涘缓锛屽凡瀛樺湪鍒欒ˉ鍏呭瓧娈碉級
+-- =============================================
+-- 濡傛灉 crm_sale_quotation_product 琛ㄤ笉瀛樺湪锛屾墽琛屽垱寤�
+CREATE TABLE IF NOT EXISTS `crm_sale_quotation_product` (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+  `quotation_id` bigint NOT NULL COMMENT '鎶ヤ环鍗曠紪鍙�',
+  `item_id` bigint NOT NULL COMMENT 'MDM鐗╂枡缂栧彿',
+  `item_unit_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+  `item_price` decimal(24,6) NOT NULL DEFAULT 0 COMMENT '鐗╂枡鍘熶环锛堝啑浣欙級',
+  `quotation_price` decimal(24,6) NOT NULL COMMENT '鎶ヤ环鍗曚环',
+  `count` decimal(24,6) NOT NULL COMMENT '鏁伴噺',
+  `total_price` decimal(24,6) NOT NULL COMMENT '灏忚閲戦',
+  `tax_percent` decimal(10,2) DEFAULT NULL COMMENT '绋庣巼(%)',
+  `tax_price` decimal(24,6) DEFAULT NULL COMMENT '绋庨',
+  `remark` varchar(256) DEFAULT NULL COMMENT '澶囨敞',
+  `creator` varchar(64) DEFAULT NULL COMMENT '鍒涘缓鑰�',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+  `updater` varchar(64) DEFAULT NULL COMMENT '鏇存柊鑰�',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+  `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '绉熸埛缂栧彿',
+  PRIMARY KEY (`id`),
+  KEY `idx_quotation_id` (`quotation_id`)
+) ENGINE=InnoDB COMMENT='CRM 閿�鍞姤浠峰崟浜у搧鏄庣粏';
+
+-- 濡傛灉琛ㄥ凡瀛樺湪浣嗙己灏� item_price 瀛楁锛屾墽琛岃ˉ鍏�
+-- ALTER TABLE `crm_sale_quotation_product` 
+-- ADD COLUMN `item_price` decimal(24,6) NOT NULL DEFAULT 0 COMMENT '鐗╂枡鍘熶环锛堝啑浣欙級' AFTER `item_unit_id`;
+```
+
+---
+
+## 娑夊強椤甸潰
+
+- 閿�鍞姤浠峰崟鍒楄〃椤甸潰
+- 閿�鍞姤浠峰崟琛ㄥ崟椤甸潰
+- 鍚堝悓鍒楄〃椤甸潰
+- 鍚堝悓璇︽儏椤甸潰
+
+---
+
+## API 鍙樻洿
+
+### 鍚堝悓鎺ュ彛鏂板
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /crm/contract/approve-process-list | 鑾峰彇鍚堝悓瀹℃壒娴佺▼鍒楄〃 |
+| PUT | /crm/contract/submit | 鎻愪氦鍚堝悓瀹℃壒锛堥渶浼� processDefinitionKey锛� |
+
+**submit 鎺ュ彛鍙傛暟鍙樻洿锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| id | Long | 鏄� | 鍚堝悓缂栧彿 |
+| processDefinitionKey | String | 鏄� | 娴佺▼瀹氫箟 Key锛堢敤鎴烽�夋嫨锛� |
+
+### 閿�鍞姤浠峰崟鎺ュ彛鍙樻洿
+
+#### 绉婚櫎鐨勬帴鍙�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| PUT | /crm/sale-quotation/submit | 鎻愪氦瀹℃壒锛堝凡绉婚櫎锛� |
+| GET | /crm/sale-quotation/approve-process-list | 鑾峰彇瀹℃壒娴佺▼鍒楄〃锛堝凡绉婚櫎锛� |
+
+#### 鐘舵�佸彉鏇�
+
+| 鏃х姸鎬佸�� | 鏃х姸鎬佸悕 | 鏂扮姸鎬佸�� | 鏂扮姸鎬佸悕 |
+|----------|----------|----------|----------|
+| 0 | 鑽夌 | 0 | 鑽夌 |
+| 10 | 瀹℃壒涓� | - | 宸茬Щ闄� |
+| 20 | 宸查�氳繃 | - | 宸茬Щ闄� |
+| 30 | 宸叉嫆缁� | - | 宸茬Щ闄� |
+| 40 | 宸插彇娑� | - | 宸茬Щ闄� |
+| 50 | 宸茶浆鍚堝悓 | 10 | 宸茶浆鍚堝悓 |
+
+---
+
+## 鍓嶇淇敼鐐�
+
+### 1. 鍚堝悓鍒楄〃椤甸潰 - 鎻愪氦瀹℃壒
+
+**鏂板鎻愪氦瀹℃壒寮圭獥锛�**
+
+```html
+<!-- 鎻愪氦瀹℃壒寮圭獥 -->
+<el-dialog title="閫夋嫨瀹℃壒娴佺▼" v-model="submitDialogVisible" width="400px">
+  <el-form label-width="100px">
+    <el-form-item label="瀹℃壒娴佺▼" required>
+      <el-select v-model="selectedProcessKey" placeholder="璇烽�夋嫨" style="width: 100%">
+        <el-option v-for="item in processList" :key="item.key" :label="item.name" :value="item.key" />
+      </el-select>
+    </el-form-item>
+  </el-form>
+  <template #footer>
+    <el-button @click="submitDialogVisible = false">鍙栨秷</el-button>
+    <el-button type="primary" @click="confirmSubmit" :loading="submitLoading">纭畾</el-button>
+  </template>
+</el-dialog>
+```
+
+**JS 鏂规硶锛�**
+
+```js
+import { getContractApproveProcessList, submitContract } from '@/api/crm/contract'
+
+methods: {
+  async handleSubmit(row) {
+    const { data } = await getContractApproveProcessList()
+    this.processList = data
+    this.currentRow = row
+    this.selectedProcessKey = null
+    this.submitDialogVisible = true
+  },
+  async confirmSubmit() {
+    if (!this.selectedProcessKey) {
+      this.$message.warning('璇烽�夋嫨瀹℃壒娴佺▼')
+      return
+    }
+    this.submitLoading = true
+    try {
+      await submitContract(this.currentRow.id, this.selectedProcessKey)
+      this.$message.success('鎻愪氦鎴愬姛')
+      this.submitDialogVisible = false
+      this.getList()
+    } finally {
+      this.submitLoading = false
+    }
+  }
+}
+```
+
+**鎿嶄綔鎸夐挳璋冩暣锛�**
+
+```html
+<el-table-column label="鎿嶄綔" width="280">
+  <template #default="{ row }">
+    <el-button v-if="row.auditStatus === 0" type="primary" size="small" @click="handleUpdate(row)">缂栬緫</el-button>
+    <el-button v-if="row.auditStatus === 0" type="success" size="small" @click="handleSubmit(row)">鎻愪氦瀹℃壒</el-button>
+    <el-button v-if="row.auditStatus === 0" type="danger" size="small" @click="handleDelete(row)">鍒犻櫎</el-button>
+    <el-button v-if="row.auditStatus === 20" type="warning" size="small" @click="handleGenerateOrder(row)">鐢熸垚璁㈠崟</el-button>
+  </template>
+</el-table-column>
+```
+
+### 2. 鍚堝悓鐘舵�佹樉绀�
+
+```html
+<!-- 鍚堝悓瀹℃壒鐘舵�� -->
+<el-tag v-if="row.auditStatus === 0" type="info">鏈彁浜�</el-tag>
+<el-tag v-if="row.auditStatus === 10" type="warning">瀹℃壒涓�</el-tag>
+<el-tag v-if="row.auditStatus === 20" type="success">瀹℃牳閫氳繃</el-tag>
+<el-tag v-if="row.auditStatus === 30" type="danger">瀹℃牳涓嶉�氳繃</el-tag>
+```
+
+### 3. 閿�鍞姤浠峰崟鍒楄〃椤甸潰
+
+**绉婚櫎瀹℃壒鐩稿叧鎿嶄綔鎸夐挳锛�**
+
+```html
+<!-- 绉婚櫎浠ヤ笅鎸夐挳 -->
+<!-- <el-button v-if="row.status === 0" type="success" size="small" @click="handleSubmit(row)">鎻愪氦瀹℃壒</el-button> -->
+
+<!-- 淇濈暀鎸夐挳 -->
+<el-button v-if="row.status === 0" type="primary" size="small" @click="handleUpdate(row)">缂栬緫</el-button>
+<el-button v-if="row.status === 0" type="warning" size="small" @click="handleConvertContract(row)">杞悎鍚�</el-button>
+<el-button v-if="row.status === 0" type="danger" size="small" @click="handleDelete(row)">鍒犻櫎</el-button>
+<el-button v-if="row.contractId" type="primary" size="small" @click="handleViewContract(row)">鏌ョ湅鍚堝悓</el-button>
+```
+
+### 4. 鎶ヤ环鍗曠姸鎬佹樉绀�
+
+```html
+<!-- 鐘舵�佹爣绛� -->
+<el-tag v-if="row.status === 0" type="info">鑽夌</el-tag>
+<el-tag v-if="row.status === 10" type="success">宸茶浆鍚堝悓</el-tag>
+```
+
+### 5. API 鏂囦欢淇敼
+
+```js
+// /src/api/crm/contract.js
+
+// 鏂板 API
+export function getContractApproveProcessList() {
+  return request({ url: '/crm/contract/approve-process-list', method: 'get' })
+}
+
+export function submitContract(id, processDefinitionKey) {
+  return request({ url: '/crm/contract/submit', method: 'put', params: { id, processDefinitionKey } })
+}
+
+// /src/api/crm/saleQuotation.js
+
+// 绉婚櫎浠ヤ笅 API
+// export function submitSaleQuotation(id, processDefinitionKey) { ... }
+// export function getSaleQuotationApproveProcessList() { ... }
+
+// 淇濈暀浠ヤ笅 API
+export function createSaleQuotation(data) { ... }
+export function updateSaleQuotation(data) { ... }
+export function deleteSaleQuotation(ids) { ... }
+export function getSaleQuotation(id) { ... }
+export function getSaleQuotationPage(params) { ... }
+export function convertSaleQuotationToContract(id) { ... }
+```
+
+---
+
+## 涓氬姟娴佺▼鍙樻洿
+
+### 鏂版祦绋�
+
+```
+鎶ヤ环鍗�(鑽夌) 鈫� 杞悎鍚� 鈫� 鍚堝悓(鑽夌) 鈫� 鐢ㄦ埛閫夋嫨瀹℃壒娴佺▼ 鈫� 鎻愪氦瀹℃壒 鈫� BPM瀹℃壒 鈫� 瀹℃壒閫氳繃 鈫� 鐢熸垚璁㈠崟
+```
+
+**娴佺▼璇存槑锛�**
+1. 閿�鍞姤浠蜂笉鍐嶉渶瑕佸鎵癸紝鑽夌鐘舵�佸彲鐩存帴杞悎鍚�
+2. 鍚堝悓鍒涘缓鍚庝负鑽夌鐘舵�侊紝闇�鐢ㄦ埛鎵嬪姩閫夋嫨瀹℃壒娴佺▼骞舵彁浜�
+3. 鐐瑰嚮"鎻愪氦瀹℃壒"鎸夐挳鍚庯紝寮瑰嚭娴佺▼閫夋嫨妗嗭紝鐢ㄦ埛閫夋嫨娴佺▼鍚庢彁浜�
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+1. **鍚堝悓瀹℃壒 BPM 鍒嗙被**锛氶渶瑕佸湪 BPM 绠$悊鍚庡彴鍒涘缓鍒嗙被缂栫爜涓� `contract_approve` 鐨勫垎绫�
+2. **鍚堝悓瀹℃壒娴佺▼**锛氶渶瑕佸湪璇ュ垎绫讳笅閰嶇疆鑷冲皯涓�涓縺娲荤殑瀹℃壒娴佺▼
+3. **娴佺▼閫夋嫨**锛氬鏋滃彧鏈変竴涓祦绋嬶紝鍓嶇鍙互鐩存帴鎻愪氦锛涘鏋滄湁澶氫釜娴佺▼锛岄渶瑕佺敤鎴烽�夋嫨
+4. **杞悎鍚屽悗**锛氭姤浠疯浆鍚堝悓鍚庯紝鍚堝悓涓鸿崏绋跨姸鎬侊紝闇�鎵嬪姩鎻愪氦瀹℃壒
\ No newline at end of file
diff --git a/docs/contract_product_field_change.md b/docs/contract_product_field_change.md
new file mode 100644
index 0000000..f16c12a
--- /dev/null
+++ b/docs/contract_product_field_change.md
@@ -0,0 +1,211 @@
+# 鍚堝悓妯″潡浜у搧瀛楁鍙樻洿
+
+## 鍙樻洿璇存槑
+
+鍚堝悓妯″潡鐨勪骇鍝佹潵婧愪粠 **CRM 浜у搧** 鏀逛负 **MDM 鐗╂枡**锛屾秹鍙婂瓧娈靛悕绉板彉鏇淬��
+
+---
+
+## 鏁版嵁搴撳彉鏇� SQL
+
+```sql
+-- =============================================
+-- 鍚堝悓浜у搧琛ㄥ瓧娈靛彉鏇�
+-- =============================================
+
+-- 1. 鍒犻櫎鏃у瓧娈碉紙濡傛灉鏈夋暟鎹鍏堝浠斤級
+ALTER TABLE `crm_contract_product` DROP COLUMN `product_id`;
+ALTER TABLE `crm_contract_product` DROP COLUMN `product_price`;
+
+-- 2. 濡傛灉鏂板瓧娈典笉瀛樺湪锛屽垯娣诲姞锛堟牴鎹疄闄呮儏鍐靛垽鏂槸鍚﹂渶瑕佹墽琛岋級
+-- ALTER TABLE `crm_contract_product` ADD COLUMN `item_id` bigint DEFAULT NULL COMMENT 'MDM鐗╂枡缂栧彿' AFTER `contract_id`;
+-- ALTER TABLE `crm_contract_product` ADD COLUMN `item_unit_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿' AFTER `item_id`;
+-- ALTER TABLE `crm_contract_product` ADD COLUMN `item_price` decimal(24,6) DEFAULT NULL COMMENT '鐗╂枡鍘熶环' AFTER `item_unit_id`;
+```
+
+---
+
+## 娑夊強椤甸潰
+
+- 鍚堝悓琛ㄥ崟椤甸潰锛堟柊寤�/缂栬緫鍚堝悓锛�
+- 鍚堝悓璇︽儏椤甸潰
+
+---
+
+## API 鍙樻洿
+
+### 1. 鍒涘缓/鏇存柊鍚堝悓鎺ュ彛
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | /crm/contract/create | 鍒涘缓鍚堝悓 |
+| PUT | /crm/contract/update | 鏇存柊鍚堝悓 |
+
+### 2. 璇锋眰鍙傛暟鍙樻洿锛坧roducts 瀛楁锛�
+
+#### 鏃у瓧娈碉紙宸插簾寮冿級
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| productId | Long | 鏄� | CRM 浜у搧缂栧彿 |
+| productPrice | BigDecimal | 鍚� | 浜у搧浠锋牸 |
+| sellingPrice | BigDecimal | 鍚� | 閿�鍞环锛堢敤浣滃悎鍚屼环锛� |
+
+#### 鏂板瓧娈�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| itemId | Long | 鏄� | MDM 鐗╂枡缂栧彿 |
+| itemPrice | BigDecimal | 鏄� | 鐗╂枡鍘熶环 |
+| contractPrice | BigDecimal | 鏄� | 鍚堝悓浠锋牸 |
+| count | Integer | 鏄� | 鏁伴噺 |
+
+### 3. 璇锋眰绀轰緥
+
+**鏃ф牸寮忥紙涓嶅啀鏀寔锛夛細**
+
+```json
+{
+  "name": "鍚堝悓鍚嶇О",
+  "customerId": 1,
+  "products": [
+    {
+      "productId": 4,
+      "sellingPrice": 1111,
+      "count": 10
+    }
+  ]
+}
+```
+
+**鏂版牸寮忥細**
+
+```json
+{
+  "name": "鍚堝悓鍚嶇О",
+  "customerId": 1,
+  "products": [
+    {
+      "itemId": 4,
+      "itemPrice": 1000,
+      "contractPrice": 1111,
+      "count": 10
+    }
+  ]
+}
+```
+
+---
+
+## 鍝嶅簲鍙樻洿
+
+### 鍚堝悓璇︽儏鎺ュ彛鍝嶅簲
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /crm/contract/get | 鑾峰彇鍚堝悓璇︽儏 |
+
+#### 浜у搧鏄庣粏瀛楁鍙樻洿
+
+| 鏃у瓧娈� | 鏂板瓧娈� | 璇存槑 |
+|--------|--------|------|
+| productId | itemId | MDM 鐗╂枡缂栧彿 |
+| productName | itemName | 鐗╂枡鍚嶇О |
+| productNo | itemCode | 鐗╂枡缂栫爜 |
+| productUnit | itemUnitName | 璁¢噺鍗曚綅鍚嶇О |
+| productPrice | itemPrice | 鐗╂枡鍘熶环 |
+| - | itemBarCode | 鐗╂枡鏉$爜锛堟柊澧烇級 |
+
+---
+
+## 鍓嶇淇敼鐐�
+
+### 1. 鐗╂枡閫夋嫨缁勪欢
+
+灏� **CRM 浜у搧閫夋嫨鍣�** 鏀逛负 **MDM 鐗╂枡閫夋嫨鍣�**銆�
+
+```html
+<!-- 鏃э細CRM 浜у搧閫夋嫨鍣� -->
+<CrmProductSelect v-model="product.productId" />
+
+<!-- 鏂帮細MDM 鐗╂枡閫夋嫨鍣� -->
+<MdmItemSelect v-model="product.itemId" @change="handleItemChange" />
+```
+
+### 2. 鐗╂枡閫夋嫨鍥炶皟
+
+```js
+methods: {
+  handleItemChange(item) {
+    // 閫夋嫨鐗╂枡鍚庤嚜鍔ㄥ~鍏呬环鏍间俊鎭�
+    this.product.itemId = item.id
+    this.product.itemPrice = item.salesPrice  // 鐗╂枡鍘熶环
+    this.product.contractPrice = item.salesPrice  // 鍚堝悓浠锋牸锛堥粯璁ょ瓑浜庡師浠凤紝鍙慨鏀癸級
+  }
+}
+```
+
+### 3. 琛ㄦ牸鍒楀瓧娈典慨鏀�
+
+```html
+<!-- 浜у搧鏄庣粏琛ㄦ牸 -->
+<el-table-column prop="itemCode" label="鐗╂枡缂栫爜" />
+<el-table-column prop="itemName" label="鐗╂枡鍚嶇О" />
+<el-table-column prop="itemBarCode" label="鐗╂枡鏉$爜" />
+<el-table-column prop="itemUnitName" label="鍗曚綅" />
+<el-table-column prop="itemPrice" label="鍘熶环" />
+<el-table-column prop="contractPrice" label="鍚堝悓浠�" />
+<el-table-column prop="count" label="鏁伴噺" />
+```
+
+### 4. data 鏁版嵁淇敼
+
+```js
+// 浜у搧鏄庣粏鏁版嵁缁撴瀯
+product: {
+  itemId: null,          // MDM 鐗╂枡缂栧彿
+  itemPrice: null,       // 鐗╂枡鍘熶环
+  contractPrice: null,   // 鍚堝悓浠锋牸
+  count: null            // 鏁伴噺
+}
+```
+
+---
+
+## MDM 鐗╂枡閫夋嫨鍣� API
+
+### 鑾峰彇鐗╂枡鍒楄〃
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /mdm/item/page | 鍒嗛〉鏌ヨ鐗╂枡 |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| code | String | 鍚� | 鐗╂枡缂栫爜 |
+| name | String | 鍚� | 鐗╂枡鍚嶇О |
+| barCode | String | 鍚� | 鐗╂枡鏉$爜 |
+| status | Integer | 鍚� | 鐘舵�侊紙0鍚敤 1绂佺敤锛夛紝浼� 0 |
+
+**鍝嶅簲瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| id | Long | 鐗╂枡缂栧彿锛堝嵆 itemId锛� |
+| code | String | 鐗╂枡缂栫爜 |
+| name | String | 鐗╂枡鍚嶇О |
+| barCode | String | 鐗╂枡鏉$爜 |
+| salesPrice | BigDecimal | 閿�鍞环 |
+| unitMeasureId | Long | 璁¢噺鍗曚綅缂栧彿 |
+| unitMeasureName | String | 璁¢噺鍗曚綅鍚嶇О |
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+1. **鐗╂枡蹇呴』鍏堝惎鐢�**锛氬彧鑳介�夋嫨鐘舵�佷负"鍚敤"鐨� MDM 鐗╂枡
+2. **浠锋牸鍙慨鏀�**锛歚contractPrice` 榛樿绛変簬鐗╂枡鍘熶环锛屼絾鍙互鎵嬪姩淇敼
+3. **杩囨浮鏈�**锛氬悗绔殏鏃跺吋瀹� `productId` 鍜� `sellingPrice` 瀛楁锛屼絾鍚庣画浼氱Щ闄ゅ吋瀹归�昏緫
+4. **鍏朵粬妯″潡鍚屾淇敼**锛氶攢鍞姤浠峰崟涔熶娇鐢� MDM 鐗╂枡锛屽瓧娈典笌鍚堝悓涓�鑷�
diff --git a/docs/crm_erp_integration_frontend.md b/docs/crm_erp_integration_frontend.md
index 3a3afbc..9bf5edb 100644
--- a/docs/crm_erp_integration_frontend.md
+++ b/docs/crm_erp_integration_frontend.md
@@ -698,6 +698,10 @@
 ALTER TABLE `crm_contract`
 ADD COLUMN `order_id` bigint DEFAULT NULL COMMENT '鍏宠仈 ERP 閿�鍞鍗曠紪鍙�' AFTER `total_price`,
 ADD COLUMN `order_no` varchar(32) DEFAULT NULL COMMENT 'ERP 閿�鍞鍗曞崟鍙�' AFTER `order_id`;
+
+-- 鏂板瀹氶噾閲戦瀛楁
+ALTER TABLE `crm_contract`
+ADD COLUMN `deposit_price` decimal(24,6) DEFAULT NULL COMMENT '瀹氶噾閲戦锛屽崟浣嶏細鍏�' AFTER `total_price`;
 ```
 
 ### 5.2 CRM 鍟嗘満琛�
@@ -1006,3 +1010,198 @@
 |------|------|
 | `docs/crm_erp_integration_frontend.md` | 鏈枃妗� |
 | `docs/crm_erp_integration_sql.sql` | SQL 鍙樻洿鑴氭湰 |
+
+---
+
+## 鍗佷簩銆侀攢鍞鍗曚綔搴熷姛鑳斤紙鏂板锛�
+
+### 12.1 鍔熻兘璇存槑
+
+閿�鍞鍗曚綔搴熷姛鑳界敤浜庢爣璁板凡瀹℃牳鐨勮鍗曚负"宸蹭綔搴�"鐘舵�侊紝瀹炵幇璁㈠崟鍏ㄦ祦绋嬪彲杩芥函銆�
+
+**涓氬姟瑙勫垯锛�**
+- 鍙湁宸插鏍哥殑璁㈠崟鎵嶈兘浣滃簾
+- 宸插嚭搴撴垨宸查��璐х殑璁㈠崟涓嶈兘浣滃簾
+- 浣滃簾鍚庤鍗曠姸鎬佸彉涓�"宸蹭綔搴�"
+- 浣滃簾鍚庡悓姝ユ洿鏂板叧鑱斿悎鍚岀姸鎬佷负"宸蹭綔搴�"
+- 绠$悊鍛樺彲浠ラ噸鏂板惎鐢ㄥ凡浣滃簾鐨勮鍗�
+
+### 12.2 鐘舵�佹灇涓�
+
+| 鐘舵�佸�� | 鏋氫妇 | 璇存槑 |
+|--------|------|------|
+| 10 | PROCESS | 鏈鏍� |
+| 20 | APPROVE | 宸插鏍� |
+| 30 | CANCEL | 宸蹭綔搴� |
+
+### 12.3 鍚堝悓鐘舵�佸悓姝�
+
+褰撻攢鍞鍗曚綔搴�/鍚敤鏃讹紝浼氳嚜鍔ㄥ悓姝ュ叧鑱斿悎鍚岀殑鐘舵�侊細
+
+| 鎿嶄綔 | 璁㈠崟鐘舵�佸彉鍖� | 鍚堝悓鐘舵�佸彉鍖� |
+|------|--------------|--------------|
+| 浣滃簾璁㈠崟 | 宸插鏍� 鈫� 宸蹭綔搴� | 瀹℃牳閫氳繃 鈫� 宸蹭綔搴� |
+| 鍚敤璁㈠崟 | 宸蹭綔搴� 鈫� 宸插鏍� | 宸蹭綔搴� 鈫� 瀹℃牳閫氳繃 |
+
+**鍚堝悓鐘舵�佹灇涓撅細**
+
+| 鐘舵�佸�� | 鏋氫妇 | 璇存槑 |
+|--------|------|------|
+| 0 | DRAFT | 鏈彁浜� |
+| 10 | PROCESS | 瀹℃壒涓� |
+| 20 | APPROVE | 瀹℃牳閫氳繃 |
+| 30 | REJECT | 瀹℃牳涓嶉�氳繃 |
+| 40 | CANCEL | 宸插彇娑� |
+| 50 | INVALID | 宸蹭綔搴� |
+
+### 12.4 API 鎺ュ彛
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| PUT | /erp/sale-order/cancel | 浣滃簾閿�鍞鍗� |
+| PUT | /erp/sale-order/enable | 閲嶆柊鍚敤閿�鍞鍗� |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| id | Long | 鏄� | 閿�鍞鍗曠紪鍙� |
+
+**鍝嶅簲锛�**
+
+```json
+{
+  "code": 0,
+  "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+**閿欒鐮侊細**
+
+| 閿欒鐮� | 璇存槑 |
+|--------|------|
+| 1_020_201_011 | 浣滃簾澶辫触锛岃鍗曟湭瀹℃牳 |
+| 1_020_201_012 | 浣滃簾澶辫触锛屽凡瀛樺湪瀵瑰簲鐨勯攢鍞嚭搴撳崟 |
+| 1_020_201_013 | 浣滃簾澶辫触锛屽凡瀛樺湪瀵瑰簲鐨勯攢鍞��璐у崟 |
+| 1_020_201_014 | 浣滃簾澶辫触锛岃鍒锋柊椤甸潰鍚庨噸璇� |
+| 1_020_201_015 | 鍚敤澶辫触锛岃鍗曟湭浣滃簾 |
+| 1_020_201_016 | 鍚敤澶辫触锛岃鍒锋柊椤甸潰鍚庨噸璇� |
+
+### 12.5 鍓嶇淇敼鐐�
+
+**鏂囦欢璺緞锛�** `/src/views/erp/sale/order/index.vue`
+
+**鎿嶄綔鍒楁寜閽細**
+
+```html
+<el-table-column label="鎿嶄綔" width="280">
+  <template #default="{ row }">
+    <el-button v-if="row.status === 10" type="primary" size="small" @click="handleUpdate(row)">缂栬緫</el-button>
+    <el-button v-if="row.status === 10" type="success" size="small" @click="handleApprove(row)">瀹℃牳</el-button>
+    <el-button v-if="row.status === 20" type="warning" size="small" @click="handleProcess(row)">鍙嶅鏍�</el-button>
+    <el-button v-if="row.status === 20" type="danger" size="small" @click="handleCancel(row)">浣滃簾</el-button>
+    <el-button v-if="row.status === 30" type="success" size="small" @click="handleEnable(row)">鍚敤</el-button>
+    <el-button v-if="row.status === 10" type="danger" size="small" @click="handleDelete(row)">鍒犻櫎</el-button>
+  </template>
+</el-table-column>
+```
+
+**鐘舵�佹爣绛撅細**
+
+```html
+<el-table-column label="鐘舵��" prop="status" width="100">
+  <template #default="{ row }">
+    <el-tag v-if="row.status === 10" type="warning">鏈鏍�</el-tag>
+    <el-tag v-if="row.status === 20" type="success">宸插鏍�</el-tag>
+    <el-tag v-if="row.status === 30" type="info">宸蹭綔搴�</el-tag>
+  </template>
+</el-table-column>
+```
+
+**鍏宠仈鍚堝悓鍒楋紙浣滃簾鏃舵樉绀虹孩鑹诧級锛�**
+
+```html
+<el-table-column label="鍏宠仈鍚堝悓" prop="contractNo" width="150">
+  <template #default="{ row }">
+    <el-link
+      v-if="row.contractId"
+      :type="row.status === 30 ? 'danger' : 'primary'"
+      @click="handleViewContract(row)"
+    >
+      {{ row.contractNo }}
+    </el-link>
+    <span v-else>-</span>
+  </template>
+</el-table-column>
+```
+
+**JS 鏂规硶锛�**
+
+```js
+import { cancelSaleOrder, enableSaleOrder } from '@/api/erp/saleOrder'
+
+methods: {
+  async handleCancel(row) {
+    try {
+      await this.$confirm('纭浣滃簾璇ラ攢鍞鍗曪紵浣滃簾鍚庡叧鑱斿悎鍚屼篃灏嗘爣璁颁负宸蹭綔搴燂紒', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      })
+      await cancelSaleOrder(row.id)
+      this.$message.success('浣滃簾鎴愬姛')
+      this.getList()
+    } catch (e) {
+      if (e !== 'cancel') {
+        this.$message.error(e.message || '浣滃簾澶辫触')
+      }
+    }
+  },
+  async handleEnable(row) {
+    try {
+      await this.$confirm('纭閲嶆柊鍚敤璇ラ攢鍞鍗曪紵鍚敤鍚庡叧鑱斿悎鍚屽皢鎭㈠涓哄鏍搁�氳繃鐘舵�侊紒', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'info'
+      })
+      await enableSaleOrder(row.id)
+      this.$message.success('鍚敤鎴愬姛')
+      this.getList()
+    } catch (e) {
+      if (e !== 'cancel') {
+        this.$message.error(e.message || '鍚敤澶辫触')
+      }
+    }
+  }
+}
+```
+
+**API 瀹氫箟鏂囦欢锛�** `/src/api/erp/saleOrder.js`
+
+```js
+// 浣滃簾閿�鍞鍗�
+export function cancelSaleOrder(id) {
+  return request({
+    url: '/erp/sale-order/cancel',
+    method: 'put',
+    params: { id }
+  })
+}
+
+// 閲嶆柊鍚敤閿�鍞鍗�
+export function enableSaleOrder(id) {
+  return request({
+    url: '/erp/sale-order/enable',
+    method: 'put',
+    params: { id }
+  })
+}
+```
+
+### 12.6 娉ㄦ剰浜嬮」
+
+1. 浣滃簾鎿嶄綔浼氬悓姝ユ洿鏂板叧鑱斿悎鍚岀姸鎬佷负"宸蹭綔搴�"
+2. 鍚敤鎿嶄綔浼氬悓姝ユ洿鏂板叧鑱斿悎鍚岀姸鎬佷负"瀹℃牳閫氳繃"
+3. 宸插嚭搴�/宸查��璐х殑璁㈠崟涓嶈兘浣滃簾锛岄渶鍏堝鐞嗙浉鍏充笟鍔″崟鎹�
+4. 浣滃簾鍚庤鍗曞彿鏄剧ず涓虹孩鑹诧紝鎻愰啋鐢ㄦ埛璇ヨ鍗曞凡澶辨晥
+5. 鍚敤鍔熻兘闇�瑕佺鐞嗗憳鏉冮檺锛坄erp:sale-order:enable`锛�
diff --git a/sql/mysql/mes_auto_code_rule_init.sql b/sql/mysql/mes_auto_code_rule_init.sql
new file mode 100644
index 0000000..0fe4242
--- /dev/null
+++ b/sql/mysql/mes_auto_code_rule_init.sql
@@ -0,0 +1,523 @@
+-- =============================================
+-- MES 缂栫爜瑙勫垯鍒濆鍖栬剼鏈�
+-- 鎵ц鍓嶈纭繚 mes_md_auto_code_rule 鍜� mes_md_auto_code_part 琛ㄥ凡瀛樺湪
+-- =============================================
+
+-- 娓呯┖鐜版湁鏁版嵁锛堥噸鏂板垵濮嬪寲鏃舵墽琛岋級
+DELETE FROM mes_md_auto_code_part;
+DELETE FROM mes_md_auto_code_rule;
+
+-- =============================================
+-- 1. 鍩虹涓绘暟鎹紪鐮佽鍒�
+-- =============================================
+
+-- 1.1 鐗╂枡鍒嗙被缂栫爜瑙勫垯 (MD_ITEM_TYPE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (1, 'MD_ITEM_TYPE_CODE', '鐗╂枡鍒嗙被缂栫爜', '鐢ㄤ簬鐢熸垚鐗╂枡鍒嗙被缂栫爜', 10, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (1, 1, 3, 3, 'ITC', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (1, 2, 4, 4, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 1.2 鐗╂枡缂栫爜瑙勫垯 (MD_ITEM_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (2, 'MD_ITEM_CODE', '鐗╂枡缂栫爜', '鐢ㄤ簬鐢熸垚鐗╂枡缂栫爜', 20, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (2, 1, 3, 5, 'ITEM_', NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (2, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (2, 3, 4, 4, NULL, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 1.3 渚涘簲鍟嗙紪鐮佽鍒� (MD_VENDOR_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (3, 'MD_VENDOR_CODE', '渚涘簲鍟嗙紪鐮�', '鐢ㄤ簬鐢熸垚渚涘簲鍟嗙紪鐮�', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (3, 1, 3, 3, 'VDR', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (3, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 1.4 瀹㈡埛缂栫爜瑙勫垯 (MD_CLIENT_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (4, 'MD_CLIENT_CODE', '瀹㈡埛缂栫爜', '鐢ㄤ簬鐢熸垚瀹㈡埛缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (4, 1, 3, 3, 'CLT', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (4, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 1.5 宸ヤ綔绔欑紪鐮佽鍒� (MD_WORKSTATION_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (5, 'MD_WORKSTATION_CODE', '宸ヤ綔绔欑紪鐮�', '鐢ㄤ簬鐢熸垚宸ヤ綔绔欑紪鐮�', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (5, 1, 3, 3, 'WKS', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (5, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 1.6 杞﹂棿缂栫爜瑙勫垯 (MD_WORKSHOP_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (6, 'MD_WORKSHOP_CODE', '杞﹂棿缂栫爜', '鐢ㄤ簬鐢熸垚杞﹂棿缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (6, 1, 3, 3, 'WSP', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (6, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 1.7 宸ュ叿绫诲瀷缂栫爜瑙勫垯 (TM_TOOL_TYPE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (7, 'TM_TOOL_TYPE_CODE', '宸ュ叿绫诲瀷缂栫爜', '鐢ㄤ簬鐢熸垚宸ュ叿绫诲瀷缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (7, 1, 3, 3, 'TTL', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (7, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- =============================================
+-- 2. 浠撳簱绠$悊缂栫爜瑙勫垯
+-- =============================================
+
+-- 2.1 浠撳簱缂栫爜 (WM_WAREHOUSE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (8, 'WM_WAREHOUSE_CODE', '浠撳簱缂栫爜', '鐢ㄤ簬鐢熸垚浠撳簱缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (8, 1, 3, 3, 'WHS', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (8, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.2 搴撳尯缂栫爜 (WM_LOCATION_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (9, 'WM_LOCATION_CODE', '搴撳尯缂栫爜', '鐢ㄤ簬鐢熸垚搴撳尯缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (9, 1, 3, 3, 'LOC', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (9, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.3 搴撲綅缂栫爜 (WM_AREA_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (10, 'WM_AREA_CODE', '搴撲綅缂栫爜', '鐢ㄤ簬鐢熸垚搴撲綅缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (10, 1, 3, 3, 'ARA', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (10, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.4 鎵规缂栫爜 (WM_BATCH_CODE) - 鎸夊ぉ寰幆
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (11, 'WM_BATCH_CODE', '鎵规缂栫爜', '鐢ㄤ簬鐢熸垚鎵规缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (11, 1, 3, 1, 'B', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (11, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (11, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.5 SN鐮� (WM_SN_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (12, 'WM_SN_CODE', 'SN鐮�', '鐢ㄤ簬鐢熸垚SN鐮�', 20, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (12, 1, 3, 3, 'SN_', NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (12, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (12, 3, 4, 6, NULL, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.6 瑁呯鍗曠紪鐮� (WM_PACKAGE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (13, 'WM_PACKAGE_CODE', '瑁呯鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚瑁呯鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, remark, creator, create_time, updater, update_time, deleted)
+VALUES (13, 1, 3, 4, 'PKG_', NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, remark, creator, create_time, updater, update_time, deleted)
+VALUES (13, 2, 2, 8, NULL, 'yyyyMMdd', '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.7 鍒拌揣閫氱煡鍗曠紪鐮� (WM_ARRIVAL_NOTICE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (14, 'WM_ARRIVAL_NOTICE_CODE', '鍒拌揣閫氱煡鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚鍒拌揣閫氱煡鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (14, 1, 3, 3, 'AN_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (14, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (14, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.8 閲囪喘鍏ュ簱鍗曠紪鐮� (WM_ITEM_RECEIPT_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (15, 'WM_ITEM_RECEIPT_CODE', '閲囪喘鍏ュ簱鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚閲囪喘鍏ュ簱鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (15, 1, 3, 3, 'IR_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (15, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (15, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.9 閲囪喘閫�璐у崟缂栫爜 (WM_RETURN_VENDOR_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (16, 'WM_RETURN_VENDOR_CODE', '閲囪喘閫�璐у崟缂栫爜', '鐢ㄤ簬鐢熸垚閲囪喘閫�璐у崟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (16, 1, 3, 3, 'RV_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (16, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (16, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.10 鐢熶骇閫�鏂欏崟缂栫爜 (WM_RETURN_ISSUE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (17, 'WM_RETURN_ISSUE_CODE', '鐢熶骇閫�鏂欏崟缂栫爜', '鐢ㄤ簬鐢熸垚鐢熶骇閫�鏂欏崟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (17, 1, 3, 3, 'RI_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (17, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (17, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.11 閿�鍞嚭搴撳崟缂栫爜 (WM_PRODUCT_SALES_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (18, 'WM_PRODUCT_SALES_CODE', '閿�鍞嚭搴撳崟缂栫爜', '鐢ㄤ簬鐢熸垚閿�鍞嚭搴撳崟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (18, 1, 3, 3, 'SO_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (18, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (18, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.12 鍙戣揣閫氱煡鍗曠紪鐮� (WM_SALES_NOTICE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (19, 'WM_SALES_NOTICE_CODE', '鍙戣揣閫氱煡鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚鍙戣揣閫氱煡鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (19, 1, 3, 3, 'SN_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (19, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (19, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.13 閿�鍞��璐у崟缂栫爜 (WM_RETURN_SALES_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (20, 'WM_RETURN_SALES_CODE', '閿�鍞��璐у崟缂栫爜', '鐢ㄤ簬鐢熸垚閿�鍞��璐у崟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (20, 1, 3, 3, 'RS_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (20, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (20, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.14 鏉傞」鍏ュ簱鍗曠紪鐮� (WM_MISC_RECEIPT_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (21, 'WM_MISC_RECEIPT_CODE', '鏉傞」鍏ュ簱鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚鏉傞」鍏ュ簱鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (21, 1, 3, 3, 'MR_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (21, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (21, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.15 鏉傞」鍑哄簱鍗曠紪鐮� (WM_MISC_ISSUE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (22, 'WM_MISC_ISSUE_CODE', '鏉傞」鍑哄簱鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚鏉傞」鍑哄簱鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (22, 1, 3, 3, 'MI_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (22, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (22, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.16 鐩樼偣鏂规缂栫爜 (WM_STOCK_TAKING_PLAN_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (23, 'WM_STOCK_TAKING_PLAN_CODE', '鐩樼偣鏂规缂栫爜', '鐢ㄤ簬鐢熸垚鐩樼偣鏂规缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (23, 1, 3, 3, 'SP_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (23, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (23, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.17 鐩樼偣浠诲姟缂栫爜 (WM_STOCK_TAKING_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (24, 'WM_STOCK_TAKING_CODE', '鐩樼偣浠诲姟缂栫爜', '鐢ㄤ簬鐢熸垚鐩樼偣浠诲姟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (24, 1, 3, 3, 'ST_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (24, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (24, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.18 杞Щ璋冩嫧鍗曠紪鐮� (TRANSFER_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (25, 'TRANSFER_CODE', '杞Щ璋冩嫧鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚杞Щ璋冩嫧鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (25, 1, 3, 3, 'TR_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (25, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (25, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.19 澶栧崗鍙戞枡鍗曠紪鐮� (WM_OUTSOURCE_ISSUE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (26, 'WM_OUTSOURCE_ISSUE_CODE', '澶栧崗鍙戞枡鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚澶栧崗鍙戞枡鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (26, 1, 3, 3, 'OI_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (26, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (26, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 2.20 澶栧崗鍏ュ簱鍗曠紪鐮� (WM_OUTSOURCE_RECEIPT_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (27, 'WM_OUTSOURCE_RECEIPT_CODE', '澶栧崗鍏ュ簱鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚澶栧崗鍏ュ簱鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (27, 1, 3, 3, 'OR_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (27, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (27, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- =============================================
+-- 3. 鐢熶骇绠$悊缂栫爜瑙勫垯
+-- =============================================
+
+-- 3.1 鐢熶骇宸ュ崟缂栫爜 (PRO_WORK_ORDER_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (28, 'PRO_WORK_ORDER_CODE', '鐢熶骇宸ュ崟缂栫爜', '鐢ㄤ簬鐢熸垚鐢熶骇宸ュ崟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (28, 1, 3, 3, 'WO_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (28, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (28, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 3.2 鐢熶骇浠诲姟缂栫爜 (PRO_TASK_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (29, 'PRO_TASK_CODE', '鐢熶骇浠诲姟缂栫爜', '鐢ㄤ簬鐢熸垚鐢熶骇浠诲姟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (29, 1, 3, 3, 'TK_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (29, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (29, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 3.3 鐢熶骇鎶ュ伐鍗曠紪鐮� (PRO_FEEDBACK_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (30, 'PRO_FEEDBACK_CODE', '鐢熶骇鎶ュ伐鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚鐢熶骇鎶ュ伐鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (30, 1, 3, 3, 'FB_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (30, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (30, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 3.4 宸ヨ壓璺嚎缂栫爜 (PRO_ROUTE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (31, 'PRO_ROUTE_CODE', '宸ヨ壓璺嚎缂栫爜', '鐢ㄤ簬鐢熸垚宸ヨ壓璺嚎缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (31, 1, 3, 3, 'RT_', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (31, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- =============================================
+-- 4. 璐ㄩ噺绠$悊缂栫爜瑙勫垯
+-- =============================================
+
+-- 4.1 鏉ユ枡妫�楠屽崟缂栫爜 (QC_IQC_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (32, 'QC_IQC_CODE', '鏉ユ枡妫�楠屽崟缂栫爜', '鐢ㄤ簬鐢熸垚鏉ユ枡妫�楠屽崟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (32, 1, 3, 4, 'IQC_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (32, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (32, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 4.2 杩囩▼妫�楠屽崟缂栫爜 (QC_IPQC_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (33, 'QC_IPQC_CODE', '杩囩▼妫�楠屽崟缂栫爜', '鐢ㄤ簬鐢熸垚杩囩▼妫�楠屽崟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (33, 1, 3, 5, 'IPQC_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (33, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (33, 3, 4, 3, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 4.3 鍑鸿揣妫�楠屽崟缂栫爜 (QC_OQC_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (34, 'QC_OQC_CODE', '鍑鸿揣妫�楠屽崟缂栫爜', '鐢ㄤ簬鐢熸垚鍑鸿揣妫�楠屽崟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (34, 1, 3, 5, 'OQC_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (34, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (34, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 4.4 閫�璐ф楠屽崟缂栫爜 (QC_RQC_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (35, 'QC_RQC_CODE', '閫�璐ф楠屽崟缂栫爜', '鐢ㄤ簬鐢熸垚閫�璐ф楠屽崟缂栫爜', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (35, 1, 3, 4, 'RQC_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (35, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (35, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- 4.5 缂洪櫡绫诲瀷缂栫爜 (QC_DEFECT_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (36, 'QC_DEFECT_CODE', '缂洪櫡绫诲瀷缂栫爜', '鐢ㄤ簬鐢熸垚缂洪櫡绫诲瀷缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (36, 1, 3, 3, 'DFC', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (36, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 4.6 鏍峰搧妫�楠岀粨鏋滅紪鐮� (QC_INDICATOR_RESULT_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (37, 'QC_INDICATOR_RESULT_CODE', '鏍峰搧妫�楠岀粨鏋滅紪鐮�', '鐢ㄤ簬鐢熸垚鏍峰搧妫�楠岀粨鏋滅紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (37, 1, 3, 4, 'QIR_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (37, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (37, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- =============================================
+-- 5. 璁惧绠$悊缂栫爜瑙勫垯
+-- =============================================
+
+-- 5.1 璁惧缂栫爜 (DV_MACHINERY_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (38, 'DV_MACHINERY_CODE', '璁惧缂栫爜', '鐢ㄤ簬鐢熸垚璁惧缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (38, 1, 3, 3, 'MC_', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (38, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 5.2 璁惧绫诲瀷缂栫爜 (DV_MACHINERY_TYPE_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (39, 'DV_MACHINERY_TYPE_CODE', '璁惧绫诲瀷缂栫爜', '鐢ㄤ簬鐢熸垚璁惧绫诲瀷缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (39, 1, 3, 3, 'MCT', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (39, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 5.3 鐐规淇濆吇椤圭洰缂栫爜 (DV_SUBJECT_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (40, 'DV_SUBJECT_CODE', '鐐规淇濆吇椤圭洰缂栫爜', '鐢ㄤ簬鐢熸垚鐐规淇濆吇椤圭洰缂栫爜', 12, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (40, 1, 3, 3, 'SBJ', NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, serial_start_no, serial_step, cycle_flag, remark, creator, create_time, updater, update_time, deleted)
+VALUES (40, 2, 4, 6, NULL, 1, 1, b'0', '娴佹按鍙�', '1', NOW(), '1', NOW(), b'0');
+
+-- 5.4 缁翠慨鍗曠紪鐮� (DV_REPAIR_CODE)
+INSERT INTO mes_md_auto_code_rule (id, code, name, description, max_length, padded, status, creator, create_time, updater, update_time, deleted)
+VALUES (41, 'DV_REPAIR_CODE', '缁翠慨鍗曠紪鐮�', '鐢ㄤ簬鐢熸垚缁翠慨鍗曠紪鐮�', 16, b'0', 0, '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (41, 1, 3, 3, 'RP_', NULL, NULL, NULL, NULL, NULL, '鍥哄畾鍓嶇紑', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (41, 2, 2, 8, NULL, 'yyyyMMdd', NULL, NULL, NULL, NULL, '鏃ユ湡', '1', NOW(), '1', NOW(), b'0');
+
+INSERT INTO mes_md_auto_code_part (rule_id, sort, type, length, fix_character, date_format, serial_start_no, serial_step, cycle_flag, cycle_method, remark, creator, create_time, updater, update_time, deleted)
+VALUES (41, 3, 4, 4, NULL, NULL, 1, 1, b'1', 3, '娴佹按鍙�-鎸夊ぉ寰幆', '1', NOW(), '1', NOW(), b'0');
+
+-- =============================================
+-- 鎵ц瀹屾垚鎻愮ず
+-- =============================================
+SELECT 'MES 缂栫爜瑙勫垯鍒濆鍖栧畬鎴愶紒' AS result;
+SELECT COUNT(*) AS rule_count FROM mes_md_auto_code_rule WHERE deleted = 0;
+SELECT COUNT(*) AS part_count FROM mes_md_auto_code_part WHERE deleted = 0;
\ No newline at end of file
diff --git a/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/api/contract/CrmContractApi.java b/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/api/contract/CrmContractApi.java
new file mode 100644
index 0000000..172864f
--- /dev/null
+++ b/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/api/contract/CrmContractApi.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.crm.api.contract;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+
+/**
+ * CRM 鍚堝悓 API 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface CrmContractApi {
+
+    String PREFIX = "/rpc-api/crm/contract";
+
+    /**
+     * 鏇存柊鍚堝悓鐘舵��
+     *
+     * @param id     鍚堝悓缂栧彿
+     * @param status 鐘舵��
+     */
+    CommonResult<Boolean> updateContractStatus(Long id, Integer status);
+
+    /**
+     * 鏍规嵁閿�鍞鍗曠紪鍙锋洿鏂板悎鍚岀姸鎬�
+     *
+     * @param orderId 閿�鍞鍗曠紪鍙�
+     * @param status  鐘舵��
+     */
+    CommonResult<Boolean> updateContractStatusByOrderId(Long orderId, Integer status);
+
+}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/api/contract/CrmContractApiImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/api/contract/CrmContractApiImpl.java
new file mode 100644
index 0000000..26bf5e4
--- /dev/null
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/api/contract/CrmContractApiImpl.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.crm.api.contract;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * CRM 鍚堝悓 API 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RestController
+@RequestMapping(CrmContractApi.PREFIX)
+@Validated
+public class CrmContractApiImpl implements CrmContractApi {
+
+    @Resource
+    @Lazy // 寤惰繜鍔犺浇锛岄伩鍏嶅惊鐜緷璧�
+    private CrmContractService contractService;
+
+    @Override
+    public CommonResult<Boolean> updateContractStatus(Long id, Integer status) {
+        contractService.updateContractStatus(id, status);
+        return success(true);
+    }
+
+    @Override
+    public CommonResult<Boolean> updateContractStatusByOrderId(Long orderId, Integer status) {
+        contractService.updateContractStatusByOrderId(orderId, status);
+        return success(true);
+    }
+
+}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/api/report/CrmReportApiImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/api/report/CrmReportApiImpl.java
index 379c959..1c6d15e 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/api/report/CrmReportApiImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/api/report/CrmReportApiImpl.java
@@ -16,6 +16,7 @@
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -47,6 +48,7 @@
     @Resource
     private CrmContractMapper contractMapper;
     @Resource
+    @Lazy // 寤惰繜鍔犺浇锛岄伩鍏嶅惊鐜緷璧�
     private CrmReceivableService receivableService;
     @Resource
     private AdminUserApi adminUserApi;
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
index 01b1a2d..b6df80f 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
@@ -176,11 +176,19 @@
     @PutMapping("/submit")
     @Operation(summary = "鎻愪氦鍚堝悓瀹℃壒")
     @PreAuthorize("@ss.hasPermission('crm:contract:update')")
-    public CommonResult<Boolean> submitContract(@RequestParam("id") Long id) {
-        contractService.submitContract(id, getLoginUserId());
+    public CommonResult<Boolean> submitContract(@RequestParam("id") Long id,
+                                                  @RequestParam("processDefinitionKey") String processDefinitionKey) {
+        contractService.submitContract(id, processDefinitionKey, getLoginUserId());
         return success(true);
     }
 
+    @GetMapping("/approve-process-list")
+    @Operation(summary = "鑾峰彇鍚堝悓瀹℃壒娴佺▼鍒楄〃")
+    @PreAuthorize("@ss.hasPermission('crm:contract:query')")
+    public CommonResult<List<Map<String, Object>>> getContractApproveProcessList() {
+        return success(contractService.getContractApproveProcessDefinitionList());
+    }
+
     private List<CrmContractRespVO> buildContractDetailList(List<CrmContractDO> contractList) {
         if (CollUtil.isEmpty(contractList)) {
             return Collections.emptyList();
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java
index 23b17b2..d33143d 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java
@@ -88,6 +88,10 @@
     @ExcelProperty("鍚堝悓閲戦")
     private BigDecimal totalPrice;
 
+    @Schema(description = "瀹氶噾閲戦锛屽崟浣嶏細鍏�", example = "1000.00")
+    @ExcelProperty("瀹氶噾閲戦")
+    private BigDecimal depositPrice;
+
     @Schema(description = "宸插洖娆鹃噾棰�", example = "5617")
     @ExcelProperty("宸插洖娆鹃噾棰�")
     private BigDecimal totalReceivablePrice;
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java
index 1ef6471..5e7b2c0 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java
@@ -69,6 +69,10 @@
     @DiffLogField(name = "鍚堝悓閲戦")
     private BigDecimal totalPrice;
 
+    @Schema(description = "瀹氶噾閲戦锛屽崟浣嶏細鍏�", example = "1000.00")
+    @DiffLogField(name = "瀹氶噾閲戦")
+    private BigDecimal depositPrice;
+
     @Schema(description = "瀹㈡埛绛剧害浜虹紪鍙�", example = "18546")
     @DiffLogField(name = "瀹㈡埛绛剧害浜�", function = CrmContactParseFunction.NAME)
     private Long signContactId;
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java
index 1414b4b..2bad9a7 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java
@@ -13,6 +13,8 @@
 import cn.iocoder.yudao.module.crm.controller.admin.quotation.vo.CrmSaleQuotationSaveReqVO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.quotation.CrmSaleQuotationDO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.quotation.CrmSaleQuotationProductDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
+import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
 import cn.iocoder.yudao.module.crm.service.quotation.CrmSaleQuotationService;
 import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
 import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
@@ -61,6 +63,8 @@
     private MdmItemApi mdmItemApi;
     @Resource
     private MdmUnitMeasureApi mdmUnitMeasureApi;
+    @Resource
+    private CrmCustomerService customerService;
 
     @PostMapping("/create")
     @Operation(summary = "鍒涘缓閿�鍞姤浠峰崟")
@@ -135,22 +139,6 @@
         ExcelUtils.write(response, "閿�鍞姤浠峰崟.xls", "鏁版嵁", CrmSaleQuotationRespVO.class, list);
     }
 
-    @PutMapping("/submit")
-    @Operation(summary = "鎻愪氦閿�鍞姤浠峰鎵�")
-    @PreAuthorize("@ss.hasPermission('crm:sale-quotation:submit')")
-    public CommonResult<Boolean> submitSaleQuotation(@RequestParam("id") Long id,
-                                                      @RequestParam("processDefinitionKey") String processDefinitionKey) {
-        saleQuotationService.submitSaleQuotation(id, processDefinitionKey, getLoginUserId());
-        return success(true);
-    }
-
-    @GetMapping("/approve-process-list")
-    @Operation(summary = "鑾峰彇閿�鍞姤浠峰鎵规祦绋嬪垪琛�")
-    @PreAuthorize("@ss.hasPermission('crm:sale-quotation:query')")
-    public CommonResult<List<Map<String, Object>>> getSaleQuotationApproveProcessList() {
-        return success(saleQuotationService.getSaleQuotationApproveProcessDefinitionList());
-    }
-
     @PostMapping("/convert-contract")
     @Operation(summary = "杞负鍚堝悓")
     @Parameter(name = "id", description = "鎶ヤ环鍗曠紪鍙�", required = true)
@@ -180,7 +168,14 @@
                 MapUtils.findAndThen(unitMap, item.getItemUnitId(), unit -> item.setItemUnitName(unit.getName()));
             }));
         }
-        // 2. 濉厖鍏宠仈淇℃伅
+        // 2. 濉厖瀹㈡埛鍚嶇О
+        if (saleQuotation.getCustomerId() != null) {
+            CrmCustomerDO customer = customerService.getCustomer(saleQuotation.getCustomerId());
+            if (customer != null) {
+                respVO.setCustomerName(customer.getName());
+            }
+        }
+        // 3. 濉厖鍏宠仈淇℃伅
         fillSaleQuotationRelatedFields(respVO);
         return respVO;
     }
@@ -195,10 +190,13 @@
         Map<Long, List<CrmSaleQuotationProductDO>> productMap = convertMultiMap(productList, CrmSaleQuotationProductDO::getQuotationId);
         // 1.2 鐗╂枡淇℃伅
         Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(convertSet(productList, CrmSaleQuotationProductDO::getItemId));
-        // 1.3 鐢ㄦ埛淇℃伅
+        // 1.3 瀹㈡埛淇℃伅
+        Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap(
+                convertSet(pageResult.getList(), CrmSaleQuotationDO::getCustomerId));
+        // 1.4 鐢ㄦ埛淇℃伅
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                 convertSet(pageResult.getList(), CrmSaleQuotationDO::getOwnerUserId));
-        // 1.4 閮ㄩ棬淇℃伅
+        // 1.5 閮ㄩ棬淇℃伅
         Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(
                 convertSet(pageResult.getList(), CrmSaleQuotationDO::getOwnerUserId));
 
@@ -207,6 +205,7 @@
             vo.setItems(BeanUtils.toBean(productMap.get(vo.getId()), CrmSaleQuotationRespVO.Item.class,
                     item -> MapUtils.findAndThen(itemMap, item.getItemId(), mdmItem -> item.setItemCode(mdmItem.getCode())
                             .setItemName(mdmItem.getName()).setItemBarCode(mdmItem.getBarCode()))));
+            MapUtils.findAndThen(customerMap, vo.getCustomerId(), customer -> vo.setCustomerName(customer.getName()));
             MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()));
             MapUtils.findAndThen(deptMap, vo.getOwnerUserId(), dept -> vo.setOwnerUserDeptName(dept.getName()));
         });
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java
index e7e3bae..61c072b 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java
@@ -104,6 +104,10 @@
      */
     private BigDecimal totalPrice;
     /**
+     * 瀹氶噾閲戦锛屽崟浣嶏細鍏�
+     */
+    private BigDecimal depositPrice;
+    /**
      * 鍏宠仈 ERP 閿�鍞鍗曠紪鍙�
      */
     private Long orderId;
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java
index a61c925..b85d74c 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java
@@ -118,6 +118,10 @@
         return selectOne(CrmContractDO::getBusinessId, businessId);
     }
 
+    default CrmContractDO selectByOrderId(Long orderId) {
+        return selectOne(CrmContractDO::getOrderId, orderId);
+    }
+
     default List<CrmContractDO> selectListByCustomerId(Long customerId) {
         return selectList(CrmContractDO::getCustomerId, customerId);
     }
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
index 4149e75..490a690 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
@@ -19,6 +19,7 @@
     ErrorCode CONTRACT_GENERATE_ORDER_FAIL_NOT_APPROVE = new ErrorCode(1_020_000_006, "鐢熸垚閿�鍞鍗曞け璐ワ紝鍘熷洜锛氬悎鍚屾湭瀹℃壒閫氳繃");
     ErrorCode CONTRACT_GENERATE_ORDER_FAIL_EXISTS_ORDER = new ErrorCode(1_020_000_007, "鐢熸垚閿�鍞鍗曞け璐ワ紝鍘熷洜锛氬凡鍏宠仈閿�鍞鍗曘�恵}銆�");
     ErrorCode CONTRACT_GENERATE_ORDER_FAIL_NO_PRODUCT = new ErrorCode(1_020_000_008, "鐢熸垚閿�鍞鍗曞け璐ワ紝鍘熷洜锛氬悎鍚屾病鏈変骇鍝佷俊鎭�");
+    ErrorCode CONTRACT_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_020_000_009, "鍚堝悓瀹℃壒娴佺▼涓嶅瓨鍦ㄦ垨鏈縺娲伙紝璇锋鏌� BPM 閰嶇疆");
 
     // ========== 绾跨储绠$悊 1-020-001-000 ==========
     ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "绾跨储涓嶅瓨鍦�");
@@ -114,12 +115,8 @@
     ErrorCode SALE_QUOTATION_NO_EXISTS = new ErrorCode(1_020_015_001, "閿�鍞姤浠峰崟鍙峰凡瀛樺湪");
     ErrorCode SALE_QUOTATION_UPDATE_FAIL_NOT_DRAFT = new ErrorCode(1_020_015_002, "閿�鍞姤浠峰崟({})涓嶆槸鑽夌鐘舵�侊紝鏃犳硶淇敼");
     ErrorCode SALE_QUOTATION_DELETE_FAIL_NOT_DRAFT = new ErrorCode(1_020_015_003, "閿�鍞姤浠峰崟({})涓嶆槸鑽夌鐘舵�侊紝鏃犳硶鍒犻櫎");
-    ErrorCode SALE_QUOTATION_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_015_004, "閿�鍞姤浠峰崟涓嶆槸鑽夌鐘舵�侊紝鏃犳硶鎻愪氦瀹℃壒");
-    ErrorCode SALE_QUOTATION_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_015_005, "閿�鍞姤浠峰崟涓嶆槸瀹℃壒涓姸鎬侊紝鏃犳硶鏇存柊瀹℃壒鐘舵��");
-    ErrorCode SALE_QUOTATION_BPM_CATEGORY_NOT_EXISTS = new ErrorCode(1_020_015_006, "閿�鍞姤浠峰鎵瑰垎绫讳笉瀛樺湪锛岃妫�鏌� BPM 閰嶇疆");
-    ErrorCode SALE_QUOTATION_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_020_015_007, "閿�鍞姤浠峰鎵规祦绋嬩笉瀛樺湪鎴栨湭婵�娲伙紝璇锋鏌� BPM 閰嶇疆");
-    ErrorCode SALE_QUOTATION_NOT_APPROVE = new ErrorCode(1_020_015_008, "閿�鍞姤浠峰崟鏈鎵归�氳繃锛屾棤娉曡浆鍚堝悓");
-    ErrorCode SALE_QUOTATION_CONTRACT_EXISTS = new ErrorCode(1_020_015_009, "閿�鍞姤浠峰崟宸茶浆鍚堝悓锛岃鍕块噸澶嶆搷浣�");
-    ErrorCode SALE_QUOTATION_ITEM_NOT_EXISTS = new ErrorCode(1_020_015_010, "鐗╂枡涓嶅瓨鍦ㄦ垨鏈惎鐢�");
+    ErrorCode SALE_QUOTATION_CONVERT_FAIL_NOT_DRAFT = new ErrorCode(1_020_015_004, "閿�鍞姤浠峰崟({})涓嶆槸鑽夌鐘舵�侊紝鏃犳硶杞悎鍚�");
+    ErrorCode SALE_QUOTATION_ITEM_NOT_EXISTS = new ErrorCode(1_020_015_005, "鐗╂枡涓嶅瓨鍦ㄦ垨鏈惎鐢�");
+    ErrorCode SALE_QUOTATION_CONTRACT_EXISTS = new ErrorCode(1_020_015_006, "閿�鍞姤浠峰崟宸茶浆鍚堝悓锛岃鍕块噸澶嶆搷浣�");
 
 }
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java
index 3203481..b23de46 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java
@@ -18,8 +18,9 @@
     DRAFT(0, "鏈彁浜�"),
     PROCESS(10, "瀹℃壒涓�"),
     APPROVE(20, "瀹℃牳閫氳繃"),
-	REJECT(30, "瀹℃牳涓嶉�氳繃"),
-    CANCEL(40, "宸插彇娑�");
+    REJECT(30, "瀹℃牳涓嶉�氳繃"),
+    CANCEL(40, "宸插彇娑�"),
+    INVALID(50, "宸蹭綔搴�");
 
     private final Integer status;
     private final String name;
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/quotation/CrmSaleQuotationStatusEnum.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/quotation/CrmSaleQuotationStatusEnum.java
index e8029d4..884c7d5 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/quotation/CrmSaleQuotationStatusEnum.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/quotation/CrmSaleQuotationStatusEnum.java
@@ -7,7 +7,7 @@
 import java.util.Arrays;
 
 /**
- * CRM 閿�鍞姤浠峰鎵圭姸鎬佹灇涓�
+ * CRM 閿�鍞姤浠风姸鎬佹灇涓�
  *
  * @author 鑺嬮亾婧愮爜
  */
@@ -16,11 +16,7 @@
 public enum CrmSaleQuotationStatusEnum implements ArrayValuable<Integer> {
 
     DRAFT(0, "鑽夌"),
-    PROCESS(10, "瀹℃壒涓�"),
-    APPROVE(20, "宸查�氳繃"),
-    REJECT(30, "宸叉嫆缁�"),
-    CANCEL(40, "宸插彇娑�"),
-    CONVERTED(50, "宸茶浆鍚堝悓");
+    CONVERTED(10, "宸茶浆鍚堝悓");
 
     private final Integer status;
     private final String name;
@@ -33,4 +29,4 @@
         return ARRAYS;
     }
 
-}
\ No newline at end of file
+}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java
index a3e6ba0..80693c2 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java
@@ -67,10 +67,18 @@
     /**
      * 鍙戣捣鍚堝悓瀹℃壒娴佺▼
      *
-     * @param id     鍚堝悓缂栧彿
-     * @param userId 鐢ㄦ埛缂栧彿
+     * @param id                    鍚堝悓缂栧彿
+     * @param processDefinitionKey  娴佺▼瀹氫箟 Key
+     * @param userId                鐢ㄦ埛缂栧彿
      */
-    void submitContract(Long id, Long userId);
+    void submitContract(Long id, String processDefinitionKey, Long userId);
+
+    /**
+     * 鑾峰彇鍚堝悓瀹℃壒娴佺▼鍒楄〃
+     *
+     * @return 娴佺▼瀹氫箟鍒楄〃
+     */
+    List<Map<String, Object>> getContractApproveProcessDefinitionList();
 
     /**
      * 鏇存柊鍚堝悓娴佺▼瀹℃壒缁撴灉
@@ -211,4 +219,20 @@
      */
     Long generateSaleOrder(Long id, Long userId);
 
+    /**
+     * 鏇存柊鍚堝悓鐘舵��
+     *
+     * @param id     鍚堝悓缂栧彿
+     * @param status 鐘舵��
+     */
+    void updateContractStatus(Long id, Integer status);
+
+    /**
+     * 鏍规嵁閿�鍞鍗曠紪鍙锋洿鏂板悎鍚岀姸鎬�
+     *
+     * @param orderId 閿�鍞鍗曠紪鍙�
+     * @param status  鐘舵��
+     */
+    void updateContractStatusByOrderId(Long orderId, Integer status);
+
 }
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
index 1ce3f41..d875b2d 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
@@ -10,6 +10,9 @@
 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
 import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
+import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
+import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService;
+import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractPageReqVO;
 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractSaveReqVO;
 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractTransferReqVO;
@@ -49,10 +52,15 @@
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
+import org.flowable.engine.repository.ProcessDefinition;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
@@ -74,6 +82,11 @@
      * BPM 鍚堝悓瀹℃壒娴佺▼鏍囪瘑
      */
     public static final String BPM_PROCESS_DEFINITION_KEY = "crm-contract-audit";
+
+    /**
+     * BPM 鍚堝悓瀹℃壒鍒嗙被缂栫爜
+     */
+    private static final String CONTRACT_APPROVE_CATEGORY_CODE = "contract_approve";
 
     @Resource
     private CrmContractMapper contractMapper;
@@ -103,6 +116,10 @@
     @Resource
     private BpmProcessInstanceApi bpmProcessInstanceApi;
     @Resource
+    private BpmCategoryService bpmCategoryService;
+    @Resource
+    private BpmProcessDefinitionService bpmProcessDefinitionService;
+    @Resource
     private ErpSaleOrderApi saleOrderApi;
     @Resource
     private MdmItemApi mdmItemApi;
@@ -123,7 +140,9 @@
         }
 
         // 2.1 鎻掑叆鍚堝悓
-        CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setNo(no);
+        CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class)
+                .setNo(no)
+                .setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus()); // 榛樿涓烘湭鎻愪氦鐘舵��
         calculateTotalPrice(contract, contractProducts);
         contractMapper.insert(contract);
         // 2.2 鎻掑叆鍚堝悓鍏宠仈鍟嗗搧
@@ -308,23 +327,98 @@
     @Transactional(rollbackFor = Exception.class)
     @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_SUBMIT_SUB_TYPE, bizNo = "{{#id}}",
             success = CRM_CONTRACT_SUBMIT_SUCCESS)
-    public void submitContract(Long id, Long userId) {
+    public void submitContract(Long id, String processDefinitionKey, Long userId) {
         // 1. 鏍¢獙鍚堝悓鏄惁鍦ㄥ鎵�
         CrmContractDO contract = validateContractExists(id);
         if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) {
             throw exception(CONTRACT_SUBMIT_FAIL_NOT_DRAFT);
         }
 
-        // 2. 鍒涘缓鍚堝悓瀹℃壒娴佺▼瀹炰緥
-        String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
-                .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY).setBusinessKey(String.valueOf(id)));
+        // 2. 鏍¢獙鍒嗙被鍜屾祦绋嬪畾涔夋槸鍚﹀瓨鍦�
+        validateContractApproveCategoryAndProcessDefinition();
 
-        // 3. 鏇存柊鍚堝悓宸ヤ綔娴佺紪鍙�
+        // 3. 鏍¢獙浼犲叆鐨勬祦绋嬪畾涔� Key 鏄惁灞炰簬璇ュ垎绫讳笖澶勪簬婵�娲荤姸鎬�
+        ProcessDefinition processDefinition = bpmProcessDefinitionService.getActiveProcessDefinition(processDefinitionKey);
+        if (processDefinition == null) {
+            throw exception(CONTRACT_BPM_PROCESS_DEFINITION_NOT_EXISTS);
+        }
+
+        // 4. 鍒涘缓鍚堝悓瀹℃壒娴佺▼瀹炰緥
+        String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
+                .setProcessDefinitionKey(processDefinitionKey).setBusinessKey(String.valueOf(id)));
+
+        // 5. 鏇存柊鍚堝悓宸ヤ綔娴佺紪鍙�
         contractMapper.updateById(new CrmContractDO().setId(id).setProcessInstanceId(processInstanceId)
                 .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
 
-        // 3. 璁板綍鏃ュ織
+        // 6. 璁板綍鏃ュ織
         LogRecordContext.putVariable("contractName", contract.getName());
+    }
+
+    /**
+     * 鏍¢獙 BPM 鍚堝悓瀹℃壒鍒嗙被鍜屾祦绋嬪畾涔夋槸鍚﹀瓨鍦�
+     */
+    private void validateContractApproveCategoryAndProcessDefinition() {
+        // 1. 鏍¢獙鍒嗙被鏄惁瀛樺湪
+        List<String> codes = Collections.singletonList(CONTRACT_APPROVE_CATEGORY_CODE);
+        Map<String, ?> categoryMap = bpmCategoryService.getCategoryMap(codes);
+        if (!categoryMap.containsKey(CONTRACT_APPROVE_CATEGORY_CODE)) {
+            throw exception(CONTRACT_BPM_PROCESS_DEFINITION_NOT_EXISTS);
+        }
+
+        // 2. 鏍¢獙鍒嗙被涓嬫槸鍚︽湁鍙敤鐨勬祦绋嬪畾涔�
+        List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService
+                .getProcessDefinitionInfoListByCategory(CONTRACT_APPROVE_CATEGORY_CODE);
+        if (CollUtil.isEmpty(definitionInfoList)) {
+            throw exception(CONTRACT_BPM_PROCESS_DEFINITION_NOT_EXISTS);
+        }
+
+        // 3. 鏍¢獙鏄惁鏈夋縺娲荤姸鎬佺殑娴佺▼瀹氫箟
+        Set<String> processDefinitionIds = convertSet(definitionInfoList, BpmProcessDefinitionInfoDO::getProcessDefinitionId);
+        List<ProcessDefinition> processDefinitions = bpmProcessDefinitionService.getProcessDefinitionList(processDefinitionIds);
+        boolean hasActiveDefinition = processDefinitions.stream()
+                .anyMatch(pd -> !pd.isSuspended());
+        if (!hasActiveDefinition) {
+            throw exception(CONTRACT_BPM_PROCESS_DEFINITION_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public List<Map<String, Object>> getContractApproveProcessDefinitionList() {
+        // 1. 鏍¢獙鍒嗙被鍜屾祦绋嬪畾涔夋槸鍚﹀瓨鍦�
+        validateContractApproveCategoryAndProcessDefinition();
+
+        // 2. 鑾峰彇鍒嗙被涓嬬殑娴佺▼瀹氫箟淇℃伅
+        List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService
+                .getProcessDefinitionInfoListByCategory(CONTRACT_APPROVE_CATEGORY_CODE);
+
+        // 3. 鑾峰彇娴佺▼瀹氫箟璇︽儏
+        Set<String> processDefinitionIds = convertSet(definitionInfoList, BpmProcessDefinitionInfoDO::getProcessDefinitionId);
+        List<ProcessDefinition> processDefinitions = bpmProcessDefinitionService.getProcessDefinitionList(processDefinitionIds);
+
+        // 4. 杩囨护锛氬彧淇濈暀婵�娲荤姸鎬侊紝涓旂浉鍚� key 鍙繚鐣欐渶鏂扮増鏈�
+        Map<String, ProcessDefinition> latestVersionMap = new HashMap<>();
+        for (ProcessDefinition pd : processDefinitions) {
+            if (pd.isSuspended()) {
+                continue;
+            }
+            ProcessDefinition existing = latestVersionMap.get(pd.getKey());
+            if (existing == null || pd.getVersion() > existing.getVersion()) {
+                latestVersionMap.put(pd.getKey(), pd);
+            }
+        }
+
+        // 5. 杩斿洖娴佺▼瀹氫箟鍒楄〃
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (ProcessDefinition pd : latestVersionMap.values()) {
+            Map<String, Object> item = new HashMap<>();
+            item.put("id", pd.getId());
+            item.put("key", pd.getKey());
+            item.put("name", pd.getName());
+            item.put("version", pd.getVersion());
+            result.add(item);
+        }
+        return result;
     }
 
     @Override
@@ -462,7 +556,8 @@
         createReqDTO.setContractNo(contract.getNo());
         createReqDTO.setSaleUserId(contract.getOwnerUserId());
         createReqDTO.setOrderTime(LocalDateTime.now().toString());
-        createReqDTO.setDiscountPercent(contract.getDiscountPercent());
+        createReqDTO.setDiscountPercent(contract.getDiscountPercent() != null ? contract.getDiscountPercent() : BigDecimal.ZERO);
+        createReqDTO.setDepositPrice(contract.getDepositPrice() != null ? contract.getDepositPrice() : BigDecimal.ZERO);
         createReqDTO.setRemark("鐢卞悎鍚屻��" + contract.getNo() + "銆戣嚜鍔ㄧ敓鎴�");
 
         // 5. 鏋勫缓璁㈠崟椤�
@@ -494,4 +589,21 @@
         return orderId;
     }
 
+    @Override
+    public void updateContractStatus(Long id, Integer status) {
+        contractMapper.updateById(new CrmContractDO()
+                .setId(id)
+                .setAuditStatus(status));
+    }
+
+    @Override
+    public void updateContractStatusByOrderId(Long orderId, Integer status) {
+        CrmContractDO contract = contractMapper.selectByOrderId(orderId);
+        if (contract != null) {
+            contractMapper.updateById(new CrmContractDO()
+                    .setId(contract.getId())
+                    .setAuditStatus(status));
+        }
+    }
+
 }
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java
index ce82858..3d425ad 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java
@@ -1,31 +1,56 @@
 package cn.iocoder.yudao.module.crm.service.contract.listener;
 
 import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
+import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
+import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper;
+import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
-import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl;
 import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationListener;
 import org.springframework.stereotype.Component;
 
 /**
- * 鍚堝悓瀹℃壒鐨勭粨鏋滅殑鐩戝惉鍣ㄥ疄鐜扮被
+ * 鍚堝悓瀹℃壒鐨勭粨鏋滅洃鍚櫒瀹炵幇绫�
+ *
+ * 閫氳繃 businessKey锛堝悎鍚孖D锛夊尮閰嶏紝鑰屼笉鏄浐瀹氱殑娴佺▼瀹氫箟 Key锛�
+ * 杩欐牱鍙互鏀寔鍒嗙被涓嬩换鎰� Key 鐨勬祦绋嬫ā鍨嬨��
  *
  * @author HUIHUI
  */
 @Component
-public class CrmContractStatusListener extends BpmProcessInstanceStatusEventListener {
+@Slf4j
+public class CrmContractStatusListener implements ApplicationListener<BpmProcessInstanceStatusEvent> {
 
     @Resource
     private CrmContractService contractService;
+    @Resource
+    private CrmContractMapper contractMapper;
 
     @Override
-    public String getProcessDefinitionKey() {
-        return CrmContractServiceImpl.BPM_PROCESS_DEFINITION_KEY;
-    }
+    public void onApplicationEvent(BpmProcessInstanceStatusEvent event) {
+        // 閫氳繃 businessKey 鏌ヨ鍚堝悓
+        Long contractId;
+        try {
+            contractId = Long.parseLong(event.getBusinessKey());
+        } catch (NumberFormatException e) {
+            return; // businessKey 涓嶆槸鏁板瓧锛屽拷鐣�
+        }
 
-    @Override
-    protected void onEvent(BpmProcessInstanceStatusEvent event) {
-        contractService.updateContractAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
+        CrmContractDO contract = contractMapper.selectById(contractId);
+        if (contract == null) {
+            return; // 涓嶆槸鍚堝悓锛屽拷鐣�
+        }
+
+        // 鍙湁瀹℃壒涓姸鎬佺殑鍚堝悓鎵嶅鐞�
+        if (!CrmAuditStatusEnum.PROCESS.getStatus().equals(contract.getAuditStatus())) {
+            log.warn("[onApplicationEvent] 鍚堝悓({}) 涓嶅浜庡鎵逛腑鐘舵�侊紝褰撳墠鐘舵��: {}", contractId, contract.getAuditStatus());
+            return;
+        }
+
+        log.info("[onApplicationEvent] 鍚堝悓({}) 瀹℃壒鐘舵�佹洿鏂�: {}", contractId, event.getStatus());
+        // 鏇存柊瀹℃壒鐘舵��
+        contractService.updateContractAuditStatus(contractId, event.getStatus());
     }
 
 }
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationService.java
index 3170988..2f15d35 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationService.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationService.java
@@ -8,7 +8,6 @@
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 
 /**
  * CRM 閿�鍞姤浠峰崟 Service 鎺ュ彛
@@ -88,30 +87,6 @@
      * @return 浜у搧鏄庣粏鍒楄〃
      */
     List<CrmSaleQuotationProductDO> getSaleQuotationProductListByQuotationIds(Collection<Long> quotationIds);
-
-    /**
-     * 鎻愪氦閿�鍞姤浠峰崟瀹℃壒
-     *
-     * @param id                    鎶ヤ环鍗曠紪鍙�
-     * @param processDefinitionKey  娴佺▼瀹氫箟 Key
-     * @param userId                鐢ㄦ埛缂栧彿
-     */
-    void submitSaleQuotation(Long id, String processDefinitionKey, Long userId);
-
-    /**
-     * 鏇存柊閿�鍞姤浠峰崟瀹℃壒鐘舵��
-     *
-     * @param id        鎶ヤ环鍗曠紪鍙�
-     * @param bpmResult BPM 瀹℃壒缁撴灉
-     */
-    void updateSaleQuotationAuditStatus(Long id, Integer bpmResult);
-
-    /**
-     * 鑾峰彇閿�鍞姤浠峰鎵规祦绋嬪垪琛�
-     *
-     * @return 娴佺▼瀹氫箟鍒楄〃
-     */
-    List<Map<String, Object>> getSaleQuotationApproveProcessDefinitionList();
 
     /**
      * 杞负鍚堝悓
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationServiceImpl.java
index 6a3f4d8..e5ad277 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationServiceImpl.java
@@ -1,16 +1,9 @@
 package cn.iocoder.yudao.module.crm.service.quotation;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.lang.Assert;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
-import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
-import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
-import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
-import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService;
-import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractSaveReqVO;
 import cn.iocoder.yudao.module.crm.controller.admin.quotation.vo.CrmSaleQuotationPageReqVO;
 import cn.iocoder.yudao.module.crm.controller.admin.quotation.vo.CrmSaleQuotationSaveReqVO;
@@ -33,7 +26,6 @@
 import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
-import org.flowable.engine.repository.ProcessDefinition;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -54,11 +46,6 @@
 @Validated
 @Slf4j
 public class CrmSaleQuotationServiceImpl implements CrmSaleQuotationService {
-
-    /**
-     * 閿�鍞姤浠� BPM 鍒嗙被缂栫爜
-     */
-    private static final String SALE_QUOTATION_APPROVE_CATEGORY_CODE = "sale_quotation_approve";
 
     @Resource
     private CrmSaleQuotationMapper saleQuotationMapper;
@@ -81,13 +68,6 @@
     private CrmPermissionService permissionService;
     @Resource
     private CrmContractService contractService;
-
-    @Resource
-    private BpmCategoryService bpmCategoryService;
-    @Resource
-    private BpmProcessDefinitionService bpmProcessDefinitionService;
-    @Resource
-    private BpmProcessInstanceApi bpmProcessInstanceApi;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -186,7 +166,8 @@
                 throw exception(SALE_QUOTATION_ITEM_NOT_EXISTS);
             }
             item.setItemUnitId(mdmItem.getUnitMeasureId());
-            item.setItemPrice(mdmItem.getSalesPrice());
+            // 鐗╂枡鍘熶环锛屽鏋� MDM 涓病鏈夊垯榛樿涓� 0
+            item.setItemPrice(mdmItem.getSalesPrice() != null ? mdmItem.getSalesPrice() : BigDecimal.ZERO);
             if (item.getQuotationPrice() != null && item.getCount() != null) {
                 item.setTotalPrice(MoneyUtils.priceMultiply(item.getQuotationPrice(), item.getCount()));
                 if (item.getTaxPercent() != null) {
@@ -276,138 +257,11 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void submitSaleQuotation(Long id, String processDefinitionKey, Long userId) {
+    public Long convertToContract(Long id, Long userId) {
         // 1. 鏍¢獙鎶ヤ环鍗曞瓨鍦ㄤ笖涓鸿崏绋跨姸鎬�
         CrmSaleQuotationDO saleQuotation = validateSaleQuotationExists(id);
         if (!CrmSaleQuotationStatusEnum.DRAFT.getStatus().equals(saleQuotation.getStatus())) {
-            throw exception(SALE_QUOTATION_SUBMIT_FAIL_NOT_DRAFT);
-        }
-
-        // 2. 鏍¢獙鍒嗙被鍜屾祦绋嬪畾涔夋槸鍚﹀瓨鍦�
-        validateSaleQuotationApproveCategoryAndProcessDefinition();
-
-        // 3. 鏍¢獙浼犲叆鐨勬祦绋嬪畾涔� Key 鏄惁灞炰簬璇ュ垎绫讳笖澶勪簬婵�娲荤姸鎬�
-        ProcessDefinition processDefinition = bpmProcessDefinitionService.getActiveProcessDefinition(processDefinitionKey);
-        if (processDefinition == null) {
-            throw exception(SALE_QUOTATION_BPM_PROCESS_DEFINITION_NOT_EXISTS);
-        }
-
-        // 4. 鍒涘缓娴佺▼瀹炰緥
-        String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId,
-                new BpmProcessInstanceCreateReqDTO()
-                        .setProcessDefinitionKey(processDefinitionKey)
-                        .setBusinessKey(String.valueOf(id)));
-
-        // 5. 鏇存柊鎶ヤ环鍗曠姸鎬�
-        saleQuotationMapper.updateById(new CrmSaleQuotationDO()
-                .setId(id)
-                .setProcessInstanceId(processInstanceId)
-                .setStatus(CrmSaleQuotationStatusEnum.PROCESS.getStatus()));
-    }
-
-    /**
-     * 鏍¢獙 BPM 閿�鍞姤浠峰鎵瑰垎绫诲拰娴佺▼瀹氫箟鏄惁瀛樺湪
-     */
-    private void validateSaleQuotationApproveCategoryAndProcessDefinition() {
-        // 1. 鏍¢獙鍒嗙被鏄惁瀛樺湪
-        List<String> codes = Collections.singletonList(SALE_QUOTATION_APPROVE_CATEGORY_CODE);
-        Map<String, ?> categoryMap = bpmCategoryService.getCategoryMap(codes);
-        if (!categoryMap.containsKey(SALE_QUOTATION_APPROVE_CATEGORY_CODE)) {
-            throw exception(SALE_QUOTATION_BPM_CATEGORY_NOT_EXISTS);
-        }
-
-        // 2. 鏍¢獙鍒嗙被涓嬫槸鍚︽湁鍙敤鐨勬祦绋嬪畾涔�
-        List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService
-                .getProcessDefinitionInfoListByCategory(SALE_QUOTATION_APPROVE_CATEGORY_CODE);
-        if (CollUtil.isEmpty(definitionInfoList)) {
-            throw exception(SALE_QUOTATION_BPM_PROCESS_DEFINITION_NOT_EXISTS);
-        }
-
-        // 3. 鏍¢獙鏄惁鏈夋縺娲荤姸鎬佺殑娴佺▼瀹氫箟
-        Set<String> processDefinitionIds = convertSet(definitionInfoList, BpmProcessDefinitionInfoDO::getProcessDefinitionId);
-        List<ProcessDefinition> processDefinitions = bpmProcessDefinitionService.getProcessDefinitionList(processDefinitionIds);
-        boolean hasActiveDefinition = processDefinitions.stream()
-                .anyMatch(pd -> !pd.isSuspended());
-        if (!hasActiveDefinition) {
-            throw exception(SALE_QUOTATION_BPM_PROCESS_DEFINITION_NOT_EXISTS);
-        }
-    }
-
-    @Override
-    public void updateSaleQuotationAuditStatus(Long id, Integer bpmResult) {
-        // 1. 鏍¢獙鎶ヤ环鍗曞瓨鍦ㄤ笖涓哄鎵逛腑鐘舵��
-        CrmSaleQuotationDO saleQuotation = validateSaleQuotationExists(id);
-        if (!CrmSaleQuotationStatusEnum.PROCESS.getStatus().equals(saleQuotation.getStatus())) {
-            log.error("[updateSaleQuotationAuditStatus] 鎶ヤ环鍗�({}) 涓嶅浜庡鎵逛腑", id);
-            throw exception(SALE_QUOTATION_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS);
-        }
-
-        // 2. 杞崲瀹℃壒缁撴灉
-        Integer auditStatus = convertBpmResultToAuditStatus(bpmResult);
-        saleQuotationMapper.updateById(new CrmSaleQuotationDO()
-                .setId(id)
-                .setStatus(auditStatus));
-    }
-
-    /**
-     * BPM 瀹℃壒缁撴灉杞崲
-     */
-    private Integer convertBpmResultToAuditStatus(Integer bpmResult) {
-        Integer auditStatus = BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)
-                ? CrmSaleQuotationStatusEnum.APPROVE.getStatus()
-                : BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)
-                ? CrmSaleQuotationStatusEnum.REJECT.getStatus()
-                : BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)
-                ? CrmSaleQuotationStatusEnum.CANCEL.getStatus() : null;
-        Assert.notNull(auditStatus, "BPM 瀹℃壒缁撴灉({}) 杞崲澶辫触", bpmResult);
-        return auditStatus;
-    }
-
-    @Override
-    public List<Map<String, Object>> getSaleQuotationApproveProcessDefinitionList() {
-        // 1. 鏍¢獙鍒嗙被鍜屾祦绋嬪畾涔夋槸鍚﹀瓨鍦�
-        validateSaleQuotationApproveCategoryAndProcessDefinition();
-
-        // 2. 鑾峰彇鍒嗙被涓嬬殑娴佺▼瀹氫箟淇℃伅
-        List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService
-                .getProcessDefinitionInfoListByCategory(SALE_QUOTATION_APPROVE_CATEGORY_CODE);
-
-        // 3. 鑾峰彇娴佺▼瀹氫箟璇︽儏
-        Set<String> processDefinitionIds = convertSet(definitionInfoList, BpmProcessDefinitionInfoDO::getProcessDefinitionId);
-        List<ProcessDefinition> processDefinitions = bpmProcessDefinitionService.getProcessDefinitionList(processDefinitionIds);
-
-        // 4. 杩囨护锛氬彧淇濈暀婵�娲荤姸鎬侊紝涓旂浉鍚� key 鍙繚鐣欐渶鏂扮増鏈�
-        Map<String, ProcessDefinition> latestVersionMap = new HashMap<>();
-        for (ProcessDefinition pd : processDefinitions) {
-            if (pd.isSuspended()) {
-                continue;
-            }
-            ProcessDefinition existing = latestVersionMap.get(pd.getKey());
-            if (existing == null || pd.getVersion() > existing.getVersion()) {
-                latestVersionMap.put(pd.getKey(), pd);
-            }
-        }
-
-        // 5. 杩斿洖娴佺▼瀹氫箟鍒楄〃
-        List<Map<String, Object>> result = new ArrayList<>();
-        for (ProcessDefinition pd : latestVersionMap.values()) {
-            Map<String, Object> item = new HashMap<>();
-            item.put("id", pd.getId());
-            item.put("key", pd.getKey());
-            item.put("name", pd.getName());
-            item.put("version", pd.getVersion());
-            result.add(item);
-        }
-        return result;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Long convertToContract(Long id, Long userId) {
-        // 1. 鏍¢獙鎶ヤ环鍗曞瓨鍦ㄤ笖宸插鎵归�氳繃
-        CrmSaleQuotationDO saleQuotation = validateSaleQuotationExists(id);
-        if (!CrmSaleQuotationStatusEnum.APPROVE.getStatus().equals(saleQuotation.getStatus())) {
-            throw exception(SALE_QUOTATION_NOT_APPROVE);
+            throw exception(SALE_QUOTATION_CONVERT_FAIL_NOT_DRAFT, saleQuotation.getNo());
         }
         // 鏍¢獙鏄惁宸茶浆鍚堝悓
         if (saleQuotation.getContractId() != null) {
@@ -437,7 +291,7 @@
         });
         contractVO.setProducts(contractProducts);
 
-        // 4. 鍒涘缓鍚堝悓
+        // 4. 鍒涘缓鍚堝悓锛堜細鑷姩妫�娴嬪悎鍚屽鎵规祦绋嬪苟鎻愪氦瀹℃壒锛�
         Long contractId = contractService.createContract(contractVO, userId);
 
         // 5. 鏇存柊鎶ヤ环鍗曞叧鑱斾俊鎭�
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/listener/CrmSaleQuotationStatusListener.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/listener/CrmSaleQuotationStatusListener.java
deleted file mode 100644
index ee11882..0000000
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/listener/CrmSaleQuotationStatusListener.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package cn.iocoder.yudao.module.crm.service.quotation.listener;
-
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
-import cn.iocoder.yudao.module.crm.dal.dataobject.quotation.CrmSaleQuotationDO;
-import cn.iocoder.yudao.module.crm.dal.mysql.quotation.CrmSaleQuotationMapper;
-import cn.iocoder.yudao.module.crm.enums.quotation.CrmSaleQuotationStatusEnum;
-import cn.iocoder.yudao.module.crm.service.quotation.CrmSaleQuotationService;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.ApplicationListener;
-import org.springframework.stereotype.Component;
-
-/**
- * 閿�鍞姤浠峰鎵圭殑缁撴灉鐩戝惉鍣ㄥ疄鐜扮被
- *
- * 閫氳繃 businessKey锛堟姤浠峰崟ID锛夊尮閰嶏紝鑰屼笉鏄浐瀹氱殑娴佺▼瀹氫箟 Key锛�
- * 杩欐牱鍙互鏀寔鍒嗙被涓嬩换鎰� Key 鐨勬祦绋嬫ā鍨嬨��
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Component
-@Slf4j
-public class CrmSaleQuotationStatusListener implements ApplicationListener<BpmProcessInstanceStatusEvent> {
-
-    @Resource
-    private CrmSaleQuotationService saleQuotationService;
-    @Resource
-    private CrmSaleQuotationMapper saleQuotationMapper;
-
-    @Override
-    public void onApplicationEvent(BpmProcessInstanceStatusEvent event) {
-        // 閫氳繃 businessKey 鏌ヨ鎶ヤ环鍗�
-        Long quotationId;
-        try {
-            quotationId = Long.parseLong(event.getBusinessKey());
-        } catch (NumberFormatException e) {
-            return; // businessKey 涓嶆槸鏁板瓧锛屽拷鐣�
-        }
-
-        CrmSaleQuotationDO saleQuotation = saleQuotationMapper.selectById(quotationId);
-        if (saleQuotation == null) {
-            return; // 涓嶆槸閿�鍞姤浠凤紝蹇界暐
-        }
-
-        // 鍙湁瀹℃壒涓姸鎬佺殑鎶ヤ环鍗曟墠澶勭悊
-        if (!CrmSaleQuotationStatusEnum.PROCESS.getStatus().equals(saleQuotation.getStatus())) {
-            log.warn("[onApplicationEvent] 閿�鍞姤浠峰崟({}) 涓嶅浜庡鎵逛腑鐘舵�侊紝褰撳墠鐘舵��: {}", quotationId, saleQuotation.getStatus());
-            return;
-        }
-
-        log.info("[onApplicationEvent] 閿�鍞姤浠峰崟({}) 瀹℃壒鐘舵�佹洿鏂�: {}", quotationId, event.getStatus());
-        // 鏇存柊瀹℃壒鐘舵��
-        saleQuotationService.updateSaleQuotationAuditStatus(quotationId, event.getStatus());
-    }
-
-}
\ No newline at end of file
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
index 383a7d9..f0211bd 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
@@ -83,6 +83,24 @@
         return success(true);
     }
 
+    @PutMapping("/cancel")
+    @Operation(summary = "浣滃簾閿�鍞鍗�")
+    @Parameter(name = "id", description = "缂栧彿", required = true)
+    @PreAuthorize("@ss.hasPermission('erp:sale-order:cancel')")
+    public CommonResult<Boolean> cancelSaleOrder(@RequestParam("id") Long id) {
+        saleOrderService.cancelSaleOrder(id);
+        return success(true);
+    }
+
+    @PutMapping("/enable")
+    @Operation(summary = "閲嶆柊鍚敤閿�鍞鍗�")
+    @Parameter(name = "id", description = "缂栧彿", required = true)
+    @PreAuthorize("@ss.hasPermission('erp:sale-order:enable')")
+    public CommonResult<Boolean> enableSaleOrder(@RequestParam("id") Long id) {
+        saleOrderService.enableSaleOrder(id);
+        return success(true);
+    }
+
     @DeleteMapping("/delete")
     @Operation(summary = "鍒犻櫎閿�鍞鍗�")
     @Parameter(name = "ids", description = "缂栧彿鏁扮粍", required = true)
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
index b1374e8..59a9ae9 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
@@ -33,6 +33,12 @@
     @ExcelProperty("瀹㈡埛鍚嶇О")
     private String customerName;
 
+    @Schema(description = "鍏宠仈鍚堝悓缂栧彿", example = "1")
+    private Long contractId;
+    @Schema(description = "鍚堝悓鍗曞彿", example = "HT001")
+    @ExcelProperty("鍚堝悓鍗曞彿")
+    private String contractNo;
+
     @Schema(description = "缁撶畻璐︽埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89")
     @ExcelProperty("缁撶畻璐︽埛缂栧彿")
     private Long accountId;
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java
index 42c0174..81412f1 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java
@@ -18,7 +18,8 @@
 public enum ErpAuditStatus implements ArrayValuable<Integer> {
 
     PROCESS(10, "鏈鏍�"), // 瀹℃牳涓�
-    APPROVE(20, "宸插鏍�"); // 瀹℃牳閫氳繃
+    APPROVE(20, "宸插鏍�"), // 瀹℃牳閫氳繃
+    CANCEL(30, "宸蹭綔搴�"); // 宸蹭綔搴�/宸叉挙閿�
 
     public static final Integer[] ARRAYS = Arrays.stream(values()).map(ErpAuditStatus::getStatus).toArray(Integer[]::new);
 
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
index c7ccb51..08d75e0 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
@@ -78,6 +78,12 @@
     ErrorCode SALE_ORDER_PROCESS_FAIL_EXISTS_OUT = new ErrorCode(1_020_201_008, "鍙嶅鏍稿け璐ワ紝宸插瓨鍦ㄥ搴旂殑閿�鍞嚭搴撳崟");
     ErrorCode SALE_ORDER_ITEM_RETURN_FAIL_OUT_EXCEED = new ErrorCode(1_020_201_009, "閿�鍞鍗曢」({})瓒呰繃鏈�澶у厑璁搁��璐ф暟閲�({})");
     ErrorCode SALE_ORDER_PROCESS_FAIL_EXISTS_RETURN = new ErrorCode(1_020_201_010, "鍙嶅鏍稿け璐ワ紝宸插瓨鍦ㄥ搴旂殑閿�鍞��璐у崟");
+    ErrorCode SALE_ORDER_CANCEL_FAIL_NOT_APPROVE = new ErrorCode(1_020_201_011, "浣滃簾澶辫触锛岄攢鍞鍗�({})鏈鏍革紝鍙湁宸插鏍哥殑璁㈠崟鎵嶈兘浣滃簾");
+    ErrorCode SALE_ORDER_CANCEL_FAIL_EXISTS_OUT = new ErrorCode(1_020_201_012, "浣滃簾澶辫触锛屽凡瀛樺湪瀵瑰簲鐨勯攢鍞嚭搴撳崟");
+    ErrorCode SALE_ORDER_CANCEL_FAIL_EXISTS_RETURN = new ErrorCode(1_020_201_013, "浣滃簾澶辫触锛屽凡瀛樺湪瀵瑰簲鐨勯攢鍞��璐у崟");
+    ErrorCode SALE_ORDER_CANCEL_FAIL = new ErrorCode(1_020_201_014, "浣滃簾澶辫触锛岃鍒锋柊椤甸潰鍚庨噸璇�");
+    ErrorCode SALE_ORDER_ENABLE_FAIL_NOT_CANCEL = new ErrorCode(1_020_201_015, "鍚敤澶辫触锛岄攢鍞鍗�({})鏈綔搴燂紝鍙湁宸蹭綔搴熺殑璁㈠崟鎵嶈兘閲嶆柊鍚敤");
+    ErrorCode SALE_ORDER_ENABLE_FAIL = new ErrorCode(1_020_201_016, "鍚敤澶辫触锛岃鍒锋柊椤甸潰鍚庨噸璇�");
 
     // ========== ERP 閿�鍞嚭搴擄紙1-030-202-000锛� ==========
     ErrorCode SALE_OUT_NOT_EXISTS = new ErrorCode(1_020_202_000, "閿�鍞嚭搴撳崟涓嶅瓨鍦�");
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java
index c75f201..b715e27 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java
@@ -43,6 +43,20 @@
     void updateSaleOrderStatus(Long id, Integer status);
 
     /**
+     * 浣滃簾閿�鍞鍗�
+     *
+     * @param id 缂栧彿
+     */
+    void cancelSaleOrder(Long id);
+
+    /**
+     * 閲嶆柊鍚敤閿�鍞鍗�
+     *
+     * @param id 缂栧彿
+     */
+    void enableSaleOrder(Long id);
+
+    /**
      * 鏇存柊閿�鍞鍗曠殑鍑哄簱鏁伴噺
      *
      * @param id 缂栧彿
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
index c3bf261..17c99a9 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
@@ -6,6 +6,7 @@
 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
+import cn.iocoder.yudao.module.crm.api.contract.CrmContractApi;
 import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO;
 import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO;
 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
@@ -56,6 +57,8 @@
     private ErpProductService productService;
     @Resource
     private CrmCustomerApi customerApi;
+    @Resource
+    private CrmContractApi contractApi;
     @Resource
     private ErpAccountService accountService;
 
@@ -147,11 +150,13 @@
             throw exception(approve ? SALE_ORDER_APPROVE_FAIL : SALE_ORDER_PROCESS_FAIL);
         }
         // 1.3 瀛樺湪閿�鍞嚭搴撳崟锛屾棤娉曞弽瀹℃牳
-        if (!approve && saleOrder.getOutCount().compareTo(BigDecimal.ZERO) > 0) {
+        BigDecimal outCount = saleOrder.getOutCount() != null ? saleOrder.getOutCount() : BigDecimal.ZERO;
+        if (!approve && outCount.compareTo(BigDecimal.ZERO) > 0) {
             throw exception(SALE_ORDER_PROCESS_FAIL_EXISTS_OUT);
         }
         // 1.4 瀛樺湪閿�鍞��璐у崟锛屾棤娉曞弽瀹℃牳
-        if (!approve && saleOrder.getReturnCount().compareTo(BigDecimal.ZERO) > 0) {
+        BigDecimal returnCount = saleOrder.getReturnCount() != null ? saleOrder.getReturnCount() : BigDecimal.ZERO;
+        if (!approve && returnCount.compareTo(BigDecimal.ZERO) > 0) {
             throw exception(SALE_ORDER_PROCESS_FAIL_EXISTS_RETURN);
         }
 
@@ -163,6 +168,62 @@
         }
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void cancelSaleOrder(Long id) {
+        // 1.1 鏍¢獙瀛樺湪
+        ErpSaleOrderDO saleOrder = validateSaleOrderExists(id);
+        // 1.2 鏍¢獙鐘舵�侊細鍙湁宸插鏍哥殑璁㈠崟鎵嶈兘浣滃簾
+        if (!ErpAuditStatus.APPROVE.getStatus().equals(saleOrder.getStatus())) {
+            throw exception(SALE_ORDER_CANCEL_FAIL_NOT_APPROVE, saleOrder.getNo());
+        }
+        // 1.3 瀛樺湪閿�鍞嚭搴撳崟锛屾棤娉曚綔搴�
+        BigDecimal outCount = saleOrder.getOutCount() != null ? saleOrder.getOutCount() : BigDecimal.ZERO;
+        if (outCount.compareTo(BigDecimal.ZERO) > 0) {
+            throw exception(SALE_ORDER_CANCEL_FAIL_EXISTS_OUT);
+        }
+        // 1.4 瀛樺湪閿�鍞��璐у崟锛屾棤娉曚綔搴�
+        BigDecimal returnCount = saleOrder.getReturnCount() != null ? saleOrder.getReturnCount() : BigDecimal.ZERO;
+        if (returnCount.compareTo(BigDecimal.ZERO) > 0) {
+            throw exception(SALE_ORDER_CANCEL_FAIL_EXISTS_RETURN);
+        }
+
+        // 2. 鏇存柊鐘舵�佷负宸蹭綔搴�
+        int updateCount = saleOrderMapper.updateByIdAndStatus(id, saleOrder.getStatus(),
+                new ErpSaleOrderDO().setStatus(ErpAuditStatus.CANCEL.getStatus()));
+        if (updateCount == 0) {
+            throw exception(SALE_ORDER_CANCEL_FAIL);
+        }
+
+        // 3. 鍚屾鏇存柊鍏宠仈鍚堝悓鐘舵�佷负宸蹭綔搴�
+        if (saleOrder.getContractId() != null) {
+            contractApi.updateContractStatus(saleOrder.getContractId(), 50).getCheckedData(); // 50 = 宸蹭綔搴�
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void enableSaleOrder(Long id) {
+        // 1.1 鏍¢獙瀛樺湪
+        ErpSaleOrderDO saleOrder = validateSaleOrderExists(id);
+        // 1.2 鏍¢獙鐘舵�侊細鍙湁宸蹭綔搴熺殑璁㈠崟鎵嶈兘閲嶆柊鍚敤
+        if (!ErpAuditStatus.CANCEL.getStatus().equals(saleOrder.getStatus())) {
+            throw exception(SALE_ORDER_ENABLE_FAIL_NOT_CANCEL, saleOrder.getNo());
+        }
+
+        // 2. 鏇存柊鐘舵�佷负宸插鏍�
+        int updateCount = saleOrderMapper.updateByIdAndStatus(id, saleOrder.getStatus(),
+                new ErpSaleOrderDO().setStatus(ErpAuditStatus.APPROVE.getStatus()));
+        if (updateCount == 0) {
+            throw exception(SALE_ORDER_ENABLE_FAIL);
+        }
+
+        // 3. 鍚屾鏇存柊鍏宠仈鍚堝悓鐘舵�佷负瀹℃牳閫氳繃
+        if (saleOrder.getContractId() != null) {
+            contractApi.updateContractStatus(saleOrder.getContractId(), 20).getCheckedData(); // 20 = 瀹℃牳閫氳繃
+        }
+    }
+
     private List<ErpSaleOrderItemDO> validateSaleOrderItems(List<ErpSaleOrderSaveReqVO.Item> list) {
         // 1. 鏍¢獙浜у搧瀛樺湪
         List<ErpProductDO> productList = productService.validProductList(

--
Gitblit v1.9.3