From 4ea1509f0e88ee331e821459d4eefb0c9902b3e7 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 12 八月 2026 13:16:04 +0800
Subject: [PATCH] feat(account): 实现采购付款和销售回款功能

---
 src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java |   66 +++++++
 src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml                  |    8 
 .gitignore                                                                                   |    1 
 src/main/resources/mapper/basic/CustomerMapper.xml                                           |   22 +
 src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml                     |    8 
 src/main/resources/mapper/basic/SupplierManageMapper.xml                                     |   30 ++-
 docs/新增回款接口联调文档.md                                                                           |   97 ++++++++++
 src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java             |    9 +
 src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java    |   47 +++++
 src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java                     |   12 +
 docs/新增付款接口联调文档.md                                                                           |  104 +++++++++++
 src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java            |    7 
 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/sales/dto/SaveReceiptPaymentDto.java                                 |   35 +++
 src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java               |    7 
 src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java          |    9 +
 17 files changed, 488 insertions(+), 20 deletions(-)

diff --git a/.gitignore b/.gitignore
index 8fac07c..5d71ab9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@
 ######################################################################
 # Claude Code
 .claude/
+.mcp.json
 
 
 ### STS ###
diff --git "a/docs/\346\226\260\345\242\236\344\273\230\346\254\276\346\216\245\345\217\243\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/docs/\346\226\260\345\242\236\344\273\230\346\254\276\346\216\245\345\217\243\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..2a441f5
--- /dev/null
+++ "b/docs/\346\226\260\345\242\236\344\273\230\346\254\276\346\216\245\345\217\243\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,104 @@
+# 鏂板浠樻鎺ュ彛鑱旇皟鏂囨。
+
+## 姒傝堪
+
+鍦ㄤ粯娆惧彴璐﹂〉闈紙`src/views/procurementManagement/paymentLedger/index.vue`锛夊彸渚т緵搴斿晢鏄庣粏琛ㄦ牸涓紝姣忔潯鏁版嵁鏂板浜嗐�屾柊澧炰粯娆俱�嶆搷浣滄寜閽�傜偣鍑诲悗寮瑰嚭琛ㄥ崟锛屽~鍐欎粯娆句俊鎭苟鎻愪氦銆�
+
+---
+
+## 鎺ュ彛淇℃伅
+
+- **URL**: `/purchase/report/savePayment`
+- **Method**: `POST`
+- **Content-Type**: `application/json`
+
+---
+
+## 璇锋眰鍙傛暟
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| `supplierId` | String | 鏄� | 渚涘簲鍟咺D锛屾潵鑷富琛紙宸︿晶锛夊綋鍓嶉�変腑琛岀殑 `supplierId` |
+| `purchaseContractNumber` | String | 鏄� | 閲囪喘鍚堝悓鍙凤紝鏉ヨ嚜鏄庣粏琛岋紙鍙充晶锛夋暟鎹殑 `purchaseContractNumber` |
+| `paymentDate` | String | 鏄� | 浠樻鏃ユ湡锛屾牸寮� `YYYY-MM-DD` |
+| `paymentAmount` | Number | 鏄� | 浠樻閲戦锛屼繚鐣欎袱浣嶅皬鏁帮紝鏈�灏忓�� 0.01 |
+| `paymentMethod` | String | 鏄� | 浠樻鏂瑰紡锛屽彲閫夊�艰涓嬫柟鏋氫妇琛� |
+| `remark` | String | 鍚� | 澶囨敞淇℃伅 |
+
+### 浠樻鏂瑰紡鏋氫妇鍊�
+
+| 鍊� | 璇存槑 |
+|------|------|
+| `閾惰杞处` | 閾惰杞处 |
+| `鐜伴噾` | 鐜伴噾 |
+| `鏀エ` | 鏀エ |
+| `寰俊/鏀粯瀹漙 | 寰俊/鏀粯瀹� |
+| `鍏朵粬` | 鍏朵粬鏂瑰紡 |
+
+---
+
+## 璇锋眰绀轰緥
+
+```json
+{
+  "supplierId": "SUPP001",
+  "purchaseContractNumber": "CG-2024-0001",
+  "paymentDate": "2024-08-12",
+  "paymentAmount": 50000.00,
+  "paymentMethod": "閾惰杞处",
+  "remark": "鍚堝悓绗竴鏈熶粯娆�"
+}
+```
+
+---
+
+## 鍝嶅簲鏍煎紡
+
+### 鎴愬姛
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": null
+}
+```
+
+### 澶辫触
+
+```json
+{
+  "code": 500,
+  "msg": "鍏蜂綋閿欒淇℃伅",
+  "data": null
+}
+```
+
+---
+
+## 鍓嶇璋冪敤娴佺▼
+
+1. 鐢ㄦ埛鍦ㄥ乏渚т富琛ㄧ偣鍑绘煇渚涘簲鍟嗚锛屽彸渚у姞杞借渚涘簲鍟嗙殑鍚堝悓鏄庣粏
+2. 鐢ㄦ埛鍦ㄥ彸渚ф槑缁嗚〃鐐瑰嚮鏌愯鐨勩�屾柊澧炰粯娆俱�嶆寜閽�
+3. 寮瑰嚭瀵硅瘽妗嗭紝灞曠ず褰撳墠鍚堝悓鐨勯噰璐悎鍚屽彿锛堝彧璇伙級
+4. 鐢ㄦ埛濉啓浠樻鏃ユ湡銆侀噾棰濄�佹柟寮忋�佸娉ㄥ悗鐐瑰嚮纭
+5. 鍓嶇璋冪敤 `POST /purchase/report/savePayment`
+6. 鎴愬姛鍚庡叧闂脊妗嗭紝鑷姩鍒锋柊宸︿晶渚涘簲鍟嗘眹鎬昏〃鍜屽彸渚ф槑缁嗚〃
+7. 澶辫触鍒欐彁绀哄悗绔繑鍥炵殑 `msg` 閿欒淇℃伅
+
+---
+
+## 鍓嶇琛ㄥ崟鏍¢獙瑙勫垯
+
+| 瀛楁 | 瑙勫垯 |
+|------|------|
+| `paymentDate` | 蹇呭~锛屾湭閫夋嫨鏃舵彁绀�"璇烽�夋嫨浠樻鏃ユ湡" |
+| `paymentAmount` | 蹇呭~锛涗笉鑳借秴杩囧彲浠樻浣欓锛堝簲浠橀噾棰� - 浠樻閲戦锛夛紝瓒呴檺鏃舵彁绀�"浠樻閲戦涓嶈兘瓒呰繃鍙粯娆句綑棰� XXX 鍏�" |
+| `paymentMethod` | 蹇呭~锛屾湭閫夋嫨鏃舵彁绀�"璇烽�夋嫨浠樻鏂瑰紡" |
+| `remark` | 閫夊~锛屾棤鏍¢獙 |
+
+### 鍙粯娆句綑棰濊绠�
+
+褰撳墠琛屽彲浠樻浣欓 = `payableAmount`锛堝簲浠橀噾棰濓級 - `paymentAmount`锛堜粯娆鹃噾棰濓級
+
+姣忔鎵撳紑鏂板浠樻寮规鏃讹紝浠樻閲戦杈撳叆妗嗕笅鏂逛細鏄剧ず榛勮壊鎻愮ず鏂囧瓧"褰撳墠鍙粯娆句綑棰濓細XXX 鍏�"銆�
diff --git "a/docs/\346\226\260\345\242\236\345\233\236\346\254\276\346\216\245\345\217\243\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/docs/\346\226\260\345\242\236\345\233\236\346\254\276\346\216\245\345\217\243\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..556c4f6
--- /dev/null
+++ "b/docs/\346\226\260\345\242\236\345\233\236\346\254\276\346\216\245\345\217\243\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,97 @@
+# 鏂板鍥炴鎺ュ彛鑱旇皟鏂囨。
+
+## 姒傝堪
+
+鍦ㄦ敹浠樻鍙拌处椤甸潰锛坄src/views/salesManagement/receiptPaymentLedger/index.vue`锛夊彸渚у鎴锋槑缁嗚〃鏍间腑锛屾瘡鏉℃暟鎹柊澧炰簡銆屾柊澧炲洖娆俱�嶆搷浣滄寜閽�傜偣鍑诲悗寮瑰嚭琛ㄥ崟锛屽~鍐欏洖娆句俊鎭苟鎻愪氦銆�
+
+---
+
+## 鎺ュ彛淇℃伅
+
+- **URL**: `/metricStatistics/saveReceiptPayment`
+- **Method**: `POST`
+- **Content-Type**: `application/json`
+
+---
+
+## 璇锋眰鍙傛暟
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| `customerId` | String | 鏄� | 瀹㈡埛ID锛屾潵鑷富琛紙宸︿晶锛夊綋鍓嶉�変腑琛岀殑 `customerId` |
+| `salesContractNo` | String | 鏄� | 閿�鍞悎鍚屽彿锛屾潵鑷槑缁嗚锛堝彸渚э級鏁版嵁鐨� `salesContractNo` |
+| `paymentDate` | String | 鏄� | 鍥炴鏃ユ湡锛屾牸寮� `YYYY-MM-DD` |
+| `paymentAmount` | Number | 鏄� | 鍥炴閲戦锛屼繚鐣欎袱浣嶅皬鏁帮紝鏈�灏忓�� 0.01 |
+| `paymentMethod` | String | 鏄� | 鍥炴鏂瑰紡锛屽彲閫夊�艰涓嬫柟鏋氫妇琛� |
+| `remark` | String | 鍚� | 澶囨敞淇℃伅 |
+
+### 鍥炴鏂瑰紡鏋氫妇鍊�
+
+| 鍊� | 璇存槑 |
+|------|------|
+| `閾惰杞处` | 閾惰杞处 |
+| `鐜伴噾` | 鐜伴噾 |
+| `鏀エ` | 鏀エ |
+| `寰俊/鏀粯瀹漙 | 寰俊/鏀粯瀹� |
+| `鍏朵粬` | 鍏朵粬鏂瑰紡 |
+
+---
+
+## 璇锋眰绀轰緥
+
+```json
+{
+  "customerId": "CUST001",
+  "salesContractNo": "XS-2024-0001",
+  "paymentDate": "2024-08-12",
+  "paymentAmount": 50000.00,
+  "paymentMethod": "閾惰杞处",
+  "remark": "鍚堝悓绗竴鏈熷洖娆�"
+}
+```
+
+---
+
+## 鍝嶅簲鏍煎紡
+
+### 鎴愬姛
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": null
+}
+```
+
+### 澶辫触
+
+```json
+{
+  "code": 500,
+  "msg": "鍏蜂綋閿欒淇℃伅",
+  "data": null
+}
+```
+
+---
+
+## 鍓嶇璋冪敤娴佺▼
+
+1. 鐢ㄦ埛鍦ㄥ彸渚ф槑缁嗚〃鐐瑰嚮鏌愯鐨勩�屾柊澧炲洖娆俱�嶆寜閽�
+2. 寮瑰嚭瀵硅瘽妗嗭紝灞曠ず褰撳墠鍚堝悓鐨勯攢鍞悎鍚屽彿锛堝彧璇伙級
+3. 鐢ㄦ埛濉啓鍥炴鏃ユ湡銆侀噾棰濄�佹柟寮忋�佸娉ㄥ悗鐐瑰嚮纭
+4. 鍓嶇璋冪敤 `POST /metricStatistics/saveReceiptPayment`
+5. 鎴愬姛鍚庡叧闂脊妗嗭紝鑷姩鍒锋柊宸︿晶瀹㈡埛姹囨�昏〃鍜屽彸渚ф槑缁嗚〃
+6. 澶辫触鍒欐彁绀哄悗绔繑鍥炵殑 `msg` 閿欒淇℃伅
+
+---
+
+## 鍓嶇琛ㄥ崟鏍¢獙瑙勫垯
+
+| 瀛楁 | 瑙勫垯 |
+|------|------|
+| `paymentDate` | 蹇呭~锛屾湭閫夋嫨鏃舵彁绀�"璇烽�夋嫨鍥炴鏃ユ湡" |
+| `paymentAmount` | 蹇呭~锛屾湭杈撳叆鏃舵彁绀�"璇疯緭鍏ュ洖娆鹃噾棰�" |
+| `paymentMethod` | 蹇呭~锛屾湭閫夋嫨鏃舵彁绀�"璇烽�夋嫨鍥炴鏂瑰紡" |
+| `remark` | 閫夊~锛屾棤鏍¢獙 |
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..6f112bf 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,11 @@
     IPage<AccountPurchasePaymentVo> listPageAccountPurchasePayment(Page page, @Param("req") AccountPurchasePaymentDto accountPurchasePaymentDto);
 
     List<IncomeExpenseAnalysisDto> selectPayment(@Param("startStr") String startStr, @Param("endStr") String endStr, @Param("dateFormat") String dateFormat);
+
+    /**
+     * 鏌ヨ鏌愰噰璐彴璐︿笅宸插鎵圭殑閲囪喘鍏ュ簱璁板綍id鍒楄〃
+     * @param purchaseLedgerId 閲囪喘鍙拌处id
+     * @return 鍏ュ簱璁板綍id鍒楄〃
+     */
+    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..700d625 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,11 @@
     List<SalesOutboundVo> getOutboundBatchesByCustomer(@Param("customerId") Integer customerId);
 
     List<IncomeExpenseAnalysisDto> selectIncomeStats(@Param("startStr") String startStr, @Param("endStr") String endStr, @Param("dateFormat") String dateFormat);
+
+    /**
+     * 鏌ヨ鏌愰攢鍞彴璐︿笅宸插鎵圭殑閿�鍞嚭搴撹褰昳d鍒楄〃
+     * @param salesLedgerId 閿�鍞彴璐d
+     * @return 鍑哄簱璁板綍id鍒楄〃
+     */
+    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..1246d68 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,63 @@
         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());
+        if (CollectionUtils.isEmpty(stockInRecordIds)) {
+            throw new ServiceException("璇ュ悎鍚屾殏鏃犲彲浠樻鐨勯噰璐叆搴撹褰�");
+        }
+
+        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 5f328bc..6b905c9 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,15 +17,20 @@
 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;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -40,6 +46,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 +97,46 @@
         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());
+        if (CollectionUtils.isEmpty(stockOutRecordIds)) {
+            throw new ServiceException("璇ュ悎鍚屾殏鏃犲彲鍥炴鐨勯攢鍞嚭搴撹褰�");
+        }
+
+        AccountSalesCollection collection = new AccountSalesCollection();
+        collection.setCustomerId(dto.getCustomerId().intValue());
+        collection.setStockOutRecordIds(stockOutRecordIds.stream().map(String::valueOf).collect(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/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..cb187d9
--- /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;
+}
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..4519916
--- /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;
+}
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 4898072..66ae5e4 100644
--- a/src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml
+++ b/src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml
@@ -97,5 +97,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 442173e..b7410dc 100644
--- a/src/main/resources/mapper/basic/CustomerMapper.xml
+++ b/src/main/resources/mapper/basic/CustomerMapper.xml
@@ -174,14 +174,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
diff --git a/src/main/resources/mapper/basic/SupplierManageMapper.xml b/src/main/resources/mapper/basic/SupplierManageMapper.xml
index 810e137..ccc005e 100644
--- a/src/main/resources/mapper/basic/SupplierManageMapper.xml
+++ b/src/main/resources/mapper/basic/SupplierManageMapper.xml
@@ -121,17 +121,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 (

--
Gitblit v1.9.3