6 天以前 4ea1509f0e88ee331e821459d4eefb0c9902b3e7
feat(account): 实现采购付款和销售回款功能

- 在 AccountingReportController 中新增 savePayment 接口用于新增付款
- 在 AccountPurchasePaymentService 中实现 savePayment 业务逻辑
- 添加 selectStockInRecordIdsByPurchaseLedgerId 查询方法获取采购入库记录
- 在 MetricStatisticsController 中新增 saveReceiptPayment 接口用于新增回款
- 在 AccountSalesCollectionService 中实现 saveReceiptPayment 业务逻辑
- 添加 selectStockOutRecordIdsBySalesLedgerId 查询方法获取销售出库记录
- 创建 SavePaymentDto 和 SaveReceiptPaymentDto 数据传输对象
- 更新 CustomerMapper.xml 和 SupplierManageMapper.xml 优化聚合查询
- 添加新增付款和回款的接口联调文档
已修改13个文件
已添加4个文件
478 ■■■■■ 文件已修改
.gitignore 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/新增付款接口联调文档.md 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/新增回款接口联调文档.md 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/dto/SavePaymentDto.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SaveReceiptPaymentDto.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerMapper.xml 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/SupplierManageMapper.xml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -11,6 +11,7 @@
######################################################################
# Claude Code
.claude/
.mcp.json
### STS ###
docs/ÐÂÔö¸¶¿î½Ó¿ÚÁªµ÷Îĵµ.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,104 @@
# æ–°å¢žä»˜æ¬¾æŽ¥å£è”调文档
## æ¦‚è¿°
在付款台账页面(`src/views/procurementManagement/paymentLedger/index.vue`)右侧供应商明细表格中,每条数据新增了「新增付款」操作按钮。点击后弹出表单,填写付款信息并提交。
---
## æŽ¥å£ä¿¡æ¯
- **URL**: `/purchase/report/savePayment`
- **Method**: `POST`
- **Content-Type**: `application/json`
---
## è¯·æ±‚参数
| å­—段 | ç±»åž‹ | å¿…å¡« | è¯´æ˜Ž |
|------|------|------|------|
| `supplierId` | String | æ˜¯ | ä¾›åº”商ID,来自主表(左侧)当前选中行的 `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 å…ƒ"。
docs/ÐÂÔö»Ø¿î½Ó¿ÚÁªµ÷Îĵµ.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` | é€‰å¡«ï¼Œæ— æ ¡éªŒ |
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);
}
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);
    /**
     * æŸ¥è¯¢æŸé”€å”®å°è´¦ä¸‹å·²å®¡æ‰¹çš„销售出库记录id列表
     * @param salesLedgerId é”€å”®å°è´¦id
     * @return å‡ºåº“记录id列表
     */
    List<Long> selectStockOutRecordIdsBySalesLedgerId(@Param("salesLedgerId") Long salesLedgerId);
}
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);
    }
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);
    }
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);
}
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);
}
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));
    }
}
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 = "供应商ID")
    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;
}
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));
    }
}
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;
}
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>
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>
src/main/resources/mapper/basic/CustomerMapper.xml
@@ -174,13 +174,19 @@
        left join (
            select
                sl.id,
                sum(ascc.collection_amount) as receiptPaymentAmount
                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
            LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
            WHERE sor.record_type='13'
                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 (
src/main/resources/mapper/basic/SupplierManageMapper.xml
@@ -121,7 +121,12 @@
       left join (
           select
               pl.id,
               sum(app.payment_amount) as paymentAmount
               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
@@ -132,6 +137,9 @@
                     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 (