From f3d598f796137d6f409f66d4b210f8e7a705c052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Tue, 27 Oct 2026 19:43:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3HCS=E5=B1=A5=E7=BA=A6?= =?UTF-8?q?=E9=98=B6=E6=AE=B5=E4=B8=8E=E5=B1=A5=E7=BA=A6=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=AD=97=E6=AE=B5=E4=BC=A0=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C103-9 履约规则行新增 fdId(update/delete 定位用),fdUniqueId 仅 add 行传值 - 履约计划ID 回填优先取响应顶层 fdExeplanId,兜底响应行 fdId - C108 履约记录补传 fdPlanId(必填)、fdJdDocNo、fdDocSubject,附件补 fdBindType=ADD - 履约计划行未同步时抛异常交由付款链置 failed 重试 - 结算付款特批补传 fd_source_sys 外部系统编号 --- .../support/hcs/HcsExeStageSyncSupport.java | 15 ++++++++----- .../support/hcs/HcsPaymentSyncSupport.java | 2 ++ .../support/hcs/HcsPerfRecordSyncSupport.java | 22 ++++++++++++++----- .../support/hcs/HcsSpecPaySyncSupport.java | 2 ++ .../hcs/dto/HcsExeplanStageDTO.java | 9 ++++++-- .../hcs/dto/HcsSpecPayPropsDTO.java | 5 +++++ 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java index 9cc2a52d..088b44d8 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java @@ -57,7 +57,7 @@ import java.util.stream.Stream; *

* 随合同推送链路执行(合同须已同步、hcs_fd_id 存在):聚合 row_op 非 none 的规则行, * 整体 fdEopExeplanOperateType 首次为 add、后续为 update;请求行必送 fdUniqueId(取 TMS 行ID,重试稳定),响应行回 fdId; - * 履约计划ID 取返回 fdChangeStages 行的 fdId 回填 blade_contract_manage.hcs_exeplan_id(实际响应无顶层 fdExeplanId), + * 履约计划ID 取响应顶层 fdExeplanId 回填 blade_contract_manage.hcs_exeplan_id, * 各行 fdId 按行回填 hcs_stage_fd_id(必须持久化,供履约记录等接口引用)。 * * @author Chill @@ -123,8 +123,12 @@ public class HcsExeStageSyncSupport { List stages = new ArrayList<>(); for (HcsContractExeStage row : pendingRows) { HcsExeplanStageDTO stage = new HcsExeplanStageDTO(); - // 阶段唯一标识:所有行必传(取 TMS 行ID,重试重发保持不变,合规按此匹配行;add 行 hcs_stage_fd_id 为空不能作值) - stage.setFdUniqueId(String.valueOf(row.getId())); + // 阶段行ID:update/delete 行必传(HCS 凭首次 add 返回的 fdId 定位行,缺失报"履约计划已不存在"),add 行无值自动省略 + stage.setFdId(row.getHcsStageFdId()); + // 阶段唯一标识:仅 add 行必传(取 TMS 行ID,HCS 回显存储);update/delete 行实测无需携带,以 fdId 定位 + if ("add".equals(row.getRowOp())) { + stage.setFdUniqueId(String.valueOf(row.getId())); + } // 【必填】行级操作:add / update / delete stage.setFdEopExeplanOperateType(row.getRowOp()); // 【必填】履约类型:payment=付款 / collection=收款 @@ -159,8 +163,9 @@ public class HcsExeStageSyncSupport { */ private void backfill(ContractManage contractManage, List pendingRows, List requestStages, HcsExeplanVO exeplan) { - // 履约计划ID 回填:响应行 fdId 即履约计划ID(首次同步行在 fdAddStages、变更行在 fdChangeStages,取首个非空回填) - String fdExeplanId = Stream.of(exeplan.getFdChangeStages(), exeplan.getFdAddStages()) + // 履约计划ID 回填:优先取响应顶层 fdExeplanId(实测 add/update 均有返回),兜底取响应行 fdId + String fdExeplanId = StringUtil.isNotBlank(exeplan.getFdExeplanId()) ? exeplan.getFdExeplanId() + : Stream.of(exeplan.getFdChangeStages(), exeplan.getFdAddStages()) .filter(Objects::nonNull) .flatMap(List::stream) .map(HcsExeplanStageVO::getFdId) diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPaymentSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPaymentSyncSupport.java index 3bb56b68..1783fe6f 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPaymentSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPaymentSyncSupport.java @@ -157,6 +157,8 @@ public class HcsPaymentSyncSupport { String message = StringUtil.isBlank(exception.getMessage()) ? "履约数据推送异常" : exception.getMessage(); markFailed(payment, message); log.error("付款特批通过后履约数据推送失败:paymentNo={},{}", payment.getPaymentNo(), message, exception); + // todo + throw new ServiceException("付款特批通过后履约数据推送失败:" + message); } } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPerfRecordSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPerfRecordSyncSupport.java index 7e7aa5a0..54e14846 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPerfRecordSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPerfRecordSyncSupport.java @@ -58,7 +58,7 @@ import java.util.List; * 付款申请为主线:审批通过 → C108-1 新增(返回 fdId 回填 hcs_perf_fd_id); * 实际付款推进(paidAmount 变化置待同步)→ C108-2 更新(formData.fdId=hcs_perf_fd_id 必填,响应无 data)。 * 关联履约阶段:按合同+付款类型匹配已同步的履约规则行(付款/收款执行与计划阶段对应), - * 无关联则不传 fd_id(§5.6)。 + * fd_plan_id(履约计划id)接口必填,无已同步计划行时抛出重试(合同链路首推后自愈)。 * * @author Chill */ @@ -149,6 +149,10 @@ public class HcsPerfRecordSyncSupport { private HcsPerfRecordFormDataDTO buildFormData(PaymentApplication payment) { ContractManage contractManage = payment.getContractId() == null ? null : contractManageMapper.selectById(payment.getContractId()); HcsContractExeStage stageRow = findPaymentStageRow(payment); + // 【必填】fd_plan_id 履约计划id:无已同步计划行时无值可传,抛出由付款链置 failed 重试(合同链路首推后下轮自愈) + if (stageRow == null || StringUtil.isBlank(stageRow.getHcsStageFdId())) { + throw new HcsException("C108 履约记录未匹配到已同步履约计划行,fd_plan_id 必传:paymentNo=" + payment.getPaymentNo()); + } HcsPerfRecordFormDataDTO formData = new HcsPerfRecordFormDataDTO(); HcsPerfRecordPropsDTO props = new HcsPerfRecordPropsDTO(); // 申请金额:appliedAmount(接口按字符串传值) @@ -161,10 +165,13 @@ public class HcsPerfRecordSyncSupport { props.setFdPlanDate(toMillis(payment.getApplyDate())); // 计划类型:paymentType(原文拼写 fd_paln_type 必须沿用) props.setFdPalnType(payment.getPaymentType()); - // 性质:款项性质取关联履约规则行的款项性质(无关联不传) - props.setFdProperty(stageRow == null ? null : stageRow.getFundNature()); - // 来源履约计划项ID:关联履约阶段 hcs_stage_fd_id(无关联则不传,§5.6) - props.setFdId(stageRow == null ? null : stageRow.getHcsStageFdId()); + // 性质:款项性质取关联履约计划行的款项性质 + props.setFdProperty(stageRow.getFundNature()); + // 履约计划id / 来源履约计划项ID:履约计划行合规阶段ID(HCS 只认自己的阶段ID) + props.setFdId(stageRow.getHcsStageFdId()); + props.setFdPlanId(stageRow.getHcsStageFdId()); + // 金蝶单据号:付款推送金蝶返回的单号(溯源用) + props.setFdJdDocNo(payment.getKingdeeBillNo()); // 【必填】合同ID:HCS 合同ID(合同未推送时为空,联调确认兜底口径) props.setFdContractId(contractManage == null ? null : contractManage.getHcsFdId()); // 业务ID:TMS 付款申请单主键(方便溯源,v4 新增) @@ -176,6 +183,8 @@ public class HcsPerfRecordSyncSupport { props.setFdXformId(xformId); // 【必填】表单模板ID(formData 顶层 fd_xform_id,v4 必填) formData.setFdXformId(xformId); + // 标题:付款履约-付款申请单号(参照结算付款特批标题风格) + formData.setFdDocSubject("付款履约-" + payment.getPaymentNo()); formData.setDynamicProps(props); return formData; } @@ -194,8 +203,9 @@ public class HcsPerfRecordSyncSupport { } HcsMechanismsDTO mechanisms = new HcsMechanismsDTO(); mechanisms.setAttachment(attachmentRefs.stream().map(ref -> { - // 附件ID(C103-2 转传返回) + // 附件ID(C103-2 转传返回);C108-1 为发起类接口,绑定类型固定 ADD ref.setFdEntityKey(PERF_ATTACH_ENTITY_KEY); + ref.setFdBindType("ADD"); return ref; }).toList()); return mechanisms; diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsSpecPaySyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsSpecPaySyncSupport.java index eb258a17..d9543a14 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsSpecPaySyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsSpecPaySyncSupport.java @@ -135,6 +135,8 @@ public class HcsSpecPaySyncSupport { props.setFdDocSubject("结算付款特批-" + payment.getPaymentNo()); // 来源付款单ID:付款申请单号(§5.5 映射表) props.setFdId(payment.getPaymentNo()); + props.setFdSourceSys(hcsProperties.getSrcSystem()); + // 【必填】付款金额:appliedAmount props.setFdPayAmount(payment.getAppliedAmount()); // 【必填】合计金额:settlementAmount diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsExeplanStageDTO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsExeplanStageDTO.java index 21dbc7ac..7443fc35 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsExeplanStageDTO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsExeplanStageDTO.java @@ -36,7 +36,8 @@ import java.math.BigDecimal; /** * 合同合规系统(HCS)C103-9(新) 履约规则同步 行级操作项(数据源 blade_contract_exe_stage,ADR-0002) *

- * 新增行可不带 fdId;更新/删除行必须带 fdId(合规阶段ID,回填自首次同步返回)。 + * add 行必传 fdUniqueId(TMS 行唯一标识,HCS 回显存储);update/delete 行必传 fdId(首次 add 返回的阶段行ID, + * 持久化于 hcs_stage_fd_id),实测无需 fdUniqueId。 * * @author Chill */ @@ -47,9 +48,13 @@ public class HcsExeplanStageDTO implements Serializable { @Serial private static final long serialVersionUID = 1L; /** - * 阶段项ID(行级 update/delete 必传,取 blade_contract_exe_stage.hcs_stage_fd_id) + * 阶段行ID(HCS 返回的 fdId,持久化于 hcs_stage_fd_id;update/delete 行必传,add 行可不传) */ private String fdId; + /** + * 阶段唯一标识(仅 add 行必传,取 TMS 行ID,HCS 回显存储;update/delete 行以 fdId 定位,无需此值) + */ + private String fdUniqueId; /** * 行级操作:add / update / delete */ diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsSpecPayPropsDTO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsSpecPayPropsDTO.java index eb9d3fc1..4b292d5e 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsSpecPayPropsDTO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsSpecPayPropsDTO.java @@ -55,6 +55,11 @@ public class HcsSpecPayPropsDTO implements Serializable { */ @JsonProperty("fd_contract_no") private String fdContractNo; + /** + * 外部系统编号 + */ + @JsonProperty("fd_source_sys") + private String fdSourceSys; /** * 收款账户名 */