:feat: 新增合同与付款特批结果回传接收端点,替代未建设的B103回调
This commit is contained in:
+1
-86
@@ -29,7 +29,7 @@ package org.springblade.transport.constant;
|
||||
* HCS(合同合规系统)列表查询 / 回调字段名常量(TMS 业务侧)
|
||||
* <p>
|
||||
* 与 {@link HcsContractFieldConstant}(C103-1/C103-11 表单字段)区分;
|
||||
* 项目立项查询用下划线字段名,合同/开票查询与 B103 回调用驼峰字段名,以实际接口为准。
|
||||
* 项目立项查询用下划线字段名,合同/开票查询用驼峰字段名,以实际接口为准。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@@ -111,91 +111,6 @@ public final class HcsFieldConstant {
|
||||
*/
|
||||
public static final String INVOICE_FD_STATUS = "fdStatus";
|
||||
|
||||
// ==================== B103 特批结果回调候选字段(报文未定稿,多候选解析,§6-U1) ====================
|
||||
|
||||
/**
|
||||
* 合同编号(驼峰)
|
||||
*/
|
||||
public static final String SPEC_CB_FD_CONTRACT_NO = "fdContractNo";
|
||||
|
||||
/**
|
||||
* 合同编号
|
||||
*/
|
||||
public static final String SPEC_CB_CONTRACT_NO = "contractNo";
|
||||
|
||||
/**
|
||||
* 合同编号(下划线)
|
||||
*/
|
||||
public static final String SPEC_CB_FD_CONTRACT_NO_SNAKE = "fd_contract_no";
|
||||
|
||||
/**
|
||||
* 合同编号(fd 模板字段,照 C103-3 查询惯例)
|
||||
*/
|
||||
public static final String SPEC_CB_FD_NUMBER = "fdNumber";
|
||||
|
||||
/**
|
||||
* 单据ID(驼峰)
|
||||
*/
|
||||
public static final String SPEC_CB_FD_ID = "fdId";
|
||||
|
||||
/**
|
||||
* 特批流程ID(驼峰)
|
||||
*/
|
||||
public static final String SPEC_CB_FD_SPEC_ID = "fdSpecId";
|
||||
|
||||
/**
|
||||
* 特批流程ID(下划线)
|
||||
*/
|
||||
public static final String SPEC_CB_FD_SPEC_ID_SNAKE = "fd_spec_id";
|
||||
|
||||
/**
|
||||
* 特批流程ID(specFdId)
|
||||
*/
|
||||
public static final String SPEC_CB_SPEC_FD_ID = "specFdId";
|
||||
|
||||
/**
|
||||
* 审批结果
|
||||
*/
|
||||
public static final String SPEC_CB_RESULT = "result";
|
||||
|
||||
/**
|
||||
* 审批结果(驼峰)
|
||||
*/
|
||||
public static final String SPEC_CB_FD_RESULT = "fdResult";
|
||||
|
||||
/**
|
||||
* 审批结果(下划线)
|
||||
*/
|
||||
public static final String SPEC_CB_FD_RESULT_SNAKE = "fd_result";
|
||||
|
||||
/**
|
||||
* 审批结果(approvalResult)
|
||||
*/
|
||||
public static final String SPEC_CB_APPROVAL_RESULT = "approvalResult";
|
||||
|
||||
/**
|
||||
* 状态(兜底候选)
|
||||
*/
|
||||
public static final String SPEC_CB_STATUS = "status";
|
||||
|
||||
/**
|
||||
* 合同编号候选键(依次取首个非空)
|
||||
*/
|
||||
public static final String[] SPEC_CB_CONTRACT_NO_KEYS = {SPEC_CB_FD_CONTRACT_NO, SPEC_CB_CONTRACT_NO,
|
||||
SPEC_CB_FD_CONTRACT_NO_SNAKE, SPEC_CB_FD_NUMBER};
|
||||
|
||||
/**
|
||||
* 特批流程ID候选键(依次取首个非空)
|
||||
*/
|
||||
public static final String[] SPEC_CB_SPEC_FD_ID_KEYS = {SPEC_CB_FD_ID, SPEC_CB_FD_SPEC_ID,
|
||||
SPEC_CB_FD_SPEC_ID_SNAKE, SPEC_CB_SPEC_FD_ID};
|
||||
|
||||
/**
|
||||
* 审批结果候选键(依次取首个非空)
|
||||
*/
|
||||
public static final String[] SPEC_CB_RESULT_KEYS = {SPEC_CB_RESULT, SPEC_CB_FD_RESULT,
|
||||
SPEC_CB_FD_RESULT_SNAKE, SPEC_CB_APPROVAL_RESULT, SPEC_CB_STATUS};
|
||||
|
||||
private HcsFieldConstant() {
|
||||
}
|
||||
}
|
||||
|
||||
+11
-1
@@ -85,7 +85,7 @@ public final class HcsSyncConstant {
|
||||
public static final String CHECK_TYPE_CREDIT = "credit";
|
||||
|
||||
/**
|
||||
* 校验类型:合同特批(C103-8 发起 / B103 结果回传留痕)
|
||||
* 校验类型:合同特批(C103-8 发起 / 合规特批结果推送留痕)
|
||||
*/
|
||||
public static final String CHECK_TYPE_SPEC = "spec";
|
||||
|
||||
@@ -148,6 +148,16 @@ public final class HcsSyncConstant {
|
||||
*/
|
||||
public static final String SPEC_STATUS_REJECTED = "rejected";
|
||||
|
||||
/**
|
||||
* 合规侧特批结果回传状态:通过(contractLegal/paymentLegal result 接口 status,D15 回传机制)
|
||||
*/
|
||||
public static final String LEGAL_RESULT_APPROVED = "APPROVED";
|
||||
|
||||
/**
|
||||
* 合规侧特批结果回传状态:驳回
|
||||
*/
|
||||
public static final String LEGAL_RESULT_REJECTED = "REJECTED";
|
||||
|
||||
// ==================== 客商风险(C101-1,外部客商高风险/黑名单管控) ====================
|
||||
|
||||
/**
|
||||
|
||||
+24
-8
@@ -40,6 +40,7 @@ import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.hcs.dto.HcsAttachmentRefDTO;
|
||||
import org.springblade.hcs.dto.HcsCurrencyVO;
|
||||
import org.springblade.hcs.dto.HcsLegalResultDTO;
|
||||
import org.springblade.hcs.dto.HcsTemplateVO;
|
||||
import org.springblade.transport.constant.HcsSyncConstant;
|
||||
import org.springblade.transport.pojo.vo.CustomerRiskVO;
|
||||
@@ -246,7 +247,7 @@ public class HcsSyncController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 合同特批结果人工确认(§6-U1 过渡方案:B103 报文未到位前与回调等效)
|
||||
* 合同特批结果人工确认(§6-U1 过渡方案:与合规推送等效)
|
||||
*/
|
||||
@PostMapping("/contract/spec/confirm")
|
||||
@ApiOperationSupport(order = 14)
|
||||
@@ -257,16 +258,31 @@ public class HcsSyncController {
|
||||
}
|
||||
|
||||
/**
|
||||
* B103 特批结果回传接收(合规系统→TMS 回调,公开端点 + 原文留痕,前端接入设计 §3.4)
|
||||
* 合同特批结果回传接收(合规系统 contractLegal/result 推送,替代未建设的 B103,公开端点 + 原文留痕)
|
||||
* <p>
|
||||
* TODO 待联调(§6-U1):B103 报文未定,当前按候选字段(contractNo/fdId/result 等)解析,
|
||||
* 解析失败仅留痕不置状态,报文口径确认后完善解析。
|
||||
* iPaaS 网关注册映射:/gwzh/HTHG/contractLegal/result → /hcs/contractLegal/result;
|
||||
* 报文 {sourceSystem, requestId=TMS合同ID, status=APPROVED/REJECTED, reason},
|
||||
* approved 恢复流程展示,rejected 联动合同审批驳回。
|
||||
*/
|
||||
@PostMapping("/callback/spec-result")
|
||||
@PostMapping("/contractLegal/result")
|
||||
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||
@ApiOperationSupport(order = 15)
|
||||
@Operation(summary = "B103特批结果回传", description = "合规系统回调:合同特批结果回传接收,原文留痕并回写合同特批状态")
|
||||
public R<String> specResultCallback(@RequestBody(required = false) Map<String, Object> body) {
|
||||
return R.data(hcsContractSpecSyncSupport.handleSpecCallback(body));
|
||||
@Operation(summary = "合同特批结果回传接收", description = "合规系统推送合同特批结果,按合同ID定位并联动特批状态,原文留痕")
|
||||
public R<String> contractLegalResult(@RequestBody(required = false) HcsLegalResultDTO param) {
|
||||
return R.data(hcsContractSpecSyncSupport.handleLegalResult(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 付款特批结果回传接收(合规系统 paymentLegal/result 推送,公开端点)
|
||||
* <p>
|
||||
* iPaaS 网关注册映射:/gwzh/HTHG/paymentLegal/result → /hcs/paymentLegal/result;
|
||||
* 报文同合同接口(requestId=TMS付款申请ID),付款特批结果不联动付款审批状态(§4.4)。
|
||||
*/
|
||||
@PostMapping("/paymentLegal/result")
|
||||
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||
@ApiOperationSupport(order = 16)
|
||||
@Operation(summary = "付款特批结果回传接收", description = "合规系统推送付款特批结果,按付款申请ID定位并回写特批状态")
|
||||
public R<String> paymentLegalResult(@RequestBody(required = false) HcsLegalResultDTO param) {
|
||||
return R.data(hcsPaymentSyncSupport.handleLegalResult(param));
|
||||
}
|
||||
}
|
||||
|
||||
+42
-80
@@ -26,19 +26,18 @@
|
||||
package org.springblade.transport.support.hcs;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.hcs.dto.HcsAttachmentRefDTO;
|
||||
import org.springblade.hcs.dto.HcsLegalResultDTO;
|
||||
import org.springblade.hcs.dto.HcsMechanismsDTO;
|
||||
import org.springblade.hcs.dto.HcsResult;
|
||||
import org.springblade.hcs.dto.HcsSpecContractSaveDTO;
|
||||
import org.springblade.hcs.dto.HcsFormSaveVO;
|
||||
import org.springblade.hcs.exception.HcsException;
|
||||
import org.springblade.hcs.feign.IHcsClient;
|
||||
import org.springblade.transport.constant.HcsFieldConstant;
|
||||
import org.springblade.transport.constant.HcsSyncConstant;
|
||||
import org.springblade.transport.mapper.ContractManageMapper;
|
||||
import org.springblade.transport.mapper.HcsContractCheckLogMapper;
|
||||
@@ -48,17 +47,17 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* HCS 合同特批同步支撑组件(C103-8 发起特批 / B103 特批结果回传,前端接入设计 §3.4)
|
||||
* HCS 合同特批同步支撑组件(C103-8 发起特批 / 合规特批结果推送接收,前端接入设计 §3.4)
|
||||
* <p>
|
||||
* 业务闭环:合同推送时 C101-1 风险校验发现黑名单 → 置 hcs_spec_status=need 挂起(推送链路门禁跳过)→
|
||||
* 内部特批审批通过后,前端上传特批材料(C103-2 取合规附件ID)并发起 C103-8 → 状态 processing(流程挂起)→
|
||||
* 集团审批结果经 B103 回传 TMS → approved 后既有扫描任务自动恢复 C103-1 推送,rejected 可重新发起。
|
||||
* 集团审批结果经合规 contractLegal/result 接口推送 TMS(替代未建设的 B103)→
|
||||
* approved 恢复流程,rejected 可重新发起。
|
||||
* <p>
|
||||
* TODO 待联调确认(前端接入设计 §6-U1):C103-8 与 B103 报文 v4 均未提供,
|
||||
* C103-8 按 C106-3 模式预估(双层嵌套返回),B103 回调按候选字段解析、原文留痕 blade_hcs_check_log。
|
||||
* TODO 待联调确认(前端接入设计 §6-U1):C103-8 报文 v4 未提供,按 C106-3 模式预估(双层嵌套返回);
|
||||
* 结果推送报文 {sourceSystem, requestId=合同ID, status=APPROVED/REJECTED, reason},原文留痕 blade_hcs_check_log。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@@ -73,7 +72,7 @@ public class HcsContractSpecSyncSupport {
|
||||
private static final String SPEC_ATTACH_ENTITY_KEY = "fd_spc_approval_attach";
|
||||
|
||||
/**
|
||||
* B103 原文留痕最大长度(blade_hcs_check_log.msg 为 varchar(512))
|
||||
* 结果推送原文留痕最大长度(blade_hcs_check_log.msg 为 varchar(512))
|
||||
*/
|
||||
private static final int CALLBACK_MSG_MAX_LENGTH = 500;
|
||||
|
||||
@@ -130,7 +129,7 @@ public class HcsContractSpecSyncSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 特批结果人工确认(§6-U1 过渡方案:B103 报文未到位前,页面确认与回调等效)
|
||||
* 特批结果人工确认(§6-U1 过渡方案:页面确认与合规推送等效)
|
||||
*
|
||||
* @param id 合同ID
|
||||
* @param result approved/rejected
|
||||
@@ -157,36 +156,40 @@ public class HcsContractSpecSyncSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* B103 特批结果回传处理(回调端点入口):候选字段解析 + 原文留痕,
|
||||
* approved 恢复合同"审批通过"展示(C103-1 已起草完成,无需恢复推送);rejected 联动合同审批驳回
|
||||
* 合同特批结果接收处理(合规 contractLegal/result 推送,替代未建设的 B103,D15 回传机制):
|
||||
* requestId=TMS 合同ID、status=APPROVED/REJECTED,
|
||||
* approved 恢复合同"审批通过"展示;rejected 联动合同审批驳回;原文全量留痕
|
||||
*
|
||||
* @param body B103 回调报文(结构待联调,原文全量留痕)
|
||||
* @param param 合规推送报文
|
||||
* @return 处理结果描述
|
||||
*/
|
||||
public String handleSpecCallback(Map<String, Object> body) {
|
||||
String raw = body == null ? "" : JSONUtil.toJsonStr(body);
|
||||
String contractNo = firstNonBlank(body, HcsFieldConstant.SPEC_CB_CONTRACT_NO_KEYS);
|
||||
String specFdId = firstNonBlank(body, HcsFieldConstant.SPEC_CB_SPEC_FD_ID_KEYS);
|
||||
String resultText = firstNonBlank(body, HcsFieldConstant.SPEC_CB_RESULT_KEYS);
|
||||
ContractManage contractManage = locateContract(contractNo, specFdId);
|
||||
public String handleLegalResult(HcsLegalResultDTO param) {
|
||||
String raw = param == null ? "" : JSONUtil.toJsonStr(param);
|
||||
String requestId = param == null ? null : param.getRequestId();
|
||||
ContractManage contractManage = locateContract(requestId);
|
||||
if (contractManage == null) {
|
||||
log.warn("B103特批结果回传未定位到合同:contractNo={},specFdId={},报文已留痕", contractNo, specFdId);
|
||||
writeCallbackLog(null, HcsSyncConstant.CHECK_RESULT_SKIP, "B103 回传未定位到合同:" + raw);
|
||||
return "已留痕:未定位到合同(contractNo=" + contractNo + ")";
|
||||
log.warn("合同特批结果推送未定位到合同:requestId={},报文已留痕", requestId);
|
||||
writeCallbackLog(null, HcsSyncConstant.CHECK_RESULT_SKIP, "合同特批结果推送未定位到合同:" + raw);
|
||||
return "已留痕:未定位到合同(requestId=" + requestId + ")";
|
||||
}
|
||||
Boolean approved = parseSpecResult(resultText);
|
||||
if (approved == null) {
|
||||
log.warn("B103特批结果字段未识别:contractNo={},resultText={},报文已留痕", contractManage.getContractNo(), resultText);
|
||||
writeCallbackLog(contractManage, HcsSyncConstant.CHECK_RESULT_SKIP, "B103 回传结果字段未识别:" + raw);
|
||||
return "已留痕:结果字段未识别(contractNo=" + contractManage.getContractNo() + ")";
|
||||
String normalizedStatus = param.getStatus() == null ? "" : param.getStatus().trim();
|
||||
boolean approved;
|
||||
if (HcsSyncConstant.LEGAL_RESULT_APPROVED.equalsIgnoreCase(normalizedStatus)) {
|
||||
approved = true;
|
||||
} else if (HcsSyncConstant.LEGAL_RESULT_REJECTED.equalsIgnoreCase(normalizedStatus)) {
|
||||
approved = false;
|
||||
} else {
|
||||
log.warn("合同特批结果状态未识别:contractNo={},status={},报文已留痕", contractManage.getContractNo(), param.getStatus());
|
||||
writeCallbackLog(contractManage, HcsSyncConstant.CHECK_RESULT_SKIP, "合同特批结果推送状态未识别:" + raw);
|
||||
return "已留痕:状态字段未识别(contractNo=" + contractManage.getContractNo() + ")";
|
||||
}
|
||||
String status = approved ? HcsSyncConstant.SPEC_STATUS_APPROVED : HcsSyncConstant.SPEC_STATUS_REJECTED;
|
||||
// 特批结果联动合同审批状态(通过恢复展示,驳回联动审批驳回),随 markSpec 一并落库
|
||||
// 特批结果联动合同审批状态(通过恢复展示,驳回联动审批驳回),随 markSpec 一并落库(reason 随原文留痕)
|
||||
syncContractOnSpecResult(contractManage, approved);
|
||||
markSpec(contractManage, status, "B103 特批结果回传:" + raw);
|
||||
markSpec(contractManage, status, "合同特批结果推送:" + raw);
|
||||
writeCallbackLog(contractManage, approved ? HcsSyncConstant.CHECK_RESULT_PASS : HcsSyncConstant.CHECK_RESULT_FAIL,
|
||||
"B103 特批结果回传:" + raw);
|
||||
log.info("B103特批结果回传处理完成:contractNo={},结果={}", contractManage.getContractNo(), status);
|
||||
"合同特批结果推送:" + raw);
|
||||
log.info("合同特批结果推送处理完成:contractNo={},结果={},reason={}", contractManage.getContractNo(), status, param.getReason());
|
||||
return "特批结果已处理:" + status;
|
||||
}
|
||||
|
||||
@@ -250,62 +253,21 @@ public class HcsContractSpecSyncSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 按合同编号/特批流程ID 定位合同(B103 报文候选键)
|
||||
* 按 TMS 合同ID 定位合同(合规推送 requestId)
|
||||
*/
|
||||
private ContractManage locateContract(String contractNo, String specFdId) {
|
||||
if (StringUtil.isNotBlank(contractNo)) {
|
||||
ContractManage contractManage = contractManageMapper.selectOne(Wrappers.<ContractManage>lambdaQuery()
|
||||
.eq(ContractManage::getContractNo, contractNo)
|
||||
.eq(ContractManage::getIsDeleted, 0)
|
||||
.last("limit 1"));
|
||||
if (contractManage != null) {
|
||||
return contractManage;
|
||||
}
|
||||
}
|
||||
if (StringUtil.isNotBlank(specFdId)) {
|
||||
return contractManageMapper.selectOne(Wrappers.<ContractManage>lambdaQuery()
|
||||
.eq(ContractManage::getHcsSpecFdId, specFdId)
|
||||
.eq(ContractManage::getIsDeleted, 0)
|
||||
.last("limit 1"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析特批结果文本:approved/通过/pass/true → true;rejected/驳回/refuse/false → false;未识别 → null
|
||||
*/
|
||||
private Boolean parseSpecResult(String resultText) {
|
||||
if (StringUtil.isBlank(resultText)) {
|
||||
private ContractManage locateContract(String requestId) {
|
||||
if (StringUtil.isBlank(requestId)) {
|
||||
return null;
|
||||
}
|
||||
String text = resultText.trim().toLowerCase();
|
||||
if (List.of("approved", "pass", "true", "通过", "审批通过", "同意").contains(text)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
if (List.of("rejected", "refuse", "refused", "false", "驳回", "不通过", "不同意").contains(text)) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从候选字段名依次取首个非空字符串值
|
||||
*/
|
||||
private String firstNonBlank(Map<String, Object> body, String... keys) {
|
||||
if (body == null) {
|
||||
try {
|
||||
return contractManageMapper.selectById(Long.valueOf(requestId.trim()));
|
||||
} catch (NumberFormatException exception) {
|
||||
return null;
|
||||
}
|
||||
for (String key : keys) {
|
||||
Object value = body.get(key);
|
||||
if (value != null && StringUtil.isNotBlank(String.valueOf(value))) {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 特批结果联动合同审批状态(confirmSpecResult 与 handleSpecCallback 共用,仅改字段,随 markSpec 落库):
|
||||
* 特批结果联动合同审批状态(handleLegalResult 与 confirmSpecResult 共用,仅改字段,随 markSpec 落库):
|
||||
* approved 恢复"审批通过"展示(C103-1 已起草完成,hcs_sync_status 保持 synced,无需再推送);
|
||||
* rejected 联动合同审批驳回(approvalStatus=rejected),走重新编辑→提交→审批→特批闭环
|
||||
*/
|
||||
@@ -350,7 +312,7 @@ public class HcsContractSpecSyncSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* B103 回传留痕(合同未定位到时 bizId 为空,原文留痕便于联调解析)
|
||||
* 结果推送留痕(合同未定位到时 bizId 为空,原文留痕便于联调解析)
|
||||
*/
|
||||
private void writeCallbackLog(ContractManage contractManage, String result, String msg) {
|
||||
if (contractManage == null) {
|
||||
@@ -363,7 +325,7 @@ public class HcsContractSpecSyncSupport {
|
||||
checkLog.setCreateTime(LocalDateTime.now());
|
||||
hcsContractCheckLogMapper.insert(checkLog);
|
||||
} catch (Exception exception) {
|
||||
log.error("B103回传留痕写入失败", exception);
|
||||
log.error("合同特批结果推送留痕写入失败", exception);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
+3
-3
@@ -74,7 +74,7 @@ import java.util.Objects;
|
||||
* 扫描任务按序执行:⓪ 特批挂起门禁 → ① 客商风险校验(可配开关,仅留痕,高风险不再阻断)→
|
||||
* ② 附件转传(v4 挂载点 fdFieldJson.attachment,随 C103-1 挂载)→ ③ C103-3 判重(§9-U4 查询能力联调确认)→
|
||||
* ④ C103-1 起草 / 变更单 C103-11 更新(§9-U5 定位方式待联调)→ ⑤ 高风险/黑名单自动特批 C103-8(外部客商管控,
|
||||
* {@link HcsContractSpecSyncSupport},挂起"特批审核"待 B103 回传)→ ⑥ 履约规则 C103-9 行级同步({@link HcsExeStageSyncSupport})。
|
||||
* {@link HcsContractSpecSyncSupport},挂起"特批审核"待合规推送结果)→ ⑥ 履约规则 C103-9 行级同步({@link HcsExeStageSyncSupport})。
|
||||
* 结果留痕:风险校验写 blade_hcs_check_log 与合同 hcs_risk_* 字段;推送结果回填 hcs_fd_id/hcs_sync_status。
|
||||
*
|
||||
* @author Chill
|
||||
@@ -114,7 +114,7 @@ public class HcsContractSyncSupport {
|
||||
log.info("HCS合同推送开始:contractNo={},approvalStatus={},首推={},hcsSpecStatus={}",
|
||||
contractManage.getContractNo(), contractManage.getApprovalStatus(),
|
||||
StringUtil.isBlank(contractManage.getHcsFdId()), contractManage.getHcsSpecStatus());
|
||||
// ⓪ 特批挂起门禁:待特批/特批中的合同跳过推送,等待 B103 特批结果回传后恢复(C103-8,前端接入设计 §3.4)
|
||||
// ⓪ 特批挂起门禁:待特批/特批中的合同跳过推送,等待合规推送特批结果后恢复(C103-8,前端接入设计 §3.4)
|
||||
if (List.of(HcsSyncConstant.SPEC_STATUS_NEED, HcsSyncConstant.SPEC_STATUS_PROCESSING).contains(contractManage.getHcsSpecStatus())) {
|
||||
log.info("HCS合同推送跳过(特批挂起中):contractNo={},hcsSpecStatus={}", contractManage.getContractNo(), contractManage.getHcsSpecStatus());
|
||||
return "合同特批挂起中(" + contractManage.getHcsSpecStatus() + "),跳过推送";
|
||||
@@ -184,7 +184,7 @@ public class HcsContractSyncSupport {
|
||||
|
||||
/**
|
||||
* 高风险/黑名单客商合同自动特批(C103-8,外部客商管控):C103-1 起草成功后置待特批并自动发起,
|
||||
* TMS 流程挂起展示"特批审核"(currentNode),B103 特批结果回传后恢复或驳回;
|
||||
* TMS 流程挂起展示"特批审核"(currentNode),合规推送特批结果(contractLegal/result)后恢复或驳回;
|
||||
* 特批已通过(单次有效)的合同不重复发起;发起失败保持待特批仅留痕,可人工重发或重新推送兜底
|
||||
*/
|
||||
private void autoApplySpecIfNeeded(ContractManage contractManage) {
|
||||
|
||||
+47
-1
@@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.hcs.config.HcsProperties;
|
||||
import org.springblade.hcs.dto.HcsLegalResultDTO;
|
||||
import org.springblade.transport.constant.HcsSyncConstant;
|
||||
import org.springblade.transport.mapper.PaymentApplicationMapper;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||
@@ -39,7 +40,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* HCS 付款链推送编排支撑组件(结算付款特批 C106-3/4 + 履约记录 C108-1/2,设计文档 §5.0/§5.5/§5.6)
|
||||
* HCS 付款链推送编排支撑组件(结算付款特批 C106-3/4 + 履约记录 C108-1/2 + 特批结果推送接收,设计文档 §5.0/§5.5/§5.6)
|
||||
* <p>
|
||||
* 编排顺序:特批(额度超额标记 need 时发起)→ 履约记录(审批通过新建 / 实际付款推进更新)。
|
||||
* 特批流程ID 与履约记录ID 在各自 Support 内即时持久化;整体同步状态(hcs_sync_status)由本组件统一回写。
|
||||
@@ -136,6 +137,51 @@ public class HcsPaymentSyncSupport {
|
||||
return "特批结果已确认:" + result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 付款特批结果接收处理(合规 paymentLegal/result 推送,替代未建设的 B103,D15 回传机制):
|
||||
* requestId=TMS 付款申请ID、status=APPROVED/REJECTED;
|
||||
* 付款特批结果不联动付款审批状态(§4.4),仅回写 hcs_spec_status
|
||||
*
|
||||
* @param param 合规推送报文
|
||||
* @return 处理结果描述
|
||||
*/
|
||||
public String handleLegalResult(HcsLegalResultDTO param) {
|
||||
String requestId = param == null ? null : param.getRequestId();
|
||||
PaymentApplication payment = locatePayment(requestId);
|
||||
if (payment == null) {
|
||||
log.warn("付款特批结果推送未定位到付款申请:requestId={},reason={}", requestId, param == null ? null : param.getReason());
|
||||
return "未定位到付款申请(requestId=" + requestId + ")";
|
||||
}
|
||||
String normalizedStatus = param.getStatus() == null ? "" : param.getStatus().trim();
|
||||
String status;
|
||||
if (HcsSyncConstant.LEGAL_RESULT_APPROVED.equalsIgnoreCase(normalizedStatus)) {
|
||||
status = HcsSyncConstant.SPEC_STATUS_APPROVED;
|
||||
} else if (HcsSyncConstant.LEGAL_RESULT_REJECTED.equalsIgnoreCase(normalizedStatus)) {
|
||||
status = HcsSyncConstant.SPEC_STATUS_REJECTED;
|
||||
} else {
|
||||
log.warn("付款特批结果状态未识别:paymentNo={},status={},reason={}", payment.getPaymentNo(), param.getStatus(), param.getReason());
|
||||
return "状态字段未识别(paymentNo=" + payment.getPaymentNo() + ")";
|
||||
}
|
||||
payment.setHcsSpecStatus(status);
|
||||
paymentApplicationMapper.updateById(payment);
|
||||
log.info("付款特批结果推送处理完成:paymentNo={},结果={},reason={}", payment.getPaymentNo(), status, param.getReason());
|
||||
return "特批结果已处理:" + status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 TMS 付款申请ID 定位付款申请(合规推送 requestId)
|
||||
*/
|
||||
private PaymentApplication locatePayment(String requestId) {
|
||||
if (StringUtil.isBlank(requestId)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return paymentApplicationMapper.selectById(Long.valueOf(requestId.trim()));
|
||||
} catch (NumberFormatException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 回填整体同步状态置 synced
|
||||
*/
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.hcs.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 合同合规系统(HCS)特批结果回传报文
|
||||
* <p>
|
||||
* 合规系统审批完成后经 iPaaS 网关推送 TMS:合同走 /hcs/contractLegal/result,
|
||||
* 付款走 /hcs/paymentLegal/result,通过 status=APPROVED、驳回 status=REJECTED,报文两接口共用。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class HcsLegalResultDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 来源系统标识(约定 WLTMS,配置 thirdParty.hcs.src-system)
|
||||
*/
|
||||
private String sourceSystem;
|
||||
/**
|
||||
* 业务单据ID(合同特批=TMS 合同ID,付款特批=TMS 付款申请ID)
|
||||
*/
|
||||
private String requestId;
|
||||
/**
|
||||
* 审批结果:APPROVED 通过 / REJECTED 驳回
|
||||
*/
|
||||
private String status;
|
||||
/**
|
||||
* 结果说明(驳回原因等,非必传)
|
||||
*/
|
||||
private String reason;
|
||||
}
|
||||
Reference in New Issue
Block a user