调整收付款问题

This commit is contained in:
2026-08-31 14:55:50 +08:00
parent 27ed35f9dd
commit 35309b32ae
3 changed files with 84 additions and 23 deletions
@@ -80,8 +80,11 @@ public class InvoiceApplicationController extends BladeController {
@GetMapping("/settlement-candidates")
@ApiOperationSupport(order = 3)
@Operation(summary = "可开票正式结算单")
public R<List<Map<String, Object>>> settlementCandidates(@RequestParam(required = false) String keyword) {
return R.data(invoiceApplicationService.settlementCandidates(keyword));
public R<IPage<Map<String, Object>>> settlementCandidates(Query query,
@RequestParam(required = false) String keyword,
@RequestParam(required = false) String contractCategory) {
return R.data(invoiceApplicationService.settlementCandidates(
Condition.getPage(query), keyword, contractCategory));
}
@GetMapping("/settlement-details")
@@ -44,7 +44,7 @@ import java.util.Map;
public interface IInvoiceApplicationService extends BaseService<InvoiceApplication> {
IPage<InvoiceApplicationVO> selectPage(IPage<InvoiceApplication> page, InvoiceApplicationVO query);
InvoiceApplicationVO detail(Long id);
List<Map<String, Object>> settlementCandidates(String keyword);
IPage<Map<String, Object>> settlementCandidates(IPage<?> page, String keyword, String contractCategory);
List<FormalSettlementDetail> settlementDetails(String settlementIds);
Map<String, Object> receiverInformation(String settlementIds);
Long saveDraft(InvoiceApplicationSaveRequest request);
@@ -28,6 +28,7 @@ package org.springblade.transport.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
@@ -37,6 +38,7 @@ import org.springblade.core.tool.utils.Func;
import org.springblade.transport.mapper.CustomerArchiveMapper;
import org.springblade.transport.mapper.CustomerContactMapper;
import org.springblade.transport.mapper.CustomerInvoiceInfoMapper;
import org.springblade.transport.mapper.ContractManageMapper;
import org.springblade.transport.mapper.FormalSettlementDetailMapper;
import org.springblade.transport.mapper.FormalSettlementMapper;
import org.springblade.transport.mapper.InvoiceApplicationDetailMapper;
@@ -50,6 +52,7 @@ import org.springblade.transport.pojo.dto.InvoiceApplicationStatusRequest;
import org.springblade.transport.pojo.entity.CustomerArchive;
import org.springblade.transport.pojo.entity.CustomerContact;
import org.springblade.transport.pojo.entity.CustomerInvoiceInfo;
import org.springblade.transport.pojo.entity.ContractManage;
import org.springblade.transport.pojo.entity.FormalSettlement;
import org.springblade.transport.pojo.entity.FormalSettlementDetail;
import org.springblade.transport.pojo.entity.InvoiceApplication;
@@ -102,6 +105,7 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
private final InvoiceApplicationRecordMapper recordMapper;
private final FormalSettlementMapper formalSettlementMapper;
private final FormalSettlementDetailMapper formalSettlementDetailMapper;
private final ContractManageMapper contractManageMapper;
private final CustomerArchiveMapper customerArchiveMapper;
private final CustomerInvoiceInfoMapper customerInvoiceInfoMapper;
private final CustomerContactMapper customerContactMapper;
@@ -142,33 +146,87 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
}
@Override
public List<Map<String, Object>> settlementCandidates(String keyword) {
public IPage<Map<String, Object>> settlementCandidates(IPage<?> page, String keyword,
String contractCategory) {
List<Long> contractIds = Func.isEmpty(contractCategory) ? List.of()
: contractManageMapper.selectList(Wrappers.<ContractManage>lambdaQuery()
.select(ContractManage::getId)
.eq(ContractManage::getContractCategory, contractCategory)
.eq(ContractManage::getIsDeleted, 0))
.stream().map(ContractManage::getId).toList();
if (Func.isNotEmpty(contractCategory) && contractIds.isEmpty()) {
return new Page<>(page.getCurrent(), page.getSize(), 0);
}
List<FormalSettlement> settlements = formalSettlementMapper.selectList(Wrappers.<FormalSettlement>lambdaQuery()
.eq(FormalSettlement::getSettlementType, "payable")
.eq(FormalSettlement::getApprovalStatus, APPROVED)
.eq(FormalSettlement::getStatus, 1)
.in(Func.isNotEmpty(contractCategory), FormalSettlement::getContractId, contractIds)
.and(Func.isNotEmpty(keyword), wrapper -> wrapper.like(FormalSettlement::getFormalSettlementNo, keyword)
.or().like(FormalSettlement::getProjectName, keyword)
.or().like(FormalSettlement::getContractName, keyword))
.orderByDesc(FormalSettlement::getCreateTime).last("limit 200"));
return settlements.stream().map(settlement -> {
BigDecimal available = availableAmount(settlement, null);
Map<String, Object> row = new LinkedHashMap<>();
row.put("id", settlement.getId());
row.put("formalSettlementNo", settlement.getFormalSettlementNo());
row.put("projectId", settlement.getProjectId());
row.put("projectName", settlement.getProjectName());
row.put("deptId", settlement.getDeptId());
row.put("deptName", settlement.getDeptName());
row.put("contractId", settlement.getContractId());
row.put("contractNo", settlement.getContractNo());
row.put("contractName", settlement.getContractName());
row.put("issuerName", settlement.getPayeeName());
row.put("receiverName", settlement.getPayerName());
row.put("settlementAmount", money(settlement.getSettlementAmount()));
row.put("availableInvoiceAmount", available);
return row;
}).filter(row -> ((BigDecimal) row.get("availableInvoiceAmount")).compareTo(BigDecimal.ZERO) > 0).toList();
.orderByDesc(FormalSettlement::getCreateTime));
Map<Long, BigDecimal> availableAmounts = candidateAvailableAmounts(settlements);
List<Map<String, Object>> candidates = settlements.stream()
.map(settlement -> settlementCandidateMap(settlement,
availableAmounts.getOrDefault(settlement.getId(), BigDecimal.ZERO)))
.filter(row -> ((BigDecimal) row.get("availableInvoiceAmount")).compareTo(BigDecimal.ZERO) > 0)
.toList();
long current = Math.max(page.getCurrent(), 1);
long size = Math.max(page.getSize(), 1);
long offset = Math.min((current - 1) * size, candidates.size());
long end = Math.min(offset + size, candidates.size());
Page<Map<String, Object>> result = new Page<>(current, size, candidates.size());
result.setRecords(candidates.subList((int) offset, (int) end));
return result;
}
private Map<Long, BigDecimal> candidateAvailableAmounts(List<FormalSettlement> settlements) {
if (settlements.isEmpty()) return Map.of();
List<Long> settlementIds = settlements.stream().map(FormalSettlement::getId).toList();
List<InvoiceApplicationSettlement> relations = settlementRelationMapper.selectList(
Wrappers.<InvoiceApplicationSettlement>lambdaQuery()
.in(InvoiceApplicationSettlement::getFormalSettlementId, settlementIds));
if (relations.isEmpty()) {
return settlements.stream().collect(Collectors.toMap(FormalSettlement::getId,
settlement -> money(settlement.getSettlementAmount()), (first, duplicate) -> first,
LinkedHashMap::new));
}
Map<Long, InvoiceApplication> applications = listByIds(relations.stream()
.map(InvoiceApplicationSettlement::getInvoiceApplicationId).distinct().toList()).stream()
.collect(Collectors.toMap(InvoiceApplication::getId, Function.identity()));
Map<Long, BigDecimal> allocatedAmounts = relations.stream()
.filter(relation -> {
InvoiceApplication application = applications.get(relation.getInvoiceApplicationId());
return application != null && !VOIDED.equals(application.getApprovalStatus())
&& !Objects.equals(application.getIsDeleted(), 1);
})
.collect(Collectors.groupingBy(InvoiceApplicationSettlement::getFormalSettlementId,
Collectors.reducing(BigDecimal.ZERO,
relation -> money(relation.getAllocatedInvoiceAmount()), BigDecimal::add)));
return settlements.stream().collect(Collectors.toMap(FormalSettlement::getId,
settlement -> money(settlement.getSettlementAmount())
.subtract(allocatedAmounts.getOrDefault(settlement.getId(), BigDecimal.ZERO))
.max(BigDecimal.ZERO),
(first, duplicate) -> first, LinkedHashMap::new));
}
private Map<String, Object> settlementCandidateMap(FormalSettlement settlement, BigDecimal available) {
Map<String, Object> row = new LinkedHashMap<>();
row.put("id", settlement.getId());
row.put("formalSettlementNo", settlement.getFormalSettlementNo());
row.put("projectId", settlement.getProjectId());
row.put("projectName", settlement.getProjectName());
row.put("deptId", settlement.getDeptId());
row.put("deptName", settlement.getDeptName());
row.put("contractId", settlement.getContractId());
row.put("contractNo", settlement.getContractNo());
row.put("contractName", settlement.getContractName());
row.put("issuerName", settlement.getPayeeName());
row.put("receiverName", settlement.getPayerName());
row.put("settlementAmount", money(settlement.getSettlementAmount()));
row.put("availableInvoiceAmount", available);
return row;
}
@Override