From 397e9f3b62b5c7c3b4de790bc682bd7ff2e2f9c0 Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Sat, 5 Sep 2026 23:26:00 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=BB=93=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FormalSettlementInvoiceClaimRequest.java | 15 ++++ .../entity/PreSettlementChangeRecord.java | 6 ++ .../FormalSettlementController.java | 9 ++ .../service/IFormalSettlementService.java | 2 + .../impl/FormalSettlementServiceImpl.java | 89 +++++++++++++++++-- .../impl/PreSettlementServiceImpl.java | 49 ++++++++-- .../ReceivablePayableDetailServiceImpl.java | 20 ++++- .../impl/SettlementAdjustmentServiceImpl.java | 4 +- .../wrapper/FormalSettlementWrapper.java | 3 +- .../blade_pre_settlement_20260818.sql | 2 + ...ttlement_change_record_detail_20260905.sql | 33 +++++++ 11 files changed, 213 insertions(+), 19 deletions(-) create mode 100644 blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementInvoiceClaimRequest.java create mode 100644 doc/sql/transport/blade_pre_settlement_change_record_detail_20260905.sql diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementInvoiceClaimRequest.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementInvoiceClaimRequest.java new file mode 100644 index 0000000..25dbff3 --- /dev/null +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementInvoiceClaimRequest.java @@ -0,0 +1,15 @@ +package org.springblade.transport.pojo.dto; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** 正式结算发票认领请求。 */ +@Data +public class FormalSettlementInvoiceClaimRequest implements Serializable { + @Serial private static final long serialVersionUID = 1L; + private Long formalSettlementId; + private List invoices; +} diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/PreSettlementChangeRecord.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/PreSettlementChangeRecord.java index d1e86ba..1322073 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/PreSettlementChangeRecord.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/PreSettlementChangeRecord.java @@ -47,6 +47,12 @@ public class PreSettlementChangeRecord extends TenantEntity { @Schema(description = "变更内容") private String changeContent; + @Schema(description = "变更前数据JSON") + private String beforeData; + + @Schema(description = "变更后数据JSON") + private String afterData; + @Schema(description = "操作人") private String operatorName; diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/FormalSettlementController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/FormalSettlementController.java index e926e86..758fcb5 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/FormalSettlementController.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/FormalSettlementController.java @@ -22,6 +22,7 @@ import org.springblade.transport.pojo.dto.FormalSettlementSaveRequest; import org.springblade.transport.pojo.dto.FormalSettlementPaymentRequest; import org.springblade.transport.pojo.dto.FormalSettlementBatchPaymentRequest; import org.springblade.transport.pojo.dto.FormalSettlementStatusRequest; +import org.springblade.transport.pojo.dto.FormalSettlementInvoiceClaimRequest; import org.springblade.transport.pojo.dto.PreSettlementDetailAdjustRequest; import org.springblade.transport.pojo.entity.FormalSettlementDetailFee; import org.springblade.transport.pojo.vo.FormalSettlementVO; @@ -169,6 +170,14 @@ public class FormalSettlementController extends BladeController { return R.data(formalSettlementService.applyPayments(request)); } + @PostMapping("/claim-invoices") + @ApiOperationSupport(order = 18) + @Operation(summary = "认领发票并同步付款申请") + public R claimInvoices(@RequestBody FormalSettlementInvoiceClaimRequest request) { + formalSettlementService.claimInvoices(request); + return R.success("发票认领成功"); + } + @GetMapping("/receipt-claims") @ApiOperationSupport(order = 19) @Operation(summary = "应收正式结算单收款认领信息") diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IFormalSettlementService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IFormalSettlementService.java index 85016e0..cd8557b 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IFormalSettlementService.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IFormalSettlementService.java @@ -21,6 +21,7 @@ import org.springblade.transport.pojo.entity.FormalSettlementDetailFee; import java.util.List; import org.springblade.transport.pojo.dto.FormalSettlementPaymentRequest; import org.springblade.transport.pojo.dto.FormalSettlementBatchPaymentRequest; +import org.springblade.transport.pojo.dto.FormalSettlementInvoiceClaimRequest; /** * 正式结算单服务 @@ -45,4 +46,5 @@ public interface IFormalSettlementService extends BaseService void refreshPaymentSummariesForPreSettlement(Long preSettlementId); String applyPayment(FormalSettlementPaymentRequest request); List applyPayments(FormalSettlementBatchPaymentRequest request); + void claimInvoices(FormalSettlementInvoiceClaimRequest request); } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java index d122787..29cc0a6 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java @@ -32,6 +32,7 @@ import org.springblade.transport.mapper.PreSettlementDetailFeeMapper; import org.springblade.transport.mapper.PreSettlementMapper; import org.springblade.transport.mapper.PreSettlementSummaryFeeMapper; import org.springblade.transport.mapper.PaymentApplicationMapper; +import org.springblade.transport.mapper.PaymentApplicationInvoiceMapper; import org.springblade.transport.mapper.PaymentApplicationSettlementMapper; import org.springblade.transport.mapper.ReceiptClaimSettlementMapper; import org.springblade.transport.mapper.ReceivablePayableDetailMapper; @@ -40,6 +41,7 @@ import org.springblade.transport.mapper.SettlementAdjustmentMapper; import org.springblade.transport.pojo.dto.FormalSettlementSaveRequest; import org.springblade.transport.pojo.dto.FormalSettlementPaymentRequest; import org.springblade.transport.pojo.dto.FormalSettlementBatchPaymentRequest; +import org.springblade.transport.pojo.dto.FormalSettlementInvoiceClaimRequest; import org.springblade.transport.pojo.dto.FormalSettlementStatusRequest; import org.springblade.transport.pojo.dto.PreSettlementDetailAdjustRequest; import org.springblade.transport.pojo.entity.FormalSettlement; @@ -58,6 +60,7 @@ import org.springblade.transport.pojo.entity.PreSettlementDetail; import org.springblade.transport.pojo.entity.PreSettlementDetailFee; import org.springblade.transport.pojo.entity.PreSettlementSummaryFee; import org.springblade.transport.pojo.entity.PaymentApplication; +import org.springblade.transport.pojo.entity.PaymentApplicationInvoice; import org.springblade.transport.pojo.entity.PaymentApplicationSettlement; import org.springblade.transport.pojo.entity.ReceiptClaimSettlement; import org.springblade.transport.pojo.entity.ReceivablePayableDetail; @@ -125,6 +128,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl invoices = request.getInvoices(); + Set invoiceNumbers = new LinkedHashSet<>(); + BigDecimal matchedTotal = BigDecimal.ZERO; + for (FormalSettlementSaveRequest.Invoice item : invoices) { + String invoiceNo = item == null ? "" : requiredText(item.getInvoiceNo(), "发票号"); + if (!invoiceNumbers.add(invoiceNo)) throw new ServiceException("发票号" + invoiceNo + "重复"); + matchedTotal = matchedTotal.add(money(item.getMatchedAmount())); + } + if (matchedTotal.compareTo(money(settlement.getSettlementAmount())) > 0) { + throw new ServiceException("发票匹配结算单金额合计不能超过结算金额"); + } + List existingInvoices = invoiceMapper.selectList( + Wrappers.lambdaQuery().eq(FormalSettlementInvoice::getFormalSettlementId, settlement.getId())); + Set existingNumbers = existingInvoices.stream().map(FormalSettlementInvoice::getInvoiceNo) + .filter(Objects::nonNull).collect(Collectors.toSet()); + int lineNo = existingInvoices.stream().map(FormalSettlementInvoice::getLineNo).filter(Objects::nonNull) + .max(Integer::compareTo).orElse(0) + 1; + BigDecimal insertedMatchedTotal = BigDecimal.ZERO; + for (FormalSettlementSaveRequest.Invoice item : invoices) { + if (existingNumbers.contains(item.getInvoiceNo())) continue; + FormalSettlementInvoice invoice = new FormalSettlementInvoice(); + invoice.setFormalSettlementId(settlement.getId()); invoice.setLineNo(lineNo++); + invoice.setInvoiceNo(item.getInvoiceNo()); invoice.setInvoiceDate(item.getInvoiceDate()); + invoice.setInvoiceType(item.getInvoiceType()); invoice.setTaxRate(item.getTaxRate()); + invoice.setInvoiceAmount(money(item.getInvoiceAmount())); + invoice.setAvailableInvoiceAmount(money(item.getAvailableInvoiceAmount())); + invoice.setMatchedAmount(money(item.getMatchedAmount())); invoice.setAttachmentJson(item.getAttachmentJson()); + invoiceMapper.insert(invoice); + insertedMatchedTotal = insertedMatchedTotal.add(money(item.getMatchedAmount())); + } + List relations = paymentApplicationSettlementMapper.selectList( + Wrappers.lambdaQuery().eq(PaymentApplicationSettlement::getFormalSettlementId, settlement.getId()) + .eq(PaymentApplicationSettlement::getIsDeleted, 0)); + Set paymentApplicationIds = new LinkedHashSet<>(relations.stream() + .map(PaymentApplicationSettlement::getPaymentApplicationId).filter(Objects::nonNull).toList()); + paymentApplicationIds.addAll(paymentApplicationMapper.selectList(Wrappers.lambdaQuery() + .eq(PaymentApplication::getSettlementId, settlement.getId()).eq(PaymentApplication::getIsDeleted, 0)) + .stream().map(PaymentApplication::getId).toList()); + for (Long paymentApplicationId : paymentApplicationIds) { + List old = paymentApplicationInvoiceMapper.selectList( + Wrappers.lambdaQuery().eq(PaymentApplicationInvoice::getPaymentApplicationId, paymentApplicationId)); + Set nums = old.stream().map(PaymentApplicationInvoice::getInvoiceNo).filter(Objects::nonNull).collect(Collectors.toSet()); + BigDecimal paymentMatchedTotal = old.stream().map(PaymentApplicationInvoice::getMatchedAmount).map(this::money) + .reduce(BigDecimal.ZERO, BigDecimal::add); + int paymentLine = old.stream().map(PaymentApplicationInvoice::getLineNo).filter(Objects::nonNull).max(Integer::compareTo).orElse(0) + 1; + for (FormalSettlementSaveRequest.Invoice item : invoices) { + if (nums.contains(item.getInvoiceNo())) continue; + PaymentApplicationInvoice invoice = new PaymentApplicationInvoice(); + invoice.setPaymentApplicationId(paymentApplicationId); invoice.setLineNo(paymentLine++); + invoice.setSettlementNo(settlement.getFormalSettlementNo()); invoice.setInvoiceNo(item.getInvoiceNo()); + invoice.setInvoiceDate(item.getInvoiceDate()); invoice.setInvoiceType(item.getInvoiceType()); + invoice.setTaxRate(item.getTaxRate()); invoice.setInvoiceAmount(money(item.getInvoiceAmount())); + invoice.setMatchedAmount(money(item.getMatchedAmount())); invoice.setAttachmentJson(item.getAttachmentJson()); + paymentApplicationInvoiceMapper.insert(invoice); + paymentMatchedTotal = paymentMatchedTotal.add(money(item.getMatchedAmount())); + } + PaymentApplication payment = paymentApplicationMapper.selectById(paymentApplicationId); + if (payment != null) { + payment.setMatchedInvoiceAmount(paymentMatchedTotal); + payment.setInvoiceStatus(paymentMatchedTotal.compareTo(BigDecimal.ZERO) > 0 ? "matched" : "unmatched"); + paymentApplicationMapper.updateById(payment); + } + } + settlement.setInvoiceAmount(money(settlement.getInvoiceAmount()).add(insertedMatchedTotal)); + settlement.setInvoiceStatus(invoiceStatus(settlement.getInvoiceAmount(), settlement.getSettlementAmount())); + updateById(settlement); + } + private String createPayment(FormalSettlement settlement, BigDecimal appliedAmount, String remark) { if (!APPROVED.equals(settlement.getApprovalStatus())) throw new ServiceException("仅审批通过的正式结算单允许发起付款申请"); if (!"payable".equals(settlement.getSettlementType())) throw new ServiceException("仅应付正式结算单允许发起付款申请"); @@ -808,8 +887,8 @@ public class FormalSettlementServiceImpl extends BaseServiceImpllambdaQuery().eq(FormalSettlementSource::getFormalSettlementId, entity.getId())).stream().map(FormalSettlementSource::getPreSettlementNo).collect(Collectors.joining(","))); return vo; } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java index 5ce49ef..0fd3b68 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java @@ -605,6 +605,8 @@ public class PreSettlementServiceImpl extends BaseServiceImpl changes = new ArrayList<>(); + Map beforeData = new LinkedHashMap<>(); + Map afterData = new LinkedHashMap<>(); for (PreSettlementDetailAdjustRequest.FeeRow requestRow : request.getRows()) { PreSettlementDetailFee fee = existingMap.get(requestRow.getId()); if (fee == null) { @@ -632,19 +634,19 @@ public class PreSettlementServiceImpl extends BaseServiceImpl afterFeeItems = parseFeeItems(fee.getFeeItemsJson()); Set feeItemNames = new LinkedHashSet<>(beforeFeeItems.keySet()); feeItemNames.addAll(afterFeeItems.keySet()); - feeItemNames.forEach(name -> appendChange(changes, prefix + name, + feeItemNames.forEach(name -> appendChange(changes, beforeData, afterData, prefix + name, beforeFeeItems.get(name), afterFeeItems.get(name))); - appendChange(changes, prefix + "结算金额(含税)", beforeAmount, afterAmount); - appendChange(changes, prefix + "结算金额(不含税)", beforeNoTaxAmount, + appendChange(changes, beforeData, afterData, prefix + "结算金额(含税)", beforeAmount, afterAmount); + appendChange(changes, beforeData, afterData, prefix + "结算金额(不含税)", beforeNoTaxAmount, fee.getSettlementAmountNoTax()); - appendTextChange(changes, prefix + "备注", beforeRemark, fee.getRemark()); + appendTextChange(changes, beforeData, afterData, prefix + "备注", beforeRemark, fee.getRemark()); } if (changes.isEmpty()) { throw new ServiceException("未修改任何结算明细费用"); @@ -653,7 +655,7 @@ public class PreSettlementServiceImpl extends BaseServiceImpl beforeData, Map afterData) { PreSettlementChangeRecord record = new PreSettlementChangeRecord(); record.setPreSettlementId(settlementId); record.setChangeType(changeType); record.setLineNo(lineNo); record.setOperationType(operationType); record.setChangeContent(content); + record.setBeforeData(beforeData == null ? null : JsonUtil.toJson(beforeData)); + record.setAfterData(afterData == null ? null : JsonUtil.toJson(afterData)); record.setOperatorName(Func.isEmpty(AuthUtil.getUserName()) ? "system" : AuthUtil.getUserName()); record.setChangeReason(reason); record.setChangeTime(LocalDateTime.now()); @@ -1476,6 +1485,17 @@ public class PreSettlementServiceImpl extends BaseServiceImpl changes, Map beforeData, Map afterData, + String fieldName, BigDecimal before, BigDecimal after) { + BigDecimal oldValue = money(before); + BigDecimal newValue = money(after); + if (oldValue.compareTo(newValue) != 0) { + changes.add("【" + fieldName + "】从【" + oldValue + "】调整为【" + newValue + "】"); + beforeData.put(fieldName, before); + afterData.put(fieldName, after); + } + } + private void appendTextChange(List changes, String fieldName, String before, String after) { String oldValue = before == null ? "" : before; String newValue = after == null ? "" : after; @@ -1484,6 +1504,17 @@ public class PreSettlementServiceImpl extends BaseServiceImpl changes, Map beforeData, Map afterData, + String fieldName, String before, String after) { + String oldValue = before == null ? "" : before; + String newValue = after == null ? "" : after; + if (!Objects.equals(oldValue, newValue)) { + changes.add("【" + fieldName + "】从【" + oldValue + "】调整为【" + newValue + "】"); + beforeData.put(fieldName, before); + afterData.put(fieldName, after); + } + } + private String firstNotEmpty(String first, String second) { return Func.isNotEmpty(first) ? first : second; } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java index adcc1ac..9fcc5b1 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java @@ -1447,7 +1447,25 @@ public class ReceivablePayableDetailServiceImpl fee.setBillingType(stringValue(rule, "billingType", "")); fee.setTransportQuantity(measure(rule, feeWaybill)); fee.setPriceUnit(stringValue(rule, "billingUnit", feeWaybill.getPriceUnit())); - fee.setUnitPrice(decimal(rule.get("unitPrice"))); + fee.setUnitPrice(resolveCalculatedUnitPrice(rule, feeWaybill)); + } + + /** + * 解析费用行展示用的实际命中单价。 + * 区间计费的规则默认单价仅用于兜底,费用行应展示当前计费量命中的区间单价。 + */ + private BigDecimal resolveCalculatedUnitPrice(Map rule, Waybill waybill) { + BigDecimal defaultUnitPrice = decimal(rule.get("unitPrice")); + String billingType = stringValue(rule, "billingType", ""); + if (!"区间单价".equals(billingType) && !"区间阶梯一口价".equals(billingType)) { + return defaultUnitPrice; + } + Optional> matchedRange = range(ranges(rule), measure(rule, waybill)); + if (matchedRange.isEmpty()) { + return defaultUnitPrice; + } + BigDecimal rangeUnitPrice = decimal(matchedRange.get().get("unitPrice")); + return rangeUnitPrice.signum() == 0 ? defaultUnitPrice : rangeUnitPrice; } private List cargoFeeKey(Waybill waybill, Map feeGoods) { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java index 4908981..f43bfae 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java @@ -255,8 +255,8 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpl