feat: 合规认领推送改为按认领主单触发并新增C107-3作废同步
This commit is contained in:
+209
-67
@@ -11,8 +11,8 @@
|
|||||||
* 2. Redistribution of this software's source code to any third party
|
* 2. Redistribution of this software's source code to any third party
|
||||||
* is strictly prohibited.
|
* is strictly prohibited.
|
||||||
* <p>
|
* <p>
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
* 3. Licensees may copyright their own code but cannot use segments of this software
|
||||||
* from this software for their own commercial purposes.
|
* for their own commercial purposes.
|
||||||
* <p>
|
* <p>
|
||||||
* Using this software signifies agreement to this license agreement and terms of use,
|
* Using this software signifies agreement to this license agreement and terms of use,
|
||||||
* and you expressly agree to be bound by the terms of use of this software.
|
* and you expressly agree to be bound by the terms of use of this software.
|
||||||
@@ -33,17 +33,24 @@ import org.springblade.core.tool.utils.StringUtil;
|
|||||||
import org.springblade.hcs.config.HcsProperties;
|
import org.springblade.hcs.config.HcsProperties;
|
||||||
import org.springblade.hcs.dto.HcsClaimRecordAddDTO;
|
import org.springblade.hcs.dto.HcsClaimRecordAddDTO;
|
||||||
import org.springblade.hcs.dto.HcsCollectionFlowVO;
|
import org.springblade.hcs.dto.HcsCollectionFlowVO;
|
||||||
|
import org.springblade.hcs.dto.HcsFormSaveVO;
|
||||||
import org.springblade.hcs.dto.HcsIdVO;
|
import org.springblade.hcs.dto.HcsIdVO;
|
||||||
|
import org.springblade.hcs.dto.HcsMechanismsDTO;
|
||||||
import org.springblade.hcs.dto.HcsPageQueryDTO;
|
import org.springblade.hcs.dto.HcsPageQueryDTO;
|
||||||
import org.springblade.hcs.dto.HcsPageVO;
|
import org.springblade.hcs.dto.HcsPageVO;
|
||||||
|
import org.springblade.hcs.dto.HcsPerfRecordFormDataDTO;
|
||||||
|
import org.springblade.hcs.dto.HcsPerfRecordPropsDTO;
|
||||||
|
import org.springblade.hcs.dto.HcsPerfRecordSaveDTO;
|
||||||
import org.springblade.hcs.dto.HcsRefVO;
|
import org.springblade.hcs.dto.HcsRefVO;
|
||||||
import org.springblade.hcs.dto.HcsResult;
|
import org.springblade.hcs.dto.HcsResult;
|
||||||
|
import org.springblade.hcs.dto.HcsUserRefVO;
|
||||||
import org.springblade.hcs.exception.HcsException;
|
import org.springblade.hcs.exception.HcsException;
|
||||||
import org.springblade.hcs.feign.IHcsClient;
|
import org.springblade.hcs.feign.IHcsClient;
|
||||||
import org.springblade.transport.constant.HcsSyncConstant;
|
import org.springblade.transport.constant.HcsSyncConstant;
|
||||||
import org.springblade.transport.mapper.ContractManageMapper;
|
import org.springblade.transport.mapper.ContractManageMapper;
|
||||||
import org.springblade.transport.mapper.FormalSettlementMapper;
|
import org.springblade.transport.mapper.FormalSettlementMapper;
|
||||||
import org.springblade.transport.mapper.KingdeeReceiptFlowMapper;
|
import org.springblade.transport.mapper.KingdeeReceiptFlowMapper;
|
||||||
|
import org.springblade.transport.mapper.ReceiptClaimHcsRecordMapper;
|
||||||
import org.springblade.transport.mapper.ReceiptClaimMapper;
|
import org.springblade.transport.mapper.ReceiptClaimMapper;
|
||||||
import org.springblade.transport.mapper.ReceiptClaimSettlementMapper;
|
import org.springblade.transport.mapper.ReceiptClaimSettlementMapper;
|
||||||
import org.springblade.transport.pojo.entity.ContractManage;
|
import org.springblade.transport.pojo.entity.ContractManage;
|
||||||
@@ -51,12 +58,14 @@ import org.springblade.transport.pojo.entity.FormalSettlement;
|
|||||||
import org.springblade.transport.pojo.entity.HcsContractExeStage;
|
import org.springblade.transport.pojo.entity.HcsContractExeStage;
|
||||||
import org.springblade.transport.pojo.entity.KingdeeReceiptFlow;
|
import org.springblade.transport.pojo.entity.KingdeeReceiptFlow;
|
||||||
import org.springblade.transport.pojo.entity.ReceiptClaim;
|
import org.springblade.transport.pojo.entity.ReceiptClaim;
|
||||||
|
import org.springblade.transport.pojo.entity.ReceiptClaimHcsRecord;
|
||||||
import org.springblade.transport.pojo.entity.ReceiptClaimSettlement;
|
import org.springblade.transport.pojo.entity.ReceiptClaimSettlement;
|
||||||
import org.springblade.transport.service.IContractExeStageService;
|
import org.springblade.transport.service.IContractExeStageService;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -67,13 +76,14 @@ import java.util.stream.Collectors;
|
|||||||
/**
|
/**
|
||||||
* HCS 收款认领链推送编排支撑组件(C103-9 更新履约计划 + C107-1 认领记录 + C108-1 履约流水)
|
* HCS 收款认领链推送编排支撑组件(C103-9 更新履约计划 + C107-1 认领记录 + C108-1 履约流水)
|
||||||
* <p>
|
* <p>
|
||||||
* 触发点:金蝶认领推送(A301-3)成功之后(手动按钮与定时任务共用钩子)。
|
* 触发点:收款流水认领事务提交后按认领主单推送(作废认领事务提交后推 C107-3 作废同步)。
|
||||||
* 开关复用既有配置(不单独新增):exe-stage.sync-enabled 门禁 C103-9/C107-1(与合同链履约计划同步同开关),
|
* 开关复用既有配置(不单独新增):exe-stage.sync-enabled 门禁 C103-9/C107-1(与合同链履约计划同步同开关),
|
||||||
* perf-record.sync-enabled 门禁 C108-1(与付款链履约记录同步同开关)。
|
* perf-record.sync-enabled 门禁 C108-1(与付款链履约记录同步同开关)。
|
||||||
* 编排顺序:先 C103-9(认领金额累加到收款履约计划行并重推,C107-1/C108-1 引用其返回的阶段ID),
|
* 编排顺序:先 C103-9(认领金额累加到收款履约计划行并重推,C107-1/C108-1 引用其返回的阶段ID),
|
||||||
* 再按「认领主单 × 合同」推 C107-1(合规流水ID 经 C104-2 按明细流水号定位),最后按合同推 C108-1 履约流水。
|
* 再按「认领主单 × 合同」推 C107-1(合规流水ID 经 C104-2 按明细流水号定位,返回 fdId 落库
|
||||||
|
* blade_receipt_claim_hcs_record 供作废 C107-3 引用),最后按合同推 C108-1 履约流水。
|
||||||
* 合同未推送合规(hcs_fd_id 空)时仅累加计划行金额,随合同链路首推。
|
* 合同未推送合规(hcs_fd_id 空)时仅累加计划行金额,随合同链路首推。
|
||||||
* 推送失败仅记日志不回滚金蝶推送结果(单合同失败不影响其余合同)。
|
* 推送失败仅落失败标记与日志,不回滚认领主流程(单合同失败不影响其余合同,不做定时重试)。
|
||||||
*
|
*
|
||||||
* @author Chill
|
* @author Chill
|
||||||
*/
|
*/
|
||||||
@@ -86,60 +96,80 @@ public class HcsClaimSyncSupport {
|
|||||||
* 认领完成状态(与 ReceiptFlowServiceImpl.CLAIMED 同值)
|
* 认领完成状态(与 ReceiptFlowServiceImpl.CLAIMED 同值)
|
||||||
*/
|
*/
|
||||||
private static final String CLAIMED = "claimed";
|
private static final String CLAIMED = "claimed";
|
||||||
|
/**
|
||||||
|
* 推送状态:推送成功
|
||||||
|
*/
|
||||||
|
private static final String PUSH_SUCCESS = "success";
|
||||||
|
/**
|
||||||
|
* 推送状态:推送失败(仅记标记,不做定时重试)
|
||||||
|
*/
|
||||||
|
private static final String PUSH_FAILED = "failed";
|
||||||
|
/**
|
||||||
|
* 推送状态:已作废(C107-3 同步成功)
|
||||||
|
*/
|
||||||
|
private static final String PUSH_VOIDED = "voided";
|
||||||
|
/**
|
||||||
|
* 认领记录状态:已认领
|
||||||
|
*/
|
||||||
|
private static final int CLAIM_STATUS_CLAIMED = 0;
|
||||||
|
/**
|
||||||
|
* 认领记录状态:已作废
|
||||||
|
*/
|
||||||
|
private static final int CLAIM_STATUS_VOIDED = 1;
|
||||||
|
|
||||||
private final IHcsClient hcsClient;
|
private final IHcsClient hcsClient;
|
||||||
private final HcsProperties hcsProperties;
|
private final HcsProperties hcsProperties;
|
||||||
private final KingdeeReceiptFlowMapper receiptFlowMapper;
|
private final KingdeeReceiptFlowMapper receiptFlowMapper;
|
||||||
private final ReceiptClaimMapper claimMapper;
|
private final ReceiptClaimMapper claimMapper;
|
||||||
private final ReceiptClaimSettlementMapper claimSettlementMapper;
|
private final ReceiptClaimSettlementMapper claimSettlementMapper;
|
||||||
|
private final ReceiptClaimHcsRecordMapper claimHcsRecordMapper;
|
||||||
private final FormalSettlementMapper formalSettlementMapper;
|
private final FormalSettlementMapper formalSettlementMapper;
|
||||||
private final ContractManageMapper contractManageMapper;
|
private final ContractManageMapper contractManageMapper;
|
||||||
private final IContractExeStageService contractExeStageService;
|
private final IContractExeStageService contractExeStageService;
|
||||||
private final HcsExeStageSyncSupport hcsExeStageSyncSupport;
|
private final HcsExeStageSyncSupport hcsExeStageSyncSupport;
|
||||||
private final HcsPerfRecordAddSupport hcsPerfRecordAddSupport;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 金蝶认领推送成功后推送合同合规(C103-9 → C107-1 → C108-1)
|
* 认领事务提交后推送合同合规(C103-9 → C107-1 → C108-1,按认领主单维度)
|
||||||
* <p>
|
* <p>
|
||||||
* 复用既有开关:exe-stage.sync-enabled(履约计划同步)门禁 C103-9/C107-1,
|
* 复用既有开关:exe-stage.sync-enabled(履约计划同步)门禁 C103-9/C107-1,
|
||||||
* perf-record.sync-enabled(履约记录同步)门禁 C108-1;开关关闭或推送异常均静默返回,
|
* perf-record.sync-enabled(履约记录同步)门禁 C108-1;开关关闭或推送异常均静默返回,
|
||||||
* 不影响金蝶认领推送主流程与事务。
|
* 不影响认领主流程与事务。
|
||||||
*
|
*
|
||||||
* @param flowId 收款流水ID
|
* @param claimId 认领主单ID
|
||||||
*/
|
*/
|
||||||
public void pushClaimToHcs(Long flowId) {
|
public void pushClaimToHcs(Long claimId) {
|
||||||
if (!hcsProperties.getExeStage().isSyncEnabled()) {
|
if (!hcsProperties.getExeStage().isSyncEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
doPushClaimToHcs(flowId);
|
doPushClaimToHcs(claimId);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
log.error("HCS收款认领链推送异常 flowId:{}", flowId, exception);
|
log.error("HCS收款认领链推送异常 claimId:{}", claimId, exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 推送主体:归集有效认领分摊(按合同分组)→ 逐合同推送(单合同失败不影响其余合同)
|
* 推送主体:归集本认领主单有效分摊(按合同分组)→ 逐合同推送(单合同失败不影响其余合同)
|
||||||
*/
|
*/
|
||||||
private void doPushClaimToHcs(Long flowId) {
|
private void doPushClaimToHcs(Long claimId) {
|
||||||
KingdeeReceiptFlow flow = receiptFlowMapper.selectById(flowId);
|
ReceiptClaim claim = claimMapper.selectById(claimId);
|
||||||
|
if (claim == null || !CLAIMED.equals(claim.getClaimStatus())) {
|
||||||
|
log.info("HCS收款认领链推送跳过:认领主单不存在或已作废 claimId={}", claimId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
KingdeeReceiptFlow flow = receiptFlowMapper.selectById(claim.getReceiptFlowId());
|
||||||
if (flow == null) {
|
if (flow == null) {
|
||||||
|
log.warn("HCS收款认领链推送跳过:收款流水不存在 claimId={},flowId={}", claimId, claim.getReceiptFlowId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 未作废认领主单(作废认领不同步合规)
|
// 本认领主单有效分摊行(作废时已置 status=0)
|
||||||
List<ReceiptClaim> claims = claimMapper.selectList(Wrappers.<ReceiptClaim>lambdaQuery()
|
|
||||||
.eq(ReceiptClaim::getReceiptFlowId, flowId)
|
|
||||||
.eq(ReceiptClaim::getClaimStatus, CLAIMED));
|
|
||||||
if (claims.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 有效分摊行(作废时已置 status=0)
|
|
||||||
List<ReceiptClaimSettlement> allocations = claimSettlementMapper.selectList(
|
List<ReceiptClaimSettlement> allocations = claimSettlementMapper.selectList(
|
||||||
Wrappers.<ReceiptClaimSettlement>lambdaQuery()
|
Wrappers.<ReceiptClaimSettlement>lambdaQuery()
|
||||||
.eq(ReceiptClaimSettlement::getReceiptFlowId, flowId)
|
.eq(ReceiptClaimSettlement::getReceiptClaimId, claimId)
|
||||||
.eq(ReceiptClaimSettlement::getStatus, 1)
|
.eq(ReceiptClaimSettlement::getStatus, 1)
|
||||||
.eq(ReceiptClaimSettlement::getIsDeleted, 0));
|
.eq(ReceiptClaimSettlement::getIsDeleted, 0));
|
||||||
if (allocations.isEmpty()) {
|
if (allocations.isEmpty()) {
|
||||||
|
log.info("HCS收款认领链推送跳过:认领主单无有效分摊 claimId={}", claimId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 结算单批量定位合同(一次 IN 查询,避免逐行 N+1)
|
// 结算单批量定位合同(一次 IN 查询,避免逐行 N+1)
|
||||||
@@ -147,20 +177,18 @@ public class HcsClaimSyncSupport {
|
|||||||
allocations.stream().map(ReceiptClaimSettlement::getFormalSettlementId)
|
allocations.stream().map(ReceiptClaimSettlement::getFormalSettlementId)
|
||||||
.filter(Objects::nonNull).distinct().toList()).stream()
|
.filter(Objects::nonNull).distinct().toList()).stream()
|
||||||
.collect(Collectors.toMap(FormalSettlement::getId, item -> item, (first, second) -> first));
|
.collect(Collectors.toMap(FormalSettlement::getId, item -> item, (first, second) -> first));
|
||||||
// 合同id → 认领主单id → 分摊金额
|
// 合同id → 本认领主单分摊金额
|
||||||
Map<Long, Map<Long, BigDecimal>> amountByContractByClaim = new LinkedHashMap<>();
|
Map<Long, BigDecimal> amountByContract = new LinkedHashMap<>();
|
||||||
for (ReceiptClaimSettlement allocation : allocations) {
|
for (ReceiptClaimSettlement allocation : allocations) {
|
||||||
FormalSettlement settlement = settlements.get(allocation.getFormalSettlementId());
|
FormalSettlement settlement = settlements.get(allocation.getFormalSettlementId());
|
||||||
if (settlement == null || settlement.getContractId() == null
|
if (settlement == null || settlement.getContractId() == null
|
||||||
|| allocation.getReceiptClaimId() == null || allocation.getAllocatedReceiptAmount() == null) {
|
|| allocation.getAllocatedReceiptAmount() == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
amountByContractByClaim
|
amountByContract.merge(settlement.getContractId(), allocation.getAllocatedReceiptAmount(), BigDecimal::add);
|
||||||
.computeIfAbsent(settlement.getContractId(), key -> new LinkedHashMap<>())
|
|
||||||
.merge(allocation.getReceiptClaimId(), allocation.getAllocatedReceiptAmount(), BigDecimal::add);
|
|
||||||
}
|
}
|
||||||
if (amountByContractByClaim.isEmpty()) {
|
if (amountByContract.isEmpty()) {
|
||||||
log.info("HCS收款认领链推送跳过:分摊行未关联合同 flowId={}", flowId);
|
log.info("HCS收款认领链推送跳过:分摊行未关联合同 claimId={},flowId={}", claimId, flow.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 合规侧收款流水ID(C107-1 必填引用,一次定位全部合同共用;定位失败仅跳过 C107-1,不阻塞履约计划更新)
|
// 合规侧收款流水ID(C107-1 必填引用,一次定位全部合同共用;定位失败仅跳过 C107-1,不阻塞履约计划更新)
|
||||||
@@ -168,47 +196,47 @@ public class HcsClaimSyncSupport {
|
|||||||
try {
|
try {
|
||||||
hcsCollectionFlowId = locateHcsCollectionFlowId(flow);
|
hcsCollectionFlowId = locateHcsCollectionFlowId(flow);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
log.error("HCS收款流水定位失败 flowId:{},跳过C107-1认领记录推送", flowId, exception);
|
log.error("HCS收款流水定位失败 flowId:{},跳过C107-1认领记录推送", flow.getId(), exception);
|
||||||
}
|
}
|
||||||
for (Map.Entry<Long, Map<Long, BigDecimal>> contractEntry : amountByContractByClaim.entrySet()) {
|
for (Map.Entry<Long, BigDecimal> contractEntry : amountByContract.entrySet()) {
|
||||||
try {
|
try {
|
||||||
pushOneContract(flow, claims, contractEntry.getKey(), contractEntry.getValue(), hcsCollectionFlowId);
|
pushOneContract(flow, claim, contractEntry.getKey(), contractEntry.getValue(), hcsCollectionFlowId);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
log.error("HCS收款认领链推送失败 flowId:{},contractId:{}", flowId, contractEntry.getKey(), exception);
|
log.error("HCS收款认领链推送失败 claimId:{},flowId:{},contractId:{}",
|
||||||
|
claimId, flow.getId(), contractEntry.getKey(), exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 推送单个合同:① C103-9 更新履约计划(认领金额累加重推)→ ② C107-1 认领记录(按认领主单分组)→ ③ C108-1 履约流水
|
* 推送单个合同:① C103-9 更新履约计划(认领金额累加重推)→ ② C107-1 认领记录(结果落库)→ ③ C108-1 履约流水
|
||||||
*/
|
*/
|
||||||
private void pushOneContract(KingdeeReceiptFlow flow, List<ReceiptClaim> claims, Long contractId,
|
private void pushOneContract(KingdeeReceiptFlow flow, ReceiptClaim claim, Long contractId,
|
||||||
Map<Long, BigDecimal> amountByClaim, String hcsCollectionFlowId) {
|
BigDecimal claimAmount, String hcsCollectionFlowId) {
|
||||||
ContractManage contractManage = contractManageMapper.selectById(contractId);
|
ContractManage contractManage = contractManageMapper.selectById(contractId);
|
||||||
if (contractManage == null) {
|
if (contractManage == null) {
|
||||||
log.warn("HCS收款认领链推送跳过:合同不存在 contractId={}", contractId);
|
log.warn("HCS收款认领链推送跳过:合同不存在 contractId={}", contractId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BigDecimal claimedTotal = amountByClaim.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
||||||
// ① C103-9 更新合同履约计划:认领金额累加到收款计划行;已同步行置 update 凭阶段ID 重推
|
// ① C103-9 更新合同履约计划:认领金额累加到收款计划行;已同步行置 update 凭阶段ID 重推
|
||||||
contractExeStageService.accumulateClaimedAmountOnPush(contractId, claimedTotal);
|
contractExeStageService.accumulateClaimedAmountOnPush(contractId, claimAmount);
|
||||||
HcsContractExeStage stageRow = contractExeStageService.findCollectionStageRow(contractId, HcsSyncConstant.FUND_NATURE_PROGRESS);
|
HcsContractExeStage stageRow = contractExeStageService.findCollectionStageRow(contractId, HcsSyncConstant.FUND_NATURE_PROGRESS);
|
||||||
if (StringUtil.isNotBlank(contractManage.getHcsFdId())) {
|
if (StringUtil.isNotBlank(contractManage.getHcsFdId())) {
|
||||||
// 行级重推(无待同步行返回提示,不视为失败);合同未推送合规时随合同链路首推
|
// 行级重推(无待同步行返回提示,不视为失败);合同未推送合规时随合同链路首推
|
||||||
hcsExeStageSyncSupport.syncExeStages(contractManage);
|
hcsExeStageSyncSupport.syncExeStages(contractManage);
|
||||||
}
|
}
|
||||||
// ② C107-1 认领记录:按「认领主单 × 合同」推送,金额为该认领主单分摊到本合同的金额
|
// ② C107-1 认领记录:本认领主单分摊到本合同的金额,返回 fdId 落库供 C107-3 作废引用
|
||||||
if (StringUtil.isBlank(hcsCollectionFlowId)) {
|
if (StringUtil.isBlank(hcsCollectionFlowId)) {
|
||||||
log.warn("HCS认领记录推送跳过:未定位到合规收款流水 flowId={},detailSerialNo={}", flow.getId(), flow.getDetailSerialNo());
|
log.warn("HCS认领记录推送跳过:未定位到合规收款流水 claimId={},flowId={},detailSerialNo={}",
|
||||||
|
claim.getId(), flow.getId(), flow.getDetailSerialNo());
|
||||||
|
saveClaimHcsRecord(claim, flow, contractManage, claimAmount, null, PUSH_FAILED, "C104-2未定位到合规收款流水");
|
||||||
} else {
|
} else {
|
||||||
Map<Long, ReceiptClaim> claimsById = claims.stream()
|
String claimRecordFdId = pushClaimRecord(flow, claim, contractManage, stageRow, claimAmount, hcsCollectionFlowId);
|
||||||
.collect(Collectors.toMap(ReceiptClaim::getId, item -> item, (first, second) -> first));
|
saveClaimHcsRecord(claim, flow, contractManage, claimAmount, claimRecordFdId,
|
||||||
for (Map.Entry<Long, BigDecimal> claimEntry : amountByClaim.entrySet()) {
|
StringUtil.isBlank(claimRecordFdId) ? PUSH_FAILED : PUSH_SUCCESS, null);
|
||||||
pushClaimRecord(flow, claimsById.get(claimEntry.getKey()), contractManage, stageRow, claimEntry.getValue(), hcsCollectionFlowId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// ③ C108-1 履约流水:按合同一条(开关 perf-record.sync-enabled,与付款链履约记录同步同开关),
|
// ③ C108-1 履约流水:按合同一条(开关 perf-record.sync-enabled,与付款链履约记录同步同开关),
|
||||||
// 须已推送合规且存在已同步收款计划行(fd_plan_id 必填);履约日期为收款流水交易日期
|
// 须已推送合规且存在已同步收款计划行(fd_plan_id 必填)
|
||||||
if (!hcsProperties.getPerfRecord().isSyncEnabled()) {
|
if (!hcsProperties.getPerfRecord().isSyncEnabled()) {
|
||||||
log.info("HCS履约流水推送跳过:履约记录同步开关未开启 contractNo={}", contractManage.getContractNo());
|
log.info("HCS履约流水推送跳过:履约记录同步开关未开启 contractNo={}", contractManage.getContractNo());
|
||||||
return;
|
return;
|
||||||
@@ -221,16 +249,18 @@ public class HcsClaimSyncSupport {
|
|||||||
log.info("HCS履约流水推送跳过:无已同步收款履约计划行 contractNo={}", contractManage.getContractNo());
|
log.info("HCS履约流水推送跳过:无已同步收款履约计划行 contractNo={}", contractManage.getContractNo());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pushPerfRecord(flow, contractManage, stageRow, claimedTotal);
|
pushPerfRecord(flow, contractManage, stageRow, claimAmount, claim.getClaimDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* C107-1 认领记录推送(单认领主单 × 单合同)
|
* C107-1 认领记录推送(单认领主单 × 单合同)
|
||||||
|
*
|
||||||
|
* @return 合规侧认领记录 fdId(响应未返回返回 null)
|
||||||
*/
|
*/
|
||||||
private void pushClaimRecord(KingdeeReceiptFlow flow, ReceiptClaim claim, ContractManage contractManage,
|
private String pushClaimRecord(KingdeeReceiptFlow flow, ReceiptClaim claim, ContractManage contractManage,
|
||||||
HcsContractExeStage stageRow, BigDecimal claimAmount, String hcsCollectionFlowId) {
|
HcsContractExeStage stageRow, BigDecimal claimAmount, String hcsCollectionFlowId) {
|
||||||
if (claim == null || claimAmount == null || claimAmount.signum() <= 0) {
|
if (claimAmount == null || claimAmount.signum() <= 0) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
HcsClaimRecordAddDTO param = new HcsClaimRecordAddDTO();
|
HcsClaimRecordAddDTO param = new HcsClaimRecordAddDTO();
|
||||||
// 【必填】收款流水引用(合规侧流水ID,C104-2 按明细流水号定位)
|
// 【必填】收款流水引用(合规侧流水ID,C104-2 按明细流水号定位)
|
||||||
@@ -259,7 +289,7 @@ public class HcsClaimSyncSupport {
|
|||||||
param.setFdClaimDate(toMillis(claim.getClaimDate()));
|
param.setFdClaimDate(toMillis(claim.getClaimDate()));
|
||||||
param.setFdRemark(claim.getRemark());
|
param.setFdRemark(claim.getRemark());
|
||||||
// 状态 0=已认领(仅推送未作废认领)
|
// 状态 0=已认领(仅推送未作废认领)
|
||||||
param.setFdStatus(0);
|
param.setFdStatus(CLAIM_STATUS_CLAIMED);
|
||||||
log.info("HCS认领记录推送开始 flowId:{},claimId:{},contractNo:{},认领金额 {}",
|
log.info("HCS认领记录推送开始 flowId:{},claimId:{},contractNo:{},认领金额 {}",
|
||||||
flow.getId(), claim.getId(), contractManage.getContractNo(), claimAmount);
|
flow.getId(), claim.getId(), contractManage.getContractNo(), claimAmount);
|
||||||
HcsResult<HcsIdVO> result = hcsClient.claimRecordAdd(param);
|
HcsResult<HcsIdVO> result = hcsClient.claimRecordAdd(param);
|
||||||
@@ -267,25 +297,137 @@ public class HcsClaimSyncSupport {
|
|||||||
log.error("HCS认领记录推送失败响应:{},claimId={}", result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), claim.getId());
|
log.error("HCS认领记录推送失败响应:{},claimId={}", result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), claim.getId());
|
||||||
throw new HcsException("C107-1 认领记录推送失败:" + (result == null ? "响应为空" : result.getMsg()));
|
throw new HcsException("C107-1 认领记录推送失败:" + (result == null ? "响应为空" : result.getMsg()));
|
||||||
}
|
}
|
||||||
// shortcut: C107-1 返回 fdId 未持久化(认领作废同步 C107-3 未实现,重推会重复);需作废联动时先落库
|
String claimRecordFdId = result.getData() == null ? null : result.getData().getFdId();
|
||||||
log.info("HCS认领记录推送成功 flowId:{},claimId:{},contractNo:{},claimRecordFdId:{}",
|
log.info("HCS认领记录推送成功 flowId:{},claimId:{},contractNo:{},claimRecordFdId:{}",
|
||||||
flow.getId(), claim.getId(), contractManage.getContractNo(),
|
flow.getId(), claim.getId(), contractManage.getContractNo(),
|
||||||
result.getData() == null ? "响应未返回" : result.getData().getFdId());
|
StringUtil.isBlank(claimRecordFdId) ? "响应未返回" : claimRecordFdId);
|
||||||
|
return claimRecordFdId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* C108-1 履约流水推送(单合同一条:申请金额=实际金额=该合同累计认领金额,履约日期=收款流水交易日期)
|
* C107-1 推送结果落库(认领主单 × 合同一条):成功持久化合规 fdId,失败落标记与原因
|
||||||
|
*/
|
||||||
|
private void saveClaimHcsRecord(ReceiptClaim claim, KingdeeReceiptFlow flow, ContractManage contractManage,
|
||||||
|
BigDecimal claimAmount, String claimRecordFdId, String pushStatus, String failReason) {
|
||||||
|
ReceiptClaimHcsRecord record = new ReceiptClaimHcsRecord();
|
||||||
|
record.setReceiptClaimId(claim.getId());
|
||||||
|
record.setReceiptFlowId(flow.getId());
|
||||||
|
record.setContractId(contractManage.getId());
|
||||||
|
record.setContractNo(contractManage.getContractNo());
|
||||||
|
record.setClaimAmount(claimAmount);
|
||||||
|
record.setHcsClaimRecordFdId(claimRecordFdId);
|
||||||
|
record.setPushStatus(pushStatus);
|
||||||
|
record.setFailReason(failReason);
|
||||||
|
record.setPushedTime(PUSH_SUCCESS.equals(pushStatus) ? LocalDateTime.now() : null);
|
||||||
|
claimHcsRecordMapper.insert(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认领作废事务提交后同步合规 C107-3(修改认领记录 fdStatus=1 已作废)
|
||||||
|
* <p>
|
||||||
|
* 仅同步本认领主单推送成功的合规记录;单条失败独立记日志,不影响其余合同。
|
||||||
|
* 作废失败时本地记录保持 success(合规侧仍为已认领),需人工在合规侧处置。
|
||||||
|
*
|
||||||
|
* @param claimId 认领主单ID
|
||||||
|
*/
|
||||||
|
public void voidClaimToHcs(Long claimId) {
|
||||||
|
if (!hcsProperties.getExeStage().isSyncEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<ReceiptClaimHcsRecord> records = claimHcsRecordMapper.selectList(
|
||||||
|
Wrappers.<ReceiptClaimHcsRecord>lambdaQuery()
|
||||||
|
.eq(ReceiptClaimHcsRecord::getReceiptClaimId, claimId)
|
||||||
|
.eq(ReceiptClaimHcsRecord::getPushStatus, PUSH_SUCCESS));
|
||||||
|
if (records.isEmpty()) {
|
||||||
|
log.info("HCS认领作废同步跳过:无推送成功的合规认领记录 claimId={}", claimId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (ReceiptClaimHcsRecord record : records) {
|
||||||
|
try {
|
||||||
|
voidOneClaimRecord(record);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.error("HCS认领作废同步失败 claimId:{},recordId:{},hcsFdId:{}",
|
||||||
|
claimId, record.getId(), record.getHcsClaimRecordFdId(), exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.error("HCS认领作废同步异常 claimId:{}", claimId, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C107-3 单条作废:fdId 必填,fdStatus=1 已作废;成功后本地记录置 voided
|
||||||
|
*/
|
||||||
|
private void voidOneClaimRecord(ReceiptClaimHcsRecord record) {
|
||||||
|
HcsClaimRecordAddDTO param = new HcsClaimRecordAddDTO();
|
||||||
|
// 【必填】合规侧认领记录ID(C107-1 推送成功时落库)
|
||||||
|
param.setFdId(record.getHcsClaimRecordFdId());
|
||||||
|
// 状态 1=已作废
|
||||||
|
param.setFdStatus(CLAIM_STATUS_VOIDED);
|
||||||
|
log.info("HCS认领作废同步开始 claimId:{},contractNo:{},hcsFdId:{}",
|
||||||
|
record.getReceiptClaimId(), record.getContractNo(), record.getHcsClaimRecordFdId());
|
||||||
|
HcsResult<HcsIdVO> result = hcsClient.claimRecordUpdate(param);
|
||||||
|
if (result == null || !result.isSuccess()) {
|
||||||
|
throw new HcsException("C107-3 认领作废同步失败:" + (result == null ? "响应为空" : result.getMsg()));
|
||||||
|
}
|
||||||
|
// 本地推送记录置已作废
|
||||||
|
claimHcsRecordMapper.update(null, Wrappers.<ReceiptClaimHcsRecord>lambdaUpdate()
|
||||||
|
.eq(ReceiptClaimHcsRecord::getId, record.getId())
|
||||||
|
.set(ReceiptClaimHcsRecord::getPushStatus, PUSH_VOIDED));
|
||||||
|
log.info("HCS认领作废同步成功 claimId:{},contractNo:{},hcsFdId:{}",
|
||||||
|
record.getReceiptClaimId(), record.getContractNo(), record.getHcsClaimRecordFdId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C108-1 履约流水推送(单合同一条:申请金额=实际金额=本次认领分摊金额)
|
||||||
*/
|
*/
|
||||||
private void pushPerfRecord(KingdeeReceiptFlow flow, ContractManage contractManage,
|
private void pushPerfRecord(KingdeeReceiptFlow flow, ContractManage contractManage,
|
||||||
HcsContractExeStage stageRow, BigDecimal claimedTotal) {
|
HcsContractExeStage stageRow, BigDecimal claimAmount, LocalDate planDate) {
|
||||||
// 履约日期:交易日期(需求口径),交易时间为空兜底当天
|
// 表单模板ID(配置 perf-record.xform-id,环境值 §9-U9,未配置不传)
|
||||||
LocalDate perfDate = flow.getTransactionTime() != null ? flow.getTransactionTime().toLocalDate() : LocalDate.now();
|
String xformId = StringUtil.isBlank(hcsProperties.getPerfRecord().getXformId()) ? null : hcsProperties.getPerfRecord().getXformId();
|
||||||
String perfFdId = hcsPerfRecordAddSupport.pushPerfRecordAdd(contractManage, stageRow,
|
HcsPerfRecordPropsDTO props = new HcsPerfRecordPropsDTO();
|
||||||
firstNonBlank(flow.getReceiptNoticeNo(), flow.getDetailSerialNo()), claimedTotal, toMillis(perfDate),
|
// 【必填】申请编号:收款通知单号,兜底明细流水号
|
||||||
HcsSyncConstant.PERF_TYPE_COLLECTION, flow.getKingdeeBillNo(), flow.getId(),
|
props.setFdApplyNo(firstNonBlank(flow.getReceiptNoticeNo(), flow.getDetailSerialNo()));
|
||||||
"收款履约-" + firstNonBlank(flow.getReceiptNoticeNo(), flow.getDetailSerialNo()));
|
// 申请金额 / 实际金额:本次认领分摊金额
|
||||||
// shortcut: 履约流水 fdId 未持久化(认领链无 C108-2 更新场景,重推会重复);需推进实际金额更新时先落库
|
props.setFdApplyAmount(claimAmount.toPlainString());
|
||||||
log.info("HCS履约流水新建完成 flowId:{},contractNo:{},perfFdId:{}", flow.getId(), contractManage.getContractNo(), perfFdId);
|
props.setFdFactAmount(claimAmount.toPlainString());
|
||||||
|
// 【必填】履约日期:认领日期(毫秒时间戳)
|
||||||
|
props.setFdPlanDate(toMillis(planDate));
|
||||||
|
// 履约类型:收款
|
||||||
|
props.setFdPalnType(HcsSyncConstant.PERFORM_TYPE_COLLECTION);
|
||||||
|
// 履约性质:收款计划行款项性质
|
||||||
|
props.setFdProperty(stageRow.getFundNature());
|
||||||
|
// 履约计划id / 来源履约计划项ID:收款计划行合规阶段ID(HCS 只认自己的阶段ID)
|
||||||
|
props.setFdId(stageRow.getHcsStageFdId());
|
||||||
|
props.setFdPlanId(stageRow.getHcsStageFdId());
|
||||||
|
// 金蝶单据号:金蝶收款单号(A301-1 同步落库)
|
||||||
|
props.setFdJdDocNo(flow.getKingdeeBillNo());
|
||||||
|
// 【必填】合同ID:HCS 合同ID
|
||||||
|
props.setFdContractId(contractManage.getHcsFdId());
|
||||||
|
// 业务ID:TMS 收款流水ID(溯源)
|
||||||
|
props.setFdBusinessId(String.valueOf(flow.getId()));
|
||||||
|
props.setFdCreateTime(System.currentTimeMillis());
|
||||||
|
props.setFdXformId(xformId);
|
||||||
|
HcsPerfRecordFormDataDTO formData = new HcsPerfRecordFormDataDTO();
|
||||||
|
formData.setFdXformId(xformId);
|
||||||
|
formData.setDynamicProps(props);
|
||||||
|
// 机制数据(C108-1 必填):认领附件暂不转传,传空列表
|
||||||
|
HcsMechanismsDTO mechanisms = new HcsMechanismsDTO();
|
||||||
|
mechanisms.setAttachment(List.of());
|
||||||
|
HcsPerfRecordSaveDTO param = new HcsPerfRecordSaveDTO();
|
||||||
|
param.setCurUser(HcsUserRefVO.ofLoginName(hcsProperties.getOperatorLoginName()));
|
||||||
|
param.setFormData(formData);
|
||||||
|
param.setMechanisms(mechanisms);
|
||||||
|
log.info("HCS履约流水新建开始 flowId:{},contractNo:{},认领金额 {}", flow.getId(), contractManage.getContractNo(), claimAmount);
|
||||||
|
HcsResult<HcsFormSaveVO> result = hcsClient.perfRecordAdd(param);
|
||||||
|
if (result == null || !result.isSuccess() || result.getData() == null || StringUtil.isBlank(result.getData().getFdId())) {
|
||||||
|
log.error("HCS履约流水新建失败响应:{},contractNo={}", result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), contractManage.getContractNo());
|
||||||
|
throw new HcsException("C108-1 履约流水新建失败:" + (result == null ? "响应为空" : result.getMsg()));
|
||||||
|
}
|
||||||
|
// shortcut: 履约流水 fdId 未持久化(认领链无 C108-2 更新场景);需推进实际金额更新时先落库
|
||||||
|
log.info("HCS履约流水新建成功 flowId:{},contractNo:{},perfFdId:{}",
|
||||||
|
flow.getId(), contractManage.getContractNo(), result.getData().getFdId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user