feat: 金蝶冲销状态回写拆分独立定时任务并支持分批配置
- 新增KingdeeWriteOffResultTask独立调度(Nacos thirdParty.bfi.writeOffResult.*开关/cron),从付款结果任务第④步拆出 - BfiProperties新增writeOffResult配置:syncEnabled开关、queryBatchSize分批大小默认1000,冲销批量查询与批量落库共用 - 回写仅扫描已同步且未冲销的结算单,已冲销为终态不再复查 - kingdee_write_off_status列默认值改为unwrittenoff,存量已同步NULL数据回填未冲销 - 补充扫描数/防重键数/金蝶返回数/落库数关键日志,summary文案修正为待查未冲销结算单
This commit is contained in:
+23
@@ -115,6 +115,11 @@ public class BfiProperties {
|
||||
*/
|
||||
private ArResult arResult = new ArResult();
|
||||
|
||||
/**
|
||||
* 金蝶冲销状态回写配置(A102-4/A302-4)
|
||||
*/
|
||||
private WriteOffResult writeOffResult = new WriteOffResult();
|
||||
|
||||
/**
|
||||
* 金蝶单据锁定补偿配置
|
||||
*/
|
||||
@@ -374,6 +379,24 @@ public class BfiProperties {
|
||||
private long lockLeaseSeconds = 1800;
|
||||
}
|
||||
|
||||
/**
|
||||
* 金蝶冲销状态回写配置项(A102-4/A302-4):定时回写开关、防重键批量查询与结算单批量更新的分批大小,
|
||||
* 防止单批过大超出金蝶查询接口与批量落库承载能力
|
||||
*/
|
||||
@Data
|
||||
public static class WriteOffResult {
|
||||
|
||||
/**
|
||||
* 冲销状态回写任务开关,默认关闭(安全兜底),由 Nacos 按环境显式开启
|
||||
*/
|
||||
private boolean syncEnabled = false;
|
||||
|
||||
/**
|
||||
* 冲销状态批量查询/批量更新分批大小,默认 1000
|
||||
*/
|
||||
private int queryBatchSize = 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* 金蝶单据锁定补偿配置项
|
||||
*/
|
||||
|
||||
+15
-5
@@ -1172,14 +1172,17 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
*/
|
||||
private String executeWriteOffSync() {
|
||||
long startMillis = System.currentTimeMillis();
|
||||
// 已同步金蝶的结算单才在金蝶存在旧应付/应收单,未同步/生成失败不查询(前端展示 '-')
|
||||
// 已同步金蝶的结算单才在金蝶存在旧应付/应收单,未同步/生成失败不查询(前端展示 '-');
|
||||
// 已冲销为终态不再复查,仅扫未冲销单据(存量 NULL 由 06 脚本回填默认未冲销)
|
||||
List<FormalSettlement> settlements = list(Wrappers.<FormalSettlement>lambdaQuery()
|
||||
.eq(FormalSettlement::getKingdeeSyncStatus, KingdeeBfiConstant.KINGDEE_STATUS_SYNCED)
|
||||
.eq(FormalSettlement::getKingdeeWriteOffStatus, KingdeeBfiConstant.KINGDEE_WRITEOFF_UNWRITTEN)
|
||||
.orderByAsc(FormalSettlement::getId));
|
||||
if (Func.isEmpty(settlements)) {
|
||||
log.info("金蝶冲销状态回写:无已同步结算单");
|
||||
return "金蝶冲销状态回写:无已同步结算单";
|
||||
log.info("金蝶冲销状态回写:无待查未冲销结算单");
|
||||
return "金蝶冲销状态回写:无待查未冲销结算单";
|
||||
}
|
||||
log.info("金蝶冲销状态回写:本轮扫描待查未冲销结算单{}笔", settlements.size());
|
||||
// 结算明细分批一次查全(消除逐单查询 N+1),按结算单 id 分组后按结算类型组装防重键
|
||||
List<Long> settlementIds = settlements.stream().map(FormalSettlement::getId).toList();
|
||||
Map<Long, List<FormalSettlementDetail>> detailsBySettlement = new HashMap<>();
|
||||
@@ -1209,17 +1212,24 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
}
|
||||
}
|
||||
// A102-4/A302-4 整批一次查询,冲销状态有变化的才落库(updateBatchById 批量更新,避免逐单 update)
|
||||
log.info("金蝶冲销状态回写:防重键组装完成,应付{}个、应收{}个,按批次大小{}分批查询",
|
||||
apSettlementBySrcCode.size(), arSettlementBySrcCode.size(), bfiProperties.getWriteOffResult().getQueryBatchSize());
|
||||
Map<String, Boolean> apWriteOffFlags = kingdeeApBillSyncSupport.queryApBillWriteOffFlags(new ArrayList<>(apSettlementBySrcCode.keySet()));
|
||||
Map<String, Boolean> arWriteOffFlags = kingdeeArBillSyncSupport.queryArBillWriteOffFlags(new ArrayList<>(arSettlementBySrcCode.keySet()));
|
||||
// 金蝶未返回的键按未冲销处理,返回数与组装数差异即金蝶侧查不到单据的规模,留痕便于对账
|
||||
log.info("金蝶冲销状态批量查询完成:应付键返回{}个、应收键返回{}个,未返回键按未冲销处理",
|
||||
apWriteOffFlags.size(), arWriteOffFlags.size());
|
||||
List<FormalSettlement> toUpdateSettlements = new ArrayList<>();
|
||||
apSettlementBySrcCode.forEach((srcCode, settlement) ->
|
||||
this.applyWriteOffFlag(settlement, apWriteOffFlags.get(srcCode), toUpdateSettlements));
|
||||
arSettlementBySrcCode.forEach((srcCode, settlement) ->
|
||||
this.applyWriteOffFlag(settlement, arWriteOffFlags.get(srcCode), toUpdateSettlements));
|
||||
if (Func.isNotEmpty(toUpdateSettlements)) {
|
||||
updateBatchById(toUpdateSettlements);
|
||||
// 批量落库按同一分批大小拆分,避免单批过大
|
||||
updateBatchById(toUpdateSettlements, bfiProperties.getWriteOffResult().getQueryBatchSize());
|
||||
log.info("金蝶冲销状态回写:批量落库完成,本批更新{}笔", toUpdateSettlements.size());
|
||||
}
|
||||
String summary = "金蝶冲销状态回写完成:待查已同步结算单" + (apSettlementBySrcCode.size() + arSettlementBySrcCode.size())
|
||||
String summary = "金蝶冲销状态回写完成:待查未冲销结算单" + (apSettlementBySrcCode.size() + arSettlementBySrcCode.size())
|
||||
+ "笔,回写" + toUpdateSettlements.size() + "笔";
|
||||
log.info("{},耗时{}ms", summary, System.currentTimeMillis() - startMillis);
|
||||
return summary;
|
||||
|
||||
+1
-1
@@ -225,7 +225,7 @@ public class KingdeeApBillSyncSupport {
|
||||
*/
|
||||
public Map<String, Boolean> queryApBillWriteOffFlags(List<String> awrpSrcCodes) {
|
||||
Map<String, Boolean> writeOffFlags = new LinkedHashMap<>();
|
||||
batchForeach(awrpSrcCodes, PAY_RESULT_QUERY_BATCH, batch -> {
|
||||
batchForeach(awrpSrcCodes, bfiProperties.getWriteOffResult().getQueryBatchSize(), batch -> {
|
||||
BfiApBillQueryDTO param = new BfiApBillQueryDTO();
|
||||
param.setAwrpSrcCode(batch);
|
||||
param.setAwrpSrcSys(bfiProperties.getSrcSys());
|
||||
|
||||
+1
-1
@@ -163,7 +163,7 @@ public class KingdeeArBillSyncSupport {
|
||||
*/
|
||||
public Map<String, Boolean> queryArBillWriteOffFlags(List<String> arBillSrcCodes) {
|
||||
Map<String, Boolean> writeOffFlags = new LinkedHashMap<>();
|
||||
kingdeeApBillSyncSupport.batchForeach(arBillSrcCodes, AR_RESULT_QUERY_BATCH, batch -> {
|
||||
kingdeeApBillSyncSupport.batchForeach(arBillSrcCodes, bfiProperties.getWriteOffResult().getQueryBatchSize(), batch -> {
|
||||
BfiArBillQueryDTO param = new BfiArBillQueryDTO();
|
||||
param.setAwrpSrcCode(batch);
|
||||
param.setAwrpSrcSys(bfiProperties.getSrcSys());
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.transport.task;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.transport.config.BfiProperties;
|
||||
import org.springblade.transport.service.IFormalSettlementService;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 金蝶冲销状态定时回写任务
|
||||
* <p>
|
||||
* A102-4/A302-4 批量查询已同步结算单对应金蝶旧应付/应收单的 hadwrittenoff(部分冲销视同已冲销),
|
||||
* 回写结算单冲销状态,用于结算单列表展示金蝶旧单是否已冲销。
|
||||
* 业务逻辑收敛在服务方法(分布式锁 + 分批查询 + 批量落库),便于手动触发联调。
|
||||
* <p>
|
||||
* 调度配置(Nacos thirdParty.bfi.writeOffResult.*):syncEnabled 开关、cron 表达式、queryBatchSize 分批大小。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RefreshScope
|
||||
@RequiredArgsConstructor
|
||||
public class KingdeeWriteOffResultTask {
|
||||
|
||||
private final IFormalSettlementService formalSettlementService;
|
||||
private final BfiProperties bfiProperties;
|
||||
|
||||
/** 金蝶冲销状态回写调度,默认每10分钟执行一次(分钟位与付款结果回写错峰) */
|
||||
@Scheduled(cron = "${thirdParty.bfi.writeOffResult.cron:0 4/10 * * * ?}")
|
||||
public void syncKingdeeWriteOffResult() {
|
||||
if (!bfiProperties.getWriteOffResult().isSyncEnabled()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String summary = formalSettlementService.syncKingdeeWriteOffResult();
|
||||
log.info("定时回写金蝶冲销状态:{}", summary);
|
||||
} catch (Exception exception) {
|
||||
log.error("定时回写金蝶冲销状态异常", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
-7
@@ -86,13 +86,6 @@ public class PaymentKingdeeResultTask {
|
||||
} catch (Exception exception) {
|
||||
log.error("定时回写金蝶开票结果异常", exception);
|
||||
}
|
||||
// ④ A102-4/A302-4 冲销状态回写(结算单列表展示金蝶旧单是否已冲销)
|
||||
try {
|
||||
String summary = formalSettlementService.syncKingdeeWriteOffResult();
|
||||
log.info("定时回写金蝶冲销状态:{}", summary);
|
||||
} catch (Exception exception) {
|
||||
log.error("定时回写金蝶冲销状态异常", exception);
|
||||
}
|
||||
}
|
||||
|
||||
/** 金蝶收票单结果回写调度(异常回收/指定补偿/单号补登),默认每10分钟执行一次 */
|
||||
|
||||
Reference in New Issue
Block a user