From 641206421e76861db238ecf24094b2a04e7c6371 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 26 八月 2026 15:50:26 +0800
Subject: [PATCH] feat(account): 新增付款和回款功能并优化生产计划下发规则

---
 src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java |   63 ++++
 src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml                  |    8 
 src/main/resources/mapper/basic/CustomerMapper.xml                                           |   22 +
 src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml                     |    8 
 src/main/resources/mapper/basic/SupplierManageMapper.xml                                     |   32 +
 .mcp.json                                                                                    |   21 +
 src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java             |    9 
 src/main/java/com/ruoyi/basic/pojo/SupplierManage.java                                       |    4 
 sql/product-inventory-management-new-pro.sql                                                 |    1 
 src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java    |   44 +++
 src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java                     |   12 
 src/main/resources/mapper/sales/SalesLedgerProductMapper.xml                                 |    2 
 src/main/java/com/ruoyi/basic/excel/SupplierManageExcelDto.java                              |    3 
 src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java               |   94 +------
 src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java            |    2 
 src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java                  |   11 
 src/main/java/com/ruoyi/purchase/dto/SavePaymentDto.java                                     |   35 ++
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java              |    3 
 src/main/resources/application-dev.yml                                                       |    2 
 doc/20260826_生产计划与销售发货数量规则前端联调文档.md                                                          |  331 +++++++++++++++++++++++++
 src/main/java/com/ruoyi/sales/dto/SaveReceiptPaymentDto.java                                 |   35 ++
 src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java               |    2 
 src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java          |    9 
 23 files changed, 648 insertions(+), 105 deletions(-)

diff --git a/.mcp.json b/.mcp.json
new file mode 100644
index 0000000..88094b6
--- /dev/null
+++ b/.mcp.json
@@ -0,0 +1,21 @@
+{
+  "mcpServers": {
+    "mysql": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "@benborla29/mcp-server-mysql"
+      ],
+      "env": {
+        "MYSQL_HOST": "127.0.0.1",
+        "MYSQL_PORT": "3306",
+        "MYSQL_USER": "root",
+        "MYSQL_PASS": "123456",
+        "MYSQL_DB": "product-inventory-management-new-pro",
+        "ALLOW_INSERT_OPERATION": "false",
+        "ALLOW_UPDATE_OPERATION": "false",
+        "ALLOW_DELETE_OPERATION": "false"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git "a/doc/20260826_\347\224\237\344\272\247\350\256\241\345\210\222\344\270\216\351\224\200\345\224\256\345\217\221\350\264\247\346\225\260\351\207\217\350\247\204\345\210\231\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260826_\347\224\237\344\272\247\350\256\241\345\210\222\344\270\216\351\224\200\345\224\256\345\217\221\350\264\247\346\225\260\351\207\217\350\247\204\345\210\231\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..ad73a4e
--- /dev/null
+++ "b/doc/20260826_\347\224\237\344\272\247\350\256\241\345\210\222\344\270\216\351\224\200\345\224\256\345\217\221\350\264\247\346\225\260\351\207\217\350\247\204\345\210\231\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,331 @@
+# 鐢熶骇璁″垝涓庨攢鍞彂璐ф暟閲忚鍒欏墠绔仈璋冩枃妗�
+
+鏇存柊鏃堕棿锛�2026-08-26
+
+## 1. 鏈璋冩暣姒傝堪
+
+### 1.1 鐢熶骇璁″垝涓嬪彂
+
+鐢熶骇璁″垝涓嬪彂涓嶅啀鍙椾互涓嬭鍒欓檺鍒讹細
+
+- 涓嶅啀闄愬埗鏈涓嬪彂鏁伴噺涓嶈兘瓒呰繃闇�姹傛暟閲忓墿浣欓噺銆�
+- 宸蹭笅鍙戞暟閲忚揪鍒伴渶姹傛暟閲忓悗锛屼粛鍙互缁х画涓嬪彂銆�
+- `quantityIssued` 鍏佽绱瓒呰繃 `qtyRequired`銆�
+
+浠嶇劧淇濈暀浠ヤ笅鏍¢獙锛�
+
+- 鑷冲皯閫夋嫨涓�涓敓浜ц鍒掋��
+- `totalAssignedQuantity` 蹇呴』澶т簬 0銆�
+- 閫夋嫨鐨勭敓浜ц鍒掑繀椤诲瓨鍦ㄣ��
+- 鍚堝苟涓嬪彂鐨勭敓浜ц鍒掑繀椤诲睘浜庡悓涓�涓骇鍝佸瀷鍙枫��
+
+### 1.2 閿�鍞彂璐�
+
+閿�鍞彂璐т笉鍐嶅彈浠ヤ笅瑙勫垯闄愬埗锛�
+
+- 涓嶅啀鍙楅攢鍞骇鍝� `quantity` 闄愬埗銆�
+- 涓嶅啀鍙楀凡鍙戣揣鏁伴噺闄愬埗銆�
+- 涓嶅啀鍙楀緟瀹℃壒鍙戣揣鏁伴噺闄愬埗銆�
+- 閿�鍞骇鍝佸凡鏄剧ず鈥滃凡鍙戣揣鈥濆悗锛屼粛鍙互缁х画鎻愪氦鍙戣揣銆�
+
+閿�鍞彂璐т粛鐒跺繀椤绘弧瓒冲簱瀛樻牎楠岋細
+
+```text
+鍙敤搴撳瓨 = 搴撳瓨鏁伴噺 - 鍐荤粨搴撳瓨 - 寰呭嚭搴撴暟閲�
+```
+
+鍙戣揣鏁伴噺瓒呰繃鍙敤搴撳瓨鏃讹紝鎺ュ彛浠嶇劧杩斿洖澶辫触銆�
+
+## 2. 閫氱敤鍝嶅簲
+
+鎴愬姛鍝嶅簲绀轰緥锛�
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": true
+}
+```
+
+澶辫触鍝嶅簲绀轰緥锛�
+
+```json
+{
+  "code": 500,
+  "msg": "涓嬪彂澶辫触锛屼笅鍙戞暟閲忓繀椤诲ぇ浜�0",
+  "data": null
+}
+```
+
+## 3. 鐢熶骇璁″垝涓嬪彂
+
+### 3.1 鎺ュ彛鍦板潃
+
+```text
+POST /productionPlan/combine
+```
+
+### 3.2 璇锋眰浣�
+
+```json
+{
+  "ids": [101, 102],
+  "totalAssignedQuantity": 500,
+  "planCompleteTime": "2026-08-30"
+}
+```
+
+瀛楁璇存槑锛�
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+| --- | --- | --- | --- |
+| `ids` | `number[]` | 鏄� | 瑕佷笅鍙戠殑鐢熶骇璁″垝 ID 闆嗗悎锛屽缓璁墠绔幓閲� |
+| `totalAssignedQuantity` | `number` | 鏄� | 鏈鎬荤敓浜ф暟閲忥紝鍙渶澶т簬 0锛屼笉鍐嶄笌闇�姹傚墿浣欐暟閲忔瘮杈� |
+| `planCompleteTime` | `string` | 鍚� | 璁″垝瀹屾垚鏃ユ湡锛屾牸寮� `yyyy-MM-dd` |
+
+### 3.3 鍓嶇澶勭悊瑕佹眰
+
+1. 涓嬪彂鏁伴噺杈撳叆妗嗗彧鏍¢獙澶т簬 0锛屼笉瑕佸啀璁剧疆鈥滃墿浣欓渶姹傛�婚噺鈥濅綔涓烘渶澶у�笺��
+2. 鐢熶骇璁″垝 `status=2` 鐨勮褰曞厑璁稿啀娆″嬀閫夊拰涓嬪彂銆�
+3. 涓嶈鍥犱负 `quantityIssued >= qtyRequired` 绂佺敤涓嬪彂鎸夐挳銆�
+4. 涓嬪彂鎴愬姛鍚庡埛鏂扮敓浜ц鍒掑垪琛ㄥ拰鐢熶骇璁㈠崟鍒楄〃銆�
+5. `quantityIssued` 鍙兘澶т簬 `qtyRequired`锛屽墠绔笉瑕佸仛瓒呴噺鎴柇鎴栧紓甯告彁绀恒��
+6. 浠嶇劧绂佹閫夋嫨涓嶅悓浜у搧鍨嬪彿鐨勮鍒掕繘琛屽悎骞朵笅鍙戯紝鍚庣浼氬啀娆℃牎楠屻��
+
+### 3.4 鐢熶骇璁″垝鐘舵��
+
+| 鐘舵�佸�� | 鍚箟 |
+| --- | --- |
+| `0` | 鏈笅鍙� |
+| `1` | 閮ㄥ垎涓嬪彂 |
+| `2` | 宸蹭笅鍙� |
+
+娉ㄦ剰锛氱姸鎬� `2` 鐜板湪鍙〃绀哄師闇�姹傛暟閲忓凡瀹屾垚锛屼笉浠h〃璇ヨ鍒掍笉鑳藉啀娆′笅鍙戙�傜姸鎬佷负 `2` 鐨勮鍒掑啀娆′笅鍙戝悗锛岀姸鎬佷粛鍙兘淇濇寔 `2`锛屽悓鏃� `quantityIssued` 浼氱户缁疮璁°��
+
+### 3.5 鑱旇皟鍦烘櫙
+
+#### 鍦烘櫙涓�锛氫笅鍙戞暟閲忚秴杩囬渶姹傛暟閲�
+
+鍋囪锛�
+
+- 闇�姹傛暟閲忥細100
+- 宸蹭笅鍙戞暟閲忥細100
+- 鏈涓嬪彂鏁伴噺锛�20
+
+璇锋眰锛�
+
+```json
+{
+  "ids": [101],
+  "totalAssignedQuantity": 20
+}
+```
+
+棰勬湡锛�
+
+- 璇锋眰鎴愬姛銆�
+- 鏂板缓鐢熶骇璁㈠崟鏁伴噺涓� 20銆�
+- 鐢熶骇璁″垝 `quantityIssued` 鏇存柊涓� 120銆�
+- 涓嶈繑鍥炩�滀笉鑳藉ぇ浜庤鍒掑墿浣欓渶姹傛�婚噺鈥濄��
+
+#### 鍦烘櫙浜岋細涓�娆¢�夋嫨澶氫釜鍚屽瀷鍙疯鍒�
+
+```json
+{
+  "ids": [101, 102, 103],
+  "totalAssignedQuantity": 500
+}
+```
+
+棰勬湡鐢熶骇璁㈠崟鐨勬�绘暟閲忎负 500锛屼笉鍐嶆牴鎹悇璁″垝闇�姹傛暟閲忔埅鏂��
+
+#### 鍦烘櫙涓夛細閫夋嫨涓嶅悓鍨嬪彿璁″垝
+
+璇锋眰浠嶇劧澶辫触锛屾彁绀烘墍閫夌敓浜ц鍒掔殑浜у搧鍨嬪彿涓嶄竴鑷淬�傝鏍¢獙娌℃湁鍙栨秷銆�
+
+## 4. 閿�鍞骇鍝佸垪琛�
+
+閿�鍞骇鍝佸垪琛ㄤ腑鐨� `noQuantity` 涓嶅啀琛ㄧず閿�鍞鍗曞墿浣欏彲鍙戞暟閲忋��
+
+鍚庣杩斿洖锛�
+
+```json
+{
+  "quantity": 10,
+  "shippedQuantity": 10,
+  "pendingApprovalQuantity": 0,
+  "noQuantity": null
+}
+```
+
+瀛楁璇存槑锛�
+
+| 瀛楁 | 璇存槑 |
+| --- | --- |
+| `quantity` | 閿�鍞骇鍝佸師濮嬫暟閲忥紝浠呯敤浜庨攢鍞笟鍔″睍绀猴紝涓嶄綔涓哄彂璐ф暟閲忎笂闄� |
+| `shippedQuantity` | 宸插彂璐ф暟閲忥紝浠呯敤浜庣粺璁″睍绀� |
+| `pendingApprovalQuantity` | 寰呭鏍告垨瀹℃牳涓殑鍙戣揣鏁伴噺锛屼粎鐢ㄤ簬缁熻灞曠ず |
+| `noQuantity` | 涓嶅啀鎻愪緵閿�鍞墿浣欏彲鍙戞暟閲忥紝鍊间负 `null` |
+
+鍓嶇娉ㄦ剰锛�
+
+- 涓嶈浣跨敤 `noQuantity` 浣滀负鍙戣揣鏁伴噺杈撳叆妗嗙殑 `max`銆�
+- 涓嶈鍥犱负 `noQuantity <= 0` 绂佺敤鍙戣揣鎸夐挳銆�
+- 涓嶈鐢� `quantity - shippedQuantity - pendingApprovalQuantity` 閲嶆柊璁$畻鍙戣揣涓婇檺銆�
+- 鍙戣揣鏁伴噺杈撳叆妗嗙殑鏈�澶у�煎簲鐢卞疄闄呭簱瀛樹俊鎭垨鐢ㄦ埛閫夋嫨鐨勫簱瀛樻壒娆″喅瀹氥��
+- `shippingStatus` 浠嶅彲鐢ㄤ簬灞曠ず锛屼絾涓嶈兘浣滀负鏄惁鍏佽缁х画鍙戣揣鐨勭‖鎬ф潯浠躲��
+
+## 5. 鏂板閿�鍞彂璐�
+
+### 5.1 鎺ュ彛鍦板潃
+
+```text
+POST /shippingInfo/add
+```
+
+### 5.2 璇锋眰浣撶ず渚�
+
+```json
+{
+  "salesLedgerId": 2001,
+  "salesLedgerProductId": 3001,
+  "type": "閿�鍞彂璐�",
+  "batchNoDetailList": [
+    {
+      "productModelId": 501,
+      "batchNo": "BATCH-20260826-001",
+      "quantity": 30
+    }
+  ],
+  "storageBlobDTOs": []
+}
+```
+
+瀛楁璇存槑锛�
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+| --- | --- | --- | --- |
+| `salesLedgerId` | `number` | 鎸変笟鍔� | 閿�鍞彴璐� ID |
+| `salesLedgerProductId` | `number` | 寤鸿浼犲叆 | 閿�鍞彴璐︿骇鍝� ID锛岀敤浜庡叧鑱旈攢鍞骇鍝佸強閲嶅鎻愪氦鏍¢獙 |
+| `type` | `string` | 鍚� | 鍙戣揣绫诲瀷 |
+| `batchNoDetailList` | `array` | 鏄� | 鍙戣揣鎵规鏄庣粏 |
+| `batchNoDetailList[].productModelId` | `number` | 鏄� | 浜у搧鍨嬪彿 ID |
+| `batchNoDetailList[].batchNo` | `string` | 鏄� | 搴撳瓨鎵规鍙� |
+| `batchNoDetailList[].quantity` | `number` | 鏄� | 鏈壒娆″彂璐ф暟閲� |
+| `storageBlobDTOs` | `array` | 鍚� | 闄勪欢鍒楄〃锛屾病鏈夐檮浠舵椂浼犵┖鏁扮粍 |
+
+### 5.3 閲嶈瑙勫垯
+
+1. 鍙戣揣鏁伴噺鍙互澶т簬閿�鍞骇鍝佸墿浣欐暟閲忋��
+2. 姣忎釜鎵规閮藉繀椤诲瓨鍦ㄥ簱瀛樿褰曘��
+3. 姣忎釜鎵规鐨勫彂璐ф暟閲忎笉鑳借秴杩囪鎵规鍙敤搴撳瓨銆�
+4. 鍙敤搴撳瓨浼氭墸闄ゅ喕缁撳簱瀛樺拰宸叉湁寰呭嚭搴撴暟閲忋��
+5. 鍚屼竴閿�鍞骇鍝佸凡鏈夆�滃緟瀹℃牳鈥濇垨鈥滃鏍镐腑鈥濆彂璐ц褰曟椂锛屼粛涓嶅厑璁搁噸澶嶆彁浜ゃ��
+6. 鏂板鎴愬姛鍚庯紝鍙戣揣鍗曡繘鍏ュ鎵规祦绋嬶紝閫氬父鐘舵�佷负鈥滃鏍镐腑鈥濄��
+
+搴撳瓨涓嶈冻鏃跺彲鑳借繑鍥烇細
+
+```text
+搴撳瓨璁板綍涓嶅瓨鍦�
+```
+
+鎴栵細
+
+```text
+鐢宠鏁伴噺瓒呰繃鍙敤搴撳瓨锛屽綋鍓嶅彲鐢ㄥ簱瀛樹负锛歺xx
+```
+
+### 5.4 鑱旇皟鍦烘櫙
+
+#### 鍦烘櫙涓�锛氶攢鍞暟閲忓凡鍙戝畬锛屼絾搴撳瓨鍏呰冻
+
+鍋囪锛�
+
+- 閿�鍞暟閲忥細10
+- 宸插彂璐ф暟閲忥細10
+- 褰撳墠鎵规鍙敤搴撳瓨锛�30
+- 鏈鍙戣揣鏁伴噺锛�20
+
+棰勬湡锛�
+
+- `/shippingInfo/add` 璇锋眰鍏佽鎻愪氦銆�
+- 涓嶅洜涓洪攢鍞暟閲忓凡鐢ㄥ畬鑰屽け璐ャ��
+- 鍚庣画浠嶆寜鐓у鎵规祦绋嬪鐞嗐��
+
+#### 鍦烘櫙浜岋細閿�鍞暟閲忔湭鍙戝畬锛屼絾搴撳瓨涓嶈冻
+
+鍋囪锛�
+
+- 閿�鍞墿浣欐暟閲忥細100
+- 褰撳墠鎵规鍙敤搴撳瓨锛�5
+- 鏈鍙戣揣鏁伴噺锛�6
+
+棰勬湡锛�
+
+- 璇锋眰澶辫触銆�
+- 杩斿洖搴撳瓨涓嶈冻淇℃伅銆�
+- 涓嶅簲璁や负閿�鍞墿浣欐暟閲忚冻澶熷氨鍏佽鍙戣揣銆�
+
+#### 鍦烘櫙涓夛細澶氫釜搴撳瓨鎵规
+
+```json
+{
+  "salesLedgerProductId": 3001,
+  "batchNoDetailList": [
+    {
+      "productModelId": 501,
+      "batchNo": "BATCH-A",
+      "quantity": 10
+    },
+    {
+      "productModelId": 501,
+      "batchNo": "BATCH-B",
+      "quantity": 15
+    }
+  ]
+}
+```
+
+姣忎釜鎵规鐙珛鏍¢獙搴撳瓨锛涗换鎰忎竴涓壒娆″簱瀛樹笉瓒虫椂锛屾暣娆¤姹傚け璐ュ苟鍥炴粴銆�
+
+## 6. 瀹℃壒閫氳繃鍚庣‘璁ゅ彂璐�
+
+### 6.1 鎺ュ彛鍦板潃
+
+```text
+POST /shippingInfo/deductStock
+```
+
+### 6.2 璇锋眰浣撶ず渚�
+
+```json
+{
+  "id": 4001,
+  "expressCompany": "椤轰赴",
+  "expressNumber": "SF1234567890",
+  "shippingCarNumber": "鑻廇12345",
+  "shippingDate": "2026-08-26"
+}
+```
+
+璇存槑锛�
+
+- `id` 涓哄彂璐у崟 ID锛屽繀濉��
+- 鎺ュ彛浼氬啀娆℃寜鍙戣揣鏄庣粏鏍¢獙搴撳瓨銆�
+- 鎴愬姛鍚庡彂璐у崟鐘舵�佹洿鏂颁负鈥滃凡鍙戣揣鈥濄��
+- 褰撳墠鎺ュ彛涓嶄細鏍规嵁閿�鍞骇鍝佸師濮嬫暟閲忛檺鍒跺彂璐с��
+- 宸茬粡鏄�滃凡鍙戣揣鈥濈姸鎬佹椂锛屼笉浼氶噸澶嶆墸鍑忓簱瀛樸��
+
+## 7. 鍓嶇鑱旇皟妫�鏌ユ竻鍗�
+
+- [ ] 鐢熶骇璁″垝涓嬪彂鏁伴噺杈撳叆妗嗕笉鍐嶇粦瀹氶渶姹傚墿浣欓噺鏈�澶у�笺��
+- [ ] 鐘舵�佷负 `2` 鐨勭敓浜ц鍒掍粛鍙�夋嫨涓嬪彂銆�
+- [ ] 鐢熶骇璁″垝涓嬪彂鎴愬姛鍚庡厑璁� `quantityIssued > qtyRequired` 灞曠ず銆�
+- [ ] 閿�鍞骇鍝佸垪琛ㄤ笉浣跨敤 `noQuantity` 闄愬埗鍙戣揣鏁伴噺銆�
+- [ ] `noQuantity=null` 鏃堕〉闈笉鏄剧ず涓衡�滀笉鍙彂璐р�濄��
+- [ ] 閿�鍞骇鍝佺姸鎬佲�滃凡鍙戣揣鈥濅笉鍐嶇洿鎺ョ鐢ㄥ彂璐ф搷浣溿��
+- [ ] 鍙戣揣鏁伴噺鏀圭敱搴撳瓨鎵规鍙敤閲忔帶鍒躲��
+- [ ] 搴撳瓨涓嶈冻鏃舵纭睍绀哄悗绔敊璇俊鎭��
+- [ ] 鍚屼竴閿�鍞骇鍝佸緟瀹℃牳/瀹℃牳涓噸澶嶆彁浜や粛鎸夊悗绔彁绀哄鐞嗐��
+- [ ] 鐢熶骇璁″垝銆侀攢鍞彂璐ф彁浜ゆ垚鍔熷悗鍒锋柊鍒楄〃鏁版嵁銆�
diff --git a/sql/product-inventory-management-new-pro.sql b/sql/product-inventory-management-new-pro.sql
index 2752b38..ea5813b 100644
--- a/sql/product-inventory-management-new-pro.sql
+++ b/sql/product-inventory-management-new-pro.sql
@@ -4895,6 +4895,7 @@
   `company_phone` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏徃鐢佃瘽',
   `bank_account_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '寮�鎴疯',
   `bank_account_num` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璐﹀彿',
+  `bank_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閾惰仈琛屽彿',
   `contact_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴浜�',
   `contact_user_phone` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
   `maintain_user_id` bigint NULL DEFAULT NULL COMMENT '缁存姢浜篒D',
diff --git a/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java b/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java
index f687c74..df2faa8 100644
--- a/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java
+++ b/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java
@@ -26,4 +26,6 @@
     IPage<AccountPurchasePaymentVo> listPageAccountPurchasePayment(Page page, @Param("req") AccountPurchasePaymentDto accountPurchasePaymentDto);
 
     List<IncomeExpenseAnalysisDto> selectPayment(@Param("startStr") String startStr, @Param("endStr") String endStr, @Param("dateFormat") String dateFormat);
+
+    List<Long> selectStockInRecordIdsByPurchaseLedgerId(@Param("purchaseLedgerId") Long purchaseLedgerId);
 }
diff --git a/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java b/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java
index 2f1cf6e..3052047 100644
--- a/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java
+++ b/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java
@@ -32,4 +32,6 @@
     List<SalesOutboundVo> getOutboundBatchesByCustomer(@Param("customerId") Integer customerId);
 
     List<IncomeExpenseAnalysisDto> selectIncomeStats(@Param("startStr") String startStr, @Param("endStr") String endStr, @Param("dateFormat") String dateFormat);
+
+    List<Long> selectStockOutRecordIdsBySalesLedgerId(@Param("salesLedgerId") Long salesLedgerId);
 }
diff --git a/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java
index b9953a0..4535525 100644
--- a/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java
@@ -1,10 +1,11 @@
 package com.ruoyi.account.service.impl.purchase;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
 import com.ruoyi.account.bean.dto.purchase.AccountPurchasePaymentDto;
 import com.ruoyi.account.bean.vo.purchase.AccountPurchasePaymentVo;
 import com.ruoyi.account.mapper.AccountStatementDetailsMapper;
@@ -17,15 +18,20 @@
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.purchase.dto.SavePaymentDto;
+import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
+import com.ruoyi.purchase.pojo.PurchaseLedger;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.List;
 import java.util.Random;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -43,6 +49,7 @@
     private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
     private final AccountStatementDetailsMapper accountStatementDetailsMapper;
     private final AccountPaymentApplicationMapper accountPaymentApplicationMapper;
+    private final PurchaseLedgerMapper purchaseLedgerMapper;
 
     @Override
     public IPage<AccountPurchasePaymentVo> listPageAccountPurchasePayment(Page page, AccountPurchasePaymentDto accountPurchasePaymentDto) {
@@ -84,6 +91,60 @@
         return removeByIds(ids);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean savePayment(SavePaymentDto dto) {
+        if (dto.getPaymentDate() == null) {
+            throw new ServiceException("璇烽�夋嫨浠樻鏃ユ湡");
+        }
+        if (dto.getPaymentAmount() == null || dto.getPaymentAmount().compareTo(BigDecimal.valueOf(0.01)) < 0) {
+            throw new ServiceException("璇疯緭鍏ヤ粯娆鹃噾棰�");
+        }
+        if (StringUtils.isEmpty(dto.getPurchaseContractNumber())) {
+            throw new ServiceException("閲囪喘鍚堝悓鍙蜂笉鑳戒负绌�");
+        }
+        if (dto.getSupplierId() == null) {
+            throw new ServiceException("渚涘簲鍟嗕笉鑳戒负绌�");
+        }
+
+        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
+                .eq(PurchaseLedger::getPurchaseContractNumber, dto.getPurchaseContractNumber()));
+        if (purchaseLedger == null) {
+            throw new ServiceException("閲囪喘鍚堝悓涓嶅瓨鍦�");
+        }
+        if (purchaseLedger.getSupplierId() == null || purchaseLedger.getSupplierId().longValue() != dto.getSupplierId().longValue()) {
+            throw new ServiceException("渚涘簲鍟嗕笌鍚堝悓涓嶅尮閰�");
+        }
+
+        List<Long> stockInRecordIds = accountPurchasePaymentMapper.selectStockInRecordIdsByPurchaseLedgerId(purchaseLedger.getId());
+
+        AccountPaymentApplication application = new AccountPaymentApplication();
+        application.setSupplierId(dto.getSupplierId().intValue());
+        application.setStockInRecordIds(stockInRecordIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
+        application.setInvoiceApplicationNo(genPaymentApplicationNo());
+        application.setPaymentMethod(dto.getPaymentMethod());
+        application.setPaymentContent(dto.getPurchaseContractNumber());
+        application.setApplyDate(dto.getPaymentDate());
+        application.setRemark(dto.getRemark());
+        application.setStatus(1);
+        application.setPaymentAmount(dto.getPaymentAmount());
+        accountPaymentApplicationMapper.insert(application);
+
+        AccountPurchasePayment payment = new AccountPurchasePayment();
+        payment.setAccountPaymentApplicationId(application.getId());
+        payment.setSupplierId(dto.getSupplierId().intValue());
+        payment.setPaymentDate(dto.getPaymentDate());
+        payment.setPaymentMethod(dto.getPaymentMethod());
+        payment.setPaymentAmount(dto.getPaymentAmount());
+        payment.setPaymentNumber(genAccountPurchasePaymentNo());
+        payment.setRemark(dto.getRemark());
+        return save(payment);
+    }
+
+    private String genPaymentApplicationNo() {
+        return "FK" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
+    }
+
     private String genAccountPurchasePaymentNo() {
         return "SK" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
     }
diff --git a/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java
index 45900d7..6980280 100644
--- a/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java
@@ -1,5 +1,6 @@
 package com.ruoyi.account.service.impl.sales;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -16,13 +17,16 @@
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.sales.dto.SaveReceiptPaymentDto;
+import com.ruoyi.sales.mapper.SalesLedgerMapper;
+import com.ruoyi.sales.pojo.SalesLedger;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 
@@ -40,6 +44,7 @@
 
     private final AccountSalesCollectionMapper accountSalesCollectionMapper;
     private final AccountStatementDetailsMapper accountStatementDetailsMapper;
+    private final SalesLedgerMapper salesLedgerMapper;
     private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");
 
 
@@ -90,6 +95,43 @@
         return accountSalesCollectionMapper.getOutboundBatchesByCustomer(customerId);
     }
 
+    @Override
+    public boolean saveReceiptPayment(SaveReceiptPaymentDto dto) {
+        if (dto.getPaymentDate() == null) {
+            throw new ServiceException("璇烽�夋嫨鍥炴鏃ユ湡");
+        }
+        if (dto.getPaymentAmount() == null || dto.getPaymentAmount().compareTo(BigDecimal.valueOf(0.01)) < 0) {
+            throw new ServiceException("璇疯緭鍏ュ洖娆鹃噾棰�");
+        }
+        if (StringUtils.isEmpty(dto.getSalesContractNo())) {
+            throw new ServiceException("閿�鍞悎鍚屽彿涓嶈兘涓虹┖");
+        }
+        if (dto.getCustomerId() == null) {
+            throw new ServiceException("瀹㈡埛涓嶈兘涓虹┖");
+        }
+
+        SalesLedger salesLedger = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
+                .eq(SalesLedger::getSalesContractNo, dto.getSalesContractNo()));
+        if (salesLedger == null) {
+            throw new ServiceException("閿�鍞悎鍚屼笉瀛樺湪");
+        }
+        if (salesLedger.getCustomerId() == null || salesLedger.getCustomerId().longValue() != dto.getCustomerId().longValue()) {
+            throw new ServiceException("瀹㈡埛涓庡悎鍚屼笉鍖归厤");
+        }
+
+        List<Long> stockOutRecordIds = accountSalesCollectionMapper.selectStockOutRecordIdsBySalesLedgerId(salesLedger.getId());
+
+        AccountSalesCollection collection = new AccountSalesCollection();
+        collection.setCustomerId(dto.getCustomerId().intValue());
+        collection.setStockOutRecordIds(stockOutRecordIds.stream().map(String::valueOf).collect(java.util.stream.Collectors.joining(",")));
+        collection.setCollectionDate(dto.getPaymentDate());
+        collection.setCollectionAmount(dto.getPaymentAmount());
+        collection.setCollectionMethod(dto.getPaymentMethod());
+        collection.setCollectionNumber(genAccountSalesCollectionNo());
+        collection.setRemark(dto.getRemark());
+        return save(collection);
+    }
+
     private String genAccountSalesCollectionNo() {
         return "SK" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
     }
diff --git a/src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java b/src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java
index 018a497..42eda98 100644
--- a/src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java
+++ b/src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java
@@ -5,6 +5,7 @@
 import com.ruoyi.account.bean.dto.purchase.AccountPurchasePaymentDto;
 import com.ruoyi.account.bean.vo.purchase.AccountPurchasePaymentVo;
 import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.purchase.dto.SavePaymentDto;
 import com.baomidou.mybatisplus.extension.service.IService;
 import jakarta.servlet.http.HttpServletResponse;
 
@@ -27,4 +28,12 @@
     void exportAccountPurchasePayment(HttpServletResponse response, AccountPurchasePaymentDto accountPurchasePaymentDto);
 
     boolean deleteAccountPurchasePayment(List<Long> ids);
+
+    /**
+     * 閲囪喘绠$悊--渚涘簲鍟嗗線鏉� 鏂板浠樻
+     *
+     * @param dto 浠樻璇锋眰鍙傛暟
+     * @return 鏄惁鎴愬姛
+     */
+    boolean savePayment(SavePaymentDto dto);
 }
diff --git a/src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java b/src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java
index d5172fb..af24a9c 100644
--- a/src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java
+++ b/src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java
@@ -6,6 +6,7 @@
 import com.ruoyi.account.bean.vo.sales.AccountSalesCollectionVo;
 import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
 import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.ruoyi.sales.dto.SaveReceiptPaymentDto;
 import com.baomidou.mybatisplus.extension.service.IService;
 import jakarta.servlet.http.HttpServletResponse;
 
@@ -30,4 +31,12 @@
     boolean deleteAccountSalesCollection(List<Long> ids);
 
     List<SalesOutboundVo> getOutboundBatchesByCustomer(Integer customerId);
+
+    /**
+     * 钀ラ攢绠$悊--瀹㈡埛寰�鏉� 鏂板鍥炴
+     *
+     * @param dto 鍥炴璇锋眰鍙傛暟
+     * @return 鏄惁鎴愬姛
+     */
+    boolean saveReceiptPayment(SaveReceiptPaymentDto dto);
 }
diff --git a/src/main/java/com/ruoyi/basic/excel/SupplierManageExcelDto.java b/src/main/java/com/ruoyi/basic/excel/SupplierManageExcelDto.java
index 87b197f..5128452 100644
--- a/src/main/java/com/ruoyi/basic/excel/SupplierManageExcelDto.java
+++ b/src/main/java/com/ruoyi/basic/excel/SupplierManageExcelDto.java
@@ -30,6 +30,9 @@
     @Excel(name = "璐﹀彿")
     private String bankAccountNum;
 
+    @Excel(name = "閾惰仈琛屽彿")
+    private String bankCode;
+
     @Excel(name = "鑱旂郴浜�")
     private String contactUserName;
 
diff --git a/src/main/java/com/ruoyi/basic/pojo/SupplierManage.java b/src/main/java/com/ruoyi/basic/pojo/SupplierManage.java
index fa10c92..e3bdf27 100644
--- a/src/main/java/com/ruoyi/basic/pojo/SupplierManage.java
+++ b/src/main/java/com/ruoyi/basic/pojo/SupplierManage.java
@@ -40,6 +40,10 @@
     @Excel(name = "璐﹀彿")
     private String bankAccountNum;
 
+    @Schema(description = "閾惰仈琛屽彿")
+    @Excel(name = "閾惰仈琛屽彿")
+    private String bankCode;
+
     @Schema(description = "鑱旂郴浜�")
     @Excel(name = "鑱旂郴浜�")
     private String contactUserName;
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
index 95c7344..f64d44f 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -666,9 +666,6 @@
         if (productModelIds.size() > 1) {
             throw new ServiceException("鎵�閫夌敓浜ц鍒掑繀椤诲睘浜庡悓涓�浜у搧瑙勬牸");
         }
-        if (productionPlans.stream().anyMatch(item -> item.getStatus() != null && item.getStatus() == 2)) {
-            throw new ServiceException("鎵�閫夌敓浜ц鍒掑凡涓嬪彂");
-        }
         ProductionPlan firstPlan = mainPlan;
         if (productionOrder.getProductModelId() == null) {
             productionOrder.setProductModelId(firstPlan.getProductModelId());
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
index 53b1ee9..b3f424d 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
@@ -61,9 +61,8 @@
      * 鍚堝苟鐢熶骇璁″垝骞朵笅鍙戠敓浜ц鍗曘��
      * 绾︽潫锛�
      * 1. 浠呭厑璁稿悓涓�浜у搧鍨嬪彿鐨勮鍒掑悎骞讹紱
-     * 2. 宸蹭笅鍙戞垨閮ㄥ垎涓嬪彂鐨勮鍒掍笉鍏佽鍐嶆鍚堝苟锛�
-     * 3. 涓嬪彂鏁伴噺涓嶈兘澶т簬鎵�閫夎鍒掑墿浣欓渶姹傛�婚噺锛�
-     * 4. 涓嬪彂鏃剁粺涓�璋冪敤 ProductionOrderService.saveProductionOrder锛岀‘淇濆悗缁伐鑹�/BOM/棰嗘枡閫昏緫涓�鑷淬��
+     * 2. 涓嬪彂鏁伴噺鍙彈杈撳叆鏁伴噺鍜屽熀纭�鏁版嵁鏍¢獙绾︽潫锛�
+     * 3. 涓嬪彂鏃剁粺涓�璋冪敤 ProductionOrderService.saveProductionOrder锛岀‘淇濆悗缁伐鑹�/BOM/棰嗘枡閫昏緫涓�鑷淬��
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -101,49 +100,18 @@
             throw new BaseException("鍚堝苟澶辫触锛屾墍閫夌敓浜ц鍒掔殑浜у搧鍨嬪彿涓嶄竴鑷�");
         }
 
-        // 浠呪�滃凡涓嬪彂鈥濊鍒掍笉鍏佽鍐嶆鍙備笌鍚堝苟涓嬪彂锛�
-        // 鈥滃緟涓嬪彂/閮ㄥ垎涓嬪彂鈥濆厑璁哥户缁笅鍙戝墿浣欐暟閲忋��
-        boolean hasFullyIssuedPlan = planLists.stream()
-                .anyMatch(item -> item.getStatus() != null
-                        && item.getStatus() == PLAN_STATUS_ISSUED);
-        if (hasFullyIssuedPlan) {
-            throw new BaseException("鍚堝苟澶辫触锛屾墍閫夌敓浜ц鍒掑瓨鍦ㄥ凡涓嬪彂鐨勬暟鎹�");
-        }
-
-        // 璁$畻鏈鍙笅鍙戠殑鍓╀綑闇�姹傛�婚噺
-        BigDecimal totalRequiredQuantity = planLists.stream()
-                .map(this::resolveRemainingQuantity)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        if (totalRequiredQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-            throw new ServiceException("涓嬪彂澶辫触锛屾墍閫夌敓浜ц鍒掑墿浣欓渶姹傛�婚噺蹇呴』澶т簬0");
-        }
-
         // 鏍¢獙涓嬪彂鏁伴噺
         BigDecimal assignedQuantity = productionPlanDto.getTotalAssignedQuantity();
         if (assignedQuantity == null || assignedQuantity.compareTo(BigDecimal.ZERO) <= 0) {
             throw new ServiceException("涓嬪彂澶辫触锛屼笅鍙戞暟閲忓繀椤诲ぇ浜�0");
         }
-        if (assignedQuantity.compareTo(totalRequiredQuantity) > 0) {
-            throw new ServiceException("涓嬪彂澶辫触锛屼笅鍙戞暟閲忎笉鑳藉ぇ浜庤鍒掑墿浣欓渶姹傛�婚噺");
-        }
 
-        // 鎸夎鍒掗『搴忓垎鎽婁笅鍙戞暟閲忥紝鏀堕泦瀹為檯鍙備笌涓嬪彂鐨勮鍒� ID
-        BigDecimal remainingForOrderBind = assignedQuantity;
-        List<Long> issuedPlanIds = new ArrayList<>();
-        for (ProductionPlanDto plan : planLists) {
-            BigDecimal remainingQuantity = resolveRemainingQuantity(plan);
-            if (remainingForOrderBind.compareTo(BigDecimal.ZERO) <= 0 || remainingQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-                continue;
-            }
-            BigDecimal issueForThisPlan = remainingForOrderBind.min(remainingQuantity);
-            remainingForOrderBind = remainingForOrderBind.subtract(issueForThisPlan);
-            if (issueForThisPlan.compareTo(BigDecimal.ZERO) > 0) {
-                issuedPlanIds.add(plan.getId());
-            }
-        }
-        if (issuedPlanIds.isEmpty()) {
-            throw new ServiceException("涓嬪彂澶辫触锛屾棤鍙笅鍙戞暟閲�");
-        }
+        // 鏈涓嬪彂鏁伴噺涓嶅啀鎸夐渶姹傞噺闄愬埗锛屾墍鏈夐�変腑璁″垝鍏卞悓浣滀负璁㈠崟鏉ユ簮
+        List<Long> issuedPlanIds = planLists.stream()
+                .map(ProductionPlanDto::getId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
 
         // 鐢熸垚鐢熶骇璁㈠崟涓诲崟锛屽苟缁戝畾鏈涓嬪彂鍏宠仈鐨勮鍒�
         ProductionOrder productionOrder = new ProductionOrder();
@@ -155,24 +123,18 @@
             throw new ServiceException("涓嬪彂澶辫触锛岀敓浜ц鍗曚繚瀛樺け璐�");
         }
 
-        // 鍥炲啓姣忔潯璁″垝鐨勭疮璁′笅鍙戦噺鍜岀姸鎬�
+        // 鍥炲啓姣忔潯璁″垝鐨勭疮璁′笅鍙戦噺鍜岀姸鎬侊紝鍏佽绱涓嬪彂閲忚秴杩囬渶姹傞噺
         BigDecimal remainingAssignedQuantity = assignedQuantity;
         List<ProductionPlan> updates = new ArrayList<>();
         for (ProductionPlanDto plan : planLists) {
-            BigDecimal requiredQuantity = Optional.ofNullable(plan.getQtyRequired()).orElse(BigDecimal.ZERO);
-            if (requiredQuantity.compareTo(BigDecimal.ZERO) < 0) {
-                requiredQuantity = BigDecimal.ZERO;
-            }
-            BigDecimal remainingQuantity = resolveRemainingQuantity(plan);
-            BigDecimal historicalIssuedQuantity = requiredQuantity.subtract(remainingQuantity);
-            BigDecimal issuedQuantity = BigDecimal.ZERO;
-            if (remainingAssignedQuantity.compareTo(BigDecimal.ZERO) > 0 && remainingQuantity.compareTo(BigDecimal.ZERO) > 0) {
-                issuedQuantity = remainingAssignedQuantity.min(remainingQuantity);
-                remainingAssignedQuantity = remainingAssignedQuantity.subtract(issuedQuantity);
-            }
+            BigDecimal historicalIssuedQuantity = Optional.ofNullable(plan.getQuantityIssued()).orElse(BigDecimal.ZERO);
+            BigDecimal issuedQuantity = remainingAssignedQuantity.min(assignedQuantity);
+            remainingAssignedQuantity = remainingAssignedQuantity.subtract(issuedQuantity);
 
             BigDecimal totalIssuedQuantity = historicalIssuedQuantity.add(issuedQuantity);
-            int planStatus = resolvePlanStatus(requiredQuantity, totalIssuedQuantity);
+            int planStatus = plan.getStatus() != null && plan.getStatus() == PLAN_STATUS_ISSUED
+                    ? PLAN_STATUS_ISSUED
+                    : resolvePlanStatus(plan.getQtyRequired(), totalIssuedQuantity);
             ProductionPlan update = new ProductionPlan();
             update.setId(plan.getId());
             update.setStatus(planStatus);
@@ -455,32 +417,6 @@
             }
         }
         return sequence;
-    }
-
-    /**
-     * 璁$畻鐢熶骇璁″垝鐨勫墿浣欐湭涓嬪彂鏁伴噺锛堥渶姹傞噺 - 宸蹭笅鍙戦噺锛屾渶灏忎负 0锛夈��
-     */
-    private BigDecimal resolveRemainingQuantity(ProductionPlan plan) {
-        // 绌哄璞℃寜 0 澶勭悊
-        if (plan == null) {
-            return BigDecimal.ZERO;
-        }
-        // 闇�姹傞噺涓虹┖鎴栧皬浜庣瓑浜� 0锛岃涓烘棤鍓╀綑
-        BigDecimal requiredQuantity = Optional.ofNullable(plan.getQtyRequired()).orElse(BigDecimal.ZERO);
-        if (requiredQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-            return BigDecimal.ZERO;
-        }
-        // 宸蹭笅鍙戦噺涓虹┖鎴栧皬浜庣瓑浜� 0锛屽墿浣欏嵆闇�姹傞噺
-        BigDecimal issuedQuantity = Optional.ofNullable(plan.getQuantityIssued()).orElse(BigDecimal.ZERO);
-        if (issuedQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-            return requiredQuantity;
-        }
-        // 宸蹭笅鍙戦噺澶т簬绛変簬闇�姹傞噺锛屽墿浣欏綊闆�
-        if (issuedQuantity.compareTo(requiredQuantity) >= 0) {
-            return BigDecimal.ZERO;
-        }
-        // 姝e父鍦烘櫙杩斿洖宸��
-        return requiredQuantity.subtract(issuedQuantity);
     }
 
     /**
diff --git a/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java b/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
index 798112b..9647b05 100644
--- a/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
+++ b/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
@@ -1,11 +1,13 @@
 package com.ruoyi.purchase.controller;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.service.purchase.AccountPurchasePaymentService;
 import com.ruoyi.basic.service.ISupplierService;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.domain.R;
+import com.ruoyi.purchase.dto.SavePaymentDto;
 import com.ruoyi.purchase.dto.VatDto;
 import com.ruoyi.purchase.service.PurchaseReportService;
 import com.ruoyi.purchase.vo.PurchaseReportVo;
@@ -15,6 +17,7 @@
 import lombok.AllArgsConstructor;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -28,6 +31,7 @@
 
     private final ISupplierService supplierService;
     private final PurchaseReportService purchaseReportService;
+    private final AccountPurchasePaymentService accountPurchasePaymentService;
 
 
     @GetMapping("/list")
@@ -74,4 +78,11 @@
     public R supplierTransactionsDetails(Page page, Long supplierId) {
         return R.ok(supplierService.supplierTransactionsDetails(page,supplierId));
     }
+
+    @PostMapping("/savePayment")
+    @Log(title = "鏂板浠樻", businessType = BusinessType.INSERT)
+    @Operation(summary = "鏂板浠樻")
+    public R savePayment(@RequestBody SavePaymentDto dto) {
+        return R.ok(accountPurchasePaymentService.savePayment(dto));
+    }
 }
diff --git a/src/main/java/com/ruoyi/purchase/dto/SavePaymentDto.java b/src/main/java/com/ruoyi/purchase/dto/SavePaymentDto.java
new file mode 100644
index 0000000..7c1acce
--- /dev/null
+++ b/src/main/java/com/ruoyi/purchase/dto/SavePaymentDto.java
@@ -0,0 +1,35 @@
+package com.ruoyi.purchase.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+/**
+ * 閲囪喘绠$悊--渚涘簲鍟嗗線鏉� 鏂板浠樻璇锋眰鍙傛暟
+ */
+@Data
+@Schema(name = "SavePaymentDto", description = "鏂板浠樻璇锋眰鍙傛暟")
+public class SavePaymentDto {
+
+    @Schema(description = "渚涘簲鍟咺D")
+    private Long supplierId;
+
+    @Schema(description = "閲囪喘鍚堝悓鍙�")
+    private String purchaseContractNumber;
+
+    @Schema(description = "浠樻鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate paymentDate;
+
+    @Schema(description = "浠樻閲戦")
+    private BigDecimal paymentAmount;
+
+    @Schema(description = "浠樻鏂瑰紡")
+    private String paymentMethod;
+
+    @Schema(description = "澶囨敞")
+    private String remark;
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java b/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
index 577508a..4572af1 100644
--- a/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
+++ b/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
@@ -1,18 +1,22 @@
 package com.ruoyi.sales.controller;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.service.sales.AccountSalesCollectionService;
 import com.ruoyi.basic.service.ICustomerService;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.framework.web.domain.R;
+import com.ruoyi.sales.dto.SaveReceiptPaymentDto;
 import com.ruoyi.sales.dto.StatisticsTableDto;
 import com.ruoyi.sales.service.impl.MetricStatisticsServiceImpl;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.AllArgsConstructor;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -28,6 +32,7 @@
 
     private final MetricStatisticsServiceImpl metricStatisticsService;
     private final ICustomerService customerService;
+    private final AccountSalesCollectionService accountSalesCollectionService;
 
     @Operation(summary = "澶撮儴鎬昏")
     @GetMapping("/total")
@@ -55,4 +60,11 @@
         return R.ok(customerService.customewTransactionsDetails(page,customerId));
     }
 
+    @PostMapping("/saveReceiptPayment")
+    @Log(title = "鏂板鍥炴", businessType = BusinessType.INSERT)
+    @Operation(summary = "鏂板鍥炴")
+    public R saveReceiptPayment(@RequestBody SaveReceiptPaymentDto dto) {
+        return R.ok(accountSalesCollectionService.saveReceiptPayment(dto));
+    }
+
 }
diff --git a/src/main/java/com/ruoyi/sales/dto/SaveReceiptPaymentDto.java b/src/main/java/com/ruoyi/sales/dto/SaveReceiptPaymentDto.java
new file mode 100644
index 0000000..7a83b6c
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/dto/SaveReceiptPaymentDto.java
@@ -0,0 +1,35 @@
+package com.ruoyi.sales.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+/**
+ * 钀ラ攢绠$悊--瀹㈡埛寰�鏉� 鏂板鍥炴璇锋眰鍙傛暟
+ */
+@Data
+@Schema(name = "SaveReceiptPaymentDto", description = "鏂板鍥炴璇锋眰鍙傛暟")
+public class SaveReceiptPaymentDto {
+
+    @Schema(description = "瀹㈡埛ID")
+    private Long customerId;
+
+    @Schema(description = "閿�鍞悎鍚屽彿")
+    private String salesContractNo;
+
+    @Schema(description = "鍥炴鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate paymentDate;
+
+    @Schema(description = "鍥炴閲戦")
+    private BigDecimal paymentAmount;
+
+    @Schema(description = "鍥炴鏂瑰紡")
+    private String paymentMethod;
+
+    @Schema(description = "澶囨敞")
+    private String remark;
+}
\ No newline at end of file
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index e5e2f9a..9b3c225 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -74,7 +74,7 @@
     druid:
       # 涓诲簱鏁版嵁婧�
       master:
-        url: jdbc:mysql://localhost:3306/product-inventory-management-bdpro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        url: jdbc:mysql://localhost:3306/product-inventory-management?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
         username: root
         password: 123456
       # 浠庡簱鏁版嵁婧�
diff --git a/src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml b/src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml
index ed247e5..77e07c5 100644
--- a/src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml
+++ b/src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml
@@ -54,5 +54,13 @@
         GROUP BY dateStr
         ORDER BY dateStr
     </select>
+    <select id="selectStockInRecordIdsByPurchaseLedgerId" resultType="java.lang.Long">
+        SELECT sir.id
+        FROM stock_in_record sir
+        LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
+        WHERE sir.approval_status = 1
+          AND sir.record_type IN ('7','10')
+          AND IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id) = #{purchaseLedgerId}
+    </select>
 
 </mapper>
diff --git a/src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml b/src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml
index 6a35890..e0e394d 100644
--- a/src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml
+++ b/src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml
@@ -112,5 +112,13 @@
          GROUP BY dateStr
          ORDER BY dateStr
     </select>
+    <select id="selectStockOutRecordIdsBySalesLedgerId" resultType="java.lang.Long">
+        SELECT sor.id
+        FROM stock_out_record sor
+        JOIN shipping_info s ON sor.record_id = s.id
+        WHERE s.sales_ledger_id = #{salesLedgerId}
+          AND sor.record_type = '13'
+          AND sor.approval_status = 1
+    </select>
 
 </mapper>
diff --git a/src/main/resources/mapper/basic/CustomerMapper.xml b/src/main/resources/mapper/basic/CustomerMapper.xml
index c69d89c..27cf2f4 100644
--- a/src/main/resources/mapper/basic/CustomerMapper.xml
+++ b/src/main/resources/mapper/basic/CustomerMapper.xml
@@ -177,14 +177,20 @@
         left join (
             select
                 sl.id,
-                sum(ascc.collection_amount) as receiptPaymentAmount
-            from account_sales_collection ascc
-            left join stock_out_record sor on FIND_IN_SET(sor.id, ascc.stock_out_record_ids) > 0
-            left join shipping_info s on sor.record_id = s.id
-            LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
-            WHERE sor.record_type='13'
-              and sor.approval_status=1
-            group by  sl.id
+                sum(t.collection_amount) as receiptPaymentAmount
+            from (
+                select
+                    ascc.collection_amount,
+                    s.sales_ledger_id
+                from account_sales_collection ascc
+                left join stock_out_record sor on FIND_IN_SET(sor.id, ascc.stock_out_record_ids) > 0
+                left join shipping_info s on sor.record_id = s.id
+                where sor.record_type='13'
+                  and sor.approval_status=1
+                group by ascc.id, s.sales_ledger_id
+            ) t
+            left join sales_ledger sl on t.sales_ledger_id = sl.id
+            group by sl.id
         )T1 on T1.id = sl.id
         left join (
             select sl.id,
diff --git a/src/main/resources/mapper/basic/SupplierManageMapper.xml b/src/main/resources/mapper/basic/SupplierManageMapper.xml
index 63bdf7e..2bc6fbd 100644
--- a/src/main/resources/mapper/basic/SupplierManageMapper.xml
+++ b/src/main/resources/mapper/basic/SupplierManageMapper.xml
@@ -13,6 +13,7 @@
         T1.company_phone,
         T1.bank_account_name,
         T1.bank_account_num,
+        T1.bank_code,
         T1.contact_user_name,
         T1.contact_user_phone,
         T1.maintain_user_id,
@@ -47,6 +48,7 @@
         T1.company_phone,
         T1.bank_account_name,
         T1.bank_account_num,
+        T1.bank_code,
         T1.contact_user_name,
         T1.contact_user_phone,
         T1.maintain_user_id,
@@ -106,17 +108,25 @@
        left join (
            select
                pl.id,
-               sum(app.payment_amount) as paymentAmount
-           from account_purchase_payment app
-           left join account_payment_application apa on app.account_payment_application_id = apa.id
-           left join stock_in_record sir on FIND_IN_SET(sir.id, apa.stock_in_record_ids) > 0
-               -- 10 绫诲瀷鎵嶅叧鑱旇川妫�琛�
-           LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
-               -- 鍔ㄦ�佸叧鑱旈噰璐紙鑷姩閫傞厤 7 鍜� 10锛�
-           LEFT JOIN purchase_ledger pl
-                     ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
-           WHERE sir.approval_status = 1
-             AND sir.record_type IN ('7','10')
+               sum(t.payment_amount) as paymentAmount
+           from (
+               select
+                   app.id,
+                   app.payment_amount,
+                   pl.id as purchase_ledger_id
+               from account_purchase_payment app
+               left join account_payment_application apa on app.account_payment_application_id = apa.id
+               left join stock_in_record sir on FIND_IN_SET(sir.id, apa.stock_in_record_ids) > 0
+                   -- 10 绫诲瀷鎵嶅叧鑱旇川妫�琛�
+               LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
+                   -- 鍔ㄦ�佸叧鑱旈噰璐紙鑷姩閫傞厤 7 鍜� 10锛�
+               LEFT JOIN purchase_ledger pl
+                         ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
+               WHERE sir.approval_status = 1
+                 AND sir.record_type IN ('7','10')
+               group by app.id, pl.id
+           ) t
+           left join purchase_ledger pl on t.purchase_ledger_id = pl.id
            group by pl.id
        )T1 on T1.id = pl.id
        left join (
diff --git a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
index 9e6839f..4ea9439 100644
--- a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
+++ b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -33,7 +33,7 @@
         WHEN (IFNULL(t2.qualitity, 0) - IFNULL(t2.locked_quantity, 0)) >0 THEN 1
         ELSE 0
         END as has_sufficient_stock,
-        (IFNULL(T1.quantity, 0) - IFNULL(t3.shipped_quantity, 0) - IFNULL(t5.pending_approval_quantity, 0)) as no_quantity,
+        NULL as no_quantity,
         IFNULL(t3.shipped_quantity, 0) as shipped_quantity,
         IFNULL(t6.return_quantity, 0) as return_quantity,
         IFNULL(t4.approved_stock_in_num, 0) as approved_stock_in_num,

--
Gitblit v1.9.3