From 9a35d408dc134247753839547b59033e92a5d78e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com>
Date: Sun, 20 Sep 2026 19:41:19 +0800
Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E6=AD=A3=E5=BC=8F=E7=BB=93?=
=?UTF-8?q?=E7=AE=97=E5=8D=95=E6=96=B0=E5=A2=9E=E5=85=A8=E7=A5=A8=E6=B1=A0?=
=?UTF-8?q?=E5=8F=91=E7=A5=A8=E8=AE=A4=E9=A2=86=E6=9F=A5=E8=AF=A2=E7=AB=AF?=
=?UTF-8?q?=E7=82=B9=EF=BC=88=E5=A4=9A=E6=9D=A1=E4=BB=B6+=E5=86=85?=
=?UTF-8?q?=E5=AD=98=E7=B2=BE=E7=A1=AE=E5=88=86=E9=A1=B5=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../FormalSettlementInvoicePoolQueryDTO.java | 74 ++++++++++++
.../vo/FormalSettlementInvoicePoolVO.java | 87 +++++++++++++++
.../FormalSettlementController.java | 9 ++
.../service/IFormalSettlementService.java | 3 +
.../impl/FormalSettlementServiceImpl.java | 105 ++++++++++++++++++
5 files changed, 278 insertions(+)
create mode 100644 blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementInvoicePoolQueryDTO.java
create mode 100644 blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/FormalSettlementInvoicePoolVO.java
diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementInvoicePoolQueryDTO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementInvoicePoolQueryDTO.java
new file mode 100644
index 00000000..2fd0a090
--- /dev/null
+++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementInvoicePoolQueryDTO.java
@@ -0,0 +1,74 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ *
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ *
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ *
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ *
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ *
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ *
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.transport.pojo.dto;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 正式结算单认领查询 全票池发票查询条件
+ *
+ * @author Chill
+ */
+@Data
+public class FormalSettlementInvoicePoolQueryDTO implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+ /**
+ * 页码,默认 1
+ */
+ private Long current = 1L;
+ /**
+ * 每页条数,默认 10,最大 500
+ */
+ private Long size = 10L;
+ /**
+ * 发票号码
+ */
+ private String invoiceNo;
+ /**
+ * 开票日期起 yyyy-MM-dd
+ */
+ private String invoiceDateStart;
+ /**
+ * 开票日期止 yyyy-MM-dd
+ */
+ private String invoiceDateEnd;
+ /**
+ * 销方税号
+ */
+ private String salerTaxNo;
+ /**
+ * 购方税号
+ */
+ private String buyerTaxNo;
+ /**
+ * 单据使用状态,多个用英文逗号分隔[1未用,30在用,60已用,65已入账]
+ */
+ private String expenseStatus;
+}
diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/FormalSettlementInvoicePoolVO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/FormalSettlementInvoicePoolVO.java
new file mode 100644
index 00000000..2b1d3566
--- /dev/null
+++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/FormalSettlementInvoicePoolVO.java
@@ -0,0 +1,87 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ *
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ *
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ *
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ *
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ *
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ *
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.transport.pojo.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 正式结算单认领查询 全票池发票VO
+ *
+ * @author Chill
+ */
+@Data
+public class FormalSettlementInvoicePoolVO implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+ /**
+ * 发票号码
+ */
+ private String invoiceNo;
+ /**
+ * 发票流水号
+ */
+ private String serialNo;
+ /**
+ * 开票日期
+ */
+ private String invoiceDate;
+ /**
+ * 发票类型名称
+ */
+ private String invoiceTypeName;
+ /**
+ * 税率(百分数,如 13);票池明细缺失时为 null
+ */
+ private BigDecimal taxRate;
+ /**
+ * 发票金额(含税,取票池价税合计)
+ */
+ private BigDecimal invoiceAmount;
+ /**
+ * 可匹配发票金额(含税,本次口径等于价税合计)
+ */
+ private BigDecimal availableInvoiceAmount;
+ /**
+ * 认领金额(默认等于可匹配金额,由前端按结算余额分配)
+ */
+ private BigDecimal matchedAmount;
+ /**
+ * 开票单位(销方名称)
+ */
+ private String salerName;
+ /**
+ * 受票单位(购方名称)
+ */
+ private String buyerName;
+ /**
+ * 附件信息JSON,结构 {"source":"piaozone","path":"A801-2下载path","name":"文件名"}
+ */
+ private String attachmentJson;
+}
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 49535ce5..9a927fed 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
@@ -27,8 +27,10 @@ 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.FormalSettlementInvoicePoolQueryDTO;
import org.springblade.transport.pojo.dto.PreSettlementDetailAdjustRequest;
import org.springblade.transport.pojo.entity.FormalSettlementDetailFee;
+import org.springblade.transport.pojo.vo.FormalSettlementInvoicePoolVO;
import org.springblade.transport.pojo.vo.FormalSettlementVO;
import org.springblade.transport.excel.FormalSettlementExcel;
import org.springblade.transport.pojo.vo.PreSettlementVO;
@@ -250,4 +252,11 @@ public class FormalSettlementController extends BladeController {
public R>> receiptClaims(@RequestParam Long formalSettlementId) {
return R.data(receiptFlowService.settlementClaims(formalSettlementId));
}
+
+ @GetMapping("/invoice-pool")
+ @ApiOperationSupport(order = 21)
+ @Operation(summary = "查询发票云全票池发票(认领查询)")
+ public R> invoicePool(FormalSettlementInvoicePoolQueryDTO query) {
+ return R.data(formalSettlementService.invoicePoolQuery(query));
+ }
}
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 cd8557b7..8f77c3a4 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
@@ -13,6 +13,7 @@ import org.springblade.core.mp.base.BaseService;
import org.springblade.transport.pojo.dto.FormalSettlementSaveRequest;
import org.springblade.transport.pojo.dto.FormalSettlementStatusRequest;
import org.springblade.transport.pojo.entity.FormalSettlement;
+import org.springblade.transport.pojo.vo.FormalSettlementInvoicePoolVO;
import org.springblade.transport.pojo.vo.FormalSettlementVO;
import org.springblade.transport.pojo.vo.PreSettlementVO;
import org.springblade.transport.pojo.entity.PreSettlement;
@@ -22,6 +23,7 @@ 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;
+import org.springblade.transport.pojo.dto.FormalSettlementInvoicePoolQueryDTO;
/**
* 正式结算单服务
@@ -47,4 +49,5 @@ public interface IFormalSettlementService extends BaseService
String applyPayment(FormalSettlementPaymentRequest request);
List applyPayments(FormalSettlementBatchPaymentRequest request);
void claimInvoices(FormalSettlementInvoiceClaimRequest request);
+ IPage invoicePoolQuery(FormalSettlementInvoicePoolQueryDTO query);
}
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 9a6cdc4c..e5202aad 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
@@ -11,12 +11,21 @@ package org.springblade.transport.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.thirdparty.bfi.constant.BfiConstant;
+import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoicePoolQueryDTO;
+import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoicePoolQueryDataDTO;
+import org.springblade.thirdparty.bfi.pojo.vo.BfiInvoicePoolItemVO;
+import org.springblade.thirdparty.bfi.pojo.vo.BfiInvoicePoolVO;
+import org.springblade.thirdparty.bfi.service.IBfiService;
import org.springblade.transport.mapper.FormalSettlementDetailMapper;
import org.springblade.transport.mapper.FormalSettlementDetailFeeMapper;
import org.springblade.transport.mapper.FormalSettlementChangeRecordMapper;
@@ -44,6 +53,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.FormalSettlementInvoiceClaimRequest;
+import org.springblade.transport.pojo.dto.FormalSettlementInvoicePoolQueryDTO;
import org.springblade.transport.pojo.dto.FormalSettlementStatusRequest;
import org.springblade.transport.pojo.dto.PreSettlementDetailAdjustRequest;
import org.springblade.transport.pojo.entity.FormalSettlement;
@@ -69,6 +79,7 @@ import org.springblade.transport.pojo.entity.ReceivablePayableDetail;
import org.springblade.transport.pojo.entity.ReceivablePayableCargoFee;
import org.springblade.transport.pojo.entity.SettlementAdjustment;
import org.springblade.transport.pojo.entity.Waybill;
+import org.springblade.transport.pojo.vo.FormalSettlementInvoicePoolVO;
import org.springblade.transport.pojo.vo.FormalSettlementVO;
import org.springblade.transport.pojo.vo.PreSettlementVO;
import org.springblade.transport.pojo.vo.SettlementAdjustmentVO;
@@ -97,6 +108,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -108,6 +120,7 @@ import java.util.stream.Collectors;
*/
@Service
@RequiredArgsConstructor
+@Slf4j
public class FormalSettlementServiceImpl extends BaseServiceImpl
implements IFormalSettlementService {
@@ -140,6 +153,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl selectPage(IPage page, FormalSettlementVO query) {
@@ -1369,4 +1383,95 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl max) throw new ServiceException("内容不能超过" + max + "个字"); return value; }
+
+ @Override
+ public IPage invoicePoolQuery(FormalSettlementInvoicePoolQueryDTO query) {
+ long pageNo = Math.max(query.getCurrent() == null ? 1 : query.getCurrent(), 1);
+ long pageSize = Math.min(Math.max(query.getSize() == null ? 10 : query.getSize(), 1), 500);
+ String invoiceNo = query.getInvoiceNo();
+ String invoiceDateStart = query.getInvoiceDateStart();
+ String invoiceDateEnd = query.getInvoiceDateEnd();
+ String salerTaxNo = query.getSalerTaxNo();
+ String buyerTaxNo = query.getBuyerTaxNo();
+ String expenseStatus = query.getExpenseStatus();
+ // A801-1 不返回总数:单次按最大页大小全量翻页拉取后,在内存中做精确分页
+ BfiInvoicePoolQueryDataDTO data = new BfiInvoicePoolQueryDataDTO();
+ data.setPageSize((int) pageSize);
+ if (StringUtil.isNotBlank(invoiceNo)) {
+ data.setInvoiceNo(invoiceNo.trim());
+ }
+ if (StringUtil.isNotBlank(invoiceDateStart)) {
+ data.setInvoiceDateStart(invoiceDateStart.trim());
+ }
+ if (StringUtil.isNotBlank(invoiceDateEnd)) {
+ data.setInvoiceDateEnd(invoiceDateEnd.trim());
+ }
+ if (StringUtil.isNotBlank(salerTaxNo)) {
+ data.setSalerTaxNo(salerTaxNo.trim());
+ }
+ if (StringUtil.isNotBlank(buyerTaxNo)) {
+ data.setBuyerTaxNo(buyerTaxNo.trim());
+ }
+ if (StringUtil.isNotBlank(expenseStatus)) {
+ data.setExpenseStatus(expenseStatus.trim());
+ }
+ BfiInvoicePoolQueryDTO param = new BfiInvoicePoolQueryDTO();
+ param.setData(data);
+ List poolInvoices = bfiService.queryInvoicePool(param);
+ List invoices = poolInvoices.stream()
+ .filter(poolInvoice -> !"1".equals(poolInvoice.getDelete()))
+ .map(this::toInvoicePoolVO)
+ .toList();
+ log.info("正式结算单认领查询 全票池原始 {} 条,过滤作废后 {} 条,返回第 {} 页 {} 条/页",
+ poolInvoices.size(), invoices.size(), pageNo, pageSize);
+ // 内存精确分页:total 为过滤后精确总数,请求页超出范围时返回空records
+ int from = (int) ((pageNo - 1) * pageSize);
+ int to = (int) Math.min(from + pageSize, invoices.size());
+ List records = from >= invoices.size() ? List.of() : invoices.subList(from, to);
+ Page page = new Page<>(pageNo, pageSize);
+ page.setRecords(records);
+ page.setTotal(invoices.size());
+ return page;
+ }
+
+ private FormalSettlementInvoicePoolVO toInvoicePoolVO(BfiInvoicePoolVO poolInvoice) {
+ FormalSettlementInvoicePoolVO vo = new FormalSettlementInvoicePoolVO();
+ vo.setInvoiceNo(poolInvoice.getInvoiceNo());
+ vo.setSerialNo(poolInvoice.getSerialNo());
+ vo.setInvoiceDate(poolInvoice.getInvoiceDate());
+ vo.setInvoiceTypeName(BfiConstant.INVOICE_TYPE_NAMES.getOrDefault(poolInvoice.getInvoiceType(),
+ poolInvoice.getInvoiceType()));
+ vo.setTaxRate(resolveTaxRate(poolInvoice));
+ BigDecimal totalAmount = parseAmount(poolInvoice.getTotalAmount());
+ vo.setInvoiceAmount(totalAmount);
+ vo.setAvailableInvoiceAmount(totalAmount);
+ vo.setMatchedAmount(totalAmount);
+ vo.setSalerName(poolInvoice.getSalerName());
+ vo.setBuyerName(poolInvoice.getBuyerName());
+ Map attachment = new LinkedHashMap<>();
+ attachment.put("source", "piaozone");
+ attachment.put("path", poolInvoice.getDownloadUrl());
+ attachment.put("name", poolInvoice.getInvoiceNo() + ".pdf");
+ vo.setAttachmentJson(JsonUtil.toJson(attachment));
+ return vo;
+ }
+
+ /**
+ * 税率优先取顶层税率的小数值换算为百分数,如 0.13 -> 13;顶层为空时回退取首条明细税率,均无时返回 null
+ */
+ private BigDecimal resolveTaxRate(BfiInvoicePoolVO poolInvoice) {
+ if (StringUtil.isNotBlank(poolInvoice.getTaxRate())) {
+ return new BigDecimal(poolInvoice.getTaxRate()).multiply(BigDecimal.valueOf(100));
+ }
+ return Optional.ofNullable(poolInvoice.getItems()).orElse(List.of()).stream()
+ .map(BfiInvoicePoolItemVO::getTaxRate)
+ .filter(StringUtil::isNotBlank)
+ .findFirst()
+ .map(taxRate -> new BigDecimal(taxRate).multiply(BigDecimal.valueOf(100)))
+ .orElse(null);
+ }
+
+ private BigDecimal parseAmount(String value) {
+ return StringUtil.isBlank(value) ? BigDecimal.ZERO : new BigDecimal(value);
+ }
}