chore: 补充收票单推送金蝶方法注释与批量推送关键环节日志

This commit is contained in:
刘泉佳
2026-09-23 11:08:50 +08:00
parent c60954ad86
commit 7b7a40b94d
@@ -491,6 +491,16 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
// ==================== 图05 环节②③:A303-2 收票单批量保存 + A302-6 收票指定应付 ====================
/**
* 批量推送收票登记至金蝶(图05 环节②③:A303-2 收票单保存 + A302-6 指定应付)
* <p>
* 编排流程:参数去重校验 → 批量组装推送计划(分摊/镜像/结算单/结算明细一次取回防 N+1)→
* A102-4 应付单已生成预检 → A801-3 幂等预检(金蝶已有收票单则跳过保存续推指定)→
* 逐单推送(单笔失败不中断整批)→ 汇总成功/失败笔数返回
*
* @param ids 收票登记主键集合
* @return 推送结果汇总(本批笔数、成功/失败笔数及失败原因明细)
*/
@Override
public String pushKingdeeReceivedInvoice(List<Long> ids) {
if (Func.isEmpty(ids)) {
@@ -500,26 +510,31 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
if (distinctIds.isEmpty()) {
throw new ServiceException("请选择需要推送金蝶的收票登记");
}
log.info("推送金蝶收票单开始:入参 {} 笔,去重后 {} 笔,收票登记id={}", ids.size(), distinctIds.size(), distinctIds);
List<InvoiceReceipt> receipts = listByIds(distinctIds);
if (receipts.size() != distinctIds.size()) {
throw new ServiceException("部分收票登记不存在或已删除");
}
// 批量组装推送计划:分摊关系/镜像/结算单/结算明细一次取回,避免逐单查库 N+1
// 1) 收票登记与正式结算单的分摊关系(按登记id分组),用于"一票一应付"校验及防重键取数来源
Map<Long, List<InvoiceReceiptSettlement>> relationsByReceipt = settlementRelationMapper.selectList(
Wrappers.<InvoiceReceiptSettlement>lambdaQuery()
.in(InvoiceReceiptSettlement::getInvoiceReceiptId, distinctIds)
.orderByAsc(InvoiceReceiptSettlement::getCreateTime)).stream()
.collect(Collectors.groupingBy(InvoiceReceiptSettlement::getInvoiceReceiptId));
// 2) 票池镜像(A801-1 同步落库的发票数据),提供明细行 itemsJson、票种编码、购方单位等推送必填字段
List<Long> mirrorIds = receipts.stream().map(InvoiceReceipt::getKingdeeInvoicePoolId)
.filter(Objects::nonNull).distinct().toList();
Map<Long, KingdeeInvoicePool> mirrorById = mirrorIds.isEmpty() ? Map.of()
: invoicePoolMapper.selectBatchIds(mirrorIds).stream()
.collect(Collectors.toMap(KingdeeInvoicePool::getId, Function.identity(), (first, second) -> first));
// 3) 分摊关系指向的正式结算单,后续校验须为审批通过的应付类型结算单
List<Long> settlementIds = relationsByReceipt.values().stream().flatMap(List::stream)
.map(InvoiceReceiptSettlement::getFormalSettlementId).filter(Objects::nonNull).distinct().toList();
Map<Long, FormalSettlement> settlementById = settlementIds.isEmpty() ? Map.of()
: formalSettlementMapper.selectBatchIds(settlementIds).stream()
.collect(Collectors.toMap(FormalSettlement::getId, Function.identity(), (first, second) -> first));
// 4) 应付结算单的明细行(按行号升序),用于组装 A302-6 指定应付的防重键 apBillSrcCode
List<Long> payableSettlementIds = settlementById.values().stream()
.filter(settlement -> "payable".equals(settlement.getSettlementType()))
.map(FormalSettlement::getId).toList();
@@ -529,19 +544,27 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
.eq(FormalSettlementDetail::getIsDeleted, 0)
.orderByAsc(FormalSettlementDetail::getLineNo)).stream()
.collect(Collectors.groupingBy(FormalSettlementDetail::getFormalSettlementId));
log.info("推送金蝶收票单批量取数完成:分摊关系 {} 条,票池镜像 {} 个,结算单 {} 张(应付 {} 张),结算明细 {} 行",
relationsByReceipt.size(), mirrorById.size(), settlementById.size(), payableSettlementIds.size(),
detailsBySettlement.values().stream().mapToInt(List::size).sum());
// 5) 逐单组装推送计划:状态机/绑定/查验/一票一应付/防重键校验,不满足项写入 blockedReason 不抛异常(逐单报因)
Map<Long, ReceivedInvoicePushPlan> planByReceipt = new LinkedHashMap<>();
for (InvoiceReceipt receipt : receipts) {
planByReceipt.put(receipt.getId(), buildReceivedInvoicePushPlan(receipt,
relationsByReceipt.getOrDefault(receipt.getId(), List.of()), mirrorById, settlementById, detailsBySettlement));
}
long blockedCount = planByReceipt.values().stream().filter(plan -> plan.blockedReason() != null).count();
log.info("推送金蝶收票单计划组装完成:本批 {} 笔,前置校验拦截 {} 笔", planByReceipt.size(), blockedCount);
// A102-4 应付单已生成预检:本批防重键一次批量查询,缺单的登记逐单提示先完成付款侧同步
List<String> apSrcCodes = planByReceipt.values().stream()
.filter(plan -> plan.blockedReason() == null)
.map(ReceivedInvoicePushPlan::apBillSrcCode).filter(Func::isNotBlank).distinct().toList();
Map<String, String> apBillNoBySrcCode = apSrcCodes.isEmpty() ? Map.of()
: kingdeeApBillSyncSupport.queryApBillExistNos(apSrcCodes);
log.info("推送金蝶收票单 A102-4 预检:待校验防重键 {} 个,已生成财务应付单 {} 个", apSrcCodes.size(), apBillNoBySrcCode.size());
// A801-3 幂等预检:按购方单位(接口必填)分组回看窗口翻页,本地按防重键匹配(金蝶已存在则跳过保存续推指定)
Map<String, BfiReceivedInvoiceVO> kingdeeRowByInvoiceNo = queryKingdeeReceivedInvoiceRows(planByReceipt);
log.info("推送金蝶收票单 A801-3 预检:金蝶已存在收票单 {} 笔,命中单据将跳过保存续推指定", kingdeeRowByInvoiceNo.size());
KingdeeSyncContext context = KingdeeSyncContext.empty();
int success = 0;
List<String> failures = new ArrayList<>();
@@ -559,6 +582,7 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
if (!failures.isEmpty()) {
summary = summary + ",失败 " + failures.size() + " 笔:" + String.join(";", failures);
}
log.info("{}", summary);
return summary;
}