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;
/**
* 收款账户名
*/