diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceiptFlowServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceiptFlowServiceImpl.java index 5f083d25..de09e49f 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceiptFlowServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceiptFlowServiceImpl.java @@ -801,15 +801,6 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl settlementIds = allocations.stream() - .map(ReceiptClaimSettlement::getFormalSettlementId) - .filter(Objects::nonNull) - .distinct() - .toList(); - Map settlements = settlementIds.isEmpty() ? Map.of() - : formalSettlementMapper.selectList(Wrappers.lambdaQuery() - .in(FormalSettlement::getId, settlementIds)).stream() - .collect(Collectors.toMap(FormalSettlement::getId, Function.identity(), (first, second) -> first)); // 推送来源编码:分摊结算单号下划线拼接(A301-3 契约口径;分摊不变则重试编码不变, // 金蝶按 awrp_src_sys + awrp_src_code 幂等防重试双单) String awrpSrcCode = allocations.stream() @@ -819,7 +810,7 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl allocations, - Map settlements) { + private BfiClaimPushDTO buildClaimPushDTO(KingdeeReceiptFlow flow, BigDecimal claimedTotal, + List allocations) { BfiClaimPushDTO param = new BfiClaimPushDTO(); // 【必填】认领公告id param.setBillid(flow.getBillId()); @@ -850,25 +841,17 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl entries = new ArrayList<>(); - for (ReceiptClaimSettlement allocation : allocations) { - BfiClaimPushEntryDTO entry = new BfiClaimPushEntryDTO(); - // 【必填】应收金额(分摊金额) - entry.setEReceivableamt(money(allocation.getAllocatedReceiptAmount())); - // 分录行序号(结算单id) - entry.setSeq(allocation.getFormalSettlementId()); - FormalSettlement settlement = settlements.get(allocation.getFormalSettlementId()); - if (settlement != null && Func.isNotEmpty(settlement.getKingdeeBillNo())) { - // 结算单已同步金蝶应收单时携带核心单据引用,金蝶按结算单id核销认领金额 - // 核心单据类型 - // entry.setECorebilltype(KingdeeBfiConstant.BFI_CLAIM_CORE_BILL_TYPE); - // 核心单据编号(结算单id) - entry.setECorebillno(String.valueOf(settlement.getId())); - } - entries.add(entry); - } - // 【必填】单据体分录 - param.setEntryentity(entries); + // 【必填】单据体分录:仅一条,应收金额=全部未推送金额(累计有效认领) + BfiClaimPushEntryDTO entry = new BfiClaimPushEntryDTO(); + // 【必填】应收金额(全部未推送金额) + entry.setEReceivableamt(claimedTotal); + // 分录行序号(第一张结算单id,分摊已按结算单id升序,多张取最小) + entry.setSeq(allocations.get(0).getFormalSettlementId()); + // 核心单据类型 + // entry.setECorebilltype(KingdeeBfiConstant.BFI_CLAIM_CORE_BILL_TYPE); + // 核心单据编号(第一张结算单id) + entry.setECorebillno(String.valueOf(allocations.get(0).getFormalSettlementId())); + param.setEntryentity(List.of(entry)); return param; } diff --git a/doc/docs/业务流程/2026-09-28-收款认领推送金蝶重构设计(认领本地化-A301-3定时+手动推送-按流水归集).md b/doc/docs/业务流程/2026-09-28-收款认领推送金蝶重构设计(认领本地化-A301-3定时+手动推送-按流水归集).md index f4cf69b7..df839661 100644 --- a/doc/docs/业务流程/2026-09-28-收款认领推送金蝶重构设计(认领本地化-A301-3定时+手动推送-按流水归集).md +++ b/doc/docs/业务流程/2026-09-28-收款认领推送金蝶重构设计(认领本地化-A301-3定时+手动推送-按流水归集).md @@ -29,7 +29,7 @@ 新增两条核心规则(本次重构的业务闸门): - **认领完成 = 累计有效认领金额 == 公告未认领金额**(`unclaimed_amount`,即 A301-2 的 `unclaimamount`;作废分摊不计入累计)。只有认领完成的流水才满足推送条件——**不认领完就不推**。 -- **推送单元 = 收款流水**:一条流水只产生一张金蝶收款单,分录取该流水下全部有效分摊行(可能跨多次认领主单);`awrp_src_code` 按分摊结算单号下划线拼接(A301-3 契约口径),一条流水只推送一次,编码不会撞码。 +- **推送单元 = 收款流水**:一条流水只产生一张金蝶收款单,**单条分录、金额 = 全部未推送金额**(累计有效认领,闸门保证等于公告未认领金额);`awrp_src_code` 按分摊结算单号下划线拼接(A301-3 契约口径),一条流水只推送一次,编码不会撞码。 ## 3. 领域模型与职责划分 @@ -117,9 +117,9 @@ claimed 累计有效认领 == unclaimed_amount(且 > 0) ← 「认领 - 重验:累计有效认领 == 最新 unclaimed_amount,不等 → 失败并提示两侧金额差额 (不等说明金蝶侧有人认领过或金额有变,需人工核对后作废/补认领) ④ awrp_src_code:按分摊结算单号下划线拼接生成并落库(分摊不变则重试编码不变) -⑤ 组装 A301-3:billid=流水.bill_id,entries = 该流水全部有效分摊行 - (分摊行 join 结算单,按结算单 id 升序;金额=allocated_receipt_amount; - seq=结算单id;结算单有 kingdee_bill_no 时携带 e_corebillno=结算单id,沿用契约取数) +⑤ 组装 A301-3:billid=流水.bill_id,**单条分录**: + e_receivableamt = 全部未推送金额(累计有效认领); + seq / e_corebillno = 第一张结算单id(分摊按结算单id升序,多张取最小) ⑥ 调 pushClaimResult: 成功 → push_status=pushed、push_fail_reason 清空、pushed_time=now、 kingdee_bill_no=响应 number、kingdee_bill_status=pushed; @@ -230,7 +230,7 @@ claimed 累计有效认领 == unclaimed_amount(且 > 0) ← 「认领 | 认领事务 | 落库后同事务立即推 A301-3,失败整体回滚 | 纯本地落库,不调 BFI | | 推送触发 | 每次认领动作 | 定时任务(`receiptClaimPush.*` 开关)+ 手动按钮,双入口同一服务方法 | | 推送条件 | 无(认领即推) | 累计有效认领 == 公告未认领金额(推送前重查 A301-2 实时对账) | -| 推送粒度 | 每次认领一张金蝶收款单 | 一条流水一张金蝶收款单(分摊行归集) | +| 推送粒度 | 每次认领一张金蝶收款单 | 一条流水一张金蝶收款单(单条分录,金额=全部未推送金额) | | awrp_src_code | 认领主单上,每次认领各自按结算单号拼接(多流水分摊到同一批结算单时撞码) | 流水上,按该流水全部分摊结算单号拼接,一条流水仅推送一次,不再撞码 | | 认领上限/认领完成口径 | receipt_amount | unclaimed_amount | | 推送状态/失败原因 | 无(失败即回滚无痕) | 流水上 push_status / push_fail_reason / pushed_time,失败可重试可追溯 | @@ -244,7 +244,7 @@ claimed 累计有效认领 == unclaimed_amount(且 > 0) ← 「认领 | 认领 | `ReceiptFlowServiceImpl.claim()` | 上限口径改公告未认领金额(缺失/为0拦截);删除同步推送调用,事务内只落本地 | | 推送 | `IReceiptFlowService.pushClaimToKingdee(flowId)` / `pushClaimByTask()` | 新增。共用 `pushClaimLocked`(`TransactionTemplate` 编程式事务,流水行锁覆盖闸门→对账→推送→落库,防并发双推);失败不抛异常跨事务边界,以 `ReceiptClaimPushResult` 返回 | | 定时任务 | `task/ReceiptClaimPushTask.java`(新增) | Nacos 开关 `thirdParty.bfi.receiptClaimPush.syncEnabled/cron`(默认关闭、每10分钟);候选=认领完成且 push_status ∈ (none, failed),按认领人姓名去重逐人重查 A301-2 | -| 推送报文 | `buildClaimPushDTO` | billid=流水.bill_id;分录=该流水全部有效分摊行(结算单升序);seq=结算单id;e_corebillno=结算单id(结算单已同步金蝶应收时携带);awrp_src_code=分摊结算单号下划线拼接 | +| 推送报文 | `buildClaimPushDTO` | billid=流水.bill_id;**单条分录**:e_receivableamt=全部未推送金额(累计有效认领),seq/e_corebillno=第一张结算单id;awrp_src_code=分摊结算单号下划线拼接 | | 手动接口 | `ReceiptFlowController.pushKingdee`(`POST /receipt-flow/push-kingdee`) | 成功返回金蝶收款单号,失败 R.fail(原因);按钮权限 `receipt_flow_push` | | 回写 | `ReceiptClaimRecordServiceImpl.refreshKingdeeResult()` | 轮询对象改流水(push_status=pushed 且回写状态 pushed/approved),按流水 awrp_src_code 匹配,级联刷新认领主单冗余字段 | | 作废 | `ReceiptClaimRecordServiceImpl.voidClaim()` | claim_status 重算口径改对照公告未认领金额(其余不变,作废不触发推送) |