diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/KingdeeReceiptFlow.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/KingdeeReceiptFlow.java index 0499d56b..533394ae 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/KingdeeReceiptFlow.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/KingdeeReceiptFlow.java @@ -137,7 +137,7 @@ public class KingdeeReceiptFlow extends TenantEntity { */ private LocalDateTime pushedTime; /** - * 金蝶推送来源单据编码(SKCL+时间戳+流水id尾号6位,按流水生成、重试复用,A301-1 回写匹配键) + * 金蝶推送来源单据编码(分摊结算单号下划线拼接,推送时生成落库;分摊不变则重试编码不变,A301-1 回写匹配键) */ private String awrpSrcCode; /** 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 dc463142..5f083d25 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 @@ -792,10 +792,6 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl allocations = claimSettlementMapper.selectList( Wrappers.lambdaQuery() @@ -814,6 +810,14 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpllambdaQuery() .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() + .map(ReceiptClaimSettlement::getFormalSettlementNo) + .filter(Func::isNotEmpty) + .distinct() + .collect(Collectors.joining("_")); + flow.setAwrpSrcCode(awrpSrcCode); BfiClaimPushDTO param = buildClaimPushDTO(flow, allocations, settlements); log.info("调用BFI接口 收款认领结果推送开始 flowId:{},billId:{},awrpSrcCode:{},分摊明细 {} 行,认领金额 {}", @@ -836,7 +840,7 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl entries = new ArrayList<>(); - int seq = 1; for (ReceiptClaimSettlement allocation : allocations) { BfiClaimPushEntryDTO entry = new BfiClaimPushEntryDTO(); // 【必填】应收金额(分摊金额) entry.setEReceivableamt(money(allocation.getAllocatedReceiptAmount())); - // 分录行序号 - entry.setSeq((long) seq++); + // 分录行序号(结算单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); - // 核心单据编号 - entry.setECorebillno(settlement.getKingdeeBillNo()); + // 核心单据编号(结算单id) + entry.setECorebillno(String.valueOf(settlement.getId())); } entries.add(entry); } @@ -939,15 +942,6 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl 0) ← 「认领 - 公告查不到 → 失败:「金蝶公告不存在或已不在认领范围,请重新同步」 - 重验:累计有效认领 == 最新 unclaimed_amount,不等 → 失败并提示两侧金额差额 (不等说明金蝶侧有人认领过或金额有变,需人工核对后作废/补认领) -④ awrp_src_code:已有则复用;无则生成并落库(SKCL+时间戳+流水id尾号6位) +④ awrp_src_code:按分摊结算单号下划线拼接生成并落库(分摊不变则重试编码不变) ⑤ 组装 A301-3:billid=流水.bill_id,entries = 该流水全部有效分摊行 (分摊行 join 结算单,按结算单 id 升序;金额=allocated_receipt_amount; - 结算单有 kingdee_bill_no 时携带 e_corebillno,沿用现有取数) + seq=结算单id;结算单有 kingdee_bill_no 时携带 e_corebillno=结算单id,沿用契约取数) ⑥ 调 pushClaimResult: 成功 → push_status=pushed、push_fail_reason 清空、pushed_time=now、 kingdee_bill_no=响应 number、kingdee_bill_status=pushed; @@ -183,14 +183,14 @@ claimed 累计有效认领 == unclaimed_amount(且 > 0) ← 「认领 | 场景 | 行为 | | --- | --- | | 定时任务与手动按钮并发推同一流水 | 流水行锁串行化 + `push_status != pushed` 静态闸门,不会双推 | -| 推送超时但金蝶实际已生成收款单 | 本地记 failed;重试复用同一 `awrp_src_code`,金蝶候选键幂等,不产生重复收款单 | +| 推送超时但金蝶实际已生成收款单 | 本地记 failed;重试时分摊不变则 `awrp_src_code` 不变,金蝶候选键幂等,不产生重复收款单 | | 推送成功后作废一笔认领、再补认领到等式满足 | 终态闸门拦截,不二次推送;金蝶侧冲销人工处置 | | 公告侧 unclaimed_amount 变小(他人在金蝶认领) | 推送前实时对账发现差额 → 拦截并提示差额,人工作废多余本地认领后重推 | | 公告侧 unclaimed_amount 变大 | 用户补认领到等式满足后推送(认领上限随新值放开) | | unclaimamount = 0 的公告 | 认领上限为 0,不可认领;累计认领 > 0 的推送前置条件天然排除空推 | | 手动推送者不在公告认领范围 | A301-2 按其姓名查不到公告 → 拦截提示,改由认领人操作 | -防重键沿用旧文档 §6.3,变更点:`awrp_src_code` 由「认领主单、结算单号拼接」改为「流水、按流水生成、重试复用」,A301-1 匹配键随之移到流水上。 +防重键沿用旧文档 §6.3,变更点:`awrp_src_code` 由「认领主单、每次认领各自拼接」改为「流水、按该流水全部分摊结算单号拼接、仅推送一次」,A301-1 匹配键随之移到流水上。 ## 6. 前端改动汇总(tms-erp-web) @@ -231,7 +231,7 @@ claimed 累计有效认领 == unclaimed_amount(且 > 0) ← 「认领 | 推送触发 | 每次认领动作 | 定时任务(`receiptClaimPush.*` 开关)+ 手动按钮,双入口同一服务方法 | | 推送条件 | 无(认领即推) | 累计有效认领 == 公告未认领金额(推送前重查 A301-2 实时对账) | | 推送粒度 | 每次认领一张金蝶收款单 | 一条流水一张金蝶收款单(分摊行归集) | -| awrp_src_code | 认领主单上,结算单号拼接(可撞码) | 流水上,SKCL+时间戳+流水尾号,重试复用 | +| awrp_src_code | 认领主单上,每次认领各自按结算单号拼接(多流水分摊到同一批结算单时撞码) | 流水上,按该流水全部分摊结算单号拼接,一条流水仅推送一次,不再撞码 | | 认领上限/认领完成口径 | receipt_amount | unclaimed_amount | | 推送状态/失败原因 | 无(失败即回滚无痕) | 流水上 push_status / push_fail_reason / pushed_time,失败可重试可追溯 | | A301-1 轮询对象 | 认领主单 | 流水(级联刷新认领主单冗余字段) | @@ -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 1起);e_corebillno=结算单金蝶应收单号;awrp_src_code 按流水生成(SKCL+时间戳+尾号6位)、重试复用 | +| 推送报文 | `buildClaimPushDTO` | billid=流水.bill_id;分录=该流水全部有效分摊行(结算单升序);seq=结算单id;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 重算口径改对照公告未认领金额(其余不变,作废不触发推送) | diff --git a/doc/sql/transport/blade_receipt_flow_push_20260928.sql b/doc/sql/transport/blade_receipt_flow_push_20260928.sql index ed40e156..f4f4c542 100644 --- a/doc/sql/transport/blade_receipt_flow_push_20260928.sql +++ b/doc/sql/transport/blade_receipt_flow_push_20260928.sql @@ -2,7 +2,7 @@ -- 支持重复执行,兼容 20260924 脚本已执行/未执行的环境,与该脚本无执行顺序要求 -- 变更点: -- 1. 收款流水表新增推送域字段(推送状态/失败原因/推送时间/推送编码/金蝶收款单号/回写状态) --- 2. 认领主单移除 awrp_src_code 及其索引(推送编码上移至流水:按流水生成、重试复用) +-- 2. 认领主单移除 awrp_src_code 及其索引(推送编码上移至流水:分摊结算单号拼接) -- 3. 收款流水表新增定时任务扫描索引与 A301-1 回写匹配索引 -- 1. 收款流水表:推送状态 @@ -41,10 +41,10 @@ PREPARE ddl_stmt FROM @ddl_sql; EXECUTE ddl_stmt; DEALLOCATE PREPARE ddl_stmt; --- 4. 收款流水表:推送来源单据编码(A301-3 awrp_src_code,A301-1 回写匹配键,重试复用) +-- 4. 收款流水表:推送来源单据编码(A301-3 awrp_src_code,分摊结算单号拼接,A301-1 回写匹配键) SET @ddl_sql = ( SELECT IF(COUNT(*) = 0, - 'ALTER TABLE `blade_kingdee_receipt_flow` ADD COLUMN `awrp_src_code` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''金蝶推送来源单据编码(SKCL+时间戳+流水id尾号6位,按流水生成重试复用)''', + 'ALTER TABLE `blade_kingdee_receipt_flow` ADD COLUMN `awrp_src_code` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''金蝶推送来源单据编码(分摊结算单号下划线拼接,A301-1回写匹配键)''', 'SELECT 1') FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_kingdee_receipt_flow' AND COLUMN_NAME = 'awrp_src_code'