From d147ef82091425c3fb26477eac0131d1f49f595f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Sun, 27 Sep 2026 23:35:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20HCS=E5=B1=A5=E7=BA=A6=E8=A7=84=E5=88=99?= =?UTF-8?q?C103-9=E8=A1=8C=E7=BA=A7=E5=90=8C=E6=AD=A5=EF=BC=88=E9=9A=8F?= =?UTF-8?q?=E5=90=88=E5=90=8C=E9=93=BE=E8=B7=AF=E6=89=A7=E8=A1=8C/?= =?UTF-8?q?=E8=A1=8C=E7=BA=A7=E5=A2=9E=E5=88=A0=E6=94=B9=E8=81=9A=E5=90=88?= =?UTF-8?q?/=E5=B1=A5=E7=BA=A6=E8=AE=A1=E5=88=92ID=E4=B8=8E=E9=98=B6?= =?UTF-8?q?=E6=AE=B5fdId=E5=9B=9E=E5=A1=AB=E6=8C=81=E4=B9=85=E5=8C=96?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/hcs/HcsContractSyncSupport.java | 25 +- .../support/hcs/HcsExeStageSyncSupport.java | 271 ++++++++++++++++++ .../transport/task/HcsPushTask.java | 2 +- 3 files changed, 288 insertions(+), 10 deletions(-) create mode 100644 blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSyncSupport.java index 4b06fcf8..471f5004 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSyncSupport.java @@ -70,7 +70,7 @@ import java.util.Objects; *
* 扫描任务按序执行:① 客商风险校验(可配开关,黑名单阻断)→ ② 附件转传(挂载点待 §9-U8 确认,先转传缓存)→ * ③ C103-3 判重(§9-U4 查询能力联调确认)→ ④ C103-1 起草 / 变更单 C103-11 更新(§9-U5 定位方式待联调)→ - * ⑤ 履约规则 C103-9(P2 接线)。 + * ⑤ 履约规则 C103-9 行级同步({@link HcsExeStageSyncSupport})。 * 结果留痕:风险校验写 blade_hcs_check_log 与合同 hcs_risk_* 字段;推送结果回填 hcs_fd_id/hcs_sync_status。 * * @author Chill @@ -97,6 +97,7 @@ public class HcsContractSyncSupport { private final CustomerArchiveMapper customerArchiveMapper; private final HcsContractCheckLogMapper hcsContractCheckLogMapper; private final HcsAttachmentSupport hcsAttachmentSupport; + private final HcsExeStageSyncSupport hcsExeStageSyncSupport; /** * 推送合同到 HCS:风险校验 → 附件转传 → 判重 → 起草/更新 → 回填合规 fdId 置 synced @@ -112,20 +113,26 @@ public class HcsContractSyncSupport { // ② 附件转传(先转传并缓存合规附件ID,C103-1 挂载方式待 §9-U8 确认后接线) transferAttachmentsIfEnabled(contractManage); // ③④ 首推判重后起草(C103-1);已有合规ID(变更单)走更新(C103-11) + String resultMessage; if (StringUtil.isBlank(contractManage.getHcsFdId())) { String existFdId = findExistFdId(contractManage); if (StringUtil.isNotBlank(existFdId)) { markSynced(contractManage, existFdId, "判重命中,回填已有合规合同ID"); - return "判重命中,回填已有合规合同ID"; + resultMessage = "判重命中,回填已有合规合同ID"; + } else { + String fdContractId = draftContract(contractManage); + // 先持久化合规合同ID(调用方必须保存),履约规则同步失败时下轮凭其走更新补偿 + markSynced(contractManage, fdContractId, "C103-1 合同发起成功"); + resultMessage = "C103-1 合同发起成功"; } - String fdContractId = draftContract(contractManage); - // TODO 待联调(P2):履约规则 C103-9 行级同步随合同链路执行(§5.3,依赖 blade_contract_exe_stage 表) - markSynced(contractManage, fdContractId, "C103-1 合同发起成功"); - return "C103-1 合同发起成功"; + } else { + updateContract(contractManage); + markSynced(contractManage, contractManage.getHcsFdId(), "C103-11 合同更新成功"); + resultMessage = "C103-11 合同更新成功"; } - updateContract(contractManage); - markSynced(contractManage, contractManage.getHcsFdId(), "C103-11 合同更新成功"); - return "C103-11 合同更新成功"; + // ⑤ 履约规则 C103-9 行级同步(随合同链路,§5.3;失败抛出由任务落 failed,下轮凭 hcs_fd_id 走更新补偿) + String exeStageResult = hcsExeStageSyncSupport.syncExeStages(contractManage); + return resultMessage + ";" + exeStageResult; } /** 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 new file mode 100644 index 00000000..301c385c --- /dev/null +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java @@ -0,0 +1,271 @@ +/** + * BladeX Commercial License Agreement + * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved. + *
+ * Use of this software is governed by the Commercial License Agreement + * obtained after purchasing a license from BladeX. + *
+ * 1. This software is for development use only under a valid license + * from BladeX. + *
+ * 2. Redistribution of this software's source code to any third party + * without a commercial license is strictly prohibited. + *
+ * 3. Licensees may copyright their own code but cannot use segments + * from this software for such purposes. Copyright of this software + * remains with BladeX. + *
+ * Using this software signifies agreement to this License, and the software + * must not be used for illegal purposes. + *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is + * not liable for any claims arising from secondary or illegal development. + *
+ * Author: Chill Zhuang (bladejava@qq.com) + */ +package org.springblade.transport.support.hcs; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springblade.core.tool.utils.StringUtil; +import org.springblade.hcs.config.HcsProperties; +import org.springblade.hcs.dto.HcsExeplanStageDTO; +import org.springblade.hcs.dto.HcsExeplanStageVO; +import org.springblade.hcs.dto.HcsExeplanSyncDTO; +import org.springblade.hcs.dto.HcsExeplanVO; +import org.springblade.hcs.dto.HcsResult; +import org.springblade.hcs.exception.HcsException; +import org.springblade.hcs.feign.IHcsClient; +import org.springblade.system.cache.UserCache; +import org.springblade.system.pojo.entity.User; +import org.springblade.transport.constant.HcsSyncConstant; +import org.springblade.transport.mapper.ContractManageMapper; +import org.springblade.transport.mapper.HcsContractExeStageMapper; +import org.springblade.transport.pojo.entity.ContractManage; +import org.springblade.transport.pojo.entity.HcsContractExeStage; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * HCS 履约规则同步支撑组件(C103-9 新版行级同步,设计文档 §5.3,ADR-0002) + *
+ * 随合同推送链路执行(合同须已同步、hcs_fd_id 存在):聚合 row_op 非 none 的规则行
+ * (add 行不带 fdId,update/delete 行必须带合规阶段ID),整体 fdEopExeplanOperateType
+ * 首次为 add、后续为 update;返回的 fdExeplanId 回填 blade_contract_manage.hcs_exeplan_id,
+ * 变更阶段 fdId 按行回填 hcs_stage_fd_id(合规返回的 fdId 必须持久化,后续行更新/删除全靠它)。
+ *
+ * @author Chill
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class HcsExeStageSyncSupport {
+
+ /**
+ * 行级扩展内容固定空 JSON
+ */
+ private static final String EXTEND_CONTENT_EMPTY = "{}";
+
+ private final IHcsClient hcsClient;
+ private final HcsProperties hcsProperties;
+ private final ContractManageMapper contractManageMapper;
+ private final HcsContractExeStageMapper hcsContractExeStageMapper;
+
+ /**
+ * 同步合同履约规则到 HCS(C103-9),成功后回填 fdExeplanId 与各阶段 fdId 并清除行级操作标记
+ *
+ * @param contractManage 合同(须已同步,hcs_fd_id 非空)
+ * @return 同步结果描述(无待同步行时返回提示)
+ */
+ public String syncExeStages(ContractManage contractManage) {
+ if (StringUtil.isBlank(contractManage.getHcsFdId())) {
+ throw new HcsException("C103-9 履约规则同步失败,合同尚未推送合规(contractNo=" + contractManage.getContractNo() + ")");
+ }
+ // 含软删行:delete 行已逻辑删除但须凭合规阶段ID 上报(原生 SQL 绕过逻辑删除过滤)
+ List
+ * TODO 待联调确认:fdChangeStages 与请求行的对应关系 v4 未明确,优先按请求行序对应(首次全 add 场景),
+ * 行数不一致时按业务属性组合键匹配,仍匹配不到的 add 行保持待同步(下轮重试)。
+ */
+ private void backfill(ContractManage contractManage, List
* 审批代码零埋点:扫描只认 approvalStatus=approved/change_approved 且 hcs_sync_status=unsynced/failed(重试未超限),
* 与审批入口(/approve、MK 回调)无关;失败落 failed 由下轮扫描自动补偿,超限仅人工重推(D7)。
- * 任务顺序:项目 → 合同(内含风险校验→附件转传→C103-1→履约规则 P2 接线)。
+ * 任务顺序:项目 → 合同(内含风险校验→附件转传→C103-1→履约规则 C103-9 行级同步)。
* 多实例部署时以 Redis 分布式锁防重扫(照既有 BladeRedis 用法,单实例部署行为与既有金蝶任务一致)。
* 扫描与推送逻辑收敛在 pushUnsyncedProjects/pushUnsyncedContracts,供手动端点(HcsSyncController)复用。
*