From 923d963b29bed3c0bc405c999d05bdf35d50f1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Mon, 9 Nov 2026 15:54:02 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=A2=E5=95=86=E9=A3=8E=E9=99=A9C10?= =?UTF-8?q?1-1=E6=9F=A5=E8=AF=A2=E6=94=B9=E6=8C=89=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E7=A4=BE=E4=BC=9A=E4=BF=A1=E7=94=A8=E4=BB=A3=E7=A0=81,=20?= =?UTF-8?q?=E4=BF=A1=E7=94=A8=E4=BB=A3=E7=A0=81=E4=B8=BA=E7=A9=BA=E5=90=84?= =?UTF-8?q?=E9=93=BE=E8=B7=AF=E8=B7=B3=E8=BF=87=E7=95=99=E7=97=95=E4=B8=8D?= =?UTF-8?q?=E9=98=BB=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/hcs/HcsContractSyncSupport.java | 17 +++-- .../support/hcs/HcsCreditCheckSupport.java | 65 +++++++++++++------ .../springblade/hcs/dto/HcsRiskQueryDTO.java | 2 +- .../org/springblade/hcs/feign/IHcsClient.java | 2 +- 4 files changed, 60 insertions(+), 26 deletions(-) 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 8c4f6c16..ae242ba3 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,14 +337,14 @@ public class HcsContractSyncSupport { } /** - * 查询单方客商风险:按名称反查客商档案(§9-U6 编码体系联调确认),反查不到记 skip 留痕不阻断; + * 查询单方客商风险:按名称反查客商档案(§9-U6 编码体系联调确认),反查不到档案或信用代码为空记 skip 留痕不阻断; * 内部组织客商默认无风险跳过(与展示/提交/付款链路口径一致,不调 C101-1) */ private RiskResult queryRisk(ContractManage contractManage, String standing, String partyName) { CustomerArchive customerArchive = queryCustomerArchive(partyName); if (customerArchive == null) { writeCheckLog(contractManage, HcsSyncConstant.CHECK_RESULT_SKIP, - standing + "方[" + partyName + "]反查不到客商编号,跳过风险校验(§9-U6)", null); + standing + "方[" + partyName + "]反查不到客商档案,跳过风险校验(§9-U6)", null); return new RiskResult(false, null); } // 内部组织类型客商默认无风险,不调 C101-1(与展示/提交/付款链路口径一致) @@ -353,13 +353,20 @@ public class HcsContractSyncSupport { standing + "方[" + partyName + "]为内部组织客商,默认无风险跳过校验", null); return new RiskResult(false, null); } + // C101-1 改按统一社会信用代码查询:信用代码为空无法查询,跳过并留痕(同反查不到口径) + String creditCode = customerArchive.getUnifiedCreditCode(); + if (StringUtil.isBlank(creditCode)) { + writeCheckLog(contractManage, HcsSyncConstant.CHECK_RESULT_SKIP, + standing + "方[" + partyName + "]信用代码为空,跳过风险校验", null); + return new RiskResult(false, null); + } HcsRiskQueryDTO param = new HcsRiskQueryDTO(); - // 【必填】客商编号:按甲乙方名称反查 CustomerArchive 客商编码(§9-U6) - param.setFdNumber(customerArchive.getCustomerCode()); + // 【必填】统一社会信用代码:按甲乙方名称反查 CustomerArchive(C101-1 改按信用代码查询) + param.setFdNumber(creditCode); 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, customerArchive.getCustomerCode()); + result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), contractManage.getContractNo(), standing, creditCode); throw new HcsException("C101-1 客商风险查询失败:" + (result == null ? "响应为空" : result.getMsg())); } HcsRiskVO risk = result.getData(); 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 235443a4..5de6e5d4 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 @@ -123,8 +123,8 @@ public class HcsCreditCheckSupport { CustomerArchive customerArchive = queryCustomerArchive(payment.getPayeeName()); if (customerArchive == null) { writeCheckLog(payment, HcsSyncConstant.CHECK_TYPE_RISK, HcsSyncConstant.CHECK_RESULT_SKIP, - "收款方[" + payment.getPayeeName() + "]反查不到客商编号,跳过风险校验(§9-U6)", null); - log.warn("HCS付款提交风险校验跳过:paymentNo={},收款方反查不到客商编号", payment.getPaymentNo()); + "收款方[" + payment.getPayeeName() + "]反查不到客商档案,跳过风险校验(§9-U6)", null); + log.warn("HCS付款提交风险校验跳过:paymentNo={},收款方反查不到客商档案", payment.getPaymentNo()); return; } // 内部组织类型客商默认无风险,不查 C101-1(与 queryCustomerRisk 展示口径一致) @@ -133,13 +133,21 @@ public class HcsCreditCheckSupport { "收款方[" + payment.getPayeeName() + "]为内部组织客商,默认无风险跳过校验", null); return; } + // C101-1 改按统一社会信用代码查询:信用代码为空无法查询,跳过并留痕(同反查不到口径) + String creditCode = customerArchive.getUnifiedCreditCode(); + if (StringUtil.isBlank(creditCode)) { + writeCheckLog(payment, HcsSyncConstant.CHECK_TYPE_RISK, HcsSyncConstant.CHECK_RESULT_SKIP, + "收款方[" + payment.getPayeeName() + "]信用代码为空,跳过风险校验", null); + log.warn("HCS付款提交风险校验跳过:paymentNo={},收款方信用代码为空", payment.getPaymentNo()); + return; + } HcsRiskQueryDTO param = new HcsRiskQueryDTO(); - // 【必填】客商编号:按收款方名称反查 CustomerArchive 客商编码(用哪个编码待联调,§9-U6) - param.setFdNumber(customerArchive.getCustomerCode()); + // 【必填】统一社会信用代码:按收款方名称反查 CustomerArchive(C101-1 改按信用代码查询) + param.setFdNumber(creditCode); HcsResult result = hcsClient.getRelativeRisk(param); if (result == null || !result.isSuccess()) { log.error("HCS客商风险查询失败响应:{},paymentNo={},fdNumber={}", - result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), payment.getPaymentNo(), customerArchive.getCustomerCode()); + result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), payment.getPaymentNo(), creditCode); throw new HcsException("C101-1 客商风险查询失败:" + (result == null ? "响应为空" : result.getMsg())); } HcsRiskVO risk = result.getData(); @@ -204,7 +212,7 @@ public class HcsCreditCheckSupport { /** * 客商风险查询(C101-1,展示与提交校验共用,前端接入设计 §3.3): - * 内部组织类型客商默认无风险(不调 C101-1);外部客商按编号查询风险等级与黑名单状态并留痕; + * 内部组织类型客商默认无风险(不调 C101-1);外部客商按信用代码查询风险等级与黑名单状态并留痕; * 金蝶黑名单(A801-5)命中同样判定为风险客商(risky=true,C101-1 空数据不漏提示); * riskTip 经 {@link #buildRiskDetail} 统一组装(等级 + 金蝶黑名单失信类别/列入事由),与列表悬浮明细同口径 * @@ -247,12 +255,13 @@ public class HcsCreditCheckSupport { riskVO.setRisky(Boolean.FALSE); return riskVO; } - RelativeRiskResult fetch = this.fetchRelativeRisk(customerCode, customerName); + // 档案存在以档案信用代码为准;档案缺失(新增客商实时校验)兜底用前端传入信用代码 + String archiveCreditCode = customerArchive == null ? null : customerArchive.getUnifiedCreditCode(); + String effectiveCreditCode = StringUtil.isNotBlank(archiveCreditCode) ? archiveCreditCode : creditCode; + RelativeRiskResult fetch = this.fetchRelativeRisk(customerCode, effectiveCreditCode, customerName); CustomerRiskVO riskVO = fetch.risk(); // 表单实时提示与列表明细统一组装口径:追加金蝶黑名单段(A801-5 按信用代码查询,失败静默缺失; // 档案缺失(新增客商实时校验)时兜底用入参信用代码) - String archiveCreditCode = customerArchive == null ? null : customerArchive.getUnifiedCreditCode(); - String effectiveCreditCode = StringUtil.isNotBlank(archiveCreditCode) ? archiveCreditCode : creditCode; BfiBlacklistVO hit = StringUtil.isBlank(effectiveCreditCode) ? null : this.queryBlacklistByCodes(List.of(effectiveCreditCode.trim().toUpperCase())).get(effectiveCreditCode.trim().toUpperCase()); String blackCategory = hit == null ? null @@ -275,20 +284,31 @@ public class HcsCreditCheckSupport { /** * C101-1 单客商远程查询并组装展示信息(不查档案、不写留痕,供单查与定时批量刷新复用); - * riskTip 不在本方法组装,由调用方经 {@link #buildRiskDetail} 统一组装 + * riskTip 不在本方法组装,由调用方经 {@link #buildRiskDetail} 统一组装; + * C101-1 改按统一社会信用代码查询,信用代码为空时不调远程、按无风险数据返回 * - * @param customerCode 客商编号 + * @param customerCode 客商编号(留痕与展示用) + * @param creditCode 统一社会信用代码(C101-1 查询键) * @param customerName 客商名称(展示信息用) * @return 风险展示信息 + 合规 traceId */ - private RelativeRiskResult fetchRelativeRisk(String customerCode, String customerName) { + private RelativeRiskResult fetchRelativeRisk(String customerCode, String creditCode, String customerName) { + if (StringUtil.isBlank(creditCode)) { + log.warn("HCS客商风险查询跳过:customerCode={}, 信用代码为空", customerCode); + CustomerRiskVO emptyRisk = new CustomerRiskVO(); + emptyRisk.setCustomerCode(customerCode); + emptyRisk.setCustomerName(customerName); + emptyRisk.setCustomerKind("external"); + emptyRisk.setRisky(Boolean.FALSE); + return new RelativeRiskResult(emptyRisk, null); + } HcsRiskQueryDTO param = new HcsRiskQueryDTO(); - // 【必填】客商编号(用哪个编码待联调,§9-U6) - param.setFdNumber(customerCode); + // 【必填】统一社会信用代码(C101-1 改按信用代码查询,字段名 fdNumber 保持合规侧定义) + param.setFdNumber(creditCode); HcsResult result = hcsClient.getRelativeRisk(param); if (result == null || !result.isSuccess()) { log.error("HCS客商风险查询失败响应:{},fdNumber={}", - result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), customerCode); + result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), creditCode); throw new HcsException("C101-1 客商风险查询失败:" + (result == null ? "响应为空" : result.getMsg())); } HcsRiskVO risk = result.getData(); @@ -441,7 +461,7 @@ public class HcsCreditCheckSupport { /** * 客商风险批量查询(C101-1,客商列表页展示用,前端接入设计 §3.3): * 逐个复用 {@link #queryCustomerRisk}(内部客商默认无风险,外部客商查 C101-1,与付款页面展示口径一致); - * C101-1 仅支持单编号查询,逐个串行调用;展示场景单个失败跳过不阻断整页(强制校验仍在合同/付款链路) + * C101-1 仅支持单信用代码查询,逐个串行调用;展示场景单个失败跳过不阻断整页(强制校验仍在合同/付款链路) * * @param customerCodes 客商编号集合 * @return 风险展示信息列表(查询失败的客商不在结果中) @@ -465,7 +485,7 @@ public class HcsCreditCheckSupport { * 客商风险每日定时刷新(C101-1,客商档案列表展示与筛选数据源): * ① 取合同期限内(正式/临时期限任一覆盖当天)审核通过且未终止合同的甲乙方名称; * ② 按名称反查客商档案,内部组织客商默认无风险跳过; - * ③ 逐个查询 C101-1(接口仅支持单编号,属远程调用非数据库 N+1;复用 {@link #fetchRelativeRisk},不重复查档案), + * ③ 逐个查询 C101-1(接口仅支持单信用代码,属远程调用非数据库 N+1;复用 {@link #fetchRelativeRisk},不重复查档案), * 单个失败记 error 日志不中断(失败原因备查); * ④ 外部客商按 200/批切分,每批黑名单(A801-5)一次批量查询 + C101-1 逐个远程查询,失信类别/列入事由落原始字段 * (明细文案由列表查询统一组装); @@ -501,7 +521,7 @@ public class HcsCreditCheckSupport { int internalCount = archiveList.size() - externalArchives.size(); int refreshCount = 0; int failCount = 0; - // 外部客商按 200/批处理:每批黑名单一次批量查询 + C101-1 逐个远程查询(接口仅支持单编号,非数据库 N+1), + // 外部客商按 200/批处理:每批黑名单一次批量查询 + C101-1 逐个远程查询(接口仅支持单信用代码,非数据库 N+1), // 批内成功结果立即批量落库与留痕,风险/黑名单批次互不影响,单批失败不中断其余批次 for (int start = 0; start < externalArchives.size(); start += HcsSyncConstant.CUSTOMER_RISK_REFRESH_BATCH) { List batch = externalArchives.subList(start, Math.min(start + HcsSyncConstant.CUSTOMER_RISK_REFRESH_BATCH, externalArchives.size())); @@ -515,7 +535,14 @@ public class HcsCreditCheckSupport { List batchCheckLogs = new ArrayList<>(); for (CustomerArchive customerArchive : batch) { try { - RelativeRiskResult fetch = this.fetchRelativeRisk(customerArchive.getCustomerCode(), customerArchive.getFullName()); + // C101-1 改按信用代码查询:信用代码为空的档案跳过刷新(不计入失败数) + if (Func.isEmpty(customerArchive.getUnifiedCreditCode())) { + log.warn("定时刷新客商风险跳过:customerCode={}, fullName={}, 信用代码为空", + customerArchive.getCustomerCode(), customerArchive.getFullName()); + continue; + } + RelativeRiskResult fetch = this.fetchRelativeRisk(customerArchive.getCustomerCode(), + customerArchive.getUnifiedCreditCode(), customerArchive.getFullName()); CustomerRiskVO risk = fetch.risk(); // 仅提交风险列,避免整行回写覆盖刷新期间其它并发修改(审批状态/额度/金蝶推送等) CustomerArchive riskPatch = new CustomerArchive(); diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsRiskQueryDTO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsRiskQueryDTO.java index d5ed92c2..6a95d4f5 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsRiskQueryDTO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsRiskQueryDTO.java @@ -44,7 +44,7 @@ public class HcsRiskQueryDTO implements Serializable { @Serial private static final long serialVersionUID = 1L; /** - * 客商编号(必填;用客商哪个编码待联调确认,§9-U6) + * 统一社会信用代码(必填;C101-1 改按信用代码查询,字段名 fdNumber 保持合规侧定义) */ private String fdNumber; } diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/feign/IHcsClient.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/feign/IHcsClient.java index c21952e4..0f55fdda 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/feign/IHcsClient.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/feign/IHcsClient.java @@ -139,7 +139,7 @@ public interface IHcsClient { HcsResult> projectList(@RequestBody HcsPageQueryDTO param); /** - * C101-1 客商获取相对方风险等级 + * C101-1 客商获取相对方风险等级(入参 fdNumber 传统一社会信用代码) * * @param param 请求参数 * @return 相对方风险信息