:feat: 合同附件挂载按 eopCdraft 枚举分类(fdEntityKey)
- HcsSyncConstant 新增 CONTRACT_ATTACH_KEY_SPECIAL/SEAL/OTHER(eopCdraftSpecial/eopCdraftSign/eopCdraftOther) - 转传接口返回 HcsAttachmentRefDTO(fdId+fdEntityKey+fdFileName),替代纯 fdId 列表 - 合同链路:主文件 approved=true 挂 eopCdraftSign、其它附件挂 eopCdraftOther、特批说明挂 eopCdraftSpecial - buildDraftParam 直接消费引用列表统一补 fdBindType=ADD;特批付款/履约记录/收票单/开票登记四个挂载点改为在返回引用上补各自字段,行为不变
This commit is contained in:
+37
-10
@@ -180,6 +180,28 @@ public final class HcsSyncConstant {
|
||||
*/
|
||||
public static final String ATTACHMENT_TYPE_SPEC_EXPLANATION = "特批说明";
|
||||
|
||||
/**
|
||||
* 附件类型:用印附件(双章归档文件,取值沿用 ContractManageServiceImpl#FILE_TYPE_SEAL_ARCHIVE)
|
||||
*/
|
||||
public static final String ATTACHMENT_TYPE_SEAL = "双章归档文件";
|
||||
|
||||
// ==================== 合同附件挂载 fdEntityKey(eopCdraft 附件面板字段 key,C103-1) ====================
|
||||
|
||||
/**
|
||||
* 合同附件字段 key:特批附件
|
||||
*/
|
||||
public static final String CONTRACT_ATTACH_KEY_SPECIAL = "eopCdraftSpecial";
|
||||
|
||||
/**
|
||||
* 合同附件字段 key:用印附件
|
||||
*/
|
||||
public static final String CONTRACT_ATTACH_KEY_SEAL = "eopCdraftSign";
|
||||
|
||||
/**
|
||||
* 合同附件字段 key:其他附件(含合同主文件)
|
||||
*/
|
||||
public static final String CONTRACT_ATTACH_KEY_OTHER = "eopCdraftOther";
|
||||
|
||||
/**
|
||||
* 特批审核挂起节点展示名(currentNode,特批发起后挂起展示,结果回传后恢复)
|
||||
*/
|
||||
@@ -202,16 +224,6 @@ public final class HcsSyncConstant {
|
||||
*/
|
||||
public static final String MASTER_CACHE_CURRENCIES = "blade:third:hcs:master:currencies";
|
||||
|
||||
/**
|
||||
* 附件映射缓存 key 前缀(hcs:att:{attachmentKey},TMS 附件元数据键 → 合规附件ID)
|
||||
*/
|
||||
public static final String ATTACHMENT_CACHE_KEY_PREFIX = "blade:third:hcs:att:";
|
||||
|
||||
/**
|
||||
* 附件映射缓存 TTL(天),重复上传仅浪费存储无业务风险,故不做持久化映射表(设计文档 §6)
|
||||
*/
|
||||
public static final long ATTACHMENT_CACHE_TTL_DAYS = 7L;
|
||||
|
||||
/**
|
||||
* 推送任务分布式锁 key 前缀(多实例部署防重扫,完整 key = 前缀 + 业务类型,任务间互不阻塞)
|
||||
*/
|
||||
@@ -227,6 +239,21 @@ public final class HcsSyncConstant {
|
||||
*/
|
||||
public static final long PUSH_SINGLE_LOCK_TTL_SECONDS = 120L;
|
||||
|
||||
/**
|
||||
* hcs_sync_msg 字段安全截断长度(列宽 varchar(512),留余量防远程错误报文超长导致落库失败)
|
||||
*/
|
||||
public static final int SYNC_MSG_MAX_LENGTH = 500;
|
||||
|
||||
/**
|
||||
* 截断超长的推送结果/失败原因(如 Feign 异常携带的远程 404 响应体),防止 Data too long 落库失败
|
||||
*/
|
||||
public static String truncateMsg(String message) {
|
||||
if (message == null) {
|
||||
return null;
|
||||
}
|
||||
return message.length() > SYNC_MSG_MAX_LENGTH ? message.substring(0, SYNC_MSG_MAX_LENGTH) : message;
|
||||
}
|
||||
|
||||
private HcsSyncConstant() {
|
||||
}
|
||||
}
|
||||
|
||||
+71
-35
@@ -26,19 +26,21 @@
|
||||
package org.springblade.transport.support.hcs;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.redis.cache.BladeRedis;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.hcs.config.HcsProperties;
|
||||
import org.springblade.hcs.constant.HcsConstant;
|
||||
import org.springblade.hcs.dto.HcsAttachmentDownloadDTO;
|
||||
import org.springblade.hcs.dto.HcsAttachmentRefDTO;
|
||||
import org.springblade.hcs.dto.HcsAttachmentVO;
|
||||
import org.springblade.hcs.dto.HcsResult;
|
||||
import org.springblade.hcs.exception.HcsException;
|
||||
import org.springblade.hcs.feign.IHcsClient;
|
||||
import org.springblade.transport.constant.HcsSyncConstant;
|
||||
import org.springblade.transport.mapper.HcsAttachmentSyncMapper;
|
||||
import org.springblade.transport.pojo.entity.HcsAttachmentSync;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@@ -48,7 +50,7 @@ import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -59,12 +61,12 @@ import java.util.Objects;
|
||||
* <p>
|
||||
* 流程:解析单据附件 JSON 元素(去重键照 ContractManage#attachmentKey 惯例)→
|
||||
* 按元数据 URL 从文件服务拉取流(基址可配 attachment.file-download-base)→
|
||||
* C103-2 上传取得合规附件ID → Redis 映射缓存(blade:third:hcs:att:{attachmentKey},TTL 7 天),
|
||||
* 未命中重传(重复上传仅浪费存储,无业务风险,故不做持久化映射表)。
|
||||
* 任一附件转传失败 → 抛出异常由整单推送失败进补偿重试。
|
||||
* C103-2 上传取得合规附件ID → 落映射同步表(blade_hcs_attachment_sync,照金蝶附件同步表设计:
|
||||
* biz_type+biz_id+attachment_key 唯一,转传前查命中即复用,仅落成功记录)。
|
||||
* 任一附件转传失败 → 抛出异常由整单推送失败进补偿重试(失败原因落单据 hcs_sync_msg)。
|
||||
* <p>
|
||||
* TODO 待联调确认(§9-U8):v4 的 C103-1 入参未定义附件字段,合同附件向 HCS 的挂载方式待合规方确认,
|
||||
* 本组件先建设通用转传能力并将合规附件ID 缓存备用,确认后按其要求挂载。
|
||||
* 合同链路挂载字段 fdEntityKey(v4 枚举):主文件 approved=true → eopCdraftSign(用印)、
|
||||
* 其它附件 → eopCdraftOther、特批说明 → eopCdraftSpecial(C103-8 特批链路)。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@@ -80,48 +82,52 @@ public class HcsAttachmentSupport {
|
||||
|
||||
private final IHcsClient hcsClient;
|
||||
private final HcsProperties hcsProperties;
|
||||
private final BladeRedis bladeRedis;
|
||||
private final HcsAttachmentSyncMapper hcsAttachmentSyncMapper;
|
||||
|
||||
/**
|
||||
* 解析单据附件 JSON 并转传,返回合规附件ID 列表(保持行序)
|
||||
* 解析单据附件 JSON 并转传,返回合规附件引用列表(保持行序)
|
||||
*
|
||||
* @param bizType 业务单据类型(HcsSyncConstant.BIZ_TYPE_*)
|
||||
* @param bizId 业务单据id
|
||||
* @param attachmentsJson 附件元数据 JSON 数组
|
||||
* @param operatorLoginName 操作人登录名(C103-2 fdLoginName)
|
||||
* @return 合规附件ID 列表
|
||||
* @return 合规附件引用列表(fdId + fdEntityKey)
|
||||
*/
|
||||
public List<String> transferAttachments(String attachmentsJson, String operatorLoginName) {
|
||||
public List<HcsAttachmentRefDTO> transferAttachments(String bizType, Long bizId, String attachmentsJson, String operatorLoginName) {
|
||||
if (StringUtil.isBlank(attachmentsJson)) {
|
||||
return List.of();
|
||||
}
|
||||
List<Map<?, ?>> attachments = parseJsonArray(attachmentsJson);
|
||||
List<String> attachmentFdIds = new ArrayList<>();
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = new ArrayList<>();
|
||||
for (Map<?, ?> attachment : attachments) {
|
||||
attachmentFdIds.add(transferOne(attachment, operatorLoginName));
|
||||
attachmentRefs.add(this.transferOne(bizType, bizId, attachment, operatorLoginName));
|
||||
}
|
||||
return attachmentFdIds;
|
||||
return attachmentRefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析合同主文件 JSON(仅 approved=true 的文件)与其它附件 JSON 并转传
|
||||
* 解析合同主文件 JSON(仅 approved=true 的文件,挂用印字段)与其它附件 JSON(挂其他附件字段)并转传
|
||||
*
|
||||
* @param bizType 业务单据类型(HcsSyncConstant.BIZ_TYPE_*)
|
||||
* @param bizId 业务单据id
|
||||
* @param contractFileJson 合同主文件 JSON
|
||||
* @param attachmentsJson 其它附件 JSON
|
||||
* @param operatorLoginName 操作人登录名
|
||||
* @return 合规附件ID 列表
|
||||
* @return 合规附件引用列表(fdId + fdEntityKey)
|
||||
*/
|
||||
public List<String> transferContractAttachments(String contractFileJson, String attachmentsJson, String operatorLoginName) {
|
||||
List<Map<?, ?>> attachments = new ArrayList<>();
|
||||
public List<HcsAttachmentRefDTO> transferContractAttachments(String bizType, Long bizId, String contractFileJson, String attachmentsJson, String operatorLoginName) {
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = new ArrayList<>();
|
||||
for (Map<?, ?> file : parseJsonArray(contractFileJson)) {
|
||||
if (isApproved(file)) {
|
||||
attachments.add(file);
|
||||
attachmentRefs.add(this.transferOne(bizType, bizId, file, operatorLoginName,
|
||||
HcsSyncConstant.CONTRACT_ATTACH_KEY_SEAL));
|
||||
}
|
||||
}
|
||||
attachments.addAll(parseJsonArray(attachmentsJson));
|
||||
List<String> attachmentFdIds = new ArrayList<>();
|
||||
for (Map<?, ?> attachment : attachments) {
|
||||
attachmentFdIds.add(transferOne(attachment, operatorLoginName));
|
||||
for (Map<?, ?> attachment : parseJsonArray(attachmentsJson)) {
|
||||
attachmentRefs.add(this.transferOne(bizType, bizId, attachment, operatorLoginName,
|
||||
HcsSyncConstant.CONTRACT_ATTACH_KEY_OTHER));
|
||||
}
|
||||
return attachmentFdIds;
|
||||
return attachmentRefs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,14 +169,26 @@ public class HcsAttachmentSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 转传单个附件:映射缓存命中直接返回,未命中下载上传后写缓存
|
||||
* 转传单个附件:映射同步表命中直接复用合规附件ID,未命中下载上传后落成功记录;
|
||||
* 返回引用默认不带 fdEntityKey,由调用方(或合同主文件/其他附件重载)指定挂载字段
|
||||
*/
|
||||
private String transferOne(Map<?, ?> attachment, String operatorLoginName) {
|
||||
private HcsAttachmentRefDTO transferOne(String bizType, Long bizId, Map<?, ?> attachment, String operatorLoginName) {
|
||||
return this.transferOne(bizType, bizId, attachment, operatorLoginName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转传单个附件并指定挂载字段 key(fdEntityKey,如合同 eopCdraftSpecial/eopCdraftSign/eopCdraftOther)
|
||||
*/
|
||||
private HcsAttachmentRefDTO transferOne(String bizType, Long bizId, Map<?, ?> attachment, String operatorLoginName, String fdEntityKey) {
|
||||
String attachmentKey = attachmentKey(attachment);
|
||||
String cacheKey = HcsSyncConstant.ATTACHMENT_CACHE_KEY_PREFIX + attachmentKey;
|
||||
String cachedFdId = bladeRedis.get(cacheKey);
|
||||
if (StringUtil.isNotBlank(cachedFdId)) {
|
||||
return cachedFdId;
|
||||
HcsAttachmentSync existing = hcsAttachmentSyncMapper.selectOne(Wrappers.<HcsAttachmentSync>lambdaQuery()
|
||||
.eq(HcsAttachmentSync::getBizType, bizType)
|
||||
.eq(HcsAttachmentSync::getBizId, bizId)
|
||||
.eq(HcsAttachmentSync::getAttachmentKey, attachmentKey)
|
||||
.last("limit 1"));
|
||||
if (existing != null && StringUtil.isNotBlank(existing.getFdId())) {
|
||||
String url = resolveUrl(attachment);
|
||||
return buildRef(existing.getFdId(), resolveFileName(attachment, url == null ? "" : url), fdEntityKey);
|
||||
}
|
||||
String url = resolveUrl(attachment);
|
||||
if (StringUtil.isBlank(url)) {
|
||||
@@ -184,12 +202,30 @@ public class HcsAttachmentSupport {
|
||||
if (result == null || !result.isSuccess() || result.getData() == null || StringUtil.isBlank(result.getData().getFdId())) {
|
||||
log.error("HCS附件转传失败响应:{}", result == null ? "无响应" : String.format("code=%s, msg=%s, traceId=%s",
|
||||
result.getCode(), result.getMsg(), result.getTraceId()));
|
||||
throw new HcsException("HCS附件转传失败:" + (result == null ? "响应为空" : result.getMsg()));
|
||||
throw new HcsException("HCS附件转传失败[" + fileName + "]:" + (result == null ? "响应为空" : result.getMsg()));
|
||||
}
|
||||
String attachmentFdId = result.getData().getFdId();
|
||||
bladeRedis.getValueOps().setIfAbsent(cacheKey, attachmentFdId, Duration.ofDays(HcsSyncConstant.ATTACHMENT_CACHE_TTL_DAYS));
|
||||
log.info("HCS附件转传完成:{} → 合规附件ID {}", fileName, attachmentFdId);
|
||||
return attachmentFdId;
|
||||
HcsAttachmentSync record = new HcsAttachmentSync();
|
||||
record.setBizType(bizType);
|
||||
record.setBizId(bizId);
|
||||
record.setAttachmentKey(attachmentKey);
|
||||
record.setAttachmentName(fileName);
|
||||
record.setFdId(attachmentFdId);
|
||||
record.setSyncTime(LocalDateTime.now());
|
||||
hcsAttachmentSyncMapper.insert(record);
|
||||
log.info("HCS附件转传完成:{} → 合规附件ID {}(业务单据[{}:{}],fdEntityKey={})", fileName, attachmentFdId, bizType, bizId, fdEntityKey);
|
||||
return buildRef(attachmentFdId, fileName, fdEntityKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合规附件引用(fdId + 挂载字段 key)
|
||||
*/
|
||||
private HcsAttachmentRefDTO buildRef(String fdId, String fileName, String fdEntityKey) {
|
||||
HcsAttachmentRefDTO ref = new HcsAttachmentRefDTO();
|
||||
ref.setFdId(fdId);
|
||||
ref.setFdFileName(fileName);
|
||||
ref.setFdEntityKey(fdEntityKey);
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+45
-58
@@ -43,12 +43,9 @@ import org.springblade.hcs.dto.HcsResult;
|
||||
import org.springblade.hcs.dto.HcsRiskQueryDTO;
|
||||
import org.springblade.hcs.dto.HcsRiskVO;
|
||||
import org.springblade.hcs.dto.HcsSignerDTO;
|
||||
import org.springblade.hcs.dto.HcsUserRefVO;
|
||||
import org.springblade.hcs.dto.HcsXformFieldDTO;
|
||||
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.HcsContractFieldConstant;
|
||||
import org.springblade.transport.constant.HcsSyncConstant;
|
||||
import org.springblade.transport.mapper.ContractManageMapper;
|
||||
@@ -124,8 +121,8 @@ public class HcsContractSyncSupport {
|
||||
if (hcsProperties.getContract().isRequireRiskCheck()) {
|
||||
risky = checkRelativeRisk(contractManage);
|
||||
}
|
||||
// ② 附件转传(v4 已明确挂载点:C103-1 fdFieldJson.attachment,转传取得合规附件ID 后随发起报文挂载)
|
||||
List<String> attachmentFdIds = transferAttachmentsIfEnabled(contractManage);
|
||||
// ② 附件转传(v4 已明确挂载点:C103-1 fdFieldJson.attachment,转传取得合规附件引用后随发起报文挂载)
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = transferAttachmentsIfEnabled(contractManage);
|
||||
// ③④ 首推判重后起草(C103-1);已有合规ID(变更单)走更新(C103-11)
|
||||
String resultMessage;
|
||||
if (StringUtil.isBlank(contractManage.getHcsFdId())) {
|
||||
@@ -134,7 +131,7 @@ public class HcsContractSyncSupport {
|
||||
markSynced(contractManage, existFdId, "判重命中,回填已有合规合同ID");
|
||||
resultMessage = "判重命中,回填已有合规合同ID";
|
||||
} else {
|
||||
String fdContractId = draftContract(contractManage, attachmentFdIds);
|
||||
String fdContractId = draftContract(contractManage, attachmentRefs);
|
||||
// 先持久化合规合同ID(调用方必须保存),履约规则同步失败时下轮凭其走更新补偿
|
||||
markSynced(contractManage, fdContractId, "C103-1 合同发起成功");
|
||||
resultMessage = "C103-1 合同发起成功";
|
||||
@@ -204,7 +201,7 @@ public class HcsContractSyncSupport {
|
||||
contractManage.getCurrentNode());
|
||||
try {
|
||||
List<HcsAttachmentRefDTO> attachments = transferSpecExplanationAttachments(contractManage);
|
||||
hcsContractSpecSyncSupport.applySpec(contractManage.getId(), attachments, requireLoginName(contractManage));
|
||||
hcsContractSpecSyncSupport.applySpec(contractManage.getId(), attachments);
|
||||
} catch (Exception exception) {
|
||||
log.warn("HCS合同自动特批发起失败(保持待特批,可人工重发):contractNo={},{}",
|
||||
contractManage.getContractNo(), exception.getMessage(), exception);
|
||||
@@ -213,7 +210,7 @@ public class HcsContractSyncSupport {
|
||||
|
||||
/**
|
||||
* 筛选合同「特批说明」类型附件(fileType=特批说明,业务字典 contract_attachment_type)并转传合规(C103-2),
|
||||
* 返回特批附件引用;无特批说明附件返回空列表(提交时已强制校验,此处由 C103-8 防御性拦截)
|
||||
* 返回特批附件引用(fdEntityKey=eopCdraftSpecial);无特批说明附件返回空列表(提交时已强制校验,此处由 C103-8 防御性拦截)
|
||||
*/
|
||||
private List<HcsAttachmentRefDTO> transferSpecExplanationAttachments(ContractManage contractManage) {
|
||||
List<Map<?, ?>> specAttachments = new ArrayList<>();
|
||||
@@ -227,17 +224,15 @@ public class HcsContractSyncSupport {
|
||||
return List.of();
|
||||
}
|
||||
String specJson = JsonUtil.toJson(specAttachments);
|
||||
String loginName = requireLoginName(contractManage);
|
||||
List<String> attachmentFdIds = hcsAttachmentSupport.transferAttachments(specJson, loginName);
|
||||
List<HcsAttachmentRefDTO> attachments = new ArrayList<>();
|
||||
for (int index = 0; index < specAttachments.size(); index++) {
|
||||
HcsAttachmentRefDTO ref = new HcsAttachmentRefDTO();
|
||||
// 附件ID:C103-2 转传返回的合规附件ID(与元数据行序一致)
|
||||
ref.setFdId(attachmentFdIds.get(index));
|
||||
ref.setFdFileName(resolveAttachmentName(specAttachments.get(index)));
|
||||
attachments.add(ref);
|
||||
String loginName = hcsProperties.getOperatorLoginName();
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = hcsAttachmentSupport.transferAttachments(
|
||||
HcsSyncConstant.BIZ_TYPE_CONTRACT, contractManage.getId(), specJson, loginName);
|
||||
for (int index = 0; index < attachmentRefs.size(); index++) {
|
||||
// 特批附件字段 key:与元数据行序一致
|
||||
attachmentRefs.get(index).setFdEntityKey(HcsSyncConstant.CONTRACT_ATTACH_KEY_SPECIAL);
|
||||
attachmentRefs.get(index).setFdFileName(resolveAttachmentName(specAttachments.get(index)));
|
||||
}
|
||||
return attachments;
|
||||
return attachmentRefs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,9 +322,9 @@ public class HcsContractSyncSupport {
|
||||
/**
|
||||
* C103-1 合同发起,返回合规合同 fdContractId
|
||||
*/
|
||||
private String draftContract(ContractManage contractManage, List<String> attachmentFdIds) {
|
||||
HcsContractDraftDTO param = buildDraftParam(contractManage, attachmentFdIds);
|
||||
log.info("HCS合同推送开始:{}(C103-1 发起,挂载附件 {} 个)", contractManage.getContractNo(), attachmentFdIds.size());
|
||||
private String draftContract(ContractManage contractManage, List<HcsAttachmentRefDTO> attachmentRefs) {
|
||||
HcsContractDraftDTO param = buildDraftParam(contractManage, attachmentRefs);
|
||||
log.info("HCS合同推送开始:{}(C103-1 发起,挂载附件 {} 个)", contractManage.getContractNo(), attachmentRefs.size());
|
||||
HcsResult<HcsContractDraftVO> result = hcsClient.contractDraft(param);
|
||||
return validateDraftResult(contractManage, result);
|
||||
}
|
||||
@@ -349,9 +344,9 @@ public class HcsContractSyncSupport {
|
||||
|
||||
/**
|
||||
* 组装 C103-1/C103-11 入参(字段标注照 §3.4 规范,映射表见设计文档 §5.2);
|
||||
* attachmentFdIds 新建传合规附件ID 列表(必填,无附件传空列表),更新传 null 不挂载
|
||||
* attachmentRefs 新建传合规附件引用列表(fdId+fdEntityKey,必填,无附件传空列表),更新传 null 不挂载
|
||||
*/
|
||||
private HcsContractDraftDTO buildDraftParam(ContractManage contractManage, List<String> attachmentFdIds) {
|
||||
private HcsContractDraftDTO buildDraftParam(ContractManage contractManage, List<HcsAttachmentRefDTO> attachmentRefs) {
|
||||
HcsContractDraftDTO param = new HcsContractDraftDTO();
|
||||
// 【必填】合同ID:C103-11 更新顶层必填(传 C103-1 返回的 fdContractId),C103-1 新建不传(v4 新增)
|
||||
param.setFdId(contractManage.getHcsFdId());
|
||||
@@ -359,24 +354,22 @@ public class HcsContractSyncSupport {
|
||||
param.setFdTemplateId(requireTemplateId(contractManage));
|
||||
// 【必填】外部系统标识:fd_sources,配置 thirdParty.hcs.src-system(D14)
|
||||
param.setFdOuterSystem(hcsProperties.getSrcSystem());
|
||||
// 【必填】操作人登录名:合同承办人登录名(§9-U2)
|
||||
param.setFdLoginName(requireLoginName(contractManage));
|
||||
// 【必填】操作人登录名:配置 thirdParty.hcs.operator-login-name(默认 srvadmin,§9-U2)
|
||||
param.setFdLoginName(hcsProperties.getOperatorLoginName());
|
||||
// 【必填】保存类型:submit(提交)
|
||||
param.setSaveType("submit");
|
||||
HcsContractFieldJsonDTO fieldJson = new HcsContractFieldJsonDTO();
|
||||
fieldJson.setXformFields(buildXformFields(contractManage));
|
||||
// 相对方(签署方):甲方/乙方,编号按名称反查 CustomerArchive(§9-U6)
|
||||
fieldJson.setSigner(buildSigners(contractManage));
|
||||
// 【必填】附件数据:C103-1 必填(无附件传空列表),fdBindType=ADD;更新不挂载(传 null)
|
||||
if (attachmentFdIds != null) {
|
||||
fieldJson.setAttachment(attachmentFdIds.stream().map(fdId -> {
|
||||
HcsAttachmentRefDTO attachment = new HcsAttachmentRefDTO();
|
||||
// 【必填】附件ID(C103-2 转传返回)
|
||||
attachment.setFdId(fdId);
|
||||
// 【必填】附件数据:C103-1 必填(无附件传空列表),fdEntityKey=特批 eopCdraftSpecial/用印 eopCdraftSign/其他 eopCdraftOther,
|
||||
// fdBindType=ADD;更新不挂载(传 null)
|
||||
if (attachmentRefs != null) {
|
||||
fieldJson.setAttachment(new ArrayList<>(attachmentRefs));
|
||||
for (HcsAttachmentRefDTO attachment : fieldJson.getAttachment()) {
|
||||
// 【必填】操作类型:ADD 新增
|
||||
attachment.setFdBindType("ADD");
|
||||
return attachment;
|
||||
}).toList());
|
||||
}
|
||||
}
|
||||
param.setFdFieldJson(fieldJson);
|
||||
return param;
|
||||
@@ -401,12 +394,17 @@ public class HcsContractSyncSupport {
|
||||
// 币种:TMS 结算币种经 currency-name-mapping 映射(默认 RMB→人民币,照金蝶惯例)
|
||||
fields.add(field(HcsContractFieldConstant.FIELD_FD_CURRENCY_ID, "币种", mapCurrencyName(contractManage.getSettlementCurrency())));
|
||||
fields.add(field(HcsContractFieldConstant.FIELD_CURRENCY, "币种", mapCurrencyName(contractManage.getSettlementCurrency())));
|
||||
// 合同结算类型:settlement-type-mapping[settlementMode](必填:payment/payment_collection/collection/none,映射到"付款/收款"待联调,§9-U3,未配置不传)
|
||||
String settlementType = hcsProperties.getContract().getSettlementTypeMapping().get(contractManage.getSettlementMode());
|
||||
// 合同结算类型:按合同类别固定规则——承运商合同=付款,客户合同=收款(2026-10-12 确认)
|
||||
String settlementType = null;
|
||||
if ("承运商合同".equals(contractManage.getContractCategory())) {
|
||||
settlementType = HcsContractFieldConstant.SETTLEMENT_TYPE_PAYMENT;
|
||||
} else if ("客户合同".equals(contractManage.getContractCategory())) {
|
||||
settlementType = HcsContractFieldConstant.SETTLEMENT_TYPE_COLLECTION;
|
||||
}
|
||||
if (StringUtil.isNotBlank(settlementType)) {
|
||||
fields.add(field(HcsContractFieldConstant.FIELD_FD_SETTLEMENT_TYPE, "合同结算类型", settlementType));
|
||||
} else {
|
||||
log.warn("HCS合同结算类型映射缺失:settlementMode=[{}] 不在 contract.settlement-type-mapping,fdSettlementType 不传(§9-U3)", contractManage.getSettlementMode());
|
||||
log.warn("HCS合同结算类型无法确定:contractCategory=[{}] 非承运商合同/客户合同,fdSettlementType 不传", contractManage.getContractCategory());
|
||||
}
|
||||
// 特批流程:fdSepcailContract 固定 false(原文拼写笔误必须沿用,D15,配置项预留)
|
||||
fields.add(field(HcsContractFieldConstant.FIELD_FD_SEPCAIL_CONTRACT, "特批流程", hcsProperties.getContract().isSpecialContractEnabled() ? "true" : "false"));
|
||||
@@ -475,16 +473,18 @@ public class HcsContractSyncSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件转传(可配开关):合同主文件 approved=true + 其它附件,返回合规附件ID 列表(挂载 C103-1 fdFieldJson.attachment)
|
||||
* 附件转传(可配开关):合同主文件 approved=true(挂 eopCdraftSign)+ 其它附件(挂 eopCdraftOther),
|
||||
* 返回合规附件引用列表(挂载 C103-1 fdFieldJson.attachment)
|
||||
*/
|
||||
private List<String> transferAttachmentsIfEnabled(ContractManage contractManage) {
|
||||
private List<HcsAttachmentRefDTO> transferAttachmentsIfEnabled(ContractManage contractManage) {
|
||||
if (!hcsProperties.getAttachment().isTransferEnabled()) {
|
||||
return List.of();
|
||||
}
|
||||
List<String> attachmentFdIds = hcsAttachmentSupport.transferContractAttachments(
|
||||
contractManage.getContractFileJson(), contractManage.getAttachmentsJson(), requireLoginName(contractManage));
|
||||
log.info("HCS合同附件转传完成:contractNo={},共 {} 个附件(随 C103-1 挂载)", contractManage.getContractNo(), attachmentFdIds.size());
|
||||
return attachmentFdIds;
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = hcsAttachmentSupport.transferContractAttachments(
|
||||
HcsSyncConstant.BIZ_TYPE_CONTRACT, contractManage.getId(),
|
||||
contractManage.getContractFileJson(), contractManage.getAttachmentsJson(), hcsProperties.getOperatorLoginName());
|
||||
log.info("HCS合同附件转传完成:contractNo={},共 {} 个附件(随 C103-1 挂载)", contractManage.getContractNo(), attachmentRefs.size());
|
||||
return attachmentRefs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -523,6 +523,7 @@ public class HcsContractSyncSupport {
|
||||
} catch (Exception exception) {
|
||||
String message = StringUtil.isBlank(exception.getMessage()) ? "推送异常" : exception.getMessage();
|
||||
markFailed(contractManage, message);
|
||||
log.error("HCS合同推送失败:{}", message, exception);
|
||||
throw new ServiceException("HCS合同推送失败:" + message);
|
||||
}
|
||||
}
|
||||
@@ -535,7 +536,7 @@ public class HcsContractSyncSupport {
|
||||
contractManage.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_SYNCED);
|
||||
contractManage.setHcsRetryCount(0);
|
||||
contractManage.setHcsSyncTime(LocalDateTime.now());
|
||||
contractManage.setHcsSyncMsg(message);
|
||||
contractManage.setHcsSyncMsg(HcsSyncConstant.truncateMsg(message));
|
||||
contractManageMapper.updateById(contractManage);
|
||||
log.info("HCS合同推送成功:contractNo={},fdContractId={},{}", contractManage.getContractNo(), fdId, message);
|
||||
}
|
||||
@@ -547,7 +548,7 @@ public class HcsContractSyncSupport {
|
||||
contractManage.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_FAILED);
|
||||
contractManage.setHcsRetryCount(contractManage.getHcsRetryCount() == null ? 1 : contractManage.getHcsRetryCount() + 1);
|
||||
contractManage.setHcsSyncTime(LocalDateTime.now());
|
||||
contractManage.setHcsSyncMsg(message);
|
||||
contractManage.setHcsSyncMsg(HcsSyncConstant.truncateMsg(message));
|
||||
contractManageMapper.updateById(contractManage);
|
||||
log.error("HCS合同推送失败:contractNo={},retryCount={},{}", contractManage.getContractNo(), contractManage.getHcsRetryCount(), message);
|
||||
}
|
||||
@@ -565,20 +566,6 @@ public class HcsContractSyncSupport {
|
||||
return templateId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合同承办人登录名(fdLoginName 必填)
|
||||
*/
|
||||
private String requireLoginName(ContractManage contractManage) {
|
||||
if (contractManage.getHandlerUserId() == null) {
|
||||
throw new HcsException("HCS合同推送失败,合同承办人未维护(contractNo=" + contractManage.getContractNo() + ")");
|
||||
}
|
||||
User user = UserCache.getUser(contractManage.getHandlerUserId());
|
||||
if (user == null || StringUtil.isBlank(user.getAccount())) {
|
||||
throw new HcsException("HCS合同推送失败,承办人登录名解析不到(handlerUserId=" + contractManage.getHandlerUserId() + ",§9-U2)");
|
||||
}
|
||||
return user.getAccount();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称反查客商编码(照 KingdeeApBillSyncSupport#queryCustomerCode 惯例,查不到返回 null)
|
||||
*/
|
||||
|
||||
+7
-3
@@ -32,6 +32,7 @@ import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.hcs.config.HcsProperties;
|
||||
import org.springblade.hcs.dto.HcsAttachmentRefDTO;
|
||||
import org.springblade.hcs.dto.HcsIdVO;
|
||||
import org.springblade.hcs.dto.HcsInvoiceRegAddDTO;
|
||||
import org.springblade.hcs.dto.HcsInvoiceRegUpdateDTO;
|
||||
@@ -181,7 +182,10 @@ public class HcsInvoiceRegSyncSupport {
|
||||
param.setFdThirdCreatorDeptCode(resolveDeptCode(application));
|
||||
// 附件ID列表:attachmentsJson 经 C103-2 转传
|
||||
if (hcsProperties.getAttachment().isTransferEnabled() && StringUtil.isNotBlank(application.getAttachmentsJson())) {
|
||||
param.setFdAttIds(hcsAttachmentSupport.transferAttachments(application.getAttachmentsJson(), resolveCreatorCode(application)));
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = hcsAttachmentSupport.transferAttachments(
|
||||
HcsSyncConstant.BIZ_TYPE_INVOICE_APPLICATION, application.getId(),
|
||||
application.getAttachmentsJson(), resolveCreatorCode(application));
|
||||
param.setFdAttIds(attachmentRefs.stream().map(HcsAttachmentRefDTO::getFdId).toList());
|
||||
}
|
||||
log.info("HCS开票登记新增开始:applicationNo={}", application.getApplicationNo());
|
||||
HcsResult<HcsIdVO> result = hcsClient.invoiceRegistrationAdd(param);
|
||||
@@ -298,7 +302,7 @@ public class HcsInvoiceRegSyncSupport {
|
||||
application.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_SYNCED);
|
||||
application.setHcsRetryCount(0);
|
||||
application.setHcsSyncTime(LocalDateTime.now());
|
||||
application.setHcsSyncMsg(message);
|
||||
application.setHcsSyncMsg(HcsSyncConstant.truncateMsg(message));
|
||||
invoiceApplicationMapper.updateById(application);
|
||||
log.info("HCS开票登记推送成功:applicationNo={},fdId={},{}", application.getApplicationNo(), fdId, message);
|
||||
}
|
||||
@@ -310,7 +314,7 @@ public class HcsInvoiceRegSyncSupport {
|
||||
application.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_FAILED);
|
||||
application.setHcsRetryCount(application.getHcsRetryCount() == null ? 1 : application.getHcsRetryCount() + 1);
|
||||
application.setHcsSyncTime(LocalDateTime.now());
|
||||
application.setHcsSyncMsg(message);
|
||||
application.setHcsSyncMsg(HcsSyncConstant.truncateMsg(message));
|
||||
invoiceApplicationMapper.updateById(application);
|
||||
log.error("HCS开票登记推送失败:applicationNo={},retryCount={},{}", application.getApplicationNo(), application.getHcsRetryCount(), message);
|
||||
}
|
||||
|
||||
+9
-19
@@ -40,8 +40,7 @@ import org.springblade.hcs.dto.HcsFormSaveVO;
|
||||
import org.springblade.hcs.dto.HcsUserRefVO;
|
||||
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.mapper.PaymentApplicationMapper;
|
||||
@@ -189,18 +188,16 @@ public class HcsPerfRecordSyncSupport {
|
||||
if (!hcsProperties.getAttachment().isTransferEnabled() || StringUtil.isBlank(payment.getAttachmentsJson())) {
|
||||
return null;
|
||||
}
|
||||
List<String> attachmentFdIds = hcsAttachmentSupport.transferAttachments(payment.getAttachmentsJson(), operatorLoginName);
|
||||
if (attachmentFdIds.isEmpty()) {
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = hcsAttachmentSupport.transferAttachments(
|
||||
HcsSyncConstant.BIZ_TYPE_PAYMENT, payment.getId(), payment.getAttachmentsJson(), operatorLoginName);
|
||||
if (attachmentRefs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
HcsMechanismsDTO mechanisms = new HcsMechanismsDTO();
|
||||
mechanisms.setAttachment(attachmentFdIds.stream().map(fdId -> {
|
||||
HcsAttachmentRefDTO attachment = new HcsAttachmentRefDTO();
|
||||
mechanisms.setAttachment(attachmentRefs.stream().map(ref -> {
|
||||
// 附件ID(C103-2 转传返回)
|
||||
attachment.setFdId(fdId);
|
||||
// 履约记录附件字段标识
|
||||
attachment.setFdEntityKey(PERF_ATTACH_ENTITY_KEY);
|
||||
return attachment;
|
||||
ref.setFdEntityKey(PERF_ATTACH_ENTITY_KEY);
|
||||
return ref;
|
||||
}).toList());
|
||||
return mechanisms;
|
||||
}
|
||||
@@ -220,17 +217,10 @@ public class HcsPerfRecordSyncSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作人登录名(付款申请创建人,§9-U2)
|
||||
* 操作人登录名(thirdParty.hcs.operator-login-name,默认 srvadmin,§9-U2)
|
||||
*/
|
||||
private String resolveLoginName(PaymentApplication payment) {
|
||||
if (payment.getCreateUser() == null) {
|
||||
throw new HcsException("C108 履约记录推送失败,付款申请创建人未维护(paymentNo=" + payment.getPaymentNo() + ")");
|
||||
}
|
||||
User user = UserCache.getUser(payment.getCreateUser());
|
||||
if (user == null || StringUtil.isBlank(user.getAccount())) {
|
||||
throw new HcsException("C108 履约记录推送失败,创建人登录名解析不到(createUser=" + payment.getCreateUser() + ")");
|
||||
}
|
||||
return user.getAccount();
|
||||
return hcsProperties.getOperatorLoginName();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-22
@@ -40,8 +40,6 @@ import org.springblade.hcs.dto.HcsReceiptBillSaveDTO;
|
||||
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.FormalSettlementMapper;
|
||||
@@ -186,18 +184,17 @@ public class HcsReceiptBillSyncSupport {
|
||||
param.setFormData(formData);
|
||||
// 附件挂载(发票扫描件):fdEntityKey=fd_attach,发起带 fdBindType=ADD,更新不带
|
||||
if (hcsProperties.getAttachment().isTransferEnabled() && StringUtil.isNotBlank(invoiceReceipt.getAttachmentsJson())) {
|
||||
List<String> attachmentFdIds = hcsAttachmentSupport.transferAttachments(invoiceReceipt.getAttachmentsJson(), operatorLoginName);
|
||||
if (!attachmentFdIds.isEmpty()) {
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = hcsAttachmentSupport.transferAttachments(
|
||||
HcsSyncConstant.BIZ_TYPE_INVOICE_RECEIPT, invoiceReceipt.getId(),
|
||||
invoiceReceipt.getAttachmentsJson(), operatorLoginName);
|
||||
if (!attachmentRefs.isEmpty()) {
|
||||
HcsMechanismsDTO mechanisms = new HcsMechanismsDTO();
|
||||
mechanisms.setAttachment(attachmentFdIds.stream().map(fdId -> {
|
||||
HcsAttachmentRefDTO attachment = new HcsAttachmentRefDTO();
|
||||
mechanisms.setAttachment(attachmentRefs.stream().map(ref -> {
|
||||
// 附件ID(C103-2 转传返回)
|
||||
attachment.setFdId(fdId);
|
||||
// 收票单附件字段标识
|
||||
attachment.setFdEntityKey(RECEIPT_ATTACH_ENTITY_KEY);
|
||||
ref.setFdEntityKey(RECEIPT_ATTACH_ENTITY_KEY);
|
||||
// 绑定类型:仅发起传 ADD
|
||||
attachment.setFdBindType(add ? "ADD" : null);
|
||||
return attachment;
|
||||
ref.setFdBindType(add ? "ADD" : null);
|
||||
return ref;
|
||||
}).toList());
|
||||
param.setMechanisms(mechanisms);
|
||||
}
|
||||
@@ -258,7 +255,7 @@ public class HcsReceiptBillSyncSupport {
|
||||
invoiceReceipt.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_SYNCED);
|
||||
invoiceReceipt.setHcsRetryCount(0);
|
||||
invoiceReceipt.setHcsSyncTime(LocalDateTime.now());
|
||||
invoiceReceipt.setHcsSyncMsg(message);
|
||||
invoiceReceipt.setHcsSyncMsg(HcsSyncConstant.truncateMsg(message));
|
||||
invoiceReceiptMapper.updateById(invoiceReceipt);
|
||||
log.info("HCS收票单推送成功:invoiceNo={},{}", invoiceReceipt.getInvoiceNo(), message);
|
||||
}
|
||||
@@ -270,23 +267,16 @@ public class HcsReceiptBillSyncSupport {
|
||||
invoiceReceipt.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_FAILED);
|
||||
invoiceReceipt.setHcsRetryCount(invoiceReceipt.getHcsRetryCount() == null ? 1 : invoiceReceipt.getHcsRetryCount() + 1);
|
||||
invoiceReceipt.setHcsSyncTime(LocalDateTime.now());
|
||||
invoiceReceipt.setHcsSyncMsg(message);
|
||||
invoiceReceipt.setHcsSyncMsg(HcsSyncConstant.truncateMsg(message));
|
||||
invoiceReceiptMapper.updateById(invoiceReceipt);
|
||||
log.error("HCS收票单推送失败:invoiceNo={},retryCount={},{}", invoiceReceipt.getInvoiceNo(), invoiceReceipt.getHcsRetryCount(), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作人登录名(收票单创建人,§9-U2)
|
||||
* 操作人登录名(thirdParty.hcs.operator-login-name,默认 srvadmin,§9-U2)
|
||||
*/
|
||||
private String resolveLoginName(InvoiceReceipt invoiceReceipt) {
|
||||
if (invoiceReceipt.getCreateUser() == null) {
|
||||
throw new HcsException("C109 收票单推送失败,收票单创建人未维护(invoiceNo=" + invoiceReceipt.getInvoiceNo() + ")");
|
||||
}
|
||||
User user = UserCache.getUser(invoiceReceipt.getCreateUser());
|
||||
if (user == null || StringUtil.isBlank(user.getAccount())) {
|
||||
throw new HcsException("C109 收票单推送失败,创建人登录名解析不到(createUser=" + invoiceReceipt.getCreateUser() + ")");
|
||||
}
|
||||
return user.getAccount();
|
||||
return hcsProperties.getOperatorLoginName();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+9
-20
@@ -38,9 +38,7 @@ import org.springblade.hcs.dto.HcsSpecPayPropsDTO;
|
||||
import org.springblade.hcs.dto.HcsSpecPaySaveDTO;
|
||||
import org.springblade.hcs.exception.HcsException;
|
||||
import org.springblade.hcs.feign.IHcsClient;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
import org.springblade.transport.constant.HcsSyncConstant;
|
||||
import org.springblade.system.pojo.entity.User;
|
||||
import org.springblade.transport.mapper.PaymentApplicationMapper;
|
||||
import org.springblade.transport.pojo.entity.ContractManage;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||
@@ -172,21 +170,19 @@ public class HcsSpecPaySyncSupport {
|
||||
if (!hcsProperties.getAttachment().isTransferEnabled() || StringUtil.isBlank(payment.getAttachmentsJson())) {
|
||||
return null;
|
||||
}
|
||||
List<String> attachmentFdIds = hcsAttachmentSupport.transferAttachments(payment.getAttachmentsJson(), operatorLoginName);
|
||||
if (attachmentFdIds.isEmpty()) {
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = hcsAttachmentSupport.transferAttachments(
|
||||
HcsSyncConstant.BIZ_TYPE_PAYMENT, payment.getId(), payment.getAttachmentsJson(), operatorLoginName);
|
||||
if (attachmentRefs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
HcsMechanismsDTO mechanisms = new HcsMechanismsDTO();
|
||||
boolean add = StringUtil.isBlank(payment.getHcsSpecFdId());
|
||||
mechanisms.setAttachment(attachmentFdIds.stream().map(fdId -> {
|
||||
HcsAttachmentRefDTO attachment = new HcsAttachmentRefDTO();
|
||||
mechanisms.setAttachment(attachmentRefs.stream().map(ref -> {
|
||||
// 附件ID(C103-2 转传返回)
|
||||
attachment.setFdId(fdId);
|
||||
// 特批附件字段标识
|
||||
attachment.setFdEntityKey(SPEC_ATTACH_ENTITY_KEY);
|
||||
ref.setFdEntityKey(SPEC_ATTACH_ENTITY_KEY);
|
||||
// 绑定类型:仅发起传 ADD
|
||||
attachment.setFdBindType(add ? "ADD" : null);
|
||||
return attachment;
|
||||
ref.setFdBindType(add ? "ADD" : null);
|
||||
return ref;
|
||||
}).toList());
|
||||
return mechanisms;
|
||||
}
|
||||
@@ -214,16 +210,9 @@ public class HcsSpecPaySyncSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作人登录名(付款申请创建人,§9-U2)
|
||||
* 操作人登录名(thirdParty.hcs.operator-login-name,默认 srvadmin,§9-U2)
|
||||
*/
|
||||
private String resolveLoginName(PaymentApplication payment) {
|
||||
if (payment.getCreateUser() == null) {
|
||||
throw new HcsException("C106 特批推送失败,付款申请创建人未维护(paymentNo=" + payment.getPaymentNo() + ")");
|
||||
}
|
||||
User user = UserCache.getUser(payment.getCreateUser());
|
||||
if (user == null || StringUtil.isBlank(user.getAccount())) {
|
||||
throw new HcsException("C106 特批推送失败,创建人登录名解析不到(createUser=" + payment.getCreateUser() + ")");
|
||||
}
|
||||
return user.getAccount();
|
||||
return hcsProperties.getOperatorLoginName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ org.springblade.transport
|
||||
│ ├── HcsSpecPaySyncSupport.java # 特批 C106-3/4
|
||||
│ ├── HcsInvoiceRegSyncSupport.java # 开票登记 C111
|
||||
│ ├── HcsReceiptBillSyncSupport.java # 收票单 C109
|
||||
│ └── HcsAttachmentSupport.java # 附件转传 + TMS→HCS 附件ID映射缓存
|
||||
│ └── HcsAttachmentSupport.java # 附件转传 + TMS→HCS 附件ID映射同步表(blade_hcs_attachment_sync)
|
||||
├── task/HcsPushTask.java # @Scheduled 扫描首推/补偿(照 PaymentKingdeeResultTask 模式)
|
||||
├── controller/HcsSyncController.java # 手动推送/重推、校验重放、对账查询端点
|
||||
└── entity/HcsContractExeStage.java # 履约规则实体(blade-transport-api)
|
||||
@@ -338,7 +338,7 @@ flowchart LR
|
||||
1. 输入:单据 `attachmentsJson`/`contractFileJson`(JSON 元素含 url/fileType/approved 等,去重键照 `attachmentKey` 惯例 url|link|fileUrl|downloadUrl|uid|originalName)。
|
||||
2. 下载:按元数据 URL 从文件服务拉取流(文件服务基址可配 `attachment.file-download-base`)。
|
||||
3. 上传:C103-2 multipart(fdFile、fdAnonymous=false、fdLoginName=操作人)→ 附件 `fdId`。
|
||||
4. 映射缓存:Redis `hcs:att:{attachmentKey}` → 合规 fdId(TTL 7d),未命中重传(重复上传仅浪费存储,无业务风险,故不做持久化映射表)。
|
||||
4. 映射同步表:`blade_hcs_attachment_sync`(biz_type+biz_id+attachment_key 唯一,照金蝶附件同步表设计)落业务单据 → 合规 fdId 映射,转传前查命中即复用;仅落成功记录(失败整单重试,原因落单据 hcs_sync_msg)。
|
||||
5. 任一附件转传失败 → 整单推送失败进补偿重试。
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user