From 2b581b730547656ea2250fccee5acdda180f7e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Thu, 22 Oct 2026 11:35:21 +0800 Subject: [PATCH] =?UTF-8?q?:fix:=20=E7=BB=9F=E4=B8=80=E5=86=85=E9=83=A8?= =?UTF-8?q?=E7=BB=84=E7=BB=87=E5=AE=A2=E5=95=86=E5=88=A4=E5=AE=9A=E5=8F=A3?= =?UTF-8?q?=E5=BE=84=E3=80=81=E7=B2=BE=E7=AE=80=E9=AB=98=E9=A3=8E=E9=99=A9?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E6=96=87=E6=A1=88=E5=B9=B6=E7=A7=BB=E9=99=A4?= =?UTF-8?q?mock=E6=8E=A7=E5=88=B6=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/HcsMockController.java | 123 ------------------ .../support/hcs/HcsContractSyncSupport.java | 38 ++---- .../support/hcs/HcsCreditCheckSupport.java | 21 ++- 3 files changed, 32 insertions(+), 150 deletions(-) delete mode 100644 blade-service/blade-transport/src/main/java/org/springblade/transport/controller/HcsMockController.java diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/HcsMockController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/HcsMockController.java deleted file mode 100644 index 247f0e87..00000000 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/HcsMockController.java +++ /dev/null @@ -1,123 +0,0 @@ -/** - * 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.controller; - -import cn.hutool.core.util.StrUtil; -import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.extern.slf4j.Slf4j; -import org.springblade.core.log.exception.ServiceException; -import org.springblade.core.tenant.annotation.TenantIgnore; -import org.springblade.core.tool.api.R; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Map; -import java.util.Objects; - -/** - * HCS 合规回调 Mock 端点 - *

- * 合同法务审批结果回调(D103)、付款法务审批结果回调(D104)、项目金蝶同步结果回调(D902)、 - * 合同金蝶同步结果回传接收(D903)四个入站回调的纯 mock 实现:仅校验来源系统标识后返回固定结果, - * 不读写业务数据、不联动状态。真实处理逻辑保留在对应 Support 中,联调时把端点切回 - * {@link } 并调用 Support 方法即可。 - * - * @author Chill - */ -@Slf4j -@RestController -@TenantIgnore -@RequestMapping("hcs") -@Tag(name = "HCS合规回调Mock", description = "HCS合规回调Mock端点(仅自测,返回固定 mock 数据)") -public class HcsMockController { - - /** - * 来源系统标识(合规方约定值,与 third-party.hcs.src-system 默认值一致) - */ - private static final String SOURCE_SYSTEM = "WLTMS"; - - /** - * 合同法务审批结果回调(D103) - */ - @PostMapping("/contractLegal/result") - @ApiOperationSupport(order = 15) - @Operation(summary = "合同法务审批结果回调Mock", description = "D103 合规推送合同特批(金蝶同步)结果,仅校验来源系统并返回 mock 数据") - public R contractLegalResult(@RequestBody(required = false) Map param) { - this.checkSourceSystem("合同法务审批结果", param); - return R.data("mock特批结果已处理:approved"); - } - - /** - * 付款法务审批结果回调(D104) - */ - @PostMapping("/paymentLegal/result") - @ApiOperationSupport(order = 16) - @Operation(summary = "付款法务审批结果回调Mock", description = "D104 合规推送付款特批结果,仅校验来源系统并返回 mock 数据") - public R paymentLegalResult(@RequestBody(required = false) Map param) { - this.checkSourceSystem("付款法务审批结果", param); - return R.data("mock付款特批结果接收已处理:approved"); - } - - /** - * 项目金蝶同步结果回调(D902) - */ - @PostMapping("/projectLegal/result") - @ApiOperationSupport(order = 18) - @Operation(summary = "项目金蝶同步结果回调Mock", description = "D902 合规推送项目金蝶同步结果,仅校验来源系统并返回 mock 数据") - public R projectLegalResult(@RequestBody(required = false) Map param) { - this.checkSourceSystem("项目金蝶同步结果", param); - return R.data("mock项目金蝶同步结果接收已处理:approved"); - } - - /** - * 合同金蝶同步结果回传接收(D903) - */ - @PostMapping("/contractKingdee/result") - @ApiOperationSupport(order = 19) - @Operation(summary = "合同金蝶同步结果回传接收Mock", description = "D903 合规推送合同金蝶最终同步结果,仅校验来源系统并返回 mock 数据") - public R contractKingdeeResult(@RequestBody(required = false) Map param) { - this.checkSourceSystem("合同金蝶同步结果", param); - return R.data("mock合同金蝶同步结果接收处理:approved"); - } - - /** - * 来源系统校验:仅接受合规方约定的来源标识,防伪造回传 - * - * @param bizName 业务名称(日志用) - * @param param 回调报文 - */ - private void checkSourceSystem(String bizName, Map param) { - String sourceSystem = param == null ? null : Objects.toString(param.get("sourceSystem"), null); - if (!StrUtil.equalsIgnoreCase(sourceSystem, SOURCE_SYSTEM)) { - log.warn("{}推送来源系统标识错误:sourceSystem={}", bizName, sourceSystem); - throw new ServiceException("来源系统标识错误"); - } - } -} 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 4766bbd5..e8634615 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 @@ -337,22 +337,29 @@ public class HcsContractSyncSupport { } /** - * 查询单方客商风险:按名称反查客商编号(§9-U6 编码体系联调确认),反查不到记 skip 留痕不阻断 + * 查询单方客商风险:按名称反查客商档案(§9-U6 编码体系联调确认),反查不到记 skip 留痕不阻断; + * 内部组织客商默认无风险跳过(与展示/提交/付款链路口径一致,不调 C101-1) */ private RiskResult queryRisk(ContractManage contractManage, String standing, String partyName) { - String customerCode = queryCustomerCode(partyName); - if (StringUtil.isBlank(customerCode)) { + CustomerArchive customerArchive = queryCustomerArchive(partyName); + if (customerArchive == null) { writeCheckLog(contractManage, HcsSyncConstant.CHECK_RESULT_SKIP, standing + "方[" + partyName + "]反查不到客商编号,跳过风险校验(§9-U6)", null); return new RiskResult(null, null, false); } + // 内部组织类型客商默认无风险,不调 C101-1(与展示/提交/付款链路口径一致) + if (HcsCreditCheckSupport.isInternalCustomer(customerArchive)) { + writeCheckLog(contractManage, HcsSyncConstant.CHECK_RESULT_SKIP, + standing + "方[" + partyName + "]为内部组织客商,默认无风险跳过校验", null); + return new RiskResult(null, null, false); + } HcsRiskQueryDTO param = new HcsRiskQueryDTO(); // 【必填】客商编号:按甲乙方名称反查 CustomerArchive 客商编码(§9-U6) - param.setFdNumber(customerCode); + param.setFdNumber(customerArchive.getCustomerCode()); HcsResult result = hcsClient.getRelativeRisk(param); if (result == null || !result.isSuccess()) { log.error("HCS客商风险查询失败响应:{},contractNo={},standing={},fdNumber={}", - result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), contractManage.getContractNo(), standing, customerCode); + result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), contractManage.getContractNo(), standing, customerArchive.getCustomerCode()); throw new HcsException("C101-1 客商风险查询失败:" + (result == null ? "响应为空" : result.getMsg())); } HcsRiskVO risk = result.getData(); @@ -534,8 +541,8 @@ public class HcsContractSyncSupport { // 甲乙方各反查一次客商档案,编号与内部组织判定共用查询结果 CustomerArchive partyAArchive = queryCustomerArchive(contractManage.getPartyA()); CustomerArchive partyBArchive = queryCustomerArchive(contractManage.getPartyB()); - boolean partyAInternal = isInternalCustomer(partyAArchive); - boolean partyBInternal = isInternalCustomer(partyBArchive); + boolean partyAInternal = HcsCreditCheckSupport.isInternalCustomer(partyAArchive); + boolean partyBInternal = HcsCreditCheckSupport.isInternalCustomer(partyBArchive); String partyAType; String partyBType; if (partyAInternal || partyBInternal) { @@ -672,14 +679,6 @@ public class HcsContractSyncSupport { return templateId; } - /** - * 按名称反查客商编码(照 KingdeeApBillSyncSupport#queryCustomerCode 惯例,查不到返回 null) - */ - private String queryCustomerCode(String partyName) { - CustomerArchive customerArchive = queryCustomerArchive(partyName); - return customerArchive == null ? null : customerArchive.getCustomerCode(); - } - /** * 按名称反查客商档案(全称或简称精确匹配,查不到返回 null) */ @@ -693,15 +692,6 @@ public class HcsContractSyncSupport { .last("limit 1")); } - /** - * 内部组织客商判定(集团内我方签约主体,档案登记 customerKind=internal/内部组织) - */ - private boolean isInternalCustomer(CustomerArchive customerArchive) { - return customerArchive != null - && (HcsSyncConstant.CUSTOMER_KIND_INTERNAL.equals(customerArchive.getCustomerKind()) - || "内部组织".equals(customerArchive.getCustomerKind())); - } - /** * 关联项目取值:合同所选项目对应合同系统项目ID(blade_project_apply.hcs_fd_id,C102-1 立项同步回填), * 未选择项目、立项单不存在或未同步合规时返回 null 不传(fdProject 选填) diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsCreditCheckSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsCreditCheckSupport.java index 8d2d8288..2b158e4e 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsCreditCheckSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsCreditCheckSupport.java @@ -118,7 +118,7 @@ public class HcsCreditCheckSupport { return; } // 内部组织类型客商默认无风险,不查 C101-1(与 queryCustomerRisk 展示口径一致) - if (HcsSyncConstant.CUSTOMER_KIND_INTERNAL.equals(customerArchive.getCustomerKind())) { + if (isInternalCustomer(customerArchive)) { writeCheckLog(payment, HcsSyncConstant.CHECK_TYPE_RISK, HcsSyncConstant.CHECK_RESULT_SKIP, "收款方[" + payment.getPayeeName() + "]为内部组织客商,默认无风险跳过校验", null); return; @@ -212,7 +212,7 @@ public class HcsCreditCheckSupport { riskVO.setCustomerCode(customerCode); riskVO.setCustomerName(customerArchive == null ? customerCode : customerArchive.getFullName()); // 内部组织类型客商默认无风险;档案不存在按外部客商查询(不静默放行) - boolean internal = customerArchive != null && HcsSyncConstant.CUSTOMER_KIND_INTERNAL.equals(customerArchive.getCustomerKind()); + boolean internal = isInternalCustomer(customerArchive); riskVO.setCustomerKind(internal ? HcsSyncConstant.CUSTOMER_KIND_INTERNAL : "external"); if (internal) { riskVO.setRisky(Boolean.FALSE); @@ -236,7 +236,9 @@ public class HcsCreditCheckSupport { riskVO.setRiskLevelName(riskLevelName(blackStatus, riskLevel)); riskVO.setRisky(risky); if (risky) { - riskVO.setRiskTip("【" + riskVO.getCustomerName() + "】:被列入外部黑名单;涉贪污受贿裁判相关提及方(3年以上及其他);被执行人信息;买卖合同纠纷;劳动纠纷;重大纠纷"); + // 风险提示固定短文案(C101-1 未返回风险项明细,不拼接枚举清单):黑名单与高风险区分表述 + riskVO.setRiskTip("【" + riskVO.getCustomerName() + "】:" + + (BLACK_STATUS_YES.equalsIgnoreCase(blackStatus) ? "被列入外部黑名单" : "为高风险客商")); } try { HcsContractCheckLog checkLog = new HcsContractCheckLog(); @@ -271,6 +273,19 @@ public class HcsCreditCheckSupport { return queryCustomerRisk(customerCode); } + /** + * 内部组织客商判定(集团内我方签约主体,档案登记 customerKind=internal/内部组织); + * 展示、提交校验、付款校验、合同推送、signer 单位类型各链路统一复用本判定 + * + * @param customerArchive 客商档案 + * @return 是否内部组织客商 + */ + public static boolean isInternalCustomer(CustomerArchive customerArchive) { + return customerArchive != null + && (HcsSyncConstant.CUSTOMER_KIND_INTERNAL.equals(customerArchive.getCustomerKind()) + || "内部组织".equals(customerArchive.getCustomerKind())); + } + /** * 风险等级转义(C101-1 枚举 0=低风险/1=中风险/2=高风险):黑名单状态优先展示,无等级返回空 */