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
deleted file mode 100644
index 2fd0a090..00000000
--- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementInvoicePoolQueryDTO.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * 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/dto/KingdeeInvoicePoolQueryDTO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/KingdeeInvoicePoolQueryDTO.java
new file mode 100644
index 00000000..c0a01139
--- /dev/null
+++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/KingdeeInvoicePoolQueryDTO.java
@@ -0,0 +1,117 @@
+/**
+ * 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 io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 金蝶票据池镜像统一查询条件(收票登记选票与正式结算单认领共用)
+ *
+ * @author Chill
+ */
+@Data
+@Schema(description = "金蝶票据池镜像统一查询条件")
+public class KingdeeInvoicePoolQueryDTO implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 当前页
+ */
+ @Schema(description = "当前页")
+ private Long current = 1L;
+
+ /**
+ * 每页条数
+ */
+ @Schema(description = "每页条数")
+ private Long size = 10L;
+
+ /**
+ * 发票号码,模糊
+ */
+ @Schema(description = "发票号码(模糊)")
+ private String invoiceNo;
+
+ /**
+ * 开票日期起 yyyy-MM-dd
+ */
+ @Schema(description = "开票日期起 yyyy-MM-dd")
+ private String invoiceDateStart;
+
+ /**
+ * 开票日期止 yyyy-MM-dd
+ */
+ @Schema(description = "开票日期止 yyyy-MM-dd")
+ private String invoiceDateEnd;
+
+ /**
+ * 开票单位(销方名称),模糊
+ */
+ @Schema(description = "开票单位(销方名称,模糊)")
+ private String salerName;
+
+ /**
+ * 受票单位(购方名称),模糊
+ */
+ @Schema(description = "受票单位(购方名称,模糊)")
+ private String buyerName;
+
+ /**
+ * 发票类型名称,模糊(镜像存中文名)
+ */
+ @Schema(description = "发票类型名称(模糊)")
+ private String invoiceType;
+
+ /**
+ * 销方税号,精确
+ */
+ @Schema(description = "销方税号")
+ private String salerTaxNo;
+
+ /**
+ * 购方税号,精确
+ */
+ @Schema(description = "购方税号")
+ private String buyerTaxNo;
+
+ /**
+ * 认领过滤:true 仅已认领,false 仅未认领,null 不过滤(已认领=存在正式结算单发票行)
+ */
+ @Schema(description = "认领过滤:true已认领/false未认领/null不限")
+ private Boolean claimed;
+
+ /**
+ * 登记过滤:true 仅已登记,false 仅未登记,null 不过滤(已登记=存在非作废收票登记)
+ */
+ @Schema(description = "登记过滤:true已登记/false未登记/null不限")
+ private Boolean registered;
+}
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
deleted file mode 100644
index 2b1d3566..00000000
--- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/FormalSettlementInvoicePoolVO.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * 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-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/KingdeeInvoicePoolVO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/KingdeeInvoicePoolVO.java
new file mode 100644
index 00000000..1da543d6
--- /dev/null
+++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/KingdeeInvoicePoolVO.java
@@ -0,0 +1,153 @@
+/**
+ * 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 com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 金蝶票据池镜像统一视图(含本地认领/登记标记;认领口径:可匹配与默认认领金额=价税合计)
+ *
+ * @author Chill
+ */
+@Data
+@Schema(description = "金蝶票据池镜像统一视图")
+public class KingdeeInvoicePoolVO implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /** 镜像主键,收票登记保存绑定用(kingdeeInvoicePoolId) */
+ @Schema(description = "镜像主键")
+ @JsonSerialize(using = ToStringSerializer.class)
+ private Long id;
+
+ /** 发票号码 */
+ @Schema(description = "发票号码")
+ private String invoiceNo;
+
+ /** 金蝶发票流水号(票池唯一标识) */
+ @Schema(description = "金蝶发票流水号")
+ private String serialNo;
+
+ /** 开票日期 yyyy-MM-dd */
+ @Schema(description = "开票日期")
+ private String invoiceDate;
+
+ /** 发票类型名称(镜像落库时已由编码转名称) */
+ @Schema(description = "发票类型名称")
+ private String invoiceType;
+
+ /** 税率百分数,如 13 */
+ @Schema(description = "税率百分数")
+ private BigDecimal taxRate;
+
+ /** 价税合计 */
+ @Schema(description = "发票金额(价税合计)")
+ private BigDecimal invoiceAmount;
+
+ /** 税额 */
+ @Schema(description = "税额")
+ private BigDecimal taxAmount;
+
+ /** 受票单位(购方名称) */
+ @Schema(description = "受票单位")
+ private String receiverName;
+
+ /** 购方税号 */
+ @Schema(description = "购方税号")
+ private String buyerTaxNo;
+
+ /** 开票单位(销方名称) */
+ @Schema(description = "开票单位")
+ private String issuerName;
+
+ /** 销方税号 */
+ @Schema(description = "销方税号")
+ private String salerTaxNo;
+
+ /** 销方开户行名称 */
+ @Schema(description = "销方开户行名称")
+ private String bankName;
+
+ /** 销方银行账号 */
+ @Schema(description = "销方银行账号")
+ private String bankAccount;
+
+ /** 销方开户行及账号 */
+ @Schema(description = "开户行及账号")
+ private String issuingBank;
+
+ /** 销方电话 */
+ @Schema(description = "电话")
+ private String phone;
+
+ /** 客户邮箱 JSON 串 */
+ @Schema(description = "客户邮箱JSON")
+ private String customerEmails;
+
+ /** 部门邮箱 JSON 串 */
+ @Schema(description = "部门邮箱JSON")
+ private String departmentEmails;
+
+ /** 金蝶流水号(登记侧展示为金蝶单据号) */
+ @Schema(description = "金蝶单据号")
+ private String kingdeeBillNo;
+
+ /** 同步状态 unsynced/synced/failed */
+ @Schema(description = "金蝶同步状态")
+ private String kingdeeStatus;
+
+ /** 查验状态 */
+ @Schema(description = "查验状态")
+ private String checkStatus;
+
+ /** 附件 JSON(票易通下载 path) */
+ @Schema(description = "附件信息JSON")
+ private String attachmentsJson;
+
+ /** 可认领金额,口径同发票金额 */
+ @Schema(description = "可认领金额")
+ private BigDecimal availableInvoiceAmount;
+
+ /** 默认认领金额,口径同发票金额 */
+ @Schema(description = "默认认领金额")
+ private BigDecimal matchedAmount;
+
+ /** 是否已被正式结算单认领 */
+ @Schema(description = "是否已认领")
+ private Boolean claimed;
+
+ /** 是否已存在非作废收票登记 */
+ @Schema(description = "是否已登记")
+ private Boolean registered;
+}
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 856756f6..fffcffff 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,14 +27,15 @@ 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.KingdeeInvoicePoolQueryDTO;
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.KingdeeInvoicePoolVO;
import org.springblade.transport.pojo.vo.FormalSettlementVO;
import org.springblade.transport.excel.FormalSettlementExcel;
import org.springblade.transport.pojo.vo.PreSettlementVO;
import org.springblade.transport.service.IFormalSettlementService;
+import org.springblade.transport.service.IInvoiceReceiptService;
import org.springblade.transport.service.IPreSettlementService;
import org.springblade.transport.service.IReceiptFlowService;
import org.springframework.web.bind.annotation.GetMapping;
@@ -63,6 +64,7 @@ public class FormalSettlementController extends BladeController {
private final IFormalSettlementService formalSettlementService;
private final IPreSettlementService preSettlementService;
private final IReceiptFlowService receiptFlowService;
+ private final IInvoiceReceiptService invoiceReceiptService;
@GetMapping("/list")
@ApiOperationSupport(order = 1)
@@ -260,8 +262,15 @@ public class FormalSettlementController extends BladeController {
@GetMapping("/invoice-pool")
@ApiOperationSupport(order = 21)
- @Operation(summary = "查询发票云全票池发票(认领查询)")
- public R> invoicePool(FormalSettlementInvoicePoolQueryDTO query) {
- return R.data(formalSettlementService.invoicePoolQuery(query));
+ @Operation(summary = "金蝶票据池镜像分页查询(认领查询)")
+ public R> invoicePool(KingdeeInvoicePoolQueryDTO query) {
+ return R.data(invoiceReceiptService.invoicePoolPage(query));
+ }
+
+ @PostMapping("/invoice-pool/fetch")
+ @ApiOperationSupport(order = 22)
+ @Operation(summary = "按发票号码从金蝶票池补查单张发票")
+ public R fetchInvoicePool(@RequestParam String invoiceNo) {
+ return R.data(invoiceReceiptService.fetchKingdeeInvoiceByNo(invoiceNo));
}
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/InvoiceReceiptController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/InvoiceReceiptController.java
index 4819ecfc..413825df 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/InvoiceReceiptController.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/InvoiceReceiptController.java
@@ -37,8 +37,9 @@ import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.tool.api.R;
import org.springblade.transport.pojo.dto.InvoiceReceiptSaveRequest;
import org.springblade.transport.pojo.dto.InvoiceReceiptStatusRequest;
-import org.springblade.transport.pojo.entity.KingdeeInvoicePool;
+import org.springblade.transport.pojo.dto.KingdeeInvoicePoolQueryDTO;
import org.springblade.transport.pojo.vo.InvoiceReceiptVO;
+import org.springblade.transport.pojo.vo.KingdeeInvoicePoolVO;
import org.springblade.transport.service.IInvoiceReceiptService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@@ -80,9 +81,16 @@ public class InvoiceReceiptController extends BladeController {
@GetMapping("/invoice-pool")
@ApiOperationSupport(order = 3)
- @Operation(summary = "查询金蝶进项发票票据池")
- public R> invoicePool(@RequestParam(required = false) String keyword) {
- return R.data(invoiceReceiptService.invoicePool(keyword));
+ @Operation(summary = "金蝶票据池镜像分页查询(含认领/登记标记)")
+ public R> invoicePool(KingdeeInvoicePoolQueryDTO query) {
+ return R.data(invoiceReceiptService.invoicePoolPage(query));
+ }
+
+ @PostMapping("/invoice-pool/fetch")
+ @ApiOperationSupport(order = 14)
+ @Operation(summary = "按发票号码从金蝶票池补查单张发票")
+ public R fetchInvoicePool(@RequestParam String invoiceNo) {
+ return R.data(invoiceReceiptService.fetchKingdeeInvoiceByNo(invoiceNo));
}
@GetMapping("/settlement-candidates")
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/KingdeeInvoicePoolMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/KingdeeInvoicePoolMapper.java
index d299c635..241517d9 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/KingdeeInvoicePoolMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/KingdeeInvoicePoolMapper.java
@@ -26,8 +26,12 @@
package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springblade.transport.pojo.dto.KingdeeInvoicePoolQueryDTO;
import org.springblade.transport.pojo.entity.KingdeeInvoicePool;
+import org.springblade.transport.pojo.vo.KingdeeInvoicePoolVO;
/**
* 金蝶进项发票票据池 Mapper 接口
@@ -36,4 +40,25 @@ import org.springblade.transport.pojo.entity.KingdeeInvoicePool;
*/
@Mapper
public interface KingdeeInvoicePoolMapper extends BaseMapper {
+
+ /**
+ * 金蝶票据池镜像统一分页查询:认领/登记标记由 EXISTS 子查询直出
+ *
+ * @param page 分页参数
+ * @param query 统一查询条件(已在上层完成 trim 与日期格式校验)
+ * @param tenantId 当前租户
+ * @return 统一视图分页
+ */
+ IPage selectInvoicePoolPage(IPage page,
+ @Param("query") KingdeeInvoicePoolQueryDTO query, @Param("tenantId") String tenantId);
+
+ /**
+ * 按发票号码查询单张镜像统一视图(补查落库后回读)
+ *
+ * @param invoiceNo 发票号码
+ * @param tenantId 当前租户
+ * @return 统一视图,无镜像时 null
+ */
+ KingdeeInvoicePoolVO selectInvoicePoolVO(@Param("invoiceNo") String invoiceNo,
+ @Param("tenantId") String tenantId);
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/KingdeeInvoicePoolMapper.xml b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/KingdeeInvoicePoolMapper.xml
new file mode 100644
index 00000000..72314c70
--- /dev/null
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/KingdeeInvoicePoolMapper.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+ EXISTS (SELECT 1 FROM blade_formal_settlement_invoice c
+ WHERE c.is_deleted = 0 AND c.tenant_id = p.tenant_id AND c.invoice_no = p.invoice_no
+ AND EXISTS (SELECT 1 FROM blade_formal_settlement s
+ WHERE s.id = c.formal_settlement_id AND s.is_deleted = 0
+ AND s.approval_status != 'voided'))
+
+
+
+
+ EXISTS (SELECT 1 FROM blade_invoice_receipt r
+ WHERE r.is_deleted = 0 AND r.tenant_id = p.tenant_id
+ AND r.approval_status != 'voided' AND r.invoice_no = p.invoice_no)
+
+
+
+
+ p.id, p.invoice_no, p.serial_no,
+ DATE_FORMAT(p.invoice_date, '%Y-%m-%d') AS invoice_date,
+ p.invoice_type, p.tax_rate, p.invoice_amount, p.tax_amount,
+ p.receiver_name, p.buyer_tax_no, p.issuer_name, p.saler_tax_no,
+ p.bank_name, p.bank_account, p.issuing_bank, p.phone,
+ p.customer_emails, p.department_emails,
+ p.kingdee_bill_no, p.kingdee_status, p.check_status, p.attachments_json,
+ p.invoice_amount AS available_invoice_amount,
+ p.invoice_amount AS matched_amount,
+ AS claimed,
+ AS registered
+
+
+
+ SELECT
+
+ FROM blade_kingdee_invoice_pool p
+ WHERE p.is_deleted = 0 AND p.status = 1 AND p.tenant_id = #{tenantId}
+
+ AND p.invoice_no LIKE CONCAT('%', #{query.invoiceNo}, '%')
+
+
+ AND p.issuer_name LIKE CONCAT('%', #{query.salerName}, '%')
+
+
+ AND p.receiver_name LIKE CONCAT('%', #{query.buyerName}, '%')
+
+
+ AND p.invoice_type LIKE CONCAT('%', #{query.invoiceType}, '%')
+
+
+ AND p.saler_tax_no = #{query.salerTaxNo}
+
+
+ AND p.buyer_tax_no = #{query.buyerTaxNo}
+
+
+ AND p.invoice_date >= #{query.invoiceDateStart}
+
+
+ AND p.invoice_date <= #{query.invoiceDateEnd}
+
+
+ AND
+
+
+ AND NOT
+
+
+ AND
+
+
+ AND NOT
+
+ ORDER BY p.source_updated_time DESC, p.create_time DESC
+
+
+
+ SELECT
+
+ FROM blade_kingdee_invoice_pool p
+ WHERE p.is_deleted = 0 AND p.status = 1 AND p.tenant_id = #{tenantId} AND p.invoice_no = #{invoiceNo}
+ LIMIT 1
+
+
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 4f956c6a..f49babc3 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,7 +13,6 @@ 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;
@@ -23,7 +22,6 @@ 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;
/**
* 正式结算单服务
@@ -50,5 +48,4 @@ 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/IInvoiceReceiptService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IInvoiceReceiptService.java
index cf5a877d..bd959bd8 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IInvoiceReceiptService.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IInvoiceReceiptService.java
@@ -29,10 +29,12 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.transport.pojo.dto.InvoiceReceiptSaveRequest;
import org.springblade.transport.pojo.dto.InvoiceReceiptStatusRequest;
+import org.springblade.transport.pojo.dto.KingdeeInvoicePoolQueryDTO;
import org.springblade.transport.pojo.entity.InvoiceReceipt;
import org.springblade.transport.pojo.entity.InvoiceReceiptRecord;
import org.springblade.transport.pojo.entity.KingdeeInvoicePool;
import org.springblade.transport.pojo.vo.InvoiceReceiptVO;
+import org.springblade.transport.pojo.vo.KingdeeInvoicePoolVO;
import java.util.List;
import java.util.Map;
@@ -48,7 +50,22 @@ public interface IInvoiceReceiptService extends BaseService {
InvoiceReceiptVO detail(Long id);
- List invoicePool(String keyword);
+ /**
+ * 金蝶票据池镜像分页查询(含本地认领/登记标记),收票登记选票与正式结算单认领共用
+ *
+ * @param query 统一查询条件
+ * @return 镜像分页
+ */
+ IPage invoicePoolPage(KingdeeInvoicePoolQueryDTO query);
+
+ /**
+ * 按发票号码从金蝶票池精确补查单张发票:与定时同步同一套白名单校验,
+ * 通过后 upsert 入镜像并返回;不受增量时间窗口约束
+ *
+ * @param invoiceNo 发票号码
+ * @return 镜像统一视图
+ */
+ KingdeeInvoicePoolVO fetchKingdeeInvoiceByNo(String invoiceNo);
List> settlementCandidates(String keyword, Long receiptId);
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 f2e1537f..38769d54 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,7 +11,6 @@ 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;
@@ -19,14 +18,6 @@ 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.pojo.vo.BfiPageVO;
-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;
@@ -54,7 +45,6 @@ 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;
@@ -80,7 +70,6 @@ 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;
@@ -110,7 +99,6 @@ 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;
@@ -151,7 +139,6 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl selectPage(IPage page, FormalSettlementVO query) {
@@ -1449,109 +1436,4 @@ 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);
- // 上限 499:预留 1 条给 hasMore 探测,单次远程请求不超过 rim 契约 pageSize 上限 500
- long pageSize = Math.min(Math.max(query.getSize() == null ? 10 : query.getSize(), 1), 499);
- 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 rim 契约不支持全量且不返回总数:透传 pageNo/pageSize 单页查询,
- // 多取 1 条探测是否还有下一页,total 合成为当前已知的最小精确值供前端分页器翻页
- BfiInvoicePoolQueryDataDTO data = new BfiInvoicePoolQueryDataDTO();
- data.setPageNo((int) pageNo);
- data.setPageSize((int) pageSize + 1);
- 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.setQueryParam(data);
- BfiPageVO poolPage = bfiService.queryInvoicePool(param);
- List invoices = poolPage.getRows() == null ? List.of()
- : poolPage.getRows().stream()
- .map(this::toInvoicePoolVO)
- .toList();
- // 多取的 1 条仅用于 hasMore 判断,不返回给前端
- boolean hasMore = invoices.size() > pageSize;
- List records = hasMore ? invoices.subList(0, (int) pageSize) : invoices;
- long total = hasMore ? pageNo * pageSize + 1 : (pageNo - 1) * pageSize + records.size();
- log.info("正式结算单认领查询 全票池第 {} 页 {} 条/页,返回 {} 条,hasMore:{}", pageNo, pageSize, records.size(), hasMore);
- Page page = new Page<>(pageNo, pageSize);
- page.setRecords(records);
- page.setTotal(total);
- return page;
- }
-
- /**
- * A801-1 全票池发票 -> 正式结算单认领VO 字段映射
- */
- private FormalSettlementInvoicePoolVO toInvoicePoolVO(BfiInvoicePoolVO poolInvoice) {
- FormalSettlementInvoicePoolVO vo = new FormalSettlementInvoicePoolVO();
- // 发票号码
- vo.setInvoiceNo(poolInvoice.getInvoiceNo());
- // 发票流水号,票池发票唯一标识
- vo.setSerialNo(poolInvoice.getSerialNo());
- // 开票日期 yyyy-MM-dd
- vo.setInvoiceDate(poolInvoice.getInvoiceDate());
- // 发票类型编码转名称,未知编码原样返回
- vo.setInvoiceTypeName(BfiConstant.INVOICE_TYPE_NAMES.getOrDefault(poolInvoice.getInvoiceType(),
- poolInvoice.getInvoiceType()));
- // 税率:顶层优先、回退首条明细,小数转百分数(0.13 -> 13)
- 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());
- // 附件信息JSON:path 供 A801-2 进项发票下载,文件名以发票号码命名
- 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);
- }
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java
index 1d3838bd..77267f19 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java
@@ -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 com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -58,6 +59,7 @@ import org.springblade.transport.mapper.InvoiceReceiptSettlementMapper;
import org.springblade.transport.mapper.KingdeeInvoicePoolMapper;
import org.springblade.transport.pojo.dto.InvoiceReceiptSaveRequest;
import org.springblade.transport.pojo.dto.InvoiceReceiptStatusRequest;
+import org.springblade.transport.pojo.dto.KingdeeInvoicePoolQueryDTO;
import org.springblade.transport.pojo.entity.CustomerArchive;
import org.springblade.transport.pojo.entity.CustomerContact;
import org.springblade.transport.pojo.entity.FormalSettlement;
@@ -66,6 +68,7 @@ import org.springblade.transport.pojo.entity.InvoiceReceiptRecord;
import org.springblade.transport.pojo.entity.InvoiceReceiptSettlement;
import org.springblade.transport.pojo.entity.KingdeeInvoicePool;
import org.springblade.transport.pojo.vo.InvoiceReceiptVO;
+import org.springblade.transport.pojo.vo.KingdeeInvoicePoolVO;
import org.springblade.transport.service.IInvoiceReceiptService;
import org.springblade.transport.wrapper.InvoiceReceiptWrapper;
import org.springframework.beans.factory.ObjectProvider;
@@ -78,6 +81,7 @@ import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
@@ -135,6 +139,9 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl invoicePool(String keyword) {
- return invoicePoolMapper.selectList(Wrappers.lambdaQuery()
- .eq(KingdeeInvoicePool::getStatus, 1)
- .and(Func.isNotEmpty(keyword), wrapper -> wrapper.like(KingdeeInvoicePool::getInvoiceNo, keyword)
- .or().like(KingdeeInvoicePool::getIssuerName, keyword)
- .or().like(KingdeeInvoicePool::getReceiverName, keyword))
- .orderByDesc(KingdeeInvoicePool::getSourceUpdatedTime)
- .orderByDesc(KingdeeInvoicePool::getCreateTime)
- .last("limit 200"));
+ public IPage invoicePoolPage(KingdeeInvoicePoolQueryDTO query) {
+ long current = query.getCurrent() == null ? 1L : Math.max(query.getCurrent(), 1L);
+ long size = query.getSize() == null ? 10L : Math.min(Math.max(query.getSize(), 1L), 100L);
+ query.setCurrent(current);
+ query.setSize(size);
+ query.setInvoiceNo(trimOrNull(query.getInvoiceNo()));
+ query.setSalerName(trimOrNull(query.getSalerName()));
+ query.setBuyerName(trimOrNull(query.getBuyerName()));
+ query.setInvoiceType(trimOrNull(query.getInvoiceType()));
+ query.setSalerTaxNo(trimOrNull(query.getSalerTaxNo()));
+ query.setBuyerTaxNo(trimOrNull(query.getBuyerTaxNo()));
+ query.setInvoiceDateStart(normalizeQueryDate(query.getInvoiceDateStart()));
+ query.setInvoiceDateEnd(normalizeQueryDate(query.getInvoiceDateEnd()));
+ Page page = new Page<>(current, size);
+ return invoicePoolMapper.selectInvoicePoolPage(page, query, AuthUtil.getTenantId());
+ }
+
+ /** 空白串归一为 null,便于 XML 的 != '' 判空条件 */
+ private String trimOrNull(String text) {
+ return StringUtil.isBlank(text) ? null : text.trim();
+ }
+
+ /** 查询日期清洗:空转 null,格式非法直接报业务异常(自定义 SQL 无类型保护,先校验再进 XML) */
+ private String normalizeQueryDate(String text) {
+ if (StringUtil.isBlank(text)) {
+ return null;
+ }
+ try {
+ return LocalDate.parse(text.trim()).toString();
+ } catch (DateTimeParseException exception) {
+ throw new ServiceException("开票日期格式应为 yyyy-MM-dd");
+ }
+ }
+
+ @Override
+ public KingdeeInvoicePoolVO fetchKingdeeInvoiceByNo(String invoiceNo) {
+ if (StringUtil.isBlank(invoiceNo)) {
+ throw new ServiceException("请填写发票号码");
+ }
+ String trimmedInvoiceNo = invoiceNo.trim();
+ // 镜像优先回读:白名单只约束「入镜像」,回读镜像不受限;镜像已有票不再打远程,不受金蝶可用性影响
+ KingdeeInvoicePoolVO existingVo = invoicePoolMapper.selectInvoicePoolVO(trimmedInvoiceNo, AuthUtil.getTenantId());
+ if (existingVo != null) {
+ return existingVo;
+ }
+ // A801-1 无时间窗口约束,票池更新时间滑出增量窗口的老票也能精确命中;复用窄查后仍保留票号全等匹配的防御过滤
+ List poolRows = queryPoolByInvoiceNo(trimmedInvoiceNo);
+ BfiInvoicePoolVO poolRow = poolRows.stream()
+ .filter(row -> StringUtil.isNotBlank(row.getInvoiceNo())
+ && trimmedInvoiceNo.equals(row.getInvoiceNo().trim()))
+ .findFirst()
+ .orElse(null);
+ if (poolRow == null) {
+ throw new ServiceException("金蝶票池未查询到发票 " + trimmedInvoiceNo);
+ }
+ if (filterByInvoiceTypes(List.of(poolRow)).isEmpty()) {
+ throw new ServiceException("发票 " + trimmedInvoiceNo + " 的票种不在同步白名单内,不能补查");
+ }
+ if (filterByArchiveTaxNos(customerTaxNoSet(), List.of(poolRow)).isEmpty()) {
+ throw new ServiceException("发票 " + trimmedInvoiceNo
+ + " 购销双方存在未建档税号,请先在客商档案维护统一社会信用代码后再补查");
+ }
+ // upsert 自带票面指纹比对,无变化不重写,重复点击安全;随后从镜像回读统一视图(含认领/登记标记)
+ batchUpsertInvoicePool(List.of(poolRow));
+ KingdeeInvoicePoolVO vo = invoicePoolMapper.selectInvoicePoolVO(trimmedInvoiceNo, AuthUtil.getTenantId());
+ if (vo == null) {
+ throw new ServiceException("补查失败:镜像回读不到发票 " + trimmedInvoiceNo);
+ }
+ return vo;
}
@Override
@@ -752,6 +819,8 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl page = bfiService.queryInvoicePool(param);
@@ -767,6 +836,8 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl page = bfiService.queryInvoicePool(param);